diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index e357b2c357..9a0a588cdf 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -7586,14 +7586,120 @@ upload_texture_image(CLP(TextureContext) *gtc, int highest_level = 0; + bool needs_reload = false; if (!gtc->_already_applied || gtc->_uses_mipmaps != uses_mipmaps || gtc->_internal_format != internal_format || gtc->_width != width || gtc->_height != height || gtc->_depth != depth) { - // We need to reload a new image. + // We need to reload a new GL Texture object. + needs_reload = true; + } + if (!needs_reload) { + // Try to subload the image over the existing GL Texture object, + // possibly saving on texture memory fragmentation. + + if (GLCAT.is_debug()) { + GLCAT.debug() + << "subloading existing texture object, " << width << " x " << height + << " x " << depth << ", mipmaps " << num_ram_mipmap_levels + << ", uses_mipmaps = " << uses_mipmaps << "\n"; + } + + for (int n = mipmap_bias; n < num_ram_mipmap_levels; ++n) { + const unsigned char *image_ptr = tex->get_ram_mipmap_image(n); + if (image_ptr == (const unsigned char *)NULL) { + GLCAT.warning() + << "No mipmap level " << n << " defined for " << tex->get_name() + << "\n"; + // No mipmap level n; stop here. + break; + } + + size_t image_size = tex->get_ram_mipmap_image_size(n); + if (one_page_only) { + image_size = tex->get_ram_mipmap_page_size(n); + image_ptr += image_size * z; + } + + PTA_uchar bgr_image; + if (!_supports_bgr && image_compression == Texture::CM_off) { + // If the GL doesn't claim to support BGR, we may have to reverse + // the component ordering of the image. + image_ptr = fix_component_ordering(bgr_image, image_ptr, image_size, + external_format, tex); + } + + int width = tex->get_expected_mipmap_x_size(n); + int height = tex->get_expected_mipmap_y_size(n); + int depth = tex->get_expected_mipmap_z_size(n); + +#ifdef DO_PSTATS + _data_transferred_pcollector.add_level(image_size); +#endif + switch (texture_target) { + case GL_TEXTURE_1D: + if (image_compression == Texture::CM_off) { + GLP(TexSubImage1D)(page_target, n - mipmap_bias, 0, width, + external_format, component_type, image_ptr); + } else { + _glCompressedTexSubImage1D(page_target, n - mipmap_bias, 0, width, + external_format, image_size, image_ptr); + } + break; + + case GL_TEXTURE_3D: + if (_supports_3d_texture) { + if (image_compression == Texture::CM_off) { + _glTexSubImage3D(page_target, n - mipmap_bias, 0, 0, 0, width, height, depth, + external_format, component_type, image_ptr); + } else { + _glCompressedTexSubImage3D(page_target, n - mipmap_bias, 0, 0, 0, width, height, depth, + external_format, image_size, image_ptr); + } + } else { + report_my_gl_errors(); + return false; + } + break; + + default: + if (image_compression == Texture::CM_off) { + if (n==0) { + // It's unfortunate that we can't adjust the width, too, + // but TexSubImage2D doesn't accept a row-stride parameter. + height = tex->get_y_size() - tex->get_pad_y_size(); + } + GLP(TexSubImage2D)(page_target, n - mipmap_bias, 0, 0, width, height, + external_format, component_type, image_ptr); + } else { + _glCompressedTexSubImage2D(page_target, n - mipmap_bias, 0, 0, width, height, + external_format, image_size, image_ptr); + } + break; + } + + highest_level = n; + } + + // Did that fail? If it did, we'll immediately try again, this + // time loading the texture from scratch. + GLenum error_code = GLP(GetError)(); + if (error_code != GL_NO_ERROR) { + if (GLCAT.is_debug()) { + GLCAT.debug() + << "GL texture subload failed for " << tex->get_name() + << " : " << get_error_string(error_code) << "\n"; + } + needs_reload = true; + } + } + + if (needs_reload) { + // Load the image up from scratch, creating a new GL Texture + // object. if (GLCAT.is_debug()) { GLCAT.debug() << "loading new texture object, " << width << " x " << height @@ -7689,91 +7795,17 @@ upload_texture_image(CLP(TextureContext) *gtc, highest_level = n; } - } else { - // We can reload the image over the previous image, possibly - // saving on texture memory fragmentation. - if (GLCAT.is_debug()) { - GLCAT.debug() - << "subloading existing texture object, " << width << " x " << height - << " x " << depth << ", mipmaps " << num_ram_mipmap_levels - << ", uses_mipmaps = " << uses_mipmaps << "\n"; - } - - for (int n = mipmap_bias; n < num_ram_mipmap_levels; ++n) { - const unsigned char *image_ptr = tex->get_ram_mipmap_image(n); - if (image_ptr == (const unsigned char *)NULL) { - GLCAT.warning() - << "No mipmap level " << n << " defined for " << tex->get_name() - << "\n"; - // No mipmap level n; stop here. - break; - } - - size_t image_size = tex->get_ram_mipmap_image_size(n); - if (one_page_only) { - image_size = tex->get_ram_mipmap_page_size(n); - image_ptr += image_size * z; - } - - PTA_uchar bgr_image; - if (!_supports_bgr && image_compression == Texture::CM_off) { - // If the GL doesn't claim to support BGR, we may have to reverse - // the component ordering of the image. - image_ptr = fix_component_ordering(bgr_image, image_ptr, image_size, - external_format, tex); - } - - int width = tex->get_expected_mipmap_x_size(n); - int height = tex->get_expected_mipmap_y_size(n); - int depth = tex->get_expected_mipmap_z_size(n); - -#ifdef DO_PSTATS - _data_transferred_pcollector.add_level(image_size); -#endif - switch (texture_target) { - case GL_TEXTURE_1D: - if (image_compression == Texture::CM_off) { - GLP(TexSubImage1D)(page_target, n - mipmap_bias, 0, width, - external_format, component_type, image_ptr); - } else { - _glCompressedTexSubImage1D(page_target, n - mipmap_bias, 0, width, - external_format, image_size, image_ptr); - } - break; - - case GL_TEXTURE_3D: - if (_supports_3d_texture) { - if (image_compression == Texture::CM_off) { - _glTexSubImage3D(page_target, n - mipmap_bias, 0, 0, 0, width, height, depth, - external_format, component_type, image_ptr); - } else { - _glCompressedTexSubImage3D(page_target, n - mipmap_bias, 0, 0, 0, width, height, depth, - external_format, image_size, image_ptr); - } - } else { - report_my_gl_errors(); - return false; - } - break; - - default: - if (image_compression == Texture::CM_off) { - if (n==0) { - // It's unfortunate that we can't adjust the width, too, - // but TexSubImage2D doesn't accept a row-stride parameter. - height = tex->get_y_size() - tex->get_pad_y_size(); - } - GLP(TexSubImage2D)(page_target, n - mipmap_bias, 0, 0, width, height, - external_format, component_type, image_ptr); - } else { - _glCompressedTexSubImage2D(page_target, n - mipmap_bias, 0, 0, width, height, - external_format, image_size, image_ptr); - } - break; - } - - highest_level = n; + // Report the error message explicitly if the GL texture creation + // failed. + GLenum error_code = GLP(GetError)(); + if (error_code != GL_NO_ERROR) { + GLCAT.error() + << "GL texture creation failed for " << tex->get_name() + << " : " << get_error_string(error_code) << "\n"; + + gtc->_already_applied = false; + return false; } } @@ -7793,16 +7825,7 @@ upload_texture_image(CLP(TextureContext) *gtc, } } - // Report the error message explicitly if the GL texture creation - // failed. - GLenum error_code = GLP(GetError)(); - if (error_code != GL_NO_ERROR) { - GLCAT.error() - << "GL texture creation failed for " << tex->get_name() - << " : " << get_error_string(error_code) << "\n"; - - return false; - } + report_my_gl_errors(); return true; } diff --git a/panda/src/gobj/texture.cxx b/panda/src/gobj/texture.cxx index c128494399..fafafecb6c 100644 --- a/panda/src/gobj/texture.cxx +++ b/panda/src/gobj/texture.cxx @@ -705,7 +705,12 @@ reload() { if (_loaded_from_image && !_fullpath.empty()) { do_clear_ram_image(); do_unlock_and_reload_ram_image(true); - return do_has_ram_image(); + if (do_has_ram_image()) { + // An explicit call to reload() should increment image_modified. + ++_image_modified; + return true; + } + return false; } // We don't have a filename to load from. @@ -2918,16 +2923,38 @@ do_unlock_and_reload_ram_image(bool allow_compression) { // properties have changed during the reload (for instance, // because we reloaded a txo), it won't contaminate the original // texture. - _x_size = tex->_x_size; - _y_size = tex->_y_size; - _z_size = tex->_z_size; _orig_file_x_size = tex->_orig_file_x_size; _orig_file_y_size = tex->_orig_file_y_size; - _num_components = tex->_num_components; - _component_width = tex->_component_width; - _texture_type = tex->_texture_type; - _format = tex->_format; - _component_type = tex->_component_type; + + // If any of *these* properties have changed, the texture has + // changed in some fundamental way. Update it appropriately. + if (tex->_x_size != _x_size || + tex->_y_size != _y_size || + tex->_z_size != _z_size || + tex->_num_components != _num_components || + tex->_component_width != _component_width || + tex->_texture_type != _texture_type || + tex->_format != _format || + tex->_component_type != _component_type) { + + _x_size = tex->_x_size; + _y_size = tex->_y_size; + _z_size = tex->_z_size; + + _num_components = tex->_num_components; + _component_width = tex->_component_width; + _texture_type = tex->_texture_type; + _format = tex->_format; + _component_type = tex->_component_type; + + // Normally, we don't update the _modified semaphores in a + // do_blah method, but we'll make an exception in this case, + // because it's easiest to modify this here, and only when we + // know it's needed. + ++_properties_modified; + ++_image_modified; + } + _keep_ram_image = tex->_keep_ram_image; _ram_image_compression = tex->_ram_image_compression; _ram_images = tex->_ram_images; @@ -2935,13 +2962,10 @@ do_unlock_and_reload_ram_image(bool allow_compression) { nassertv(_reloading); _reloading = false; - // Normally, we don't update the _modified semaphores in a do_blah - // method, but we'll make an exception in this case, because it's - // easiest to modify these here, and only when we know it's - // needed. - ++_image_modified; - ++_properties_modified; - + // We don't generally increment the _image_modified semaphore, + // because this is just a reload, and presumably the image hasn't + // changed (unless we hit the if condition above). + _cvar.notify_all(); } } @@ -4022,9 +4046,9 @@ get_ram_image_as(const string &requested_format) { nassertr(_num_components != 3, CPTA_uchar(get_class_type())); component = _num_components - 1; } else if (format.at(s) == '0') { - newdata[p * format.size() + s] = 0; + newdata[p * format.size() + s] = 0x00; } else if (format.at(s) == '1') { - newdata[p * format.size() + s] = -1; + newdata[p * format.size() + s] = 0xff; } else { gobj_cat.error() << "Unexpected component character '" << format.at(s) << "', expected one of RGBA!\n";