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 
11 void
schro_opengl_wavelet_transform(SchroFrameData * frame_data,int filter)12 schro_opengl_wavelet_transform (SchroFrameData *frame_data, int filter)
13 {
14   SCHRO_ERROR ("unimplemented");
15   SCHRO_ASSERT (0);
16 }
17 
18 void
schro_opengl_wavelet_vertical_deinterleave(SchroFrameData * frame_data)19 schro_opengl_wavelet_vertical_deinterleave (SchroFrameData *frame_data)
20 {
21   int width, height;
22   int framebuffer_index, texture_index;
23   SchroOpenGLCanvas *canvas = NULL;
24   SchroOpenGL *opengl = NULL;
25   SchroOpenGLShader *shader_copy = NULL;
26   SchroOpenGLShader *shader_vertical_deinterleave_l = NULL;
27   SchroOpenGLShader *shader_vertical_deinterleave_h = NULL;
28 
29   SCHRO_ASSERT (SCHRO_FRAME_FORMAT_DEPTH (frame_data->format)
30       == SCHRO_FRAME_FORMAT_DEPTH_S16);
31   SCHRO_ASSERT (frame_data->width % 2 == 0);
32   SCHRO_ASSERT (frame_data->height % 2 == 0);
33 
34   width = frame_data->width;
35   height = frame_data->height;
36   // FIXME: hack to store custom data per frame component
37   canvas = *((SchroOpenGLCanvas **) frame_data->data);
38 
39   SCHRO_ASSERT (canvas != NULL);
40 
41   opengl = canvas->opengl;
42 
43   schro_opengl_lock (opengl);
44 
45   shader_copy = schro_opengl_shader_get (opengl,
46       SCHRO_OPENGL_SHADER_COPY_S16);
47   shader_vertical_deinterleave_l = schro_opengl_shader_get (opengl,
48       SCHRO_OPENGL_SHADER_IIWT_S16_VERTICAL_DEINTERLEAVE_L);
49   shader_vertical_deinterleave_h = schro_opengl_shader_get (opengl,
50       SCHRO_OPENGL_SHADER_IIWT_S16_VERTICAL_DEINTERLEAVE_H);
51 
52   SCHRO_ASSERT (shader_copy != NULL);
53   SCHRO_ASSERT (shader_vertical_deinterleave_l != NULL);
54   SCHRO_ASSERT (shader_vertical_deinterleave_h != NULL);
55 
56   schro_opengl_setup_viewport (width, height);
57 
58   SCHRO_OPENGL_CHECK_ERROR
59 
60   #define SWITCH_FRAMEBUFFER_AND_TEXTURE_INDICES \
61       framebuffer_index = 1 - framebuffer_index; \
62       texture_index = 1 - texture_index; \
63       SCHRO_ASSERT (framebuffer_index != texture_index);
64 
65   #define BIND_FRAMEBUFFER_AND_TEXTURE \
66       glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, \
67           canvas->framebuffers[framebuffer_index]); \
68       glBindTexture (GL_TEXTURE_RECTANGLE_ARB, \
69           canvas->texture.handles[texture_index]); \
70       SCHRO_OPENGL_CHECK_ERROR
71 
72   framebuffer_index = 1;
73   texture_index = 0;
74 
75   /* pass 1: vertical deinterleave */
76   BIND_FRAMEBUFFER_AND_TEXTURE
77 
78   glUseProgramObjectARB (shader_vertical_deinterleave_l->program);
79   glUniform1iARB (shader_vertical_deinterleave_l->textures[0], 0);
80 
81   schro_opengl_render_quad (0, 0, width, height / 2);
82 
83   glUseProgramObjectARB (shader_vertical_deinterleave_h->program);
84   glUniform1iARB (shader_vertical_deinterleave_h->textures[0], 0);
85   glUniform2fARB (shader_vertical_deinterleave_h->offset, 0, height / 2);
86 
87   schro_opengl_render_quad (0, height / 2, width, height / 2);
88 
89   SCHRO_OPENGL_CHECK_ERROR
90 
91   glFlush ();
92 
93   /* pass 2: transfer data from secondary to primary framebuffer */
94   SWITCH_FRAMEBUFFER_AND_TEXTURE_INDICES
95   BIND_FRAMEBUFFER_AND_TEXTURE
96 
97   glUseProgramObjectARB (shader_copy->program);
98   glUniform1iARB (shader_copy->textures[0], 0);
99 
100   schro_opengl_render_quad (0, 0, width, height);
101 
102   SCHRO_OPENGL_CHECK_ERROR
103 
104   glFlush ();
105 
106   #undef SWITCH_FRAMEBUFFER_AND_TEXTURE_INDICES
107   #undef BIND_FRAMEBUFFER_AND_TEXTURE
108 
109 #if SCHRO_OPENGL_UNBIND_TEXTURES
110   glBindTexture (GL_TEXTURE_RECTANGLE_ARB, 0);
111 #endif
112   glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
113 
114   schro_opengl_unlock (opengl);
115 }
116 
117 static void
schro_opengl_wavelet_render_quad(SchroOpenGLShader * shader,int x,int y,int quad_width,int quad_height,int total_width,int total_height)118 schro_opengl_wavelet_render_quad (SchroOpenGLShader *shader, int x, int y,
119     int quad_width, int quad_height, int total_width, int total_height)
120 {
121   int x_inverse, y_inverse;
122   int two_x = 0, two_y = 0, one_x = 0, one_y = 0;
123 
124   x_inverse = total_width - x - quad_width;
125   y_inverse = total_height - y - quad_height;
126 
127   if (quad_width == total_width && quad_height < total_height) {
128     two_y = 2;
129     one_y = 1;
130   } else if (quad_width < total_width && quad_height == total_height) {
131     two_x = 2;
132     one_x = 1;
133   } else {
134     SCHRO_ERROR ("invalid quad to total relation");
135     SCHRO_ASSERT (0);
136   }
137 
138   SCHRO_ASSERT (x_inverse >= 0);
139   SCHRO_ASSERT (y_inverse >= 0);
140 
141   #define UNIFORM(_number, _operation, __x, __y) \
142       do { \
143         if (shader->_number##_##_operation != -1) { \
144           glUniform2fARB (shader->_number##_##_operation, \
145               __x < _number##_x ? __x : _number##_x, \
146               __y < _number##_y ? __y : _number##_y); \
147         } \
148       } while (0)
149 
150   UNIFORM (two, decrease, x, y);
151   UNIFORM (one, decrease, x, y);
152   UNIFORM (one, increase, x_inverse, y_inverse);
153   UNIFORM (two, increase, x_inverse, y_inverse);
154 
155   #undef UNIFORM
156 
157   schro_opengl_render_quad (x, y, quad_width, quad_height);
158 }
159 
160 void
schro_opengl_wavelet_inverse_transform(SchroFrameData * frame_data,int filter)161 schro_opengl_wavelet_inverse_transform (SchroFrameData *frame_data,
162     int filter)
163 {
164   int width, height, subband_width, subband_height;
165   int framebuffer_index, texture_index;
166   int filter_shift = FALSE;
167   SchroOpenGLCanvas *canvas = NULL;
168   SchroOpenGL *opengl = NULL;
169   SchroOpenGLShader *shader_copy = NULL;
170   SchroOpenGLShader *shader_filter_lp = NULL;
171   SchroOpenGLShader *shader_filter_hp = NULL;
172   SchroOpenGLShader *shader_vertical_interleave = NULL;
173   SchroOpenGLShader *shader_horizontal_interleave = NULL;
174   SchroOpenGLShader *shader_filter_shift = NULL;
175 
176   SCHRO_ASSERT (SCHRO_FRAME_FORMAT_DEPTH (frame_data->format)
177       == SCHRO_FRAME_FORMAT_DEPTH_S16);
178   SCHRO_ASSERT (frame_data->width >= 2);
179   SCHRO_ASSERT (frame_data->height >= 2);
180   SCHRO_ASSERT (frame_data->width % 2 == 0);
181   SCHRO_ASSERT (frame_data->height % 2 == 0);
182 
183   width = frame_data->width;
184   height = frame_data->height;
185   subband_width = width / 2;
186   subband_height = height / 2;
187   // FIXME: hack to store custom data per frame component
188   canvas = *((SchroOpenGLCanvas **) frame_data->data);
189 
190   SCHRO_ASSERT (canvas != NULL);
191 
192   opengl = canvas->opengl;
193 
194   schro_opengl_lock (opengl);
195 
196   shader_copy = schro_opengl_shader_get (opengl,
197       SCHRO_OPENGL_SHADER_COPY_S16);
198 
199   SCHRO_ASSERT (shader_copy != NULL);
200 
201   switch (filter) {
202     case SCHRO_WAVELET_DESLAURIES_DUBUC_9_7:
203       shader_filter_lp = schro_opengl_shader_get (opengl,
204           SCHRO_OPENGL_SHADER_IIWT_S16_FILTER_DESLAURIERS_DUBUC_9_7_Lp);
205       shader_filter_hp = schro_opengl_shader_get (opengl,
206           SCHRO_OPENGL_SHADER_IIWT_S16_FILTER_DESLAURIERS_DUBUC_9_7_Hp);
207 
208       filter_shift = TRUE;
209       break;
210     case SCHRO_WAVELET_LE_GALL_5_3:
211       shader_filter_lp = schro_opengl_shader_get (opengl,
212           SCHRO_OPENGL_SHADER_IIWT_S16_FILTER_LE_GALL_5_3_Lp);
213       shader_filter_hp = schro_opengl_shader_get (opengl,
214           SCHRO_OPENGL_SHADER_IIWT_S16_FILTER_LE_GALL_5_3_Hp);
215 
216       filter_shift = TRUE;
217       break;
218     case SCHRO_WAVELET_DESLAURIES_DUBUC_13_7:
219       shader_filter_lp = schro_opengl_shader_get (opengl,
220           SCHRO_OPENGL_SHADER_IIWT_S16_FILTER_DESLAURIERS_DUBUC_13_7_Lp);
221       shader_filter_hp = schro_opengl_shader_get (opengl,
222           SCHRO_OPENGL_SHADER_IIWT_S16_FILTER_DESLAURIERS_DUBUC_13_7_Hp);
223 
224       filter_shift = TRUE;
225       break;
226     case SCHRO_WAVELET_HAAR_0:
227       shader_filter_lp = schro_opengl_shader_get (opengl,
228           SCHRO_OPENGL_SHADER_IIWT_S16_FILTER_HAAR_Lp);
229       shader_filter_hp = schro_opengl_shader_get (opengl,
230           SCHRO_OPENGL_SHADER_IIWT_S16_FILTER_HAAR_Hp);
231 
232       filter_shift = FALSE;
233       break;
234     case SCHRO_WAVELET_HAAR_1:
235       shader_filter_lp = schro_opengl_shader_get (opengl,
236           SCHRO_OPENGL_SHADER_IIWT_S16_FILTER_HAAR_Lp);
237       shader_filter_hp = schro_opengl_shader_get (opengl,
238           SCHRO_OPENGL_SHADER_IIWT_S16_FILTER_HAAR_Hp);
239 
240       filter_shift = TRUE;
241       break;
242     case SCHRO_WAVELET_FIDELITY:
243       SCHRO_ERROR ("fidelity filter is not implemented yet");
244       SCHRO_ASSERT (0);
245 
246       filter_shift = FALSE;
247       break;
248     case SCHRO_WAVELET_DAUBECHIES_9_7:
249       SCHRO_ERROR ("daubechies 9,7 filter is not implemented yet");
250       SCHRO_ASSERT (0);
251 
252       filter_shift = TRUE;
253       break;
254     default:
255       SCHRO_ERROR ("unknown filter %i", filter);
256       SCHRO_ASSERT (0);
257       break;
258   }
259 
260   SCHRO_ASSERT (shader_filter_lp != NULL);
261   SCHRO_ASSERT (shader_filter_hp != NULL);
262 
263   shader_vertical_interleave = schro_opengl_shader_get (opengl,
264       SCHRO_OPENGL_SHADER_IIWT_S16_VERTICAL_INTERLEAVE);
265   shader_horizontal_interleave = schro_opengl_shader_get (opengl,
266       SCHRO_OPENGL_SHADER_IIWT_S16_HORIZONTAL_INTERLEAVE);
267 
268   SCHRO_ASSERT (shader_vertical_interleave != NULL);
269   SCHRO_ASSERT (shader_horizontal_interleave != NULL);
270 
271   if (filter_shift) {
272     shader_filter_shift = schro_opengl_shader_get (opengl,
273         SCHRO_OPENGL_SHADER_IIWT_S16_FILTER_SHIFT);
274 
275     SCHRO_ASSERT (shader_filter_shift);
276   } else {
277     shader_filter_shift = NULL;
278   }
279 
280   schro_opengl_setup_viewport (width, height);
281 
282   SCHRO_OPENGL_CHECK_ERROR
283 
284   #define SWITCH_FRAMEBUFFER_AND_TEXTURE_INDICES \
285       framebuffer_index = 1 - framebuffer_index; \
286       texture_index = 1 - texture_index; \
287       SCHRO_ASSERT (framebuffer_index != texture_index);
288 
289   #define BIND_FRAMEBUFFER_AND_TEXTURE \
290       glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, \
291           canvas->framebuffers[framebuffer_index]); \
292       glBindTexture (GL_TEXTURE_RECTANGLE_ARB, \
293           canvas->texture.handles[texture_index]); \
294       SCHRO_OPENGL_CHECK_ERROR
295 
296   framebuffer_index = 1;
297   texture_index = 0;
298 
299   /* pass 1: vertical filtering => XL + f(XH) = XL' */
300   BIND_FRAMEBUFFER_AND_TEXTURE
301 
302   glUseProgramObjectARB (shader_filter_lp->program);
303   glUniform1iARB (shader_filter_lp->textures[0], 0);
304   glUniform2fARB (shader_filter_lp->offset, 0, subband_height);
305 
306   #define RENDER_QUAD_VERTICAL_Lp(_y, _quad_height) \
307       schro_opengl_wavelet_render_quad (shader_filter_lp, 0, _y, width, \
308           _quad_height, width, height)
309 
310   RENDER_QUAD_VERTICAL_Lp (0, 1);
311 
312   if (subband_height > 2) {
313     RENDER_QUAD_VERTICAL_Lp (1, 1);
314 
315     if (subband_height > 4) {
316       RENDER_QUAD_VERTICAL_Lp (2, subband_height - 4);
317     }
318 
319     RENDER_QUAD_VERTICAL_Lp (subband_height - 2, 1);
320   }
321 
322   RENDER_QUAD_VERTICAL_Lp (subband_height - 1, 1);
323 
324   #undef RENDER_QUAD_VERTICAL_Lp
325 
326   /* copy XH */
327   glUseProgramObjectARB (shader_copy->program);
328   glUniform1iARB (shader_copy->textures[0], 0);
329 
330   schro_opengl_render_quad (0, subband_height, width, subband_height);
331 
332   SCHRO_OPENGL_CHECK_ERROR
333 
334   glFlush ();
335 
336   /* pass 2: vertical filtering => f(XL') + XH = XH' */
337   SWITCH_FRAMEBUFFER_AND_TEXTURE_INDICES
338   BIND_FRAMEBUFFER_AND_TEXTURE
339 
340   glUseProgramObjectARB (shader_filter_hp->program);
341   glUniform1iARB (shader_filter_hp->textures[0], 0);
342   glUniform2fARB (shader_filter_hp->offset, 0, subband_height);
343 
344   #define RENDER_QUAD_VERTICAL_Hp(_y_offset, _quad_height) \
345       schro_opengl_wavelet_render_quad (shader_filter_hp, 0, \
346           subband_height + (_y_offset), width, _quad_height, width, height)
347 
348   RENDER_QUAD_VERTICAL_Hp (0, 1);
349 
350   if (subband_height > 2) {
351     RENDER_QUAD_VERTICAL_Hp (1, 1);
352 
353     if (subband_height > 4) {
354       RENDER_QUAD_VERTICAL_Hp (2, subband_height - 4);
355     }
356 
357     RENDER_QUAD_VERTICAL_Hp (subband_height - 2, 1);
358   }
359 
360   RENDER_QUAD_VERTICAL_Hp (subband_height - 1, 1);
361 
362   #undef RENDER_QUAD_VERTICAL_Hp
363 
364   /* copy XL' */
365   glUseProgramObjectARB (shader_copy->program);
366   glUniform1iARB (shader_copy->textures[0], 0);
367 
368   schro_opengl_render_quad (0, 0, width, subband_height);
369 
370   SCHRO_OPENGL_CHECK_ERROR
371 
372   glFlush ();
373 
374   /* pass 3: vertical interleave => i(LL', LH') = L, i(HL', HH') = H */
375   SWITCH_FRAMEBUFFER_AND_TEXTURE_INDICES
376   BIND_FRAMEBUFFER_AND_TEXTURE
377 
378   glUseProgramObjectARB (shader_vertical_interleave->program);
379   glUniform1iARB (shader_vertical_interleave->textures[0], 0);
380   glUniform2fARB (shader_vertical_interleave->offset, 0, subband_height);
381 
382   schro_opengl_render_quad (0, 0, width, height);
383 
384   SCHRO_OPENGL_CHECK_ERROR
385 
386   glFlush ();
387 
388   /* pass 4: horizontal filtering => L + f(H) = L' */
389   SWITCH_FRAMEBUFFER_AND_TEXTURE_INDICES
390   BIND_FRAMEBUFFER_AND_TEXTURE
391 
392   glUseProgramObjectARB (shader_filter_lp->program);
393   glUniform1iARB (shader_filter_lp->textures[0], 0);
394   glUniform2fARB (shader_filter_lp->offset, subband_width, 0);
395 
396   #define RENDER_QUAD_HORIZONTAL_Lp(_x, _quad_width) \
397       schro_opengl_wavelet_render_quad (shader_filter_lp, _x, 0, _quad_width, \
398           height, width, height)
399 
400   RENDER_QUAD_HORIZONTAL_Lp (0, 1);
401 
402   if (subband_width > 2) {
403     RENDER_QUAD_HORIZONTAL_Lp (1, 1);
404 
405     if (subband_width > 4) {
406       RENDER_QUAD_HORIZONTAL_Lp (2, subband_width - 4);
407     }
408 
409     RENDER_QUAD_HORIZONTAL_Lp (subband_width - 2, 1);
410   }
411 
412   RENDER_QUAD_HORIZONTAL_Lp (subband_width - 1, 1);
413 
414   #undef RENDER_QUAD_HORIZONTAL_Lp
415 
416   /* copy H */
417   glUseProgramObjectARB (shader_copy->program);
418   glUniform1iARB (shader_copy->textures[0], 0);
419 
420   schro_opengl_render_quad (subband_width, 0, subband_width, height);
421 
422   SCHRO_OPENGL_CHECK_ERROR
423 
424   glFlush ();
425 
426   /* pass 5: horizontal filtering => f(L') + H = H' */
427   SWITCH_FRAMEBUFFER_AND_TEXTURE_INDICES
428   BIND_FRAMEBUFFER_AND_TEXTURE
429 
430   glUseProgramObjectARB (shader_filter_hp->program);
431   glUniform1iARB (shader_filter_hp->textures[0], 0);
432   glUniform2fARB (shader_filter_hp->offset, subband_width, 0);
433 
434   #define RENDER_QUAD_HORIZONTAL_Hp(_x_offset, _quad_width) \
435       schro_opengl_wavelet_render_quad (shader_filter_hp, \
436           subband_width + (_x_offset), 0, _quad_width, height, width, height);
437 
438   RENDER_QUAD_HORIZONTAL_Hp (0, 1);
439 
440   if (subband_width > 2) {
441     RENDER_QUAD_HORIZONTAL_Hp (1, 1);
442 
443     if (subband_width > 4) {
444       RENDER_QUAD_HORIZONTAL_Hp (2, subband_width - 4);
445     }
446 
447     RENDER_QUAD_HORIZONTAL_Hp (subband_width - 2, 1);
448   }
449 
450   RENDER_QUAD_HORIZONTAL_Hp (subband_width - 1, 1);
451 
452   #undef RENDER_QUAD_HORIZONTAL_Hp
453 
454   /* copy L' */
455   glUseProgramObjectARB (shader_copy->program);
456   glUniform1iARB (shader_copy->textures[0], 0);
457 
458   schro_opengl_render_quad (0, 0, subband_width, height);
459 
460   SCHRO_OPENGL_CHECK_ERROR
461 
462   glFlush ();
463 
464   /* pass 6: horizontal interleave => i(L', H') = LL */
465   SWITCH_FRAMEBUFFER_AND_TEXTURE_INDICES
466   BIND_FRAMEBUFFER_AND_TEXTURE
467 
468   glUseProgramObjectARB (shader_horizontal_interleave->program);
469   glUniform1iARB (shader_horizontal_interleave->textures[0], 0);
470   glUniform2fARB (shader_horizontal_interleave->offset, width / 2, 0);
471 
472   schro_opengl_render_quad (0, 0, width, height);
473 
474   SCHRO_OPENGL_CHECK_ERROR
475 
476   glFlush ();
477 
478   /* pass 7: filter shift */
479   if (filter_shift) {
480     SWITCH_FRAMEBUFFER_AND_TEXTURE_INDICES
481     BIND_FRAMEBUFFER_AND_TEXTURE
482 
483     glUseProgramObjectARB (shader_filter_shift->program);
484     glUniform1iARB (shader_filter_shift->textures[0], 0);
485 
486     schro_opengl_render_quad (0, 0, width, height);
487 
488     SCHRO_OPENGL_CHECK_ERROR
489 
490     glFlush ();
491   }
492 
493   /* pass 8: transfer data from secondary to primary framebuffer if previous
494              pass result wasn't rendered into the primary framebuffer */
495   if (framebuffer_index != 0) {
496     SWITCH_FRAMEBUFFER_AND_TEXTURE_INDICES
497     BIND_FRAMEBUFFER_AND_TEXTURE
498 
499     glUseProgramObjectARB (shader_copy->program);
500     glUniform1iARB (shader_copy->textures[0], 0);
501 
502     schro_opengl_render_quad (0, 0, width, height);
503 
504     SCHRO_OPENGL_CHECK_ERROR
505 
506     glFlush ();
507   }
508 
509   #undef SWITCH_FRAMEBUFFER_AND_TEXTURE_INDICES
510   #undef BIND_FRAMEBUFFER_AND_TEXTURE
511 
512   glUseProgramObjectARB (0);
513 #if SCHRO_OPENGL_UNBIND_TEXTURES
514   glBindTexture (GL_TEXTURE_RECTANGLE_ARB, 0);
515 #endif
516   glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
517 
518   schro_opengl_unlock (opengl);
519 }
520 
521