From 826e0785bf6b852a4231f5f3d87655b2cf4e1856 Mon Sep 17 00:00:00 2001
From: Fernando Sahmkow <fsahmkow27@gmail.com>
Date: Thu, 24 Nov 2022 20:45:06 +0100
Subject: [PATCH] Fermi2D: Cleanup and address feedback.

---
 src/video_core/engines/sw_blitter/blitter.cpp |  16 +--
 .../engines/sw_blitter/converter.cpp          |   6 +
 .../engines/sw_blitter/generate_converters.py | 136 ++++++++++++++++++
 3 files changed, 150 insertions(+), 8 deletions(-)
 create mode 100644 src/video_core/engines/sw_blitter/generate_converters.py

diff --git a/src/video_core/engines/sw_blitter/blitter.cpp b/src/video_core/engines/sw_blitter/blitter.cpp
index c923a80e9..2f1ea4626 100644
--- a/src/video_core/engines/sw_blitter/blitter.cpp
+++ b/src/video_core/engines/sw_blitter/blitter.cpp
@@ -26,8 +26,8 @@ namespace {
 
 constexpr size_t ir_components = 4;
 
-void NeighrestNeighbor(std::span<const u8> input, std::span<u8> output, u32 src_width,
-                       u32 src_height, u32 dst_width, u32 dst_height, size_t bpp) {
+void NearestNeighbor(std::span<const u8> input, std::span<u8> output, u32 src_width, u32 src_height,
+                     u32 dst_width, u32 dst_height, size_t bpp) {
     const size_t dx_du = std::llround((static_cast<f64>(src_width) / dst_width) * (1ULL << 32));
     const size_t dy_dv = std::llround((static_cast<f64>(src_height) / dst_height) * (1ULL << 32));
     size_t src_y = 0;
@@ -44,8 +44,8 @@ void NeighrestNeighbor(std::span<const u8> input, std::span<u8> output, u32 src_
     }
 }
 
-void NeighrestNeighborFast(std::span<const f32> input, std::span<f32> output, u32 src_width,
-                           u32 src_height, u32 dst_width, u32 dst_height) {
+void NearestNeighborFast(std::span<const f32> input, std::span<f32> output, u32 src_width,
+                         u32 src_height, u32 dst_width, u32 dst_height) {
     const size_t dx_du = std::llround((static_cast<f64>(src_width) / dst_width) * (1ULL << 32));
     const size_t dy_dv = std::llround((static_cast<f64>(src_height) / dst_height) * (1ULL << 32));
     size_t src_y = 0;
@@ -171,8 +171,8 @@ bool SoftwareBlitEngine::Blit(Fermi2D::Surface& src, Fermi2D::Surface& dst,
         src.format != dst.format || src_extent_x != dst_extent_x || src_extent_y != dst_extent_y;
 
     const auto convertion_phase_same_format = [&]() {
-        NeighrestNeighbor(impl->src_buffer, impl->dst_buffer, src_extent_x, src_extent_y,
-                          dst_extent_x, dst_extent_y, dst_bytes_per_pixel);
+        NearestNeighbor(impl->src_buffer, impl->dst_buffer, src_extent_x, src_extent_y,
+                        dst_extent_x, dst_extent_y, dst_bytes_per_pixel);
     };
 
     const auto convertion_phase_ir = [&]() {
@@ -182,8 +182,8 @@ bool SoftwareBlitEngine::Blit(Fermi2D::Surface& src, Fermi2D::Surface& dst,
         input_converter->ConvertTo(impl->src_buffer, impl->intermediate_src);
 
         if (config.filter != Fermi2D::Filter::Bilinear) {
-            NeighrestNeighborFast(impl->intermediate_src, impl->intermediate_dst, src_extent_x,
-                                  src_extent_y, dst_extent_x, dst_extent_y);
+            NearestNeighborFast(impl->intermediate_src, impl->intermediate_dst, src_extent_x,
+                                src_extent_y, dst_extent_x, dst_extent_y);
         } else {
             Bilinear(impl->intermediate_src, impl->intermediate_dst, src_extent_x, src_extent_y,
                      dst_extent_x, dst_extent_y);
diff --git a/src/video_core/engines/sw_blitter/converter.cpp b/src/video_core/engines/sw_blitter/converter.cpp
index 37c5eff69..cd46dfd4f 100644
--- a/src/video_core/engines/sw_blitter/converter.cpp
+++ b/src/video_core/engines/sw_blitter/converter.cpp
@@ -41,6 +41,12 @@ enum class ComponentType : u32 {
 
 namespace {
 
+/*
+ * Note: Use generate_converters.py to generate the structs and searches for new render target
+ * formats and copy paste them to this file in order to update. just call "python
+ * generate_converters.py" and get the code from the output. modify the file to add new formats.
+ */
+
 constexpr std::array<f32, 256> SRGB_TO_RGB_LUT = {
     0.000000e+00f, 3.035270e-04f, 6.070540e-04f, 9.105810e-04f, 1.214108e-03f, 1.517635e-03f,
     1.821162e-03f, 2.124689e-03f, 2.428216e-03f, 2.731743e-03f, 3.035270e-03f, 3.346536e-03f,
diff --git a/src/video_core/engines/sw_blitter/generate_converters.py b/src/video_core/engines/sw_blitter/generate_converters.py
new file mode 100644
index 000000000..f641564f7
--- /dev/null
+++ b/src/video_core/engines/sw_blitter/generate_converters.py
@@ -0,0 +1,136 @@
+# SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+import re
+
+class Format:
+    def __init__(self, string_value):
+        self.name = string_value
+        tmp = string_value.split('_')
+        self.component_type = tmp[1]
+        component_data = re.findall(r"\w\d+", tmp[0])
+        self.num_components = len(component_data)
+        sizes = []
+        swizzle = []
+        for data in component_data:
+            swizzle.append(data[0])
+            sizes.append(int(data[1:]))
+        self.sizes = sizes
+        self.swizzle = swizzle
+
+    def build_component_type_array(self):
+        result = "{ "
+        b = False
+        for i in range(0, self.num_components):
+            if b:
+                result += ", "
+            b = True
+            result += "ComponentType::" + self.component_type
+        result += " }"
+        return result
+
+    def build_component_sizes_array(self):
+        result = "{ "
+        b = False
+        for i in range(0, self.num_components):
+            if b:
+                result += ", "
+            b = True
+            result += str(self.sizes[i])
+        result += " }"
+        return result
+
+    def build_component_swizzle_array(self):
+        result = "{ "
+        b = False
+        for i in range(0, self.num_components):
+            if b:
+                result += ", "
+            b = True
+            swizzle = self.swizzle[i]
+            if swizzle == "X":
+                swizzle = "None"
+            result += "Swizzle::" + swizzle
+        result += " }"
+        return result
+
+    def print_declaration(self):
+        print("struct " + self.name + "Traits {")
+        print("  static constexpr size_t num_components = " + str(self.num_components) + ";")
+        print("  static constexpr std::array<ComponentType, num_components> component_types = " + self.build_component_type_array() + ";")
+        print("  static constexpr std::array<size_t, num_components> component_sizes = " + self.build_component_sizes_array() + ";")
+        print("  static constexpr std::array<Swizzle, num_components> component_swizzle = " + self.build_component_swizzle_array() + ";")
+        print("};\n")
+
+    def print_case(self):
+        print("case RenderTargetFormat::" + self.name + ":")
+        print("  return impl->converters_cache")
+        print("    .emplace(format, std::make_unique<ConverterImpl<" + self.name + "Traits>>())")
+        print("    .first->second.get();")
+        print("  break;")
+
+txt = """
+R32G32B32A32_FLOAT
+R32G32B32A32_SINT
+R32G32B32A32_UINT
+R32G32B32X32_FLOAT
+R32G32B32X32_SINT
+R32G32B32X32_UINT
+R16G16B16A16_UNORM
+R16G16B16A16_SNORM
+R16G16B16A16_SINT
+R16G16B16A16_UINT
+R16G16B16A16_FLOAT
+R32G32_FLOAT
+R32G32_SINT
+R32G32_UINT
+R16G16B16X16_FLOAT
+A8R8G8B8_UNORM
+A8R8G8B8_SRGB
+A2B10G10R10_UNORM
+A2B10G10R10_UINT
+A2R10G10B10_UNORM
+A8B8G8R8_UNORM
+A8B8G8R8_SRGB
+A8B8G8R8_SNORM
+A8B8G8R8_SINT
+A8B8G8R8_UINT
+R16G16_UNORM
+R16G16_SNORM
+R16G16_SINT
+R16G16_UINT
+R16G16_FLOAT
+B10G11R11_FLOAT
+R32_SINT
+R32_UINT
+R32_FLOAT
+X8R8G8B8_UNORM
+X8R8G8B8_SRGB
+R5G6B5_UNORM
+A1R5G5B5_UNORM
+R8G8_UNORM
+R8G8_SNORM
+R8G8_SINT
+R8G8_UINT
+R16_UNORM
+R16_SNORM
+R16_SINT
+R16_UINT
+R16_FLOAT
+R8_UNORM
+R8_SNORM
+R8_SINT
+R8_UINT
+X1R5G5B5_UNORM
+X8B8G8R8_UNORM
+X8B8G8R8_SRGB
+"""
+
+x = txt.split()
+y = list(map(lambda a: Format(a), x))
+formats = list(y)
+for format in formats:
+  format.print_declaration()
+
+for format in formats:
+  format.print_case()