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_);
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_;
}

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
* 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);
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -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<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_)
{
Texture *tex = reinterpret_cast<Texture *>(tex_);

View File

@ -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. */

View File

@ -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)

View File

@ -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;

View File

@ -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;
}

View File

@ -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();

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::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;
}

View File

@ -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. */