diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2022-02-24 23:40:16 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2022-02-25 00:51:19 +0300 |
commit | e59f754c169d855110296a365d93c33e82333385 (patch) | |
tree | e42f9ad35ae0fbd4edf87e8d5d5f1eac2b46a3af /source/blender/gpu/opengl | |
parent | c23ee6d7b4d6665aed4d0440153f0b1e80b77c8b (diff) |
GPUTexture: Use immutable storage
This means textures need to have the number of mipmap levels specified
upfront. It does not mean the data is immutable.
There is fallback code for OpenGL < 4.2.
Immutable storage will enables texture views in the future.
Diffstat (limited to 'source/blender/gpu/opengl')
-rw-r--r-- | source/blender/gpu/opengl/gl_backend.cc | 3 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_context.hh | 1 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_texture.cc | 140 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_texture.hh | 2 |
4 files changed, 77 insertions, 69 deletions
diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc index 7a1674a5f01..302d8249914 100644 --- a/source/blender/gpu/opengl/gl_backend.cc +++ b/source/blender/gpu/opengl/gl_backend.cc @@ -240,6 +240,7 @@ static void detect_workarounds() GLContext::texture_cube_map_array_support = false; GLContext::texture_filter_anisotropic_support = false; GLContext::texture_gather_support = false; + GLContext::texture_storage_support = false; GLContext::vertex_attrib_binding_support = false; return; } @@ -439,6 +440,7 @@ bool GLContext::shader_draw_parameters_support = false; bool GLContext::texture_cube_map_array_support = false; bool GLContext::texture_filter_anisotropic_support = false; bool GLContext::texture_gather_support = false; +bool GLContext::texture_storage_support = false; bool GLContext::vertex_attrib_binding_support = false; /** Workarounds. */ @@ -501,6 +503,7 @@ void GLBackend::capabilities_init() GLContext::texture_cube_map_array_support = GLEW_ARB_texture_cube_map_array; GLContext::texture_filter_anisotropic_support = GLEW_EXT_texture_filter_anisotropic; GLContext::texture_gather_support = GLEW_ARB_texture_gather; + GLContext::texture_storage_support = GLEW_VERSION_4_3; GLContext::vertex_attrib_binding_support = GLEW_ARB_vertex_attrib_binding; detect_workarounds(); diff --git a/source/blender/gpu/opengl/gl_context.hh b/source/blender/gpu/opengl/gl_context.hh index fe2ad0a4747..369b667cbcc 100644 --- a/source/blender/gpu/opengl/gl_context.hh +++ b/source/blender/gpu/opengl/gl_context.hh @@ -64,6 +64,7 @@ class GLContext : public Context { static bool texture_cube_map_array_support; static bool texture_filter_anisotropic_support; static bool texture_gather_support; + static bool texture_storage_support; static bool vertex_attrib_binding_support; /** Workarounds. */ diff --git a/source/blender/gpu/opengl/gl_texture.cc b/source/blender/gpu/opengl/gl_texture.cc index 22af2dd463f..37bf2f6b8b3 100644 --- a/source/blender/gpu/opengl/gl_texture.cc +++ b/source/blender/gpu/opengl/gl_texture.cc @@ -69,9 +69,79 @@ bool GLTexture::init_internal() return false; } - this->ensure_mipmaps(0); + GLenum internal_format = to_gl_internal_format(format_); + const bool is_cubemap = bool(type_ == GPU_TEXTURE_CUBE); + const bool is_layered = bool(type_ & GPU_TEXTURE_ARRAY); + const bool is_compressed = bool(format_flag_ & GPU_TEXTURE_ARRAY); + const int dimensions = (is_cubemap) ? 2 : this->dimensions_count(); + GLenum gl_format = to_gl_data_format(format_); + GLenum gl_type = to_gl(to_data_format(format_)); - /* Avoid issue with incomplete textures. */ + auto mip_size = [&](int h, int w = 1, int d = 1) -> size_t { + return divide_ceil_u(w, 4) * divide_ceil_u(h, 4) * divide_ceil_u(d, 4) * + to_block_size(format_); + }; + switch (dimensions) { + default: + case 1: + if (GLContext::texture_storage_support) { + glTexStorage1D(target_, mipmaps_, internal_format, w_); + } + else { + for (int i = 0, w = w_; i < mipmaps_; i++) { + if (is_compressed) { + glCompressedTexImage1D(target_, i, internal_format, w, 0, mip_size(w), nullptr); + } + else { + glTexImage1D(target_, i, internal_format, w, 0, gl_format, gl_type, nullptr); + } + w = max_ii(1, (w / 2)); + } + } + break; + case 2: + if (GLContext::texture_storage_support) { + glTexStorage2D(target_, mipmaps_, internal_format, w_, h_); + } + else { + for (int i = 0, w = w_, h = h_; i < mipmaps_; i++) { + for (int f = 0; f < (is_cubemap ? 6 : 1); f++) { + GLenum target = (is_cubemap) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + f : target_; + if (is_compressed) { + glCompressedTexImage2D(target, i, internal_format, w, h, 0, mip_size(w, h), nullptr); + } + else { + glTexImage2D(target, i, internal_format, w, h, 0, gl_format, gl_type, nullptr); + } + } + w = max_ii(1, (w / 2)); + h = is_layered ? h_ : max_ii(1, (h / 2)); + } + } + break; + case 3: + if (GLContext::texture_storage_support) { + glTexStorage3D(target_, mipmaps_, internal_format, w_, h_, d_); + } + else { + for (int i = 0, w = w_, h = h_, d = d_; i < mipmaps_; i++) { + if (is_compressed) { + glCompressedTexImage3D( + target_, i, internal_format, w, h, d, 0, mip_size(w, h, d), nullptr); + } + else { + glTexImage3D(target_, i, internal_format, w, h, d, 0, gl_format, gl_type, nullptr); + } + w = max_ii(1, (w / 2)); + h = max_ii(1, (h / 2)); + d = is_layered ? d_ : max_ii(1, (d / 2)); + } + } + break; + } + this->mip_range_set(0, mipmaps_ - 1); + + /* Avoid issue with formats not supporting filtering. Nearest by default. */ if (GLContext::direct_state_access_support) { glTextureParameteri(tex_id_, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } @@ -105,67 +175,6 @@ bool GLTexture::init_internal(GPUVertBuf *vbo) return true; } -void GLTexture::ensure_mipmaps(int miplvl) -{ - int effective_h = (type_ == GPU_TEXTURE_1D_ARRAY) ? 0 : h_; - int effective_d = (type_ != GPU_TEXTURE_3D) ? 0 : d_; - int max_dimension = max_iii(w_, effective_h, effective_d); - int max_miplvl = floor(log2(max_dimension)); - miplvl = min_ii(miplvl, max_miplvl); - - while (mipmaps_ < miplvl) { - int mip = ++mipmaps_; - const int dimensions = this->dimensions_count(); - - int w = mip_width_get(mip); - int h = mip_height_get(mip); - int d = mip_depth_get(mip); - GLenum internal_format = to_gl_internal_format(format_); - GLenum gl_format = to_gl_data_format(format_); - GLenum gl_type = to_gl(to_data_format(format_)); - - GLContext::state_manager_active_get()->texture_bind_temp(this); - - if (type_ == GPU_TEXTURE_CUBE) { - for (int i = 0; i < d; i++) { - GLenum target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i; - glTexImage2D(target, mip, internal_format, w, h, 0, gl_format, gl_type, nullptr); - } - } - else if (format_flag_ & GPU_FORMAT_COMPRESSED) { - size_t size = ((w + 3) / 4) * ((h + 3) / 4) * to_block_size(format_); - switch (dimensions) { - default: - case 1: - glCompressedTexImage1D(target_, mip, internal_format, w, 0, size, nullptr); - break; - case 2: - glCompressedTexImage2D(target_, mip, internal_format, w, h, 0, size, nullptr); - break; - case 3: - glCompressedTexImage3D(target_, mip, internal_format, w, h, d, 0, size, nullptr); - break; - } - } - else { - switch (dimensions) { - default: - case 1: - glTexImage1D(target_, mip, internal_format, w, 0, gl_format, gl_type, nullptr); - break; - case 2: - glTexImage2D(target_, mip, internal_format, w, h, 0, gl_format, gl_type, nullptr); - break; - case 3: - glTexImage3D(target_, mip, internal_format, w, h, d, 0, gl_format, gl_type, nullptr); - break; - } - } - } - - this->mip_range_set(0, mipmaps_); -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -216,9 +225,7 @@ void GLTexture::update_sub( BLI_assert(validate_data_format(format_, type)); BLI_assert(data != nullptr); - this->ensure_mipmaps(mip); - - if (mip > mipmaps_) { + if (mip >= mipmaps_) { debug::raise_gl_error("Updating a miplvl on a texture too small to have this many levels."); return; } @@ -283,7 +290,6 @@ void GLTexture::update_sub( */ void GLTexture::generate_mipmap() { - this->ensure_mipmaps(9999); /* Some drivers have bugs when using #glGenerateMipmap with depth textures (see T56789). * In this case we just create a complete texture with mipmaps manually without * down-sampling. You must initialize the texture levels using other methods like diff --git a/source/blender/gpu/opengl/gl_texture.hh b/source/blender/gpu/opengl/gl_texture.hh index 07d3bb8c946..9e128da90e8 100644 --- a/source/blender/gpu/opengl/gl_texture.hh +++ b/source/blender/gpu/opengl/gl_texture.hh @@ -77,8 +77,6 @@ class GLTexture : public Texture { private: bool proxy_check(int mip); - /** Will create enough mipmaps up to get to the given level. */ - void ensure_mipmaps(int mip); void update_sub_direct_state_access( int mip, int offset[3], int extent[3], GLenum gl_format, GLenum gl_type, const void *data); GPUFrameBuffer *framebuffer_get(); |