tests: fix build on os/x
[schroedinger.git] / schroedinger / opengl / schroopenglframe_push.c
blob61d78b5a5b4e5dd7a54744be740c47dee19068ae
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>
12 static void
13 schro_opengl_canvas_push_convert (SchroOpenGLCanvas *dest, SchroFrameData *src,
14 void *texture_data, int y_offset, int height)
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;
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);
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;
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);
43 if (SCHRO_OPENGL_CANVAS_IS_FLAG_SET (PUSH_U8_AS_F32)) {
44 texture_data_f32 = (float *) texture_data;
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;
52 texture_data_f32 = OFFSET (texture_data_f32, texture_stride);
53 frame_data_u8 = OFFSET (frame_data_u8, frame_stride);
55 } else {
56 texture_data_u8 = (uint8_t *) texture_data;
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];
64 texture_data_u8 = OFFSET (texture_data_u8, texture_stride);
65 frame_data_u8 = OFFSET (frame_data_u8, frame_stride);
67 } else {
68 for (y = 0; y < height; ++y) {
69 orc_memcpy (texture_data_u8, frame_data_u8, width);
71 texture_data_u8 = OFFSET (texture_data_u8, texture_stride);
72 frame_data_u8 = OFFSET (frame_data_u8, frame_stride);
77 break;
78 case SCHRO_FRAME_FORMAT_DEPTH_S16:
79 frame_data_s16 = SCHRO_FRAME_DATA_GET_LINE (src, y_offset);
81 if (SCHRO_OPENGL_CANVAS_IS_FLAG_SET (PUSH_S16_AS_U16)) {
82 texture_data_u16 = (uint16_t *) texture_data;
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);
90 texture_data_u16 = OFFSET (texture_data_u16, texture_stride);
91 frame_data_s16 = OFFSET (frame_data_s16, frame_stride);
93 } else if (SCHRO_OPENGL_CANVAS_IS_FLAG_SET (PUSH_S16_AS_F32)) {
94 texture_data_f32 = (float *) texture_data;
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;
102 texture_data_f32 = OFFSET (texture_data_f32, texture_stride);
103 frame_data_s16 = OFFSET (frame_data_s16, frame_stride);
105 } else {
106 texture_data_s16 = (int16_t *) texture_data;
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];
114 texture_data_s16 = OFFSET (texture_data_s16, texture_stride);
115 frame_data_s16 = OFFSET (frame_data_s16, frame_stride);
117 } else {
118 for (y = 0; y < height; ++y) {
119 orc_memcpy (texture_data_s16, frame_data_s16,
120 width * sizeof (int16_t));
122 texture_data_s16 = OFFSET (texture_data_s16, texture_stride);
123 frame_data_s16 = OFFSET (frame_data_s16, frame_stride);
128 break;
129 default:
130 SCHRO_ASSERT (0);
131 break;
135 void
136 schro_opengl_frame_push (SchroFrame *dest, SchroFrame *src)
138 int i;
139 int components;
140 SchroOpenGLCanvas *dest_canvas = NULL;
141 SchroOpenGL *opengl = NULL;
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);
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);
153 SCHRO_ASSERT (dest_canvas != NULL);
155 opengl = dest_canvas->opengl;
157 schro_opengl_lock (opengl);
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);
163 schro_opengl_canvas_push (dest_canvas, src->components + i);
166 schro_opengl_unlock (opengl);
169 void
170 schro_opengl_canvas_push (SchroOpenGLCanvas *dest, SchroFrameData *src)
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;
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);
190 width = src->width;
191 height = src->height;
192 depth = SCHRO_FRAME_FORMAT_DEPTH (src->format);
194 schro_opengl_lock (dest->opengl);
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);
209 SCHRO_OPENGL_CHECK_ERROR
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;
218 for (i = 0; i < SCHRO_OPENGL_TRANSFER_PIXELBUFFERS; ++i) {
219 pixelbuffer_height = dest->push.heights[i];
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);
225 mapped_data = glMapBufferARB (GL_PIXEL_UNPACK_BUFFER_EXT,
226 GL_WRITE_ONLY_ARB);
228 schro_opengl_canvas_push_convert (dest, src, mapped_data,
229 pixelbuffer_y_offset, pixelbuffer_height);
231 glUnmapBufferARB (GL_PIXEL_UNPACK_BUFFER_EXT);
233 pixelbuffer_y_offset += pixelbuffer_height;
235 SCHRO_OPENGL_CHECK_ERROR
238 if (!SCHRO_OPENGL_CANVAS_IS_FLAG_SET (PUSH_RENDER_QUAD)) {
239 glBindTexture (GL_TEXTURE_RECTANGLE_ARB, dest->texture.handles[0]);
242 pixelbuffer_y_offset = 0;
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);
256 for (i = 0; i < SCHRO_OPENGL_TRANSFER_PIXELBUFFERS; ++i) {
257 pixelbuffer_height = dest->push.heights[i];
259 glBindBufferARB (GL_PIXEL_UNPACK_BUFFER_EXT, dest->push.pixelbuffers[i]);
261 SCHRO_OPENGL_CHECK_ERROR
263 if (SCHRO_OPENGL_CANVAS_IS_FLAG_SET (PUSH_DRAWPIXELS)) {
264 glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, dest->framebuffers[0]);
266 glWindowPos2iARB (0, pixelbuffer_y_offset);
267 glDrawPixels (width, pixelbuffer_height, dest->texture.pixel_format,
268 dest->push.type, NULL);
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);
277 SCHRO_OPENGL_CHECK_ERROR
279 pixelbuffer_y_offset += pixelbuffer_height;
282 if (dest->push.type == GL_SHORT) {
283 glPixelTransferf (GL_RED_SCALE, 1);
284 glPixelTransferf (GL_RED_BIAS, 0);
287 glBindBufferARB (GL_PIXEL_UNPACK_BUFFER_EXT, 0);
288 } else {
289 tmp_data = schro_opengl_get_tmp (dest->opengl, dest->push.stride * height);
291 schro_opengl_canvas_push_convert (dest, src, tmp_data, 0, height);
293 if (!SCHRO_OPENGL_CANVAS_IS_FLAG_SET (PUSH_RENDER_QUAD)) {
294 glBindTexture (GL_TEXTURE_RECTANGLE_ARB, dest->texture.handles[0]);
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);
309 if (SCHRO_OPENGL_CANVAS_IS_FLAG_SET (PUSH_DRAWPIXELS)) {
310 glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, dest->framebuffers[0]);
312 glWindowPos2iARB (0, 0);
313 glDrawPixels (width, height, dest->texture.pixel_format, dest->push.type,
314 tmp_data);
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);
322 if (dest->push.type == GL_SHORT) {
323 glPixelTransferf (GL_RED_SCALE, 1);
324 glPixelTransferf (GL_RED_BIAS, 0);
328 SCHRO_OPENGL_CHECK_ERROR
330 if (SCHRO_OPENGL_CANVAS_IS_FLAG_SET (PUSH_RENDER_QUAD)) {
331 schro_opengl_setup_viewport (width, height);
333 glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, dest->framebuffers[0]);
335 SCHRO_OPENGL_CHECK_ERROR
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;
352 glUseProgramObjectARB (shader->program);
353 glUniform1iARB (shader->textures[0], 0);
356 schro_opengl_render_quad (0, 0, width, height);
358 if (SCHRO_OPENGL_CANVAS_IS_FLAG_SET (PUSH_SHADER)) {
359 glUseProgramObjectARB (0);
362 glFlush ();
364 glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
366 SCHRO_OPENGL_CHECK_ERROR
369 #if SCHRO_OPENGL_UNBIND_TEXTURES
370 glBindTexture (GL_TEXTURE_RECTANGLE_ARB, 0);
371 #endif
373 if (SCHRO_OPENGL_CANVAS_IS_FLAG_SET (PUSH_RENDER_QUAD)) {
374 glDeleteTextures (1, &src_texture);
377 schro_opengl_unlock (dest->opengl);