Vuo  2.4.1
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
84static bool VuoImageRenderer_initialized = false;
85
89static void VuoImageRenderer_init(void)
90{
91 static dispatch_once_t once = 0;
92 dispatch_once(&once, ^{
94
95 VuoGlContext_perform(^(CGLContextObj cgl_ctx){
98 {
99 VuoImageRendererGlobal.quadDataBuffer = VuoGlPool_use(cgl_ctx, VuoGlPool_ArrayBuffer, sizeof(quadData));
101 glBindBuffer(GL_ARRAY_BUFFER, VuoImageRendererGlobal.quadDataBuffer);
102 glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(quadData), quadData);
103 }
105
106 glFlushRenderAPPLE();
107
108 glGenFramebuffers(1, &VuoImageRendererGlobal.outputFramebuffer);
109 });
110 });
111}
112
116extern "C" VuoImage VuoImageRenderer_draw(void *ir, VuoShader shader, unsigned int pixelsWide, unsigned int pixelsHigh, VuoImageColorDepth imageColorDepth)
117{
118 return VuoImageRenderer_render(shader, pixelsWide, pixelsHigh, imageColorDepth);
119}
120
124extern "C" void *VuoImageRenderer_make(void *)
125{
126 return NULL;
127}
128
134VuoImage VuoImageRenderer_render(VuoShader shader, unsigned int pixelsWide, unsigned int pixelsHigh, VuoImageColorDepth imageColorDepth)
135{
136 if (pixelsWide < 1 || pixelsHigh < 1)
137 return NULL;
138
139 GLuint internalFormat;
140 GLuint outputTexture = VuoImageRenderer_draw_internal(shader, pixelsWide, pixelsHigh, imageColorDepth, false, false, 0, &internalFormat);
141 if (!outputTexture)
142 return NULL;
143
144 VuoImage outputImage = VuoImage_make(outputTexture, internalFormat, pixelsWide, pixelsHigh);
145
146 VuoImage firstInputImage = VuoShader_getFirstImage(shader);
147 if (firstInputImage)
148 outputImage->scaleFactor = firstInputImage->scaleFactor;
149
150 return outputImage;
151}
152
158unsigned long int VuoImageRenderer_draw_internal(VuoShader shader, unsigned int pixelsWide, unsigned int pixelsHigh, VuoImageColorDepth imageColorDepth, bool outputToIOSurface, bool outputToGlTextureRectangle, unsigned int outputToSpecificTexture, GLuint *outputInternalFormat)
159{
161
162 __block GLuint outputTexture = 0;
163 __block IOSurfaceID surfID = 0;
164 VuoGlContext_perform(^(CGLContextObj cgl_ctx){
165 glViewport(0, 0, pixelsWide, pixelsHigh);
166
167 // Create a new GL Texture Object.
168 bool shaderOpaque = VuoShader_isOpaque(shader);
169 GLenum textureFormat = shaderOpaque ? GL_BGR : GL_BGRA;
170 GLuint textureTarget = (outputToIOSurface || outputToGlTextureRectangle) ? GL_TEXTURE_RECTANGLE_ARB : GL_TEXTURE_2D;
171 GLuint textureTargetInternalFormat = VuoImageColorDepth_getGlInternalFormat(textureFormat, imageColorDepth);
172 if (outputInternalFormat)
173 *outputInternalFormat = textureTargetInternalFormat;
174
175 VuoIoSurface ioSurface = NULL;
176 if (outputToIOSurface)
178 ioSurface = VuoIoSurfacePool_use(cgl_ctx, pixelsWide, pixelsHigh, &outputTexture);
179 else if (outputToSpecificTexture)
180 outputTexture = outputToSpecificTexture;
181 else
182 outputTexture = VuoGlTexturePool_use(cgl_ctx, VuoGlTexturePool_Allocate, outputToGlTextureRectangle ? GL_TEXTURE_RECTANGLE_ARB : GL_TEXTURE_2D, textureTargetInternalFormat, pixelsWide, pixelsHigh, textureFormat, NULL);
183
184 if (!outputTexture)
185 return;
186
187 glBindFramebuffer(GL_FRAMEBUFFER, VuoImageRendererGlobal.outputFramebuffer);
188// VLog("glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, %s, %d, 0);", VuoGl_stringForConstant(textureTarget), outputTexture);
189 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureTarget, outputTexture, 0);
190
191 if (!shaderOpaque)
192 {
193 glClearColor(0,0,0,0);
194 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
195 }
196
197 // Execute the shader.
198 {
199 GLint positionAttribute;
200 GLint textureCoordinateAttribute;
201 bool ret = VuoShader_getAttributeLocations(shader, VuoMesh_IndividualTriangles, cgl_ctx, &positionAttribute, NULL, &textureCoordinateAttribute, NULL);
202 if (!ret)
203 {
204 VDebugLog("Error: Failed to get attribute locations.");
205 glBindFramebuffer(GL_FRAMEBUFFER, 0);
206 if (outputToIOSurface)
207 VuoIoSurfacePool_disuse(ioSurface, false); // It was never used, so no need to quarantine it.
208 else if (outputToSpecificTexture)
209 {}
210 else
211 {
212 VuoGlTexture_retain(outputTexture, NULL, NULL);
213 VuoGlTexture_release(VuoGlTexturePool_Allocate, outputToGlTextureRectangle ? GL_TEXTURE_RECTANGLE_ARB : GL_TEXTURE_2D, textureTargetInternalFormat, pixelsWide, pixelsHigh, outputTexture);
214 }
215 outputTexture = 0;
216 surfID = 0;
217 return;
218 }
219
220 VuoGlProgram program;
221 if (!VuoShader_activate(shader, VuoMesh_IndividualTriangles, cgl_ctx, &program))
222 {
223 VUserLog("Shader activation failed.");
224 outputTexture = 0;
225 surfID = 0;
226 return;
227 }
228
229 {
231
232 GLint projectionMatrixUniform = VuoGlProgram_getUniformLocation(program, "projectionMatrix");
233 glUniformMatrix4fv(projectionMatrixUniform, 1, GL_FALSE, unityMatrix);
234
235 GLint cameraMatrixInverseUniform = VuoGlProgram_getUniformLocation(program, "cameraMatrixInverse");
236 glUniformMatrix4fv(cameraMatrixInverseUniform, 1, GL_FALSE, unityMatrix);
237
238 GLint useFisheyeProjectionUniform = VuoGlProgram_getUniformLocation(program, "useFisheyeProjection");
239 glUniform1i(useFisheyeProjectionUniform, false);
240
241 GLint modelviewMatrixUniform = VuoGlProgram_getUniformLocation(program, "modelviewMatrix");
242 glUniformMatrix4fv(modelviewMatrixUniform, 1, GL_FALSE, unityMatrix);
243
244 GLint aspectRatioUniform = VuoGlProgram_getUniformLocation(program, "aspectRatio");
245 if (aspectRatioUniform != -1)
246 glUniform1f(aspectRatioUniform, (float)pixelsWide/(float)pixelsHigh);
247
248 GLint viewportSizeUniform = VuoGlProgram_getUniformLocation(program, "viewportSize");
249 if (viewportSizeUniform != -1)
250 glUniform2f(viewportSizeUniform, (float)pixelsWide, (float)pixelsHigh);
251
252 glBindBuffer(GL_ARRAY_BUFFER, VuoImageRendererGlobal.quadDataBuffer);
253
254 glEnableVertexAttribArray(positionAttribute);
255 glVertexAttribPointer(positionAttribute, 4 /* XYZW */, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*4, (void*)0);
256
257 if (textureCoordinateAttribute != -1)
258 {
259 glEnableVertexAttribArray(textureCoordinateAttribute);
260 glVertexAttribPointer(textureCoordinateAttribute, 4 /* XYZW */, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*4, (void*)(sizeof(GLfloat)*16));
261 }
262
263#ifdef VUO_PROFILE
264 GLuint timeElapsedQuery;
265 glGenQueries(1, &timeElapsedQuery);
266 glBeginQuery(GL_TIME_ELAPSED_EXT, timeElapsedQuery);
267#endif
268
269 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
270
271#ifdef VUO_PROFILE
272 double seconds;
273 glEndQuery(GL_TIME_ELAPSED_EXT);
274 GLuint nanoseconds;
275 glGetQueryObjectuiv(timeElapsedQuery, GL_QUERY_RESULT, &nanoseconds);
276 seconds = ((double)nanoseconds) / NSEC_PER_SEC;
277 glDeleteQueries(1, &timeElapsedQuery);
278
279 double objectPercent = seconds / (1./60.) * 100.;
280 VLog("%6.2f %% of 60 Hz frame %s", objectPercent, shader->name);
281#endif
282
283 if (textureCoordinateAttribute != -1)
284 glDisableVertexAttribArray(textureCoordinateAttribute);
285
286 glDisableVertexAttribArray(positionAttribute);
287
288 glBindBuffer(GL_ARRAY_BUFFER, 0);
290 }
292 }
293
294 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureTarget, 0, 0);
295 glBindFramebuffer(GL_FRAMEBUFFER, 0);
296
297 if (outputToIOSurface)
298 {
299 surfID = VuoIoSurfacePool_getId(ioSurface);
300 VuoIoSurfacePool_disuse(ioSurface, true); // We may be sending it to another process, so we need to quarantine it.
301 }
302
303 glFlushRenderAPPLE();
304 });
305
306 if (outputToIOSurface)
307 return surfID;
308 else
309 return outputTexture;
310}
311
317extern "C" void VuoImageRenderer_fini(void)
318{
320 return;
321
322 static dispatch_once_t once = 0;
323 dispatch_once(&once, ^{
324 VuoGlContext_perform(^(CGLContextObj cgl_ctx){
325 glBindBuffer(GL_ARRAY_BUFFER, 0);
326
327 VuoGlPool_release(VuoGlPool_ArrayBuffer, sizeof(quadData), VuoImageRendererGlobal.quadDataBuffer);
328
330 glDeleteFramebuffers(1, &VuoImageRendererGlobal.outputFramebuffer);
331 });
332 });
333}