ALLEGRO_BITMAP_OGL* _al_ogl_create_backbuffer(ALLEGRO_DISPLAY *disp) { ALLEGRO_BITMAP_OGL *ogl_backbuffer; ALLEGRO_BITMAP *backbuffer; ALLEGRO_STATE backup; int format; ALLEGRO_DEBUG("Creating backbuffer\n"); al_store_state(&backup, ALLEGRO_STATE_NEW_BITMAP_PARAMETERS); // FIXME: _al_deduce_color_format would work fine if the display paramerers // are filled in, for WIZ and IPOD #ifdef ALLEGRO_GP2XWIZ format = ALLEGRO_PIXEL_FORMAT_RGB_565; /* Only support display format */ #elif defined ALLEGRO_IPHONE format = ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE; // TODO: This one is also supported //format = ALLEGRO_PIXEL_FORMAT_RGB_565; #else format = _al_deduce_color_format(&disp->extra_settings); /* Eww. No OpenGL hardware in the world does that - let's just * switch to some default. */ if (al_get_pixel_size(format) == 3) { /* Or should we use RGBA? Maybe only if not Nvidia cards? */ format = ALLEGRO_PIXEL_FORMAT_ABGR_8888; } #endif ALLEGRO_TRACE_CHANNEL_LEVEL("display", 1)("Deduced format %s for backbuffer.\n", _al_pixel_format_name(format)); /* Now that the display backbuffer has a format, update extra_settings so * the user can query it back. */ _al_set_color_components(format, &disp->extra_settings, ALLEGRO_REQUIRE); disp->backbuffer_format = format; ALLEGRO_DEBUG("Creating backbuffer bitmap\n"); al_set_new_bitmap_format(format); /* Using ALLEGRO_NO_PRESERVE_TEXTURE prevents extra memory being allocated */ al_set_new_bitmap_flags(ALLEGRO_VIDEO_BITMAP | ALLEGRO_NO_PRESERVE_TEXTURE); backbuffer = _al_ogl_create_bitmap(disp, disp->w, disp->h); al_restore_state(&backup); if (!backbuffer) { ALLEGRO_DEBUG("Backbuffer bitmap creation failed.\n"); return NULL; } ALLEGRO_TRACE_CHANNEL_LEVEL("display", 1)( "Created backbuffer bitmap (actual format: %s)\n", _al_pixel_format_name(backbuffer->format)); ogl_backbuffer = (ALLEGRO_BITMAP_OGL*)backbuffer; ogl_backbuffer->is_backbuffer = 1; backbuffer->display = disp; return ogl_backbuffer; }
static void ogl_unlock_region_nonbb_nonfbo(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y) { const int lock_format = bitmap->locked_region.format; unsigned char *start_ptr; GLenum e; if (bitmap->lock_flags & ALLEGRO_LOCK_WRITEONLY) { ALLEGRO_DEBUG("Unlocking non-backbuffer non-FBO WRITEONLY\n"); start_ptr = ogl_bitmap->lock_buffer; } else { ALLEGRO_DEBUG("Unlocking non-backbuffer non-FBO READWRITE\n"); glPixelStorei(GL_UNPACK_ROW_LENGTH, ogl_bitmap->true_w); start_ptr = (unsigned char *)bitmap->lock_data + (bitmap->lock_h - 1) * bitmap->locked_region.pitch; } glTexSubImage2D(GL_TEXTURE_2D, 0, bitmap->lock_x, gl_y, bitmap->lock_w, bitmap->lock_h, get_glformat(lock_format, 2), get_glformat(lock_format, 1), start_ptr); e = glGetError(); if (e) { ALLEGRO_ERROR("glTexSubImage2D for format %s failed (%s).\n", _al_pixel_format_name(lock_format), _al_gl_error_string(e)); } }
static bool ogl_lock_region_backbuffer( ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int x, int gl_y, int w, int h, int format, int flags) { const int pixel_size = al_get_pixel_size(format); const int pitch = ogl_pitch(w, pixel_size); GLenum e; ogl_bitmap->lock_buffer = al_malloc(pitch * h); if (ogl_bitmap->lock_buffer == NULL) { return false; } if (!(flags & ALLEGRO_LOCK_WRITEONLY)) { glReadPixels(x, gl_y, w, h, get_glformat(format, 2), get_glformat(format, 1), ogl_bitmap->lock_buffer); e = glGetError(); if (e) { ALLEGRO_ERROR("glReadPixels for format %s failed (%s).\n", _al_pixel_format_name(format), _al_gl_error_string(e)); al_free(ogl_bitmap->lock_buffer); ogl_bitmap->lock_buffer = NULL; return false; } } bitmap->locked_region.data = ogl_bitmap->lock_buffer + pitch * (h - 1); bitmap->locked_region.format = format; bitmap->locked_region.pitch = -pitch; bitmap->locked_region.pixel_size = pixel_size; return true; }
static void ogl_unlock_region_backbuffer(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y) { const int lock_format = bitmap->locked_region.format; bool popmatrix = false; GLenum e; GLint program = 0; ALLEGRO_DISPLAY *display = al_get_current_display(); if (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) { // FIXME: This is a hack where we temporarily disable the active shader. // It will only work on Desktop OpenGL in non-strict mode where we even // can switch back to the fixed pipeline. The correct way would be to not // use any OpenGL 2 functions (like glDrawPixels). Probably we will want // separate OpenGL <= 2 (including OpenGL ES 1) and OpenGL >= 3 (including // OpenGL ES >= 2) drivers at some point. glGetIntegerv(GL_CURRENT_PROGRAM, &program); glUseProgram(0); } /* glWindowPos2i may not be available. */ if (al_get_opengl_version() >= _ALLEGRO_OPENGL_VERSION_1_4) { glWindowPos2i(bitmap->lock_x, gl_y); } else { /* glRasterPos is affected by the current modelview and projection * matrices (so maybe we actually need to reset both of them?). * The coordinate is also clipped; the small offset was required to * prevent it being culled on one of my machines. --pw * * Consider using glWindowPos2fMESAemulate from: * http://www.opengl.org/resources/features/KilgardTechniques/oglpitfall/ */ glPushMatrix(); glLoadIdentity(); glRasterPos2f(bitmap->lock_x, bitmap->lock_y + bitmap->lock_h - 1e-4f); popmatrix = true; } glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); glDrawPixels(bitmap->lock_w, bitmap->lock_h, get_glformat(lock_format, 2), get_glformat(lock_format, 1), ogl_bitmap->lock_buffer); e = glGetError(); if (e) { ALLEGRO_ERROR("glDrawPixels for format %s failed (%s).\n", _al_pixel_format_name(lock_format), _al_gl_error_string(e)); } if (popmatrix) { glPopMatrix(); } if (program != 0) { glUseProgram(program); } }
static void use_fbo_for_bitmap(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap, ALLEGRO_FBO_INFO *info) { ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap = bitmap->extra; GLint e; if (info->fbo_state == FBO_INFO_UNUSED) info->fbo_state = FBO_INFO_TRANSIENT; info->owner = bitmap; info->last_use_time = al_get_time(); ogl_bitmap->fbo_info = info; /* Bind to the FBO. */ _al_ogl_bind_framebuffer(info->fbo); /* Attach the texture. */ if (ANDROID_PROGRAMMABLE_PIPELINE(al_get_current_display())) { glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ogl_bitmap->texture, 0); } else { glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, ogl_bitmap->texture, 0); } e = glGetError(); if (e) { ALLEGRO_DEBUG("glFrameBufferTexture2DEXT failed! fbo=%d texture=%d (%s)", info->fbo, ogl_bitmap->texture, _al_gl_error_string(e)); } /* See comment about unimplemented functions on Android above */ if (UNLESS_ANDROID_OR_RPI( glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)) { /* For some reason, we cannot use the FBO with this * texture. So no reason to keep re-trying, output a log * message and switch to (extremely slow) software mode. */ ALLEGRO_ERROR("Could not use FBO for bitmap with format %s.\n", _al_pixel_format_name(al_get_bitmap_format(bitmap))); ALLEGRO_ERROR("*** SWITCHING TO SOFTWARE MODE ***\n"); _al_ogl_bind_framebuffer(0); glDeleteFramebuffersEXT(1, &info->fbo); _al_ogl_reset_fbo_info(info); ogl_bitmap->fbo_info = NULL; } else { display->ogl_extras->opengl_target = bitmap; } }
static bool ogl_lock_region_nonbb_readwrite_nonfbo( ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int x, int gl_y, int w, int h, int format) { /* No FBO - fallback to reading the entire texture */ const int pixel_size = al_get_pixel_size(format); const int pitch = ogl_pitch(ogl_bitmap->true_w, pixel_size); GLenum e; bool ok; (void) w; ogl_bitmap->lock_buffer = al_malloc(pitch * ogl_bitmap->true_h); if (ogl_bitmap->lock_buffer == NULL) { return false; } ok = true; glBindTexture(GL_TEXTURE_2D, ogl_bitmap->texture); glGetTexImage(GL_TEXTURE_2D, 0, get_glformat(format, 2), get_glformat(format, 1), ogl_bitmap->lock_buffer); e = glGetError(); if (e) { ALLEGRO_ERROR("glGetTexImage for format %s failed (%s).\n", _al_pixel_format_name(format), _al_gl_error_string(e)); al_free(ogl_bitmap->lock_buffer); ogl_bitmap->lock_buffer = NULL; ok = false; } if (ok) { bitmap->locked_region.data = ogl_bitmap->lock_buffer + pitch * (gl_y + h - 1) + pixel_size * x; bitmap->locked_region.format = format; bitmap->locked_region.pitch = -pitch; bitmap->locked_region.pixel_size = pixel_size; } return ok; }
static void ogl_unlock_region_nonbb_fbo_readwrite(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y) { const int lock_format = bitmap->locked_region.format; GLenum e; GLint tex_internalformat; glTexSubImage2D(GL_TEXTURE_2D, 0, bitmap->lock_x, gl_y, bitmap->lock_w, bitmap->lock_h, get_glformat(lock_format, 2), get_glformat(lock_format, 1), ogl_bitmap->lock_buffer); e = glGetError(); if (e) { ALLEGRO_ERROR("glTexSubImage2D for format %s failed (%s).\n", _al_pixel_format_name(lock_format), _al_gl_error_string(e)); glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &tex_internalformat); ALLEGRO_DEBUG("x/y/w/h: %d/%d/%d/%d, internal format: %d\n", bitmap->lock_x, gl_y, bitmap->lock_w, bitmap->lock_h, tex_internalformat); } }
static bool ogl_lock_region_nonbb_readwrite_fbo( ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int x, int gl_y, int w, int h, int format) { const int pixel_size = al_get_pixel_size(format); const int pitch = ogl_pitch(w, pixel_size); GLint old_fbo; GLenum e; bool ok; glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &old_fbo); e = glGetError(); if (e) { ALLEGRO_ERROR("glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT) failed (%s).\n", _al_gl_error_string(e)); return false; } ok = true; glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ogl_bitmap->fbo_info->fbo); e = glGetError(); if (e) { ALLEGRO_ERROR("glBindFramebufferEXT failed (%s).\n", _al_gl_error_string(e)); ok = false; } if (ok) { ogl_bitmap->lock_buffer = al_malloc(pitch * h); if (ogl_bitmap->lock_buffer == NULL) { ok = false; } } if (ok) { glReadPixels(x, gl_y, w, h, get_glformat(format, 2), get_glformat(format, 1), ogl_bitmap->lock_buffer); e = glGetError(); if (e) { ALLEGRO_ERROR("glReadPixels for format %s failed (%s).\n", _al_pixel_format_name(format), _al_gl_error_string(e)); } } glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, old_fbo); if (ok) { bitmap->locked_region.data = ogl_bitmap->lock_buffer + pitch * (h - 1); bitmap->locked_region.format = format; bitmap->locked_region.pitch = -pitch; bitmap->locked_region.pixel_size = pixel_size; return true; } al_free(ogl_bitmap->lock_buffer); ogl_bitmap->lock_buffer = NULL; return ok; }
static void setup_fbo(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap) { ALLEGRO_BITMAP_OGL *ogl_bitmap; if (bitmap->parent) bitmap = bitmap->parent; ogl_bitmap = (void *)bitmap; /* We can't return here. Target's FBO can be taken away by locking * a lot of bitmaps consecutively. * Also affects ex_multiwin; resizing one window affects the other. */ if (false && display->ogl_extras->opengl_target == ogl_bitmap) return; #if !defined ALLEGRO_GP2XWIZ if (!ogl_bitmap->is_backbuffer) { ALLEGRO_FBO_INFO *info = NULL; /* When a bitmap is set as target bitmap, we try to create an FBO for it. */ if (ogl_bitmap->fbo_info == NULL && !(bitmap->flags & ALLEGRO_FORCE_LOCKING)) { #ifdef ALLEGRO_IPHONE /* FIXME This is quite a hack but I don't know how the Allegro extension * manager works to fix this properly (getting extensions properly reported * on iphone. */ if (true) #else if (al_get_opengl_extension_list()->ALLEGRO_GL_EXT_framebuffer_object || al_get_opengl_extension_list()->ALLEGRO_GL_OES_framebuffer_object) #endif { info = ogl_find_unused_fbo(display); ASSERT(info->fbo_state != FBO_INFO_PERSISTENT); if (info->fbo_state == FBO_INFO_TRANSIENT) { info->owner->fbo_info = NULL; ALLEGRO_DEBUG("Deleting FBO: %u\n", info->fbo); glDeleteFramebuffersEXT(1, &info->fbo); _al_ogl_reset_fbo_info(info); } glGenFramebuffersEXT(1, &info->fbo); ALLEGRO_DEBUG("Created FBO: %u\n", info->fbo); } } else { info = ogl_bitmap->fbo_info; } if (info && info->fbo) { /* Bind to the FBO. */ #ifndef ALLEGRO_IPHONE ASSERT(display->ogl_extras->extension_list->ALLEGRO_GL_EXT_framebuffer_object || display->ogl_extras->extension_list->ALLEGRO_GL_OES_framebuffer_object); #endif if (info->fbo_state == FBO_INFO_UNUSED) info->fbo_state = FBO_INFO_TRANSIENT; info->owner = ogl_bitmap; info->last_use_time = al_get_time(); ogl_bitmap->fbo_info = info; glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, info->fbo); /* Attach the texture. */ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, ogl_bitmap->texture, 0); if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) { /* For some reason, we cannot use the FBO with this * texture. So no reason to keep re-trying, output a log * message and switch to (extremely slow) software mode. */ ALLEGRO_ERROR("Could not use FBO for bitmap with format %s.\n", _al_pixel_format_name(bitmap->format)); ALLEGRO_ERROR("*** SWITCHING TO SOFTWARE MODE ***\n"); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); glDeleteFramebuffersEXT(1, &info->fbo); _al_ogl_reset_fbo_info(info); ogl_bitmap->fbo_info = NULL; } else { display->ogl_extras->opengl_target = ogl_bitmap; glViewport(0, 0, bitmap->w, bitmap->h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, bitmap->w, bitmap->h, 0, -1, 1); } } } else { display->ogl_extras->opengl_target = ogl_bitmap; // TODO: Might as well have a vtable entry here #ifdef ALLEGRO_IPHONE _al_iphone_setup_opengl_view(display); #else if (display->ogl_extras->extension_list->ALLEGRO_GL_EXT_framebuffer_object || display->ogl_extras->extension_list->ALLEGRO_GL_OES_framebuffer_object) { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } glViewport(0, 0, display->w, display->h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); /* We use upside down coordinates compared to OpenGL, so the bottommost * coordinate is display->h not 0. */ glOrtho(0, display->w, display->h, 0, -1, 1); #endif } #else ALLEGRO_DISPLAY_GP2XWIZ_OGL *wiz_disp = (ALLEGRO_DISPLAY_GP2XWIZ_OGL *)display; display->ogl_extras->opengl_target = ogl_bitmap; if (!ogl_bitmap->is_backbuffer) { /* FIXME: implement */ } else { eglMakeCurrent(wiz_disp->egl_display, wiz_disp->egl_surface, wiz_disp->egl_surface, wiz_disp->egl_context); glViewport(0, 0, display->w, display->h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); /* We use upside down coordinates compared to OpenGL, so the bottommost * coordinate is display->h not 0. */ glOrtho(0, display->w, display->h, 0, -1, 1); } #endif }