From 93cef9c3bf3c93e8cd89f0694918e1548e3163e2 Mon Sep 17 00:00:00 2001 From: David Rose Date: Thu, 14 Aug 2008 00:25:34 +0000 Subject: [PATCH] async texture loading support for dx8,9 --- panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx | 60 +++++++++---- panda/src/dxgsg8/dxGraphicsStateGuardian8.h | 2 + panda/src/dxgsg8/dxTextureContext8.cxx | 89 ++++++++++++++++++ panda/src/dxgsg8/dxTextureContext8.h | 1 + panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx | 58 ++++++++---- panda/src/dxgsg9/dxGraphicsStateGuardian9.h | 2 + panda/src/dxgsg9/dxTextureContext9.cxx | 90 ++++++++++++++++++- panda/src/dxgsg9/dxTextureContext9.h | 1 + 8 files changed, 265 insertions(+), 38 deletions(-) diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx index 8d591b3c3f..17c6e38a1a 100644 --- a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx @@ -160,7 +160,9 @@ prepare_texture(Texture *tex) { return NULL; } - if (!dtc->create_texture(*_screen)) { + if (!upload_texture(dtc)) { + dxgsg8_cat.error() + << "Unable to create texture " << *tex << endl; delete dtc; return NULL; } @@ -186,28 +188,21 @@ apply_texture(int i, TextureContext *tc) { tc->set_active(true); DXTextureContext8 *dtc = DCAST(DXTextureContext8, tc); + Texture *tex = tc->get_texture(); // If the texture image has changed, or if its use of mipmaps has // changed, we need to re-create the image. if (dtc->was_modified()) { - if (!get_supports_compressed_texture_format(tc->get_texture()->get_ram_image_compression())) { - dxgsg8_cat.error() - << *dtc->get_texture() << " is stored in an unsupported compressed format.\n"; - _d3d_device->SetTextureStageState(i, D3DTSS_COLOROP, D3DTOP_DISABLE); - return; - } - - if (!dtc->create_texture(*_screen)) { + if (!upload_texture(dtc)) { // Oops, we can't re-create the texture for some reason. dxgsg8_cat.error() - << "Unable to re-create texture " << *dtc->get_texture() << endl; - _d3d_device->SetTextureStageState(i, D3DTSS_COLOROP, D3DTOP_DISABLE); + << "Unable to re-create texture " << *tex << endl; + _d3d_device->SetTextureStageState(i, D3DTSS_COLOROP, D3DTOP_DISABLE); return; } } - Texture *tex = tc->get_texture(); Texture::WrapMode wrap_u, wrap_v, wrap_w; wrap_u = tex->get_wrap_u(); wrap_v = tex->get_wrap_v(); @@ -249,16 +244,10 @@ apply_texture(int i, TextureContext *tc) { new_mip_filter = D3DTEXF_NONE; } -#ifndef NDEBUG // sanity check - if ((!dtc->has_mipmaps()) && (new_mip_filter != D3DTEXF_NONE)) { - dxgsg8_cat.error() - << "Trying to set mipmap filtering for texture with no generated mipmaps!! texname[" - << tex->get_name() << "], filter(" - << tex->get_minfilter() << ")\n"; + if (!dtc->has_mipmaps()) { new_mip_filter = D3DTEXF_NONE; } -#endif if (aniso_degree >= 2) { new_min_filter = D3DTEXF_ANISOTROPIC; @@ -270,6 +259,39 @@ apply_texture(int i, TextureContext *tc) { _d3d_device->SetTexture(i, dtc->get_d3d_texture()); } +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian8::upload_texture +// Access: Public +// Description: Creates a texture surface on the graphics card and +// fills it with its pixel data. +//////////////////////////////////////////////////////////////////// +bool DXGraphicsStateGuardian8:: +upload_texture(DXTextureContext8 *dtc) { + Texture *tex = dtc->get_texture(); + if (!get_supports_compressed_texture_format(tex->get_ram_image_compression())) { + dxgsg8_cat.error() + << *tex << " is stored in an unsupported compressed format.\n"; + return false; + } + + if (_incomplete_render && + !tex->has_ram_image() && tex->might_have_ram_image() && + tex->has_simple_ram_image() && + !_loader.is_null()) { + // If we don't have the texture data right now, go get it, but in + // the meantime load a temporary simple image in its place. + async_reload_texture(dtc); + if (!tex->has_ram_image()) { + if (dtc->was_simple_image_modified()) { + return dtc->create_simple_texture(*_screen); + } + return true; + } + } + + return dtc->create_texture(*_screen); +} + //////////////////////////////////////////////////////////////////// // Function: DXGraphicsStateGuardian8::release_texture // Access: Public, Virtual diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.h b/panda/src/dxgsg8/dxGraphicsStateGuardian8.h index 0b5421e0e8..579907d0aa 100644 --- a/panda/src/dxgsg8/dxGraphicsStateGuardian8.h +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.h @@ -31,6 +31,7 @@ class Light; +class DXTextureContext8; class DXVertexBufferContext8; class DXIndexBufferContext8; @@ -49,6 +50,7 @@ public: virtual TextureContext *prepare_texture(Texture *tex); void apply_texture(int i, TextureContext *tc); + bool upload_texture(DXTextureContext8 *dtc); virtual void release_texture(TextureContext *tc); virtual VertexBufferContext *prepare_vertex_buffer(GeomVertexArrayData *data); diff --git a/panda/src/dxgsg8/dxTextureContext8.cxx b/panda/src/dxgsg8/dxTextureContext8.cxx index c7bc3d6554..9f2bd789a1 100644 --- a/panda/src/dxgsg8/dxTextureContext8.cxx +++ b/panda/src/dxgsg8/dxTextureContext8.cxx @@ -722,6 +722,95 @@ create_texture(DXScreenData &scrn) { return false; } +//////////////////////////////////////////////////////////////////// +// Function: DXTextureContext8::create_simple_texture +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +bool DXTextureContext8:: +create_simple_texture(DXScreenData &scrn) { + nassertr(IS_VALID_PTR(get_texture()), false); + + HRESULT hr; + + delete_texture(); + + _d3d_format = D3DFMT_A8R8G8B8; + D3DFORMAT target_pixel_format = D3DFMT_A8R8G8B8; + DWORD target_bpp = 32; + DWORD num_color_channels = 4; + + DWORD target_width = (DWORD)get_texture()->get_simple_x_size(); + DWORD target_height = (DWORD)get_texture()->get_simple_y_size(); + DWORD mip_level_count = 1; + DWORD usage = 0; + D3DPOOL pool = D3DPOOL_MANAGED; + + int data_size = target_width * target_height * 4; + + hr = scrn._d3d_device->CreateTexture + (target_width, target_height, mip_level_count, usage, + target_pixel_format, pool, &_d3d_2d_texture); + _d3d_texture = _d3d_2d_texture; + if (FAILED(hr)) { + dxgsg8_cat.error() + << "D3D create_simple_texture failed!" << D3DERRORSTRING(hr); + dxgsg8_cat.error() + << " width = " << target_width << " height = " << target_height << " target_pixel_format = " << target_pixel_format << "\n"; + + goto error_exit; + } + + if (dxgsg8_cat.is_debug()) { + dxgsg8_cat.debug() + << "create_simple_texture: " << get_texture()->get_name() + << "\n"; + } + + { + CPTA_uchar image = get_texture()->get_simple_ram_image(); + + hr = -1; + // hr = fill_d3d_texture_pixels(scrn._supports_automatic_mipmap_generation, scrn._d3d_device); + + IDirect3DSurface8 *surface = NULL; + _d3d_2d_texture->GetSurfaceLevel(0, &surface); + + RECT source_size; + source_size.left = source_size.top = 0; + source_size.right = target_width; + source_size.bottom = target_height; + + DWORD mip_filter = D3DX_FILTER_LINEAR; + + hr = D3DXLoadSurfaceFromMemory + (surface, (PALETTEENTRY*)NULL, (RECT*)NULL, (LPCVOID)image.p(), + target_pixel_format, target_width * 4, (PALETTEENTRY*)NULL, + &source_size, mip_filter, (D3DCOLOR)0x0); + + RELEASE(surface, dxgsg8, "create_simple_texture Surface", RELEASE_ONCE); + } + + if (FAILED(hr)) { + dxgsg8_cat.debug () + << "*** fill_d3d_texture_pixels failed ***: format " + << target_pixel_format + << "\n"; + + goto error_exit; + } + + mark_simple_loaded(); + return true; + + error_exit: + RELEASE(_d3d_texture, dxgsg8, "texture", RELEASE_ONCE); + _d3d_2d_texture = NULL; + _d3d_volume_texture = NULL; + _d3d_cube_texture = NULL; + return false; +} + //////////////////////////////////////////////////////////////////// // Function: DXTextureContext8::delete_texture // Access: Public diff --git a/panda/src/dxgsg8/dxTextureContext8.h b/panda/src/dxgsg8/dxTextureContext8.h index 9242621e6e..3b4b041d1d 100644 --- a/panda/src/dxgsg8/dxTextureContext8.h +++ b/panda/src/dxgsg8/dxTextureContext8.h @@ -29,6 +29,7 @@ public: virtual ~DXTextureContext8(); bool create_texture(DXScreenData &scrn); + bool create_simple_texture(DXScreenData &scrn); void delete_texture(); INLINE bool has_mipmaps() const; diff --git a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx index bbc707ce73..41ef555823 100755 --- a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx +++ b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx @@ -207,7 +207,9 @@ prepare_texture(Texture *tex) { return NULL; } - if (!dtc->create_texture(*_screen)) { + if (!upload_texture(dtc)) { + dxgsg9_cat.error() + << "Unable to create texture " << *tex << endl; delete dtc; return NULL; } @@ -237,28 +239,21 @@ apply_texture(int i, TextureContext *tc) { if (_lru) { _lru -> access_page (dtc -> _lru_page); } + Texture *tex = tc->get_texture(); // If the texture image has changed, or if its use of mipmaps has // changed, we need to re-create the image. if (dtc->was_modified()) { - if (!get_supports_compressed_texture_format(tc->get_texture()->get_ram_image_compression())) { - dxgsg9_cat.error() - << *dtc->get_texture() << " is stored in an unsupported compressed format.\n"; - set_texture_stage_state(i, D3DTSS_COLOROP, D3DTOP_DISABLE); - return; - } - - if (!dtc->create_texture(*_screen)) { + if (!upload_texture(dtc)) { // Oops, we can't re-create the texture for some reason. dxgsg9_cat.error() - << "Unable to re-create texture " << *dtc->get_texture() << endl; + << "Unable to re-create texture " << *tex << endl; set_texture_stage_state(i, D3DTSS_COLOROP, D3DTOP_DISABLE); return; } } - Texture *tex = tc->get_texture(); Texture::WrapMode wrap_u, wrap_v, wrap_w; DWORD address_u; @@ -311,16 +306,10 @@ apply_texture(int i, TextureContext *tc) { new_mip_filter = D3DTEXF_NONE; } -#ifndef NDEBUG // sanity check - if ((!dtc->has_mipmaps()) && (new_mip_filter != D3DTEXF_NONE)) { - dxgsg9_cat.error() - << "Trying to set mipmap filtering for texture with no generated mipmaps!! texname[" - << tex->get_name() << "], filter(" - << tex->get_minfilter() << ")\n"; + if (!dtc->has_mipmaps()) { new_mip_filter = D3DTEXF_NONE; } -#endif if (aniso_degree >= 2) { new_min_filter = D3DTEXF_ANISOTROPIC; @@ -332,6 +321,39 @@ apply_texture(int i, TextureContext *tc) { _d3d_device->SetTexture(i, dtc->get_d3d_texture()); } +//////////////////////////////////////////////////////////////////// +// Function: DXGraphicsStateGuardian9::upload_texture +// Access: Public +// Description: Creates a texture surface on the graphics card and +// fills it with its pixel data. +//////////////////////////////////////////////////////////////////// +bool DXGraphicsStateGuardian9:: +upload_texture(DXTextureContext9 *dtc) { + Texture *tex = dtc->get_texture(); + if (!get_supports_compressed_texture_format(tex->get_ram_image_compression())) { + dxgsg9_cat.error() + << *tex << " is stored in an unsupported compressed format.\n"; + return false; + } + + if (_incomplete_render && + !tex->has_ram_image() && tex->might_have_ram_image() && + tex->has_simple_ram_image() && + !_loader.is_null()) { + // If we don't have the texture data right now, go get it, but in + // the meantime load a temporary simple image in its place. + async_reload_texture(dtc); + if (!tex->has_ram_image()) { + if (dtc->was_simple_image_modified()) { + return dtc->create_simple_texture(*_screen); + } + return true; + } + } + + return dtc->create_texture(*_screen); +} + //////////////////////////////////////////////////////////////////// // Function: DXGraphicsStateGuardian9::release_texture // Access: Public, Virtual diff --git a/panda/src/dxgsg9/dxGraphicsStateGuardian9.h b/panda/src/dxgsg9/dxGraphicsStateGuardian9.h index 9c2a8ae9ac..f446ad89c1 100755 --- a/panda/src/dxgsg9/dxGraphicsStateGuardian9.h +++ b/panda/src/dxgsg9/dxGraphicsStateGuardian9.h @@ -64,6 +64,7 @@ enum GsgPageType class Light; +class DXTextureContext9; class DXVertexBufferContext9; class DXIndexBufferContext9; @@ -83,6 +84,7 @@ public: virtual TextureContext *prepare_texture(Texture *tex); void apply_texture(int i, TextureContext *tc); + bool upload_texture(DXTextureContext9 *dtc); virtual void release_texture(TextureContext *tc); ShaderContext *prepare_shader(Shader *se); diff --git a/panda/src/dxgsg9/dxTextureContext9.cxx b/panda/src/dxgsg9/dxTextureContext9.cxx index a80c38e355..389be5a4ca 100755 --- a/panda/src/dxgsg9/dxTextureContext9.cxx +++ b/panda/src/dxgsg9/dxTextureContext9.cxx @@ -88,7 +88,6 @@ create_texture(DXScreenData &scrn) { nassertr(IS_VALID_PTR(get_texture()), false); delete_texture(); - mark_loaded(); // bpp indicates requested fmt, not texture fmt DWORD target_bpp = get_bits_per_pixel(get_texture()->get_format(), &num_alpha_bits); @@ -968,6 +967,95 @@ create_texture(DXScreenData &scrn) { return false; } +//////////////////////////////////////////////////////////////////// +// Function: DXTextureContext9::create_simple_texture +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +bool DXTextureContext9:: +create_simple_texture(DXScreenData &scrn) { + nassertr(IS_VALID_PTR(get_texture()), false); + + HRESULT hr; + + delete_texture(); + + _d3d_format = D3DFMT_A8R8G8B8; + D3DFORMAT target_pixel_format = D3DFMT_A8R8G8B8; + DWORD target_bpp = 32; + DWORD num_color_channels = 4; + + DWORD target_width = (DWORD)get_texture()->get_simple_x_size(); + DWORD target_height = (DWORD)get_texture()->get_simple_y_size(); + DWORD mip_level_count = 1; + DWORD usage = 0; + D3DPOOL pool = D3DPOOL_MANAGED; + + int data_size = target_width * target_height * 4; + + hr = scrn._d3d_device->CreateTexture + (target_width, target_height, mip_level_count, usage, + target_pixel_format, pool, &_d3d_2d_texture, NULL); + _d3d_texture = _d3d_2d_texture; + if (FAILED(hr)) { + dxgsg9_cat.error() + << "D3D create_simple_texture failed!" << D3DERRORSTRING(hr); + dxgsg9_cat.error() + << " width = " << target_width << " height = " << target_height << " target_pixel_format = " << target_pixel_format << "\n"; + + goto error_exit; + } + + if (DEBUG_TEXTURES && dxgsg9_cat.is_debug()) { + dxgsg9_cat.debug() + << "create_simple_texture: " << get_texture()->get_name() + << "\n"; + } + + { + CPTA_uchar image = get_texture()->get_simple_ram_image(); + + hr = -1; + // hr = fill_d3d_texture_pixels(scrn._supports_automatic_mipmap_generation, scrn._d3d_device); + + IDirect3DSurface9 *surface = NULL; + _d3d_2d_texture->GetSurfaceLevel(0, &surface); + + RECT source_size; + source_size.left = source_size.top = 0; + source_size.right = target_width; + source_size.bottom = target_height; + + DWORD mip_filter = D3DX_FILTER_LINEAR; + + hr = D3DXLoadSurfaceFromMemory + (surface, (PALETTEENTRY*)NULL, (RECT*)NULL, (LPCVOID)image.p(), + target_pixel_format, target_width * 4, (PALETTEENTRY*)NULL, + &source_size, mip_filter, (D3DCOLOR)0x0); + + RELEASE(surface, dxgsg9, "create_simple_texture Surface", RELEASE_ONCE); + } + + if (FAILED(hr)) { + dxgsg9_cat.debug () + << "*** fill_d3d_texture_pixels failed ***: format " + << target_pixel_format + << "\n"; + + goto error_exit; + } + + mark_simple_loaded(); + return true; + + error_exit: + RELEASE(_d3d_texture, dxgsg9, "texture", RELEASE_ONCE); + _d3d_2d_texture = NULL; + _d3d_volume_texture = NULL; + _d3d_cube_texture = NULL; + return false; +} + //////////////////////////////////////////////////////////////////// // Function: DXTextureContext9::delete_texture // Access: Public diff --git a/panda/src/dxgsg9/dxTextureContext9.h b/panda/src/dxgsg9/dxTextureContext9.h index 08dd7a1ac7..a43c64d565 100755 --- a/panda/src/dxgsg9/dxTextureContext9.h +++ b/panda/src/dxgsg9/dxTextureContext9.h @@ -31,6 +31,7 @@ public: virtual ~DXTextureContext9(); bool create_texture(DXScreenData &scrn); + bool create_simple_texture(DXScreenData &scrn); void delete_texture(); INLINE bool has_mipmaps() const;