From c44da02ceedf0e7308002f32c8094c3f85804ba6 Mon Sep 17 00:00:00 2001 From: David Rose Date: Wed, 14 Jan 2009 01:33:14 +0000 Subject: [PATCH] fix issues with texture compression of small, L8 textures --- panda/src/dxgsg8/dxTextureContext8.cxx | 43 +++++++++++++++++++++--- panda/src/dxgsg9/dxTextureContext9.cxx | 45 +++++++++++++++++++++++--- panda/src/gobj/config_gobj.cxx | 6 ++++ panda/src/gobj/config_gobj.h | 1 + panda/src/gobj/texture.cxx | 5 +++ 5 files changed, 91 insertions(+), 9 deletions(-) diff --git a/panda/src/dxgsg8/dxTextureContext8.cxx b/panda/src/dxgsg8/dxTextureContext8.cxx index b9aecf680a..8953333a1d 100644 --- a/panda/src/dxgsg8/dxTextureContext8.cxx +++ b/panda/src/dxgsg8/dxTextureContext8.cxx @@ -377,6 +377,15 @@ create_texture(DXScreenData &scrn) { } } + // We can't compress for some reason, so ensure the uncompressed + // image is ready to load. + if (texture_stored_compressed) { + tex->get_uncompressed_ram_image(); + compression_mode = tex->get_ram_image_compression(); + texture_stored_compressed = compression_mode != Texture::CM_off; + compress_texture = false; + } + // handle each target bitdepth separately. might be less confusing // to reorg by num_color_channels (input type) switch (target_bpp) { @@ -1001,11 +1010,37 @@ extract_texture_data() { return false; } + int x_size = tex->get_expected_mipmap_x_size(n); int y_size = tex->get_expected_mipmap_y_size(n); - int size = rect.Pitch * (y_size / div); - size = min(size, (int)tex->get_expected_ram_mipmap_image_size(n)); - PTA_uchar image = PTA_uchar::empty_array(size); - memcpy(image.p(), rect.pBits, size); + PTA_uchar image; + + if (compression == Texture::CM_off) { + // Uncompressed, but we have to respect the pitch. + int pitch = x_size * tex->get_num_components() * tex->get_component_width(); + pitch = min(pitch, (int)rect.Pitch); + int size = pitch * y_size; + image = PTA_uchar::empty_array(size); + if (pitch == rect.Pitch) { + // Easy copy. + memcpy(image.p(), rect.pBits, size); + } else { + // Harder copy: we have to de-interleave DirectX's extra bytes + // on the end of each row. + unsigned char *dest = image.p(); + unsigned char *source = (unsigned char *)rect.pBits; + for (int yi = 0; yi < y_size; ++yi) { + memcpy(dest, source, pitch); + dest += pitch; + source += rect.Pitch; + } + } + + } else { + // Compressed; just copy the data verbatim. + int size = rect.Pitch * (y_size / div); + image = PTA_uchar::empty_array(size); + memcpy(image.p(), rect.pBits, size); + } _d3d_2d_texture->UnlockRect(n); if (n == 0) { diff --git a/panda/src/dxgsg9/dxTextureContext9.cxx b/panda/src/dxgsg9/dxTextureContext9.cxx index cb18813e20..e1cc08e294 100755 --- a/panda/src/dxgsg9/dxTextureContext9.cxx +++ b/panda/src/dxgsg9/dxTextureContext9.cxx @@ -405,6 +405,15 @@ create_texture(DXScreenData &scrn) { } } + // We can't compress for some reason, so ensure the uncompressed + // image is ready to load. + if (texture_stored_compressed) { + tex->get_uncompressed_ram_image(); + compression_mode = tex->get_ram_image_compression(); + texture_stored_compressed = compression_mode != Texture::CM_off; + compress_texture = false; + } + // handle each target bitdepth separately. might be less confusing // to reorg by num_color_channels (input type, rather than desired // 1st target) @@ -1236,12 +1245,38 @@ extract_texture_data(DXScreenData &screen) { << "Texture::LockRect() failed! level = " << n << " " << D3DERRORSTRING(hr); return state; } - + + int x_size = tex->get_expected_mipmap_x_size(n); int y_size = tex->get_expected_mipmap_y_size(n); - int size = rect.Pitch * (y_size / div); - size = min(size, (int)tex->get_expected_ram_mipmap_image_size(n)); - PTA_uchar image = PTA_uchar::empty_array(size); - memcpy(image.p(), rect.pBits, size); + PTA_uchar image; + + if (compression == Texture::CM_off) { + // Uncompressed, but we have to respect the pitch. + int pitch = x_size * tex->get_num_components() * tex->get_component_width(); + pitch = min(pitch, (int)rect.Pitch); + int size = pitch * y_size; + image = PTA_uchar::empty_array(size); + if (pitch == rect.Pitch) { + // Easy copy. + memcpy(image.p(), rect.pBits, size); + } else { + // Harder copy: we have to de-interleave DirectX's extra bytes + // on the end of each row. + unsigned char *dest = image.p(); + unsigned char *source = (unsigned char *)rect.pBits; + for (int yi = 0; yi < y_size; ++yi) { + memcpy(dest, source, pitch); + dest += pitch; + source += rect.Pitch; + } + } + + } else { + // Compressed; just copy the data verbatim. + int size = rect.Pitch * (y_size / div); + image = PTA_uchar::empty_array(size); + memcpy(image.p(), rect.pBits, size); + } _d3d_2d_texture->UnlockRect(n); if (n == 0) { diff --git a/panda/src/gobj/config_gobj.cxx b/panda/src/gobj/config_gobj.cxx index 3c8a23081e..1672ea2c78 100644 --- a/panda/src/gobj/config_gobj.cxx +++ b/panda/src/gobj/config_gobj.cxx @@ -82,6 +82,12 @@ ConfigVariableDouble texture_scale "scale factor is applied before textures-power-2 or " "max-texture-dimension.")); +ConfigVariableInt texture_scale_limit +("texture-scale-limit", 4, + PRC_DESC("This specifies the limit below which texture-scale will not " + "reduce a texture image. This is a single dimension which applies " + "to both X and Y.")); + ConfigVariableList exclude_texture_scale ("exclude-texture-scale", PRC_DESC("This is a list of glob patterns for texture filenames " diff --git a/panda/src/gobj/config_gobj.h b/panda/src/gobj/config_gobj.h index bfc2426cc4..1be20e619c 100644 --- a/panda/src/gobj/config_gobj.h +++ b/panda/src/gobj/config_gobj.h @@ -49,6 +49,7 @@ EXPCL_PANDA_GOBJ istream &operator >> (istream &in, ShaderUtilization &sut); // Configure variables for gobj package. extern EXPCL_PANDA_GOBJ ConfigVariableInt max_texture_dimension; extern EXPCL_PANDA_GOBJ ConfigVariableDouble texture_scale; +extern EXPCL_PANDA_GOBJ ConfigVariableInt texture_scale_limit; extern EXPCL_PANDA_GOBJ ConfigVariableList exclude_texture_scale; diff --git a/panda/src/gobj/texture.cxx b/panda/src/gobj/texture.cxx index 5d10795be3..1230ce771b 100644 --- a/panda/src/gobj/texture.cxx +++ b/panda/src/gobj/texture.cxx @@ -1817,6 +1817,11 @@ adjust_size(int &x_size, int &y_size, const string &name) { if (!exclude) { new_x_size = (int)cfloor(new_x_size * texture_scale + 0.5); new_y_size = (int)cfloor(new_y_size * texture_scale + 0.5); + + // Don't auto-scale below 4 in either dimension. This causes + // problems for DirectX and texture compression. + new_x_size = min(max(new_x_size, (int)texture_scale_limit), x_size); + new_y_size = min(max(new_y_size, (int)texture_scale_limit), y_size); } switch (get_textures_power_2()) {