1 
2 #ifdef HAVE_CONFIG_H
3 #include "config.h"
4 #endif
5 #include <schroedinger/schrodebug.h>
6 #include <schroedinger/opengl/schroopengl.h>
7 #include <schroedinger/opengl/schroopenglcanvas.h>
8 #include <schroedinger/opengl/schroopenglframe.h>
9 #include <schroedinger/opengl/schroopenglshader.h>
10 #include <orc/orc.h>
11 
12 static void
schro_opengl_canvas_push_convert(SchroOpenGLCanvas * dest,SchroFrameData * src,void * texture_data,int y_offset,int height)13 schro_opengl_canvas_push_convert (SchroOpenGLCanvas *dest, SchroFrameData *src,
14     void *texture_data, int y_offset, int height)
15 {
16   int x, y;
17   int width;
18   int frame_stride, texture_stride, texture_channels;
19   uint8_t *frame_data_u8 = NULL;
20   int16_t *frame_data_s16 = NULL;
21   uint8_t *texture_data_u8 = NULL;
22   uint16_t *texture_data_u16 = NULL;
23   int16_t *texture_data_s16 = NULL;
24   float *texture_data_f32 = NULL;
25 
26   SCHRO_ASSERT (dest != NULL);
27   SCHRO_ASSERT (src != NULL);
28   SCHRO_ASSERT (dest->format == src->format);
29   SCHRO_ASSERT (dest->width == src->width);
30   SCHRO_ASSERT (dest->height == src->height);
31   SCHRO_ASSERT (texture_data != NULL);
32 
33   width = src->width;
34   frame_stride = src->stride;
35   texture_stride = dest->push.stride;
36   texture_channels = SCHRO_FRAME_IS_PACKED (src->format)
37       ? 1 : dest->texture.channels;
38 
39   switch (SCHRO_FRAME_FORMAT_DEPTH (src->format)) {
40     case SCHRO_FRAME_FORMAT_DEPTH_U8:
41       frame_data_u8 = SCHRO_FRAME_DATA_GET_LINE (src, y_offset);
42 
43       if (SCHRO_OPENGL_CANVAS_IS_FLAG_SET (PUSH_U8_AS_F32)) {
44         texture_data_f32 = (float *) texture_data;
45 
46         for (y = 0; y < height; ++y) {
47           for (x = 0; x < width; ++x) {
48             texture_data_f32[x * texture_channels]
49                 = (float) frame_data_u8[x] / 255.0;
50           }
51 
52           texture_data_f32 = OFFSET (texture_data_f32, texture_stride);
53           frame_data_u8 = OFFSET (frame_data_u8, frame_stride);
54         }
55       } else {
56         texture_data_u8 = (uint8_t *) texture_data;
57 
58         if (texture_channels > 1) {
59           for (y = 0; y < height; ++y) {
60             for (x = 0; x < width; ++x) {
61               texture_data_u8[x * texture_channels] = frame_data_u8[x];
62             }
63 
64             texture_data_u8 = OFFSET (texture_data_u8, texture_stride);
65             frame_data_u8 = OFFSET (frame_data_u8, frame_stride);
66           }
67         } else {
68           for (y = 0; y < height; ++y) {
69             orc_memcpy (texture_data_u8, frame_data_u8, width);
70 
71             texture_data_u8 = OFFSET (texture_data_u8, texture_stride);
72             frame_data_u8 = OFFSET (frame_data_u8, frame_stride);
73           }
74         }
75       }
76 
77       break;
78     case SCHRO_FRAME_FORMAT_DEPTH_S16:
79       frame_data_s16 = SCHRO_FRAME_DATA_GET_LINE (src, y_offset);
80 
81       if (SCHRO_OPENGL_CANVAS_IS_FLAG_SET (PUSH_S16_AS_U16)) {
82         texture_data_u16 = (uint16_t *) texture_data;
83 
84         for (y = 0; y < height; ++y) {
85           for (x = 0; x < width; ++x) {
86             texture_data_u16[x * texture_channels]
87                 = (uint16_t) ((int32_t) frame_data_s16[x] + 32768);
88           }
89 
90           texture_data_u16 = OFFSET (texture_data_u16, texture_stride);
91           frame_data_s16 = OFFSET (frame_data_s16, frame_stride);
92         }
93       } else if (SCHRO_OPENGL_CANVAS_IS_FLAG_SET (PUSH_S16_AS_F32)) {
94         texture_data_f32 = (float *) texture_data;
95 
96         for (y = 0; y < height; ++y) {
97           for (x = 0; x < width; ++x) {
98             texture_data_f32[x * texture_channels]
99                 = (float) ((int32_t) frame_data_s16[x] + 32768) / 65535.0;
100           }
101 
102           texture_data_f32 = OFFSET (texture_data_f32, texture_stride);
103           frame_data_s16 = OFFSET (frame_data_s16, frame_stride);
104         }
105       } else {
106         texture_data_s16 = (int16_t *) texture_data;
107 
108         if (texture_channels > 1) {
109           for (y = 0; y < height; ++y) {
110             for (x = 0; x < width; ++x) {
111               texture_data_s16[x * texture_channels] = frame_data_s16[x];
112             }
113 
114             texture_data_s16 = OFFSET (texture_data_s16, texture_stride);
115             frame_data_s16 = OFFSET (frame_data_s16, frame_stride);
116           }
117         } else {
118           for (y = 0; y < height; ++y) {
119             orc_memcpy (texture_data_s16, frame_data_s16,
120                 width * sizeof (int16_t));
121 
122             texture_data_s16 = OFFSET (texture_data_s16, texture_stride);
123             frame_data_s16 = OFFSET (frame_data_s16, frame_stride);
124           }
125         }
126       }
127 
128       break;
129     default:
130       SCHRO_ASSERT (0);
131       break;
132   }
133 }
134 
135 void
schro_opengl_frame_push(SchroFrame * dest,SchroFrame * src)136 schro_opengl_frame_push (SchroFrame *dest, SchroFrame *src)
137 {
138   int i;
139   int components;
140   SchroOpenGLCanvas *dest_canvas = NULL;
141   SchroOpenGL *opengl = NULL;
142 
143   SCHRO_ASSERT (dest != NULL);
144   SCHRO_ASSERT (src != NULL);
145   SCHRO_ASSERT (SCHRO_FRAME_IS_OPENGL (dest));
146   SCHRO_ASSERT (!SCHRO_FRAME_IS_OPENGL (src));
147   SCHRO_ASSERT (dest->format == src->format);
148 
149   components = SCHRO_FRAME_IS_PACKED (src->format) ? 1 : 3;
150   // FIXME: hack to store custom data per frame component
151   dest_canvas = *((SchroOpenGLCanvas **) dest->components[0].data);
152 
153   SCHRO_ASSERT (dest_canvas != NULL);
154 
155   opengl = dest_canvas->opengl;
156 
157   schro_opengl_lock (opengl);
158 
159   for (i = 0; i < components; ++i) {
160     // FIXME: hack to store custom data per frame component
161     dest_canvas = *((SchroOpenGLCanvas **) dest->components[i].data);
162 
163     schro_opengl_canvas_push (dest_canvas, src->components + i);
164   }
165 
166   schro_opengl_unlock (opengl);
167 }
168 
169 void
schro_opengl_canvas_push(SchroOpenGLCanvas * dest,SchroFrameData * src)170 schro_opengl_canvas_push (SchroOpenGLCanvas *dest, SchroFrameData *src)
171 {
172   int i;
173   int width, height, depth;
174   int pixelbuffer_y_offset, pixelbuffer_height;
175   GLuint src_texture = 0; // FIXME: don't create a new locale texture here
176                           // but use a single global texture for such temporary
177                           // purpose
178   void *mapped_data = NULL;
179   void *tmp_data = NULL;
180   SchroOpenGLShader *shader;
181 
182   SCHRO_ASSERT (dest->format == src->format);
183   SCHRO_ASSERT (dest->width == src->width);
184   SCHRO_ASSERT (dest->height == src->height);
185   SCHRO_ASSERT (dest->texture.handles[0] != 0);
186   SCHRO_ASSERT (dest->texture.handles[1] != 0);
187   SCHRO_ASSERT (dest->framebuffers[0] != 0);
188   SCHRO_ASSERT (dest->framebuffers[1] != 0);
189 
190   width = src->width;
191   height = src->height;
192   depth = SCHRO_FRAME_FORMAT_DEPTH (src->format);
193 
194   schro_opengl_lock (dest->opengl);
195 
196   if (SCHRO_OPENGL_CANVAS_IS_FLAG_SET (PUSH_RENDER_QUAD)) {
197     glGenTextures (1, &src_texture);
198     glBindTexture (GL_TEXTURE_RECTANGLE_ARB, src_texture);
199     glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, dest->texture.internal_format,
200         width, height, 0, dest->texture.pixel_format, dest->texture.type, NULL);
201     glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER,
202         GL_NEAREST);
203     glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER,
204         GL_NEAREST);
205     glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
206     glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);
207     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
208 
209     SCHRO_OPENGL_CHECK_ERROR
210   }
211 
212   if ((SCHRO_OPENGL_CANVAS_IS_FLAG_SET (PUSH_U8_PIXELBUFFER) &&
213       depth == SCHRO_FRAME_FORMAT_DEPTH_U8) ||
214       (SCHRO_OPENGL_CANVAS_IS_FLAG_SET (PUSH_S16_PIXELBUFFER) &&
215       depth == SCHRO_FRAME_FORMAT_DEPTH_S16)) {
216     pixelbuffer_y_offset = 0;
217 
218     for (i = 0; i < SCHRO_OPENGL_TRANSFER_PIXELBUFFERS; ++i) {
219       pixelbuffer_height = dest->push.heights[i];
220 
221       glBindBufferARB (GL_PIXEL_UNPACK_BUFFER_EXT, dest->push.pixelbuffers[i]);
222       glBufferDataARB (GL_PIXEL_UNPACK_BUFFER_ARB,
223           dest->push.stride * pixelbuffer_height, NULL, GL_STREAM_DRAW_ARB);
224 
225       mapped_data = glMapBufferARB (GL_PIXEL_UNPACK_BUFFER_EXT,
226           GL_WRITE_ONLY_ARB);
227 
228       schro_opengl_canvas_push_convert (dest, src, mapped_data,
229           pixelbuffer_y_offset, pixelbuffer_height);
230 
231       glUnmapBufferARB (GL_PIXEL_UNPACK_BUFFER_EXT);
232 
233       pixelbuffer_y_offset += pixelbuffer_height;
234 
235       SCHRO_OPENGL_CHECK_ERROR
236     }
237 
238     if (!SCHRO_OPENGL_CANVAS_IS_FLAG_SET (PUSH_RENDER_QUAD)) {
239       glBindTexture (GL_TEXTURE_RECTANGLE_ARB, dest->texture.handles[0]);
240     }
241 
242     pixelbuffer_y_offset = 0;
243 
244     if (dest->push.type == GL_SHORT) {
245       /* OpenGL maps signed values different to float values than unsigned
246          values. for S16 -32768 is mapped to -1.0 and 32767 to 1.0, for U16
247          0 is mapped to 0.0 and 65535 to 1.0. after this mapping scale and
248          bias are applied and the resulting value is clamped to [0..1].
249          with default scale = 1 and default bias = 0 all negative values
250          from S16 are clamped to 0.0, changing scale and bias to 0.5 gives
251          a unclamped mapping that doesn't discard all negative values for S16 */
252       glPixelTransferf (GL_RED_SCALE, 0.5);
253       glPixelTransferf (GL_RED_BIAS, 0.5);
254     }
255 
256     for (i = 0; i < SCHRO_OPENGL_TRANSFER_PIXELBUFFERS; ++i) {
257       pixelbuffer_height = dest->push.heights[i];
258 
259       glBindBufferARB (GL_PIXEL_UNPACK_BUFFER_EXT, dest->push.pixelbuffers[i]);
260 
261       SCHRO_OPENGL_CHECK_ERROR
262 
263       if (SCHRO_OPENGL_CANVAS_IS_FLAG_SET (PUSH_DRAWPIXELS)) {
264         glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, dest->framebuffers[0]);
265 
266         glWindowPos2iARB (0, pixelbuffer_y_offset);
267         glDrawPixels (width, pixelbuffer_height, dest->texture.pixel_format,
268             dest->push.type, NULL);
269 
270         glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
271       } else {
272         glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, pixelbuffer_y_offset,
273             width, pixelbuffer_height, dest->texture.pixel_format,
274             dest->push.type, NULL);
275       }
276 
277       SCHRO_OPENGL_CHECK_ERROR
278 
279       pixelbuffer_y_offset += pixelbuffer_height;
280     }
281 
282     if (dest->push.type == GL_SHORT) {
283       glPixelTransferf (GL_RED_SCALE, 1);
284       glPixelTransferf (GL_RED_BIAS, 0);
285     }
286 
287     glBindBufferARB (GL_PIXEL_UNPACK_BUFFER_EXT, 0);
288   } else {
289     tmp_data = schro_opengl_get_tmp (dest->opengl, dest->push.stride * height);
290 
291     schro_opengl_canvas_push_convert (dest, src, tmp_data, 0, height);
292 
293     if (!SCHRO_OPENGL_CANVAS_IS_FLAG_SET (PUSH_RENDER_QUAD)) {
294       glBindTexture (GL_TEXTURE_RECTANGLE_ARB, dest->texture.handles[0]);
295     }
296 
297     if (dest->push.type == GL_SHORT) {
298       /* OpenGL maps signed values different to float values than unsigned
299          values. for S16 -32768 is mapped to -1.0 and 32767 to 1.0, for U16
300          0 is mapped to 0.0 and 65535 to 1.0. after this mapping scale and
301          bias are applied and the resulting value is clamped to [0..1].
302          with default scale = 1 and default bias = 0 all negative values
303          from S16 are clamped to 0.0, changing scale and bias to 0.5 gives
304          a unclamped mapping that doesn't discard all negative values for S16 */
305       glPixelTransferf (GL_RED_SCALE, 0.5);
306       glPixelTransferf (GL_RED_BIAS, 0.5);
307     }
308 
309     if (SCHRO_OPENGL_CANVAS_IS_FLAG_SET (PUSH_DRAWPIXELS)) {
310       glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, dest->framebuffers[0]);
311 
312       glWindowPos2iARB (0, 0);
313       glDrawPixels (width, height, dest->texture.pixel_format, dest->push.type,
314           tmp_data);
315 
316       glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
317     } else {
318       glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height,
319           dest->texture.pixel_format, dest->push.type, tmp_data);
320     }
321 
322     if (dest->push.type == GL_SHORT) {
323       glPixelTransferf (GL_RED_SCALE, 1);
324       glPixelTransferf (GL_RED_BIAS, 0);
325     }
326   }
327 
328   SCHRO_OPENGL_CHECK_ERROR
329 
330   if (SCHRO_OPENGL_CANVAS_IS_FLAG_SET (PUSH_RENDER_QUAD)) {
331     schro_opengl_setup_viewport (width, height);
332 
333     glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, dest->framebuffers[0]);
334 
335     SCHRO_OPENGL_CHECK_ERROR
336 
337     if (SCHRO_OPENGL_CANVAS_IS_FLAG_SET (PUSH_SHADER)) {
338       switch (SCHRO_FRAME_FORMAT_DEPTH (src->format)) {
339         case SCHRO_FRAME_FORMAT_DEPTH_U8:
340           shader = schro_opengl_shader_get (dest->opengl,
341              SCHRO_OPENGL_SHADER_COPY_U8);
342             break;
343         case SCHRO_FRAME_FORMAT_DEPTH_S16:
344           shader = schro_opengl_shader_get (dest->opengl,
345              SCHRO_OPENGL_SHADER_COPY_S16);
346           break;
347         default:
348           SCHRO_ASSERT (0);
349           break;
350       }
351 
352       glUseProgramObjectARB (shader->program);
353       glUniform1iARB (shader->textures[0], 0);
354     }
355 
356     schro_opengl_render_quad (0, 0, width, height);
357 
358     if (SCHRO_OPENGL_CANVAS_IS_FLAG_SET (PUSH_SHADER)) {
359       glUseProgramObjectARB (0);
360     }
361 
362     glFlush ();
363 
364     glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
365 
366     SCHRO_OPENGL_CHECK_ERROR
367   }
368 
369 #if SCHRO_OPENGL_UNBIND_TEXTURES
370   glBindTexture (GL_TEXTURE_RECTANGLE_ARB, 0);
371 #endif
372 
373   if (SCHRO_OPENGL_CANVAS_IS_FLAG_SET (PUSH_RENDER_QUAD)) {
374     glDeleteTextures (1, &src_texture);
375   }
376 
377   schro_opengl_unlock (dest->opengl);
378 }
379 
380