/* * Refresh the texture memory. This must be done after a device is * lost or after it is reset. */ void _al_d3d_refresh_texture_memory(void) { unsigned int i; for (i = 0; i < created_bitmaps._size; i++) { ALLEGRO_BITMAP_D3D **bptr = (ALLEGRO_BITMAP_D3D **)_al_vector_ref(&created_bitmaps, i); ALLEGRO_BITMAP_D3D *bmp = *bptr; ALLEGRO_BITMAP *al_bmp = (ALLEGRO_BITMAP *)bmp; ALLEGRO_DISPLAY_D3D *bmps_display = (ALLEGRO_DISPLAY_D3D *)al_bmp->display; if ((al_bmp->flags & ALLEGRO_MEMORY_BITMAP) || (al_bmp->parent)) { continue; } d3d_create_textures(bmps_display, bmp->texture_w, bmp->texture_h, al_bmp->flags, &bmp->video_texture, /*&bmp->system_texture*/0, al_bmp->format); d3d_sync_bitmap_texture(al_bmp, 0, 0, al_bmp->w, al_bmp->h); if (_al_d3d_render_to_texture_supported()) { bmps_display->device->UpdateTexture( (IDirect3DBaseTexture9 *)bmp->system_texture, (IDirect3DBaseTexture9 *)bmp->video_texture); } } }
static void d3d_unlock_region(ALLEGRO_BITMAP *bitmap) { ALLEGRO_BITMAP_D3D *d3d_bmp = (ALLEGRO_BITMAP_D3D *)bitmap; d3d_bmp->modified = true; if (bitmap->locked_region.format != 0 && bitmap->locked_region.format != bitmap->format) { if (!(bitmap->lock_flags & ALLEGRO_LOCK_READONLY)) { _al_convert_bitmap_data( bitmap->locked_region.data, bitmap->locked_region.format, bitmap->locked_region.pitch, d3d_bmp->locked_rect.pBits, bitmap->format, d3d_bmp->locked_rect.Pitch, 0, 0, 0, 0, bitmap->lock_w, bitmap->lock_h); } al_free(bitmap->locked_region.data); } if (d3d_bmp->is_backbuffer) { ALLEGRO_DISPLAY_D3D *d3d_disp = (ALLEGRO_DISPLAY_D3D *)bitmap->display; d3d_disp->render_target->UnlockRect(); } else { LPDIRECT3DTEXTURE9 texture; if (_al_d3d_render_to_texture_supported()) texture = d3d_bmp->system_texture; else texture = d3d_bmp->video_texture; texture->UnlockRect(0); if (bitmap->lock_flags & ALLEGRO_LOCK_READONLY) return; d3d_do_upload(d3d_bmp, bitmap->lock_x, bitmap->lock_y, bitmap->lock_w, bitmap->lock_h, false); } }
/* * Must be called before the D3D device is reset (e.g., when * resizing a window). All non-synced display bitmaps must be * synced to memory. */ void _al_d3d_prepare_bitmaps_for_reset(ALLEGRO_DISPLAY_D3D *disp) { unsigned int i; if (disp->device_lost) return; if (!_al_d3d_render_to_texture_supported()) return; al_lock_mutex(_al_d3d_lost_device_mutex); for (i = 0; i < created_bitmaps._size; i++) { ALLEGRO_BITMAP_D3D **bptr = (ALLEGRO_BITMAP_D3D **)_al_vector_ref(&created_bitmaps, i); ALLEGRO_BITMAP_D3D *bmp = *bptr; ALLEGRO_BITMAP *al_bmp = (ALLEGRO_BITMAP *)bmp; if (bmp->display == disp) { //d3d_sync_bitmap_memory(al_bmp); if (!al_bmp->preserve_texture) { bmp->modified = false; } else if (!bmp->is_backbuffer && bmp->modified && !(al_bmp->flags & ALLEGRO_MEMORY_BITMAP)) { _al_d3d_sync_bitmap(al_bmp); bmp->modified = false; } } } al_unlock_mutex(_al_d3d_lost_device_mutex); }
/* 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"); } }
/* Copies video texture to system texture and bitmap->memory */ static void _al_d3d_sync_bitmap(ALLEGRO_BITMAP *dest) { ALLEGRO_BITMAP_D3D *d3d_dest; LPDIRECT3DSURFACE9 system_texture_surface; LPDIRECT3DSURFACE9 video_texture_surface; UINT i; if (!_al_d3d_render_to_texture_supported()) return; if (dest->locked) { return; } d3d_dest = (ALLEGRO_BITMAP_D3D *)dest; if (d3d_dest->system_texture == NULL || d3d_dest->video_texture == NULL) { return; } if (dest->parent) { dest = dest->parent; } if (d3d_dest->system_texture->GetSurfaceLevel( 0, &system_texture_surface) != D3D_OK) { ALLEGRO_ERROR("_al_d3d_sync_bitmap: GetSurfaceLevel failed while updating video texture.\n"); return; } if (d3d_dest->video_texture->GetSurfaceLevel( 0, &video_texture_surface) != D3D_OK) { ALLEGRO_ERROR("_al_d3d_sync_bitmap: GetSurfaceLevel failed while updating video texture.\n"); return; } if (d3d_dest->display->device->GetRenderTargetData( video_texture_surface, system_texture_surface) != D3D_OK) { ALLEGRO_ERROR("_al_d3d_sync_bitmap: GetRenderTargetData failed.\n"); return; } if ((i = system_texture_surface->Release()) != 0) { ALLEGRO_DEBUG("_al_d3d_sync_bitmap (system) ref count == %d\n", i); } if ((i = video_texture_surface->Release()) != 0) { // This can be non-zero ALLEGRO_DEBUG("_al_d3d_sync_bitmap (video) ref count == %d\n", i); } d3d_sync_bitmap_memory(dest); }
static void d3d_do_upload(ALLEGRO_BITMAP_D3D *d3d_bmp, int x, int y, int width, int height, bool sync_from_memory) { ALLEGRO_BITMAP *bmp = (ALLEGRO_BITMAP *)d3d_bmp; if (sync_from_memory) { d3d_sync_bitmap_texture(bmp, x, y, width, height); } if (_al_d3d_render_to_texture_supported()) { if (d3d_bmp->display->device->UpdateTexture( (IDirect3DBaseTexture9 *)d3d_bmp->system_texture, (IDirect3DBaseTexture9 *)d3d_bmp->video_texture) != D3D_OK) { ALLEGRO_ERROR("d3d_do_upload: Couldn't update texture.\n"); return; } } }
/* 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"); } }
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; }
static void d3d_draw_bitmap_region( ALLEGRO_BITMAP *src, ALLEGRO_COLOR tint, float sx, float sy, float sw, float sh, int flags) { ALLEGRO_BITMAP *dest = al_get_target_bitmap(); ALLEGRO_BITMAP_D3D *d3d_dest = (ALLEGRO_BITMAP_D3D *)dest; ALLEGRO_BITMAP_D3D *d3d_src = (ALLEGRO_BITMAP_D3D *)src; if (!_al_d3d_render_to_texture_supported()) { _al_draw_bitmap_region_memory(src, tint, (int)sx, (int)sy, (int)sw, (int)sh, 0, 0, (int)flags); return; } if (d3d_dest->display->device_lost) return; _al_d3d_set_bitmap_clip(dest); /* For sub-bitmaps */ if (src->parent) { sx += src->xofs; sy += src->yofs; src = src->parent; d3d_src = (ALLEGRO_BITMAP_D3D *)src; } if (dest->parent) { dest = dest->parent; d3d_dest = (ALLEGRO_BITMAP_D3D *)dest; } if (d3d_src->is_backbuffer) { IDirect3DSurface9 *surface; D3DSURFACE_DESC desc; if (d3d_src->display->render_target->GetDesc(&desc) != D3D_OK) { ALLEGRO_ERROR("d3d_draw_bitmap_region: GetDesc failed.\n"); return; } if (desc.MultiSampleType == D3DMULTISAMPLE_NONE) { surface = d3d_src->display->render_target; } else { RECT r; if (d3d_src->display->device->CreateRenderTarget( desc.Width, desc.Height, desc.Format, D3DMULTISAMPLE_NONE, 0, TRUE, &surface, NULL ) != D3D_OK) { ALLEGRO_ERROR( "d3d_draw_bitmap_region: CreateRenderTarget failed.\n"); return; } r.top = 0; r.left = 0; r.right = desc.Width; r.bottom = desc.Height; if (d3d_src->display->device->StretchRect( d3d_src->display->render_target, &r, surface, &r, D3DTEXF_NONE ) != D3D_OK) { ALLEGRO_ERROR("d3d_draw_bitmap_region: StretchRect failed.\n"); surface->Release(); return; } } ALLEGRO_BITMAP *tmp_bmp = d3d_create_bitmap_from_surface( surface, src->flags); if (tmp_bmp) { d3d_draw_bitmap_region((ALLEGRO_BITMAP *)tmp_bmp, tint, sx, sy, sw, sh, flags); al_destroy_bitmap(tmp_bmp); if (desc.MultiSampleType != D3DMULTISAMPLE_NONE) { surface->Release(); } } return; } _al_d3d_set_blender(d3d_dest->display); d3d_draw_textured_quad( d3d_dest->display, d3d_src, tint, sx, sy, sw, sh, flags); d3d_dest->modified = true; }
static bool d3d_create_textures(ALLEGRO_DISPLAY_D3D *disp, int w, int h, int flags, LPDIRECT3DTEXTURE9 *video_texture, LPDIRECT3DTEXTURE9 *system_texture, int format) { int levels; int autogenmipmap; int err; if (flags & ALLEGRO_MIPMAP) { /* "0" for all possible levels, required for auto mipmap generation. */ levels = 0; autogenmipmap = D3DUSAGE_AUTOGENMIPMAP; } else { levels = 1; autogenmipmap = 0; } if (_al_d3d_render_to_texture_supported()) { if (video_texture) { err = disp->device->CreateTexture(w, h, levels, D3DUSAGE_RENDERTARGET | autogenmipmap, (D3DFORMAT)_al_format_to_d3d(format), D3DPOOL_DEFAULT, video_texture, NULL); if (err != D3D_OK && err != D3DOK_NOAUTOGEN) { ALLEGRO_ERROR("d3d_create_textures: Unable to create video texture.\n"); return false; } } if (system_texture) { err = disp->device->CreateTexture(w, h, 1, 0, (D3DFORMAT)_al_format_to_d3d(format), D3DPOOL_SYSTEMMEM, system_texture, NULL); if (err != D3D_OK) { ALLEGRO_ERROR("d3d_create_textures: Unable to create system texture.\n"); if (video_texture && (*video_texture)) { (*video_texture)->Release(); *video_texture = NULL; } return false; } } return true; } else { if (video_texture) { err = disp->device->CreateTexture(w, h, 1, 0, (D3DFORMAT)_al_format_to_d3d(format), D3DPOOL_MANAGED, video_texture, NULL); if (err != D3D_OK) { ALLEGRO_ERROR("d3d_create_textures: Unable to create video texture (no render-to-texture).\n"); return false; } } return true; } }
/* Copies video texture to system texture and bitmap->memory */ static bool _al_d3d_sync_bitmap(ALLEGRO_BITMAP *dest) { ALLEGRO_BITMAP_D3D *d3d_dest; LPDIRECT3DSURFACE9 system_texture_surface; LPDIRECT3DSURFACE9 video_texture_surface; bool ok; UINT i; if (!_al_d3d_render_to_texture_supported()) { ALLEGRO_ERROR("Render-to-texture not supported.\n"); return false; } if (dest->locked) { ALLEGRO_ERROR("Already locked.\n"); return false; } d3d_dest = (ALLEGRO_BITMAP_D3D *)dest; if (d3d_dest->system_texture == NULL || d3d_dest->video_texture == NULL) { ALLEGRO_ERROR("A texture is null.\n"); return false; } if (dest->parent) { dest = dest->parent; } ok = true; system_texture_surface = NULL; video_texture_surface = NULL; if (d3d_dest->system_texture->GetSurfaceLevel( 0, &system_texture_surface) != D3D_OK) { ALLEGRO_ERROR("_al_d3d_sync_bitmap: GetSurfaceLevel failed while updating video texture.\n"); ok = false; } if (ok && d3d_dest->video_texture->GetSurfaceLevel( 0, &video_texture_surface) != D3D_OK) { ALLEGRO_ERROR("_al_d3d_sync_bitmap: GetSurfaceLevel failed while updating video texture.\n"); ok = false; } if (ok && d3d_dest->display->device->GetRenderTargetData( video_texture_surface, system_texture_surface) != D3D_OK) { ALLEGRO_ERROR("_al_d3d_sync_bitmap: GetRenderTargetData failed.\n"); ok = false; } if (system_texture_surface) { if ((i = system_texture_surface->Release()) != 0) { ALLEGRO_DEBUG("_al_d3d_sync_bitmap (system) ref count == %d\n", i); } } if (video_texture_surface) { if ((i = video_texture_surface->Release()) != 0) { // This can be non-zero ALLEGRO_DEBUG("_al_d3d_sync_bitmap (video) ref count == %d\n", i); } } if (ok) { d3d_sync_bitmap_memory(dest); } return ok; }