static bool ogl_lock_region_nonbb_readwrite( ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int x, int gl_y, int w, int h, int format, bool* restore_fbo) { bool ok; ASSERT(bitmap->parent == NULL); ASSERT(bitmap->locked == false); ASSERT(_al_get_bitmap_display(bitmap) == al_get_current_display()); /* Try to create an FBO if there isn't one. */ *restore_fbo = _al_ogl_setup_fbo_non_backbuffer(_al_get_bitmap_display(bitmap), bitmap); if (ogl_bitmap->fbo_info) { ALLEGRO_DEBUG("Locking non-backbuffer READWRITE with fbo\n"); ok = ogl_lock_region_nonbb_readwrite_fbo(bitmap, ogl_bitmap, x, gl_y, w, h, format); } else { ALLEGRO_DEBUG("Locking non-backbuffer READWRITE no fbo\n"); ok = ogl_lock_region_nonbb_readwrite_nonfbo(bitmap, ogl_bitmap, x, gl_y, w, h, format); } return ok; }
static void _bitmap_drawer(ALLEGRO_BITMAP *bitmap, ALLEGRO_COLOR tint, float sx, float sy, float sw, float sh, int flags) { ALLEGRO_BITMAP *dest = al_get_target_bitmap(); ALLEGRO_DISPLAY *display = _al_get_bitmap_display(dest); ASSERT(bitmap->parent == NULL); ASSERT(!(flags & (ALLEGRO_FLIP_HORIZONTAL | ALLEGRO_FLIP_VERTICAL))); ASSERT(bitmap != dest && bitmap != dest->parent); /* If destination is memory, do a memory blit */ if (al_get_bitmap_flags(dest) & ALLEGRO_MEMORY_BITMAP || _al_pixel_format_is_compressed(al_get_bitmap_format(dest))) { _al_draw_bitmap_region_memory(bitmap, tint, sx, sy, sw, sh, 0, 0, flags); } else { /* if source is memory or incompatible */ if ((al_get_bitmap_flags(bitmap) & ALLEGRO_MEMORY_BITMAP) || (!al_is_compatible_bitmap(bitmap))) { if (display && display->vt->draw_memory_bitmap_region) { display->vt->draw_memory_bitmap_region(display, bitmap, sx, sy, sw, sh, flags); } else { _al_draw_bitmap_region_memory(bitmap, tint, sx, sy, sw, sh, 0, 0, flags); } } else { /* Compatible display bitmap, use full acceleration */ bitmap->vt->draw_bitmap_region(bitmap, tint, sx, sy, sw, sh, flags); } } }
/* Function: al_destroy_display */ void al_destroy_display(ALLEGRO_DISPLAY *display) { if (display) { /* This causes warnings and potential errors on Android because * it clears the context and Android needs this thread to have * the context bound in its destroy function and to destroy the * shader. Just skip this part on Android. */ #ifndef ALLEGRO_ANDROID ALLEGRO_BITMAP *bmp; bmp = al_get_target_bitmap(); if (bmp && _al_get_bitmap_display(bmp) == display) al_set_target_bitmap(NULL); /* This can happen if we have a current display, but the target bitmap * was a memory bitmap. */ if (display == al_get_current_display()) _al_set_current_display_only(NULL); #endif al_destroy_shader(display->default_shader); display->default_shader = NULL; ASSERT(display->vt); display->vt->destroy_display(display); } }
/* Function: al_backup_dirty_bitmaps */ void al_backup_dirty_bitmaps(ALLEGRO_DISPLAY *display) { unsigned int i; for (i = 0; i < display->bitmaps._size; i++) { ALLEGRO_BITMAP **bptr = (ALLEGRO_BITMAP **)_al_vector_ref(&display->bitmaps, i); ALLEGRO_BITMAP *bmp = *bptr; if (_al_get_bitmap_display(bmp) == display) { if (bmp->vt && bmp->vt->backup_dirty_bitmap) { bmp->vt->backup_dirty_bitmap(bmp); } } } }
/* Function: al_clear_depth_buffer */ void al_clear_depth_buffer(float z) { ALLEGRO_BITMAP *target = al_get_target_bitmap(); ASSERT(target); if (al_get_bitmap_flags(target) & ALLEGRO_MEMORY_BITMAP) { /* has no depth buffer */ } else { ALLEGRO_DISPLAY *display = _al_get_bitmap_display(target); ASSERT(display); display->vt->clear_depth_buffer(display, z); } }
/* Function: al_clear_to_color */ void al_clear_to_color(ALLEGRO_COLOR color) { ALLEGRO_BITMAP *target = al_get_target_bitmap(); ASSERT(target); if (al_get_bitmap_flags(target) & ALLEGRO_MEMORY_BITMAP || _al_pixel_format_is_compressed(al_get_bitmap_format(target))) { _al_clear_bitmap_by_locking(target, &color); } else { ALLEGRO_DISPLAY *display = _al_get_bitmap_display(target); ASSERT(display); ASSERT(display->vt); display->vt->clear(display, &color); } }
/* Function: al_draw_pixel */ void al_draw_pixel(float x, float y, ALLEGRO_COLOR color) { ALLEGRO_BITMAP *target = al_get_target_bitmap(); ASSERT(target); if (al_get_bitmap_flags(target) & ALLEGRO_MEMORY_BITMAP || _al_pixel_format_is_compressed(al_get_bitmap_format(target))) { _al_draw_pixel_memory(target, x, y, &color); } else { ALLEGRO_DISPLAY *display = _al_get_bitmap_display(target); ASSERT(display); ASSERT(display->vt); display->vt->draw_pixel(display, x, y, &color); } }
/* Function: al_destroy_bitmap */ void al_destroy_bitmap(ALLEGRO_BITMAP *bitmap) { if (!bitmap) { return; } /* As a convenience, implicitly untarget the bitmap on the calling thread * before it is destroyed, but maintain the current display. */ if (bitmap == al_get_target_bitmap()) { ALLEGRO_DISPLAY *display = al_get_current_display(); if (display) al_set_target_bitmap(al_get_backbuffer(display)); else al_set_target_bitmap(NULL); } _al_set_bitmap_shader_field(bitmap, NULL); _al_unregister_destructor(_al_dtor_list, bitmap); if (!al_is_sub_bitmap(bitmap)) { ALLEGRO_DISPLAY* disp = _al_get_bitmap_display(bitmap); if (al_get_bitmap_flags(bitmap) & ALLEGRO_MEMORY_BITMAP) { destroy_memory_bitmap(bitmap); return; } /* Else it's a display bitmap */ if (bitmap->locked) al_unlock_bitmap(bitmap); if (bitmap->vt) bitmap->vt->destroy_bitmap(bitmap); if (disp) _al_vector_find_and_delete(&disp->bitmaps, &bitmap); if (bitmap->memory) al_free(bitmap->memory); } al_free(bitmap); }
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_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); } }
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; }