renderer_vulkan: Rework MRT swizzles and add unsupported format swizzle support.

This commit is contained in:
squidbus 2024-12-25 05:26:46 -08:00
parent 8a006a2bc6
commit 4e6a7e555e
12 changed files with 126 additions and 141 deletions

View File

@ -25,34 +25,28 @@ void Translator::EmitExport(const GcnInst& inst) {
IR::VectorReg(inst.src[3].code), IR::VectorReg(inst.src[3].code),
}; };
const auto swizzle = [&](u32 comp) { const auto set_attribute = [&](u32 comp, IR::F32 value) {
if (!IR::IsMrt(attrib)) { if (!IR::IsMrt(attrib)) {
return comp; ir.SetAttribute(attrib, value, comp);
return;
} }
const u32 index = u32(attrib) - u32(IR::Attribute::RenderTarget0); const u32 index = u32(attrib) - u32(IR::Attribute::RenderTarget0);
switch (runtime_info.fs_info.color_buffers[index].mrt_swizzle) { const auto [r, g, b, a] = runtime_info.fs_info.color_buffers[index].swizzle;
case MrtSwizzle::Identity: const std::array swizzle_array = {r, g, b, a};
return comp; const auto swizzled_comp = swizzle_array[comp];
case MrtSwizzle::Alt: if (u32(swizzled_comp) < u32(AmdGpu::CompSwizzle::Red)) {
static constexpr std::array<u32, 4> AltSwizzle = {2, 1, 0, 3}; ir.SetAttribute(attrib, value, comp);
return AltSwizzle[comp]; return;
case MrtSwizzle::Reverse:
static constexpr std::array<u32, 4> RevSwizzle = {3, 2, 1, 0};
return RevSwizzle[comp];
case MrtSwizzle::ReverseAlt:
static constexpr std::array<u32, 4> AltRevSwizzle = {3, 0, 1, 2};
return AltRevSwizzle[comp];
default:
UNREACHABLE();
} }
ir.SetAttribute(attrib, value, u32(swizzled_comp) - u32(AmdGpu::CompSwizzle::Red));
}; };
const auto unpack = [&](u32 idx) { const auto unpack = [&](u32 idx) {
const IR::Value value = ir.UnpackHalf2x16(ir.GetVectorReg(vsrc[idx])); const IR::Value value = ir.UnpackHalf2x16(ir.GetVectorReg(vsrc[idx]));
const IR::F32 r = IR::F32{ir.CompositeExtract(value, 0)}; const IR::F32 r = IR::F32{ir.CompositeExtract(value, 0)};
const IR::F32 g = IR::F32{ir.CompositeExtract(value, 1)}; const IR::F32 g = IR::F32{ir.CompositeExtract(value, 1)};
ir.SetAttribute(attrib, r, swizzle(idx * 2)); set_attribute(idx * 2, r);
ir.SetAttribute(attrib, g, swizzle(idx * 2 + 1)); set_attribute(idx * 2 + 1, g);
}; };
// Components are float16 packed into a VGPR // Components are float16 packed into a VGPR
@ -73,7 +67,7 @@ void Translator::EmitExport(const GcnInst& inst) {
continue; continue;
} }
const IR::F32 comp = ir.GetVectorReg<IR::F32>(vsrc[i]); const IR::F32 comp = ir.GetVectorReg<IR::F32>(vsrc[i]);
ir.SetAttribute(attrib, comp, swizzle(i)); set_attribute(i, comp);
} }
} }
if (IR::IsMrt(attrib)) { if (IR::IsMrt(attrib)) {

View File

@ -475,29 +475,12 @@ void Translator::EmitFetch(const GcnInst& inst) {
// Read the V# of the attribute to figure out component number and type. // Read the V# of the attribute to figure out component number and type.
const auto buffer = info.ReadUdReg<AmdGpu::Buffer>(attrib.sgpr_base, attrib.dword_offset); const auto buffer = info.ReadUdReg<AmdGpu::Buffer>(attrib.sgpr_base, attrib.dword_offset);
const auto comp = [&](AmdGpu::CompSwizzle swizzle) -> IR::F32 { const std::array components = buffer.DstSelect().Apply<IR::F32>(
switch (swizzle) { [&](const u32 index) { return ir.GetAttribute(attr, index); },
case AmdGpu::CompSwizzle::One: [&](const u32 imm) { return ir.Imm32(float(imm)); });
return ir.Imm32(1.f); for (u32 i = 0; i < components.size(); i++) {
case AmdGpu::CompSwizzle::Zero: ir.SetVectorReg(dst_reg++, components[i]);
return ir.Imm32(0.f); }
case AmdGpu::CompSwizzle::Red:
return ir.GetAttribute(attr, 0);
case AmdGpu::CompSwizzle::Green:
return ir.GetAttribute(attr, 1);
case AmdGpu::CompSwizzle::Blue:
return ir.GetAttribute(attr, 2);
case AmdGpu::CompSwizzle::Alpha:
return ir.GetAttribute(attr, 3);
default:
UNREACHABLE();
}
};
const auto [r, g, b, a] = buffer.DstSelect();
ir.SetVectorReg(dst_reg++, comp(r));
ir.SetVectorReg(dst_reg++, comp(g));
ir.SetVectorReg(dst_reg++, comp(b));
ir.SetVectorReg(dst_reg++, comp(a));
// In case of programmable step rates we need to fallback to instance data pulling in // In case of programmable step rates we need to fallback to instance data pulling in
// shader, so VBs should be bound as regular data buffers // shader, so VBs should be bound as regular data buffers

View File

@ -129,26 +129,10 @@ bool IsImageInstruction(const IR::Inst& inst) {
} }
IR::Value SwizzleVector(IR::IREmitter& ir, auto sharp, IR::Value texel) { IR::Value SwizzleVector(IR::IREmitter& ir, auto sharp, IR::Value texel) {
const auto comp = [&](AmdGpu::CompSwizzle swizzle) -> IR::Value { const std::array components = sharp.DstSelect().template Apply<IR::Value>(
switch (swizzle) { [&](const u32 index) { return ir.CompositeExtract(texel, index); },
case AmdGpu::CompSwizzle::Zero: [&](const u32 imm) { return ir.Imm32(float(imm)); });
return ir.Imm32(0.f); return ir.CompositeConstruct(components[0], components[1], components[2], components[3]);
case AmdGpu::CompSwizzle::One:
return ir.Imm32(1.f);
case AmdGpu::CompSwizzle::Red:
return ir.CompositeExtract(texel, 0);
case AmdGpu::CompSwizzle::Green:
return ir.CompositeExtract(texel, 1);
case AmdGpu::CompSwizzle::Blue:
return ir.CompositeExtract(texel, 2);
case AmdGpu::CompSwizzle::Alpha:
return ir.CompositeExtract(texel, 3);
default:
UNREACHABLE();
}
};
const auto [r, g, b, a] = sharp.DstSelect();
return ir.CompositeConstruct(comp(r), comp(g), comp(b), comp(a));
}; };
class Descriptors { class Descriptors {

View File

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

View File

@ -889,10 +889,54 @@ struct Liverpool {
return !info.linear_general; return !info.linear_general;
} }
NumberFormat NumFormat() const { [[nodiscard]] DataFormat DataFormat() const {
return RemapDataFormat(info.format);
}
[[nodiscard]] NumberFormat NumFormat() const {
// There is a small difference between T# and CB number types, account for it. // There is a small difference between T# and CB number types, account for it.
return info.number_type == AmdGpu::NumberFormat::SnormNz ? AmdGpu::NumberFormat::Srgb return RemapNumberFormat(info.number_type == NumberFormat::SnormNz
: info.number_type.Value(); ? NumberFormat::Srgb
: info.number_type.Value());
}
[[nodiscard]] CompMapping Swizzle() const {
// clang-format off
static constexpr std::array<std::array<CompMapping, 4>, 4> mrt_swizzles{{
// Standard
std::array<CompMapping, 4>{{
{.r = CompSwizzle::Red, .g = CompSwizzle::Zero, .b = CompSwizzle::Zero, .a = CompSwizzle::Zero},
{.r = CompSwizzle::Red, .g = CompSwizzle::Green, .b = CompSwizzle::Zero, .a = CompSwizzle::Zero},
{.r = CompSwizzle::Red, .g = CompSwizzle::Green, .b = CompSwizzle::Blue, .a = CompSwizzle::Zero},
{.r = CompSwizzle::Red, .g = CompSwizzle::Green, .b = CompSwizzle::Blue, .a = CompSwizzle::Alpha},
}},
// Alternate
std::array<CompMapping, 4>{{
{.r = CompSwizzle::Zero, .g = CompSwizzle::Red, .b = CompSwizzle::Zero, .a = CompSwizzle::Zero},
{.r = CompSwizzle::Red, .g = CompSwizzle::Zero, .b = CompSwizzle::Zero, .a = CompSwizzle::Green},
{.r = CompSwizzle::Red, .g = CompSwizzle::Green, .b = CompSwizzle::Zero, .a = CompSwizzle::Blue},
{.r = CompSwizzle::Blue, .g = CompSwizzle::Green, .b = CompSwizzle::Red, .a = CompSwizzle::Alpha},
}},
// StandardReverse
std::array<CompMapping, 4>{{
{CompSwizzle::Zero, CompSwizzle::Zero, CompSwizzle::Red, CompSwizzle::Zero},
{CompSwizzle::Green, CompSwizzle::Red, CompSwizzle::Zero, CompSwizzle::Zero},
{CompSwizzle::Blue, CompSwizzle::Green, CompSwizzle::Red, CompSwizzle::Zero},
{CompSwizzle::Alpha, CompSwizzle::Blue, CompSwizzle::Green, CompSwizzle::Red},
}},
// AlternateReverse
std::array<CompMapping, 4>{{
{CompSwizzle::Zero, CompSwizzle::Zero, CompSwizzle::Zero, CompSwizzle::Red},
{CompSwizzle::Green, CompSwizzle::Zero, CompSwizzle::Zero, CompSwizzle::Red},
{CompSwizzle::Blue, CompSwizzle::Green, CompSwizzle::Zero, CompSwizzle::Red},
{CompSwizzle::Alpha, CompSwizzle::Red, CompSwizzle::Green, CompSwizzle::Blue},
}},
}};
// clang-format on
const auto swap_idx = static_cast<u32>(info.comp_swap.Value());
const auto components_idx = NumComponents(info.format) - 1;
const auto mrt_swizzle = mrt_swizzles[swap_idx][components_idx];
return RemapComponents(info.format, mrt_swizzle);
} }
}; };

View File

@ -3,6 +3,7 @@
#pragma once #pragma once
#include <functional>
#include "common/alignment.h" #include "common/alignment.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/bit_field.h" #include "common/bit_field.h"
@ -27,6 +28,45 @@ struct CompMapping {
CompSwizzle a : 3; CompSwizzle a : 3;
auto operator<=>(const CompMapping& other) const = default; auto operator<=>(const CompMapping& other) const = default;
template <typename T>
[[nodiscard]] std::array<T, 4> Apply(const std::array<T, 4>& data) const {
return Apply<T>([&data](const u32 index) { return data[index]; },
[](const u32 imm) { return T(imm); });
}
template <typename T>
[[nodiscard]] std::array<T, 4> Apply(const std::function<T(u32)>& get_value,
const std::function<T(u32)>& get_immediate) const {
return {
ApplySingle(get_value, get_immediate, r),
ApplySingle(get_value, get_immediate, g),
ApplySingle(get_value, get_immediate, b),
ApplySingle(get_value, get_immediate, a),
};
}
private:
template <typename T>
T ApplySingle(const std::function<T(u32)>& get_value,
const std::function<T(u32)>& get_immediate, const CompSwizzle swizzle) const {
switch (swizzle) {
case CompSwizzle::Zero:
return get_immediate(0);
case CompSwizzle::One:
return get_immediate(1);
case CompSwizzle::Red:
return get_value(0);
case CompSwizzle::Green:
return get_value(1);
case CompSwizzle::Blue:
return get_value(2);
case CompSwizzle::Alpha:
return get_value(3);
default:
UNREACHABLE();
}
}
}; };
inline DataFormat RemapDataFormat(const DataFormat format) { inline DataFormat RemapDataFormat(const DataFormat format) {

View File

@ -707,31 +707,6 @@ vk::Format SurfaceFormat(AmdGpu::DataFormat data_format, AmdGpu::NumberFormat nu
return format->vk_format; return format->vk_format;
} }
vk::Format AdjustColorBufferFormat(vk::Format base_format,
Liverpool::ColorBuffer::SwapMode comp_swap) {
const bool comp_swap_alt = comp_swap == Liverpool::ColorBuffer::SwapMode::Alternate;
const bool comp_swap_reverse = comp_swap == Liverpool::ColorBuffer::SwapMode::StandardReverse;
const bool comp_swap_alt_reverse =
comp_swap == Liverpool::ColorBuffer::SwapMode::AlternateReverse;
if (comp_swap_alt) {
switch (base_format) {
case vk::Format::eR8G8B8A8Unorm:
return vk::Format::eB8G8R8A8Unorm;
case vk::Format::eB8G8R8A8Unorm:
return vk::Format::eR8G8B8A8Unorm;
case vk::Format::eR8G8B8A8Srgb:
return vk::Format::eB8G8R8A8Srgb;
case vk::Format::eB8G8R8A8Srgb:
return vk::Format::eR8G8B8A8Srgb;
case vk::Format::eA2B10G10R10UnormPack32:
return vk::Format::eA2R10G10B10UnormPack32;
default:
break;
}
}
return base_format;
}
static constexpr DepthFormatInfo CreateDepthFormatInfo( static constexpr DepthFormatInfo CreateDepthFormatInfo(
const DepthBuffer::ZFormat z_format, const DepthBuffer::StencilFormat stencil_format, const DepthBuffer::ZFormat z_format, const DepthBuffer::StencilFormat stencil_format,
const vk::Format vk_format) { const vk::Format vk_format) {
@ -774,21 +749,12 @@ vk::Format DepthFormat(DepthBuffer::ZFormat z_format, DepthBuffer::StencilFormat
} }
vk::ClearValue ColorBufferClearValue(const AmdGpu::Liverpool::ColorBuffer& color_buffer) { vk::ClearValue ColorBufferClearValue(const AmdGpu::Liverpool::ColorBuffer& color_buffer) {
const auto comp_swap = color_buffer.info.comp_swap.Value(); const auto comp_swizzle = color_buffer.Swizzle();
const auto format = color_buffer.info.format.Value(); const auto format = color_buffer.DataFormat();
const auto number_type = color_buffer.info.number_type.Value(); const auto number_type = color_buffer.NumFormat();
const auto& c0 = color_buffer.clear_word0; const auto& c0 = color_buffer.clear_word0;
const auto& c1 = color_buffer.clear_word1; const auto& c1 = color_buffer.clear_word1;
const auto num_bits = AmdGpu::NumBits(color_buffer.info.format);
const auto num_components = AmdGpu::NumComponents(format);
const bool comp_swap_alt =
comp_swap == AmdGpu::Liverpool::ColorBuffer::SwapMode::Alternate ||
comp_swap == AmdGpu::Liverpool::ColorBuffer::SwapMode::AlternateReverse;
const bool comp_swap_reverse =
comp_swap == AmdGpu::Liverpool::ColorBuffer::SwapMode::StandardReverse ||
comp_swap == AmdGpu::Liverpool::ColorBuffer::SwapMode::AlternateReverse;
vk::ClearColorValue color{}; vk::ClearColorValue color{};
@ -1109,25 +1075,9 @@ vk::ClearValue ColorBufferClearValue(const AmdGpu::Liverpool::ColorBuffer& color
break; break;
} }
if (num_components == 1) { color.float32 = comp_swizzle.Apply(color.float32);
if (comp_swap != Liverpool::ColorBuffer::SwapMode::Standard) { color.int32 = comp_swizzle.Apply(color.int32);
color.float32[static_cast<int>(comp_swap)] = color.float32[0]; color.uint32 = comp_swizzle.Apply(color.uint32);
color.float32[0] = 0.0f;
}
} else {
if (comp_swap_alt && num_components == 4) {
std::swap(color.float32[0], color.float32[2]);
}
if (comp_swap_reverse) {
std::reverse(std::begin(color.float32), std::begin(color.float32) + num_components);
}
if (comp_swap_alt && num_components != 4) {
color.float32[3] = color.float32[num_components - 1];
color.float32[num_components - 1] = 0.0f;
}
}
return {.color = color}; return {.color = color};
} }

View File

@ -56,9 +56,6 @@ std::span<const SurfaceFormatInfo> SurfaceFormats();
vk::Format SurfaceFormat(AmdGpu::DataFormat data_format, AmdGpu::NumberFormat num_format); vk::Format SurfaceFormat(AmdGpu::DataFormat data_format, AmdGpu::NumberFormat num_format);
vk::Format AdjustColorBufferFormat(vk::Format base_format,
Liverpool::ColorBuffer::SwapMode comp_swap);
struct DepthFormatInfo { struct DepthFormatInfo {
Liverpool::DepthBuffer::ZFormat z_format; Liverpool::DepthBuffer::ZFormat z_format;
Liverpool::DepthBuffer::StencilFormat stencil_format; Liverpool::DepthBuffer::StencilFormat stencil_format;

View File

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

View File

@ -168,7 +168,7 @@ const Shader::RuntimeInfo& PipelineCache::BuildRuntimeInfo(Stage stage, LogicalS
for (u32 i = 0; i < Shader::MaxColorBuffers; i++) { for (u32 i = 0; i < Shader::MaxColorBuffers; i++) {
info.fs_info.color_buffers[i] = { info.fs_info.color_buffers[i] = {
.num_format = graphics_key.color_num_formats[i], .num_format = graphics_key.color_num_formats[i],
.mrt_swizzle = static_cast<Shader::MrtSwizzle>(graphics_key.mrt_swizzles[i]), .swizzle = graphics_key.color_swizzles[i],
}; };
} }
break; break;
@ -304,7 +304,7 @@ bool PipelineCache::RefreshGraphicsKey() {
key.color_num_formats.fill(AmdGpu::NumberFormat::Unorm); key.color_num_formats.fill(AmdGpu::NumberFormat::Unorm);
key.blend_controls.fill({}); key.blend_controls.fill({});
key.write_masks.fill({}); key.write_masks.fill({});
key.mrt_swizzles.fill(Liverpool::ColorBuffer::SwapMode::Standard); key.color_swizzles.fill({});
key.vertex_buffer_formats.fill(vk::Format::eUndefined); key.vertex_buffer_formats.fill(vk::Format::eUndefined);
key.patch_control_points = 0; key.patch_control_points = 0;
@ -327,14 +327,10 @@ bool PipelineCache::RefreshGraphicsKey() {
continue; continue;
} }
const auto base_format =
LiverpoolToVK::SurfaceFormat(col_buf.info.format, col_buf.NumFormat());
key.color_formats[remapped_cb] = key.color_formats[remapped_cb] =
LiverpoolToVK::AdjustColorBufferFormat(base_format, col_buf.info.comp_swap.Value()); LiverpoolToVK::SurfaceFormat(col_buf.DataFormat(), col_buf.NumFormat());
key.color_num_formats[remapped_cb] = col_buf.NumFormat(); key.color_num_formats[remapped_cb] = col_buf.NumFormat();
if (base_format == key.color_formats[remapped_cb]) { key.color_swizzles[remapped_cb] = col_buf.Swizzle();
key.mrt_swizzles[remapped_cb] = col_buf.info.comp_swap.Value();
}
} }
fetch_shader = std::nullopt; fetch_shader = std::nullopt;
@ -450,7 +446,7 @@ bool PipelineCache::RefreshGraphicsKey() {
// of the latter we need to change format to undefined, and either way we need to // of the latter we need to change format to undefined, and either way we need to
// increment the index for the null attachment binding. // increment the index for the null attachment binding.
key.color_formats[remapped_cb] = vk::Format::eUndefined; key.color_formats[remapped_cb] = vk::Format::eUndefined;
key.mrt_swizzles[remapped_cb] = Liverpool::ColorBuffer::SwapMode::Standard; key.color_swizzles[remapped_cb] = {};
++remapped_cb; ++remapped_cb;
continue; continue;
} }

View File

@ -265,9 +265,9 @@ ImageInfo::ImageInfo(const AmdGpu::Liverpool::ColorBuffer& buffer,
const AmdGpu::Liverpool::CbDbExtent& hint /*= {}*/) noexcept { const AmdGpu::Liverpool::CbDbExtent& hint /*= {}*/) noexcept {
props.is_tiled = buffer.IsTiled(); props.is_tiled = buffer.IsTiled();
tiling_mode = buffer.GetTilingMode(); tiling_mode = buffer.GetTilingMode();
pixel_format = LiverpoolToVK::SurfaceFormat(buffer.info.format, buffer.NumFormat()); pixel_format = LiverpoolToVK::SurfaceFormat(buffer.DataFormat(), buffer.NumFormat());
num_samples = buffer.NumSamples(); num_samples = buffer.NumSamples();
num_bits = NumBits(buffer.info.format); num_bits = NumBits(buffer.DataFormat());
type = vk::ImageType::e2D; type = vk::ImageType::e2D;
size.width = hint.Valid() ? hint.width : buffer.Pitch(); size.width = hint.Valid() ? hint.width : buffer.Pitch();
size.height = hint.Valid() ? hint.height : buffer.Height(); size.height = hint.Valid() ? hint.height : buffer.Height();

View File

@ -73,13 +73,10 @@ ImageViewInfo::ImageViewInfo(const AmdGpu::Image& image, const Shader::ImageReso
} }
ImageViewInfo::ImageViewInfo(const AmdGpu::Liverpool::ColorBuffer& col_buffer) noexcept { ImageViewInfo::ImageViewInfo(const AmdGpu::Liverpool::ColorBuffer& col_buffer) noexcept {
const auto base_format =
Vulkan::LiverpoolToVK::SurfaceFormat(col_buffer.info.format, col_buffer.NumFormat());
range.base.layer = col_buffer.view.slice_start; range.base.layer = col_buffer.view.slice_start;
range.extent.layers = col_buffer.NumSlices() - range.base.layer; range.extent.layers = col_buffer.NumSlices() - range.base.layer;
type = range.extent.layers > 1 ? vk::ImageViewType::e2DArray : vk::ImageViewType::e2D; type = range.extent.layers > 1 ? vk::ImageViewType::e2DArray : vk::ImageViewType::e2D;
format = Vulkan::LiverpoolToVK::AdjustColorBufferFormat(base_format, format = Vulkan::LiverpoolToVK::SurfaceFormat(col_buffer.DataFormat(), col_buffer.NumFormat());
col_buffer.info.comp_swap.Value());
} }
ImageViewInfo::ImageViewInfo(const AmdGpu::Liverpool::DepthBuffer& depth_buffer, ImageViewInfo::ImageViewInfo(const AmdGpu::Liverpool::DepthBuffer& depth_buffer,