diff --git a/source/blender/draw/intern/DRW_gpu_wrapper.hh b/source/blender/draw/intern/DRW_gpu_wrapper.hh index 7606aff4b55..2c7e3623a43 100644 --- a/source/blender/draw/intern/DRW_gpu_wrapper.hh +++ b/source/blender/draw/intern/DRW_gpu_wrapper.hh @@ -691,7 +691,7 @@ class Texture : NonCopyable { eGPUTextureFormat format = GPU_texture_format(tx_); for (auto i : IndexRange(mip_len)) { mip_views_.append( - GPU_texture_create_view(name_, tx_, format, i, 1, 0, 9999, cube_as_array)); + GPU_texture_create_view(name_, tx_, format, i, 1, 0, 9999, cube_as_array, false)); } return true; } @@ -726,7 +726,7 @@ class Texture : NonCopyable { eGPUTextureFormat format = GPU_texture_format(tx_); for (auto i : IndexRange(layer_len)) { layer_views_.append( - GPU_texture_create_view(name_, tx_, format, 0, 9999, i, 1, cube_as_array)); + GPU_texture_create_view(name_, tx_, format, 0, 9999, i, 1, cube_as_array, false)); } return true; } @@ -742,8 +742,8 @@ class Texture : NonCopyable { { if (stencil_view_ == nullptr) { eGPUTextureFormat format = GPU_texture_format(tx_); - stencil_view_ = GPU_texture_create_view(name_, tx_, format, 0, 9999, 0, 9999, cube_as_array); - GPU_texture_stencil_texture_mode_set(stencil_view_, true); + stencil_view_ = GPU_texture_create_view( + name_, tx_, format, 0, 9999, 0, 9999, cube_as_array, true); } return stencil_view_; } diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index b695ed9b1ed..d2207839b5e 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -700,6 +700,13 @@ void GPU_texture_free(GPUTexture *texture); * \note If \a cube_as_array is true, then the created view will be a 2D array texture instead of a * cube-map texture or cube-map-array texture. * + * For Depth-Stencil texture view formats: + * \note If \a use_stencil is true, the texture is expected to be bound to a UINT sampler and will + * return the stencil value (in a range of [0..255]) as the first component. + * \note If \a use_stencil is false (default), the texture is expected to be bound to a DEPTH + * sampler and will return the normalized depth value (in a range of [0..1]) as the first + * component. + * * TODO(fclem): Target conversion (ex: Texture 2D as Texture 2D Array) is not implemented yet. */ GPUTexture *GPU_texture_create_view(const char *name, @@ -709,7 +716,8 @@ GPUTexture *GPU_texture_create_view(const char *name, int mip_len, int layer_start, int layer_len, - bool cube_as_array); + bool cube_as_array, + bool use_stencil); /** \} */ @@ -908,16 +916,6 @@ void GPU_texture_extend_mode(GPUTexture *texture, GPUSamplerExtendMode extend_mo */ void GPU_texture_swizzle_set(GPUTexture *texture, const char swizzle[4]); -/** - * Set a depth-stencil texture read mode. - * - * If \a use_stencil is true, the texture is expected to be bound to a UINT sampler and will return - * the stencil value (in a range of [0..255]) as the first component. - * If \a use_stencil is false, the texture is expected to be bound to a DEPTH sampler and will - * return the normalized depth value (in a range of [0..1]) as the first component. - */ -void GPU_texture_stencil_texture_mode_set(GPUTexture *texture, bool use_stencil); - /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/gpu/intern/gpu_texture.cc b/source/blender/gpu/intern/gpu_texture.cc index 62ff6c2a0c6..a3c8d49a34d 100644 --- a/source/blender/gpu/intern/gpu_texture.cc +++ b/source/blender/gpu/intern/gpu_texture.cc @@ -139,7 +139,8 @@ bool Texture::init_view(GPUTexture *src_, int mip_len, int layer_start, int layer_len, - bool cube_as_array) + bool cube_as_array, + bool use_stencil) { const Texture *src = unwrap(src_); w_ = src->w_; @@ -172,7 +173,7 @@ bool Texture::init_view(GPUTexture *src_, type_ = (type_ & ~GPU_TEXTURE_CUBE) | GPU_TEXTURE_2D_ARRAY; } sampler_state = src->sampler_state; - return this->init_internal(src_, mip_start, layer_start); + return this->init_internal(src_, mip_start, layer_start, use_stencil); } void Texture::usage_set(eGPUTextureUsage usage_flags) @@ -457,7 +458,8 @@ GPUTexture *GPU_texture_create_view(const char *name, int mip_len, int layer_start, int layer_len, - bool cube_as_array) + bool cube_as_array, + bool use_stencil) { BLI_assert(mip_len > 0); BLI_assert(layer_len > 0); @@ -472,7 +474,8 @@ GPUTexture *GPU_texture_create_view(const char *name, mip_len, layer_start, layer_len, - cube_as_array); + cube_as_array, + use_stencil); return wrap(view); } @@ -668,12 +671,6 @@ void GPU_texture_swizzle_set(GPUTexture *tex, const char swizzle[4]) reinterpret_cast(tex)->swizzle_set(swizzle); } -void GPU_texture_stencil_texture_mode_set(GPUTexture *tex, bool use_stencil) -{ - BLI_assert(GPU_texture_has_stencil_format(tex) || !use_stencil); - reinterpret_cast(tex)->stencil_texture_mode_set(use_stencil); -} - void GPU_texture_free(GPUTexture *tex_) { Texture *tex = reinterpret_cast(tex_); diff --git a/source/blender/gpu/intern/gpu_texture_private.hh b/source/blender/gpu/intern/gpu_texture_private.hh index 1ea1d600e62..ebbdd7f3e42 100644 --- a/source/blender/gpu/intern/gpu_texture_private.hh +++ b/source/blender/gpu/intern/gpu_texture_private.hh @@ -139,13 +139,13 @@ class Texture { int mip_len, int layer_start, int layer_len, - bool cube_as_array); + bool cube_as_array, + bool use_stencil); virtual void generate_mipmap() = 0; virtual void copy_to(Texture *tex) = 0; virtual void clear(eGPUDataFormat format, const void *data) = 0; virtual void swizzle_set(const char swizzle_mask[4]) = 0; - virtual void stencil_texture_mode_set(bool use_stencil) = 0; virtual void mip_range_set(int min, int max) = 0; virtual void *read(int mip, eGPUDataFormat format) = 0; @@ -313,7 +313,10 @@ class Texture { protected: virtual bool init_internal() = 0; virtual bool init_internal(GPUVertBuf *vbo) = 0; - virtual bool init_internal(GPUTexture *src, int mip_offset, int layer_offset) = 0; + virtual bool init_internal(GPUTexture *src, + int mip_offset, + int layer_offset, + bool use_stencil) = 0; }; /* Syntactic sugar. */ diff --git a/source/blender/gpu/metal/mtl_texture.hh b/source/blender/gpu/metal/mtl_texture.hh index d7191cd647c..f0058a9062b 100644 --- a/source/blender/gpu/metal/mtl_texture.hh +++ b/source/blender/gpu/metal/mtl_texture.hh @@ -219,6 +219,7 @@ class MTLTexture : public Texture { MTLTextureSwizzleChannels mtl_swizzle_mask_; bool mip_range_dirty_ = false; + bool texture_view_stencil_ = false; int mip_texture_base_level_ = 0; int mip_texture_max_level_ = 1000; int mip_texture_base_layer_ = 0; @@ -256,9 +257,6 @@ class MTLTexture : public Texture { void copy_to(Texture *dst) override; void clear(eGPUDataFormat format, const void *data) override; void swizzle_set(const char swizzle_mask[4]) override; - void stencil_texture_mode_set(bool use_stencil) override{ - /* TODO(Metal): implement. */ - }; void mip_range_set(int min, int max) override; void *read(int mip, eGPUDataFormat type) override; @@ -285,7 +283,8 @@ class MTLTexture : public Texture { bool init_internal(GPUVertBuf *vbo) override; bool init_internal(GPUTexture *src, int mip_offset, - int layer_offset) override; /* Texture View */ + int layer_offset, + bool use_stencil) override; /* Texture View */ private: /* Common Constructor, default initialization. */ @@ -516,6 +515,32 @@ inline std::string tex_data_format_to_msl_texture_template_type(eGPUDataFormat t return ""; } +/* Fetch Metal texture type from GPU texture type. */ +inline MTLTextureType to_metal_type(eGPUTextureType type) +{ + switch (type) { + case GPU_TEXTURE_1D: + return MTLTextureType1D; + case GPU_TEXTURE_2D: + return MTLTextureType2D; + case GPU_TEXTURE_3D: + return MTLTextureType3D; + case GPU_TEXTURE_CUBE: + return MTLTextureTypeCube; + case GPU_TEXTURE_BUFFER: + return MTLTextureTypeTextureBuffer; + case GPU_TEXTURE_1D_ARRAY: + return MTLTextureType1DArray; + case GPU_TEXTURE_2D_ARRAY: + return MTLTextureType2DArray; + case GPU_TEXTURE_CUBE_ARRAY: + return MTLTextureTypeCubeArray; + default: + BLI_assert_unreachable(); + } + return MTLTextureType2D; +} + /* Determine whether format is writable or not. Use mtl_format_get_writeable_view_format(..) for * these. */ inline bool mtl_format_is_writable(MTLPixelFormat format) diff --git a/source/blender/gpu/metal/mtl_texture.mm b/source/blender/gpu/metal/mtl_texture.mm index 9c67e901034..80093d55240 100644 --- a/source/blender/gpu/metal/mtl_texture.mm +++ b/source/blender/gpu/metal/mtl_texture.mm @@ -159,14 +159,35 @@ void gpu::MTLTexture::bake_mip_swizzle_view() break; } + /* Determine texture view format. If texture view is used as a stencil view, we instead provide + * the equivalent format for performing stencil reads/samples. */ + MTLPixelFormat texture_view_pixel_format = texture_.pixelFormat; + if (texture_view_stencil_) { + switch (texture_view_pixel_format) { + case MTLPixelFormatDepth24Unorm_Stencil8: + texture_view_pixel_format = MTLPixelFormatX24_Stencil8; + break; + case MTLPixelFormatDepth32Float_Stencil8: + texture_view_pixel_format = MTLPixelFormatX32_Stencil8; + break; + default: + BLI_assert_msg(false, "Texture format does not support stencil views."); + break; + } + } + + /* Note: Texture type for cube maps can be overriden as a 2D array. This is done + * via modifying this textures type flags. */ + MTLTextureType texture_view_texture_type = to_metal_type(type_); + int range_len = min_ii((mip_texture_max_level_ - mip_texture_base_level_) + 1, texture_.mipmapLevelCount - mip_texture_base_level_); BLI_assert(range_len > 0); BLI_assert(mip_texture_base_level_ < texture_.mipmapLevelCount); BLI_assert(mip_texture_base_layer_ < num_slices); mip_swizzle_view_ = [texture_ - newTextureViewWithPixelFormat:texture_.pixelFormat - textureType:texture_.textureType + newTextureViewWithPixelFormat:texture_view_pixel_format + textureType:texture_view_texture_type levels:NSMakeRange(mip_texture_base_level_, range_len) slices:NSMakeRange(mip_texture_base_layer_, num_slices) swizzle:mtl_swizzle_mask_]; @@ -1810,7 +1831,10 @@ bool gpu::MTLTexture::init_internal(GPUVertBuf *vbo) return true; } -bool gpu::MTLTexture::init_internal(GPUTexture *src, int mip_offset, int layer_offset) +bool gpu::MTLTexture::init_internal(GPUTexture *src, + int mip_offset, + int layer_offset, + bool use_stencil) { BLI_assert(src); @@ -1841,6 +1865,13 @@ bool gpu::MTLTexture::init_internal(GPUTexture *src, int mip_offset, int layer_o is_baked_ = true; is_dirty_ = false; + /* Stencil view support. */ + texture_view_stencil_ = false; + if (use_stencil) { + BLI_assert(ELEM(format_, GPU_DEPTH24_STENCIL8, GPU_DEPTH32F_STENCIL8)); + texture_view_stencil_ = true; + } + /* Bake mip swizzle view. */ bake_mip_swizzle_view(); return true; diff --git a/source/blender/gpu/opengl/gl_texture.cc b/source/blender/gpu/opengl/gl_texture.cc index fd7d60d92d4..b22ca0e059e 100644 --- a/source/blender/gpu/opengl/gl_texture.cc +++ b/source/blender/gpu/opengl/gl_texture.cc @@ -178,7 +178,7 @@ bool GLTexture::init_internal(GPUVertBuf *vbo) return true; } -bool GLTexture::init_internal(GPUTexture *src, int mip_offset, int layer_offset) +bool GLTexture::init_internal(GPUTexture *src, int mip_offset, int layer_offset, bool use_stencil) { BLI_assert(GLContext::texture_storage_support); @@ -197,6 +197,11 @@ bool GLTexture::init_internal(GPUTexture *src, int mip_offset, int layer_offset) debug::object_label(GL_TEXTURE, tex_id_, name_); + /* Stencil view support. */ + if (ELEM(format_, GPU_DEPTH24_STENCIL8, GPU_DEPTH32F_STENCIL8)) { + stencil_texture_mode_set(use_stencil); + } + return true; } diff --git a/source/blender/gpu/opengl/gl_texture.hh b/source/blender/gpu/opengl/gl_texture.hh index f8f1b7e6306..32ff0ddbe21 100644 --- a/source/blender/gpu/opengl/gl_texture.hh +++ b/source/blender/gpu/opengl/gl_texture.hh @@ -76,7 +76,6 @@ class GLTexture : public Texture { void copy_to(Texture *dst) override; void clear(eGPUDataFormat format, const void *data) override; void swizzle_set(const char swizzle_mask[4]) override; - void stencil_texture_mode_set(bool use_stencil) override; void mip_range_set(int min, int max) override; void *read(int mip, eGPUDataFormat type) override; @@ -117,10 +116,11 @@ class GLTexture : public Texture { /** Return true on success. */ bool init_internal(GPUVertBuf *vbo) override; /** Return true on success. */ - bool init_internal(GPUTexture *src, int mip_offset, int layer_offset) override; + bool init_internal(GPUTexture *src, int mip_offset, int layer_offset, bool use_stencil) override; private: bool proxy_check(int mip); + void stencil_texture_mode_set(bool use_stencil); 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(); diff --git a/source/blender/gpu/vulkan/vk_texture.cc b/source/blender/gpu/vulkan/vk_texture.cc index e636fe7172d..b1fc27ff209 100644 --- a/source/blender/gpu/vulkan/vk_texture.cc +++ b/source/blender/gpu/vulkan/vk_texture.cc @@ -62,8 +62,6 @@ void VKTexture::clear(eGPUDataFormat format, const void *data) void VKTexture::swizzle_set(const char /*swizzle_mask*/[4]) {} -void VKTexture::stencil_texture_mode_set(bool /*use_stencil*/) {} - void VKTexture::mip_range_set(int /*min*/, int /*max*/) {} void *VKTexture::read(int mip, eGPUDataFormat format) @@ -181,7 +179,10 @@ bool VKTexture::init_internal(GPUVertBuf * /*vbo*/) return false; } -bool VKTexture::init_internal(GPUTexture * /*src*/, int /*mip_offset*/, int /*layer_offset*/) +bool VKTexture::init_internal(GPUTexture * /*src*/, + int /*mip_offset*/, + int /*layer_offset*/, + bool /*use_stencil*/) { return false; } diff --git a/source/blender/gpu/vulkan/vk_texture.hh b/source/blender/gpu/vulkan/vk_texture.hh index 7e9e803e596..4b73c6d38d9 100644 --- a/source/blender/gpu/vulkan/vk_texture.hh +++ b/source/blender/gpu/vulkan/vk_texture.hh @@ -36,7 +36,6 @@ class VKTexture : public Texture { void copy_to(Texture *tex) override; void clear(eGPUDataFormat format, const void *data) override; void swizzle_set(const char swizzle_mask[4]) override; - void stencil_texture_mode_set(bool use_stencil) override; void mip_range_set(int min, int max) override; void *read(int mip, eGPUDataFormat format) override; void update_sub( @@ -68,7 +67,7 @@ class VKTexture : public Texture { protected: bool init_internal() override; bool init_internal(GPUVertBuf *vbo) override; - bool init_internal(GPUTexture *src, int mip_offset, int layer_offset) override; + bool init_internal(GPUTexture *src, int mip_offset, int layer_offset, bool use_stencil) override; private: /** Is this texture already allocated on device. */