Line data Source code
1 : /* ______ ___ ___
2 : * /\ _ \ /\_ \ /\_ \
3 : * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
4 : * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
5 : * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
6 : * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7 : * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8 : * /\____/
9 : * \_/__/
10 : *
11 : * OpenGL framebuffer objects.
12 : *
13 : * See LICENSE.txt for copyright information.
14 : */
15 :
16 : #include <float.h>
17 :
18 : #include "allegro5/allegro.h"
19 : #include "allegro5/allegro_opengl.h"
20 : #include "allegro5/internal/aintern.h"
21 : #include "allegro5/internal/aintern_opengl.h"
22 : #include "allegro5/internal/aintern_pixels.h"
23 :
24 : #ifdef ALLEGRO_ANDROID
25 : #include "allegro5/internal/aintern_android.h"
26 : #elif defined ALLEGRO_IPHONE
27 : #include "allegro5/internal/aintern_iphone.h"
28 : #endif
29 :
30 : #include "ogl_helpers.h"
31 :
32 : ALLEGRO_DEBUG_CHANNEL("opengl")
33 :
34 :
35 : /* forward declarations */
36 : static void setup_fbo_backbuffer(ALLEGRO_DISPLAY *display,
37 : ALLEGRO_BITMAP *bitmap);
38 : static void use_fbo_for_bitmap(ALLEGRO_DISPLAY *display,
39 : ALLEGRO_BITMAP *bitmap, ALLEGRO_FBO_INFO *info);
40 :
41 :
42 : /* glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT..) not supported on some Androids.
43 : * We keep track of it manually.
44 : */
45 : #ifdef ALLEGRO_ANDROID
46 :
47 : static GLint _al_gl_curr_fbo = 0;
48 :
49 : GLint _al_android_get_curr_fbo(void)
50 : {
51 : return _al_gl_curr_fbo;
52 : }
53 :
54 : void _al_android_set_curr_fbo(GLint fbo)
55 : {
56 : _al_gl_curr_fbo = fbo;
57 : }
58 :
59 : GLint _al_ogl_bind_framebuffer(GLint fbo)
60 : {
61 : GLint old_fbo = _al_android_get_curr_fbo();
62 : GLint e;
63 :
64 : if (ANDROID_PROGRAMMABLE_PIPELINE(al_get_current_display())) {
65 : glBindFramebuffer(GL_FRAMEBUFFER, fbo);
66 : }
67 : else {
68 : glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
69 : }
70 : e = glGetError();
71 : if (e) {
72 : ALLEGRO_DEBUG("glBindFramebufferEXT failed (%s)",
73 : _al_gl_error_string(e));
74 : }
75 : _al_android_set_curr_fbo(fbo);
76 : return old_fbo;
77 : }
78 :
79 : #else /* !ALLEGRO_ANDROID */
80 :
81 2793 : GLint _al_ogl_bind_framebuffer(GLint fbo)
82 : {
83 : GLint old_fbo;
84 2793 : glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &old_fbo);
85 2793 : glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
86 2793 : return old_fbo;
87 : }
88 :
89 : #endif /* !ALLEGRO_ANDROID */
90 :
91 :
92 163 : void _al_ogl_reset_fbo_info(ALLEGRO_FBO_INFO *info)
93 : {
94 163 : info->fbo_state = FBO_INFO_UNUSED;
95 163 : info->fbo = 0;
96 163 : info->buffers.depth_buffer = 0;
97 163 : info->buffers.multisample_buffer = 0;
98 163 : info->buffers.dw = 0;
99 163 : info->buffers.dh = 0;
100 163 : info->buffers.mw = 0;
101 163 : info->buffers.mh = 0;
102 163 : info->owner = NULL;
103 163 : info->last_use_time = 0.0;
104 163 : }
105 :
106 :
107 : #if !defined ALLEGRO_RASPBERRYPI && (!defined ALLEGRO_ANDROID || defined ALLEGRO_CFG_OPENGLES3) && !defined ALLEGRO_CFG_OPENGLES
108 0 : static void check_gl_error(void)
109 : {
110 0 : GLint e = glGetError();
111 0 : if (e) {
112 0 : ALLEGRO_ERROR("OpenGL call failed! (%s)\n",
113 : _al_gl_error_string(e));
114 : }
115 0 : }
116 : #endif
117 :
118 :
119 163 : static void detach_depth_buffer(ALLEGRO_FBO_INFO *info)
120 : {
121 : #ifndef ALLEGRO_RASPBERRYPI
122 163 : if (info->buffers.depth_buffer == 0)
123 : return;
124 0 : ALLEGRO_DEBUG("Deleting depth render buffer: %u\n",
125 : info->buffers.depth_buffer);
126 0 : glDeleteRenderbuffersEXT(1, &info->buffers.depth_buffer);
127 0 : info->buffers.depth_buffer = 0;
128 0 : info->buffers.dw = 0;
129 0 : info->buffers.dh = 0;
130 0 : info->buffers.depth = 0;
131 : #endif
132 : }
133 :
134 :
135 163 : static void detach_multisample_buffer(ALLEGRO_FBO_INFO *info)
136 : {
137 : #ifndef ALLEGRO_RASPBERRYPI
138 163 : if (info->buffers.multisample_buffer == 0)
139 : return;
140 0 : ALLEGRO_DEBUG("Deleting multisample render buffer: %u\n",
141 : info->buffers.depth_buffer);
142 0 : glDeleteRenderbuffersEXT(1, &info->buffers.multisample_buffer);
143 0 : info->buffers.multisample_buffer = 0;
144 0 : info->buffers.mw = 0;
145 0 : info->buffers.mh = 0;
146 0 : info->buffers.samples = 0;
147 : #endif
148 : }
149 :
150 :
151 :
152 1296 : static void attach_depth_buffer(ALLEGRO_FBO_INFO *info)
153 : {
154 : #if !defined ALLEGRO_RASPBERRYPI
155 : GLuint rb;
156 1296 : GLenum gldepth = GL_DEPTH_COMPONENT16;
157 :
158 1296 : ALLEGRO_BITMAP *b = info->owner;
159 1296 : int bits = al_get_bitmap_depth(b);
160 :
161 1296 : if (info->buffers.depth_buffer != 0) {
162 :
163 0 : if (info->buffers.depth != bits ||
164 0 : info->buffers.dw != al_get_bitmap_width(b) ||
165 0 : info->buffers.dh != al_get_bitmap_height(b)) {
166 0 : detach_depth_buffer(info);
167 : }
168 : }
169 :
170 1296 : if (!bits)
171 1296 : return;
172 :
173 0 : if (info->buffers.depth_buffer == 0) {
174 0 : ALLEGRO_DISPLAY *display = _al_get_bitmap_display(info->owner);
175 0 : int w = al_get_bitmap_width(info->owner);
176 0 : int h = al_get_bitmap_height(info->owner);
177 :
178 0 : if (bits == 24) gldepth = GL_DEPTH_COMPONENT24;
179 :
180 0 : glGenRenderbuffersEXT(1, &rb);
181 0 : glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, rb);
182 :
183 0 : int samples = al_get_bitmap_samples(info->owner);
184 :
185 : bool extension_supported;
186 : #ifdef ALLEGRO_CFG_OPENGLES
187 : (void)display;
188 : extension_supported = al_have_opengl_extension("EXT_multisampled_render_to_texture");
189 : #else
190 0 : extension_supported = display->ogl_extras->extension_list->ALLEGRO_GL_EXT_framebuffer_multisample;
191 : #endif
192 :
193 0 : if (samples == 0 || !extension_supported)
194 0 : glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, gldepth, w, h);
195 : #if !defined ALLEGRO_ANDROID || defined ALLEGRO_CFG_OPENGLES3
196 : else
197 0 : glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT,
198 : samples, gldepth, w, h);
199 : #else
200 : else {
201 : return;
202 : }
203 : #endif
204 :
205 0 : info->buffers.depth_buffer = rb;
206 : info->buffers.dw = w;
207 0 : info->buffers.dw = h;
208 0 : info->buffers.depth = bits;
209 0 : GLint e = glGetError();
210 0 : if (e) {
211 0 : ALLEGRO_ERROR("glRenderbufferStorage failed! bits=%d w=%d h=%d (%s)\n",
212 : bits, w, h, _al_gl_error_string(e));
213 : }
214 : else {
215 0 : ALLEGRO_DEBUG("Depth render buffer created: %u\n",
216 : info->buffers.depth_buffer);
217 : }
218 :
219 0 : glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
220 : GL_RENDERBUFFER_EXT, rb);
221 0 : if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) {
222 0 : ALLEGRO_ERROR("attaching depth renderbuffer failed\n");
223 : }
224 :
225 0 : glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
226 : }
227 : #endif
228 : }
229 :
230 :
231 1296 : static void attach_multisample_buffer(ALLEGRO_FBO_INFO *info)
232 : {
233 : #if !defined ALLEGRO_RASPBERRYPI && (!defined ALLEGRO_ANDROID || defined ALLEGRO_CFG_OPENGLES3)
234 1296 : ALLEGRO_BITMAP *b = info->owner;
235 1296 : int samples = al_get_bitmap_samples(b);
236 :
237 1296 : if (info->buffers.multisample_buffer != 0) {
238 :
239 0 : if (info->buffers.samples != samples ||
240 0 : info->buffers.mw != al_get_bitmap_width(b) ||
241 0 : info->buffers.mh != al_get_bitmap_height(b)) {
242 0 : detach_multisample_buffer(info);
243 : }
244 : }
245 :
246 1296 : if (!samples)
247 : return;
248 0 : ALLEGRO_DISPLAY *display = _al_get_bitmap_display(info->owner);
249 0 : if (!display->ogl_extras->extension_list->ALLEGRO_GL_EXT_framebuffer_multisample)
250 : return;
251 :
252 : #ifdef ALLEGRO_CFG_OPENGLES
253 : (void)display;
254 : #else
255 :
256 0 : if (info->buffers.multisample_buffer == 0) {
257 : GLuint rb;
258 : GLint e;
259 0 : int w = al_get_bitmap_width(info->owner);
260 0 : int h = al_get_bitmap_height(info->owner);
261 :
262 0 : glGenRenderbuffersEXT(1, &rb);
263 0 : glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, rb);
264 0 : check_gl_error();
265 :
266 0 : glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT,
267 0 : samples, _al_ogl_get_glformat(
268 : al_get_bitmap_format(info->owner), 0), w, h);
269 0 : info->buffers.multisample_buffer = rb;
270 0 : info->buffers.mw = w;
271 0 : info->buffers.mh = h;
272 0 : info->buffers.samples = samples;
273 0 : e = glGetError();
274 0 : if (e) {
275 0 : ALLEGRO_ERROR("glRenderbufferStorage failed! samples=%d w=%d h=%d (%s)\n",
276 : samples, w, h, _al_gl_error_string(e));
277 : }
278 : else {
279 0 : ALLEGRO_DEBUG("Multisample render buffer created: %u\n",
280 : info->buffers.multisample_buffer);
281 : }
282 :
283 0 : glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
284 : GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, rb);
285 :
286 0 : if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) {
287 0 : ALLEGRO_ERROR("attaching multisample renderbuffer failed\n");
288 : }
289 :
290 0 : glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
291 : }
292 : #endif
293 : #else
294 : (void)info;
295 : #endif
296 : }
297 :
298 :
299 0 : bool _al_ogl_create_persistent_fbo(ALLEGRO_BITMAP *bitmap)
300 : {
301 : ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap;
302 : ALLEGRO_FBO_INFO *info;
303 : GLint old_fbo, e;
304 :
305 0 : if (bitmap->parent)
306 0 : bitmap = bitmap->parent;
307 0 : ogl_bitmap = bitmap->extra;
308 :
309 : /* Don't continue if the bitmap does not belong to the current display. */
310 0 : if (_al_get_bitmap_display(bitmap)->ogl_extras->is_shared == false &&
311 0 : _al_get_bitmap_display(bitmap) != al_get_current_display()) {
312 : return false;
313 : }
314 :
315 0 : if (ogl_bitmap->is_backbuffer) {
316 : return false;
317 : }
318 :
319 : ASSERT(!ogl_bitmap->fbo_info);
320 :
321 0 : info = al_malloc(sizeof(ALLEGRO_FBO_INFO));
322 0 : info->owner = bitmap;
323 : if (ANDROID_PROGRAMMABLE_PIPELINE(al_get_current_display())) {
324 : glGenFramebuffers(1, &info->fbo);
325 : }
326 : else {
327 0 : glGenFramebuffersEXT(1, &info->fbo);
328 : }
329 0 : if (info->fbo == 0) {
330 0 : al_free(info);
331 0 : return false;
332 : }
333 :
334 0 : old_fbo = _al_ogl_bind_framebuffer(info->fbo);
335 :
336 : if (ANDROID_PROGRAMMABLE_PIPELINE(al_get_current_display())) {
337 : glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
338 : GL_TEXTURE_2D, ogl_bitmap->texture, 0);
339 : }
340 : else {
341 0 : glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
342 : GL_TEXTURE_2D, ogl_bitmap->texture, 0);
343 : }
344 :
345 0 : e = glGetError();
346 0 : if (e) {
347 0 : ALLEGRO_DEBUG("glFrameBufferTexture2DEXT failed! fbo=%d texture=%d (%s)\n",
348 : info->fbo, ogl_bitmap->texture, _al_gl_error_string(e));
349 : }
350 :
351 0 : attach_depth_buffer(info);
352 :
353 : /* You'll see this a couple times in this file: some ES 1.1 functions aren't
354 : * implemented on Android. This is an ugly workaround.
355 : */
356 0 : if (UNLESS_ANDROID_OR_RPI(
357 : glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT))
358 : {
359 0 : ALLEGRO_ERROR("FBO incomplete.\n");
360 0 : _al_ogl_bind_framebuffer(old_fbo);
361 0 : glDeleteFramebuffersEXT(1, &info->fbo);
362 0 : al_free(info);
363 0 : return false;
364 : }
365 :
366 0 : _al_ogl_bind_framebuffer(old_fbo);
367 :
368 0 : info->fbo_state = FBO_INFO_PERSISTENT;
369 0 : info->last_use_time = al_get_time();
370 0 : ogl_bitmap->fbo_info = info;
371 0 : ALLEGRO_DEBUG("Persistent FBO: %u\n", info->fbo);
372 : return true;
373 : }
374 :
375 :
376 0 : ALLEGRO_FBO_INFO *_al_ogl_persist_fbo(ALLEGRO_DISPLAY *display,
377 : ALLEGRO_FBO_INFO *transient_fbo_info)
378 : {
379 0 : ALLEGRO_OGL_EXTRAS *extras = display->ogl_extras;
380 : int i;
381 : ASSERT(transient_fbo_info->fbo_state == FBO_INFO_TRANSIENT);
382 :
383 0 : for (i = 0; i < ALLEGRO_MAX_OPENGL_FBOS; i++) {
384 0 : if (transient_fbo_info == &extras->fbos[i]) {
385 0 : ALLEGRO_FBO_INFO *new_info = al_malloc(sizeof(ALLEGRO_FBO_INFO));
386 0 : *new_info = *transient_fbo_info;
387 0 : new_info->fbo_state = FBO_INFO_PERSISTENT;
388 0 : _al_ogl_reset_fbo_info(transient_fbo_info);
389 0 : ALLEGRO_DEBUG("Persistent FBO: %u\n", new_info->fbo);
390 : return new_info;
391 : }
392 : }
393 :
394 0 : ALLEGRO_ERROR("Could not find FBO %u in pool\n", transient_fbo_info->fbo);
395 : return transient_fbo_info;
396 : }
397 :
398 :
399 : static ALLEGRO_FBO_INFO *ogl_find_unused_fbo(ALLEGRO_DISPLAY *display)
400 : {
401 163 : ALLEGRO_OGL_EXTRAS *extras = display->ogl_extras;
402 163 : double min_time = DBL_MAX;
403 163 : int min_time_index = -1;
404 : int i;
405 :
406 209 : for (i = 0; i < ALLEGRO_MAX_OPENGL_FBOS; i++) {
407 207 : if (extras->fbos[i].fbo_state == FBO_INFO_UNUSED)
408 161 : return &extras->fbos[i];
409 46 : if (extras->fbos[i].last_use_time < min_time) {
410 14 : min_time = extras->fbos[i].last_use_time;
411 14 : min_time_index = i;
412 : }
413 : }
414 :
415 2 : return &extras->fbos[min_time_index];
416 : }
417 :
418 :
419 163 : void _al_ogl_del_fbo(ALLEGRO_FBO_INFO *info)
420 : {
421 163 : ALLEGRO_BITMAP_EXTRA_OPENGL *extra = info->owner->extra;
422 163 : extra->fbo_info = NULL;
423 163 : ALLEGRO_DEBUG("Deleting FBO: %u\n", info->fbo);
424 : if (ANDROID_PROGRAMMABLE_PIPELINE(al_get_current_display())) {
425 : glDeleteFramebuffers(1, &info->fbo);
426 : }
427 : else {
428 163 : glDeleteFramebuffersEXT(1, &info->fbo);
429 : }
430 :
431 163 : detach_depth_buffer(info);
432 163 : detach_multisample_buffer(info);
433 :
434 163 : info->fbo = 0;
435 163 : }
436 :
437 :
438 163 : static ALLEGRO_FBO_INFO *ogl_new_fbo(ALLEGRO_DISPLAY *display)
439 : {
440 : ALLEGRO_FBO_INFO *info;
441 : GLint e;
442 :
443 326 : info = ogl_find_unused_fbo(display);
444 : ASSERT(info->fbo_state != FBO_INFO_PERSISTENT);
445 :
446 163 : if (info->fbo_state == FBO_INFO_TRANSIENT) {
447 2 : _al_ogl_del_fbo(info);
448 2 : _al_ogl_reset_fbo_info(info);
449 : }
450 : else {
451 : /* FBO_INFO_UNUSED */
452 : }
453 :
454 : if (ANDROID_PROGRAMMABLE_PIPELINE(al_get_current_display())) {
455 : glGenFramebuffers(1, &info->fbo);
456 : }
457 : else {
458 163 : glGenFramebuffersEXT(1, &info->fbo);
459 : }
460 163 : e = glGetError();
461 163 : if (e) {
462 0 : ALLEGRO_ERROR("glGenFramebuffersEXT failed\n");
463 0 : _al_ogl_reset_fbo_info(info);
464 0 : return NULL;
465 : }
466 :
467 163 : ALLEGRO_DEBUG("Created FBO: %u\n", info->fbo);
468 : return info;
469 : }
470 :
471 :
472 1651 : void _al_ogl_setup_fbo(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap)
473 : {
474 : ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap;
475 :
476 1651 : if (bitmap->parent)
477 9 : bitmap = bitmap->parent;
478 1651 : ogl_bitmap = bitmap->extra;
479 :
480 : /* We can't return here. Target's FBO can be taken away by locking
481 : * a lot of bitmaps consecutively.
482 : * Also affects ex_multiwin; resizing one window affects the other.
483 : */
484 : if (false && display->ogl_extras->opengl_target == bitmap)
485 : return;
486 :
487 1651 : _al_ogl_unset_target_bitmap(display, display->ogl_extras->opengl_target);
488 :
489 1651 : if (ogl_bitmap->is_backbuffer)
490 1497 : setup_fbo_backbuffer(display, bitmap);
491 : else
492 154 : _al_ogl_setup_fbo_non_backbuffer(display, bitmap);
493 : }
494 :
495 :
496 : /* With the framebuffer_multisample extension, the absolutely one and
497 : * only way to ever access the multisample buffer is with the
498 : * framebuffer_blit extension. [1]
499 : *
500 : * This is what we do in this function - if there is a multisample
501 : * buffer, downsample it back into the texture.
502 : *
503 : * [1] https://www.opengl.org/registry/specs/EXT/framebuffer_multisample.txt
504 : */
505 1650 : void _al_ogl_finalize_fbo(ALLEGRO_DISPLAY *display,
506 : ALLEGRO_BITMAP *bitmap)
507 : {
508 1650 : ALLEGRO_BITMAP_EXTRA_OPENGL *extra = bitmap->extra;
509 1650 : if (!extra)
510 1650 : return;
511 1650 : ALLEGRO_FBO_INFO *info = extra->fbo_info;
512 : (void)display;
513 1650 : if (!info)
514 : return;
515 228 : if (!info->buffers.multisample_buffer)
516 : return;
517 : #ifndef ALLEGRO_CFG_OPENGLES
518 0 : int w = al_get_bitmap_width(bitmap);
519 0 : int h = al_get_bitmap_height(bitmap);
520 :
521 : GLuint blit_fbo;
522 0 : glGenFramebuffersEXT(1, &blit_fbo);
523 0 : glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, blit_fbo);
524 0 : glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
525 : GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, extra->texture, 0);
526 :
527 0 : glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, info->fbo);
528 0 : glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, blit_fbo);
529 0 : glBlitFramebufferEXT(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
530 0 : check_gl_error();
531 :
532 0 : glDeleteFramebuffersEXT(1, &blit_fbo);
533 : #else
534 : (void)bitmap;
535 : #endif
536 : }
537 :
538 :
539 : static void setup_fbo_backbuffer(ALLEGRO_DISPLAY *display,
540 : ALLEGRO_BITMAP *bitmap)
541 : {
542 1497 : display->ogl_extras->opengl_target = bitmap;
543 :
544 : // The IS_OPENGLES part is a hack.
545 1497 : if (IS_OPENGLES ||
546 1497 : display->ogl_extras->extension_list->ALLEGRO_GL_EXT_framebuffer_object ||
547 0 : display->ogl_extras->extension_list->ALLEGRO_GL_OES_framebuffer_object)
548 : {
549 1497 : _al_ogl_bind_framebuffer(0);
550 : }
551 :
552 : #ifdef ALLEGRO_IPHONE
553 : _al_iphone_setup_opengl_view(display, false);
554 : #endif
555 : }
556 :
557 :
558 1296 : bool _al_ogl_setup_fbo_non_backbuffer(ALLEGRO_DISPLAY *display,
559 : ALLEGRO_BITMAP *bitmap)
560 : {
561 1296 : ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap = bitmap->extra;
562 : ALLEGRO_FBO_INFO *info;
563 :
564 : ASSERT(bitmap->parent == NULL);
565 :
566 : /* When a bitmap is set as target bitmap, we try to create an FBO for it. */
567 1296 : info = ogl_bitmap->fbo_info;
568 1296 : if (!info) {
569 : /* FIXME The IS_OPENGLES part is quite a hack but I don't know how the
570 : * Allegro extension manager works to fix this properly (getting
571 : * extensions properly reported on iphone). All iOS devices support
572 : * FBOs though (currently.)
573 : */
574 163 : if (IS_OPENGLES ||
575 163 : al_get_opengl_extension_list()->ALLEGRO_GL_EXT_framebuffer_object ||
576 0 : al_get_opengl_extension_list()->ALLEGRO_GL_OES_framebuffer_object)
577 : {
578 163 : info = ogl_new_fbo(display);
579 : }
580 : }
581 :
582 1296 : if (!info || info->fbo == 0) {
583 : return false;
584 : }
585 :
586 1296 : use_fbo_for_bitmap(display, bitmap, info);
587 1296 : return true; /* state changed */
588 : }
589 :
590 :
591 1296 : static void use_fbo_for_bitmap(ALLEGRO_DISPLAY *display,
592 : ALLEGRO_BITMAP *bitmap, ALLEGRO_FBO_INFO *info)
593 : {
594 1296 : ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap = bitmap->extra;
595 : GLint e;
596 :
597 1296 : if (info->fbo_state == FBO_INFO_UNUSED)
598 163 : info->fbo_state = FBO_INFO_TRANSIENT;
599 1296 : info->owner = bitmap;
600 1296 : info->last_use_time = al_get_time();
601 1296 : ogl_bitmap->fbo_info = info;
602 :
603 : /* Bind to the FBO. */
604 1296 : _al_ogl_bind_framebuffer(info->fbo);
605 :
606 1296 : attach_multisample_buffer(info);
607 1296 : attach_depth_buffer(info);
608 :
609 : /* If we have a multisample renderbuffer, we can only syncronize
610 : * it back to the texture once we stop drawing into it - i.e.
611 : * when the target bitmap is changed to something else.
612 : */
613 1296 : if (!info->buffers.multisample_buffer) {
614 :
615 : /* Attach the texture. */
616 : #ifdef ALLEGRO_CFG_OPENGLES
617 : if (ANDROID_PROGRAMMABLE_PIPELINE(al_get_current_display())) {
618 : if (al_get_bitmap_samples(bitmap) == 0 || !al_have_opengl_extension("EXT_multisampled_render_to_texture")) {
619 : glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
620 : GL_TEXTURE_2D, ogl_bitmap->texture, 0);
621 : }
622 : #if !defined ALLEGRO_IPHONE && (!defined ALLEGRO_ANDROID || defined ALLEGRO_CFG_OPENGLES3)
623 : else {
624 : glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER,
625 : GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ogl_bitmap->texture,
626 : 0, al_get_bitmap_samples(bitmap));
627 :
628 : }
629 : #endif
630 : }
631 : else
632 : #endif
633 : {
634 1296 : glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
635 : GL_TEXTURE_2D, ogl_bitmap->texture, 0);
636 : }
637 :
638 1296 : e = glGetError();
639 1296 : if (e) {
640 0 : ALLEGRO_DEBUG("glFrameBufferTexture2DEXT failed! fbo=%d texture=%d (%s)\n",
641 : info->fbo, ogl_bitmap->texture, _al_gl_error_string(e));
642 : }
643 : }
644 :
645 : /* See comment about unimplemented functions on Android above */
646 1296 : if (UNLESS_ANDROID_OR_RPI(
647 : glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT))
648 : {
649 : /* For some reason, we cannot use the FBO with this
650 : * texture. So no reason to keep re-trying, output a log
651 : * message and switch to (extremely slow) software mode.
652 : */
653 0 : ALLEGRO_ERROR("Could not use FBO for bitmap with format %s.\n",
654 0 : _al_pixel_format_name(al_get_bitmap_format(bitmap)));
655 0 : ALLEGRO_ERROR("*** SWITCHING TO SOFTWARE MODE ***\n");
656 0 : _al_ogl_bind_framebuffer(0);
657 0 : glDeleteFramebuffersEXT(1, &info->fbo);
658 0 : _al_ogl_reset_fbo_info(info);
659 0 : ogl_bitmap->fbo_info = NULL;
660 : }
661 : else {
662 1296 : display->ogl_extras->opengl_target = bitmap;
663 : }
664 1296 : }
665 :
666 :
667 : /* vim: set sts=3 sw=3 et: */
|