Merge pull request #12432 from liamwhite/float-write

shader_recompiler: use float image operations on load/store when required
This commit is contained in:
Fernando S 2023-12-22 17:40:26 +01:00 committed by GitHub
commit 4d6b6ba76c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 184 additions and 39 deletions

View file

@ -214,16 +214,16 @@ Id TextureImage(EmitContext& ctx, IR::TextureInstInfo info, const IR::Value& ind
} }
} }
Id Image(EmitContext& ctx, const IR::Value& index, IR::TextureInstInfo info) { std::pair<Id, bool> Image(EmitContext& ctx, const IR::Value& index, IR::TextureInstInfo info) {
if (!index.IsImmediate() || index.U32() != 0) { if (!index.IsImmediate() || index.U32() != 0) {
throw NotImplementedException("Indirect image indexing"); throw NotImplementedException("Indirect image indexing");
} }
if (info.type == TextureType::Buffer) { if (info.type == TextureType::Buffer) {
const ImageBufferDefinition def{ctx.image_buffers.at(info.descriptor_index)}; const ImageBufferDefinition def{ctx.image_buffers.at(info.descriptor_index)};
return ctx.OpLoad(def.image_type, def.id); return {ctx.OpLoad(def.image_type, def.id), def.is_integer};
} else { } else {
const ImageDefinition def{ctx.images.at(info.descriptor_index)}; const ImageDefinition def{ctx.images.at(info.descriptor_index)};
return ctx.OpLoad(def.image_type, def.id); return {ctx.OpLoad(def.image_type, def.id), def.is_integer};
} }
} }
@ -566,13 +566,23 @@ Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id co
LOG_WARNING(Shader_SPIRV, "Typeless image read not supported by host"); LOG_WARNING(Shader_SPIRV, "Typeless image read not supported by host");
return ctx.ConstantNull(ctx.U32[4]); return ctx.ConstantNull(ctx.U32[4]);
} }
return Emit(&EmitContext::OpImageSparseRead, &EmitContext::OpImageRead, ctx, inst, ctx.U32[4], const auto [image, is_integer] = Image(ctx, index, info);
Image(ctx, index, info), coords, std::nullopt, std::span<const Id>{}); const Id result_type{is_integer ? ctx.U32[4] : ctx.F32[4]};
Id color{Emit(&EmitContext::OpImageSparseRead, &EmitContext::OpImageRead, ctx, inst,
result_type, image, coords, std::nullopt, std::span<const Id>{})};
if (!is_integer) {
color = ctx.OpBitcast(ctx.U32[4], color);
}
return color;
} }
void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color) { void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color) {
const auto info{inst->Flags<IR::TextureInstInfo>()}; const auto info{inst->Flags<IR::TextureInstInfo>()};
ctx.OpImageWrite(Image(ctx, index, info), coords, color); const auto [image, is_integer] = Image(ctx, index, info);
if (!is_integer) {
color = ctx.OpBitcast(ctx.F32[4], color);
}
ctx.OpImageWrite(image, coords, color);
} }
Id EmitIsTextureScaled(EmitContext& ctx, const IR::Value& index) { Id EmitIsTextureScaled(EmitContext& ctx, const IR::Value& index) {

View file

@ -74,20 +74,19 @@ spv::ImageFormat GetImageFormat(ImageFormat format) {
throw InvalidArgument("Invalid image format {}", format); throw InvalidArgument("Invalid image format {}", format);
} }
Id ImageType(EmitContext& ctx, const ImageDescriptor& desc) { Id ImageType(EmitContext& ctx, const ImageDescriptor& desc, Id sampled_type) {
const spv::ImageFormat format{GetImageFormat(desc.format)}; const spv::ImageFormat format{GetImageFormat(desc.format)};
const Id type{ctx.U32[1]};
switch (desc.type) { switch (desc.type) {
case TextureType::Color1D: case TextureType::Color1D:
return ctx.TypeImage(type, spv::Dim::Dim1D, false, false, false, 2, format); return ctx.TypeImage(sampled_type, spv::Dim::Dim1D, false, false, false, 2, format);
case TextureType::ColorArray1D: case TextureType::ColorArray1D:
return ctx.TypeImage(type, spv::Dim::Dim1D, false, true, false, 2, format); return ctx.TypeImage(sampled_type, spv::Dim::Dim1D, false, true, false, 2, format);
case TextureType::Color2D: case TextureType::Color2D:
return ctx.TypeImage(type, spv::Dim::Dim2D, false, false, false, 2, format); return ctx.TypeImage(sampled_type, spv::Dim::Dim2D, false, false, false, 2, format);
case TextureType::ColorArray2D: case TextureType::ColorArray2D:
return ctx.TypeImage(type, spv::Dim::Dim2D, false, true, false, 2, format); return ctx.TypeImage(sampled_type, spv::Dim::Dim2D, false, true, false, 2, format);
case TextureType::Color3D: case TextureType::Color3D:
return ctx.TypeImage(type, spv::Dim::Dim3D, false, false, false, 2, format); return ctx.TypeImage(sampled_type, spv::Dim::Dim3D, false, false, false, 2, format);
case TextureType::Buffer: case TextureType::Buffer:
throw NotImplementedException("Image buffer"); throw NotImplementedException("Image buffer");
default: default:
@ -1273,7 +1272,9 @@ void EmitContext::DefineImageBuffers(const Info& info, u32& binding) {
throw NotImplementedException("Array of image buffers"); throw NotImplementedException("Array of image buffers");
} }
const spv::ImageFormat format{GetImageFormat(desc.format)}; const spv::ImageFormat format{GetImageFormat(desc.format)};
const Id image_type{TypeImage(U32[1], spv::Dim::Buffer, false, false, false, 2, format)}; const Id sampled_type{desc.is_integer ? U32[1] : F32[1]};
const Id image_type{
TypeImage(sampled_type, spv::Dim::Buffer, false, false, false, 2, format)};
const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, image_type)}; const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, image_type)};
const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)}; const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)};
Decorate(id, spv::Decoration::Binding, binding); Decorate(id, spv::Decoration::Binding, binding);
@ -1283,6 +1284,7 @@ void EmitContext::DefineImageBuffers(const Info& info, u32& binding) {
.id = id, .id = id,
.image_type = image_type, .image_type = image_type,
.count = desc.count, .count = desc.count,
.is_integer = desc.is_integer,
}); });
if (profile.supported_spirv >= 0x00010400) { if (profile.supported_spirv >= 0x00010400) {
interfaces.push_back(id); interfaces.push_back(id);
@ -1327,7 +1329,8 @@ void EmitContext::DefineImages(const Info& info, u32& binding, u32& scaling_inde
if (desc.count != 1) { if (desc.count != 1) {
throw NotImplementedException("Array of images"); throw NotImplementedException("Array of images");
} }
const Id image_type{ImageType(*this, desc)}; const Id sampled_type{desc.is_integer ? U32[1] : F32[1]};
const Id image_type{ImageType(*this, desc, sampled_type)};
const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, image_type)}; const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, image_type)};
const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)}; const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)};
Decorate(id, spv::Decoration::Binding, binding); Decorate(id, spv::Decoration::Binding, binding);
@ -1337,6 +1340,7 @@ void EmitContext::DefineImages(const Info& info, u32& binding, u32& scaling_inde
.id = id, .id = id,
.image_type = image_type, .image_type = image_type,
.count = desc.count, .count = desc.count,
.is_integer = desc.is_integer,
}); });
if (profile.supported_spirv >= 0x00010400) { if (profile.supported_spirv >= 0x00010400) {
interfaces.push_back(id); interfaces.push_back(id);

View file

@ -47,12 +47,14 @@ struct ImageBufferDefinition {
Id id; Id id;
Id image_type; Id image_type;
u32 count; u32 count;
bool is_integer;
}; };
struct ImageDefinition { struct ImageDefinition {
Id id; Id id;
Id image_type; Id image_type;
u32 count; u32 count;
bool is_integer;
}; };
struct UniformDefinitions { struct UniformDefinitions {

View file

@ -24,6 +24,8 @@ public:
[[nodiscard]] virtual TexturePixelFormat ReadTexturePixelFormat(u32 raw_handle) = 0; [[nodiscard]] virtual TexturePixelFormat ReadTexturePixelFormat(u32 raw_handle) = 0;
[[nodiscard]] virtual bool IsTexturePixelFormatInteger(u32 raw_handle) = 0;
[[nodiscard]] virtual u32 ReadViewportTransformState() = 0; [[nodiscard]] virtual u32 ReadViewportTransformState() = 0;
[[nodiscard]] virtual u32 TextureBoundBuffer() const = 0; [[nodiscard]] virtual u32 TextureBoundBuffer() const = 0;

View file

@ -372,6 +372,10 @@ TexturePixelFormat ReadTexturePixelFormat(Environment& env, const ConstBufferAdd
return env.ReadTexturePixelFormat(GetTextureHandle(env, cbuf)); return env.ReadTexturePixelFormat(GetTextureHandle(env, cbuf));
} }
bool IsTexturePixelFormatInteger(Environment& env, const ConstBufferAddr& cbuf) {
return env.IsTexturePixelFormatInteger(GetTextureHandle(env, cbuf));
}
class Descriptors { class Descriptors {
public: public:
explicit Descriptors(TextureBufferDescriptors& texture_buffer_descriptors_, explicit Descriptors(TextureBufferDescriptors& texture_buffer_descriptors_,
@ -403,6 +407,7 @@ public:
})}; })};
image_buffer_descriptors[index].is_written |= desc.is_written; image_buffer_descriptors[index].is_written |= desc.is_written;
image_buffer_descriptors[index].is_read |= desc.is_read; image_buffer_descriptors[index].is_read |= desc.is_read;
image_buffer_descriptors[index].is_integer |= desc.is_integer;
return index; return index;
} }
@ -432,6 +437,7 @@ public:
})}; })};
image_descriptors[index].is_written |= desc.is_written; image_descriptors[index].is_written |= desc.is_written;
image_descriptors[index].is_read |= desc.is_read; image_descriptors[index].is_read |= desc.is_read;
image_descriptors[index].is_integer |= desc.is_integer;
return index; return index;
} }
@ -469,6 +475,20 @@ void PatchImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) {
ir.FPRecip(ir.ConvertUToF(32, 32, ir.CompositeExtract(texture_size, 1)))))); ir.FPRecip(ir.ConvertUToF(32, 32, ir.CompositeExtract(texture_size, 1))))));
} }
bool IsPixelFormatSNorm(TexturePixelFormat pixel_format) {
switch (pixel_format) {
case TexturePixelFormat::A8B8G8R8_SNORM:
case TexturePixelFormat::R8G8_SNORM:
case TexturePixelFormat::R8_SNORM:
case TexturePixelFormat::R16G16B16A16_SNORM:
case TexturePixelFormat::R16G16_SNORM:
case TexturePixelFormat::R16_SNORM:
return true;
default:
return false;
}
}
void PatchTexelFetch(IR::Block& block, IR::Inst& inst, TexturePixelFormat pixel_format) { void PatchTexelFetch(IR::Block& block, IR::Inst& inst, TexturePixelFormat pixel_format) {
const auto it{IR::Block::InstructionList::s_iterator_to(inst)}; const auto it{IR::Block::InstructionList::s_iterator_to(inst)};
IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
@ -587,11 +607,13 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
} }
const bool is_written{inst->GetOpcode() != IR::Opcode::ImageRead}; const bool is_written{inst->GetOpcode() != IR::Opcode::ImageRead};
const bool is_read{inst->GetOpcode() != IR::Opcode::ImageWrite}; const bool is_read{inst->GetOpcode() != IR::Opcode::ImageWrite};
const bool is_integer{IsTexturePixelFormatInteger(env, cbuf)};
if (flags.type == TextureType::Buffer) { if (flags.type == TextureType::Buffer) {
index = descriptors.Add(ImageBufferDescriptor{ index = descriptors.Add(ImageBufferDescriptor{
.format = flags.image_format, .format = flags.image_format,
.is_written = is_written, .is_written = is_written,
.is_read = is_read, .is_read = is_read,
.is_integer = is_integer,
.cbuf_index = cbuf.index, .cbuf_index = cbuf.index,
.cbuf_offset = cbuf.offset, .cbuf_offset = cbuf.offset,
.count = cbuf.count, .count = cbuf.count,
@ -603,6 +625,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
.format = flags.image_format, .format = flags.image_format,
.is_written = is_written, .is_written = is_written,
.is_read = is_read, .is_read = is_read,
.is_integer = is_integer,
.cbuf_index = cbuf.index, .cbuf_index = cbuf.index,
.cbuf_offset = cbuf.offset, .cbuf_offset = cbuf.offset,
.count = cbuf.count, .count = cbuf.count,
@ -658,7 +681,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
if (!host_info.support_snorm_render_buffer && inst->GetOpcode() == IR::Opcode::ImageFetch && if (!host_info.support_snorm_render_buffer && inst->GetOpcode() == IR::Opcode::ImageFetch &&
flags.type == TextureType::Buffer) { flags.type == TextureType::Buffer) {
const auto pixel_format = ReadTexturePixelFormat(env, cbuf); const auto pixel_format = ReadTexturePixelFormat(env, cbuf);
if (pixel_format != TexturePixelFormat::OTHER) { if (IsPixelFormatSNorm(pixel_format)) {
PatchTexelFetch(*texture_inst.block, *texture_inst.inst, pixel_format); PatchTexelFetch(*texture_inst.block, *texture_inst.inst, pixel_format);
} }
} }

View file

@ -35,14 +35,109 @@ enum class TextureType : u32 {
}; };
constexpr u32 NUM_TEXTURE_TYPES = 9; constexpr u32 NUM_TEXTURE_TYPES = 9;
enum class TexturePixelFormat : u32 { enum class TexturePixelFormat {
A8B8G8R8_UNORM,
A8B8G8R8_SNORM, A8B8G8R8_SNORM,
A8B8G8R8_SINT,
A8B8G8R8_UINT,
R5G6B5_UNORM,
B5G6R5_UNORM,
A1R5G5B5_UNORM,
A2B10G10R10_UNORM,
A2B10G10R10_UINT,
A2R10G10B10_UNORM,
A1B5G5R5_UNORM,
A5B5G5R1_UNORM,
R8_UNORM,
R8_SNORM, R8_SNORM,
R8G8_SNORM, R8_SINT,
R8_UINT,
R16G16B16A16_FLOAT,
R16G16B16A16_UNORM,
R16G16B16A16_SNORM, R16G16B16A16_SNORM,
R16G16_SNORM, R16G16B16A16_SINT,
R16G16B16A16_UINT,
B10G11R11_FLOAT,
R32G32B32A32_UINT,
BC1_RGBA_UNORM,
BC2_UNORM,
BC3_UNORM,
BC4_UNORM,
BC4_SNORM,
BC5_UNORM,
BC5_SNORM,
BC7_UNORM,
BC6H_UFLOAT,
BC6H_SFLOAT,
ASTC_2D_4X4_UNORM,
B8G8R8A8_UNORM,
R32G32B32A32_FLOAT,
R32G32B32A32_SINT,
R32G32_FLOAT,
R32G32_SINT,
R32_FLOAT,
R16_FLOAT,
R16_UNORM,
R16_SNORM, R16_SNORM,
OTHER R16_UINT,
R16_SINT,
R16G16_UNORM,
R16G16_FLOAT,
R16G16_UINT,
R16G16_SINT,
R16G16_SNORM,
R32G32B32_FLOAT,
A8B8G8R8_SRGB,
R8G8_UNORM,
R8G8_SNORM,
R8G8_SINT,
R8G8_UINT,
R32G32_UINT,
R16G16B16X16_FLOAT,
R32_UINT,
R32_SINT,
ASTC_2D_8X8_UNORM,
ASTC_2D_8X5_UNORM,
ASTC_2D_5X4_UNORM,
B8G8R8A8_SRGB,
BC1_RGBA_SRGB,
BC2_SRGB,
BC3_SRGB,
BC7_SRGB,
A4B4G4R4_UNORM,
G4R4_UNORM,
ASTC_2D_4X4_SRGB,
ASTC_2D_8X8_SRGB,
ASTC_2D_8X5_SRGB,
ASTC_2D_5X4_SRGB,
ASTC_2D_5X5_UNORM,
ASTC_2D_5X5_SRGB,
ASTC_2D_10X8_UNORM,
ASTC_2D_10X8_SRGB,
ASTC_2D_6X6_UNORM,
ASTC_2D_6X6_SRGB,
ASTC_2D_10X6_UNORM,
ASTC_2D_10X6_SRGB,
ASTC_2D_10X5_UNORM,
ASTC_2D_10X5_SRGB,
ASTC_2D_10X10_UNORM,
ASTC_2D_10X10_SRGB,
ASTC_2D_12X10_UNORM,
ASTC_2D_12X10_SRGB,
ASTC_2D_12X12_UNORM,
ASTC_2D_12X12_SRGB,
ASTC_2D_8X6_UNORM,
ASTC_2D_8X6_SRGB,
ASTC_2D_6X5_UNORM,
ASTC_2D_6X5_SRGB,
E5B9G9R9_FLOAT,
D32_FLOAT,
D16_UNORM,
X8_D24_UNORM,
S8_UINT,
D24_UNORM_S8_UINT,
S8_UINT_D24_UNORM,
D32_FLOAT_S8_UINT,
}; };
enum class ImageFormat : u32 { enum class ImageFormat : u32 {
@ -97,6 +192,7 @@ struct ImageBufferDescriptor {
ImageFormat format; ImageFormat format;
bool is_written; bool is_written;
bool is_read; bool is_read;
bool is_integer;
u32 cbuf_index; u32 cbuf_index;
u32 cbuf_offset; u32 cbuf_offset;
u32 count; u32 count;
@ -129,6 +225,7 @@ struct ImageDescriptor {
ImageFormat format; ImageFormat format;
bool is_written; bool is_written;
bool is_read; bool is_read;
bool is_integer;
u32 cbuf_index; u32 cbuf_index;
u32 cbuf_offset; u32 cbuf_offset;
u32 count; u32 count;

View file

@ -51,7 +51,7 @@ using VideoCommon::LoadPipelines;
using VideoCommon::SerializePipeline; using VideoCommon::SerializePipeline;
using Context = ShaderContext::Context; using Context = ShaderContext::Context;
constexpr u32 CACHE_VERSION = 9; constexpr u32 CACHE_VERSION = 10;
template <typename Container> template <typename Container>
auto MakeSpan(Container& container) { auto MakeSpan(Container& container) {

View file

@ -54,7 +54,7 @@ using VideoCommon::FileEnvironment;
using VideoCommon::GenericEnvironment; using VideoCommon::GenericEnvironment;
using VideoCommon::GraphicsEnvironment; using VideoCommon::GraphicsEnvironment;
constexpr u32 CACHE_VERSION = 10; constexpr u32 CACHE_VERSION = 11;
constexpr std::array<char, 8> VULKAN_CACHE_MAGIC_NUMBER{'y', 'u', 'z', 'u', 'v', 'k', 'c', 'h'}; constexpr std::array<char, 8> VULKAN_CACHE_MAGIC_NUMBER{'y', 'u', 'z', 'u', 'v', 'k', 'c', 'h'};
template <typename Container> template <typename Container>

View file

@ -62,23 +62,9 @@ static Shader::TextureType ConvertTextureType(const Tegra::Texture::TICEntry& en
} }
static Shader::TexturePixelFormat ConvertTexturePixelFormat(const Tegra::Texture::TICEntry& entry) { static Shader::TexturePixelFormat ConvertTexturePixelFormat(const Tegra::Texture::TICEntry& entry) {
switch (PixelFormatFromTextureInfo(entry.format, entry.r_type, entry.g_type, entry.b_type, return static_cast<Shader::TexturePixelFormat>(
entry.a_type, entry.srgb_conversion)) { PixelFormatFromTextureInfo(entry.format, entry.r_type, entry.g_type, entry.b_type,
case VideoCore::Surface::PixelFormat::A8B8G8R8_SNORM: entry.a_type, entry.srgb_conversion));
return Shader::TexturePixelFormat::A8B8G8R8_SNORM;
case VideoCore::Surface::PixelFormat::R8_SNORM:
return Shader::TexturePixelFormat::R8_SNORM;
case VideoCore::Surface::PixelFormat::R8G8_SNORM:
return Shader::TexturePixelFormat::R8G8_SNORM;
case VideoCore::Surface::PixelFormat::R16G16B16A16_SNORM:
return Shader::TexturePixelFormat::R16G16B16A16_SNORM;
case VideoCore::Surface::PixelFormat::R16G16_SNORM:
return Shader::TexturePixelFormat::R16G16_SNORM;
case VideoCore::Surface::PixelFormat::R16_SNORM:
return Shader::TexturePixelFormat::R16_SNORM;
default:
return Shader::TexturePixelFormat::OTHER;
}
} }
static std::string_view StageToPrefix(Shader::Stage stage) { static std::string_view StageToPrefix(Shader::Stage stage) {
@ -398,6 +384,11 @@ Shader::TexturePixelFormat GraphicsEnvironment::ReadTexturePixelFormat(u32 handl
return result; return result;
} }
bool GraphicsEnvironment::IsTexturePixelFormatInteger(u32 handle) {
return VideoCore::Surface::IsPixelFormatInteger(
static_cast<VideoCore::Surface::PixelFormat>(ReadTexturePixelFormat(handle)));
}
u32 GraphicsEnvironment::ReadViewportTransformState() { u32 GraphicsEnvironment::ReadViewportTransformState() {
const auto& regs{maxwell3d->regs}; const auto& regs{maxwell3d->regs};
viewport_transform_state = regs.viewport_scale_offset_enabled; viewport_transform_state = regs.viewport_scale_offset_enabled;
@ -448,6 +439,11 @@ Shader::TexturePixelFormat ComputeEnvironment::ReadTexturePixelFormat(u32 handle
return result; return result;
} }
bool ComputeEnvironment::IsTexturePixelFormatInteger(u32 handle) {
return VideoCore::Surface::IsPixelFormatInteger(
static_cast<VideoCore::Surface::PixelFormat>(ReadTexturePixelFormat(handle)));
}
u32 ComputeEnvironment::ReadViewportTransformState() { u32 ComputeEnvironment::ReadViewportTransformState() {
return viewport_transform_state; return viewport_transform_state;
} }
@ -551,6 +547,11 @@ Shader::TexturePixelFormat FileEnvironment::ReadTexturePixelFormat(u32 handle) {
return it->second; return it->second;
} }
bool FileEnvironment::IsTexturePixelFormatInteger(u32 handle) {
return VideoCore::Surface::IsPixelFormatInteger(
static_cast<VideoCore::Surface::PixelFormat>(ReadTexturePixelFormat(handle)));
}
u32 FileEnvironment::ReadViewportTransformState() { u32 FileEnvironment::ReadViewportTransformState() {
return viewport_transform_state; return viewport_transform_state;
} }

View file

@ -115,6 +115,8 @@ public:
Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override; Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override;
bool IsTexturePixelFormatInteger(u32 handle) override;
u32 ReadViewportTransformState() override; u32 ReadViewportTransformState() override;
std::optional<Shader::ReplaceConstant> GetReplaceConstBuffer(u32 bank, u32 offset) override; std::optional<Shader::ReplaceConstant> GetReplaceConstBuffer(u32 bank, u32 offset) override;
@ -139,6 +141,8 @@ public:
Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override; Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override;
bool IsTexturePixelFormatInteger(u32 handle) override;
u32 ReadViewportTransformState() override; u32 ReadViewportTransformState() override;
std::optional<Shader::ReplaceConstant> GetReplaceConstBuffer( std::optional<Shader::ReplaceConstant> GetReplaceConstBuffer(
@ -171,6 +175,8 @@ public:
[[nodiscard]] Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override; [[nodiscard]] Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override;
[[nodiscard]] bool IsTexturePixelFormatInteger(u32 handle) override;
[[nodiscard]] u32 ReadViewportTransformState() override; [[nodiscard]] u32 ReadViewportTransformState() override;
[[nodiscard]] u32 LocalMemorySize() const override; [[nodiscard]] u32 LocalMemorySize() const override;