diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 9afeab89e5..5f5f90abc1 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -1084,10 +1084,12 @@ reset() { if (is_at_least_gl_version(4, 4) || has_extension("GL_ARB_clear_texture")) { _glClearTexImage = (PFNGLCLEARTEXIMAGEPROC) get_extension_func("glClearTexImage"); + _glClearTexSubImage = (PFNGLCLEARTEXSUBIMAGEPROC) + get_extension_func("glClearTexSubImage"); - if (_glClearTexImage == nullptr) { + if (_glClearTexImage == nullptr || _glClearTexSubImage == nullptr) { GLCAT.warning() - << "GL_ARB_clear_texture advertised as supported by OpenGL runtime, but could not get pointers to extension function.\n"; + << "GL_ARB_clear_texture advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n"; } else { _supports_clear_texture = true; } @@ -13458,59 +13460,9 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) { } } - bool success = true; - if (texture_type == Texture::TT_cube_map) { - // A cube map must load six different 2-d images (which are stored as the - // six pages of the system ram image). - if (!_supports_cube_map) { - report_my_gl_errors(); - return false; - } - nassertr(target == GL_TEXTURE_CUBE_MAP, false); - - success = success && upload_texture_image - (gtc, needs_reload, uses_mipmaps, mipmap_bias, - GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_POSITIVE_X, - internal_format, external_format, component_type, - true, 0, image_compression); - - success = success && upload_texture_image - (gtc, needs_reload, uses_mipmaps, mipmap_bias, - GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, - internal_format, external_format, component_type, - true, 1, image_compression); - - success = success && upload_texture_image - (gtc, needs_reload, uses_mipmaps, mipmap_bias, - GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, - internal_format, external_format, component_type, - true, 2, image_compression); - - success = success && upload_texture_image - (gtc, needs_reload, uses_mipmaps, mipmap_bias, - GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, - internal_format, external_format, component_type, - true, 3, image_compression); - - success = success && upload_texture_image - (gtc, needs_reload, uses_mipmaps, mipmap_bias, - GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, - internal_format, external_format, component_type, - true, 4, image_compression); - - success = success && upload_texture_image - (gtc, needs_reload, uses_mipmaps, mipmap_bias, - GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, - internal_format, external_format, component_type, - true, 5, image_compression); - - } else { - // Any other kind of texture can be loaded all at once. - success = upload_texture_image - (gtc, needs_reload, uses_mipmaps, mipmap_bias, target, - target, internal_format, external_format, - component_type, false, 0, image_compression); - } + bool success = upload_texture_image + (gtc, needs_reload, uses_mipmaps, mipmap_bias, target, + internal_format, external_format, component_type, image_compression); if (gtc->_generate_mipmaps && _glGenerateMipmap != nullptr && !image.is_null()) { @@ -13571,21 +13523,13 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) { /** * Loads a texture image, or one page of a cube map image, from system RAM to * texture memory. - * - * texture_target is normally the same thing as page_target; both represent - * the GL target onto which the texture image is loaded, e.g. GL_TEXTURE_1D, - * GL_TEXTURE_2D, etc. The only time they may differ is in the case of cube - * mapping, in which case texture_target will be target for the overall - * texture, e.g. GL_TEXTURE_CUBE_MAP, and page_target will be the target for - * this particular page, e.g. GL_TEXTURE_CUBE_MAP_POSITIVE_X. */ bool CLP(GraphicsStateGuardian):: upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload, bool uses_mipmaps, int mipmap_bias, - GLenum texture_target, GLenum page_target, + GLenum texture_target, GLint internal_format, GLint external_format, GLenum component_type, - bool one_page_only, int z, Texture::CompressionMode image_compression) { // Make sure the error stack is cleared out before we begin. clear_my_gl_errors(); @@ -13635,29 +13579,32 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload, // saving on texture memory fragmentation. if (GLCAT.is_debug()) { + SparseArray pages = gtc->get_image_modified_pages(0); if (num_ram_mipmap_levels == 0) { if (tex->has_clear_color()) { GLCAT.debug() << "clearing texture " << tex->get_name() << ", " - << width << " x " << height << " x " << depth << ", z = " << z + << width << " x " << height << " x " << depth << ", pages " << pages << ", uses_mipmaps = " << uses_mipmaps << ", clear_color = " << tex->get_clear_color() << "\n"; } else { GLCAT.debug() << "not loading NULL image for texture " << tex->get_name() << ", " << width << " x " << height << " x " << depth - << ", z = " << z << ", uses_mipmaps = " << uses_mipmaps << "\n"; + << ", pages " << pages << ", uses_mipmaps = " << uses_mipmaps << "\n"; } } else { GLCAT.debug() << "updating image data of texture " << tex->get_name() << ", " << width << " x " << height << " x " << depth - << ", z = " << z << ", mipmaps " << num_ram_mipmap_levels + << ", pages " << pages << ", mipmaps " << num_ram_mipmap_levels << ", uses_mipmaps = " << uses_mipmaps << "\n"; } } for (int n = mipmap_bias; n < num_levels; ++n) { + SparseArray pages = gtc->get_image_modified_pages(n); + // we grab the mipmap pointer first, if it is NULL we grab the normal // mipmap image pointer which is a PTA_uchar const unsigned char *image_ptr = (unsigned char*)tex->get_ram_mipmap_pointer(n); @@ -13684,8 +13631,17 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload, // function. vector_uchar clear_data = tex->get_clear_data(); - _glClearTexImage(gtc->_index, n - mipmap_bias, external_format, - component_type, (void *)&clear_data[0]); + if (pages.has_all_of(0, depth)) { + _glClearTexImage(gtc->_index, n - mipmap_bias, external_format, + component_type, (void *)&clear_data[0]); + } + else for (size_t sri = 0; sri < pages.get_num_subranges(); ++sri) { + int begin = pages.get_subrange_begin(sri); + int num_pages = pages.get_subrange_end(sri) - begin; + _glClearTexSubImage(gtc->_index, n - mipmap_bias, 0, 0, begin, + width, height, num_pages, external_format, + component_type, (void *)&clear_data[0]); + } continue; } } else { @@ -13714,14 +13670,11 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload, } PTA_uchar bgr_image; - size_t view_size = tex->get_ram_mipmap_view_size(n); + size_t page_size = tex->get_ram_mipmap_page_size(n); if (image_ptr != nullptr) { const unsigned char *orig_image_ptr = image_ptr; + size_t view_size = tex->get_ram_mipmap_view_size(n); image_ptr += view_size * gtc->get_view(); - if (one_page_only) { - view_size = tex->get_ram_mipmap_page_size(n); - image_ptr += view_size * z; - } nassertr(image_ptr >= orig_image_ptr && image_ptr + view_size <= orig_image_ptr + tex->get_ram_mipmap_image_size(n), false); if (image_compression == Texture::CM_off) { @@ -13734,23 +13687,29 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload, int width = tex->get_expected_mipmap_x_size(n); int height = tex->get_expected_mipmap_y_size(n); -#ifndef OPENGLES_1 - int depth = tex->get_expected_mipmap_z_size(n); -#endif #ifdef DO_PSTATS - _data_transferred_pcollector.add_level(view_size); + _data_transferred_pcollector.add_level(page_size * pages.get_num_on_bits()); #endif switch (texture_target) { #ifndef OPENGLES_1 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, view_size, image_ptr); + for (size_t sri = 0; sri < pages.get_num_subranges(); ++sri) { + int begin = pages.get_subrange_begin(sri); + int num_pages = pages.get_subrange_end(sri) - begin; + const unsigned char *page_ptr = image_ptr + page_size * begin; + + if (image_compression == Texture::CM_off) { + _glTexSubImage3D(texture_target, n - mipmap_bias, + 0, 0, begin, width, height, num_pages, + external_format, component_type, page_ptr); + } else { + _glCompressedTexSubImage3D(texture_target, n - mipmap_bias, + 0, 0, begin, width, height, num_pages, + external_format, + page_size * num_pages, page_ptr); + } } } else { report_my_gl_errors(); @@ -13762,11 +13721,11 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload, #ifndef OPENGLES case GL_TEXTURE_1D: if (image_compression == Texture::CM_off) { - glTexSubImage1D(page_target, n - mipmap_bias, 0, width, + glTexSubImage1D(texture_target, n - mipmap_bias, 0, width, external_format, component_type, image_ptr); } else { - _glCompressedTexSubImage1D(page_target, n - mipmap_bias, 0, width, - external_format, view_size, image_ptr); + _glCompressedTexSubImage1D(texture_target, n - mipmap_bias, 0, width, + external_format, page_size, image_ptr); } break; #endif // OPENGLES @@ -13775,12 +13734,21 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload, case GL_TEXTURE_2D_ARRAY: case GL_TEXTURE_CUBE_MAP_ARRAY: if (_supports_2d_texture_array) { - 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, view_size, image_ptr); + for (size_t sri = 0; sri < pages.get_num_subranges(); ++sri) { + int begin = pages.get_subrange_begin(sri); + int num_pages = pages.get_subrange_end(sri) - begin; + const unsigned char *page_ptr = image_ptr + page_size * begin; + + if (image_compression == Texture::CM_off) { + _glTexSubImage3D(texture_target, n - mipmap_bias, + 0, 0, begin, width, height, num_pages, + external_format, component_type, page_ptr); + } else { + _glCompressedTexSubImage3D(texture_target, n - mipmap_bias, + 0, 0, begin, width, height, num_pages, + external_format, + page_size * num_pages, page_ptr); + } } } else { report_my_gl_errors(); @@ -13792,7 +13760,7 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload, #ifndef OPENGLES case GL_TEXTURE_BUFFER: if (_supports_buffer_texture) { - _glBufferSubData(GL_TEXTURE_BUFFER, 0, view_size, image_ptr); + _glBufferSubData(GL_TEXTURE_BUFFER, 0, page_size, image_ptr); } else { report_my_gl_errors(); return false; @@ -13800,18 +13768,46 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload, break; #endif // OPENGLES + case GL_TEXTURE_CUBE_MAP: + if (_supports_cube_map) { + // This is the only texture type that must be specified using separate + // per-page calls. + if (n == 0) { + height = tex->get_y_size() - tex->get_pad_y_size(); + } + for (int z = 0; z < 6; ++z) { + if (pages.get_bit(z)) { + GLenum page_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + z; + const unsigned char *page_ptr = image_ptr + page_size * z; + + if (image_compression == Texture::CM_off) { + glTexSubImage2D(page_target, n - mipmap_bias, 0, 0, width, height, + external_format, component_type, page_ptr); + } else { + _glCompressedTexSubImage2D(page_target, n - mipmap_bias, + 0, 0, width, height, + external_format, page_size, page_ptr); + } + } + } + } else { + report_my_gl_errors(); + return false; + } + break; + default: if (image_compression == Texture::CM_off) { - if (n==0) { + 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(); } - glTexSubImage2D(page_target, n - mipmap_bias, 0, 0, width, height, + glTexSubImage2D(texture_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, view_size, image_ptr); + _glCompressedTexSubImage2D(texture_target, n - mipmap_bias, 0, 0, width, height, + external_format, page_size, image_ptr); } break; } @@ -13835,7 +13831,7 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload, if (GLCAT.is_debug()) { GLCAT.debug() << "loading new texture object for " << tex->get_name() << ", " << width - << " x " << height << " x " << depth << ", z = " << z << ", mipmaps " + << " x " << height << " x " << depth << ", mipmaps " << num_ram_mipmap_levels << ", uses_mipmaps = " << uses_mipmaps << "\n"; } @@ -13900,10 +13896,6 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload, if (image_ptr != nullptr) { const unsigned char *orig_image_ptr = image_ptr; image_ptr += view_size * gtc->get_view(); - if (one_page_only) { - view_size = tex->get_ram_mipmap_page_size(n); - image_ptr += view_size * z; - } nassertr(image_ptr >= orig_image_ptr && image_ptr + view_size <= orig_image_ptr + tex->get_ram_mipmap_image_size(n), false); if (image_compression == Texture::CM_off) { @@ -13927,12 +13919,11 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload, #ifndef OPENGLES // 1-d textures not supported by OpenGL ES. Fall through. case GL_TEXTURE_1D: if (image_compression == Texture::CM_off) { - glTexImage1D(page_target, n - mipmap_bias, internal_format, - width, 0, - external_format, component_type, image_ptr); + glTexImage1D(texture_target, n - mipmap_bias, internal_format, + width, 0, external_format, component_type, image_ptr); } else { - _glCompressedTexImage1D(page_target, n - mipmap_bias, external_format, width, - 0, view_size, image_ptr); + _glCompressedTexImage1D(texture_target, n - mipmap_bias, external_format, + width, 0, view_size, image_ptr); } break; #endif // OPENGLES // OpenGL ES will fall through. @@ -13941,13 +13932,12 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload, case GL_TEXTURE_3D: if (_supports_3d_texture) { if (image_compression == Texture::CM_off) { - _glTexImage3D(page_target, n - mipmap_bias, internal_format, + _glTexImage3D(texture_target, n - mipmap_bias, internal_format, width, height, depth, 0, external_format, component_type, image_ptr); } else { - _glCompressedTexImage3D(page_target, n - mipmap_bias, external_format, width, - height, depth, - 0, view_size, image_ptr); + _glCompressedTexImage3D(texture_target, n - mipmap_bias, external_format, + width, height, depth, 0, view_size, image_ptr); } } else { report_my_gl_errors(); @@ -13961,13 +13951,12 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload, case GL_TEXTURE_CUBE_MAP_ARRAY: if (_supports_2d_texture_array) { if (image_compression == Texture::CM_off) { - _glTexImage3D(page_target, n - mipmap_bias, internal_format, + _glTexImage3D(texture_target, n - mipmap_bias, internal_format, width, height, depth, 0, external_format, component_type, image_ptr); } else { - _glCompressedTexImage3D(page_target, n - mipmap_bias, external_format, width, - height, depth, - 0, view_size, image_ptr); + _glCompressedTexImage3D(texture_target, n - mipmap_bias, external_format, + width, height, depth, 0, view_size, image_ptr); } } else { report_my_gl_errors(); @@ -13988,13 +13977,37 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload, break; #endif // OPENGLES + case GL_TEXTURE_CUBE_MAP: + if (_supports_cube_map) { + // This is the only texture type that must be specified using separate + // per-page calls. + size_t page_size = tex->get_ram_mipmap_page_size(n); + for (int z = 0; z < 6; ++z) { + GLenum page_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + z; + const unsigned char *page_ptr = image_ptr + page_size * z; + + if (image_compression == Texture::CM_off) { + glTexImage2D(page_target, n - mipmap_bias, internal_format, + width, height, 0, + external_format, component_type, page_ptr); + } else { + _glCompressedTexImage2D(page_target, n - mipmap_bias, external_format, + width, height, 0, page_size, page_ptr); + } + } + } else { + report_my_gl_errors(); + return false; + } + break; + default: if (image_compression == Texture::CM_off) { - glTexImage2D(page_target, n - mipmap_bias, internal_format, + glTexImage2D(texture_target, n - mipmap_bias, internal_format, width, height, 0, external_format, component_type, image_ptr); } else { - _glCompressedTexImage2D(page_target, n - mipmap_bias, external_format, + _glCompressedTexImage2D(texture_target, n - mipmap_bias, external_format, width, height, 0, view_size, image_ptr); } } diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index 7f0814041c..b7aa02c08e 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.h @@ -616,10 +616,9 @@ protected: bool upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps); bool upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload, bool uses_mipmaps, int mipmap_bias, - GLenum texture_target, GLenum page_target, + GLenum texture_target, GLint internal_format, GLint external_format, GLenum component_type, - bool one_page_only, int z, Texture::CompressionMode image_compression); void generate_mipmaps(CLP(TextureContext) *gtc); bool upload_simple_texture(CLP(TextureContext) *gtc); @@ -808,6 +807,7 @@ public: bool _supports_clear_texture; #ifndef OPENGLES PFNGLCLEARTEXIMAGEPROC _glClearTexImage; + PFNGLCLEARTEXSUBIMAGEPROC _glClearTexSubImage; #endif bool _supports_clear_buffer;