Browse Source

[shader_recompiler] Added texture type functions

lsfg-android
CamilleLaVey 4 weeks ago
parent
commit
f6ccf2c368
  1. 63
      src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
  2. 3
      src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
  3. 1
      src/shader_recompiler/backend/spirv/spirv_emit_context.h
  4. 7
      src/shader_recompiler/frontend/ir/modifiers.h
  5. 4
      src/shader_recompiler/ir_opt/texture_pass.cpp
  6. 1
      src/shader_recompiler/shader_info.h

63
src/shader_recompiler/backend/spirv/emit_spirv_image.cpp

@ -260,6 +260,13 @@ bool IsTextureMsaa(EmitContext& ctx, const IR::TextureInstInfo& info) {
return ctx.textures.at(info.descriptor_index).is_multisample; return ctx.textures.at(info.descriptor_index).is_multisample;
} }
bool IsTextureInteger(EmitContext& ctx, const IR::TextureInstInfo& info) {
if (info.type == TextureType::Buffer) {
return false;
}
return ctx.textures.at(info.descriptor_index).is_integer;
}
Id Decorate(EmitContext& ctx, IR::Inst* inst, Id sample) { Id Decorate(EmitContext& ctx, IR::Inst* inst, Id sample) {
const auto info{inst->Flags<IR::TextureInstInfo>()}; const auto info{inst->Flags<IR::TextureInstInfo>()};
if (info.relaxed_precision != 0) { if (info.relaxed_precision != 0) {
@ -480,11 +487,14 @@ Id EmitBoundImageWrite(EmitContext&) {
Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
Id bias_lc, const IR::Value& offset) { Id bias_lc, const IR::Value& offset) {
const auto info{inst->Flags<IR::TextureInstInfo>()}; const auto info{inst->Flags<IR::TextureInstInfo>()};
const bool is_integer{IsTextureInteger(ctx, info)};
const Id result_type{is_integer ? ctx.U32[4] : ctx.F32[4]};
Id color;
if (ctx.stage == Stage::Fragment) { if (ctx.stage == Stage::Fragment) {
const ImageOperands operands(ctx, info.has_bias != 0, false, info.has_lod_clamp != 0, const ImageOperands operands(ctx, info.has_bias != 0, false, info.has_lod_clamp != 0,
bias_lc, offset); bias_lc, offset);
return Emit(&EmitContext::OpImageSparseSampleImplicitLod,
&EmitContext::OpImageSampleImplicitLod, ctx, inst, ctx.F32[4],
color = Emit(&EmitContext::OpImageSparseSampleImplicitLod,
&EmitContext::OpImageSampleImplicitLod, ctx, inst, result_type,
Texture(ctx, info, index), coords, operands.MaskOptional(), operands.Span()); Texture(ctx, info, index), coords, operands.MaskOptional(), operands.Span());
} else { } else {
// We can't use implicit lods on non-fragment stages on SPIR-V. Maxwell hardware behaves as // We can't use implicit lods on non-fragment stages on SPIR-V. Maxwell hardware behaves as
@ -492,26 +502,29 @@ Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value&
// derivatives // derivatives
const Id lod{ctx.Const(0.0f)}; const Id lod{ctx.Const(0.0f)};
const ImageOperands operands(ctx, false, true, info.has_lod_clamp != 0, lod, offset); const ImageOperands operands(ctx, false, true, info.has_lod_clamp != 0, lod, offset);
return Emit(&EmitContext::OpImageSparseSampleExplicitLod,
&EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4],
color = Emit(&EmitContext::OpImageSparseSampleExplicitLod,
&EmitContext::OpImageSampleExplicitLod, ctx, inst, result_type,
Texture(ctx, info, index), coords, operands.Mask(), operands.Span()); Texture(ctx, info, index), coords, operands.Mask(), operands.Span());
} }
return is_integer ? ctx.OpBitcast(ctx.F32[4], color) : color;
} }
Id EmitImageSampleExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id EmitImageSampleExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
Id lod, const IR::Value& offset) { Id lod, const IR::Value& offset) {
const auto info{inst->Flags<IR::TextureInstInfo>()}; const auto info{inst->Flags<IR::TextureInstInfo>()};
const bool is_integer{IsTextureInteger(ctx, info)};
const Id result_type{is_integer ? ctx.U32[4] : ctx.F32[4]};
const ImageOperands operands(ctx, false, true, false, lod, offset); const ImageOperands operands(ctx, false, true, false, lod, offset);
Id result = Emit(&EmitContext::OpImageSparseSampleExplicitLod, Id result = Emit(&EmitContext::OpImageSparseSampleExplicitLod,
&EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4],
&EmitContext::OpImageSampleExplicitLod, ctx, inst, result_type,
Texture(ctx, info, index), coords, operands.Mask(), operands.Span()); Texture(ctx, info, index), coords, operands.Mask(), operands.Span());
#ifdef __ANDROID__ #ifdef __ANDROID__
if (Settings::values.fix_bloom_effects.GetValue()) {
if (!is_integer && Settings::values.fix_bloom_effects.GetValue()) {
result = ctx.OpVectorTimesScalar(ctx.F32[4], result, ctx.Const(0.98f)); result = ctx.OpVectorTimesScalar(ctx.F32[4], result, ctx.Const(0.98f));
} }
#endif #endif
return result;
return is_integer ? ctx.OpBitcast(ctx.F32[4], result) : result;
} }
Id EmitImageSampleDrefImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id EmitImageSampleDrefImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index,
@ -547,30 +560,39 @@ Id EmitImageSampleDrefExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Va
Id EmitImageGather(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id EmitImageGather(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
const IR::Value& offset, const IR::Value& offset2) { const IR::Value& offset, const IR::Value& offset2) {
const auto info{inst->Flags<IR::TextureInstInfo>()}; const auto info{inst->Flags<IR::TextureInstInfo>()};
const bool is_integer{IsTextureInteger(ctx, info)};
const Id result_type{is_integer ? ctx.U32[4] : ctx.F32[4]};
const ImageOperands operands(ctx, offset, offset2); const ImageOperands operands(ctx, offset, offset2);
if (ctx.profile.need_gather_subpixel_offset) { if (ctx.profile.need_gather_subpixel_offset) {
coords = ImageGatherSubpixelOffset(ctx, info, TextureImage(ctx, info, index), coords); coords = ImageGatherSubpixelOffset(ctx, info, TextureImage(ctx, info, index), coords);
} }
return Emit(&EmitContext::OpImageSparseGather, &EmitContext::OpImageGather, ctx, inst,
ctx.F32[4], Texture(ctx, info, index), coords, ctx.Const(info.gather_component),
operands.MaskOptional(), operands.Span());
const Id color{Emit(&EmitContext::OpImageSparseGather, &EmitContext::OpImageGather, ctx, inst,
result_type, Texture(ctx, info, index), coords,
ctx.Const(info.gather_component), operands.MaskOptional(),
operands.Span())};
return is_integer ? ctx.OpBitcast(ctx.F32[4], color) : color;
} }
Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
const IR::Value& offset, const IR::Value& offset2, Id dref) { const IR::Value& offset, const IR::Value& offset2, Id dref) {
const auto info{inst->Flags<IR::TextureInstInfo>()}; const auto info{inst->Flags<IR::TextureInstInfo>()};
const bool is_integer{IsTextureInteger(ctx, info)};
const Id result_type{is_integer ? ctx.U32[4] : ctx.F32[4]};
const ImageOperands operands(ctx, offset, offset2); const ImageOperands operands(ctx, offset, offset2);
if (ctx.profile.need_gather_subpixel_offset) { if (ctx.profile.need_gather_subpixel_offset) {
coords = ImageGatherSubpixelOffset(ctx, info, TextureImage(ctx, info, index), coords); coords = ImageGatherSubpixelOffset(ctx, info, TextureImage(ctx, info, index), coords);
} }
return Emit(&EmitContext::OpImageSparseDrefGather, &EmitContext::OpImageDrefGather, ctx, inst,
ctx.F32[4], Texture(ctx, info, index), coords, dref, operands.MaskOptional(),
operands.Span());
const Id color{Emit(&EmitContext::OpImageSparseDrefGather, &EmitContext::OpImageDrefGather,
ctx, inst, result_type, Texture(ctx, info, index), coords, dref,
operands.MaskOptional(), operands.Span())};
return is_integer ? ctx.OpBitcast(ctx.F32[4], color) : color;
} }
Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset, Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset,
Id lod, Id ms) { Id lod, Id ms) {
const auto info{inst->Flags<IR::TextureInstInfo>()}; const auto info{inst->Flags<IR::TextureInstInfo>()};
const bool is_integer{IsTextureInteger(ctx, info)};
const Id result_type{is_integer ? ctx.U32[4] : ctx.F32[4]};
AddOffsetToCoordinates(ctx, info, coords, offset); AddOffsetToCoordinates(ctx, info, coords, offset);
if (info.type == TextureType::Buffer) { if (info.type == TextureType::Buffer) {
lod = Id{}; lod = Id{};
@ -580,8 +602,10 @@ Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id c
lod = Id{}; lod = Id{};
} }
const ImageOperands operands(lod, ms); const ImageOperands operands(lod, ms);
return Emit(&EmitContext::OpImageSparseFetch, &EmitContext::OpImageFetch, ctx, inst, ctx.F32[4],
TextureImage(ctx, info, index), coords, operands.MaskOptional(), operands.Span());
const Id color{Emit(&EmitContext::OpImageSparseFetch, &EmitContext::OpImageFetch, ctx, inst,
result_type, TextureImage(ctx, info, index), coords,
operands.MaskOptional(), operands.Span())};
return is_integer ? ctx.OpBitcast(ctx.F32[4], color) : color;
} }
Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod, Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod,
@ -626,14 +650,17 @@ Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, I
Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
Id derivatives, const IR::Value& offset, Id lod_clamp) { Id derivatives, const IR::Value& offset, Id lod_clamp) {
const auto info{inst->Flags<IR::TextureInstInfo>()}; const auto info{inst->Flags<IR::TextureInstInfo>()};
const bool is_integer{IsTextureInteger(ctx, info)};
const Id result_type{is_integer ? ctx.U32[4] : ctx.F32[4]};
const auto operands = info.num_derivatives == 3 const auto operands = info.num_derivatives == 3
? ImageOperands(ctx, info.has_lod_clamp != 0, derivatives, ? ImageOperands(ctx, info.has_lod_clamp != 0, derivatives,
ctx.Def(offset), {}, lod_clamp) ctx.Def(offset), {}, lod_clamp)
: ImageOperands(ctx, info.has_lod_clamp != 0, derivatives, : ImageOperands(ctx, info.has_lod_clamp != 0, derivatives,
info.num_derivatives, offset, lod_clamp); info.num_derivatives, offset, lod_clamp);
return Emit(&EmitContext::OpImageSparseSampleExplicitLod,
&EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4],
Texture(ctx, info, index), coords, operands.Mask(), operands.Span());
const Id color{Emit(&EmitContext::OpImageSparseSampleExplicitLod,
&EmitContext::OpImageSampleExplicitLod, ctx, inst, result_type,
Texture(ctx, info, index), coords, operands.Mask(), operands.Span())};
return is_integer ? ctx.OpBitcast(ctx.F32[4], color) : color;
} }
Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords) { Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords) {

3
src/shader_recompiler/backend/spirv/spirv_emit_context.cpp

@ -30,7 +30,7 @@ enum class Operation {
Id ImageType(EmitContext& ctx, const TextureDescriptor& desc) { Id ImageType(EmitContext& ctx, const TextureDescriptor& desc) {
const spv::ImageFormat format{spv::ImageFormat::Unknown}; const spv::ImageFormat format{spv::ImageFormat::Unknown};
const Id type{ctx.F32[1]};
const Id type{desc.is_integer ? ctx.U32[1] : ctx.F32[1]};
const bool depth{desc.is_depth}; const bool depth{desc.is_depth};
const bool ms{desc.is_multisample}; const bool ms{desc.is_multisample};
switch (desc.type) { switch (desc.type) {
@ -1375,6 +1375,7 @@ void EmitContext::DefineTextures(const Info& info, u32& binding, u32& scaling_in
.image_type = image_type, .image_type = image_type,
.count = desc.count, .count = desc.count,
.is_multisample = desc.is_multisample, .is_multisample = desc.is_multisample,
.is_integer = desc.is_integer,
}); });
if (profile.supported_spirv >= 0x00010400) { if (profile.supported_spirv >= 0x00010400) {
interfaces.push_back(id); interfaces.push_back(id);

1
src/shader_recompiler/backend/spirv/spirv_emit_context.h

@ -42,6 +42,7 @@ struct TextureDefinition {
Id image_type; Id image_type;
u32 count; u32 count;
bool is_multisample; bool is_multisample;
bool is_integer;
}; };
struct TextureBufferDefinition { struct TextureBufferDefinition {

7
src/shader_recompiler/frontend/ir/modifiers.h

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -43,6 +46,10 @@ union TextureInstInfo {
BitField<25, 2, u32> num_derivatives; BitField<25, 2, u32> num_derivatives;
BitField<27, 3, ImageFormat> image_format; BitField<27, 3, ImageFormat> image_format;
BitField<30, 1, u32> ndv_is_active; BitField<30, 1, u32> ndv_is_active;
/// Only meaningful for the sampled-texture family (ImageSampleImplicitLod, ImageFetch,
/// ImageGather, etc.); unused/zero for storage-image opcodes, which carry their own
/// is_integer via ImageDescriptor/ImageBufferDescriptor instead.
BitField<31, 1, u32> is_integer;
}; };
static_assert(sizeof(TextureInstInfo) <= sizeof(u32)); static_assert(sizeof(TextureInstInfo) <= sizeof(u32));

4
src/shader_recompiler/ir_opt/texture_pass.cpp

@ -562,6 +562,7 @@ public:
})}; })};
// TODO: Read this from TIC // TODO: Read this from TIC
texture_descriptors[index].is_multisample |= desc.is_multisample; texture_descriptors[index].is_multisample |= desc.is_multisample;
texture_descriptors[index].is_integer |= desc.is_integer;
return index; return index;
} }
@ -791,10 +792,12 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
}); });
} else { } else {
count = std::min(count, sampled_dynamic_cap); count = std::min(count, sampled_dynamic_cap);
const bool is_integer{IsTexturePixelFormatIntegerCached(env, cbuf)};
index = descriptors.Add(TextureDescriptor{ index = descriptors.Add(TextureDescriptor{
.type = flags.type, .type = flags.type,
.is_depth = flags.is_depth != 0, .is_depth = flags.is_depth != 0,
.is_multisample = is_multisample, .is_multisample = is_multisample,
.is_integer = is_integer,
.has_secondary = cbuf.has_secondary, .has_secondary = cbuf.has_secondary,
.cbuf_index = cbuf.index, .cbuf_index = cbuf.index,
.cbuf_offset = cbuf.offset, .cbuf_offset = cbuf.offset,
@ -805,6 +808,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
.count = count, .count = count,
.size_shift = size_shift, .size_shift = size_shift,
}); });
flags.is_integer.Assign(is_integer ? 1 : 0);
} }
break; break;
} }

1
src/shader_recompiler/shader_info.h

@ -209,6 +209,7 @@ struct TextureDescriptor {
TextureType type; TextureType type;
bool is_depth; bool is_depth;
bool is_multisample; bool is_multisample;
bool is_integer;
bool has_secondary; bool has_secondary;
u32 cbuf_index; u32 cbuf_index;
u32 cbuf_offset; u32 cbuf_offset;

Loading…
Cancel
Save