Metal: Stencil texture view support #107971

Merged
Jeroen Bakker merged 3 commits from Jason-Fielder/blender:MetalStencilViewSupport_And_Refactor into main 2023-05-22 20:40:43 +02:00
10 changed files with 102 additions and 43 deletions

View File

@ -691,7 +691,7 @@ class Texture : NonCopyable {
eGPUTextureFormat format = GPU_texture_format(tx_); eGPUTextureFormat format = GPU_texture_format(tx_);
for (auto i : IndexRange(mip_len)) { for (auto i : IndexRange(mip_len)) {
mip_views_.append( 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; return true;
} }
@ -726,7 +726,7 @@ class Texture : NonCopyable {
eGPUTextureFormat format = GPU_texture_format(tx_); eGPUTextureFormat format = GPU_texture_format(tx_);
for (auto i : IndexRange(layer_len)) { for (auto i : IndexRange(layer_len)) {
layer_views_.append( 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; return true;
} }
@ -742,8 +742,8 @@ class Texture : NonCopyable {
{ {
if (stencil_view_ == nullptr) { if (stencil_view_ == nullptr) {
eGPUTextureFormat format = GPU_texture_format(tx_); eGPUTextureFormat format = GPU_texture_format(tx_);
stencil_view_ = GPU_texture_create_view(name_, tx_, format, 0, 9999, 0, 9999, cube_as_array); stencil_view_ = GPU_texture_create_view(
GPU_texture_stencil_texture_mode_set(stencil_view_, true); name_, tx_, format, 0, 9999, 0, 9999, cube_as_array, true);
} }
return stencil_view_; return stencil_view_;
} }

View File

@ -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 * \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. * 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. * TODO(fclem): Target conversion (ex: Texture 2D as Texture 2D Array) is not implemented yet.
*/ */
GPUTexture *GPU_texture_create_view(const char *name, GPUTexture *GPU_texture_create_view(const char *name,
@ -709,7 +716,8 @@ GPUTexture *GPU_texture_create_view(const char *name,
int mip_len, int mip_len,
int layer_start, int layer_start,
int layer_len, 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]); 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);
/** \} */ /** \} */
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */

View File

@ -139,7 +139,8 @@ bool Texture::init_view(GPUTexture *src_,
int mip_len, int mip_len,
int layer_start, int layer_start,
int layer_len, int layer_len,
bool cube_as_array) bool cube_as_array,
bool use_stencil)
{ {
const Texture *src = unwrap(src_); const Texture *src = unwrap(src_);
w_ = src->w_; w_ = src->w_;
@ -172,7 +173,7 @@ bool Texture::init_view(GPUTexture *src_,
type_ = (type_ & ~GPU_TEXTURE_CUBE) | GPU_TEXTURE_2D_ARRAY; type_ = (type_ & ~GPU_TEXTURE_CUBE) | GPU_TEXTURE_2D_ARRAY;
} }
sampler_state = src->sampler_state; 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) void Texture::usage_set(eGPUTextureUsage usage_flags)
@ -457,7 +458,8 @@ GPUTexture *GPU_texture_create_view(const char *name,
int mip_len, int mip_len,
int layer_start, int layer_start,
int layer_len, int layer_len,
bool cube_as_array) bool cube_as_array,
bool use_stencil)
{ {
BLI_assert(mip_len > 0); BLI_assert(mip_len > 0);
BLI_assert(layer_len > 0); BLI_assert(layer_len > 0);
@ -472,7 +474,8 @@ GPUTexture *GPU_texture_create_view(const char *name,
mip_len, mip_len,
layer_start, layer_start,
layer_len, layer_len,
cube_as_array); cube_as_array,
use_stencil);
return wrap(view); return wrap(view);
} }
@ -668,12 +671,6 @@ void GPU_texture_swizzle_set(GPUTexture *tex, const char swizzle[4])
reinterpret_cast<Texture *>(tex)->swizzle_set(swizzle); reinterpret_cast<Texture *>(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<Texture *>(tex)->stencil_texture_mode_set(use_stencil);
}
void GPU_texture_free(GPUTexture *tex_) void GPU_texture_free(GPUTexture *tex_)
{ {
Texture *tex = reinterpret_cast<Texture *>(tex_); Texture *tex = reinterpret_cast<Texture *>(tex_);

View File

@ -139,13 +139,13 @@ class Texture {
int mip_len, int mip_len,
int layer_start, int layer_start,
int layer_len, int layer_len,
bool cube_as_array); bool cube_as_array,
bool use_stencil);
virtual void generate_mipmap() = 0; virtual void generate_mipmap() = 0;
virtual void copy_to(Texture *tex) = 0; virtual void copy_to(Texture *tex) = 0;
virtual void clear(eGPUDataFormat format, const void *data) = 0; virtual void clear(eGPUDataFormat format, const void *data) = 0;
virtual void swizzle_set(const char swizzle_mask[4]) = 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 mip_range_set(int min, int max) = 0;
virtual void *read(int mip, eGPUDataFormat format) = 0; virtual void *read(int mip, eGPUDataFormat format) = 0;
@ -313,7 +313,10 @@ class Texture {
protected: protected:
virtual bool init_internal() = 0; virtual bool init_internal() = 0;
virtual bool init_internal(GPUVertBuf *vbo) = 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. */ /* Syntactic sugar. */

View File

@ -219,6 +219,7 @@ class MTLTexture : public Texture {
MTLTextureSwizzleChannels mtl_swizzle_mask_; MTLTextureSwizzleChannels mtl_swizzle_mask_;
bool mip_range_dirty_ = false; bool mip_range_dirty_ = false;
bool texture_view_stencil_ = false;
int mip_texture_base_level_ = 0; int mip_texture_base_level_ = 0;
int mip_texture_max_level_ = 1000; int mip_texture_max_level_ = 1000;
int mip_texture_base_layer_ = 0; int mip_texture_base_layer_ = 0;
@ -256,9 +257,6 @@ class MTLTexture : public Texture {
void copy_to(Texture *dst) override; void copy_to(Texture *dst) override;
void clear(eGPUDataFormat format, const void *data) override; void clear(eGPUDataFormat format, const void *data) override;
void swizzle_set(const char swizzle_mask[4]) 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 mip_range_set(int min, int max) override;
void *read(int mip, eGPUDataFormat type) 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(GPUVertBuf *vbo) override;
bool init_internal(GPUTexture *src, bool init_internal(GPUTexture *src,
int mip_offset, int mip_offset,
int layer_offset) override; /* Texture View */ int layer_offset,
bool use_stencil) override; /* Texture View */
private: private:
/* Common Constructor, default initialization. */ /* Common Constructor, default initialization. */
@ -516,6 +515,32 @@ inline std::string tex_data_format_to_msl_texture_template_type(eGPUDataFormat t
return ""; 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 /* Determine whether format is writable or not. Use mtl_format_get_writeable_view_format(..) for
* these. */ * these. */
inline bool mtl_format_is_writable(MTLPixelFormat format) inline bool mtl_format_is_writable(MTLPixelFormat format)

View File

@ -159,14 +159,35 @@ void gpu::MTLTexture::bake_mip_swizzle_view()
break; 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, int range_len = min_ii((mip_texture_max_level_ - mip_texture_base_level_) + 1,
texture_.mipmapLevelCount - mip_texture_base_level_); texture_.mipmapLevelCount - mip_texture_base_level_);
BLI_assert(range_len > 0); BLI_assert(range_len > 0);
BLI_assert(mip_texture_base_level_ < texture_.mipmapLevelCount); BLI_assert(mip_texture_base_level_ < texture_.mipmapLevelCount);
BLI_assert(mip_texture_base_layer_ < num_slices); BLI_assert(mip_texture_base_layer_ < num_slices);
mip_swizzle_view_ = [texture_ mip_swizzle_view_ = [texture_
newTextureViewWithPixelFormat:texture_.pixelFormat newTextureViewWithPixelFormat:texture_view_pixel_format
textureType:texture_.textureType textureType:texture_view_texture_type
levels:NSMakeRange(mip_texture_base_level_, range_len) levels:NSMakeRange(mip_texture_base_level_, range_len)
slices:NSMakeRange(mip_texture_base_layer_, num_slices) slices:NSMakeRange(mip_texture_base_layer_, num_slices)
swizzle:mtl_swizzle_mask_]; swizzle:mtl_swizzle_mask_];
@ -1810,7 +1831,10 @@ bool gpu::MTLTexture::init_internal(GPUVertBuf *vbo)
return true; 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); BLI_assert(src);
@ -1841,6 +1865,13 @@ bool gpu::MTLTexture::init_internal(GPUTexture *src, int mip_offset, int layer_o
is_baked_ = true; is_baked_ = true;
is_dirty_ = false; 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. */
bake_mip_swizzle_view(); bake_mip_swizzle_view();
return true; return true;

View File

@ -178,7 +178,7 @@ bool GLTexture::init_internal(GPUVertBuf *vbo)
return true; 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); 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_); 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; return true;
} }

View File

@ -76,7 +76,6 @@ class GLTexture : public Texture {
void copy_to(Texture *dst) override; void copy_to(Texture *dst) override;
void clear(eGPUDataFormat format, const void *data) override; void clear(eGPUDataFormat format, const void *data) override;
void swizzle_set(const char swizzle_mask[4]) 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 mip_range_set(int min, int max) override;
void *read(int mip, eGPUDataFormat type) override; void *read(int mip, eGPUDataFormat type) override;
@ -117,10 +116,11 @@ class GLTexture : public Texture {
/** Return true on success. */ /** Return true on success. */
bool init_internal(GPUVertBuf *vbo) override; bool init_internal(GPUVertBuf *vbo) override;
/** Return true on success. */ /** 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: private:
bool proxy_check(int mip); bool proxy_check(int mip);
void stencil_texture_mode_set(bool use_stencil);
void update_sub_direct_state_access( void update_sub_direct_state_access(
int mip, int offset[3], int extent[3], GLenum gl_format, GLenum gl_type, const void *data); int mip, int offset[3], int extent[3], GLenum gl_format, GLenum gl_type, const void *data);
GPUFrameBuffer *framebuffer_get(); GPUFrameBuffer *framebuffer_get();

View File

@ -62,8 +62,6 @@ void VKTexture::clear(eGPUDataFormat format, const void *data)
void VKTexture::swizzle_set(const char /*swizzle_mask*/[4]) {} 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::mip_range_set(int /*min*/, int /*max*/) {}
void *VKTexture::read(int mip, eGPUDataFormat format) void *VKTexture::read(int mip, eGPUDataFormat format)
@ -181,7 +179,10 @@ bool VKTexture::init_internal(GPUVertBuf * /*vbo*/)
return false; 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; return false;
} }

View File

@ -36,7 +36,6 @@ class VKTexture : public Texture {
void copy_to(Texture *tex) override; void copy_to(Texture *tex) override;
void clear(eGPUDataFormat format, const void *data) override; void clear(eGPUDataFormat format, const void *data) override;
void swizzle_set(const char swizzle_mask[4]) 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 mip_range_set(int min, int max) override;
void *read(int mip, eGPUDataFormat format) override; void *read(int mip, eGPUDataFormat format) override;
void update_sub( void update_sub(
@ -68,7 +67,7 @@ class VKTexture : public Texture {
protected: protected:
bool init_internal() override; bool init_internal() override;
bool init_internal(GPUVertBuf *vbo) 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: private:
/** Is this texture already allocated on device. */ /** Is this texture already allocated on device. */