From 7d7dd66ba78fc97795edeb7c1a0221e4bb676c85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Thu, 24 Feb 2022 22:45:00 +0100 Subject: GPUTexture: Add support for texture view This is an OpenGL 4.3 feature that enables creating a texture using a range of the same data as another texture. --- source/blender/gpu/GPU_texture.h | 13 ++++++ source/blender/gpu/intern/gpu_texture.cc | 51 ++++++++++++++++++++++++ source/blender/gpu/intern/gpu_texture_private.hh | 7 ++++ source/blender/gpu/opengl/gl_texture.cc | 22 ++++++++++ source/blender/gpu/opengl/gl_texture.hh | 2 + 5 files changed, 95 insertions(+) diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index d689fbe14b5..734d407d011 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -226,6 +226,19 @@ GPUTexture *GPU_texture_create_compressed_2d( * Create an error texture that will bind an invalid texture (pink) at draw time. */ GPUTexture *GPU_texture_create_error(int dimension, bool array); +/** + * Create an alias of the source texture data. + * If \a src is freed, the texture view will continue to be valid. + * If \a mip_start or \a mip_len is bigger than available mips they will be clamped. + * TODO(@fclem): Target conversion is not implemented yet. + */ +GPUTexture *GPU_texture_create_view(const char *name, + const GPUTexture *src, + eGPUTextureFormat format, + int mip_start, + int mip_len, + int layer_start, + int layer_len); void GPU_texture_update_mipmap(GPUTexture *tex, int miplvl, diff --git a/source/blender/gpu/intern/gpu_texture.cc b/source/blender/gpu/intern/gpu_texture.cc index 507ad47e36a..9e6a6f75391 100644 --- a/source/blender/gpu/intern/gpu_texture.cc +++ b/source/blender/gpu/intern/gpu_texture.cc @@ -131,6 +131,42 @@ bool Texture::init_buffer(GPUVertBuf *vbo, eGPUTextureFormat format) return this->init_internal(vbo); } +bool Texture::init_view(const GPUTexture *src_, + eGPUTextureFormat format, + int mip_start, + int mip_len, + int layer_start, + int layer_len) +{ + const Texture *src = unwrap(src_); + w_ = src->w_; + h_ = src->h_; + d_ = src->d_; + switch (type_) { + case GPU_TEXTURE_1D_ARRAY: + h_ = layer_len; + break; + case GPU_TEXTURE_CUBE_ARRAY: + BLI_assert(layer_len % 6 == 0); + ATTR_FALLTHROUGH; + case GPU_TEXTURE_2D_ARRAY: + d_ = layer_len; + break; + default: + BLI_assert(layer_len == 1 && layer_start == 0); + break; + } + mip_start = min_ii(mip_start, src->mipmaps_ - 1); + mip_len = min_ii(mip_len, (src->mipmaps_ - mip_start)); + mipmaps_ = mip_len; + format_ = format; + format_flag_ = to_format_flag(format); + /* For now always copy the target. Target aliasing could be exposed later. */ + type_ = src->type_; + sampler_state = src->sampler_state; + return this->init_internal(src_, mip_start, layer_start); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -343,6 +379,21 @@ GPUTexture *GPU_texture_create_error(int dimension, bool is_array) return gpu_texture_create("invalid_tex", w, h, d, type, 1, GPU_RGBA8, GPU_DATA_FLOAT, pixel); } +GPUTexture *GPU_texture_create_view(const char *name, + const GPUTexture *src, + eGPUTextureFormat format, + int mip_start, + int mip_len, + int layer_start, + int layer_len) +{ + BLI_assert(mip_len > 0); + BLI_assert(layer_len > 0); + Texture *view = GPUBackend::get()->texture_alloc(name); + view->init_view(src, format, mip_start, mip_len, layer_start, layer_len); + return wrap(view); +} + /* ------ Update ------ */ void GPU_texture_update_mipmap(GPUTexture *tex_, diff --git a/source/blender/gpu/intern/gpu_texture_private.hh b/source/blender/gpu/intern/gpu_texture_private.hh index b019235e463..ec11fab421c 100644 --- a/source/blender/gpu/intern/gpu_texture_private.hh +++ b/source/blender/gpu/intern/gpu_texture_private.hh @@ -106,6 +106,12 @@ class Texture { bool init_3D(int w, int h, int d, int mips, eGPUTextureFormat format); bool init_cubemap(int w, int layers, int mips, eGPUTextureFormat format); bool init_buffer(GPUVertBuf *vbo, eGPUTextureFormat format); + bool init_view(const GPUTexture *src, + eGPUTextureFormat format, + int mip_start, + int mip_len, + int layer_start, + int layer_len); virtual void generate_mipmap() = 0; virtual void copy_to(Texture *tex) = 0; @@ -234,6 +240,7 @@ class Texture { protected: virtual bool init_internal() = 0; virtual bool init_internal(GPUVertBuf *vbo) = 0; + virtual bool init_internal(const GPUTexture *src, int mip_offset, int layer_offset) = 0; }; /* Syntactic sugar. */ diff --git a/source/blender/gpu/opengl/gl_texture.cc b/source/blender/gpu/opengl/gl_texture.cc index 37bf2f6b8b3..0a5c7f8e79e 100644 --- a/source/blender/gpu/opengl/gl_texture.cc +++ b/source/blender/gpu/opengl/gl_texture.cc @@ -175,6 +175,28 @@ bool GLTexture::init_internal(GPUVertBuf *vbo) return true; } +bool GLTexture::init_internal(const GPUTexture *src, int mip_offset, int layer_offset) +{ + BLI_assert(GLContext::texture_storage_support); + + const GLTexture *gl_src = static_cast(unwrap(src)); + GLenum internal_format = to_gl_internal_format(format_); + target_ = to_gl_target(type_); + + glTextureView(tex_id_, + target_, + gl_src->tex_id_, + internal_format, + mip_offset, + mipmaps_, + layer_offset, + this->layer_count()); + + debug::object_label(GL_TEXTURE, tex_id_, name_); + + return true; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/gpu/opengl/gl_texture.hh b/source/blender/gpu/opengl/gl_texture.hh index 9e128da90e8..d4d024f5e3e 100644 --- a/source/blender/gpu/opengl/gl_texture.hh +++ b/source/blender/gpu/opengl/gl_texture.hh @@ -74,6 +74,8 @@ class GLTexture : public Texture { bool init_internal() override; /** Return true on success. */ bool init_internal(GPUVertBuf *vbo) override; + /** Return true on success. */ + bool init_internal(const GPUTexture *src, int mip_offset, int layer_offset) override; private: bool proxy_check(int mip); -- cgit v1.2.3