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