From 4fa52738ce03a319d15416d1641f1bef08d597ef Mon Sep 17 00:00:00 2001 From: Michael Parkin-White Date: Tue, 16 May 2023 13:19:37 +0100 Subject: [PATCH] Metal: Stencil texture view support Adds stencil texture view support for Metal, allowing reading of stencil component during texture sample/read. Stencil view creation refactored to use additional parameter in textureview creation function, due to deferred stencil parameter causing double texture view creation in Metal, when this should ideally be provided upfront. Authored by Apple: Michael Parkin-White Ref #96261 --- source/blender/draw/intern/DRW_gpu_wrapper.hh | 8 ++-- source/blender/gpu/GPU_texture.h | 20 +++++----- source/blender/gpu/intern/gpu_texture.cc | 17 ++++----- .../blender/gpu/intern/gpu_texture_private.hh | 9 +++-- source/blender/gpu/metal/mtl_texture.hh | 33 +++++++++++++++-- source/blender/gpu/metal/mtl_texture.mm | 37 +++++++++++++++++-- source/blender/gpu/opengl/gl_texture.cc | 7 +++- source/blender/gpu/opengl/gl_texture.hh | 4 +- source/blender/gpu/vulkan/vk_texture.cc | 7 ++-- source/blender/gpu/vulkan/vk_texture.hh | 3 +- 10 files changed, 102 insertions(+), 43 deletions(-) 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 35aab01be06..de4e598c125 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) @@ -454,7 +455,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); @@ -469,7 +471,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); } @@ -665,12 +668,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. */ -- 2.30.2