Vuo  2.0.2
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  GLenum textureFormat = VuoShader_isOpaque(shader) ? GL_BGR : GL_BGRA;
166  GLuint textureTarget = (outputToIOSurface || outputToGlTextureRectangle) ? GL_TEXTURE_RECTANGLE_ARB : GL_TEXTURE_2D;
167  GLuint textureTargetInternalFormat = VuoImageColorDepth_getGlInternalFormat(textureFormat, imageColorDepth);
168  if (outputInternalFormat)
169  *outputInternalFormat = textureTargetInternalFormat;
170 
171  VuoIoSurface ioSurface = NULL;
172  if (outputToIOSurface)
174  ioSurface = VuoIoSurfacePool_use(cgl_ctx, pixelsWide, pixelsHigh, &outputTexture);
175  else if (outputToSpecificTexture)
176  outputTexture = outputToSpecificTexture;
177  else
178  outputTexture = VuoGlTexturePool_use(cgl_ctx, VuoGlTexturePool_Allocate, outputToGlTextureRectangle ? GL_TEXTURE_RECTANGLE_ARB : GL_TEXTURE_2D, textureTargetInternalFormat, pixelsWide, pixelsHigh, textureFormat, NULL);
179 
180  if (!outputTexture)
181  return;
182 
183  glBindFramebuffer(GL_FRAMEBUFFER, VuoImageRendererGlobal.outputFramebuffer);
184 // VLog("glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, %s, %d, 0);", VuoGl_stringForConstant(textureTarget), outputTexture);
185  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureTarget, outputTexture, 0);
186 
187  glClearColor(0,0,0,0);
188  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
189 
190  // Execute the shader.
191  {
192  GLint positionAttribute;
193  GLint textureCoordinateAttribute;
194  bool ret = VuoShader_getAttributeLocations(shader, VuoMesh_IndividualTriangles, cgl_ctx, &positionAttribute, NULL, &textureCoordinateAttribute, NULL);
195  if (!ret)
196  {
197  VDebugLog("Error: Failed to get attribute locations.");
198  glBindFramebuffer(GL_FRAMEBUFFER, 0);
199  if (outputToIOSurface)
200  VuoIoSurfacePool_disuse(ioSurface, false); // It was never used, so no need to quarantine it.
201  else if (outputToSpecificTexture)
202  {}
203  else
204  {
205  VuoGlTexture_retain(outputTexture, NULL, NULL);
206  VuoGlTexture_release(VuoGlTexturePool_Allocate, outputToGlTextureRectangle ? GL_TEXTURE_RECTANGLE_ARB : GL_TEXTURE_2D, textureTargetInternalFormat, pixelsWide, pixelsHigh, outputTexture);
207  }
208  outputTexture = 0;
209  surfID = 0;
210  return;
211  }
212 
213  VuoGlProgram program;
214  if (!VuoShader_activate(shader, VuoMesh_IndividualTriangles, cgl_ctx, &program))
215  {
216  VUserLog("Shader activation failed.");
217  outputTexture = 0;
218  surfID = 0;
219  return;
220  }
221 
222  {
224 
225  GLint projectionMatrixUniform = VuoGlProgram_getUniformLocation(program, "projectionMatrix");
226  glUniformMatrix4fv(projectionMatrixUniform, 1, GL_FALSE, unityMatrix);
227 
228  GLint cameraMatrixInverseUniform = VuoGlProgram_getUniformLocation(program, "cameraMatrixInverse");
229  glUniformMatrix4fv(cameraMatrixInverseUniform, 1, GL_FALSE, unityMatrix);
230 
231  GLint useFisheyeProjectionUniform = VuoGlProgram_getUniformLocation(program, "useFisheyeProjection");
232  glUniform1i(useFisheyeProjectionUniform, false);
233 
234  GLint modelviewMatrixUniform = VuoGlProgram_getUniformLocation(program, "modelviewMatrix");
235  glUniformMatrix4fv(modelviewMatrixUniform, 1, GL_FALSE, unityMatrix);
236 
237  GLint aspectRatioUniform = VuoGlProgram_getUniformLocation(program, "aspectRatio");
238  if (aspectRatioUniform != -1)
239  glUniform1f(aspectRatioUniform, (float)pixelsWide/(float)pixelsHigh);
240 
241  GLint viewportSizeUniform = VuoGlProgram_getUniformLocation(program, "viewportSize");
242  if (viewportSizeUniform != -1)
243  glUniform2f(viewportSizeUniform, (float)pixelsWide, (float)pixelsHigh);
244 
245  glBindBuffer(GL_ARRAY_BUFFER, VuoImageRendererGlobal.quadDataBuffer);
246 
247  glEnableVertexAttribArray(positionAttribute);
248  glVertexAttribPointer(positionAttribute, 4 /* XYZW */, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*4, (void*)0);
249 
250  if (textureCoordinateAttribute != -1)
251  {
252  glEnableVertexAttribArray(textureCoordinateAttribute);
253  glVertexAttribPointer(textureCoordinateAttribute, 4 /* XYZW */, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*4, (void*)(sizeof(GLfloat)*16));
254  }
255 
256 #ifdef VUO_PROFILE
257  GLuint timeElapsedQuery;
258  glGenQueries(1, &timeElapsedQuery);
259  glBeginQuery(GL_TIME_ELAPSED_EXT, timeElapsedQuery);
260 #endif
261 
262  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
263 
264 #ifdef VUO_PROFILE
265  double seconds;
266  glEndQuery(GL_TIME_ELAPSED_EXT);
267  GLuint nanoseconds;
268  glGetQueryObjectuiv(timeElapsedQuery, GL_QUERY_RESULT, &nanoseconds);
269  seconds = ((double)nanoseconds) / NSEC_PER_SEC;
270  glDeleteQueries(1, &timeElapsedQuery);
271 
272  double objectPercent = seconds / (1./60.) * 100.;
273  VLog("%6.2f %% of 60 Hz frame %s", objectPercent, shader->name);
274 #endif
275 
276  if (textureCoordinateAttribute != -1)
277  glDisableVertexAttribArray(textureCoordinateAttribute);
278 
279  glDisableVertexAttribArray(positionAttribute);
280 
281  glBindBuffer(GL_ARRAY_BUFFER, 0);
283  }
285  }
286 
287  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureTarget, 0, 0);
288  glBindFramebuffer(GL_FRAMEBUFFER, 0);
289 
290  if (outputToIOSurface)
291  {
292  surfID = VuoIoSurfacePool_getId(ioSurface);
293  VuoIoSurfacePool_disuse(ioSurface, true); // We may be sending it to another process, so we need to quarantine it.
294  }
295 
296  glFlushRenderAPPLE();
297  });
298 
299  if (outputToIOSurface)
300  return surfID;
301  else
302  return outputTexture;
303 }
304 
310 static void VuoImageRenderer_fini(void)
311 {
312  VuoGlContext_perform(^(CGLContextObj cgl_ctx){
313  glBindBuffer(GL_ARRAY_BUFFER, 0);
314 
315  VuoGlPool_release(VuoGlPool_ArrayBuffer, sizeof(quadData), VuoImageRendererGlobal.quadDataBuffer);
316 
318  glDeleteFramebuffers(1, &VuoImageRendererGlobal.outputFramebuffer);
319  });
320 }