From 3dcaa84ba442ac173c8b5241049296d8fe8a3fd7 Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Mon, 2 Mar 2020 18:54:08 -0300
Subject: [PATCH] shader/transform_feedback: Add host API friendly TFB builder

---
 CMakeModules/GenerateSCMRev.cmake            |   2 +
 src/common/CMakeLists.txt                    |   2 +
 src/video_core/CMakeLists.txt                |   2 +
 src/video_core/shader/transform_feedback.cpp | 114 +++++++++++++++++++
 src/video_core/shader/transform_feedback.h   |  22 ++++
 5 files changed, 142 insertions(+)
 create mode 100644 src/video_core/shader/transform_feedback.cpp
 create mode 100644 src/video_core/shader/transform_feedback.h

diff --git a/CMakeModules/GenerateSCMRev.cmake b/CMakeModules/GenerateSCMRev.cmake
index 8c13a94fb4..83e4e9df2e 100644
--- a/CMakeModules/GenerateSCMRev.cmake
+++ b/CMakeModules/GenerateSCMRev.cmake
@@ -102,6 +102,8 @@ set(HASH_FILES
     "${VIDEO_CORE}/shader/shader_ir.cpp"
     "${VIDEO_CORE}/shader/shader_ir.h"
     "${VIDEO_CORE}/shader/track.cpp"
+    "${VIDEO_CORE}/shader/transform_feedback.cpp"
+    "${VIDEO_CORE}/shader/transform_feedback.h"
 )
 set(COMBINED "")
 foreach (F IN LISTS HASH_FILES)
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 1f621fb1fb..fbebed7159 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -83,6 +83,8 @@ add_custom_command(OUTPUT scm_rev.cpp
       "${VIDEO_CORE}/shader/shader_ir.cpp"
       "${VIDEO_CORE}/shader/shader_ir.h"
       "${VIDEO_CORE}/shader/track.cpp"
+      "${VIDEO_CORE}/shader/transform_feedback.cpp"
+      "${VIDEO_CORE}/shader/transform_feedback.h"
       # and also check that the scm_rev files haven't changed
       "${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp.in"
       "${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.h"
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 0101e5f0e1..91df062d7c 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -129,6 +129,8 @@ add_library(video_core STATIC
     shader/shader_ir.cpp
     shader/shader_ir.h
     shader/track.cpp
+    shader/transform_feedback.cpp
+    shader/transform_feedback.h
     surface.cpp
     surface.h
     texture_cache/format_lookup_table.cpp
diff --git a/src/video_core/shader/transform_feedback.cpp b/src/video_core/shader/transform_feedback.cpp
new file mode 100644
index 0000000000..db86c940f6
--- /dev/null
+++ b/src/video_core/shader/transform_feedback.cpp
@@ -0,0 +1,114 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <algorithm>
+#include <array>
+#include <unordered_map>
+
+#include "common/assert.h"
+#include "common/common_types.h"
+#include "video_core/engines/maxwell_3d.h"
+#include "video_core/shader/registry.h"
+#include "video_core/shader/transform_feedback.h"
+
+namespace VideoCommon::Shader {
+
+namespace {
+
+using Maxwell = Tegra::Engines::Maxwell3D::Regs;
+
+// TODO(Rodrigo): Change this to constexpr std::unordered_set in C++20
+
+/// Attribute offsets that describe a vector
+constexpr std::array VECTORS = {
+    28,  // gl_Position
+    32,  // Generic 0
+    36,  // Generic 1
+    40,  // Generic 2
+    44,  // Generic 3
+    48,  // Generic 4
+    52,  // Generic 5
+    56,  // Generic 6
+    60,  // Generic 7
+    64,  // Generic 8
+    68,  // Generic 9
+    72,  // Generic 10
+    76,  // Generic 11
+    80,  // Generic 12
+    84,  // Generic 13
+    88,  // Generic 14
+    92,  // Generic 15
+    96,  // Generic 16
+    100, // Generic 17
+    104, // Generic 18
+    108, // Generic 19
+    112, // Generic 20
+    116, // Generic 21
+    120, // Generic 22
+    124, // Generic 23
+    128, // Generic 24
+    132, // Generic 25
+    136, // Generic 26
+    140, // Generic 27
+    144, // Generic 28
+    148, // Generic 29
+    152, // Generic 30
+    156, // Generic 31
+    160, // gl_FrontColor
+    164, // gl_FrontSecondaryColor
+    160, // gl_BackColor
+    164, // gl_BackSecondaryColor
+    192, // gl_TexCoord[0]
+    196, // gl_TexCoord[1]
+    200, // gl_TexCoord[2]
+    204, // gl_TexCoord[3]
+    208, // gl_TexCoord[4]
+    212, // gl_TexCoord[5]
+    216, // gl_TexCoord[6]
+    220, // gl_TexCoord[7]
+};
+} // namespace
+
+std::unordered_map<u8, VaryingTFB> BuildTransformFeedback(const GraphicsInfo& info) {
+
+    std::unordered_map<u8, VaryingTFB> tfb;
+
+    for (std::size_t buffer = 0; buffer < Maxwell::NumTransformFeedbackBuffers; ++buffer) {
+        const auto& locations = info.tfb_varying_locs[buffer];
+        const auto& layout = info.tfb_layouts[buffer];
+        const std::size_t varying_count = layout.varying_count;
+
+        std::size_t highest = 0;
+
+        for (std::size_t offset = 0; offset < varying_count; ++offset) {
+            const std::size_t base_offset = offset;
+            const u8 location = locations[offset];
+
+            VaryingTFB varying;
+            varying.buffer = layout.stream;
+            varying.offset = offset * sizeof(u32);
+            varying.components = 1;
+
+            if (std::find(VECTORS.begin(), VECTORS.end(), location / 4 * 4) != VECTORS.end()) {
+                UNIMPLEMENTED_IF_MSG(location % 4 != 0, "Unaligned TFB");
+
+                const u8 base_index = location / 4;
+                while (offset + 1 < varying_count && base_index == locations[offset + 1] / 4) {
+                    ++offset;
+                    ++varying.components;
+                }
+            }
+
+            [[maybe_unused]] const bool inserted = tfb.emplace(location, varying).second;
+            UNIMPLEMENTED_IF_MSG(!inserted, "Varying already stored");
+
+            highest = std::max(highest, (base_offset + varying.components) * sizeof(u32));
+        }
+
+        UNIMPLEMENTED_IF(highest != layout.stride);
+    }
+    return tfb;
+}
+
+} // namespace VideoCommon::Shader
diff --git a/src/video_core/shader/transform_feedback.h b/src/video_core/shader/transform_feedback.h
new file mode 100644
index 0000000000..8a8235019a
--- /dev/null
+++ b/src/video_core/shader/transform_feedback.h
@@ -0,0 +1,22 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <unordered_map>
+
+#include "common/common_types.h"
+#include "video_core/shader/registry.h"
+
+namespace VideoCommon::Shader {
+
+struct VaryingTFB {
+    std::size_t buffer;
+    std::size_t offset;
+    std::size_t components;
+};
+
+std::unordered_map<u8, VaryingTFB> BuildTransformFeedback(const GraphicsInfo& info);
+
+} // namespace VideoCommon::Shader