Vuo  2.0.3
VuoImageRenderer.cc
Go to the documentation of this file.
1 
10 #include "VuoImageRenderer.h"
11 
12 
13 #include <IOSurface/IOSurface.h>
14 
15 #include <OpenGL/CGLMacro.h>
17 #define glGenVertexArrays glGenVertexArraysAPPLE
18 #define glBindVertexArray glBindVertexArrayAPPLE
19 #define glDeleteVertexArrays glDeleteVertexArraysAPPLE
20 
22 #include "module.h"
23 extern "C"
24 {
25 #ifdef VUO_COMPILER
27  "title" : "VuoImageRenderer",
28  "dependencies" : [
29  "VuoImage",
30  "VuoImageColorDepth",
31  "VuoShader",
32  "VuoGlContext",
33  "VuoGlPool",
34  "OpenGL.framework"
35  ]
36  });
37 #endif
38 }
39 
44 {
45  GLuint outputFramebuffer;
46 
47  GLuint vertexArray;
48  GLuint quadDataBuffer;
49 };
54 
58 static const GLfloat quadData[] = {
59  // Positions
60  -1, -1, 0, 1,
61  1, -1, 0, 1,
62  -1, 1, 0, 1,
63  1, 1, 0, 1,
64 
65  // Texture Coordinates
66  0, 0, 0, 0,
67  1, 0, 0, 0,
68  0, 1, 0, 0,
69  1, 1, 0, 0
70 };
74 static const GLfloat unityMatrix[16] = {
75  1,0,0,0,
76  0,1,0,0,
77  0,0,1,0,
78  0,0,0,1
79 };
80 
81 static void VuoImageRenderer_fini(void);
82 
86 static void VuoImageRenderer_init(void)
87 {
88  static dispatch_once_t once = 0;
89  dispatch_once(&once, ^{
90  VuoGlContext_perform(^(CGLContextObj cgl_ctx){
93  {
94  VuoImageRendererGlobal.quadDataBuffer = VuoGlPool_use(cgl_ctx, VuoGlPool_ArrayBuffer, sizeof(quadData));
96  glBindBuffer(GL_ARRAY_BUFFER, VuoImageRendererGlobal.quadDataBuffer);
97  glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(quadData), quadData);
98  }
100 
101  glFlushRenderAPPLE();
102 
103  glGenFramebuffers(1, &VuoImageRendererGlobal.outputFramebuffer);
104  });
105 
107  });
108 }
109 
113 extern "C" VuoImage VuoImageRenderer_draw(void *ir, VuoShader shader, unsigned int pixelsWide, unsigned int pixelsHigh, VuoImageColorDepth imageColorDepth)
114 {
115  return VuoImageRenderer_render(shader, pixelsWide, pixelsHigh, imageColorDepth);
116 }
117 
121 extern "C" void *VuoImageRenderer_make(void *)
122 {
123  return NULL;
124 }
125 
131 VuoImage VuoImageRenderer_render(VuoShader shader, unsigned int pixelsWide, unsigned int pixelsHigh, VuoImageColorDepth imageColorDepth)
132 {
133  if (pixelsWide < 1 || pixelsHigh < 1)
134  return NULL;
135 
136  GLuint internalFormat;
137  GLuint outputTexture = VuoImageRenderer_draw_internal(shader, pixelsWide, pixelsHigh, imageColorDepth, false, false, 0, &internalFormat);
138  if (!outputTexture)
139  return NULL;
140 
141  VuoImage outputImage = VuoImage_make(outputTexture, internalFormat, pixelsWide, pixelsHigh);
142 
143  VuoImage firstInputImage = VuoShader_getFirstImage(shader);
144  if (firstInputImage)
145  outputImage->scaleFactor = firstInputImage->scaleFactor;
146 
147  return outputImage;
148 }
149 
155 unsigned long int VuoImageRenderer_draw_internal(VuoShader shader, unsigned int pixelsWide, unsigned int pixelsHigh, VuoImageColorDepth imageColorDepth, bool outputToIOSurface, bool outputToGlTextureRectangle, unsigned int outputToSpecificTexture, GLuint *outputInternalFormat)
156 {
158 
159  __block GLuint outputTexture = 0;
160  __block IOSurfaceID surfID = 0;
161  VuoGlContext_perform(^(CGLContextObj cgl_ctx){
162  glViewport(0, 0, pixelsWide, pixelsHigh);
163 
164  // Create a new GL Texture Object.
165  bool shaderOpaque = VuoShader_isOpaque(shader);
166  GLenum textureFormat = shaderOpaque ? GL_BGR : GL_BGRA;
167  GLuint textureTarget = (outputToIOSurface || outputToGlTextureRectangle) ? GL_TEXTURE_RECTANGLE_ARB : GL_TEXTURE_2D;
168  GLuint textureTargetInternalFormat = VuoImageColorDepth_getGlInternalFormat(textureFormat, imageColorDepth);
169  if (outputInternalFormat)
170  *outputInternalFormat = textureTargetInternalFormat;
171 
172  VuoIoSurface ioSurface = NULL;
173  if (outputToIOSurface)
175  ioSurface = VuoIoSurfacePool_use(cgl_ctx, pixelsWide, pixelsHigh, &outputTexture);
176  else if (outputToSpecificTexture)
177  outputTexture = outputToSpecificTexture;
178  else
179  outputTexture = VuoGlTexturePool_use(cgl_ctx, VuoGlTexturePool_Allocate, outputToGlTextureRectangle ? GL_TEXTURE_RECTANGLE_ARB : GL_TEXTURE_2D, textureTargetInternalFormat, pixelsWide, pixelsHigh, textureFormat, NULL);
180 
181  if (!outputTexture)
182  return;
183 
184  glBindFramebuffer(GL_FRAMEBUFFER, VuoImageRendererGlobal.outputFramebuffer);
185 // VLog("glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, %s, %d, 0);", VuoGl_stringForConstant(textureTarget), outputTexture);
186  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureTarget, outputTexture, 0);
187 
188  if (!shaderOpaque)
189  {
190  glClearColor(0,0,0,0);
191  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
192  }
193 
194  // Execute the shader.
195  {
196  GLint positionAttribute;
197  GLint textureCoordinateAttribute;
198  bool ret = VuoShader_getAttributeLocations(shader, VuoMesh_IndividualTriangles, cgl_ctx, &positionAttribute, NULL, &textureCoordinateAttribute, NULL);
199  if (!ret)
200  {
201  VDebugLog("Error: Failed to get attribute locations.");
202  glBindFramebuffer(GL_FRAMEBUFFER, 0);
203  if (outputToIOSurface)
204  VuoIoSurfacePool_disuse(ioSurface, false); // It was never used, so no need to quarantine it.
205  else if (outputToSpecificTexture)
206  {}
207  else
208  {
209  VuoGlTexture_retain(outputTexture, NULL, NULL);
210  VuoGlTexture_release(VuoGlTexturePool_Allocate, outputToGlTextureRectangle ? GL_TEXTURE_RECTANGLE_ARB : GL_TEXTURE_2D, textureTargetInternalFormat, pixelsWide, pixelsHigh, outputTexture);
211  }
212  outputTexture = 0;
213  surfID = 0;
214  return;
215  }
216 
217  VuoGlProgram program;
218  if (!VuoShader_activate(shader, VuoMesh_IndividualTriangles, cgl_ctx, &program))
219  {
220  VUserLog("Shader activation failed.");
221  outputTexture = 0;
222  surfID = 0;
223  return;
224  }
225 
226  {
228 
229  GLint projectionMatrixUniform = VuoGlProgram_getUniformLocation(program, "projectionMatrix");
230  glUniformMatrix4fv(projectionMatrixUniform, 1, GL_FALSE, unityMatrix);
231 
232  GLint cameraMatrixInverseUniform = VuoGlProgram_getUniformLocation(program, "cameraMatrixInverse");
233  glUniformMatrix4fv(cameraMatrixInverseUniform, 1, GL_FALSE, unityMatrix);
234 
235  GLint useFisheyeProjectionUniform = VuoGlProgram_getUniformLocation(program, "useFisheyeProjection");
236  glUniform1i(useFisheyeProjectionUniform, false);
237 
238  GLint modelviewMatrixUniform = VuoGlProgram_getUniformLocation(program, "modelviewMatrix");
239  glUniformMatrix4fv(modelviewMatrixUniform, 1, GL_FALSE, unityMatrix);
240 
241  GLint aspectRatioUniform = VuoGlProgram_getUniformLocation(program, "aspectRatio");
242  if (aspectRatioUniform != -1)
243  glUniform1f(aspectRatioUniform, (float)pixelsWide/(float)pixelsHigh);
244 
245  GLint viewportSizeUniform = VuoGlProgram_getUniformLocation(program, "viewportSize");
246  if (viewportSizeUniform != -1)
247  glUniform2f(viewportSizeUniform, (float)pixelsWide, (float)pixelsHigh);
248 
249  glBindBuffer(GL_ARRAY_BUFFER, VuoImageRendererGlobal.quadDataBuffer);
250 
251  glEnableVertexAttribArray(positionAttribute);
252  glVertexAttribPointer(positionAttribute, 4 /* XYZW */, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*4, (void*)0);
253 
254  if (textureCoordinateAttribute != -1)
255  {
256  glEnableVertexAttribArray(textureCoordinateAttribute);
257  glVertexAttribPointer(textureCoordinateAttribute, 4 /* XYZW */, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*4, (void*)(sizeof(GLfloat)*16));
258  }
259 
260 #ifdef VUO_PROFILE
261  GLuint timeElapsedQuery;
262  glGenQueries(1, &timeElapsedQuery);
263  glBeginQuery(GL_TIME_ELAPSED_EXT, timeElapsedQuery);
264 #endif
265 
266  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
267 
268 #ifdef VUO_PROFILE
269  double seconds;
270  glEndQuery(GL_TIME_ELAPSED_EXT);
271  GLuint nanoseconds;
272  glGetQueryObjectuiv(timeElapsedQuery, GL_QUERY_RESULT, &nanoseconds);
273  seconds = ((double)nanoseconds) / NSEC_PER_SEC;
274  glDeleteQueries(1, &timeElapsedQuery);
275 
276  double objectPercent = seconds / (1./60.) * 100.;
277  VLog("%6.2f %% of 60 Hz frame %s", objectPercent, shader->name);
278 #endif
279 
280  if (textureCoordinateAttribute != -1)
281  glDisableVertexAttribArray(textureCoordinateAttribute);
282 
283  glDisableVertexAttribArray(positionAttribute);
284 
285  glBindBuffer(GL_ARRAY_BUFFER, 0);
287  }
289  }
290 
291  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureTarget, 0, 0);
292  glBindFramebuffer(GL_FRAMEBUFFER, 0);
293 
294  if (outputToIOSurface)
295  {
296  surfID = VuoIoSurfacePool_getId(ioSurface);
297  VuoIoSurfacePool_disuse(ioSurface, true); // We may be sending it to another process, so we need to quarantine it.
298  }
299 
300  glFlushRenderAPPLE();
301  });
302 
303  if (outputToIOSurface)
304  return surfID;
305  else
306  return outputTexture;
307 }
308 
314 static void VuoImageRenderer_fini(void)
315 {
316  VuoGlContext_perform(^(CGLContextObj cgl_ctx){
317  glBindBuffer(GL_ARRAY_BUFFER, 0);
318 
319  VuoGlPool_release(VuoGlPool_ArrayBuffer, sizeof(quadData), VuoImageRendererGlobal.quadDataBuffer);
320 
322  glDeleteFramebuffers(1, &VuoImageRendererGlobal.outputFramebuffer);
323  });
324 }