From 617a769ef760f7564bd3d64ddfbe6629a55c748c Mon Sep 17 00:00:00 2001 From: David Rose Date: Thu, 14 Aug 2008 23:50:17 +0000 Subject: [PATCH] more work towards asynchronous texture loads: auto-caching compressed texture versions --- panda/src/dxgsg8/dxTextureContext8.cxx | 2 +- panda/src/dxgsg9/dxTextureContext9.cxx | 2 +- panda/src/egg/eggTexture.I | 2 +- panda/src/egg2pg/config_egg2pg.cxx | 8 + panda/src/egg2pg/config_egg2pg.h | 1 + panda/src/egg2pg/eggLoader.cxx | 14 +- .../glstuff/glGraphicsStateGuardian_src.cxx | 467 +++++++++-------- .../src/glstuff/glGraphicsStateGuardian_src.h | 1 + panda/src/gobj/Sources.pp | 6 +- panda/src/gobj/config_gobj.cxx | 19 - panda/src/gobj/config_gobj.h | 2 - panda/src/gobj/texture.I | 226 ++++----- panda/src/gobj/texture.cxx | 480 ++++++++++++++---- panda/src/gobj/texture.h | 40 +- panda/src/gobj/texturePool.I | 24 +- panda/src/gobj/texturePool.cxx | 237 ++++++--- panda/src/gobj/texturePool.h | 35 +- panda/src/gobj/texturePoolFilter.cxx | 3 +- panda/src/gobj/texturePoolFilter.h | 5 +- panda/src/gsgbase/graphicsStateGuardianBase.h | 1 + panda/src/pgraph/Sources.pp | 3 - panda/src/pgraph/loader.cxx | 2 +- panda/src/pgraph/loaderFileTypeBam.cxx | 2 +- panda/src/pgraph/pgraph_composite3.cxx | 1 - panda/src/putil/Sources.pp | 3 + panda/src/putil/bam.h | 3 +- panda/src/putil/bamCache.I | 93 ++++ panda/src/putil/bamCache.cxx | 19 +- panda/src/putil/bamCache.h | 16 +- panda/src/putil/bamReader.I | 21 + panda/src/putil/bamReader.h | 8 +- panda/src/putil/config_util.cxx | 20 + panda/src/putil/config_util.h | 7 +- panda/src/{pgraph => putil}/loaderOptions.I | 28 +- panda/src/{pgraph => putil}/loaderOptions.cxx | 43 ++ panda/src/{pgraph => putil}/loaderOptions.h | 20 +- panda/src/putil/putil_composite2.cxx | 1 + .../tinydisplay/tinyGraphicsStateGuardian.cxx | 2 +- 38 files changed, 1256 insertions(+), 611 deletions(-) rename panda/src/{pgraph => putil}/loaderOptions.I (69%) rename panda/src/{pgraph => putil}/loaderOptions.cxx (63%) rename panda/src/{pgraph => putil}/loaderOptions.h (74%) diff --git a/panda/src/dxgsg8/dxTextureContext8.cxx b/panda/src/dxgsg8/dxTextureContext8.cxx index 9f2bd789a1..a93d727d63 100644 --- a/panda/src/dxgsg8/dxTextureContext8.cxx +++ b/panda/src/dxgsg8/dxTextureContext8.cxx @@ -709,7 +709,7 @@ create_texture(DXScreenData &scrn) { goto error_exit; } - get_texture()->texture_uploaded(); + get_texture()->texture_uploaded(scrn._dxgsg8); mark_loaded(); return true; diff --git a/panda/src/dxgsg9/dxTextureContext9.cxx b/panda/src/dxgsg9/dxTextureContext9.cxx index 389be5a4ca..09328faf99 100755 --- a/panda/src/dxgsg9/dxTextureContext9.cxx +++ b/panda/src/dxgsg9/dxTextureContext9.cxx @@ -952,7 +952,7 @@ create_texture(DXScreenData &scrn) { } } } - get_texture()->texture_uploaded(); + get_texture()->texture_uploaded(scrn._dxgsg9); } mark_loaded(); diff --git a/panda/src/egg/eggTexture.I b/panda/src/egg/eggTexture.I index 87be5e721d..f072cce768 100644 --- a/panda/src/egg/eggTexture.I +++ b/panda/src/egg/eggTexture.I @@ -955,7 +955,7 @@ get_alpha_file_channel() const { // mipmap level number; and the texture will be defined // with a series of images, one for each mipmap level. // -// If the filename is of a time that already requires a +// If the filename is of a type that already requires a // hash mark, such as a cube map or a 3-d texture, then // the filename should now require two hash marks, and // the first one indicates the mipmap level number, diff --git a/panda/src/egg2pg/config_egg2pg.cxx b/panda/src/egg2pg/config_egg2pg.cxx index 6bdfd9d85c..fee061b1d0 100644 --- a/panda/src/egg2pg/config_egg2pg.cxx +++ b/panda/src/egg2pg/config_egg2pg.cxx @@ -148,6 +148,14 @@ ConfigVariableBool egg_emulate_bface "it is false, a single polygon will be created with the two_sided " "flag set on it.")); +ConfigVariableBool egg_preload_simple_textures +("egg-preload-simple-textures", true, + PRC_DESC("This specifies whether the egg loader will generate simple " + "texture images for each texture loaded. This supercedes the " + "preload-simple-textures global default, for egg files. In " + "fact, the egg loader will generate simple texture images if " + "either this or preload-simple-textures is true.")); + ConfigureFn(config_egg2pg) { init_libegg2pg(); } diff --git a/panda/src/egg2pg/config_egg2pg.h b/panda/src/egg2pg/config_egg2pg.h index c2acd0bd17..02fab7b82f 100644 --- a/panda/src/egg2pg/config_egg2pg.h +++ b/panda/src/egg2pg/config_egg2pg.h @@ -50,6 +50,7 @@ extern EXPCL_PANDAEGG ConfigVariableEnum egg_alpha_mod extern EXPCL_PANDAEGG ConfigVariableInt egg_max_vertices; extern EXPCL_PANDAEGG ConfigVariableInt egg_max_indices; extern EXPCL_PANDAEGG ConfigVariableBool egg_emulate_bface; +extern EXPCL_PANDAEGG ConfigVariableBool egg_preload_simple_textures; extern EXPCL_PANDAEGG void init_libegg2pg(); diff --git a/panda/src/egg2pg/eggLoader.cxx b/panda/src/egg2pg/eggLoader.cxx index 62abfe6281..62331e4819 100644 --- a/panda/src/egg2pg/eggLoader.cxx +++ b/panda/src/egg2pg/eggLoader.cxx @@ -928,6 +928,12 @@ load_texture(TextureDef &def, EggTexture *egg_tex) { } } + // By convention, the egg loader will preload the simple texture images. + LoaderOptions options; + if (egg_preload_simple_textures) { + options.set_texture_flags(options.get_texture_flags() | LoaderOptions::TF_preload_simple); + } + PT(Texture) tex; switch (egg_tex->get_texture_type()) { case EggTexture::TT_unspecified: @@ -938,22 +944,22 @@ load_texture(TextureDef &def, EggTexture *egg_tex) { egg_tex->get_alpha_fullpath(), wanted_channels, egg_tex->get_alpha_file_channel(), - egg_tex->get_read_mipmaps()); + egg_tex->get_read_mipmaps(), options); } else { tex = TexturePool::load_texture(egg_tex->get_fullpath(), wanted_channels, - egg_tex->get_read_mipmaps()); + egg_tex->get_read_mipmaps(), options); } break; case EggTexture::TT_3d_texture: tex = TexturePool::load_3d_texture(egg_tex->get_fullpath(), - egg_tex->get_read_mipmaps()); + egg_tex->get_read_mipmaps(), options); break; case EggTexture::TT_cube_map: tex = TexturePool::load_cube_map(egg_tex->get_fullpath(), - egg_tex->get_read_mipmaps()); + egg_tex->get_read_mipmaps(), options); break; } diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 16c5ca0f64..b02bd69666 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -46,6 +46,8 @@ #include "indirectLess.h" #include "pStatTimer.h" #include "load_prc_file.h" +#include "bamCache.h" +#include "bamCacheRecord.h" #ifdef HAVE_CG #include "Cg/cgGL.h" @@ -2666,224 +2668,8 @@ extract_texture_data(Texture *tex) { TextureContext *tc = tex->prepare_now(get_prepared_objects(), this); nassertr(tc != (TextureContext *)NULL, false); CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc); - GLenum target = get_texture_target(tex->get_texture_type()); - GLP(BindTexture)(target, gtc->_index); - report_my_gl_errors(); - - GLint wrap_u, wrap_v, wrap_w; - GLint minfilter, magfilter; - GLfloat border_color[4]; - - GLP(GetTexParameteriv)(target, GL_TEXTURE_WRAP_S, &wrap_u); - GLP(GetTexParameteriv)(target, GL_TEXTURE_WRAP_T, &wrap_v); - wrap_w = GL_REPEAT; - if (_supports_3d_texture) { - GLP(GetTexParameteriv)(target, GL_TEXTURE_WRAP_R, &wrap_w); - } - GLP(GetTexParameteriv)(target, GL_TEXTURE_MIN_FILTER, &minfilter); - - // Mesa has a bug querying this property. - magfilter = GL_LINEAR; - // GLP(GetTexParameteriv)(target, GL_TEXTURE_MAG_FILTER, &magfilter); - - GLP(GetTexParameterfv)(target, GL_TEXTURE_BORDER_COLOR, border_color); - - GLenum page_target = target; - if (target == GL_TEXTURE_CUBE_MAP) { - // We need a particular page to get the level parameter from. - page_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X; - } - - GLint width = 1, height = 1, depth = 1; - GLP(GetTexLevelParameteriv)(page_target, 0, GL_TEXTURE_WIDTH, &width); - GLP(GetTexLevelParameteriv)(page_target, 0, GL_TEXTURE_HEIGHT, &height); - if (_supports_3d_texture) { - GLP(GetTexLevelParameteriv)(page_target, 0, GL_TEXTURE_DEPTH, &depth); - } - report_my_gl_errors(); - - GLint internal_format; - GLP(GetTexLevelParameteriv)(page_target, 0, GL_TEXTURE_INTERNAL_FORMAT, &internal_format); - - // Make sure we were able to query those parameters properly. - GLenum error_code = GLP(GetError)(); - if (error_code != GL_NO_ERROR) { - GLCAT.error() - << "Unable to query texture parameters for " << tex->get_name() - << " : " << get_error_string(error_code) << "\n"; - - return false; - } - - Texture::ComponentType type = Texture::T_unsigned_byte; - Texture::Format format = Texture::F_rgb; - Texture::CompressionMode compression = Texture::CM_off; - - switch (internal_format) { - case GL_COLOR_INDEX: - format = Texture::F_color_index; - break; - case GL_DEPTH_COMPONENT: - case GL_DEPTH_STENCIL_EXT: - type = Texture::T_float; - format = Texture::F_depth_stencil; - break; - case GL_RGBA: - format = Texture::F_rgba; - break; - case GL_RGBA4: - format = Texture::F_rgba4; - break; - case GL_RGBA8: - format = Texture::F_rgba8; - break; - case GL_RGBA12: - type = Texture::T_unsigned_short; - format = Texture::F_rgba12; - break; - - case GL_RGB: - format = Texture::F_rgb; - break; - case GL_RGB5: - format = Texture::F_rgb5; - break; - case GL_RGB5_A1: - format = Texture::F_rgba5; - break; - case GL_RGB8: - format = Texture::F_rgb8; - break; - case GL_RGB12: - format = Texture::F_rgb12; - break; - case GL_R3_G3_B2: - format = Texture::F_rgb332; - - case GL_RED: - format = Texture::F_red; - break; - case GL_GREEN: - format = Texture::F_green; - break; - case GL_BLUE: - format = Texture::F_blue; - break; - case GL_ALPHA: - format = Texture::F_alpha; - break; - case GL_LUMINANCE: - format = Texture::F_luminance; - break; - case GL_LUMINANCE_ALPHA: - format = Texture::F_luminance_alpha; - break; - - case GL_COMPRESSED_RGB: - format = Texture::F_rgb; - compression = Texture::CM_on; - break; - case GL_COMPRESSED_RGBA: - format = Texture::F_rgba; - compression = Texture::CM_on; - break; - case GL_COMPRESSED_ALPHA: - format = Texture::F_alpha; - compression = Texture::CM_on; - break; - case GL_COMPRESSED_LUMINANCE: - format = Texture::F_luminance; - compression = Texture::CM_on; - break; - case GL_COMPRESSED_LUMINANCE_ALPHA: - format = Texture::F_luminance_alpha; - compression = Texture::CM_on; - break; - - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - format = Texture::F_rgb; - compression = Texture::CM_dxt1; - break; - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - format = Texture::F_rgbm; - compression = Texture::CM_dxt1; - break; - case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: - format = Texture::F_rgba; - compression = Texture::CM_dxt3; - break; - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: - format = Texture::F_rgba; - compression = Texture::CM_dxt5; - break; - case GL_COMPRESSED_RGB_FXT1_3DFX: - format = Texture::F_rgb; - compression = Texture::CM_fxt1; - break; - case GL_COMPRESSED_RGBA_FXT1_3DFX: - format = Texture::F_rgba; - compression = Texture::CM_fxt1; - break; - } - - /* - switch (target) { - case GL_TEXTURE_1D: - tex->setup_1d_texture(width, type, format); - break; - - case GL_TEXTURE_2D: - tex->setup_2d_texture(width, height, type, format); - break; - - case GL_TEXTURE_3D: - tex->setup_3d_texture(width, height, depth, type, format); - break; - - case GL_TEXTURE_CUBE_MAP: - tex->setup_cube_map(width, type, format); - break; - } - */ - - tex->set_wrap_u(get_panda_wrap_mode(wrap_u)); - tex->set_wrap_v(get_panda_wrap_mode(wrap_v)); - tex->set_wrap_w(get_panda_wrap_mode(wrap_w)); - tex->set_border_color(Colorf(border_color[0], border_color[1], - border_color[2], border_color[3])); - - tex->set_minfilter(get_panda_filter_type(minfilter)); - // tex->set_magfilter(get_panda_filter_type(magfilter)); - - PTA_uchar image; - size_t page_size = 0; - - if (!extract_texture_image(image, page_size, tex, target, page_target, - type, compression, 0)) { - return false; - } - - tex->set_ram_image(image, compression, page_size); - - if (tex->uses_mipmaps()) { - // Also get the mipmap levels. - GLint num_expected_levels = tex->get_expected_num_mipmap_levels(); - GLint highest_level = num_expected_levels; - if (is_at_least_version(1, 2)) { - GLP(GetTexParameteriv)(target, GL_TEXTURE_MAX_LEVEL, &highest_level); - highest_level = min(highest_level, num_expected_levels); - } - for (int n = 1; n <= highest_level; ++n) { - if (!extract_texture_image(image, page_size, tex, target, page_target, - type, compression, n)) { - return false; - } - tex->set_ram_mipmap_image(n, image, page_size); - } - } - - return true; + return do_extract_texture_data(gtc); } //////////////////////////////////////////////////////////////////// @@ -7159,7 +6945,22 @@ upload_texture(CLP(TextureContext) *gtc) { } #endif - tex->texture_uploaded(); + if (tex->get_post_load_store_cache()) { + tex->set_post_load_store_cache(false); + // OK, get the RAM image, and save it in a BamCache record. + if (do_extract_texture_data(gtc)) { + if (tex->has_ram_image()) { + BamCache *cache = BamCache::get_global_ptr(); + PT(BamCacheRecord) record = cache->lookup(tex->get_fullpath(), "txo"); + if (record != (BamCacheRecord *)NULL) { + record->set_data(tex, false); + cache->store(record); + } + } + } + } + + tex->texture_uploaded(this); gtc->mark_loaded(); report_my_gl_errors(); @@ -7679,6 +7480,236 @@ check_nonresident_texture(BufferContextChain &chain) { } } +//////////////////////////////////////////////////////////////////// +// Function: GLGraphicsStateGuardian::do_extract_texture_data +// Access: Protected +// Description: The internal implementation of +// extract_texture_data(), given an already-created +// TextureContext. +//////////////////////////////////////////////////////////////////// +bool CLP(GraphicsStateGuardian):: +do_extract_texture_data(CLP(TextureContext) *gtc) { + report_my_gl_errors(); + + Texture *tex = gtc->get_texture(); + GLenum target = get_texture_target(tex->get_texture_type()); + GLP(BindTexture)(target, gtc->_index); + + GLint wrap_u, wrap_v, wrap_w; + GLint minfilter, magfilter; + GLfloat border_color[4]; + + GLP(GetTexParameteriv)(target, GL_TEXTURE_WRAP_S, &wrap_u); + GLP(GetTexParameteriv)(target, GL_TEXTURE_WRAP_T, &wrap_v); + wrap_w = GL_REPEAT; + if (_supports_3d_texture) { + GLP(GetTexParameteriv)(target, GL_TEXTURE_WRAP_R, &wrap_w); + } + GLP(GetTexParameteriv)(target, GL_TEXTURE_MIN_FILTER, &minfilter); + + // Mesa has a bug querying this property. + magfilter = GL_LINEAR; + // GLP(GetTexParameteriv)(target, GL_TEXTURE_MAG_FILTER, &magfilter); + + GLP(GetTexParameterfv)(target, GL_TEXTURE_BORDER_COLOR, border_color); + + GLenum page_target = target; + if (target == GL_TEXTURE_CUBE_MAP) { + // We need a particular page to get the level parameter from. + page_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X; + } + + GLint width = 1, height = 1, depth = 1; + GLP(GetTexLevelParameteriv)(page_target, 0, GL_TEXTURE_WIDTH, &width); + GLP(GetTexLevelParameteriv)(page_target, 0, GL_TEXTURE_HEIGHT, &height); + if (_supports_3d_texture) { + GLP(GetTexLevelParameteriv)(page_target, 0, GL_TEXTURE_DEPTH, &depth); + } + report_my_gl_errors(); + + GLint internal_format; + GLP(GetTexLevelParameteriv)(page_target, 0, GL_TEXTURE_INTERNAL_FORMAT, &internal_format); + + // Make sure we were able to query those parameters properly. + GLenum error_code = GLP(GetError)(); + if (error_code != GL_NO_ERROR) { + GLCAT.error() + << "Unable to query texture parameters for " << tex->get_name() + << " : " << get_error_string(error_code) << "\n"; + + return false; + } + + Texture::ComponentType type = Texture::T_unsigned_byte; + Texture::Format format = Texture::F_rgb; + Texture::CompressionMode compression = Texture::CM_off; + + switch (internal_format) { + case GL_COLOR_INDEX: + format = Texture::F_color_index; + break; + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL_EXT: + type = Texture::T_float; + format = Texture::F_depth_stencil; + break; + case GL_RGBA: + format = Texture::F_rgba; + break; + case GL_RGBA4: + format = Texture::F_rgba4; + break; + case GL_RGBA8: + format = Texture::F_rgba8; + break; + case GL_RGBA12: + type = Texture::T_unsigned_short; + format = Texture::F_rgba12; + break; + + case GL_RGB: + format = Texture::F_rgb; + break; + case GL_RGB5: + format = Texture::F_rgb5; + break; + case GL_RGB5_A1: + format = Texture::F_rgba5; + break; + case GL_RGB8: + format = Texture::F_rgb8; + break; + case GL_RGB12: + format = Texture::F_rgb12; + break; + case GL_R3_G3_B2: + format = Texture::F_rgb332; + + case GL_RED: + format = Texture::F_red; + break; + case GL_GREEN: + format = Texture::F_green; + break; + case GL_BLUE: + format = Texture::F_blue; + break; + case GL_ALPHA: + format = Texture::F_alpha; + break; + case GL_LUMINANCE: + format = Texture::F_luminance; + break; + case GL_LUMINANCE_ALPHA: + format = Texture::F_luminance_alpha; + break; + + case GL_COMPRESSED_RGB: + format = Texture::F_rgb; + compression = Texture::CM_on; + break; + case GL_COMPRESSED_RGBA: + format = Texture::F_rgba; + compression = Texture::CM_on; + break; + case GL_COMPRESSED_ALPHA: + format = Texture::F_alpha; + compression = Texture::CM_on; + break; + case GL_COMPRESSED_LUMINANCE: + format = Texture::F_luminance; + compression = Texture::CM_on; + break; + case GL_COMPRESSED_LUMINANCE_ALPHA: + format = Texture::F_luminance_alpha; + compression = Texture::CM_on; + break; + + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + format = Texture::F_rgb; + compression = Texture::CM_dxt1; + break; + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + format = Texture::F_rgbm; + compression = Texture::CM_dxt1; + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + format = Texture::F_rgba; + compression = Texture::CM_dxt3; + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + format = Texture::F_rgba; + compression = Texture::CM_dxt5; + break; + case GL_COMPRESSED_RGB_FXT1_3DFX: + format = Texture::F_rgb; + compression = Texture::CM_fxt1; + break; + case GL_COMPRESSED_RGBA_FXT1_3DFX: + format = Texture::F_rgba; + compression = Texture::CM_fxt1; + break; + } + + /* + switch (target) { + case GL_TEXTURE_1D: + tex->setup_1d_texture(width, type, format); + break; + + case GL_TEXTURE_2D: + tex->setup_2d_texture(width, height, type, format); + break; + + case GL_TEXTURE_3D: + tex->setup_3d_texture(width, height, depth, type, format); + break; + + case GL_TEXTURE_CUBE_MAP: + tex->setup_cube_map(width, type, format); + break; + } + */ + + tex->set_wrap_u(get_panda_wrap_mode(wrap_u)); + tex->set_wrap_v(get_panda_wrap_mode(wrap_v)); + tex->set_wrap_w(get_panda_wrap_mode(wrap_w)); + tex->set_border_color(Colorf(border_color[0], border_color[1], + border_color[2], border_color[3])); + + tex->set_minfilter(get_panda_filter_type(minfilter)); + // tex->set_magfilter(get_panda_filter_type(magfilter)); + + PTA_uchar image; + size_t page_size = 0; + + if (!extract_texture_image(image, page_size, tex, target, page_target, + type, compression, 0)) { + return false; + } + + tex->set_ram_image(image, compression, page_size); + + if (tex->uses_mipmaps()) { + // Also get the mipmap levels. + GLint num_expected_levels = tex->get_expected_num_mipmap_levels(); + GLint highest_level = num_expected_levels; + if (is_at_least_version(1, 2)) { + GLP(GetTexParameteriv)(target, GL_TEXTURE_MAX_LEVEL, &highest_level); + highest_level = min(highest_level, num_expected_levels); + } + for (int n = 1; n <= highest_level; ++n) { + if (!extract_texture_image(image, page_size, tex, target, page_target, + type, compression, n)) { + return false; + } + tex->set_ram_mipmap_image(n, image, page_size); + } + } + + return true; +} + //////////////////////////////////////////////////////////////////// // Function: GLGraphicsStateGuardian::extract_texture_image // Access: Protected diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index 2fe7f83c59..90f4cda120 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.h @@ -336,6 +336,7 @@ protected: size_t get_texture_memory_size(Texture *tex); void check_nonresident_texture(BufferContextChain &chain); + bool do_extract_texture_data(CLP(TextureContext) *gtc); bool extract_texture_image(PTA_uchar &image, size_t &page_size, Texture *tex, GLenum target, GLenum page_target, Texture::ComponentType type, diff --git a/panda/src/gobj/Sources.pp b/panda/src/gobj/Sources.pp index af0ca56b56..aaa49e1fa7 100644 --- a/panda/src/gobj/Sources.pp +++ b/panda/src/gobj/Sources.pp @@ -39,13 +39,13 @@ geomVertexWriter.h geomVertexWriter.I \ indexBufferContext.I indexBufferContext.h \ internalName.I internalName.h \ + lens.h lens.I \ material.I material.h materialPool.I materialPool.h \ matrixLens.I matrixLens.h \ occlusionQueryContext.I occlusionQueryContext.h \ orthographicLens.I orthographicLens.h perspectiveLens.I \ perspectiveLens.h \ preparedGraphicsObjects.I preparedGraphicsObjects.h \ - lens.h lens.I \ queryContext.I queryContext.h \ savedContext.I savedContext.h \ shader.I shader.h \ @@ -103,12 +103,12 @@ indexBufferContext.cxx \ material.cxx \ internalName.cxx \ + lens.cxx \ materialPool.cxx matrixLens.cxx \ occlusionQueryContext.cxx \ orthographicLens.cxx \ perspectiveLens.cxx \ preparedGraphicsObjects.cxx \ - lens.cxx \ queryContext.cxx \ savedContext.cxx \ shader.cxx \ @@ -165,13 +165,13 @@ geomVertexWriter.h geomVertexWriter.I \ indexBufferContext.I indexBufferContext.h \ internalName.I internalName.h \ + lens.h lens.I \ material.I material.h \ materialPool.I materialPool.h matrixLens.I matrixLens.h \ occlusionQueryContext.I occlusionQueryContext.h \ orthographicLens.I orthographicLens.h perspectiveLens.I \ perspectiveLens.h \ preparedGraphicsObjects.I preparedGraphicsObjects.h \ - lens.h lens.I \ queryContext.I queryContext.h \ savedContext.I savedContext.h \ shader.I shader.h \ diff --git a/panda/src/gobj/config_gobj.cxx b/panda/src/gobj/config_gobj.cxx index 455c47666b..c336ed8407 100644 --- a/panda/src/gobj/config_gobj.cxx +++ b/panda/src/gobj/config_gobj.cxx @@ -98,25 +98,6 @@ ConfigVariableBool keep_texture_ram "texture image from disk; but it will consume memory somewhat " "wastefully.")); -ConfigVariableBool preload_textures -("preload-textures", true, - PRC_DESC("When this is true, texture images are loaded from disk as soon " - "as the Texture is created from the TexturePool. When this is " - "false, the Texture is created immediately, but the image data " - "is not loaded from disk until the Texture is actually rendered " - "(or otherwise prepared) on the GSG. This can help reduce " - "wasted memory from Textures that are created but never used " - "to render.")); - -ConfigVariableBool preload_simple_textures -("preload-simple-textures", false, - PRC_DESC("When this is true, every texture image will have a simple " - "image generated for it at load time. (Normally, textures " - "get a simple image at egg2bam time.) This slows the initial " - "loading time of textures, but allows you to take advantage " - "of gsg::set_incomplete_render() to load textures on-the-fly " - "in a sub-thread.")); - ConfigVariableBool compressed_textures ("compressed-textures", false, PRC_DESC("Set this to true to compress textures as they are loaded into " diff --git a/panda/src/gobj/config_gobj.h b/panda/src/gobj/config_gobj.h index b7bc652dfd..99514e237e 100644 --- a/panda/src/gobj/config_gobj.h +++ b/panda/src/gobj/config_gobj.h @@ -51,8 +51,6 @@ extern EXPCL_PANDA_GOBJ ConfigVariableList exclude_texture_scale; extern EXPCL_PANDA_GOBJ ConfigVariableBool keep_texture_ram; -extern EXPCL_PANDA_GOBJ ConfigVariableBool preload_textures; -extern EXPCL_PANDA_GOBJ ConfigVariableBool preload_simple_textures; extern EXPCL_PANDA_GOBJ ConfigVariableBool compressed_textures; extern EXPCL_PANDA_GOBJ ConfigVariableBool vertex_buffers; extern EXPCL_PANDA_GOBJ ConfigVariableBool vertex_arrays; diff --git a/panda/src/gobj/texture.I b/panda/src/gobj/texture.I index b63fa132f1..702e9675a7 100644 --- a/panda/src/gobj/texture.I +++ b/panda/src/gobj/texture.I @@ -122,143 +122,6 @@ setup_cube_map(int size, ComponentType component_type, setup_texture(TT_cube_map, size, size, 6, component_type, format); } -//////////////////////////////////////////////////////////////////// -// Function: Texture::read -// Access: Published -// Description: Reads the named filename into the texture. -//////////////////////////////////////////////////////////////////// -INLINE bool Texture:: -read(const Filename &fullpath) { - ReMutexHolder holder(_lock); - clear(); - return do_read(fullpath, Filename(), 0, 0, 0, 0, false, false, - !preload_textures && !preload_simple_textures, NULL); -} - -//////////////////////////////////////////////////////////////////// -// Function: Texture::read -// Access: Published -// Description: Combine a 3-component image with a grayscale image -// to get a 4-component image. -// -// See the description of the full-parameter read() -// method for the meaning of the -// primary_file_num_channels and alpha_file_channel -// parameters. -//////////////////////////////////////////////////////////////////// -INLINE bool Texture:: -read(const Filename &fullpath, const Filename &alpha_fullpath, - int primary_file_num_channels, int alpha_file_channel) { - ReMutexHolder holder(_lock); - clear(); - return do_read(fullpath, alpha_fullpath, primary_file_num_channels, - alpha_file_channel, 0, 0, false, false, - !preload_textures && !preload_simple_textures, - NULL); -} - -//////////////////////////////////////////////////////////////////// -// Function: Texture::read -// Access: Published -// Description: Reads a single file into a single page or mipmap -// level, or automatically reads a series of files into -// a series of pages and/or mipmap levels. -// -// See the description of the full-parameter read() -// method for the meaning of the various parameters. -//////////////////////////////////////////////////////////////////// -INLINE bool Texture:: -read(const Filename &fullpath, int z, int n, - bool read_pages, bool read_mipmaps) { - ReMutexHolder holder(_lock); - ++_properties_modified; - ++_image_modified; - return do_read(fullpath, Filename(), 0, 0, z, n, read_pages, read_mipmaps, - !preload_textures && !preload_simple_textures, NULL); -} - -//////////////////////////////////////////////////////////////////// -// Function: Texture::read -// Access: Published -// Description: Reads the texture from the indicated filename. If -// primary_file_num_channels is not 0, it specifies the -// number of components to downgrade the image to if it -// is greater than this number. -// -// If the filename has the extension .txo, this -// implicitly reads a texture object instead of a -// filename (which replaces all of the texture -// properties). In this case, all the rest of the -// parameters are ignored, and the filename should not -// contain any hash marks; just the one named file will -// be read, since a single .txo file can contain all -// pages and mipmaps necessary to define a texture. -// -// If alpha_fullpath is not empty, it specifies the name -// of a file from which to retrieve the alpha. In this -// case, alpha_file_channel represents the numeric -// channel of this image file to use as the resulting -// texture's alpha channel; usually, this is 0 to -// indicate the grayscale combination of r, g, b; or it -// may be a one-based channel number, e.g. 1 for the red -// channel, 2 for the green channel, and so on. -// -// If read pages is false, then z indicates the page -// number into which this image will be assigned. -// Normally this is 0 for the first (or only) page of -// the texture. 3-D textures have one page for each -// level of depth, and cube map textures always have six -// pages. -// -// If read_pages is true, multiple images will be read -// at once, one for each page of a cube map or a 3-D -// texture. In this case, the filename should contain a -// sequence of one or more hash marks ("#") which will -// be filled in with the z value of each page, -// zero-based. In this case, the z parameter indicates -// the maximum z value that will be loaded, or 0 to load -// all filenames that exist. -// -// If read_mipmaps is false, then n indicates the mipmap -// level to which this image will be assigned. Normally -// this is 0 for the base texture image, but it is -// possible to load custom mipmap levels into the later -// images. After the base texture image is loaded (thus -// defining the size of the texture), you can call -// get_expected_num_mipmap_levels() to determine the -// maximum sensible value for n. -// -// If read_mipmaps is true, multiple images will be read -// as above, but this time the images represent the -// different mipmap levels of the texture image. In -// this case, the n parameter indicates the maximum n -// value that will be loaded, or 0 to load all filenames -// that exist (up to the expected number of mipmap -// levels). -// -// If both read_pages and read_mipmaps is true, then -// both sequences will be read; the filename should -// contain two sequences of hash marks, separated by -// some character such as a hyphen, underscore, or dot. -// The first hash mark sequence will be filled in with -// the mipmap level, while the second hash mark sequence -// will be the page index. -// -// This method implicitly sets keep_ram_image to false. -//////////////////////////////////////////////////////////////////// -INLINE bool Texture:: -read(const Filename &fullpath, const Filename &alpha_fullpath, - int primary_file_num_channels, int alpha_file_channel, - int z, int n, bool read_pages, bool read_mipmaps, - BamCacheRecord *record) { - ReMutexHolder holder(_lock); - ++_properties_modified; - ++_image_modified; - return do_read(fullpath, alpha_fullpath, primary_file_num_channels, - alpha_file_channel, z, n, read_pages, read_mipmaps, - !preload_textures && !preload_simple_textures, record); -} - //////////////////////////////////////////////////////////////////// // Function: Texture::write // Access: Published @@ -574,6 +437,45 @@ set_pad_size(int x, int y, int z) { _pad_z_size = z; } +//////////////////////////////////////////////////////////////////// +// Function: Texture::get_orig_file_x_size +// Access: Published +// Description: Returns the X size of the original disk image that +// this Texture was loaded from (if it came from a disk +// file), before any automatic rescaling by Panda. +//////////////////////////////////////////////////////////////////// +INLINE int Texture:: +get_orig_file_x_size() const { + return _orig_file_x_size; +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::get_orig_file_y_size +// Access: Published +// Description: Returns the Y size of the original disk image that +// this Texture was loaded from (if it came from a disk +// file), before any automatic rescaling by Panda. +//////////////////////////////////////////////////////////////////// +INLINE int Texture:: +get_orig_file_y_size() const { + return _orig_file_y_size; +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::get_orig_file_z_size +// Access: Published +// Description: Returns the Z size of the original disk image that +// this Texture was loaded from (if it came from a disk +// file), before any automatic rescaling by Panda. +//////////////////////////////////////////////////////////////////// +INLINE int Texture:: +get_orig_file_z_size() const { + // At the moment, we perform no automatic adjustment of Z size. So + // we can just return the current value, since it would be the same + // thing. + return _z_size; +} + //////////////////////////////////////////////////////////////////// // Function: Texture::get_num_components // Access: Published @@ -737,6 +639,29 @@ get_compression() const { return _compression; } +//////////////////////////////////////////////////////////////////// +// Function: Texture::has_compression +// Access: Published +// Description: Returns true if the texture indicates it wants to be +// compressed, either with CM_on or higher, or +// CM_default and compressed-textures is true. +// +// If true returned, this is not a guarantee that the +// texture is actually successfully compressed on the +// GSG. It may be that the GSG does not support the +// requested compression mode, in which case the texture +// may actually be stored uncompressed in texture +// memory. +//////////////////////////////////////////////////////////////////// +INLINE bool Texture:: +has_compression() const { + if (_compression == CM_default) { + return compressed_textures; + } else { + return (_compression != CM_off); + } +} + //////////////////////////////////////////////////////////////////// // Function: Texture::get_render_to_texture // Access: Published @@ -1408,7 +1333,34 @@ set_match_framebuffer_format(bool flag) { _match_framebuffer_format = flag; } +//////////////////////////////////////////////////////////////////// +// Function: Texture::get_post_load_store_cache +// Access: Public +// Description: Returns the setting of the post_load_store_cache +// flag. See set_post_load_store_cache(). +//////////////////////////////////////////////////////////////////// +INLINE bool Texture:: +get_post_load_store_cache() const { + return _post_load_store_cache; +} +//////////////////////////////////////////////////////////////////// +// Function: Texture::set_post_load_store_cache +// Access: Public +// Description: Sets the post_load_store_cache flag. When this is +// set, the next time the texture is loaded on a GSG, it +// will automatically extract its RAM image from the GSG +// and save it to the global BamCache. +// +// This is used to store compressed RAM images in the +// BamCache. This flag should not be set explicitly; it +// is set automatically by the TexturePool when +// model-cache-compressed-textures is set true. +//////////////////////////////////////////////////////////////////// +INLINE void Texture:: +set_post_load_store_cache(bool flag) { + _post_load_store_cache = flag; +} //////////////////////////////////////////////////////////////////// // Function: Texture::store_unscaled_byte diff --git a/panda/src/gobj/texture.cxx b/panda/src/gobj/texture.cxx index 27a895717c..7222f3a248 100644 --- a/panda/src/gobj/texture.cxx +++ b/panda/src/gobj/texture.cxx @@ -78,6 +78,7 @@ Texture(const string &name) : _ram_image_compression = CM_off; _render_to_texture = false; _match_framebuffer_format = false; + _post_load_store_cache = false; _quality_level = QL_default; _texture_type = TT_2d_texture; @@ -91,6 +92,9 @@ Texture(const string &name) : _pad_y_size = 0; _pad_z_size = 0; + _orig_file_x_size = 0; + _orig_file_y_size = 0; + _loaded_from_image = false; _loaded_from_txo = false; _has_read_pages = false; @@ -146,6 +150,8 @@ operator = (const Texture ©) { _pad_x_size = copy._pad_x_size; _pad_y_size = copy._pad_y_size; _pad_z_size = copy._pad_z_size; + _orig_file_x_size = copy._orig_file_x_size; + _orig_file_y_size = copy._orig_file_y_size; _num_components = copy._num_components; _component_width = copy._component_width; _texture_type = copy._texture_type; @@ -163,6 +169,7 @@ operator = (const Texture ©) { _border_color = copy._border_color; _compression = copy._compression; _match_framebuffer_format = copy._match_framebuffer_format; + _post_load_store_cache = false; _quality_level = copy._quality_level; _ram_image_compression = copy._ram_image_compression; _ram_images = copy._ram_images; @@ -251,6 +258,8 @@ setup_texture(Texture::TextureType texture_type, int x_size, int y_size, clear_ram_image(); set_pad_size(); + _orig_file_x_size = 0; + _orig_file_y_size = 0; _loaded_from_image = false; _loaded_from_txo = false; _has_read_pages = false; @@ -387,6 +396,150 @@ generate_alpha_scale_map() { } } +//////////////////////////////////////////////////////////////////// +// Function: Texture::read +// Access: Published +// Description: Reads the named filename into the texture. +//////////////////////////////////////////////////////////////////// +bool Texture:: +read(const Filename &fullpath, const LoaderOptions &options) { + ReMutexHolder holder(_lock); + clear(); + bool header_only = ((options.get_texture_flags() & (LoaderOptions::TF_preload | LoaderOptions::TF_preload_simple)) == 0); + return do_read(fullpath, Filename(), 0, 0, 0, 0, false, false, + header_only, NULL); +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::read +// Access: Published +// Description: Combine a 3-component image with a grayscale image +// to get a 4-component image. +// +// See the description of the full-parameter read() +// method for the meaning of the +// primary_file_num_channels and alpha_file_channel +// parameters. +//////////////////////////////////////////////////////////////////// +bool Texture:: +read(const Filename &fullpath, const Filename &alpha_fullpath, + int primary_file_num_channels, int alpha_file_channel, + const LoaderOptions &options) { + ReMutexHolder holder(_lock); + clear(); + bool header_only = ((options.get_texture_flags() & (LoaderOptions::TF_preload | LoaderOptions::TF_preload_simple)) == 0); + return do_read(fullpath, alpha_fullpath, primary_file_num_channels, + alpha_file_channel, 0, 0, false, false, + header_only, + NULL); +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::read +// Access: Published +// Description: Reads a single file into a single page or mipmap +// level, or automatically reads a series of files into +// a series of pages and/or mipmap levels. +// +// See the description of the full-parameter read() +// method for the meaning of the various parameters. +//////////////////////////////////////////////////////////////////// +bool Texture:: +read(const Filename &fullpath, int z, int n, + bool read_pages, bool read_mipmaps, + const LoaderOptions &options) { + ReMutexHolder holder(_lock); + ++_properties_modified; + ++_image_modified; + bool header_only = ((options.get_texture_flags() & (LoaderOptions::TF_preload | LoaderOptions::TF_preload_simple)) == 0); + return do_read(fullpath, Filename(), 0, 0, z, n, read_pages, read_mipmaps, + header_only, NULL); +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::read +// Access: Published +// Description: Reads the texture from the indicated filename. If +// primary_file_num_channels is not 0, it specifies the +// number of components to downgrade the image to if it +// is greater than this number. +// +// If the filename has the extension .txo, this +// implicitly reads a texture object instead of a +// filename (which replaces all of the texture +// properties). In this case, all the rest of the +// parameters are ignored, and the filename should not +// contain any hash marks; just the one named file will +// be read, since a single .txo file can contain all +// pages and mipmaps necessary to define a texture. +// +// If alpha_fullpath is not empty, it specifies the name +// of a file from which to retrieve the alpha. In this +// case, alpha_file_channel represents the numeric +// channel of this image file to use as the resulting +// texture's alpha channel; usually, this is 0 to +// indicate the grayscale combination of r, g, b; or it +// may be a one-based channel number, e.g. 1 for the red +// channel, 2 for the green channel, and so on. +// +// If read pages is false, then z indicates the page +// number into which this image will be assigned. +// Normally this is 0 for the first (or only) page of +// the texture. 3-D textures have one page for each +// level of depth, and cube map textures always have six +// pages. +// +// If read_pages is true, multiple images will be read +// at once, one for each page of a cube map or a 3-D +// texture. In this case, the filename should contain a +// sequence of one or more hash marks ("#") which will +// be filled in with the z value of each page, +// zero-based. In this case, the z parameter indicates +// the maximum z value that will be loaded, or 0 to load +// all filenames that exist. +// +// If read_mipmaps is false, then n indicates the mipmap +// level to which this image will be assigned. Normally +// this is 0 for the base texture image, but it is +// possible to load custom mipmap levels into the later +// images. After the base texture image is loaded (thus +// defining the size of the texture), you can call +// get_expected_num_mipmap_levels() to determine the +// maximum sensible value for n. +// +// If read_mipmaps is true, multiple images will be read +// as above, but this time the images represent the +// different mipmap levels of the texture image. In +// this case, the n parameter indicates the maximum n +// value that will be loaded, or 0 to load all filenames +// that exist (up to the expected number of mipmap +// levels). +// +// If both read_pages and read_mipmaps is true, then +// both sequences will be read; the filename should +// contain two sequences of hash marks, separated by +// some character such as a hyphen, underscore, or dot. +// The first hash mark sequence will be filled in with +// the mipmap level, while the second hash mark sequence +// will be the page index. +// +// This method implicitly sets keep_ram_image to false. +//////////////////////////////////////////////////////////////////// +bool Texture:: +read(const Filename &fullpath, const Filename &alpha_fullpath, + int primary_file_num_channels, int alpha_file_channel, + int z, int n, bool read_pages, bool read_mipmaps, + BamCacheRecord *record, + const LoaderOptions &options) { + ReMutexHolder holder(_lock); + ++_properties_modified; + ++_image_modified; + bool header_only = ((options.get_texture_flags() & (LoaderOptions::TF_preload | LoaderOptions::TF_preload_simple)) == 0); + return do_read(fullpath, alpha_fullpath, primary_file_num_channels, + alpha_file_channel, z, n, read_pages, read_mipmaps, + header_only, record); +} + //////////////////////////////////////////////////////////////////// // Function: Texture::estimate_texture_memory // Access: Published @@ -688,7 +841,7 @@ load_related(const InternalName *suffix) const { // Use it to load the texture. res = TexturePool::load_texture(main, alph, _primary_file_num_channels, - _alpha_file_channel); + _alpha_file_channel, false); } else { // If the alpha variant of the filename doesn't exist, just go // ahead and load the related texture without alpha. @@ -1309,7 +1462,9 @@ generate_ram_mipmap_images() { // texture. The simple image is only supported for // ordinary 2-d textures. // -// Also see generate_simple_ram_image(). +// Also see generate_simple_ram_image(), +// modify_simple_ram_image(), and +// new_simple_ram_image(). //////////////////////////////////////////////////////////////////// void Texture:: set_simple_ram_image(PTA_uchar image, int x_size, int y_size) { @@ -1322,10 +1477,46 @@ set_simple_ram_image(PTA_uchar image, int x_size, int y_size) { _simple_y_size = y_size; _simple_ram_image._image = image; _simple_ram_image._page_size = image.size(); - _simple_image_date_generated = 0; + _simple_image_date_generated = (PN_int32)time(NULL); ++_simple_image_modified; } +//////////////////////////////////////////////////////////////////// +// Function: Texture::modify_simple_ram_image +// Access: Published +// Description: Returns a modifiable pointer to the internal "simple" +// texture image. See set_simple_ram_image(). +//////////////////////////////////////////////////////////////////// +PTA_uchar Texture:: +modify_simple_ram_image() { + ReMutexHolder holder(_lock); + _simple_image_date_generated = (PN_int32)time(NULL); + return _simple_ram_image._image; +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::new_simple_ram_image +// Access: Published +// Description: Creates an empty array for the simple ram image of +// the indicated size, and returns a modifiable pointer +// to the new array. See set_simple_ram_image(). +//////////////////////////////////////////////////////////////////// +PTA_uchar Texture:: +new_simple_ram_image(int x_size, int y_size) { + ReMutexHolder holder(_lock); + nassertr(get_texture_type() == TT_2d_texture, PTA_uchar()); + size_t expected_page_size = (size_t)(x_size * y_size * 4); + + _simple_x_size = x_size; + _simple_y_size = y_size; + _simple_ram_image._image = PTA_uchar::empty_array(expected_page_size); + _simple_ram_image._page_size = expected_page_size; + _simple_image_date_generated = (PN_int32)time(NULL); + ++_simple_image_modified; + + return _simple_ram_image._image; +} + //////////////////////////////////////////////////////////////////// // Function: Texture::generate_simple_ram_image // Access: Published @@ -1338,14 +1529,13 @@ void Texture:: generate_simple_ram_image() { ReMutexHolder holder(_lock); - if (get_texture_type() != TT_2d_texture) { - clear_simple_ram_image(); + if (get_texture_type() != TT_2d_texture || + get_ram_image_compression() != CM_off) { return; } PNMImage pnmimage; if (!store(pnmimage)) { - clear_simple_ram_image(); return; } @@ -1854,11 +2044,13 @@ prepare_now(PreparedGraphicsObjects *prepared_objects, // is false. // // Normally, this is not called directly except by the -// GraphicsStateGuardian. +// GraphicsStateGuardian. It will be called in the draw +// thread. //////////////////////////////////////////////////////////////////// void Texture:: -texture_uploaded() { +texture_uploaded(GraphicsStateGuardianBase *gsg) { ReMutexHolder holder(_lock); + if (!keep_texture_ram && !_keep_ram_image) { // Once we have prepared the texture, we can generally safely // remove the pixels from main RAM. The GSG is now responsible @@ -2197,6 +2389,11 @@ do_read_one(const Filename &fullpath, const Filename &alpha_fullpath, } int x_size = image.get_x_size(); int y_size = image.get_y_size(); + if (z == 0 && n == 0) { + _orig_file_x_size = x_size; + _orig_file_y_size = y_size; + } + if (textures_header_only) { // In this mode, we never intend to load the actual texture // image anyway, so we don't even need to make the size right. @@ -2224,6 +2421,8 @@ do_read_one(const Filename &fullpath, const Filename &alpha_fullpath, } if (z == 0 && n == 0) { + _orig_file_x_size = image.get_x_size(); + _orig_file_y_size = image.get_y_size(); consider_rescale(image, fullpath.get_basename()); } else { image.set_read_size(get_expected_mipmap_x_size(n), @@ -2526,7 +2725,7 @@ do_load_one(const PNMImage &pnmimage, const string &name, int z, int n) { do_modify_ram_image(); _loaded_from_image = true; } - + do_modify_ram_mipmap_image(n); // Ensure the PNMImage is an appropriate size. @@ -2609,25 +2808,45 @@ reconsider_dirty() { void Texture:: reload_ram_image() { BamCache *cache = BamCache::get_global_ptr(); + PT(BamCacheRecord) record; + if (cache->get_active() && !textures_header_only) { // See if the texture can be found in the on-disk cache, if it is // active. - PT(BamCacheRecord) record = cache->lookup(get_fullpath(), "txo"); + + record = cache->lookup(get_fullpath(), "txo"); if (record != (BamCacheRecord *)NULL && record->has_data()) { - gobj_cat.info() - << "Texture " << get_name() << " reloaded from disk cache.\n"; - PT(Texture) tex = DCAST(Texture, record->extract_data()); - // We don't want to replace all the texture parameters--for - // instance, we don't want to change the filter type or the - // border color or anything--we just want to get the image and - // necessary associated parameters. - reconsider_image_properties(tex->get_x_size(), tex->get_y_size(), - tex->get_num_components(), - tex->get_component_type(), 0); - set_compression(tex->get_compression()); - _ram_images = tex->_ram_images; - return; + + // But don't use the cache record if the config parameters have + // changed, and we want a different-sized texture now. + int x_size = _orig_file_x_size; + int y_size = _orig_file_y_size; + Texture::adjust_size(x_size, y_size, _filename.get_basename()); + if (get_x_size() == x_size && get_y_size() == y_size) { + PT(Texture) tex = DCAST(Texture, record->extract_data()); + + // Also don't keep the cached version if it's compressed but + // we want uncompressed. + if (tex->get_ram_image_compression() == CM_off || !has_compression()) { + gobj_cat.info() + << "Texture " << get_name() << " reloaded from disk cache\n"; + // We don't want to replace all the texture parameters--for + // instance, we don't want to change the filter type or the + // border color or anything--we just want to get the image and + // necessary associated parameters. + _loaded_from_image = false; + reconsider_image_properties(tex->get_x_size(), tex->get_y_size(), + tex->get_num_components(), + tex->get_component_type(), 0); + set_compression(tex->get_compression()); + _ram_image_compression = tex->_ram_image_compression; + _ram_images = tex->_ram_images; + _loaded_from_image = true; + + return; + } + } } } @@ -2644,10 +2863,17 @@ reload_ram_image() { if (_has_read_mipmaps) { n = _num_mipmap_levels_read; } + _loaded_from_image = false; do_read(get_fullpath(), get_alpha_fullpath(), _primary_file_num_channels, _alpha_file_channel, z, n, _has_read_pages, _has_read_mipmaps, false, NULL); + + if (has_ram_image() && record != (BamCacheRecord *)NULL) { + // Update the cache. + record->set_data(this, false); + cache->store(record); + } } //////////////////////////////////////////////////////////////////// @@ -2791,6 +3017,91 @@ has_binary_alpha(Format format) { } } +//////////////////////////////////////////////////////////////////// +// Function: Texture::adjust_size +// Access: Public, Static +// Description: Computes the proper size of the texture, based on the +// original size, the filename, and the resizing whims +// of the config file. +// +// x_size and y_size should be loaded with the texture +// image's original size on disk. On return, they will +// be loaded with the texture's in-memory target size. +// The return value is true if the size has been +// adjusted, or false if it is the same. +//////////////////////////////////////////////////////////////////// +bool Texture:: +adjust_size(int &x_size, int &y_size, const string &name) { + bool exclude = false; + int num_excludes = exclude_texture_scale.get_num_unique_values(); + for (int i = 0; i < num_excludes && !exclude; ++i) { + GlobPattern pat(exclude_texture_scale.get_unique_value(i)); + if (pat.matches(name)) { + exclude = true; + } + } + + int new_x_size = x_size; + int new_y_size = y_size; + + 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); + } + + switch (get_textures_power_2()) { + case ATS_down: + new_x_size = down_to_power_2(new_x_size); + new_y_size = down_to_power_2(new_y_size); + break; + + case ATS_up: + new_x_size = up_to_power_2(new_x_size); + new_y_size = up_to_power_2(new_y_size); + break; + + case ATS_none: + break; + } + + switch (textures_square.get_value()) { + case ATS_down: + new_x_size = new_y_size = min(new_x_size, new_y_size); + break; + + case ATS_up: + new_x_size = new_y_size = max(new_x_size, new_y_size); + break; + + case ATS_none: + break; + } + + if (!exclude) { + int max_dimension = max_texture_dimension; + + if (max_dimension < 0) { + GraphicsStateGuardianBase *gsg = GraphicsStateGuardianBase::get_default_gsg(); + if (gsg != (GraphicsStateGuardianBase *)NULL) { + max_dimension = gsg->get_max_texture_dimension(); + } + } + + if (max_dimension > 0) { + new_x_size = min(new_x_size, (int)max_dimension); + new_y_size = min(new_y_size, (int)max_dimension); + } + } + + if (x_size != new_x_size || y_size != new_y_size) { + x_size = new_x_size; + y_size = new_y_size; + return true; + } + + return false; +} + //////////////////////////////////////////////////////////////////// // Function: Texture::reconsider_z_size // Access: Protected @@ -3128,69 +3439,9 @@ set_size_padded(int x, int y, int z) { //////////////////////////////////////////////////////////////////// void Texture:: consider_rescale(PNMImage &pnmimage, const string &name) { - bool exclude = false; - int num_excludes = exclude_texture_scale.get_num_unique_values(); - for (int i = 0; i < num_excludes && !exclude; ++i) { - GlobPattern pat(exclude_texture_scale.get_unique_value(i)); - if (pat.matches(name)) { - exclude = true; - } - } - int new_x_size = pnmimage.get_x_size(); int new_y_size = pnmimage.get_y_size(); - - 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); - } - - switch (get_textures_power_2()) { - case ATS_down: - new_x_size = down_to_power_2(new_x_size); - new_y_size = down_to_power_2(new_y_size); - break; - - case ATS_up: - new_x_size = up_to_power_2(new_x_size); - new_y_size = up_to_power_2(new_y_size); - break; - - case ATS_none: - break; - } - - switch (textures_square.get_value()) { - case ATS_down: - new_x_size = new_y_size = min(new_x_size, new_y_size); - break; - - case ATS_up: - new_x_size = new_y_size = max(new_x_size, new_y_size); - break; - - case ATS_none: - break; - } - - if (!exclude) { - int max_dimension = max_texture_dimension; - - if (max_dimension < 0) { - GraphicsStateGuardianBase *gsg = GraphicsStateGuardianBase::get_default_gsg(); - if (gsg != (GraphicsStateGuardianBase *)NULL) { - max_dimension = gsg->get_max_texture_dimension(); - } - } - - if (max_dimension > 0) { - new_x_size = min(new_x_size, (int)max_dimension); - new_y_size = min(new_y_size, (int)max_dimension); - } - } - - if (pnmimage.get_x_size() != new_x_size || - pnmimage.get_y_size() != new_y_size) { + if (adjust_size(new_x_size, new_y_size, name)) { pnmimage.set_read_size(new_x_size, new_y_size); } } @@ -3719,19 +3970,24 @@ make_from_bam(const FactoryParams ¶ms) { case TT_1d_texture: case TT_2d_texture: if (alpha_filename.empty()) { - me = TexturePool::load_texture(filename, primary_file_num_channels); + me = TexturePool::load_texture(filename, primary_file_num_channels, + false, manager->get_loader_options()); } else { me = TexturePool::load_texture(filename, alpha_filename, - primary_file_num_channels, alpha_file_channel); + primary_file_num_channels, + alpha_file_channel, + false, manager->get_loader_options()); } break; case TT_3d_texture: - me = TexturePool::load_3d_texture(filename); + me = TexturePool::load_3d_texture(filename, false, + manager->get_loader_options()); break; case TT_cube_map: - me = TexturePool::load_cube_map(filename); + me = TexturePool::load_cube_map(filename, false, + manager->get_loader_options()); break; } } @@ -3795,6 +4051,39 @@ fillin(DatagramIterator &scan, BamReader *manager, bool has_rawdata) { set_format(format); } + _orig_file_x_size = 0; + _orig_file_y_size = 0; + bool has_simple_ram_image = false; + if (manager->get_file_minor_ver() >= 18) { + _orig_file_x_size = scan.get_uint32(); + _orig_file_y_size = scan.get_uint32(); + has_simple_ram_image = scan.get_bool(); + } + + if (has_simple_ram_image) { + int x_size = scan.get_uint32(); + int y_size = scan.get_uint32(); + PN_int32 date_generated = scan.get_int32(); + + size_t u_size = scan.get_uint32(); + PTA_uchar image = PTA_uchar::empty_array(u_size, get_class_type()); + for (size_t u_idx = 0; u_idx < u_size; ++u_idx) { + image[(int)u_idx] = scan.get_uint8(); + } + + // Only replace the simple ram image if it was generated more + // recently than the one we already have. + if (_simple_ram_image._image.empty() || + date_generated > _simple_image_date_generated) { + _simple_x_size = x_size; + _simple_y_size = y_size; + _simple_image_date_generated = date_generated; + _simple_ram_image._image = image; + _simple_ram_image._page_size = u_size; + ++_simple_image_modified; + } + } + if (has_rawdata) { // In the rawdata case, we must always set the format. _format = format; @@ -3945,6 +4234,21 @@ write_datagram(BamWriter *manager, Datagram &me) { me.add_uint8(_format); me.add_uint8(_num_components); + me.add_uint32(_orig_file_x_size); + me.add_uint32(_orig_file_y_size); + + bool has_simple_ram_image = !_simple_ram_image._image.empty(); + me.add_bool(has_simple_ram_image); + + // Write out the simple image too, so it will be available later. + if (has_simple_ram_image) { + me.add_uint32(_simple_x_size); + me.add_uint32(_simple_y_size); + me.add_int32(_simple_image_date_generated); + me.add_uint32(_simple_ram_image._image.size()); + me.append_data(_simple_ram_image._image, _simple_ram_image._image.size()); + } + // If we are also including the texture's image data, then stuff it // in here. if (has_rawdata) { diff --git a/panda/src/gobj/texture.h b/panda/src/gobj/texture.h index 22547acac8..f3f0d09148 100644 --- a/panda/src/gobj/texture.h +++ b/panda/src/gobj/texture.h @@ -28,6 +28,7 @@ #include "pStatCollector.h" #include "reMutex.h" #include "reMutexHolder.h" +#include "loaderOptions.h" class PNMImage; class TextureContext; @@ -211,15 +212,18 @@ PUBLISHED: void generate_normalization_cube_map(int size); void generate_alpha_scale_map(); - INLINE bool read(const Filename &fullpath); - INLINE bool read(const Filename &fullpath, const Filename &alpha_fullpath, - int primary_file_num_channels, int alpha_file_channel); - INLINE bool read(const Filename &fullpath, int z, int n, - bool read_pages, bool read_mipmaps); - INLINE bool read(const Filename &fullpath, const Filename &alpha_fullpath, - int primary_file_num_channels, int alpha_file_channel, - int z, int n, bool read_pages, bool read_mipmaps, - BamCacheRecord *record = NULL); + bool read(const Filename &fullpath, const LoaderOptions &options = LoaderOptions()); + bool read(const Filename &fullpath, const Filename &alpha_fullpath, + int primary_file_num_channels, int alpha_file_channel, + const LoaderOptions &options = LoaderOptions()); + bool read(const Filename &fullpath, int z, int n, + bool read_pages, bool read_mipmaps, + const LoaderOptions &options = LoaderOptions()); + bool read(const Filename &fullpath, const Filename &alpha_fullpath, + int primary_file_num_channels, int alpha_file_channel, + int z, int n, bool read_pages, bool read_mipmaps, + BamCacheRecord *record = NULL, + const LoaderOptions &options = LoaderOptions()); INLINE bool write(const Filename &fullpath); INLINE bool write(const Filename &fullpath, int z, int n, @@ -273,6 +277,7 @@ PUBLISHED: INLINE int get_anisotropic_degree() const; INLINE Colorf get_border_color() const; INLINE CompressionMode get_compression() const; + INLINE bool has_compression() const; INLINE bool get_render_to_texture() const; INLINE bool uses_mipmaps() const; @@ -321,6 +326,8 @@ PUBLISHED: INLINE size_t get_simple_ram_image_size() const; INLINE CPTA_uchar get_simple_ram_image() const; void set_simple_ram_image(PTA_uchar image, int x_size, int y_size); + PTA_uchar modify_simple_ram_image(); + PTA_uchar new_simple_ram_image(int x_size, int y_size); void generate_simple_ram_image(); void clear_simple_ram_image(); @@ -369,6 +376,10 @@ PUBLISHED: INLINE void set_pad_size(int x=0, int y=0, int z=0); void set_size_padded(int x=1, int y=1, int z=1); + + INLINE int get_orig_file_x_size() const; + INLINE int get_orig_file_y_size() const; + INLINE int get_orig_file_z_size() const; void set_format(Format format); void set_component_type(ComponentType component_type); @@ -383,11 +394,14 @@ PUBLISHED: INLINE bool get_match_framebuffer_format() const; INLINE void set_match_framebuffer_format(bool flag); + INLINE bool get_post_load_store_cache() const; + INLINE void set_post_load_store_cache(bool flag); + TextureContext *prepare_now(PreparedGraphicsObjects *prepared_objects, GraphicsStateGuardianBase *gsg); public: - void texture_uploaded(); + void texture_uploaded(GraphicsStateGuardianBase *gsg); virtual bool has_cull_callback() const; virtual bool cull_callback(CullTraverser *trav, const CullTraverserData &data) const; @@ -405,6 +419,8 @@ public: static bool has_alpha(Format format); static bool has_binary_alpha(Format format); + static bool adjust_size(int &x_size, int &y_size, const string &name); + protected: virtual bool do_read(const Filename &fullpath, const Filename &alpha_fullpath, int primary_file_num_channels, int alpha_file_channel, @@ -541,11 +557,15 @@ protected: CompressionMode _compression; bool _render_to_texture; bool _match_framebuffer_format; + bool _post_load_store_cache; QualityLevel _quality_level; int _pad_x_size; int _pad_y_size; int _pad_z_size; + + int _orig_file_x_size; + int _orig_file_y_size; // A Texture keeps a list (actually, a map) of all the // PreparedGraphicsObjects tables that it has been prepared into. diff --git a/panda/src/gobj/texturePool.I b/panda/src/gobj/texturePool.I index 3b4e12d890..dce2a93fa7 100644 --- a/panda/src/gobj/texturePool.I +++ b/panda/src/gobj/texturePool.I @@ -55,9 +55,9 @@ verify_texture(const string &filename) { //////////////////////////////////////////////////////////////////// INLINE Texture *TexturePool:: load_texture(const string &filename, int primary_file_num_channels, - bool read_mipmaps) { + bool read_mipmaps, const LoaderOptions &options) { return get_global_ptr()->ns_load_texture(filename, primary_file_num_channels, - read_mipmaps); + read_mipmaps, options); } //////////////////////////////////////////////////////////////////// @@ -78,11 +78,11 @@ load_texture(const string &filename, int primary_file_num_channels, INLINE Texture *TexturePool:: load_texture(const string &filename, const string &alpha_filename, int primary_file_num_channels, int alpha_file_channel, - bool read_mipmaps) { + bool read_mipmaps, const LoaderOptions &options) { return get_global_ptr()->ns_load_texture(filename, alpha_filename, - primary_file_num_channels, - alpha_file_channel, - read_mipmaps); + primary_file_num_channels, + alpha_file_channel, + read_mipmaps, options); } //////////////////////////////////////////////////////////////////// @@ -100,8 +100,10 @@ load_texture(const string &filename, const string &alpha_filename, // second with the index number of each 3-d level. //////////////////////////////////////////////////////////////////// INLINE Texture *TexturePool:: -load_3d_texture(const string &filename_pattern, bool read_mipmaps) { - return get_global_ptr()->ns_load_3d_texture(filename_pattern, read_mipmaps); +load_3d_texture(const string &filename_pattern, bool read_mipmaps, + const LoaderOptions &options) { + return get_global_ptr()->ns_load_3d_texture(filename_pattern, read_mipmaps, + options); } //////////////////////////////////////////////////////////////////// @@ -119,8 +121,10 @@ load_3d_texture(const string &filename_pattern, bool read_mipmaps) { // second with the face number, 0 through 5. //////////////////////////////////////////////////////////////////// INLINE Texture *TexturePool:: -load_cube_map(const string &filename_pattern, bool read_mipmaps) { - return get_global_ptr()->ns_load_cube_map(filename_pattern, read_mipmaps); +load_cube_map(const string &filename_pattern, bool read_mipmaps, + const LoaderOptions &options) { + return get_global_ptr()->ns_load_cube_map(filename_pattern, read_mipmaps, + options); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/gobj/texturePool.cxx b/panda/src/gobj/texturePool.cxx index 788eeb8a2a..fa3bfd38a9 100644 --- a/panda/src/gobj/texturePool.cxx +++ b/panda/src/gobj/texturePool.cxx @@ -235,7 +235,7 @@ ns_has_texture(const Filename &orig_filename) { //////////////////////////////////////////////////////////////////// Texture *TexturePool:: ns_load_texture(const Filename &orig_filename, int primary_file_num_channels, - bool read_mipmaps) { + bool read_mipmaps, const LoaderOptions &options) { Filename filename(orig_filename); if (!_fake_texture_image.empty()) { @@ -265,31 +265,12 @@ ns_load_texture(const Filename &orig_filename, int primary_file_num_channels, // Can one of our texture filters supply the texture? tex = pre_load(orig_filename, Filename(), primary_file_num_channels, 0, - read_mipmaps); + read_mipmaps, options); BamCache *cache = BamCache::get_global_ptr(); - if (tex == (Texture *)NULL) { - // The texture was not supplied by a texture filter. See if it - // can be found in the on-disk cache, if it is active. - if (cache->get_active() && !textures_header_only) { - record = cache->lookup(filename, "txo"); - if (record != (BamCacheRecord *)NULL) { - if (record->has_data()) { - gobj_cat.info() - << "Texture " << filename << " found in disk cache.\n"; - tex = DCAST(Texture, record->extract_data()); - if (preload_simple_textures && !tex->has_simple_ram_image()) { - tex->generate_simple_ram_image(); - } - if (!preload_textures) { - // But drop the RAM until we need it. - tex->clear_ram_image(); - } - tex->set_keep_ram_image(false); - } - } - } - } + bool compressed_cache_record = false; + try_load_cache(tex, cache, filename, record, compressed_cache_record, + options); if (tex == (Texture *)NULL) { // The texture was neither in the pool, nor found in the on-disk @@ -298,19 +279,32 @@ ns_load_texture(const Filename &orig_filename, int primary_file_num_channels, << "Loading texture " << filename << "\n"; tex = make_texture(filename.get_extension()); if (!tex->read(filename, Filename(), primary_file_num_channels, 0, - 0, 0, false, read_mipmaps, record)) { + 0, 0, false, read_mipmaps, record, options)) { // This texture was not found or could not be read. report_texture_unreadable(filename); return NULL; } - if (preload_simple_textures) { + if (options.get_texture_flags() & LoaderOptions::TF_preload_simple) { tex->generate_simple_ram_image(); } store_record = (record != (BamCacheRecord *)NULL); } + if (cache->get_cache_compressed_textures() && tex->has_compression()) { + // We don't want to save the uncompressed version; we'll save the + // compressed version when it becomes available. + store_record = false; + if (!compressed_cache_record) { + tex->set_post_load_store_cache(true); + } + + } else if (!cache->get_cache_textures()) { + // We don't want to save this texture. + store_record = false; + } + // Set the original filename, before we searched along the path. nassertr(tex != (Texture *)NULL, NULL); tex->set_filename(orig_filename); @@ -341,7 +335,7 @@ ns_load_texture(const Filename &orig_filename, int primary_file_num_channels, cache->store(record); } - if (!preload_textures) { + if (!(options.get_texture_flags() & LoaderOptions::TF_preload)) { // And now drop the RAM until we need it. tex->clear_ram_image(); } @@ -364,13 +358,13 @@ ns_load_texture(const Filename &orig_filename, const Filename &orig_alpha_filename, int primary_file_num_channels, int alpha_file_channel, - bool read_mipmaps) { + bool read_mipmaps, const LoaderOptions &options) { Filename filename(orig_filename); Filename alpha_filename(orig_alpha_filename); if (!_fake_texture_image.empty()) { return ns_load_texture(_fake_texture_image, primary_file_num_channels, - read_mipmaps); + read_mipmaps, options); } VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); @@ -399,25 +393,12 @@ ns_load_texture(const Filename &orig_filename, // Can one of our texture filters supply the texture? tex = pre_load(orig_filename, alpha_filename, primary_file_num_channels, - alpha_file_channel, read_mipmaps); + alpha_file_channel, read_mipmaps, options); BamCache *cache = BamCache::get_global_ptr(); - if (tex == (Texture *)NULL) { - // The texture was not supplied by a texture filter. See if it - // can be found in the on-disk cache, if it is active. - if (cache->get_active() && !textures_header_only) { - // See if the texture can be found in the on-disk cache, if it is - // active. - record = cache->lookup(filename, "txo"); - if (record != (BamCacheRecord *)NULL) { - if (record->has_data()) { - gobj_cat.info() - << "Texture " << filename << " found in disk cache.\n"; - tex = DCAST(Texture, record->extract_data()); - } - } - } - } + bool compressed_cache_record = false; + try_load_cache(tex, cache, filename, record, compressed_cache_record, + options); if (tex == (Texture *)NULL) { // The texture was neither in the pool, nor found in the on-disk @@ -427,19 +408,33 @@ ns_load_texture(const Filename &orig_filename, << alpha_filename << endl; tex = make_texture(filename.get_extension()); if (!tex->read(filename, alpha_filename, primary_file_num_channels, - alpha_file_channel, 0, 0, false, read_mipmaps)) { + alpha_file_channel, 0, 0, false, read_mipmaps, NULL, + options)) { // This texture was not found or could not be read. report_texture_unreadable(filename); return NULL; } - if (preload_simple_textures) { + if (options.get_texture_flags() & LoaderOptions::TF_preload_simple) { tex->generate_simple_ram_image(); } store_record = (record != (BamCacheRecord *)NULL); } + if (cache->get_cache_compressed_textures() && tex->has_compression()) { + // We don't want to save the uncompressed version; we'll save the + // compressed version when it becomes available. + store_record = false; + if (!compressed_cache_record) { + tex->set_post_load_store_cache(true); + } + + } else if (!cache->get_cache_textures()) { + // We don't want to save this texture. + store_record = false; + } + // Set the original filenames, before we searched along the path. nassertr(tex != (Texture *)NULL, NULL); tex->set_filename(orig_filename); @@ -470,7 +465,7 @@ ns_load_texture(const Filename &orig_filename, cache->store(record); } - if (!preload_textures) { + if (!(options.get_texture_flags() & LoaderOptions::TF_preload)) { // And now drop the RAM until we need it. tex->clear_ram_image(); } @@ -490,7 +485,7 @@ ns_load_texture(const Filename &orig_filename, //////////////////////////////////////////////////////////////////// Texture *TexturePool:: ns_load_3d_texture(const Filename &filename_pattern, - bool read_mipmaps) { + bool read_mipmaps, const LoaderOptions &options) { Filename filename(filename_pattern); filename.set_pattern(true); @@ -514,18 +509,9 @@ ns_load_3d_texture(const Filename &filename_pattern, bool store_record = false; BamCache *cache = BamCache::get_global_ptr(); - if (cache->get_active() && !textures_header_only) { - // See if the texture can be found in the on-disk cache, if it is - // active. - record = cache->lookup(filename, "txo"); - if (record != (BamCacheRecord *)NULL) { - if (record->has_data()) { - gobj_cat.info() - << "Texture " << filename << " found in disk cache.\n"; - tex = DCAST(Texture, record->extract_data()); - } - } - } + bool compressed_cache_record = false; + try_load_cache(tex, cache, filename, record, compressed_cache_record, + options); if (tex == (Texture *)NULL || tex->get_texture_type() != Texture::TT_3d_texture) { @@ -535,7 +521,7 @@ ns_load_3d_texture(const Filename &filename_pattern, << "Loading 3-d texture " << filename << "\n"; tex = make_texture(filename.get_extension()); tex->setup_3d_texture(); - if (!tex->read(filename, 0, 0, true, read_mipmaps)) { + if (!tex->read(filename, 0, 0, true, read_mipmaps, options)) { // This texture was not found or could not be read. report_texture_unreadable(filename); return NULL; @@ -543,6 +529,19 @@ ns_load_3d_texture(const Filename &filename_pattern, store_record = (record != (BamCacheRecord *)NULL); } + if (cache->get_cache_compressed_textures() && tex->has_compression()) { + // We don't want to save the uncompressed version; we'll save the + // compressed version when it becomes available. + store_record = false; + if (!compressed_cache_record) { + tex->set_post_load_store_cache(true); + } + + } else if (!cache->get_cache_textures()) { + // We don't want to save this texture. + store_record = false; + } + // Set the original filename, before we searched along the path. nassertr(tex != (Texture *)NULL, false); tex->set_filename(filename_pattern); @@ -579,7 +578,8 @@ ns_load_3d_texture(const Filename &filename_pattern, // Description: The nonstatic implementation of load_cube_map(). //////////////////////////////////////////////////////////////////// Texture *TexturePool:: -ns_load_cube_map(const Filename &filename_pattern, bool read_mipmaps) { +ns_load_cube_map(const Filename &filename_pattern, bool read_mipmaps, + const LoaderOptions &options) { Filename filename(filename_pattern); filename.set_pattern(true); @@ -603,18 +603,9 @@ ns_load_cube_map(const Filename &filename_pattern, bool read_mipmaps) { bool store_record = false; BamCache *cache = BamCache::get_global_ptr(); - if (cache->get_active() && !textures_header_only) { - // See if the texture can be found in the on-disk cache, if it is - // active. - record = cache->lookup(filename, "txo"); - if (record != (BamCacheRecord *)NULL) { - if (record->has_data()) { - gobj_cat.info() - << "Texture " << filename << " found in disk cache.\n"; - tex = DCAST(Texture, record->extract_data()); - } - } - } + bool compressed_cache_record = false; + try_load_cache(tex, cache, filename, record, compressed_cache_record, + options); if (tex == (Texture *)NULL || tex->get_texture_type() != Texture::TT_cube_map) { @@ -624,13 +615,26 @@ ns_load_cube_map(const Filename &filename_pattern, bool read_mipmaps) { << "Loading cube map texture " << filename << "\n"; tex = make_texture(filename.get_extension()); tex->setup_cube_map(); - if (!tex->read(filename, 0, 0, true, read_mipmaps)) { + if (!tex->read(filename, 0, 0, true, read_mipmaps, options)) { // This texture was not found or could not be read. report_texture_unreadable(filename); return NULL; } store_record = (record != (BamCacheRecord *)NULL); } + + if (cache->get_cache_compressed_textures() && tex->has_compression()) { + // We don't want to save the uncompressed version; we'll save the + // compressed version when it becomes available. + store_record = false; + if (!compressed_cache_record) { + tex->set_post_load_store_cache(true); + } + + } else if (!cache->get_cache_textures()) { + // We don't want to save this texture. + store_record = false; + } // Set the original filename, before we searched along the path. nassertr(tex != (Texture *)NULL, false); @@ -840,6 +844,81 @@ ns_list_contents(ostream &out) const { out << "texture pool size - texture pool ram: " << total_size - total_ram_size << "\n"; } +//////////////////////////////////////////////////////////////////// +// Function: TexturePool::try_load_cache +// Access: Private +// Description: Attempts to load the texture from the cache record. +//////////////////////////////////////////////////////////////////// +void TexturePool:: +try_load_cache(PT(Texture) &tex, BamCache *cache, const Filename &filename, + PT(BamCacheRecord) &record, bool &compressed_cache_record, + const LoaderOptions &options) { + if (tex == (Texture *)NULL) { + // The texture was not supplied by a texture filter. See if it + // can be found in the on-disk cache, if it is active. + if ((cache->get_cache_textures() || cache->get_cache_compressed_textures()) && !textures_header_only) { + record = cache->lookup(filename, "txo"); + if (record != (BamCacheRecord *)NULL) { + if (record->has_data()) { + tex = DCAST(Texture, record->extract_data()); + compressed_cache_record = (tex->get_ram_image_compression() != Texture::CM_off); + int x_size = tex->get_orig_file_x_size(); + int y_size = tex->get_orig_file_y_size(); + Texture::adjust_size(x_size, y_size, filename.get_basename()); + + if (!cache->get_cache_textures() && !compressed_cache_record) { + // We're not supposed to be caching uncompressed textures. + if (gobj_cat.is_debug()) { + gobj_cat.debug() + << "Not caching uncompressed texture " << *tex << "\n"; + } + tex = NULL; + record = NULL; + + } else if (x_size != tex->get_x_size() || + y_size != tex->get_y_size()) { + // The cached texture no longer matches our expected size + // (the resizing config variables must have changed). + // We'll have to reload the texture from its original file + // so we can rebuild the cache. + if (gobj_cat.is_debug()) { + gobj_cat.debug() + << "Cached texture " << *tex << " has size " + << tex->get_x_size() << " x " << tex->get_y_size() + << " instead of " << x_size << " x " << y_size + << "; dropping cache.\n"; + } + tex = NULL; + + } else if (!tex->has_compression() && tex->get_ram_image_compression() != Texture::CM_off) { + // This texture shouldn't be compressed, but it is. Go + // reload it. + if (gobj_cat.is_debug()) { + gobj_cat.debug() + << "Cached texture " << *tex + << " is compressed in cache; dropping cache.\n"; + } + tex = NULL; + + } else { + gobj_cat.info() + << "Texture " << filename << " found in disk cache.\n"; + if ((options.get_texture_flags() & LoaderOptions::TF_preload_simple) && + !tex->has_simple_ram_image()) { + tex->generate_simple_ram_image(); + } + if (!(options.get_texture_flags() & LoaderOptions::TF_preload)) { + // But drop the RAM until we need it. + tex->clear_ram_image(); + } + tex->set_keep_ram_image(false); + } + } + } + } + } +} + //////////////////////////////////////////////////////////////////// // Function: TexturePool::report_texture_unreadable // Access: Private @@ -892,7 +971,7 @@ report_texture_unreadable(const Filename &filename) const { PT(Texture) TexturePool:: pre_load(const Filename &orig_filename, const Filename &orig_alpha_filename, int primary_file_num_channels, int alpha_file_channel, - bool read_mipmaps) { + bool read_mipmaps, const LoaderOptions &options) { PT(Texture) tex; MutexHolder holder(_lock); @@ -903,7 +982,7 @@ pre_load(const Filename &orig_filename, const Filename &orig_alpha_filename, ++fi) { tex = (*fi)->pre_load(orig_filename, orig_alpha_filename, primary_file_num_channels, alpha_file_channel, - read_mipmaps); + read_mipmaps, options); if (tex != (Texture *)NULL) { return tex; } diff --git a/panda/src/gobj/texturePool.h b/panda/src/gobj/texturePool.h index eb661434dc..fbb79b34f2 100644 --- a/panda/src/gobj/texturePool.h +++ b/panda/src/gobj/texturePool.h @@ -19,10 +19,13 @@ #include "texture.h" #include "filename.h" #include "config_gobj.h" +#include "loaderOptions.h" #include "pmutex.h" #include "pmap.h" class TexturePoolFilter; +class BamCache; +class BamCacheRecord; //////////////////////////////////////////////////////////////////// // Class : TexturePool @@ -41,16 +44,20 @@ PUBLISHED: INLINE static bool verify_texture(const string &filename); INLINE static Texture *load_texture(const string &filename, int primary_file_num_channels = 0, - bool read_mipmaps = false); + bool read_mipmaps = false, + const LoaderOptions &options = LoaderOptions()); INLINE static Texture *load_texture(const string &filename, const string &alpha_filename, int primary_file_num_channels = 0, int alpha_file_channel = 0, - bool read_mipmaps = false); + bool read_mipmaps = false, + const LoaderOptions &options = LoaderOptions()); INLINE static Texture *load_3d_texture(const string &filename_pattern, - bool read_mipmaps = false); + bool read_mipmaps = false, + const LoaderOptions &options = LoaderOptions()); INLINE static Texture *load_cube_map(const string &filename_pattern, - bool read_mipmaps = false); + bool read_mipmaps = false, + const LoaderOptions &options = LoaderOptions()); INLINE static Texture *get_normalization_cube_map(int size); INLINE static Texture *get_alpha_scale_map(); @@ -87,17 +94,21 @@ private: bool ns_has_texture(const Filename &orig_filename); Texture *ns_load_texture(const Filename &orig_filename, - int primary_file_num_channels, - bool read_mipmaps); + int primary_file_num_channels, + bool read_mipmaps, + const LoaderOptions &options); Texture *ns_load_texture(const Filename &orig_filename, const Filename &orig_alpha_filename, int primary_file_num_channels, int alpha_file_channel, - bool read_mipmaps); + bool read_mipmaps, + const LoaderOptions &options); Texture *ns_load_3d_texture(const Filename &filename_pattern, - bool read_mipmaps); + bool read_mipmaps, + const LoaderOptions &options); Texture *ns_load_cube_map(const Filename &filename_pattern, - bool read_mipmaps); + bool read_mipmaps, + const LoaderOptions &options); Texture *ns_get_normalization_cube_map(int size); Texture *ns_get_alpha_scale_map(); @@ -107,6 +118,10 @@ private: int ns_garbage_collect(); void ns_list_contents(ostream &out) const; + void try_load_cache(PT(Texture) &tex, BamCache *cache, + const Filename &filename, PT(BamCacheRecord) &record, + bool &compressed_cache_record, + const LoaderOptions &options); void report_texture_unreadable(const Filename &filename) const; // Methods to invoke a TexturePoolFilter. @@ -114,7 +129,7 @@ private: const Filename &orig_alpha_filename, int primary_file_num_channels, int alpha_file_channel, - bool read_mipmaps); + bool read_mipmaps, const LoaderOptions &options); PT(Texture) post_load(Texture *tex); void load_filters(); diff --git a/panda/src/gobj/texturePoolFilter.cxx b/panda/src/gobj/texturePoolFilter.cxx index 5039f9ca98..f3b0a69f30 100644 --- a/panda/src/gobj/texturePoolFilter.cxx +++ b/panda/src/gobj/texturePoolFilter.cxx @@ -37,7 +37,8 @@ TexturePoolFilter:: // this filename. //////////////////////////////////////////////////////////////////// PT(Texture) TexturePoolFilter:: -pre_load(const Filename &, const Filename &, int, int, bool) { +pre_load(const Filename &, const Filename &, int, int, bool, + const LoaderOptions &) { return NULL; } diff --git a/panda/src/gobj/texturePoolFilter.h b/panda/src/gobj/texturePoolFilter.h index 86ee817476..c82dace9e5 100644 --- a/panda/src/gobj/texturePoolFilter.h +++ b/panda/src/gobj/texturePoolFilter.h @@ -20,6 +20,8 @@ #include "pointerTo.h" #include "typedObject.h" +class LoaderOptions; + //////////////////////////////////////////////////////////////////// // Class : TexturePoolFilter // Description : This is an abstract base class, a placeholder for any @@ -50,7 +52,8 @@ public: const Filename &orig_alpha_filename, int primary_file_num_channels, int alpha_file_channel, - bool read_mipmaps); + bool read_mipmaps, + const LoaderOptions &options); virtual PT(Texture) post_load(Texture *tex); virtual void output(ostream &out) const; diff --git a/panda/src/gsgbase/graphicsStateGuardianBase.h b/panda/src/gsgbase/graphicsStateGuardianBase.h index 83fc451b42..9d05741061 100644 --- a/panda/src/gsgbase/graphicsStateGuardianBase.h +++ b/panda/src/gsgbase/graphicsStateGuardianBase.h @@ -134,6 +134,7 @@ public: virtual TextureContext *prepare_texture(Texture *tex)=0; virtual void release_texture(TextureContext *tc)=0; + virtual bool extract_texture_data(Texture *tex)=0; virtual GeomContext *prepare_geom(Geom *geom)=0; virtual void release_geom(GeomContext *gc)=0; diff --git a/panda/src/pgraph/Sources.pp b/panda/src/pgraph/Sources.pp index 25b831537a..81d22966ee 100644 --- a/panda/src/pgraph/Sources.pp +++ b/panda/src/pgraph/Sources.pp @@ -69,7 +69,6 @@ loaderFileType.h \ loaderFileTypeBam.h \ loaderFileTypeRegistry.h \ - loaderOptions.I loaderOptions.h \ lodNode.I lodNode.h \ lodNodeType.h \ materialAttrib.I materialAttrib.h \ @@ -184,7 +183,6 @@ loaderFileType.cxx \ loaderFileTypeBam.cxx \ loaderFileTypeRegistry.cxx \ - loaderOptions.cxx \ lodNode.cxx \ lodNodeType.cxx \ materialAttrib.cxx \ @@ -295,7 +293,6 @@ loaderFileType.h \ loaderFileTypeBam.h \ loaderFileTypeRegistry.h \ - loaderOptions.I loaderOptions.h \ lodNode.I lodNode.h \ lodNodeType.h \ materialAttrib.I materialAttrib.h \ diff --git a/panda/src/pgraph/loader.cxx b/panda/src/pgraph/loader.cxx index 5d9d0e3cfe..79f2223d02 100644 --- a/panda/src/pgraph/loader.cxx +++ b/panda/src/pgraph/loader.cxx @@ -257,7 +257,7 @@ try_load_file(const Filename &pathname, const LoaderOptions &options, bool report_errors = (options.get_flags() & LoaderOptions::LF_report_errors) != 0; PT(BamCacheRecord) record; - if (cache->get_active() && requested_type->get_allow_disk_cache(options)) { + if (cache->get_cache_models() && requested_type->get_allow_disk_cache(options)) { // See if the model can be found in the on-disk cache, if it is // active. record = cache->lookup(pathname, "bam"); diff --git a/panda/src/pgraph/loaderFileTypeBam.cxx b/panda/src/pgraph/loaderFileTypeBam.cxx index e0b512c372..e801f934af 100644 --- a/panda/src/pgraph/loaderFileTypeBam.cxx +++ b/panda/src/pgraph/loaderFileTypeBam.cxx @@ -80,7 +80,7 @@ load_file(const Filename &path, const LoaderOptions &options, if (!bam_file.open_read(path, report_errors)) { return NULL; } - + bam_file.get_reader()->set_loader_options(options); return bam_file.read_node(report_errors); } diff --git a/panda/src/pgraph/pgraph_composite3.cxx b/panda/src/pgraph/pgraph_composite3.cxx index d59094a10c..f1345472dc 100644 --- a/panda/src/pgraph/pgraph_composite3.cxx +++ b/panda/src/pgraph/pgraph_composite3.cxx @@ -9,7 +9,6 @@ #include "loaderFileType.cxx" #include "loaderFileTypeBam.cxx" #include "loaderFileTypeRegistry.cxx" -#include "loaderOptions.cxx" #include "lodNode.cxx" #include "lodNodeType.cxx" #include "materialAttrib.cxx" diff --git a/panda/src/putil/Sources.pp b/panda/src/putil/Sources.pp index 88607ac97e..225998a6cc 100644 --- a/panda/src/putil/Sources.pp +++ b/panda/src/putil/Sources.pp @@ -48,6 +48,7 @@ lineStream.h lineStreamBuf.I lineStreamBuf.h \ linkedListNode.I linkedListNode.h \ load_prc_file.h \ + loaderOptions.I loaderOptions.h \ modifierButtons.I modifierButtons.h mouseButton.h \ mouseData.I mouseData.h nameUniquifier.I nameUniquifier.h \ nodeCachedReferenceCount.h nodeCachedReferenceCount.I \ @@ -96,6 +97,7 @@ keyboardButton.cxx lineStream.cxx lineStreamBuf.cxx \ linkedListNode.cxx \ load_prc_file.cxx \ + loaderOptions.cxx \ modifierButtons.cxx mouseButton.cxx mouseData.cxx \ nameUniquifier.cxx \ nodeCachedReferenceCount.cxx \ @@ -153,6 +155,7 @@ lineStream.h lineStreamBuf.I lineStreamBuf.h \ linkedListNode.I linkedListNode.h \ load_prc_file.h \ + loaderOptions.I loaderOptions.h \ modifierButtons.I \ modifierButtons.h mouseButton.h mouseData.I mouseData.h \ nameUniquifier.I nameUniquifier.h \ diff --git a/panda/src/putil/bam.h b/panda/src/putil/bam.h index 755935f6ac..e7ec1c114e 100644 --- a/panda/src/putil/bam.h +++ b/panda/src/putil/bam.h @@ -32,7 +32,7 @@ static const unsigned short _bam_major_ver = 6; // Bumped to major version 5 on 5/6/05 for new Geom implementation. // Bumped to major version 6 on 2/11/06 to factor out PandaNode::CData. -static const unsigned short _bam_minor_ver = 17; +static const unsigned short _bam_minor_ver = 18; // Bumped to minor version 1 on 3/12/06 to add Texture::_compression. // Bumped to minor version 2 on 3/17/06 to add PandaNode::_draw_control_mask. // Bumped to minor version 3 on 3/21/06 to add Texture::_ram_images. @@ -50,6 +50,7 @@ static const unsigned short _bam_minor_ver = 17; // Bumped to minor version 15 on 4/9/08 to add TextureAttrib::_implicit_sort. // Bumped to minor version 16 on 5/13/08 to add Texture::_quality_level. // Bumped to minor version 17 on 8/6/08 to add PartBundle::_anim_preload. +// Bumped to minor version 18 on 8/14/08 to add Texture::_simple_ram_image. #endif diff --git a/panda/src/putil/bamCache.I b/panda/src/putil/bamCache.I index 077ed7c776..ee0722c0e8 100644 --- a/panda/src/putil/bamCache.I +++ b/panda/src/putil/bamCache.I @@ -20,6 +20,10 @@ // that the cache should be consulted automatically on // loads, "not active" means that objects should be // loaded directly without consulting the cache. +// +// This represents the global flag. Also see the +// individual cache_models, cache_textures, +// cache_compressed_textures flags. //////////////////////////////////////////////////////////////////// INLINE void BamCache:: set_active(bool active) { @@ -34,12 +38,101 @@ set_active(bool active) { // should be consulted automatically on loads, "not // active" means that objects should be loaded directly // without consulting the cache. +// +// This represents the global flag. Also see the +// individual cache_models, cache_textures, +// cache_compressed_textures flags. //////////////////////////////////////////////////////////////////// INLINE bool BamCache:: get_active() const { return _active; } +//////////////////////////////////////////////////////////////////// +// Function: BamCache::set_cache_models +// Access: Published +// Description: Indicates whether model files (e.g. egg files and bam +// files) will be stored in the cache, as bam files. +//////////////////////////////////////////////////////////////////// +INLINE void BamCache:: +set_cache_models(bool flag) { + _cache_models = flag; +} + +//////////////////////////////////////////////////////////////////// +// Function: BamCache::get_cache_models +// Access: Published +// Description: Returns whether model files (e.g. egg files and bam +// files) will be stored in the cache, as bam files. +// +// This also returns false if get_active() is false. +//////////////////////////////////////////////////////////////////// +INLINE bool BamCache:: +get_cache_models() const { + return _cache_models && _active; +} + +//////////////////////////////////////////////////////////////////// +// Function: BamCache::set_cache_textures +// Access: Published +// Description: Indicates whether texture files will be stored in the +// cache, as uncompressed txo files. +//////////////////////////////////////////////////////////////////// +INLINE void BamCache:: +set_cache_textures(bool flag) { + _cache_textures = flag; +} + +//////////////////////////////////////////////////////////////////// +// Function: BamCache::get_cache_textures +// Access: Published +// Description: Returns whether texture files (e.g. egg files and bam +// files) will be stored in the cache, as txo files. +// +// This also returns false if get_active() is false. +//////////////////////////////////////////////////////////////////// +INLINE bool BamCache:: +get_cache_textures() const { + return _cache_textures && _active; +} + +//////////////////////////////////////////////////////////////////// +// Function: BamCache::set_cache_compressed_textures +// 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. +// +// This may be set in conjunction with +// set_cache_textures(), or independently of it. If +// set_cache_textures() is true and this is false, all +// textures will be cached in their uncompressed form. +// If set_cache_textures() is false and this is true, +// only compressed textures will be cached, and they +// will be cached in their compressed form. If both are +// true, all textures will be cached, in their +// uncompressed or compressed form appropriately. +//////////////////////////////////////////////////////////////////// +INLINE void BamCache:: +set_cache_compressed_textures(bool flag) { + _cache_compressed_textures = flag; +} + +//////////////////////////////////////////////////////////////////// +// Function: BamCache::get_cache_compressed_textures +// Access: Published +// Description: Returns whether compressed texture files will be +// stored in the cache, as compressed txo files. See +// set_cache_compressed_textures(). +// +// This also returns false if get_active() is false. +//////////////////////////////////////////////////////////////////// +INLINE bool BamCache:: +get_cache_compressed_textures() const { + return _cache_compressed_textures && _active; +} + //////////////////////////////////////////////////////////////////// // Function: BamCache::get_root // Access: Published diff --git a/panda/src/putil/bamCache.cxx b/panda/src/putil/bamCache.cxx index 1c846733ae..775a9464e9 100644 --- a/panda/src/putil/bamCache.cxx +++ b/panda/src/putil/bamCache.cxx @@ -53,16 +53,31 @@ BamCache() : PRC_DESC("This is the amount of time, in seconds, between automatic " "flushes of the model-cache index.")); + ConfigVariableBool model_cache_models + ("model-cache-models", true, + PRC_DESC("If this is set to true, models will be cached in the " + "model cache, as bam files.")); + ConfigVariableBool model_cache_textures ("model-cache-textures", true, PRC_DESC("If this is set to true, textures will also be cached in the " "model cache, as txo files.")); + ConfigVariableBool model_cache_compressed_textures + ("model-cache-compressed-textures", false, + PRC_DESC("If this is set to true, compressed textures will be cached " + "in the model cache, in their compressed form as downloaded " + "by the GSG. This may be set in conjunction with " + "model-cache-textures, or it may be independent.")); + ConfigVariableInt model_cache_max_kbytes ("model-cache-max-kbytes", 1048576, PRC_DESC("This is the maximum size of the model cache, in kilobytes.")); + _cache_models = model_cache_models; _cache_textures = model_cache_textures; + _cache_compressed_textures = model_cache_compressed_textures; + _flush_time = model_cache_flush; _max_kbytes = model_cache_max_kbytes; @@ -143,10 +158,6 @@ set_root(const Filename &root) { PT(BamCacheRecord) BamCache:: lookup(const Filename &source_filename, const string &cache_extension) { consider_flush_index(); - - if ((cache_extension == "txo")&&(!_cache_textures)) { - return NULL; - } Filename source_pathname(source_filename); source_pathname.make_absolute(); diff --git a/panda/src/putil/bamCache.h b/panda/src/putil/bamCache.h index d3949649c8..2fbc54e275 100644 --- a/panda/src/putil/bamCache.h +++ b/panda/src/putil/bamCache.h @@ -48,6 +48,15 @@ PUBLISHED: INLINE void set_active(bool flag); INLINE bool get_active() const; + INLINE void set_cache_models(bool flag); + INLINE bool get_cache_models() const; + + INLINE void set_cache_textures(bool flag); + INLINE bool get_cache_textures() const; + + INLINE void set_cache_compressed_textures(bool flag); + INLINE bool get_cache_compressed_textures() const; + void set_root(const Filename &root); INLINE const Filename &get_root() const; @@ -92,17 +101,20 @@ private: PT(BamCacheRecord) read_record(const Filename &source_pathname, const Filename &cache_filename, int pass); - static PT(BamCacheRecord) do_read_record(Filename &cache_pathname, bool read_data); + static PT(BamCacheRecord) do_read_record(Filename &cache_pathname, + bool read_data); static string hash_filename(const string &filename); static void make_global(); bool _active; + bool _cache_models; + bool _cache_textures; + bool _cache_compressed_textures; bool _read_only; Filename _root; int _flush_time; int _max_kbytes; - bool _cache_textures; static BamCache *_global_ptr; BamCacheIndex *_index; diff --git a/panda/src/putil/bamReader.I b/panda/src/putil/bamReader.I index 58268b3410..09aca7396f 100644 --- a/panda/src/putil/bamReader.I +++ b/panda/src/putil/bamReader.I @@ -26,6 +26,27 @@ get_filename() const { return _filename; } +//////////////////////////////////////////////////////////////////// +// Function: BamReader::get_loader_options +// Access: Public +// Description: Returns the LoaderOptions passed to the loader when +// the model was requested, if any. +//////////////////////////////////////////////////////////////////// +INLINE const LoaderOptions &BamReader:: +get_loader_options() const { + return _loader_options; +} + +//////////////////////////////////////////////////////////////////// +// Function: BamReader::set_loader_options +// Access: Public +// Description: Specifies the LoaderOptions for this BamReader. +//////////////////////////////////////////////////////////////////// +INLINE void BamReader:: +set_loader_options(const LoaderOptions &options) { + _loader_options = options; +} + //////////////////////////////////////////////////////////////////// // Function: BamReader::is_eof // Access: Public diff --git a/panda/src/putil/bamReader.h b/panda/src/putil/bamReader.h index dffd80e258..634c41706b 100644 --- a/panda/src/putil/bamReader.h +++ b/panda/src/putil/bamReader.h @@ -23,6 +23,7 @@ #include "datagramIterator.h" #include "bamReaderParam.h" #include "bamEndian.h" +#include "loaderOptions.h" #include "factory.h" #include "vector_int.h" #include "pset.h" @@ -99,6 +100,9 @@ public: AuxData *get_aux_data(TypedWritable *obj, const string &name) const; INLINE const Filename &get_filename() const; + + INLINE const LoaderOptions &get_loader_options() const; + INLINE void set_loader_options(const LoaderOptions &options); TypedWritable *read_object(); INLINE bool is_eof() const; @@ -185,9 +189,11 @@ private: typedef phash_map IndexMap; IndexMap _index_map; - // This is the filename of the BAM, or null string if not in a file. + // This is the filename of the BAM, or empty string if not in a file. Filename _filename; + LoaderOptions _loader_options; + // This maps the object ID numbers encountered within the Bam file // to the actual pointers of the corresponding generated objects. class CreatedObj { diff --git a/panda/src/putil/config_util.cxx b/panda/src/putil/config_util.cxx index 5b38c07299..edc3e9861b 100644 --- a/panda/src/putil/config_util.cxx +++ b/panda/src/putil/config_util.cxx @@ -126,6 +126,26 @@ ConfigVariableDouble sleep_precision "timeout of 1.0 seconds, we can expect to actually sleep for " "somewhere between 1.0 and 1.0 + sleep-precision seconds.")); +ConfigVariableBool preload_textures +("preload-textures", true, + PRC_DESC("When this is true, texture images are loaded from disk as soon " + "as the Texture is created from the TexturePool. When this is " + "false, the Texture is created immediately, but the image data " + "is not loaded from disk until the Texture is actually rendered " + "(or otherwise prepared) on the GSG. This can help reduce " + "wasted memory from Textures that are created but never used " + "to render.")); + +ConfigVariableBool preload_simple_textures +("preload-simple-textures", false, + PRC_DESC("When this is true, every texture image will have a simple " + "image generated for it at load time. (Normally, textures " + "get a simple image at egg2bam time.) This slows the initial " + "loading time of textures, but allows you to take advantage " + "of gsg::set_incomplete_render() to load textures on-the-fly " + "in a sub-thread. It's not generally necessary if you are " + "loading bam files that were generated via egg2bam.")); + //////////////////////////////////////////////////////////////////// // Function: init_libputil // Description: Initializes the library. This must be called at diff --git a/panda/src/putil/config_util.h b/panda/src/putil/config_util.h index c29032c903..e498d95a83 100644 --- a/panda/src/putil/config_util.h +++ b/panda/src/putil/config_util.h @@ -53,11 +53,10 @@ EXPCL_PANDA_PUTIL ConfigVariableSearchPath &get_sound_path(); EXPCL_PANDA_PUTIL ConfigVariableSearchPath &get_plugin_path(); END_PUBLISH -extern ConfigVariableDouble clock_frame_rate; -extern ConfigVariableDouble clock_degrade_factor; -extern ConfigVariableDouble max_dt; extern ConfigVariableDouble sleep_precision; -extern ConfigVariableDouble average_frame_rate_interval; + +extern EXPCL_PANDA_PUTIL ConfigVariableBool preload_textures; +extern EXPCL_PANDA_PUTIL ConfigVariableBool preload_simple_textures; extern EXPCL_PANDA_PUTIL void init_libputil(); diff --git a/panda/src/pgraph/loaderOptions.I b/panda/src/putil/loaderOptions.I similarity index 69% rename from panda/src/pgraph/loaderOptions.I rename to panda/src/putil/loaderOptions.I index 23d5946636..4b45291ac9 100644 --- a/panda/src/pgraph/loaderOptions.I +++ b/panda/src/putil/loaderOptions.I @@ -19,8 +19,8 @@ // Description: //////////////////////////////////////////////////////////////////// INLINE LoaderOptions:: -LoaderOptions(int flags) : - _flags(flags) +LoaderOptions(int flags, int texture_flags) : + _flags(flags), _texture_flags(texture_flags) { } @@ -31,7 +31,8 @@ LoaderOptions(int flags) : //////////////////////////////////////////////////////////////////// INLINE LoaderOptions:: LoaderOptions(const LoaderOptions ©) : - _flags(copy._flags) + _flags(copy._flags), + _texture_flags(copy._texture_flags) { } @@ -43,6 +44,7 @@ LoaderOptions(const LoaderOptions ©) : INLINE void LoaderOptions:: operator = (const LoaderOptions ©) { _flags = copy._flags; + _texture_flags = copy._texture_flags; } //////////////////////////////////////////////////////////////////// @@ -64,3 +66,23 @@ INLINE int LoaderOptions:: get_flags() const { return _flags; } + +//////////////////////////////////////////////////////////////////// +// Function: LoaderOptions::set_texture_flags +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void LoaderOptions:: +set_texture_flags(int texture_flags) { + _texture_flags = texture_flags; +} + +//////////////////////////////////////////////////////////////////// +// Function: LoaderOptions::get_texture_flags +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE int LoaderOptions:: +get_texture_flags() const { + return _texture_flags; +} diff --git a/panda/src/pgraph/loaderOptions.cxx b/panda/src/putil/loaderOptions.cxx similarity index 63% rename from panda/src/pgraph/loaderOptions.cxx rename to panda/src/putil/loaderOptions.cxx index de49108fc0..2303c0aba1 100644 --- a/panda/src/pgraph/loaderOptions.cxx +++ b/panda/src/putil/loaderOptions.cxx @@ -13,8 +13,26 @@ //////////////////////////////////////////////////////////////////// #include "loaderOptions.h" +#include "config_util.h" #include "indent.h" +//////////////////////////////////////////////////////////////////// +// Function: LoaderOptions::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +LoaderOptions:: +LoaderOptions(int flags) : + _flags(flags), _texture_flags(0) +{ + if (preload_textures) { + _texture_flags |= TF_preload; + } + if (preload_simple_textures) { + _texture_flags |= TF_preload_simple; + } +} + //////////////////////////////////////////////////////////////////// // Function: LoaderOptions::output // Access: Published @@ -23,6 +41,7 @@ void LoaderOptions:: output(ostream &out) const { out << "LoaderOptions("; + string sep = ""; write_flag(out, sep, "LF_search", LF_search); write_flag(out, sep, "LF_report_errors", LF_report_errors); @@ -41,6 +60,16 @@ output(ostream &out) const { if (sep.empty()) { out << "0"; } + + out << ", "; + + sep = ""; + write_texture_flag(out, sep, "TF_preload", TF_preload); + write_texture_flag(out, sep, "TF_preload_simple", TF_preload_simple); + if (sep.empty()) { + out << "0"; + } + out << ")"; } @@ -57,3 +86,17 @@ write_flag(ostream &out, string &sep, sep = " | "; } } + +//////////////////////////////////////////////////////////////////// +// Function: LoaderOptions::write_texture_flag +// Access: Private +// Description: Used to implement output(). +//////////////////////////////////////////////////////////////////// +void LoaderOptions:: +write_texture_flag(ostream &out, string &sep, + const string &flag_name, int flag) const { + if ((_texture_flags & flag) == flag) { + out << sep << flag_name; + sep = " | "; + } +} diff --git a/panda/src/pgraph/loaderOptions.h b/panda/src/putil/loaderOptions.h similarity index 74% rename from panda/src/pgraph/loaderOptions.h rename to panda/src/putil/loaderOptions.h index c9cfba527d..7d19c267b9 100644 --- a/panda/src/pgraph/loaderOptions.h +++ b/panda/src/putil/loaderOptions.h @@ -22,10 +22,9 @@ // Description : Specifies parameters that may be passed to the // loader. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA_PGRAPH LoaderOptions { +class EXPCL_PANDA_PUTIL LoaderOptions { PUBLISHED: - // At the moment, we only have this one set of flags. Maybe one day - // there will be more options. + // Flags for loading model files. enum LoaderFlags { LF_search = 0x0001, LF_report_errors = 0x0002, @@ -39,19 +38,32 @@ PUBLISHED: LF_allow_instance = 0x0080, // returned pointer might be shared }; - INLINE LoaderOptions(int flags = LF_search | LF_report_errors); + // Flags for loading texture files. + enum TextureFlags { + TF_preload = 0x0004, // Texture will have RAM image + TF_preload_simple = 0x0008, // Texture will have simple RAM image + }; + + LoaderOptions(int flags = LF_search | LF_report_errors); + INLINE LoaderOptions(int flags, int texture_flags); INLINE LoaderOptions(const LoaderOptions ©); INLINE void operator = (const LoaderOptions ©); INLINE void set_flags(int flags); INLINE int get_flags() const; + INLINE void set_texture_flags(int flags); + INLINE int get_texture_flags() const; + void output(ostream &out) const; private: void write_flag(ostream &out, string &sep, const string &flag_name, int flag) const; + void write_texture_flag(ostream &out, string &sep, + const string &flag_name, int flag) const; int _flags; + int _texture_flags; }; INLINE ostream &operator << (ostream &out, const LoaderOptions &opts) { diff --git a/panda/src/putil/putil_composite2.cxx b/panda/src/putil/putil_composite2.cxx index 8c506f3ef3..f165e5f5b0 100644 --- a/panda/src/putil/putil_composite2.cxx +++ b/panda/src/putil/putil_composite2.cxx @@ -3,6 +3,7 @@ #include "lineStreamBuf.cxx" #include "linkedListNode.cxx" #include "load_prc_file.cxx" +#include "loaderOptions.cxx" #include "modifierButtons.cxx" #include "mouseButton.cxx" #include "mouseData.cxx" diff --git a/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx b/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx index fa2d9c3e47..3f16665d54 100644 --- a/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx +++ b/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx @@ -2114,7 +2114,7 @@ upload_texture(TinyTextureContext *gtc) { gtc->update_data_size_bytes(bytecount); - tex->texture_uploaded(); + tex->texture_uploaded(this); gtc->mark_loaded(); return true;