diff --git a/src/shader_recompiler/frontend/translate/export.cpp b/src/shader_recompiler/frontend/translate/export.cpp index 5927aa696..83240e17f 100644 --- a/src/shader_recompiler/frontend/translate/export.cpp +++ b/src/shader_recompiler/frontend/translate/export.cpp @@ -25,34 +25,28 @@ void Translator::EmitExport(const GcnInst& inst) { IR::VectorReg(inst.src[3].code), }; - const auto swizzle = [&](u32 comp) { + const auto set_attribute = [&](u32 comp, IR::F32 value) { if (!IR::IsMrt(attrib)) { - return comp; + ir.SetAttribute(attrib, value, comp); + return; } const u32 index = u32(attrib) - u32(IR::Attribute::RenderTarget0); - switch (runtime_info.fs_info.color_buffers[index].mrt_swizzle) { - case MrtSwizzle::Identity: - return comp; - case MrtSwizzle::Alt: - static constexpr std::array AltSwizzle = {2, 1, 0, 3}; - return AltSwizzle[comp]; - case MrtSwizzle::Reverse: - static constexpr std::array RevSwizzle = {3, 2, 1, 0}; - return RevSwizzle[comp]; - case MrtSwizzle::ReverseAlt: - static constexpr std::array AltRevSwizzle = {3, 0, 1, 2}; - return AltRevSwizzle[comp]; - default: - UNREACHABLE(); + const auto [r, g, b, a] = runtime_info.fs_info.color_buffers[index].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); + return; } + ir.SetAttribute(attrib, value, u32(swizzled_comp) - u32(AmdGpu::CompSwizzle::Red)); }; const auto unpack = [&](u32 idx) { const IR::Value value = ir.UnpackHalf2x16(ir.GetVectorReg(vsrc[idx])); const IR::F32 r = IR::F32{ir.CompositeExtract(value, 0)}; const IR::F32 g = IR::F32{ir.CompositeExtract(value, 1)}; - ir.SetAttribute(attrib, r, swizzle(idx * 2)); - ir.SetAttribute(attrib, g, swizzle(idx * 2 + 1)); + set_attribute(idx * 2, r); + set_attribute(idx * 2 + 1, g); }; // Components are float16 packed into a VGPR @@ -73,7 +67,7 @@ void Translator::EmitExport(const GcnInst& inst) { continue; } const IR::F32 comp = ir.GetVectorReg(vsrc[i]); - ir.SetAttribute(attrib, comp, swizzle(i)); + set_attribute(i, comp); } } if (IR::IsMrt(attrib)) { diff --git a/src/shader_recompiler/frontend/translate/translate.cpp b/src/shader_recompiler/frontend/translate/translate.cpp index 3765f7f00..05c3b1169 100644 --- a/src/shader_recompiler/frontend/translate/translate.cpp +++ b/src/shader_recompiler/frontend/translate/translate.cpp @@ -475,29 +475,12 @@ void Translator::EmitFetch(const GcnInst& inst) { // Read the V# of the attribute to figure out component number and type. const auto buffer = info.ReadUdReg(attrib.sgpr_base, attrib.dword_offset); - const auto comp = [&](AmdGpu::CompSwizzle swizzle) -> IR::F32 { - switch (swizzle) { - case AmdGpu::CompSwizzle::One: - return ir.Imm32(1.f); - case AmdGpu::CompSwizzle::Zero: - 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)); + const std::array components = buffer.DstSelect().Apply( + [&](const u32 index) { return ir.GetAttribute(attr, index); }, + [&](const u32 imm) { return ir.Imm32(float(imm)); }); + for (u32 i = 0; i < components.size(); i++) { + ir.SetVectorReg(dst_reg++, components[i]); + } // 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 diff --git a/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp b/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp index 3540831f7..537907bc1 100644 --- a/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp +++ b/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp @@ -129,26 +129,10 @@ bool IsImageInstruction(const IR::Inst& inst) { } IR::Value SwizzleVector(IR::IREmitter& ir, auto sharp, IR::Value texel) { - const auto comp = [&](AmdGpu::CompSwizzle swizzle) -> IR::Value { - switch (swizzle) { - case AmdGpu::CompSwizzle::Zero: - return ir.Imm32(0.f); - 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)); + const std::array components = sharp.DstSelect().template Apply( + [&](const u32 index) { return ir.CompositeExtract(texel, index); }, + [&](const u32 imm) { return ir.Imm32(float(imm)); }); + return ir.CompositeConstruct(components[0], components[1], components[2], components[3]); }; class Descriptors { diff --git a/src/shader_recompiler/runtime_info.h b/src/shader_recompiler/runtime_info.h index bbf74f5d3..781a0b14a 100644 --- a/src/shader_recompiler/runtime_info.h +++ b/src/shader_recompiler/runtime_info.h @@ -180,7 +180,7 @@ struct FragmentRuntimeInfo { std::array inputs; struct PsColorBuffer { AmdGpu::NumberFormat num_format; - MrtSwizzle mrt_swizzle; + AmdGpu::CompMapping swizzle; auto operator<=>(const PsColorBuffer&) const noexcept = default; }; diff --git a/src/video_core/amdgpu/liverpool.h b/src/video_core/amdgpu/liverpool.h index 83271a82d..c876e9277 100644 --- a/src/video_core/amdgpu/liverpool.h +++ b/src/video_core/amdgpu/liverpool.h @@ -889,10 +889,54 @@ struct Liverpool { 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. - return info.number_type == AmdGpu::NumberFormat::SnormNz ? AmdGpu::NumberFormat::Srgb - : info.number_type.Value(); + return RemapNumberFormat(info.number_type == NumberFormat::SnormNz + ? NumberFormat::Srgb + : info.number_type.Value()); + } + + [[nodiscard]] CompMapping Swizzle() const { + // clang-format off + static constexpr std::array, 4> mrt_swizzles{{ + // Standard + std::array{{ + {.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{{ + {.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{{ + {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{{ + {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(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); } }; diff --git a/src/video_core/amdgpu/resource.h b/src/video_core/amdgpu/resource.h index 13f9dc25d..3a206f458 100644 --- a/src/video_core/amdgpu/resource.h +++ b/src/video_core/amdgpu/resource.h @@ -3,6 +3,7 @@ #pragma once +#include #include "common/alignment.h" #include "common/assert.h" #include "common/bit_field.h" @@ -27,6 +28,45 @@ struct CompMapping { CompSwizzle a : 3; auto operator<=>(const CompMapping& other) const = default; + + template + [[nodiscard]] std::array Apply(const std::array& data) const { + return Apply([&data](const u32 index) { return data[index]; }, + [](const u32 imm) { return T(imm); }); + } + + template + [[nodiscard]] std::array Apply(const std::function& get_value, + const std::function& 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 + T ApplySingle(const std::function& get_value, + const std::function& 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) { diff --git a/src/video_core/renderer_vulkan/liverpool_to_vk.cpp b/src/video_core/renderer_vulkan/liverpool_to_vk.cpp index cf7576a2c..a3ef64e6b 100644 --- a/src/video_core/renderer_vulkan/liverpool_to_vk.cpp +++ b/src/video_core/renderer_vulkan/liverpool_to_vk.cpp @@ -707,31 +707,6 @@ vk::Format SurfaceFormat(AmdGpu::DataFormat data_format, AmdGpu::NumberFormat nu 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( const DepthBuffer::ZFormat z_format, const DepthBuffer::StencilFormat stencil_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) { - const auto comp_swap = color_buffer.info.comp_swap.Value(); - const auto format = color_buffer.info.format.Value(); - const auto number_type = color_buffer.info.number_type.Value(); + const auto comp_swizzle = color_buffer.Swizzle(); + const auto format = color_buffer.DataFormat(); + const auto number_type = color_buffer.NumFormat(); const auto& c0 = color_buffer.clear_word0; 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{}; @@ -1109,25 +1075,9 @@ vk::ClearValue ColorBufferClearValue(const AmdGpu::Liverpool::ColorBuffer& color break; } - if (num_components == 1) { - if (comp_swap != Liverpool::ColorBuffer::SwapMode::Standard) { - color.float32[static_cast(comp_swap)] = color.float32[0]; - 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; - } - } + color.float32 = comp_swizzle.Apply(color.float32); + color.int32 = comp_swizzle.Apply(color.int32); + color.uint32 = comp_swizzle.Apply(color.uint32); return {.color = color}; } diff --git a/src/video_core/renderer_vulkan/liverpool_to_vk.h b/src/video_core/renderer_vulkan/liverpool_to_vk.h index c3f78f2a4..4a0c68b0c 100644 --- a/src/video_core/renderer_vulkan/liverpool_to_vk.h +++ b/src/video_core/renderer_vulkan/liverpool_to_vk.h @@ -56,9 +56,6 @@ std::span SurfaceFormats(); 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 { Liverpool::DepthBuffer::ZFormat z_format; Liverpool::DepthBuffer::StencilFormat stencil_format; diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h index ee8afa3e6..c8f4999b1 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h @@ -32,7 +32,7 @@ struct GraphicsPipelineKey { u32 num_color_attachments; std::array color_formats; std::array color_num_formats; - std::array mrt_swizzles; + std::array color_swizzles; vk::Format depth_format; vk::Format stencil_format; diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 74ae6b61c..a709f1c02 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -168,7 +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], - .mrt_swizzle = static_cast(graphics_key.mrt_swizzles[i]), + .swizzle = graphics_key.color_swizzles[i], }; } break; @@ -304,7 +304,7 @@ bool PipelineCache::RefreshGraphicsKey() { key.color_num_formats.fill(AmdGpu::NumberFormat::Unorm); key.blend_controls.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.patch_control_points = 0; @@ -327,14 +327,10 @@ bool PipelineCache::RefreshGraphicsKey() { continue; } - const auto base_format = - LiverpoolToVK::SurfaceFormat(col_buf.info.format, col_buf.NumFormat()); 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(); - if (base_format == key.color_formats[remapped_cb]) { - key.mrt_swizzles[remapped_cb] = col_buf.info.comp_swap.Value(); - } + key.color_swizzles[remapped_cb] = col_buf.Swizzle(); } 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 // increment the index for the null attachment binding. key.color_formats[remapped_cb] = vk::Format::eUndefined; - key.mrt_swizzles[remapped_cb] = Liverpool::ColorBuffer::SwapMode::Standard; + key.color_swizzles[remapped_cb] = {}; ++remapped_cb; continue; } diff --git a/src/video_core/texture_cache/image_info.cpp b/src/video_core/texture_cache/image_info.cpp index 2cc4aab38..0559f1be3 100644 --- a/src/video_core/texture_cache/image_info.cpp +++ b/src/video_core/texture_cache/image_info.cpp @@ -265,9 +265,9 @@ ImageInfo::ImageInfo(const AmdGpu::Liverpool::ColorBuffer& buffer, const AmdGpu::Liverpool::CbDbExtent& hint /*= {}*/) noexcept { props.is_tiled = buffer.IsTiled(); 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_bits = NumBits(buffer.info.format); + num_bits = NumBits(buffer.DataFormat()); type = vk::ImageType::e2D; size.width = hint.Valid() ? hint.width : buffer.Pitch(); size.height = hint.Valid() ? hint.height : buffer.Height(); diff --git a/src/video_core/texture_cache/image_view.cpp b/src/video_core/texture_cache/image_view.cpp index 1b48cd82a..a9ae41dd1 100644 --- a/src/video_core/texture_cache/image_view.cpp +++ b/src/video_core/texture_cache/image_view.cpp @@ -73,13 +73,10 @@ ImageViewInfo::ImageViewInfo(const AmdGpu::Image& image, const Shader::ImageReso } 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.extent.layers = col_buffer.NumSlices() - range.base.layer; type = range.extent.layers > 1 ? vk::ImageViewType::e2DArray : vk::ImageViewType::e2D; - format = Vulkan::LiverpoolToVK::AdjustColorBufferFormat(base_format, - col_buffer.info.comp_swap.Value()); + format = Vulkan::LiverpoolToVK::SurfaceFormat(col_buffer.DataFormat(), col_buffer.NumFormat()); } ImageViewInfo::ImageViewInfo(const AmdGpu::Liverpool::DepthBuffer& depth_buffer,