LCOV - code coverage report
Current view: top level - src/opengl - ogl_fbo.c (source / functions) Hit Total Coverage
Test: allegro_auto.info Lines: 106 239 44.4 %
Date: 2018-08-11 00:50:28 Functions: 12 15 80.0 %
Legend: Lines: hit not hit

          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: */

Generated by: LCOV version 1.13