video_core: Implement conversion for uncommon/unsupported number formats.

This commit is contained in:
squidbus 2025-01-04 05:48:55 -08:00
parent c3ecf599ad
commit 331ae6c2e5
8 changed files with 129 additions and 8 deletions

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "shader_recompiler/frontend/translate/translate.h"
#include "shader_recompiler/ir/reinterpret.h"
#include "shader_recompiler/runtime_info.h"
namespace Shader::Gcn {
@ -31,14 +32,16 @@ void Translator::EmitExport(const GcnInst& inst) {
return;
}
const u32 index = u32(attrib) - u32(IR::Attribute::RenderTarget0);
const auto [r, g, b, a] = runtime_info.fs_info.color_buffers[index].swizzle;
const auto col_buf = runtime_info.fs_info.color_buffers[index];
const auto converted = IR::ApplyWriteNumberConversion(ir, value, col_buf.num_conversion);
const auto [r, g, b, a] = col_buf.swizzle;
const std::array swizzle_array = {r, g, b, a};
const auto swizzled_comp = swizzle_array[comp];
if (u32(swizzled_comp) < u32(AmdGpu::CompSwizzle::Red)) {
ir.SetAttribute(attrib, value, comp);
ir.SetAttribute(attrib, converted, comp);
return;
}
ir.SetAttribute(attrib, value, u32(swizzled_comp) - u32(AmdGpu::CompSwizzle::Red));
ir.SetAttribute(attrib, converted, u32(swizzled_comp) - u32(AmdGpu::CompSwizzle::Red));
};
const auto unpack = [&](u32 idx) {

View File

@ -753,12 +753,17 @@ void PatchTextureBufferInterpretation(IR::Block& block, IR::Inst& inst, Info& in
IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
if (inst.GetOpcode() == IR::Opcode::StoreBufferFormatF32) {
inst.SetArg(2, ApplySwizzle(ir, inst.Arg(2), buffer.DstSelect()));
const auto swizzled = ApplySwizzle(ir, inst.Arg(2), buffer.DstSelect());
const auto converted =
ApplyWriteNumberConversionVec4(ir, swizzled, buffer.GetNumberConversion());
inst.SetArg(2, converted);
} else if (inst.GetOpcode() == IR::Opcode::LoadBufferFormatF32) {
const auto inst_info = inst.Flags<IR::BufferInstInfo>();
const auto texel = ir.LoadBufferFormat(inst.Arg(0), inst.Arg(1), inst_info);
const auto swizzled = ApplySwizzle(ir, texel, buffer.DstSelect());
inst.ReplaceUsesWith(swizzled);
const auto converted =
ApplyReadNumberConversionVec4(ir, swizzled, buffer.GetNumberConversion());
inst.ReplaceUsesWith(converted);
}
}
@ -773,7 +778,10 @@ void PatchImageInterpretation(IR::Block& block, IR::Inst& inst, Info& info) {
IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
if (inst.GetOpcode() == IR::Opcode::ImageWrite) {
inst.SetArg(4, ApplySwizzle(ir, inst.Arg(4), image.DstSelect()));
const auto swizzled = ApplySwizzle(ir, inst.Arg(4), image.DstSelect());
const auto converted =
ApplyWriteNumberConversionVec4(ir, swizzled, image.GetNumberConversion());
inst.SetArg(4, converted);
} else if (inst.GetOpcode() == IR::Opcode::ImageRead) {
const auto inst_info = inst.Flags<IR::TextureInstInfo>();
const auto lod = inst.Arg(2);
@ -782,7 +790,9 @@ void PatchImageInterpretation(IR::Block& block, IR::Inst& inst, Info& info) {
ir.ImageRead(inst.Arg(0), inst.Arg(1), lod.IsEmpty() ? IR::U32{} : IR::U32{lod},
ms.IsEmpty() ? IR::U32{} : IR::U32{ms}, inst_info);
const auto swizzled = ApplySwizzle(ir, texel, image.DstSelect());
inst.ReplaceUsesWith(swizzled);
const auto converted =
ApplyReadNumberConversionVec4(ir, swizzled, image.GetNumberConversion());
inst.ReplaceUsesWith(converted);
}
}

View File

@ -21,4 +21,66 @@ inline Value ApplySwizzle(IREmitter& ir, const Value& vector, const AmdGpu::Comp
return swizzled;
}
/// Applies a number conversion in the read direction.
inline F32 ApplyReadNumberConversion(IREmitter& ir, const F32& value,
const AmdGpu::NumberConversion& conversion) {
switch (conversion) {
case AmdGpu::NumberConversion::None:
return value;
case AmdGpu::NumberConversion::UintToUscaled:
return ir.ConvertUToF(32, 32, value);
case AmdGpu::NumberConversion::SintToSscaled:
return ir.ConvertSToF(32, 32, value);
case AmdGpu::NumberConversion::UnormToUbnorm:
// Convert 0...1 to -1...1
return ir.FPSub(ir.FPMul(value, ir.Imm32(2.f)), ir.Imm32(1.f));
default:
UNREACHABLE();
}
}
inline Value ApplyReadNumberConversionVec4(IREmitter& ir, const Value& value,
const AmdGpu::NumberConversion& conversion) {
if (conversion == AmdGpu::NumberConversion::None) {
return value;
}
const auto x = ApplyReadNumberConversion(ir, F32{ir.CompositeExtract(value, 0)}, conversion);
const auto y = ApplyReadNumberConversion(ir, F32{ir.CompositeExtract(value, 1)}, conversion);
const auto z = ApplyReadNumberConversion(ir, F32{ir.CompositeExtract(value, 2)}, conversion);
const auto w = ApplyReadNumberConversion(ir, F32{ir.CompositeExtract(value, 3)}, conversion);
return ir.CompositeConstruct(x, y, z, w);
}
/// Applies a number conversion in the write direction.
inline F32 ApplyWriteNumberConversion(IREmitter& ir, const F32& value,
const AmdGpu::NumberConversion& conversion) {
switch (conversion) {
case AmdGpu::NumberConversion::None:
return value;
case AmdGpu::NumberConversion::UintToUscaled:
// Need to return float type to maintain IR semantics.
return ir.BitCast<F32>(U32{ir.ConvertFToU(32, value)});
case AmdGpu::NumberConversion::SintToSscaled:
// Need to return float type to maintain IR semantics.
return ir.BitCast<F32>(U32{ir.ConvertFToS(32, value)});
case AmdGpu::NumberConversion::UnormToUbnorm:
// Convert -1...1 to 0...1
return ir.FPDiv(ir.FPAdd(value, ir.Imm32(1.f)), ir.Imm32(2.f));
default:
UNREACHABLE();
}
}
inline Value ApplyWriteNumberConversionVec4(IREmitter& ir, const Value& value,
const AmdGpu::NumberConversion& conversion) {
if (conversion == AmdGpu::NumberConversion::None) {
return value;
}
const auto x = ApplyWriteNumberConversion(ir, F32{ir.CompositeExtract(value, 0)}, conversion);
const auto y = ApplyWriteNumberConversion(ir, F32{ir.CompositeExtract(value, 1)}, conversion);
const auto z = ApplyWriteNumberConversion(ir, F32{ir.CompositeExtract(value, 2)}, conversion);
const auto w = ApplyWriteNumberConversion(ir, F32{ir.CompositeExtract(value, 3)}, conversion);
return ir.CompositeConstruct(x, y, z, w);
}
} // namespace Shader::IR

View File

@ -180,6 +180,7 @@ struct FragmentRuntimeInfo {
std::array<PsInput, 32> inputs;
struct PsColorBuffer {
AmdGpu::NumberFormat num_format;
AmdGpu::NumberConversion num_conversion;
AmdGpu::CompMapping swizzle;
auto operator<=>(const PsColorBuffer&) const noexcept = default;

View File

@ -902,6 +902,10 @@ struct Liverpool {
: info.number_type.Value());
}
[[nodiscard]] NumberConversion GetNumberConversion() const {
return MapNumberConversion(info.number_type);
}
[[nodiscard]] CompMapping Swizzle() const {
// clang-format off
static constexpr std::array<std::array<CompMapping, 4>, 4> mrt_swizzles{{

View File

@ -74,7 +74,16 @@ inline DataFormat RemapDataFormat(const DataFormat format) {
}
inline NumberFormat RemapNumberFormat(const NumberFormat format) {
return format;
switch (format) {
case NumberFormat::Uscaled:
return NumberFormat::Uint;
case NumberFormat::Sscaled:
return NumberFormat::Sint;
case NumberFormat::Ubnorm:
return NumberFormat::Unorm;
default:
return format;
}
}
inline CompMapping RemapComponents(const DataFormat format, const CompMapping components) {
@ -101,6 +110,26 @@ inline CompMapping RemapComponents(const DataFormat format, const CompMapping co
}
}
enum NumberConversion {
None,
UintToUscaled,
SintToSscaled,
UnormToUbnorm,
};
inline NumberConversion MapNumberConversion(const NumberFormat format) {
switch (format) {
case NumberFormat::Uscaled:
return UintToUscaled;
case NumberFormat::Sscaled:
return SintToSscaled;
case NumberFormat::Ubnorm:
return UnormToUbnorm;
default:
return None;
}
}
// Table 8.5 Buffer Resource Descriptor [Sea Islands Series Instruction Set Architecture]
struct Buffer {
u64 base_address : 44;
@ -151,6 +180,10 @@ struct Buffer {
return RemapDataFormat(DataFormat(data_format));
}
NumberConversion GetNumberConversion() const noexcept {
return MapNumberConversion(NumberFormat(num_format));
}
u32 GetStride() const noexcept {
return stride;
}
@ -354,6 +387,10 @@ struct Image {
return RemapNumberFormat(NumberFormat(num_format));
}
NumberConversion GetNumberConversion() const noexcept {
return MapNumberConversion(NumberFormat(num_format));
}
TilingMode GetTilingMode() const {
if (tiling_index >= 0 && tiling_index <= 7) {
return tiling_index == 5 ? TilingMode::Texture_MicroTiled

View File

@ -32,6 +32,7 @@ struct GraphicsPipelineKey {
u32 num_color_attachments;
std::array<vk::Format, Liverpool::NumColorBuffers> color_formats;
std::array<AmdGpu::NumberFormat, Liverpool::NumColorBuffers> color_num_formats;
std::array<AmdGpu::NumberConversion, Liverpool::NumColorBuffers> color_num_conversions;
std::array<AmdGpu::CompMapping, Liverpool::NumColorBuffers> color_swizzles;
vk::Format depth_format;
vk::Format stencil_format;

View File

@ -168,6 +168,7 @@ const Shader::RuntimeInfo& PipelineCache::BuildRuntimeInfo(Stage stage, LogicalS
for (u32 i = 0; i < Shader::MaxColorBuffers; i++) {
info.fs_info.color_buffers[i] = {
.num_format = graphics_key.color_num_formats[i],
.num_conversion = graphics_key.color_num_conversions[i],
.swizzle = graphics_key.color_swizzles[i],
};
}
@ -302,6 +303,7 @@ bool PipelineCache::RefreshGraphicsKey() {
key.num_color_attachments = 0;
key.color_formats.fill(vk::Format::eUndefined);
key.color_num_formats.fill(AmdGpu::NumberFormat::Unorm);
key.color_num_conversions.fill(AmdGpu::NumberConversion::None);
key.blend_controls.fill({});
key.write_masks.fill({});
key.color_swizzles.fill({});
@ -330,6 +332,7 @@ bool PipelineCache::RefreshGraphicsKey() {
key.color_formats[remapped_cb] =
LiverpoolToVK::SurfaceFormat(col_buf.GetDataFmt(), col_buf.GetNumberFmt());
key.color_num_formats[remapped_cb] = col_buf.GetNumberFmt();
key.color_num_conversions[remapped_cb] = col_buf.GetNumberConversion();
key.color_swizzles[remapped_cb] = col_buf.Swizzle();
}