/* Copy bitmap->memory to texture memory */ static void d3d_sync_bitmap_texture(ALLEGRO_BITMAP *bitmap, int x, int y, int width, int height) { D3DLOCKED_RECT locked_rect; RECT rect; ALLEGRO_BITMAP_D3D *d3d_bmp = (ALLEGRO_BITMAP_D3D *)bitmap; LPDIRECT3DTEXTURE9 texture; rect.left = x; rect.top = y; rect.right = x + width; rect.bottom = y + height; if (_al_d3d_render_to_texture_supported()) texture = d3d_bmp->system_texture; else texture = d3d_bmp->video_texture; if (texture->LockRect(0, &locked_rect, &rect, 0) == D3D_OK) { _al_convert_bitmap_data(bitmap->memory, bitmap->format, bitmap->w*al_get_pixel_size(bitmap->format), locked_rect.pBits, bitmap->format, locked_rect.Pitch, x, y, 0, 0, width, height); /* Copy an extra row and column so the texture ends nicely */ if (rect.bottom > bitmap->h) { _al_convert_bitmap_data( bitmap->memory, bitmap->format, bitmap->w*al_get_pixel_size(bitmap->format), locked_rect.pBits, bitmap->format, locked_rect.Pitch, 0, bitmap->h-1, 0, height, width, 1); } if (rect.right > bitmap->w) { _al_convert_bitmap_data( bitmap->memory, bitmap->format, bitmap->w*al_get_pixel_size(bitmap->format), locked_rect.pBits, bitmap->format, locked_rect.Pitch, bitmap->w-1, 0, width, 0, 1, height); } if (rect.bottom > bitmap->h && rect.right > bitmap->w) { _al_convert_bitmap_data( bitmap->memory, bitmap->format, bitmap->w*al_get_pixel_size(bitmap->format), locked_rect.pBits, bitmap->format, locked_rect.Pitch, bitmap->w-1, bitmap->h-1, width, height, 1, 1); } texture->UnlockRect(0); } else { ALLEGRO_ERROR("d3d_sync_bitmap_texture: Couldn't lock texture to upload.\n"); } }
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_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; }
bool _al_ogl_resize_backbuffer(ALLEGRO_BITMAP_OGL *b, int w, int h) { int pitch; pitch = w * al_get_pixel_size(b->bitmap.format); b->bitmap.w = w; b->bitmap.h = h; b->bitmap.pitch = pitch; b->bitmap.cl = 0; b->bitmap.ct = 0; b->bitmap.cr_excl = w; b->bitmap.cb_excl = h; /* There is no texture associated with the backbuffer so no need to care * about texture size limitations. */ b->true_w = w; b->true_h = h; #if !defined(ALLEGRO_IPHONE) && !defined(ALLEGRO_GP2XWIZ) b->bitmap.memory = NULL; #else /* iPhone/Wiz ports still expect the buffer to be present. */ { /* FIXME: lazily manage memory */ size_t bytes = pitch * h; al_free(b->bitmap.memory); b->bitmap.memory = al_calloc(1, bytes); } #endif return true; }
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_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; }
void _al_convert_bitmap_data( void *src, int src_format, int src_pitch, void *dst, int dst_format, int dst_pitch, int sx, int sy, int dx, int dy, int width, int height) { ASSERT(src); ASSERT(dst); ASSERT(_al_pixel_format_is_real(dst_format)); /* Use memcpy if no conversion is needed. */ if (src_format == dst_format) { int y; int size = al_get_pixel_size(src_format); char *src_ptr = ((char *)src) + sy * src_pitch + sx * size; char *dst_ptr = ((char *)dst) + dy * dst_pitch + dx * size; width *= size; for (y = 0; y < height; y++) { memcpy(dst_ptr, src_ptr, width); src_ptr += src_pitch; dst_ptr += dst_pitch; } return; } (_al_convert_funcs[src_format][dst_format])(src, src_pitch, dst, dst_pitch, sx, sy, dx, dy, width, height); }
/* Creates a memory bitmap. */ static ALLEGRO_BITMAP *_al_create_memory_bitmap(int w, int h) { ALLEGRO_BITMAP *bitmap; int pitch; int format = al_get_new_bitmap_format(); format = _al_get_real_pixel_format(al_get_current_display(), format); bitmap = al_calloc(1, sizeof *bitmap); bitmap->size = sizeof(*bitmap); pitch = w * al_get_pixel_size(format); bitmap->vt = NULL; bitmap->format = format; bitmap->flags = (al_get_new_bitmap_flags() | ALLEGRO_MEMORY_BITMAP) & ~ALLEGRO_VIDEO_BITMAP; bitmap->w = w; bitmap->h = h; bitmap->pitch = pitch; bitmap->display = NULL; bitmap->locked = false; bitmap->cl = bitmap->ct = 0; bitmap->cr_excl = w; bitmap->cb_excl = h; al_identity_transform(&bitmap->transform); bitmap->parent = NULL; bitmap->xofs = bitmap->yofs = 0; bitmap->memory = al_malloc(pitch * h); bitmap->preserve_texture = !(al_get_new_bitmap_flags() & ALLEGRO_NO_PRESERVE_TEXTURE); return bitmap; }
void m_draw_scaled_backbuffer(int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh, MBITMAP *dest) { ALLEGRO_BITMAP *old_target = al_get_target_bitmap(); int old_format = al_get_new_bitmap_format(); al_set_new_bitmap_format(al_get_bitmap_format(al_get_backbuffer(display))); MBITMAP *tmp = m_create_bitmap(sw, sh); int scr_w = al_get_display_width(display); int scr_h = al_get_display_height(display); if (sx+sw > scr_w) { sw = scr_w-sx; } else if (sx < 0) { sw -= sx; sx = 0; } if (sy+sh > scr_h) { sh = scr_h-sy; } else if (sy < 0) { sh -= sy; sy = 0; } #if defined ALLEGRO_RASPBERRYPI || defined ALLEGRO_IPHONE || defined ALLEGRO_ANDROID ALLEGRO_LOCKED_REGION *lr1 = al_lock_bitmap(tmp->bitmap, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_WRITEONLY); ALLEGRO_LOCKED_REGION *lr2 = al_lock_bitmap_region( al_get_backbuffer(display), sx, sy, sw, sh, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY ); int pixel_size = al_get_pixel_size(al_get_bitmap_format(al_get_backbuffer(display))); for (int y = 0; y < sh; y++) { uint8_t *d1 = (uint8_t *)lr1->data + lr1->pitch * y; uint8_t *d2 = (uint8_t *)lr2->data + lr2->pitch * y; memcpy(d1, d2, pixel_size*sw); } al_unlock_bitmap(tmp->bitmap); al_unlock_bitmap(al_get_backbuffer(display)); #else m_set_target_bitmap(tmp); al_draw_bitmap_region(al_get_backbuffer(display), sx, sy, sw, sh, 0, 0, 0); #endif m_set_target_bitmap(dest); al_draw_scaled_bitmap( tmp->bitmap, 0, 0, sw, sh, dx, dy, dw, dh, 0 ); m_destroy_bitmap(tmp); al_set_target_bitmap(old_target); al_set_new_bitmap_format(old_format); }
/* We use al_get_display_format() as a hint for the preferred RGB ordering when * nothing else is specified. */ static bool try_display_format(ALLEGRO_DISPLAY *display, int *format) { int best_format; int bytes; if (!display) { return false; } best_format = al_get_display_format(display); if (!_al_pixel_format_is_real(best_format)) return false; bytes = al_get_pixel_size(*format); if (bytes && bytes != al_get_pixel_size(best_format)) return false; if (_al_pixel_format_has_alpha(*format) && !_al_pixel_format_has_alpha(best_format)) { switch (best_format) { case ALLEGRO_PIXEL_FORMAT_RGBX_8888: *format = ALLEGRO_PIXEL_FORMAT_RGBA_8888; return true; case ALLEGRO_PIXEL_FORMAT_XRGB_8888: *format = ALLEGRO_PIXEL_FORMAT_ARGB_8888; return true; case ALLEGRO_PIXEL_FORMAT_XBGR_8888: *format = ALLEGRO_PIXEL_FORMAT_ABGR_8888; return true; default: return false; } } *format = best_format; return true; }
static void ogl_lock_region_nonbb_writeonly( 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); (void) x; (void) gl_y; ogl_bitmap->lock_buffer = al_malloc(pitch * h); 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; }
/* Creates a memory bitmap. */ static ALLEGRO_BITMAP *create_memory_bitmap(ALLEGRO_DISPLAY *current_display, int w, int h, int format, int flags) { ALLEGRO_BITMAP *bitmap; int pitch; if (_al_pixel_format_is_video_only(format)) { /* Can't have a video-only memory bitmap... */ return NULL; } format = _al_get_real_pixel_format(current_display, format); bitmap = al_calloc(1, sizeof *bitmap); pitch = w * al_get_pixel_size(format); bitmap->vt = NULL; bitmap->_format = format; /* If this is really a video bitmap, we add it to the list of to * be converted bitmaps. */ bitmap->_flags = flags | ALLEGRO_MEMORY_BITMAP; bitmap->_flags &= ~ALLEGRO_VIDEO_BITMAP; bitmap->w = w; bitmap->h = h; bitmap->pitch = pitch; bitmap->_display = NULL; bitmap->locked = false; bitmap->cl = bitmap->ct = 0; bitmap->cr_excl = w; bitmap->cb_excl = h; al_identity_transform(&bitmap->transform); al_identity_transform(&bitmap->inverse_transform); bitmap->inverse_transform_dirty = false; al_identity_transform(&bitmap->proj_transform); al_orthographic_transform(&bitmap->proj_transform, 0, 0, -1.0, w, h, 1.0); bitmap->parent = NULL; bitmap->xofs = bitmap->yofs = 0; bitmap->memory = al_malloc(pitch * h); _al_register_convert_bitmap(bitmap); return bitmap; }
/* Copy texture memory to bitmap->memory */ static void d3d_sync_bitmap_memory(ALLEGRO_BITMAP *bitmap) { D3DLOCKED_RECT locked_rect; ALLEGRO_BITMAP_D3D *d3d_bmp = (ALLEGRO_BITMAP_D3D *)bitmap; LPDIRECT3DTEXTURE9 texture; if (_al_d3d_render_to_texture_supported()) texture = d3d_bmp->system_texture; else texture = d3d_bmp->video_texture; if (texture->LockRect(0, &locked_rect, NULL, 0) == D3D_OK) { _al_convert_bitmap_data(locked_rect.pBits, bitmap->format, locked_rect.Pitch, bitmap->memory, bitmap->format, al_get_pixel_size(bitmap->format)*bitmap->w, 0, 0, 0, 0, bitmap->w, bitmap->h); texture->UnlockRect(0); } else { ALLEGRO_ERROR("d3d_sync_bitmap_memory: Couldn't lock texture.\n"); } }
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); } }
static ALLEGRO_BITMAP *do_create_bitmap(int w, int h) { ALLEGRO_BITMAP *bitmap; ALLEGRO_BITMAP **back; ALLEGRO_SYSTEM *system = al_get_system_driver(); ALLEGRO_DISPLAY *current_display = al_get_current_display(); int64_t mul; /* Reject bitmaps where a calculation pixel_size*w*h would overflow * int. Supporting such bitmaps would require a lot more work. */ mul = 4 * (int64_t) w * (int64_t) h; if (mul > (int64_t) INT_MAX) { ALLEGRO_WARN("Rejecting %dx%d bitmap\n", w, h); return NULL; } if ((al_get_new_bitmap_flags() & ALLEGRO_MEMORY_BITMAP) || (!current_display || !current_display->vt || current_display->vt->create_bitmap == NULL) || (system->displays._size < 1)) { return _al_create_memory_bitmap(w, h); } /* Else it's a display bitmap */ bitmap = current_display->vt->create_bitmap(current_display, w, h); if (!bitmap) { ALLEGRO_ERROR("failed to create display bitmap\n"); return NULL; } /* XXX the ogl_display driver sets some of these variables. It's not clear * who should be responsible for setting what. * The pitch must be set by the driver. */ bitmap->display = current_display; bitmap->w = w; bitmap->h = h; bitmap->locked = false; bitmap->cl = 0; bitmap->ct = 0; bitmap->cr_excl = w; bitmap->cb_excl = h; al_identity_transform(&bitmap->transform); bitmap->parent = NULL; bitmap->xofs = 0; bitmap->yofs = 0; bitmap->preserve_texture = !(al_get_new_bitmap_flags() & ALLEGRO_NO_PRESERVE_TEXTURE); ASSERT(bitmap->pitch >= w * al_get_pixel_size(bitmap->format)); /* The display driver should have set the bitmap->memory field if * appropriate; video bitmaps may leave it NULL. */ if (!bitmap->vt->upload_bitmap(bitmap)) { al_destroy_bitmap(bitmap); return NULL; } /* We keep a list of bitmaps depending on the current display so that we can * convert them to memory bimaps when the display is destroyed. */ back = _al_vector_alloc_back(¤t_display->bitmaps); *back = bitmap; return bitmap; }
ALLEGRO_BITMAP *_al_create_bitmap_params(ALLEGRO_DISPLAY *current_display, int w, int h, int format, int flags) { ALLEGRO_SYSTEM *system = al_get_system_driver(); ALLEGRO_BITMAP *bitmap; ALLEGRO_BITMAP **back; int64_t mul; bool result; /* Reject bitmaps where a calculation pixel_size*w*h would overflow * int. Supporting such bitmaps would require a lot more work. */ mul = 4 * (int64_t) w * (int64_t) h; if (mul > (int64_t) INT_MAX) { ALLEGRO_WARN("Rejecting %dx%d bitmap\n", w, h); return NULL; } if ((flags & ALLEGRO_MEMORY_BITMAP) || !current_display || !current_display->vt || current_display->vt->create_bitmap == NULL || _al_vector_size(&system->displays) < 1) { if (flags & ALLEGRO_VIDEO_BITMAP) return NULL; return create_memory_bitmap(current_display, w, h, format, flags); } /* Else it's a display bitmap */ bitmap = current_display->vt->create_bitmap(current_display, w, h, format, flags); if (!bitmap) { ALLEGRO_ERROR("failed to create display bitmap\n"); return NULL; } bitmap->_display = current_display; bitmap->w = w; bitmap->h = h; bitmap->locked = false; bitmap->cl = 0; bitmap->ct = 0; bitmap->cr_excl = w; bitmap->cb_excl = h; al_identity_transform(&bitmap->transform); al_identity_transform(&bitmap->inverse_transform); bitmap->inverse_transform_dirty = false; al_identity_transform(&bitmap->proj_transform); al_orthographic_transform(&bitmap->proj_transform, 0, 0, -1.0, w, h, 1.0); bitmap->parent = NULL; bitmap->xofs = 0; bitmap->yofs = 0; bitmap->_flags |= ALLEGRO_VIDEO_BITMAP; bitmap->dirty = !(bitmap->_flags & ALLEGRO_NO_PRESERVE_TEXTURE); /* The display driver should have set the bitmap->memory field if * appropriate; video bitmaps may leave it NULL. */ ASSERT(bitmap->pitch >= w * al_get_pixel_size(bitmap->_format)); result = bitmap->vt->upload_bitmap(bitmap); if (!result) { al_destroy_bitmap(bitmap); if (flags & ALLEGRO_VIDEO_BITMAP) return NULL; /* With ALLEGRO_CONVERT_BITMAP, just use a memory bitmap instead if * video failed. */ return create_memory_bitmap(current_display, w, h, format, flags); } /* We keep a list of bitmaps depending on the current display so that we can * convert them to memory bimaps when the display is destroyed. */ back = _al_vector_alloc_back(¤t_display->bitmaps); *back = bitmap; return 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; 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; }
/* Function: al_lock_bitmap_region */ ALLEGRO_LOCKED_REGION *al_lock_bitmap_region(ALLEGRO_BITMAP *bitmap, int x, int y, int width, int height, int format, int flags) { ASSERT(x >= 0); ASSERT(y >= 0); ASSERT(width >= 0); ASSERT(height >= 0); /* For sub-bitmaps */ if (bitmap->parent) { x += bitmap->xofs; y += bitmap->yofs; bitmap = bitmap->parent; } if (bitmap->locked) return NULL; ASSERT(x+width <= bitmap->w); ASSERT(y+height <= bitmap->h); bitmap->lock_x = x; bitmap->lock_y = y; bitmap->lock_w = width; bitmap->lock_h = height; bitmap->lock_flags = flags; if (bitmap->flags & ALLEGRO_MEMORY_BITMAP) { int f = _al_get_real_pixel_format(al_get_current_display(), format); if (f < 0) { return NULL; } ASSERT(bitmap->memory); if (format == ALLEGRO_PIXEL_FORMAT_ANY || bitmap->format == format || f == bitmap->format) { bitmap->locked_region.data = bitmap->memory + bitmap->pitch * y + x * al_get_pixel_size(bitmap->format); bitmap->locked_region.format = bitmap->format; bitmap->locked_region.pitch = bitmap->pitch; bitmap->locked_region.pixel_size = al_get_pixel_size(bitmap->format); } else { bitmap->locked_region.pitch = al_get_pixel_size(f) * width; bitmap->locked_region.data = al_malloc(bitmap->locked_region.pitch*height); bitmap->locked_region.format = f; bitmap->locked_region.pixel_size = al_get_pixel_size(f); if (!(bitmap->lock_flags & ALLEGRO_LOCK_WRITEONLY)) { _al_convert_bitmap_data( bitmap->memory, bitmap->format, bitmap->pitch, bitmap->locked_region.data, f, bitmap->locked_region.pitch, x, y, 0, 0, width, height); } } } else { if (!bitmap->vt->lock_region(bitmap, x, y, width, height, format, flags)) { return NULL; } } bitmap->locked = true; return &bitmap->locked_region; }
static ALLEGRO_BITMAP *d3d_create_bitmap_from_surface(LPDIRECT3DSURFACE9 surface, int format, int flags) { ALLEGRO_BITMAP *bitmap; ALLEGRO_BITMAP_D3D *d3d_bmp; D3DSURFACE_DESC desc; D3DLOCKED_RECT surf_locked_rect; D3DLOCKED_RECT sys_locked_rect; ALLEGRO_STATE backup; unsigned int y; if (surface->GetDesc(&desc) != D3D_OK) { ALLEGRO_ERROR("d3d_create_bitmap_from_surface: GetDesc failed.\n"); return NULL; } if (surface->LockRect(&surf_locked_rect, 0, D3DLOCK_READONLY) != D3D_OK) { ALLEGRO_ERROR("d3d_create_bitmap_from_surface: LockRect failed.\n"); return NULL; } al_store_state(&backup, ALLEGRO_STATE_NEW_BITMAP_PARAMETERS); al_set_new_bitmap_format(format); al_set_new_bitmap_flags(flags); bitmap = al_create_bitmap(desc.Width, desc.Height); d3d_bmp = (ALLEGRO_BITMAP_D3D *)bitmap; al_restore_state(&backup); if (!bitmap) { surface->UnlockRect(); return NULL; } if (d3d_bmp->system_texture->LockRect(0, &sys_locked_rect, 0, 0) != D3D_OK) { surface->UnlockRect(); al_destroy_bitmap(bitmap); ALLEGRO_ERROR("d3d_create_bitmap_from_surface: Lock system texture failed.\n"); return NULL; } for (y = 0; y < desc.Height; y++) { memcpy( ((char*)sys_locked_rect.pBits)+(sys_locked_rect.Pitch*y), ((char*)surf_locked_rect.pBits)+(surf_locked_rect.Pitch*y), desc.Width*al_get_pixel_size(format) ); } surface->UnlockRect(); d3d_bmp->system_texture->UnlockRect(0); if (d3d_bmp->display->device->UpdateTexture( (IDirect3DBaseTexture9 *)d3d_bmp->system_texture, (IDirect3DBaseTexture9 *)d3d_bmp->video_texture) != D3D_OK) { ALLEGRO_ERROR("d3d_create_bitmap_from_texture: Couldn't update texture.\n"); } return bitmap; }
static ALLEGRO_LOCKED_REGION *d3d_lock_region(ALLEGRO_BITMAP *bitmap, int x, int y, int w, int h, int format, int flags) { ALLEGRO_BITMAP_D3D *d3d_bmp = (ALLEGRO_BITMAP_D3D *)bitmap; if (d3d_bmp->display->device_lost) return NULL; RECT rect; DWORD Flags = flags & ALLEGRO_LOCK_READONLY ? D3DLOCK_READONLY : 0; int f = _al_get_real_pixel_format(al_get_current_display(), format); if (f < 0) { return NULL; } rect.left = x; rect.right = x + w; rect.top = y; rect.bottom = y + h; if (d3d_bmp->is_backbuffer) { ALLEGRO_DISPLAY_D3D *d3d_disp = (ALLEGRO_DISPLAY_D3D *)bitmap->display; if (d3d_disp->render_target->LockRect(&d3d_bmp->locked_rect, &rect, Flags) != D3D_OK) { ALLEGRO_ERROR("LockRect failed in d3d_lock_region.\n"); return NULL; } } else { LPDIRECT3DTEXTURE9 texture; if (_al_d3d_render_to_texture_supported()) { /* * Sync bitmap->memory with texture */ bitmap->locked = false; _al_d3d_sync_bitmap(bitmap); bitmap->locked = true; texture = d3d_bmp->system_texture; } else { texture = d3d_bmp->video_texture; } if (texture->LockRect(0, &d3d_bmp->locked_rect, &rect, Flags) != D3D_OK) { ALLEGRO_ERROR("LockRect failed in d3d_lock_region.\n"); return NULL; } } if (format == ALLEGRO_PIXEL_FORMAT_ANY || bitmap->format == format || f == bitmap->format) { bitmap->locked_region.data = d3d_bmp->locked_rect.pBits; bitmap->locked_region.format = bitmap->format; bitmap->locked_region.pitch = d3d_bmp->locked_rect.Pitch; bitmap->locked_region.pixel_size = al_get_pixel_size(bitmap->format); } else { bitmap->locked_region.pitch = al_get_pixel_size(f) * w; bitmap->locked_region.data = al_malloc(bitmap->locked_region.pitch*h); bitmap->locked_region.format = f; bitmap->locked_region.pixel_size = al_get_pixel_size(bitmap->format); if (!(bitmap->lock_flags & ALLEGRO_LOCK_WRITEONLY)) { _al_convert_bitmap_data( d3d_bmp->locked_rect.pBits, bitmap->format, d3d_bmp->locked_rect.Pitch, bitmap->locked_region.data, f, bitmap->locked_region.pitch, 0, 0, 0, 0, w, h); } } return &bitmap->locked_region; }