Vuo  2.4.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
21
22#include "module.h"
23extern "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
58static 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};
74static 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
81static void VuoImageRenderer_fini(void);
82
86static 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
113extern "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
121extern "C" void *VuoImageRenderer_make(void *)
122{
123 return NULL;
124}
125
131VuoImage 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
155unsigned 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
314static 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}