static void 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; glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &old_fbo); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ogl_bitmap->fbo_info->fbo); ogl_bitmap->lock_buffer = al_malloc(pitch * h); 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_format_name(format), _al_gl_error_string(e)); } glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, old_fbo); 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; }
static void 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; (void) w; ogl_bitmap->lock_buffer = al_malloc(pitch * ogl_bitmap->true_h); 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_format_name(format), _al_gl_error_string(e)); } 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; }
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 void ogl_unlock_region_nonbb_fbo_writeonly(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y, int orig_format) { const int lock_format = bitmap->locked_region.format; const int orig_pixel_size = al_get_pixel_size(orig_format); const int dst_pitch = bitmap->lock_w * orig_pixel_size; unsigned char * const tmpbuf = al_malloc(dst_pitch * bitmap->lock_h); GLenum e; _al_convert_bitmap_data( ogl_bitmap->lock_buffer, bitmap->locked_region.format, -bitmap->locked_region.pitch, tmpbuf, orig_format, dst_pitch, 0, 0, 0, 0, bitmap->lock_w, bitmap->lock_h); glTexSubImage2D(GL_TEXTURE_2D, 0, bitmap->lock_x, gl_y, bitmap->lock_w, bitmap->lock_h, get_glformat(orig_format, 2), get_glformat(orig_format, 1), tmpbuf); e = glGetError(); if (e) { ALLEGRO_ERROR("glTexSubImage2D for format %d failed (%s).\n", lock_format, _al_gl_error_string(e)); } al_free(tmpbuf); }
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 bool check_gl_error(const char* name) { GLenum err = glGetError(); if (err != 0) { ALLEGRO_WARN("%s (%s)\n", name, _al_gl_error_string(err)); return false; } return true; }
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 void xdpy_flip_display(ALLEGRO_DISPLAY *d) { ALLEGRO_SYSTEM_XGLX *system = (ALLEGRO_SYSTEM_XGLX *)al_get_system_driver(); ALLEGRO_DISPLAY_XGLX *glx = (ALLEGRO_DISPLAY_XGLX *)d; int e = glGetError(); if (e) { ALLEGRO_ERROR("OpenGL error was not 0: %s\n", _al_gl_error_string(e)); } if (d->extra_settings.settings[ALLEGRO_SINGLE_BUFFER]) glFlush(); else glXSwapBuffers(system->gfxdisplay, glx->glxwindow); }
GLint _al_ogl_bind_framebuffer(GLint fbo) { GLint old_fbo = _al_android_get_curr_fbo(); GLint e; if (ANDROID_PROGRAMMABLE_PIPELINE(al_get_current_display())) { glBindFramebuffer(GL_FRAMEBUFFER, fbo); } else { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); } e = glGetError(); if (e) { ALLEGRO_DEBUG("glBindFramebufferEXT failed (%s)", _al_gl_error_string(e)); } _al_android_set_curr_fbo(fbo); return old_fbo; }
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; /* 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_format_name(lock_format), _al_gl_error_string(e)); } if (popmatrix) { glPopMatrix(); } }
static bool glsl_use_shader(ALLEGRO_SHADER *shader, ALLEGRO_DISPLAY *display, bool set_projview_matrix_from_display) { ALLEGRO_SHADER_GLSL_S *gl_shader; GLuint program_object; GLenum err; if (!(display->flags & ALLEGRO_OPENGL)) { return false; } gl_shader = (ALLEGRO_SHADER_GLSL_S *)shader; program_object = gl_shader->program_object; glGetError(); /* clear error */ glUseProgram(program_object); err = glGetError(); if (err != GL_NO_ERROR) { ALLEGRO_WARN("glUseProgram(%u) failed: %s\n", program_object, _al_gl_error_string(err)); display->ogl_extras->program_object = 0; return false; } display->ogl_extras->program_object = program_object; /* Copy variable locations. */ display->ogl_extras->varlocs = gl_shader->varlocs; /* Optionally set projview matrix. We skip this when it is known that the * matrices in the display are out of date and are about to be clobbered * itself. */ if (set_projview_matrix_from_display) { _al_glsl_set_projview_matrix( display->ogl_extras->varlocs.projview_matrix_loc, &display->projview_transform); } return true; }
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); } }
ALLEGRO_LOCKED_REGION *_al_ogl_lock_region_new(ALLEGRO_BITMAP *bitmap, int x, int y, int w, int h, int format, int flags) { ALLEGRO_BITMAP_EXTRA_OPENGL * const ogl_bitmap = bitmap->extra; const GLint gl_y = bitmap->h - y - h; ALLEGRO_DISPLAY *disp; ALLEGRO_DISPLAY *old_disp = NULL; ALLEGRO_BITMAP *old_target = al_get_target_bitmap(); GLenum e; bool ok; bool restore_fbo = false; if (format == ALLEGRO_PIXEL_FORMAT_ANY) { /* Never pick compressed formats with ANY, as it interacts weirdly with * existing code (e.g. al_get_pixel_size() etc) */ int bitmap_format = al_get_bitmap_format(bitmap); if (_al_pixel_format_is_compressed(bitmap_format)) { // XXX Get a good format from the driver? format = ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE; } else { format = bitmap_format; } } disp = al_get_current_display(); format = _al_get_real_pixel_format(disp, format); /* Change OpenGL context if necessary. */ if (!disp || (_al_get_bitmap_display(bitmap)->ogl_extras->is_shared == false && _al_get_bitmap_display(bitmap) != disp)) { old_disp = disp; _al_set_current_display_only(_al_get_bitmap_display(bitmap)); } ok = true; /* Set up the pixel store state. We will need to match it when unlocking. * There may be other pixel store state we should be setting. * See also pitfalls 7 & 8 from: * http://www.opengl.org/resources/features/KilgardTechniques/oglpitfall/ */ glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); { const int pixel_size = al_get_pixel_size(format); const int pixel_alignment = ogl_pixel_alignment(pixel_size); glPixelStorei(GL_PACK_ALIGNMENT, pixel_alignment); e = glGetError(); if (e) { ALLEGRO_ERROR("glPixelStorei(GL_PACK_ALIGNMENT, %d) failed (%s).\n", pixel_alignment, _al_gl_error_string(e)); ok = false; } } if (ok) { if (ogl_bitmap->is_backbuffer) { ALLEGRO_DEBUG("Locking backbuffer\n"); ok = ogl_lock_region_backbuffer(bitmap, ogl_bitmap, x, gl_y, w, h, format, flags); } else if (flags & ALLEGRO_LOCK_WRITEONLY) { ALLEGRO_DEBUG("Locking non-backbuffer WRITEONLY\n"); ok = ogl_lock_region_nonbb_writeonly(bitmap, ogl_bitmap, x, gl_y, w, h, format); } else { ALLEGRO_DEBUG("Locking non-backbuffer READWRITE\n"); ok = ogl_lock_region_nonbb_readwrite(bitmap, ogl_bitmap, x, gl_y, w, h, format, &restore_fbo); } } glPopClientAttrib(); /* Restore state after switching FBO. */ if (restore_fbo) { if (!old_target) { /* Old target was NULL; release the context. */ _al_set_current_display_only(NULL); } else if (!_al_get_bitmap_display(old_target)) { /* Old target was memory bitmap; leave the current display alone. */ } else if (old_target != bitmap) { /* Old target was another OpenGL bitmap. */ _al_ogl_setup_fbo(_al_get_bitmap_display(old_target), old_target); } } ASSERT(al_get_target_bitmap() == old_target); if (old_disp != NULL) { _al_set_current_display_only(old_disp); } if (ok) { return &bitmap->locked_region; } ALLEGRO_ERROR("Failed to lock region\n"); ASSERT(ogl_bitmap->lock_buffer == NULL); return NULL; }
static void ogl_flush_vertex_cache(ALLEGRO_DISPLAY *disp) { GLuint current_texture; ALLEGRO_OGL_EXTRAS *o = disp->ogl_extras; if (!disp->vertex_cache) return; if (disp->num_cache_vertices == 0) return; if (disp->flags & ALLEGRO_USE_PROGRAMMABLE_PIPELINE) { #ifndef ALLEGRO_CFG_NO_GLES2 if (disp->ogl_extras->use_tex_loc >= 0) { glUniform1i(disp->ogl_extras->use_tex_loc, 1); } if (disp->ogl_extras->use_tex_matrix_loc >= 0) { glUniform1i(disp->ogl_extras->use_tex_matrix_loc, 0); } #endif } else { glEnable(GL_TEXTURE_2D); } glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)¤t_texture); if (current_texture != disp->cache_texture) { if (disp->flags & ALLEGRO_USE_PROGRAMMABLE_PIPELINE) { #ifndef ALLEGRO_CFG_NO_GLES2 /* Use texture unit 0 */ glActiveTexture(GL_TEXTURE0); if (disp->ogl_extras->tex_loc >= 0) glUniform1i(disp->ogl_extras->tex_loc, 0); #endif } glBindTexture(GL_TEXTURE_2D, disp->cache_texture); } #if !defined ALLEGRO_IPHONE && !defined ALLEGRO_ANDROID if (disp->flags & ALLEGRO_USE_PROGRAMMABLE_PIPELINE) { int stride = sizeof(ALLEGRO_OGL_BITMAP_VERTEX); int bytes = disp->num_cache_vertices * stride; /* We create the VAO and VBO on first use. */ if (o->vao == 0) { glGenVertexArrays(1, &o->vao); ALLEGRO_DEBUG("new VAO: %u\n", o->vao); } glBindVertexArray(o->vao); if (o->vbo == 0) { glGenBuffers(1, &o->vbo); ALLEGRO_DEBUG("new VBO: %u\n", o->vbo); } glBindBuffer(GL_ARRAY_BUFFER, o->vbo); /* Then we upload data into it. */ glBufferData(GL_ARRAY_BUFFER, bytes, disp->vertex_cache, GL_STREAM_DRAW); /* Finally set the "pos", "texccord" and "color" attributes used by our * shader and enable them. */ if (o->pos_loc >= 0) { glVertexAttribPointer(o->pos_loc, 2, GL_FLOAT, false, stride, (void *)offsetof(ALLEGRO_OGL_BITMAP_VERTEX, x)); glEnableVertexAttribArray(o->pos_loc); } if (o->texcoord_loc >= 0) { glVertexAttribPointer(o->texcoord_loc, 2, GL_FLOAT, false, stride, (void *)offsetof(ALLEGRO_OGL_BITMAP_VERTEX, tx)); glEnableVertexAttribArray(o->texcoord_loc); } if (o->color_loc >= 0) { glVertexAttribPointer(o->color_loc, 4, GL_FLOAT, false, stride, (void *)offsetof(ALLEGRO_OGL_BITMAP_VERTEX, r)); glEnableVertexAttribArray(o->color_loc); } } else #endif { vert_ptr_on(disp, 2, GL_FLOAT, sizeof(ALLEGRO_OGL_BITMAP_VERTEX), (char *)(disp->vertex_cache) + offsetof(ALLEGRO_OGL_BITMAP_VERTEX, x)); tex_ptr_on(disp, 2, GL_FLOAT, sizeof(ALLEGRO_OGL_BITMAP_VERTEX), (char*)(disp->vertex_cache) + offsetof(ALLEGRO_OGL_BITMAP_VERTEX, tx)); color_ptr_on(disp, 4, GL_FLOAT, sizeof(ALLEGRO_OGL_BITMAP_VERTEX), (char*)(disp->vertex_cache) + offsetof(ALLEGRO_OGL_BITMAP_VERTEX, r)); if (!(disp->flags & ALLEGRO_USE_PROGRAMMABLE_PIPELINE)) glDisableClientState(GL_NORMAL_ARRAY); } glDrawArrays(GL_TRIANGLES, 0, disp->num_cache_vertices); #ifdef DEBUGMODE { int e = glGetError(); if (e) { ALLEGRO_WARN("glDrawArrays failed: %s\n", _al_gl_error_string(e)); } } #endif #if !defined ALLEGRO_IPHONE && !defined ALLEGRO_ANDROID if (disp->flags & ALLEGRO_USE_PROGRAMMABLE_PIPELINE) { if (o->pos_loc >= 0) glDisableVertexAttribArray(o->pos_loc); if (o->texcoord_loc >= 0) glDisableVertexAttribArray(o->texcoord_loc); if (o->color_loc >= 0) glDisableVertexAttribArray(o->color_loc); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); } else #endif { vert_ptr_off(disp); tex_ptr_off(disp); color_ptr_off(disp); } disp->num_cache_vertices = 0; if (disp->flags & ALLEGRO_USE_PROGRAMMABLE_PIPELINE) { #ifndef ALLEGRO_CFG_NO_GLES2 if (disp->ogl_extras->use_tex_loc >= 0) glUniform1i(disp->ogl_extras->use_tex_loc, 0); #endif } }
bool _al_ogl_create_persistent_fbo(ALLEGRO_BITMAP *bitmap) { ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap; ALLEGRO_FBO_INFO *info; GLint old_fbo, e; if (bitmap->parent) bitmap = bitmap->parent; ogl_bitmap = bitmap->extra; /* Don't continue if the bitmap does not belong to the current display. */ if (_al_get_bitmap_display(bitmap)->ogl_extras->is_shared == false && _al_get_bitmap_display(bitmap) != al_get_current_display()) { return false; } if (ogl_bitmap->is_backbuffer) { return false; } ASSERT(!ogl_bitmap->fbo_info); info = al_malloc(sizeof(ALLEGRO_FBO_INFO)); if (ANDROID_PROGRAMMABLE_PIPELINE(al_get_current_display())) { glGenFramebuffers(1, &info->fbo); } else { glGenFramebuffersEXT(1, &info->fbo); } if (info->fbo == 0) { al_free(info); return false; } old_fbo = _al_ogl_bind_framebuffer(info->fbo); 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)); } /* You'll see this a couple times in this file: some ES 1.1 functions aren't * implemented on Android. This is an ugly workaround. */ if (UNLESS_ANDROID_OR_RPI( glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)) { ALLEGRO_ERROR("FBO incomplete.\n"); _al_ogl_bind_framebuffer(old_fbo); glDeleteFramebuffersEXT(1, &info->fbo); al_free(info); return false; } _al_ogl_bind_framebuffer(old_fbo); info->fbo_state = FBO_INFO_PERSISTENT; info->owner = bitmap; info->last_use_time = al_get_time(); ogl_bitmap->fbo_info = info; ALLEGRO_DEBUG("Persistent FBO: %u\n", info->fbo); return true; }
static void ogl_unlock_region_non_readonly(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap) { const int lock_format = bitmap->locked_region.format; const int gl_y = bitmap->h - bitmap->lock_y - bitmap->lock_h; ALLEGRO_DISPLAY *old_disp = NULL; ALLEGRO_DISPLAY *disp; int orig_format; bool biased_alpha = false; GLenum e; disp = al_get_current_display(); orig_format = _al_get_real_pixel_format(disp, _al_get_bitmap_memory_format(bitmap)); /* Change OpenGL context if necessary. */ if (!disp || (_al_get_bitmap_display(bitmap)->ogl_extras->is_shared == false && _al_get_bitmap_display(bitmap) != disp)) { old_disp = disp; _al_set_current_display_only(_al_get_bitmap_display(bitmap)); } /* Keep this in sync with ogl_lock_region. */ glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); { const int lock_pixel_size = al_get_pixel_size(lock_format); const int pixel_alignment = ogl_pixel_alignment(lock_pixel_size); glPixelStorei(GL_UNPACK_ALIGNMENT, pixel_alignment); e = glGetError(); if (e) { ALLEGRO_ERROR("glPixelStorei(GL_UNPACK_ALIGNMENT, %d) failed (%s).\n", pixel_alignment, _al_gl_error_string(e)); } } if (exactly_15bpp(lock_format)) { /* OpenGL does not support 15-bpp internal format without an alpha, * so when storing such data we must ensure the alpha bit is set. */ glPixelTransferi(GL_ALPHA_BIAS, 1); biased_alpha = true; } if (ogl_bitmap->is_backbuffer) { ALLEGRO_DEBUG("Unlocking backbuffer\n"); ogl_unlock_region_backbuffer(bitmap, ogl_bitmap, gl_y); } else { glBindTexture(GL_TEXTURE_2D, ogl_bitmap->texture); if (ogl_bitmap->fbo_info) { ALLEGRO_DEBUG("Unlocking non-backbuffer (FBO)\n"); ogl_unlock_region_nonbb_fbo(bitmap, ogl_bitmap, gl_y, orig_format); } else { ALLEGRO_DEBUG("Unlocking non-backbuffer (non-FBO)\n"); ogl_unlock_region_nonbb_nonfbo(bitmap, ogl_bitmap, gl_y); } /* If using FBOs, we need to regenerate mipmaps explicitly now. */ /* XXX why don't we check ogl_bitmap->fbo_info? */ if ((al_get_bitmap_flags(bitmap) & ALLEGRO_MIPMAP) && al_get_opengl_extension_list()->ALLEGRO_GL_EXT_framebuffer_object) { glGenerateMipmapEXT(GL_TEXTURE_2D); e = glGetError(); if (e) { ALLEGRO_ERROR("glGenerateMipmapEXT for texture %d failed (%s).\n", ogl_bitmap->texture, _al_gl_error_string(e)); } } } if (biased_alpha) { glPixelTransferi(GL_ALPHA_BIAS, 0); } glPopClientAttrib(); if (old_disp) { _al_set_current_display_only(old_disp); } }
ALLEGRO_LOCKED_REGION *_al_ogl_lock_region_new(ALLEGRO_BITMAP *bitmap, int x, int y, int w, int h, int format, int flags) { ALLEGRO_BITMAP_EXTRA_OPENGL * const ogl_bitmap = bitmap->extra; const GLint gl_y = bitmap->h - y - h; ALLEGRO_DISPLAY *disp; ALLEGRO_DISPLAY *old_disp = NULL; GLenum e; if (format == ALLEGRO_PIXEL_FORMAT_ANY) { format = bitmap->format; } disp = al_get_current_display(); format = _al_get_real_pixel_format(disp, format); /* Change OpenGL context if necessary. */ if (!disp || (bitmap->display->ogl_extras->is_shared == false && bitmap->display != disp)) { old_disp = disp; _al_set_current_display_only(bitmap->display); } /* Set up the pixel store state. We will need to match it when unlocking. * There may be other pixel store state we should be setting. * See also pitfalls 7 & 8 from: * http://www.opengl.org/resources/features/KilgardTechniques/oglpitfall/ */ glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); { const int pixel_size = al_get_pixel_size(format); const int pixel_alignment = ogl_pixel_alignment(pixel_size); glPixelStorei(GL_PACK_ALIGNMENT, pixel_alignment); e = glGetError(); if (e) { ALLEGRO_ERROR("glPixelStorei(GL_PACK_ALIGNMENT, %d) failed (%s).\n", pixel_alignment, _al_gl_error_string(e)); } } if (ogl_bitmap->is_backbuffer) { ALLEGRO_DEBUG("Locking backbuffer\n"); ogl_lock_region_backbuffer(bitmap, ogl_bitmap, x, gl_y, w, h, format, flags); } else if (flags & ALLEGRO_LOCK_WRITEONLY) { ALLEGRO_DEBUG("Locking non-backbuffer WRITEONLY\n"); ogl_lock_region_nonbb_writeonly(bitmap, ogl_bitmap, x, gl_y, w, h, format); } else { ALLEGRO_DEBUG("Locking non-backbuffer READWRITE\n"); ogl_lock_region_nonbb_readwrite(bitmap, ogl_bitmap, x, gl_y, w, h, format); } glPopClientAttrib(); if (old_disp != NULL) { _al_set_current_display_only(old_disp); } return &bitmap->locked_region; }