diff --git a/dtool/Config.pp b/dtool/Config.pp index dc4b52cfef..5d2f2343f6 100644 --- a/dtool/Config.pp +++ b/dtool/Config.pp @@ -470,6 +470,13 @@ // drfftw instead of rfftw. #defer HAVE_DRFFTW_H $[libtest $[FFTW_LPATH],drfftw] +// Is libsquish installed, and where? +#define SQUISH_IPATH /usr/local/include +#define SQUISH_LPATH /usr/local/lib +#define SQUISH_LIBS squish +#defer HAVE_SQUISH $[libtest $[SQUISH_LPATH],$[SQUISH_LIBS]] + + // Is Berkeley DB installed, and where? Presently, this is only used // for some applications (egg-optchar in particular) in Pandatool, and // it is completely optional there. If available, egg-optchar takes diff --git a/dtool/LocalSetup.pp b/dtool/LocalSetup.pp index 13d37fdd65..860ea44dd8 100644 --- a/dtool/LocalSetup.pp +++ b/dtool/LocalSetup.pp @@ -41,6 +41,11 @@ #else #print - Did not find fftw #endif +#if $[HAVE_SQUISH] +#print + squish +#else +#print - Did not find squish +#endif #if $[HAVE_CG] #print + Nvidia Cg High Level Shading Language #else @@ -232,6 +237,9 @@ $[cdefine HAVE_TAR] /* Define if we have libfftw installed. */ $[cdefine HAVE_FFTW] +/* Define if we have libsquish installed. */ +$[cdefine HAVE_SQUISH] + /* Define if we have Berkeley DB installed. */ $[cdefine HAVE_BDB] diff --git a/dtool/Package.pp b/dtool/Package.pp index 7d71615476..2522caf435 100644 --- a/dtool/Package.pp +++ b/dtool/Package.pp @@ -145,6 +145,11 @@ #set FFTW_LIBS $[FFTW_LIBS] #set HAVE_FFTW $[HAVE_FFTW] +#set SQUISH_IPATH $[unixfilename $[SQUISH_IPATH]] +#set SQUISH_LPATH $[unixfilename $[SQUISH_LPATH]] +#set SQUISH_LIBS $[SQUISH_LIBS] +#set HAVE_SQUISH $[HAVE_SQUISH] + #set BDB_IPATH $[unixfilename $[BDB_IPATH]] #set BDB_LPATH $[unixfilename $[BDB_LPATH]] #set BDB_LIBS $[BDB_LIBS] diff --git a/dtool/pptempl/Global.pp b/dtool/pptempl/Global.pp index fc442b177a..71966026e3 100644 --- a/dtool/pptempl/Global.pp +++ b/dtool/pptempl/Global.pp @@ -241,6 +241,13 @@ #define fftw_libs $[FFTW_LIBS] #endif +#if $[HAVE_SQUISH] + #define squish_ipath $[wildcard $[SQUISH_IPATH]] + #define squish_lpath $[wildcard $[SQUISH_LPATH]] + #define squish_cflags $[SQUISH_CFLAGS] + #define squish_libs $[SQUISH_LIBS] +#endif + #if $[HAVE_BDB] #define bdb_ipath $[wildcard $[BDB_IPATH]] #define bdb_lpath $[wildcard $[BDB_LPATH]] diff --git a/panda/src/display/graphicsStateGuardian.I b/panda/src/display/graphicsStateGuardian.I index 2489292e0e..f8ed10ecb1 100644 --- a/panda/src/display/graphicsStateGuardian.I +++ b/panda/src/display/graphicsStateGuardian.I @@ -419,13 +419,15 @@ get_supports_compressed_texture() const { //////////////////////////////////////////////////////////////////// // Function: GraphicsStateGuardian::get_supports_compressed_texture_format -// Access: Published +// Access: Published, Virtual // Description: Returns true if this GSG can accept textures // pre-compressed in the indicated format. +// compression_mode may be any of the +// Texture::CompressionMode enums. //////////////////////////////////////////////////////////////////// INLINE bool GraphicsStateGuardian:: -get_supports_compressed_texture_format(Texture::CompressionMode compression) const { - return _compressed_texture_formats.get_bit(compression); +get_supports_compressed_texture_format(int compression_mode) const { + return _compressed_texture_formats.get_bit(compression_mode); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/display/graphicsStateGuardian.h b/panda/src/display/graphicsStateGuardian.h index 297b2016cf..b32c022423 100644 --- a/panda/src/display/graphicsStateGuardian.h +++ b/panda/src/display/graphicsStateGuardian.h @@ -122,7 +122,7 @@ PUBLISHED: INLINE bool get_supports_tex_non_pow2() const; INLINE bool get_supports_compressed_texture() const; - INLINE bool get_supports_compressed_texture_format(Texture::CompressionMode compression) const; + virtual INLINE bool get_supports_compressed_texture_format(int compression_mode) const; INLINE int get_max_lights() const; INLINE int get_max_clip_planes() const; diff --git a/panda/src/gobj/Sources.pp b/panda/src/gobj/Sources.pp index 031810712e..ecec47af81 100644 --- a/panda/src/gobj/Sources.pp +++ b/panda/src/gobj/Sources.pp @@ -1,7 +1,7 @@ #define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \ dtoolutil:c dtoolbase:c dtool:m prc:c //#define OSX_SYS_LIBS mx -#define USE_PACKAGES zlib cg +#define USE_PACKAGES zlib cg squish #begin lib_target #define TARGET gobj diff --git a/panda/src/gobj/config_gobj.cxx b/panda/src/gobj/config_gobj.cxx index 314ffd4c12..3c8a23081e 100644 --- a/panda/src/gobj/config_gobj.cxx +++ b/panda/src/gobj/config_gobj.cxx @@ -106,6 +106,17 @@ ConfigVariableBool compressed_textures "changes the meaning of set_compression(Texture::CM_default) to " "Texture::CM_on.")); +ConfigVariableBool cpu_compress_textures +("cpu-compress-textures", false, + PRC_DESC("Set this true to use the squish library to compress textures on " + "the CPU, as they are loaded, rather than to hand them off to " + "the graphics driver to compress them. This will be done " + "only if the graphics window is already open and is the default " + "graphics context, and it claims to support DXT1/3/5 " + "compression. If any of this is not true, the texture will " + "not be automatically compressed via squish, but it may still " + "be compressed by the graphics driver.")); + ConfigVariableBool vertex_buffers ("vertex-buffers", true, PRC_DESC("Set this true to allow the use of vertex buffers (or buffer " diff --git a/panda/src/gobj/config_gobj.h b/panda/src/gobj/config_gobj.h index 5914a62e13..bfc2426cc4 100644 --- a/panda/src/gobj/config_gobj.h +++ b/panda/src/gobj/config_gobj.h @@ -54,6 +54,7 @@ extern EXPCL_PANDA_GOBJ ConfigVariableList exclude_texture_scale; extern EXPCL_PANDA_GOBJ ConfigVariableBool keep_texture_ram; extern EXPCL_PANDA_GOBJ ConfigVariableBool compressed_textures; +extern EXPCL_PANDA_GOBJ ConfigVariableBool cpu_compress_textures; extern EXPCL_PANDA_GOBJ ConfigVariableBool vertex_buffers; extern EXPCL_PANDA_GOBJ ConfigVariableBool vertex_arrays; extern EXPCL_PANDA_GOBJ ConfigVariableBool display_lists; diff --git a/panda/src/gobj/texture.I b/panda/src/gobj/texture.I index 0fa135c8f1..80912c17a3 100644 --- a/panda/src/gobj/texture.I +++ b/panda/src/gobj/texture.I @@ -253,7 +253,11 @@ load(const PNMImage &pnmimage, const LoaderOptions &options) { do_clear(); ++_properties_modified; ++_image_modified; - return do_load_one(pnmimage, get_name(), 0, 0, options); + if (do_load_one(pnmimage, get_name(), 0, 0, options)) { + consider_auto_compress_ram_image(); + return true; + } + return false; } //////////////////////////////////////////////////////////////////// @@ -267,7 +271,11 @@ load(const PNMImage &pnmimage, int z, int n, const LoaderOptions &options) { MutexHolder holder(_lock); ++_properties_modified; ++_image_modified; - return do_load_one(pnmimage, get_name(), z, n, options); + if (do_load_one(pnmimage, get_name(), z, n, options)) { + consider_auto_compress_ram_image(); + return true; + } + return false; } //////////////////////////////////////////////////////////////////// @@ -1205,6 +1213,56 @@ set_keep_ram_image(bool keep_ram_image) { _keep_ram_image = keep_ram_image; } +//////////////////////////////////////////////////////////////////// +// Function: Texture::compress_ram_image +// Access: Published +// Description: Attempts to compress the texture's RAM image +// internally, to a format supported by the indicated +// GSG. In order for this to work, the squish library +// must have been compiled into Panda. +// +// If compression is CM_on, then an appropriate +// compression method that is supported by the indicated +// GSG is automatically chosen. If the GSG pointer is +// NULL, any of the standard DXT1/3/5 compression +// methods will be used, regardless of whether it is +// supported. +// +// If compression is any specific compression method, +// that method is used regardless of whether the GSG +// supports it. +// +// quality_level determines the speed/quality tradeoff +// of the compression. If it is QL_default, the +// texture's own quality_level parameter is used. +// +// Returns true if successful, false otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool Texture:: +compress_ram_image(Texture::CompressionMode compression, + Texture::QualityLevel quality_level, + GraphicsStateGuardianBase *gsg) { + MutexHolder holder(_lock); + return do_compress_ram_image(compression, quality_level, gsg); +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::uncompress_ram_image +// Access: Published +// Description: Attempts to uncompress the texture's RAM image +// internally. In order for this to work, the squish +// library must have been compiled into Panda, and the +// ram image must be compressed in a format supported by +// squish. +// +// Returns true if successful, false otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool Texture:: +uncompress_ram_image() { + MutexHolder holder(_lock); + return do_uncompress_ram_image(); +} + //////////////////////////////////////////////////////////////////// // Function: Texture::get_num_ram_mipmap_images // Access: Published diff --git a/panda/src/gobj/texture.cxx b/panda/src/gobj/texture.cxx index daec0a1bda..5d10795be3 100644 --- a/panda/src/gobj/texture.cxx +++ b/panda/src/gobj/texture.cxx @@ -39,13 +39,17 @@ #include "streamReader.h" #include "texturePeeker.h" +#ifdef HAVE_SQUISH +#include +#endif // HAVE_SQUISH + #include ConfigVariableEnum texture_quality_level ("texture-quality-level", Texture::QL_normal, PRC_DESC("This specifies a global quality level for all textures. You " "may specify either fastest, normal, or best. This actually " - "affects the meaning of Texture::set_quality_level(TQL_default), " + "affects the meaning of Texture::set_quality_level(QL_default), " "so it may be overridden on a per-texture basis. This generally " "only has an effect when using the tinydisplay software renderer; " "it has little or no effect on normal, hardware-accelerated " @@ -2082,6 +2086,12 @@ do_read(const Filename &fullpath, const Filename &alpha_fullpath, // information, don't let the Texture think that it's got the // image now. do_clear_ram_image(); + } else { + if ((options.get_texture_flags() & LoaderOptions::TF_preload) != 0) { + // If we intend to keep the ram image around, consider + // compressing it. + consider_auto_compress_ram_image(); + } } return true; @@ -2472,6 +2482,7 @@ do_read_txo(istream &in, const string &filename) { return false; } + Namable::operator = (*other); do_assign(*other); _loaded_from_image = true; _loaded_from_txo = true; @@ -2798,7 +2809,7 @@ do_write_one(const Filename &fullpath, int z, int n) const { bool Texture:: do_store_one(PNMImage &pnmimage, int z, int n) const { // First, reload the ram image if necessary. - ((Texture *)this)->do_get_ram_image(); + ((Texture *)this)->do_get_uncompressed_ram_image(); nassertr(do_has_ram_mipmap_image(n), false); nassertr(z >= 0 && z < do_get_expected_mipmap_z_size(n), false); @@ -3009,6 +3020,17 @@ do_reload_ram_image(bool allow_compression) { _ram_image_compression = tex->_ram_image_compression; _ram_images = tex->_ram_images; _loaded_from_image = true; + + if (allow_compression && consider_auto_compress_ram_image()) { + if (cache->get_cache_compressed_textures()) { + // We've re-compressed the image after loading it from the + // cache. To keep the cache current, rewrite it to the + // cache now, in its newly compressed form. + record->set_data(this, false); + cache->store(record); + } + } + return; } } @@ -3122,6 +3144,180 @@ do_make_ram_mipmap_image(int n) { return _ram_images[n]._image; } +//////////////////////////////////////////////////////////////////// +// Function: Texture::consider_auto_compress_ram_image +// Access: Protected +// Description: Should be called after a texture has been loaded into +// RAM, this considers compressing the RAM image, if +// cpu-compress-textures has been set and the default +// GSG has been set and supports it. + +// Returns true if the image was modified by this +// operation, false if it wasn't. +//////////////////////////////////////////////////////////////////// +bool Texture:: +consider_auto_compress_ram_image() { + if (cpu_compress_textures) { + CompressionMode compression = _compression; + if (compression == CM_default) { + if (!compressed_textures) { + return false; + } + compression = CM_on; + } + if (compression != CM_off && _ram_image_compression == CM_off) { + GraphicsStateGuardianBase *gsg = GraphicsStateGuardianBase::get_default_gsg(); + if (gsg != (GraphicsStateGuardianBase *)NULL) { + if (do_compress_ram_image(compression, QL_default, gsg)) { + gobj_cat.info() + << "Compressed " << get_name() << " with " + << _ram_image_compression << "\n"; + return true; + } + } + } + } + + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::do_compress_ram_image +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +bool Texture:: +do_compress_ram_image(Texture::CompressionMode compression, + Texture::QualityLevel quality_level, + GraphicsStateGuardianBase *gsg) { + nassertr(compression != CM_off, false); + + if (compression == CM_on) { + // Select an appropriate compression mode automatically. + switch (_format) { + case Texture::F_rgbm: + case Texture::F_rgb: + case Texture::F_rgb5: + case Texture::F_rgba5: + case Texture::F_rgb8: + case Texture::F_rgb12: + case Texture::F_rgb332: + if (gsg == NULL || gsg->get_supports_compressed_texture_format(CM_dxt1)) { + compression = CM_dxt1; + } else if (gsg == NULL || gsg->get_supports_compressed_texture_format(CM_dxt3)) { + compression = CM_dxt3; + } else if (gsg == NULL || gsg->get_supports_compressed_texture_format(CM_dxt5)) { + compression = CM_dxt5; + } + break; + + case Texture::F_rgba4: + if (gsg == NULL || gsg->get_supports_compressed_texture_format(CM_dxt3)) { + compression = CM_dxt3; + } else if (gsg == NULL || gsg->get_supports_compressed_texture_format(CM_dxt5)) { + compression = CM_dxt5; + } + break; + + case Texture::F_rgba: + case Texture::F_rgba8: + case Texture::F_rgba12: + if (gsg == NULL || gsg->get_supports_compressed_texture_format(CM_dxt5)) { + compression = CM_dxt5; + } + break; + } + } + + // Choose an appropriate quality level. + if (quality_level == Texture::QL_default) { + quality_level = _quality_level; + } + if (quality_level == Texture::QL_default) { + quality_level = texture_quality_level; + } + +#ifdef HAVE_SQUISH + if (_texture_type != TT_3d_texture && _component_type == T_unsigned_byte) { + int squish_flags = 0; + switch (compression) { + case CM_dxt1: + squish_flags |= squish::kDxt1; + break; + + case CM_dxt3: + squish_flags |= squish::kDxt3; + break; + + case CM_dxt5: + squish_flags |= squish::kDxt5; + break; + } + + if (squish_flags != 0) { + // This compression mode is supported by squish; use it. + switch (quality_level) { + case QL_fastest: + squish_flags |= squish::kColourRangeFit; + break; + + case QL_normal: + // ColourClusterFit is just too slow for everyday use. + squish_flags |= squish::kColourRangeFit; + // squish_flags |= squish::kColourClusterFit; + break; + + case QL_best: + squish_flags |= squish::kColourIterativeClusterFit; + break; + } + + if (do_squish(compression, squish_flags)) { + return true; + } + } + } +#endif // HAVE_SQUISH + + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::do_uncompress_ram_image +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +bool Texture:: +do_uncompress_ram_image() { + +#ifdef HAVE_SQUISH + if (_texture_type != TT_3d_texture && _component_type == T_unsigned_byte) { + int squish_flags = 0; + switch (_ram_image_compression) { + case CM_dxt1: + squish_flags |= squish::kDxt1; + break; + + case CM_dxt3: + squish_flags |= squish::kDxt3; + break; + + case CM_dxt5: + squish_flags |= squish::kDxt5; + break; + } + + if (squish_flags != 0) { + // This compression mode is supported by squish; use it. + if (do_unsquish(squish_flags)) { + return true; + } + } + } +#endif // HAVE_SQUISH + return false; +} + //////////////////////////////////////////////////////////////////// // Function: Texture::do_reconsider_z_size // Access: Protected @@ -3660,6 +3856,17 @@ do_get_ram_image() { //////////////////////////////////////////////////////////////////// CPTA_uchar Texture:: do_get_uncompressed_ram_image() { + if (!_ram_images.empty() && _ram_image_compression != CM_off) { + // We have an image in-ram, but it's compressed. Try to + // uncompress it first. + if (do_uncompress_ram_image()) { + gobj_cat.info() + << "Uncompressed " << get_name() << "\n"; + return _ram_images[0]._image; + } + } + + // Couldn't uncompress the existing image. Try to reload it. if (_loaded_from_image && (!do_has_ram_image() || _ram_image_compression != CM_off) && !_fullpath.empty()) { do_unlock_and_reload_ram_image(false); } @@ -5094,6 +5301,183 @@ filter_3d_unsigned_short(unsigned char *&p, const unsigned char *&q, q += 2; } +//////////////////////////////////////////////////////////////////// +// Function: Texture::do_squish +// Access: Private +// Description: Invokes the squish library to compress the RAM +// image(s). +//////////////////////////////////////////////////////////////////// +bool Texture:: +do_squish(Texture::CompressionMode compression, int squish_flags) { +#ifdef HAVE_SQUISH + if (_ram_images.empty()) { + return false; + } + RamImages compressed_ram_images; + compressed_ram_images.reserve(_ram_images.size()); + for (size_t n = 0; n < _ram_images.size(); ++n) { + RamImage compressed_image; + int x_size = do_get_expected_mipmap_x_size(n); + int y_size = do_get_expected_mipmap_y_size(n); + int z_size = do_get_expected_mipmap_z_size(n); + int page_size = squish::GetStorageRequirements(x_size, y_size, squish_flags); + int cell_size = squish::GetStorageRequirements(4, 4, squish_flags); + + compressed_image._page_size = page_size; + compressed_image._image = PTA_uchar::empty_array(page_size * z_size); + for (int z = 0; z < z_size; ++z) { + unsigned char *dest_page = compressed_image._image.p() + z * page_size; + unsigned const char *source_page = _ram_images[n]._image.p() + z * _ram_images[n]._page_size; + unsigned const char *source_page_end = source_page + _ram_images[n]._page_size; + // Convert one 4 x 4 cell at a time. + unsigned char *d = dest_page; + for (int y = 0; y < y_size; y += 4) { + for (int x = 0; x < x_size; x += 4) { + unsigned char tb[16 * 4]; + int mask = 0; + unsigned char *t = tb; + for (int i = 0; i < 16; ++i) { + int xi = x + i % 4; + int yi = y + i / 4; + unsigned const char *s = source_page + (yi * x_size + xi) * _num_components; + if (s < source_page_end) { + switch (_num_components) { + case 1: + t[0] = s[0]; // r + t[1] = s[0]; // g + t[2] = s[0]; // b + t[3] = 255; // a + break; + + case 2: + t[0] = s[0]; // r + t[1] = s[0]; // g + t[2] = s[0]; // b + t[3] = s[1]; // a + break; + + case 3: + t[0] = s[2]; // r + t[1] = s[1]; // g + t[2] = s[0]; // b + t[3] = 255; // a + break; + + case 4: + t[0] = s[2]; // r + t[1] = s[1]; // g + t[2] = s[0]; // b + t[3] = s[3]; // a + break; + } + mask |= (1 << i); + } + t += 4; + } + squish::CompressMasked(tb, mask, d, squish_flags); + d += cell_size; + Thread::consider_yield(); + } + } + } + compressed_ram_images.push_back(compressed_image); + } + _ram_images.swap(compressed_ram_images); + _ram_image_compression = compression; + ++_image_modified; + return true; + +#else // HAVE_SQUISH + return false; + +#endif // HAVE_SQUISH +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::do_unsquish +// Access: Private +// Description: Invokes the squish library to uncompress the RAM +// image(s). +//////////////////////////////////////////////////////////////////// +bool Texture:: +do_unsquish(int squish_flags) { +#ifdef HAVE_SQUISH + if (_ram_images.empty()) { + return false; + } + RamImages uncompressed_ram_images; + uncompressed_ram_images.reserve(_ram_images.size()); + for (size_t n = 0; n < _ram_images.size(); ++n) { + RamImage uncompressed_image; + int x_size = do_get_expected_mipmap_x_size(n); + int y_size = do_get_expected_mipmap_y_size(n); + int z_size = do_get_expected_mipmap_z_size(n); + int page_size = squish::GetStorageRequirements(x_size, y_size, squish_flags); + int cell_size = squish::GetStorageRequirements(4, 4, squish_flags); + + uncompressed_image._page_size = do_get_expected_ram_mipmap_page_size(n); + uncompressed_image._image = PTA_uchar::empty_array(uncompressed_image._page_size * z_size); + for (int z = 0; z < z_size; ++z) { + unsigned char *dest_page = uncompressed_image._image.p() + z * uncompressed_image._page_size; + unsigned char *dest_page_end = dest_page + uncompressed_image._page_size; + unsigned const char *source_page = _ram_images[n]._image.p() + z * page_size; + // Unconvert one 4 x 4 cell at a time. + unsigned const char *s = source_page; + for (int y = 0; y < y_size; y += 4) { + for (int x = 0; x < x_size; x += 4) { + unsigned char tb[16 * 4]; + squish::Decompress(tb, s, squish_flags); + s += cell_size; + + unsigned char *t = tb; + for (int i = 0; i < 16; ++i) { + int xi = x + i % 4; + int yi = y + i / 4; + unsigned char *d = dest_page + (yi * x_size + xi) * _num_components; + if (d < dest_page_end) { + switch (_num_components) { + case 1: + d[0] = t[1]; // g + break; + + case 2: + d[0] = t[1]; // g + d[1] = t[3]; // a + break; + + case 3: + d[2] = t[0]; // r + d[1] = t[1]; // g + d[0] = t[2]; // b + break; + + case 4: + d[2] = t[0]; // r + d[1] = t[1]; // g + d[0] = t[2]; // b + d[3] = t[3]; // a + break; + } + } + t += 4; + } + } + Thread::consider_yield(); + } + } + uncompressed_ram_images.push_back(uncompressed_image); + } + _ram_images.swap(uncompressed_ram_images); + _ram_image_compression = CM_off; + ++_image_modified; + return true; + +#else // HAVE_SQUISH + return false; + +#endif // HAVE_SQUISH +} + //////////////////////////////////////////////////////////////////// // Function: Texture::register_with_read_factory // Access: Public, Static diff --git a/panda/src/gobj/texture.h b/panda/src/gobj/texture.h index fbdc7ddb4c..4bf9ac48e9 100644 --- a/panda/src/gobj/texture.h +++ b/panda/src/gobj/texture.h @@ -313,6 +313,11 @@ PUBLISHED: INLINE void set_keep_ram_image(bool keep_ram_image); virtual bool get_keep_ram_image() const; + INLINE bool compress_ram_image(CompressionMode compression = CM_on, + QualityLevel quality_level = QL_default, + GraphicsStateGuardianBase *gsg = NULL); + INLINE bool uncompress_ram_image(); + INLINE int get_num_ram_mipmap_images() const; INLINE bool has_ram_mipmap_image(int n) const; int get_num_loadable_ram_mipmap_images() const; @@ -475,6 +480,12 @@ protected: PTA_uchar do_modify_ram_mipmap_image(int n); PTA_uchar do_make_ram_mipmap_image(int n); + bool consider_auto_compress_ram_image(); + bool do_compress_ram_image(CompressionMode compression, + QualityLevel quality_level, + GraphicsStateGuardianBase *gsg); + bool do_uncompress_ram_image(); + bool do_reconsider_z_size(int z); bool do_reconsider_image_properties(int x_size, int y_size, int num_components, ComponentType component_type, int z, @@ -607,6 +618,9 @@ private: const unsigned char *&q, size_t pixel_size, size_t row_size, size_t page_size); + + bool do_squish(CompressionMode compression, int squish_flags); + bool do_unsquish(int squish_flags); protected: // Protects all of the members of this class. diff --git a/panda/src/gobj/texturePool.cxx b/panda/src/gobj/texturePool.cxx index 1599d8ee04..e4c9f0c964 100644 --- a/panda/src/gobj/texturePool.cxx +++ b/panda/src/gobj/texturePool.cxx @@ -920,6 +920,16 @@ try_load_cache(PT(Texture) &tex, BamCache *cache, const Filename &filename, if (!(options.get_texture_flags() & LoaderOptions::TF_preload)) { // But drop the RAM until we need it. tex->clear_ram_image(); + + } else if (tex->consider_auto_compress_ram_image()) { + if (cache->get_cache_compressed_textures()) { + // We've re-compressed the image after loading it from the + // cache. To keep the cache current, rewrite it to the + // cache now, in its newly compressed form. + record->set_data(tex, false); + cache->store(record); + compressed_cache_record = true; + } } tex->set_keep_ram_image(false); } diff --git a/panda/src/gsgbase/graphicsStateGuardianBase.h b/panda/src/gsgbase/graphicsStateGuardianBase.h index ed253dc733..d402970e62 100644 --- a/panda/src/gsgbase/graphicsStateGuardianBase.h +++ b/panda/src/gsgbase/graphicsStateGuardianBase.h @@ -115,6 +115,7 @@ PUBLISHED: virtual int get_max_vertices_per_primitive() const=0; virtual int get_max_texture_dimension() const=0; + virtual bool get_supports_compressed_texture_format(int compression_mode) const=0; virtual bool get_supports_multisample() const=0; virtual int get_supported_geom_rendering() const=0; diff --git a/panda/src/putil/bamCache.I b/panda/src/putil/bamCache.I index ee0722c0e8..72ea3f4d34 100644 --- a/panda/src/putil/bamCache.I +++ b/panda/src/putil/bamCache.I @@ -101,8 +101,9 @@ get_cache_textures() const { // Access: Published // Description: Indicates whether compressed texture files will be // stored in the cache, as compressed txo files. The -// compression data is extracted from the GSG after the -// texture has been loaded. +// compressed data may either be generated in-CPU, via +// the squish library, or it may be extracted from the +// GSG after the texture has been loaded. // // This may be set in conjunction with // set_cache_textures(), or independently of it. If diff --git a/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx b/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx index 8f2197f461..47d3353009 100644 --- a/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx +++ b/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx @@ -1597,17 +1597,22 @@ prepare_texture(Texture *tex) { default: // Anything else is not supported. tinydisplay_cat.info() - << "not loading texture " << tex->get_name() << ": " + << "Not loading texture " << tex->get_name() << ": " << tex->get_texture_type() << "\n"; return NULL; } + // Even though the texture might be compressed now, it might have an + // available uncompressed version that we can load. So don't reject + // it out-of-hand just because it's compressed. + /* if (tex->get_ram_image_compression() != Texture::CM_off) { tinydisplay_cat.info() - << "not loading texture " << tex->get_name() << ": " + << "Not loading texture " << tex->get_name() << ": " << tex->get_ram_image_compression() << "\n"; return NULL; } + */ TinyTextureContext *gtc = new TinyTextureContext(_prepared_objects, tex);