From 9aec85d39c0c95419bd086ccac158dbb77c20002 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Fri, 5 Oct 2018 23:46:40 -0400
Subject: [PATCH] fermi_2d: Implement simple copies with AccelerateSurfaceCopy.

---
 src/video_core/engines/fermi_2d.cpp | 48 ++++++++++++++++-------------
 src/video_core/engines/fermi_2d.h   |  8 ++++-
 src/video_core/gpu.cpp              |  2 +-
 3 files changed, 35 insertions(+), 23 deletions(-)

diff --git a/src/video_core/engines/fermi_2d.cpp b/src/video_core/engines/fermi_2d.cpp
index ea1555c5d5..912e785b9a 100644
--- a/src/video_core/engines/fermi_2d.cpp
+++ b/src/video_core/engines/fermi_2d.cpp
@@ -4,11 +4,13 @@
 
 #include "core/memory.h"
 #include "video_core/engines/fermi_2d.h"
+#include "video_core/rasterizer_interface.h"
 #include "video_core/textures/decoders.h"
 
 namespace Tegra::Engines {
 
-Fermi2D::Fermi2D(MemoryManager& memory_manager) : memory_manager(memory_manager) {}
+Fermi2D::Fermi2D(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager)
+    : memory_manager(memory_manager), rasterizer{rasterizer} {}
 
 void Fermi2D::WriteReg(u32 method, u32 value) {
     ASSERT_MSG(method < Regs::NUM_REGS,
@@ -44,27 +46,31 @@ void Fermi2D::HandleSurfaceCopy() {
     u32 src_bytes_per_pixel = RenderTargetBytesPerPixel(regs.src.format);
     u32 dst_bytes_per_pixel = RenderTargetBytesPerPixel(regs.dst.format);
 
-    if (regs.src.linear == regs.dst.linear) {
-        // If the input layout and the output layout are the same, just perform a raw copy.
-        ASSERT(regs.src.BlockHeight() == regs.dst.BlockHeight());
-        Memory::CopyBlock(dest_cpu, source_cpu,
-                          src_bytes_per_pixel * regs.dst.width * regs.dst.height);
-        return;
-    }
+    if (!rasterizer.AccelerateSurfaceCopy(regs.src, regs.dst)) {
+        // TODO(bunnei): The below implementation currently will not get hit, as
+        // AccelerateSurfaceCopy tries to always copy and will always return success. This should be
+        // changed once we properly support flushing.
 
-    u8* src_buffer = Memory::GetPointer(source_cpu);
-    u8* dst_buffer = Memory::GetPointer(dest_cpu);
-
-    if (!regs.src.linear && regs.dst.linear) {
-        // If the input is tiled and the output is linear, deswizzle the input and copy it over.
-        Texture::CopySwizzledData(regs.src.width, regs.src.height, src_bytes_per_pixel,
-                                  dst_bytes_per_pixel, src_buffer, dst_buffer, true,
-                                  regs.src.BlockHeight());
-    } else {
-        // If the input is linear and the output is tiled, swizzle the input and copy it over.
-        Texture::CopySwizzledData(regs.src.width, regs.src.height, src_bytes_per_pixel,
-                                  dst_bytes_per_pixel, dst_buffer, src_buffer, false,
-                                  regs.dst.BlockHeight());
+        if (regs.src.linear == regs.dst.linear) {
+            // If the input layout and the output layout are the same, just perform a raw copy.
+            ASSERT(regs.src.BlockHeight() == regs.dst.BlockHeight());
+            Memory::CopyBlock(dest_cpu, source_cpu,
+                              src_bytes_per_pixel * regs.dst.width * regs.dst.height);
+            return;
+        }
+        u8* src_buffer = Memory::GetPointer(source_cpu);
+        u8* dst_buffer = Memory::GetPointer(dest_cpu);
+        if (!regs.src.linear && regs.dst.linear) {
+            // If the input is tiled and the output is linear, deswizzle the input and copy it over.
+            Texture::CopySwizzledData(regs.src.width, regs.src.height, src_bytes_per_pixel,
+                                      dst_bytes_per_pixel, src_buffer, dst_buffer, true,
+                                      regs.src.BlockHeight());
+        } else {
+            // If the input is linear and the output is tiled, swizzle the input and copy it over.
+            Texture::CopySwizzledData(regs.src.width, regs.src.height, src_bytes_per_pixel,
+                                      dst_bytes_per_pixel, dst_buffer, src_buffer, false,
+                                      regs.dst.BlockHeight());
+        }
     }
 }
 
diff --git a/src/video_core/engines/fermi_2d.h b/src/video_core/engines/fermi_2d.h
index 021b83eaa0..81d15c62a8 100644
--- a/src/video_core/engines/fermi_2d.h
+++ b/src/video_core/engines/fermi_2d.h
@@ -12,6 +12,10 @@
 #include "video_core/gpu.h"
 #include "video_core/memory_manager.h"
 
+namespace VideoCore {
+class RasterizerInterface;
+}
+
 namespace Tegra::Engines {
 
 #define FERMI2D_REG_INDEX(field_name)                                                              \
@@ -19,7 +23,7 @@ namespace Tegra::Engines {
 
 class Fermi2D final {
 public:
-    explicit Fermi2D(MemoryManager& memory_manager);
+    explicit Fermi2D(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager);
     ~Fermi2D() = default;
 
     /// Write the value to the register identified by method.
@@ -94,6 +98,8 @@ public:
     MemoryManager& memory_manager;
 
 private:
+    VideoCore::RasterizerInterface& rasterizer;
+
     /// Performs the copy from the source surface to the destination surface as configured in the
     /// registers.
     void HandleSurfaceCopy();
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index baa8b63b79..9ba7e35338 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -25,7 +25,7 @@ u32 FramebufferConfig::BytesPerPixel(PixelFormat format) {
 GPU::GPU(VideoCore::RasterizerInterface& rasterizer) {
     memory_manager = std::make_unique<Tegra::MemoryManager>();
     maxwell_3d = std::make_unique<Engines::Maxwell3D>(rasterizer, *memory_manager);
-    fermi_2d = std::make_unique<Engines::Fermi2D>(*memory_manager);
+    fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer, *memory_manager);
     maxwell_compute = std::make_unique<Engines::MaxwellCompute>();
     maxwell_dma = std::make_unique<Engines::MaxwellDMA>(*memory_manager);
     kepler_memory = std::make_unique<Engines::KeplerMemory>(*memory_manager);