Browse Source

Merge pull request #248 from Subv/cb_data

GPU: Handle writes to the CB_DATA method.
bunnei 8 years ago
parent
commit
6317a0b2ca

+ 1 - 0
src/video_core/CMakeLists.txt

@@ -7,6 +7,7 @@ add_library(video_core STATIC
     engines/maxwell_3d.h
     engines/maxwell_3d.h
     engines/maxwell_compute.cpp
     engines/maxwell_compute.cpp
     engines/maxwell_compute.h
     engines/maxwell_compute.h
+    gpu.cpp
     gpu.h
     gpu.h
     memory_manager.cpp
     memory_manager.cpp
     memory_manager.h
     memory_manager.h

+ 57 - 0
src/video_core/engines/maxwell_3d.cpp

@@ -13,6 +13,7 @@ constexpr u32 MacroRegistersStart = 0xE00;
 
 
 const std::unordered_map<u32, Maxwell3D::MethodInfo> Maxwell3D::method_handlers = {
 const std::unordered_map<u32, Maxwell3D::MethodInfo> Maxwell3D::method_handlers = {
     {0xE24, {"SetShader", 5, &Maxwell3D::SetShader}},
     {0xE24, {"SetShader", 5, &Maxwell3D::SetShader}},
+    {0xE2A, {"BindStorageBuffer", 1, &Maxwell3D::BindStorageBuffer}},
 };
 };
 
 
 Maxwell3D::Maxwell3D(MemoryManager& memory_manager) : memory_manager(memory_manager) {}
 Maxwell3D::Maxwell3D(MemoryManager& memory_manager) : memory_manager(memory_manager) {}
@@ -83,6 +84,25 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
         ASSERT_MSG(regs.code_address.CodeAddress() == 0, "Unexpected CODE_ADDRESS register value.");
         ASSERT_MSG(regs.code_address.CodeAddress() == 0, "Unexpected CODE_ADDRESS register value.");
         break;
         break;
     }
     }
+    case MAXWELL3D_REG_INDEX(const_buffer.cb_data[0]):
+    case MAXWELL3D_REG_INDEX(const_buffer.cb_data[1]):
+    case MAXWELL3D_REG_INDEX(const_buffer.cb_data[2]):
+    case MAXWELL3D_REG_INDEX(const_buffer.cb_data[3]):
+    case MAXWELL3D_REG_INDEX(const_buffer.cb_data[4]):
+    case MAXWELL3D_REG_INDEX(const_buffer.cb_data[5]):
+    case MAXWELL3D_REG_INDEX(const_buffer.cb_data[6]):
+    case MAXWELL3D_REG_INDEX(const_buffer.cb_data[7]):
+    case MAXWELL3D_REG_INDEX(const_buffer.cb_data[8]):
+    case MAXWELL3D_REG_INDEX(const_buffer.cb_data[9]):
+    case MAXWELL3D_REG_INDEX(const_buffer.cb_data[10]):
+    case MAXWELL3D_REG_INDEX(const_buffer.cb_data[11]):
+    case MAXWELL3D_REG_INDEX(const_buffer.cb_data[12]):
+    case MAXWELL3D_REG_INDEX(const_buffer.cb_data[13]):
+    case MAXWELL3D_REG_INDEX(const_buffer.cb_data[14]):
+    case MAXWELL3D_REG_INDEX(const_buffer.cb_data[15]): {
+        ProcessCBData(value);
+        break;
+    }
     case MAXWELL3D_REG_INDEX(cb_bind[0].raw_config): {
     case MAXWELL3D_REG_INDEX(cb_bind[0].raw_config): {
         ProcessCBBind(Regs::ShaderStage::Vertex);
         ProcessCBBind(Regs::ShaderStage::Vertex);
         break;
         break;
@@ -181,6 +201,26 @@ void Maxwell3D::SetShader(const std::vector<u32>& parameters) {
     ProcessCBBind(shader_stage);
     ProcessCBBind(shader_stage);
 }
 }
 
 
+void Maxwell3D::BindStorageBuffer(const std::vector<u32>& parameters) {
+    /**
+     * Parameters description:
+     * [0] = Buffer offset >> 2
+     */
+
+    u32 buffer_offset = parameters[0] << 2;
+
+    // Perform the same operations as the real macro code.
+    // Note: This value is hardcoded in the macro's code.
+    static constexpr u32 DefaultCBSize = 0x5F00;
+    regs.const_buffer.cb_size = DefaultCBSize;
+
+    GPUVAddr address = regs.ssbo_info.BufferAddress();
+    regs.const_buffer.cb_address_high = address >> 32;
+    regs.const_buffer.cb_address_low = address & 0xFFFFFFFF;
+
+    regs.const_buffer.cb_pos = buffer_offset;
+}
+
 void Maxwell3D::ProcessCBBind(Regs::ShaderStage stage) {
 void Maxwell3D::ProcessCBBind(Regs::ShaderStage stage) {
     // Bind the buffer currently in CB_ADDRESS to the specified index in the desired shader stage.
     // Bind the buffer currently in CB_ADDRESS to the specified index in the desired shader stage.
     auto& shader = state.shader_stages[static_cast<size_t>(stage)];
     auto& shader = state.shader_stages[static_cast<size_t>(stage)];
@@ -194,5 +234,22 @@ void Maxwell3D::ProcessCBBind(Regs::ShaderStage stage) {
     buffer.size = regs.const_buffer.cb_size;
     buffer.size = regs.const_buffer.cb_size;
 }
 }
 
 
+void Maxwell3D::ProcessCBData(u32 value) {
+    // Write the input value to the current const buffer at the current position.
+    GPUVAddr buffer_address = regs.const_buffer.BufferAddress();
+    ASSERT(buffer_address != 0);
+
+    // Don't allow writing past the end of the buffer.
+    ASSERT(regs.const_buffer.cb_pos + sizeof(u32) <= regs.const_buffer.cb_size);
+
+    VAddr address =
+        memory_manager.PhysicalToVirtualAddress(buffer_address + regs.const_buffer.cb_pos);
+
+    Memory::Write32(address, value);
+
+    // Increment the current buffer position.
+    regs.const_buffer.cb_pos = regs.const_buffer.cb_pos + 4;
+}
+
 } // namespace Engines
 } // namespace Engines
 } // namespace Tegra
 } // namespace Tegra

+ 18 - 1
src/video_core/engines/maxwell_3d.h

@@ -166,7 +166,19 @@ public:
 
 
                 u32 tex_cb_index;
                 u32 tex_cb_index;
 
 
-                INSERT_PADDING_WORDS(0x4B3);
+                INSERT_PADDING_WORDS(0x395);
+
+                struct {
+                    /// Compressed address of a buffer that holds information about bound SSBOs.
+                    /// This address is usually bound to c0 in the shaders.
+                    u32 buffer_address;
+
+                    GPUVAddr BufferAddress() const {
+                        return static_cast<GPUVAddr>(buffer_address) << 8;
+                    }
+                } ssbo_info;
+
+                INSERT_PADDING_WORDS(0x11D);
             };
             };
             std::array<u32, NUM_REGS> reg_array;
             std::array<u32, NUM_REGS> reg_array;
         };
         };
@@ -218,6 +230,9 @@ private:
     /// Handles a write to the QUERY_GET register.
     /// Handles a write to the QUERY_GET register.
     void ProcessQueryGet();
     void ProcessQueryGet();
 
 
+    /// Handles a write to the CB_DATA[i] register.
+    void ProcessCBData(u32 value);
+
     /// Handles a write to the CB_BIND register.
     /// Handles a write to the CB_BIND register.
     void ProcessCBBind(Regs::ShaderStage stage);
     void ProcessCBBind(Regs::ShaderStage stage);
 
 
@@ -226,6 +241,7 @@ private:
 
 
     /// Method call handlers
     /// Method call handlers
     void SetShader(const std::vector<u32>& parameters);
     void SetShader(const std::vector<u32>& parameters);
+    void BindStorageBuffer(const std::vector<u32>& parameters);
 
 
     struct MethodInfo {
     struct MethodInfo {
         const char* name;
         const char* name;
@@ -249,6 +265,7 @@ ASSERT_REG_POSITION(shader_config[0], 0x800);
 ASSERT_REG_POSITION(const_buffer, 0x8E0);
 ASSERT_REG_POSITION(const_buffer, 0x8E0);
 ASSERT_REG_POSITION(cb_bind[0], 0x904);
 ASSERT_REG_POSITION(cb_bind[0], 0x904);
 ASSERT_REG_POSITION(tex_cb_index, 0x982);
 ASSERT_REG_POSITION(tex_cb_index, 0x982);
+ASSERT_REG_POSITION(ssbo_info, 0xD18);
 
 
 #undef ASSERT_REG_POSITION
 #undef ASSERT_REG_POSITION
 
 

+ 21 - 0
src/video_core/gpu.cpp

@@ -0,0 +1,21 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "video_core/engines/fermi_2d.h"
+#include "video_core/engines/maxwell_3d.h"
+#include "video_core/engines/maxwell_compute.h"
+#include "video_core/gpu.h"
+
+namespace Tegra {
+
+GPU::GPU() {
+    memory_manager = std::make_unique<MemoryManager>();
+    maxwell_3d = std::make_unique<Engines::Maxwell3D>(*memory_manager);
+    fermi_2d = std::make_unique<Engines::Fermi2D>();
+    maxwell_compute = std::make_unique<Engines::MaxwellCompute>();
+}
+
+GPU::~GPU() = default;
+
+} // namespace Tegra

+ 8 - 10
src/video_core/gpu.h

@@ -8,13 +8,16 @@
 #include <unordered_map>
 #include <unordered_map>
 #include <vector>
 #include <vector>
 #include "common/common_types.h"
 #include "common/common_types.h"
-#include "video_core/engines/fermi_2d.h"
-#include "video_core/engines/maxwell_3d.h"
-#include "video_core/engines/maxwell_compute.h"
 #include "video_core/memory_manager.h"
 #include "video_core/memory_manager.h"
 
 
 namespace Tegra {
 namespace Tegra {
 
 
+namespace Engines {
+class Fermi2D;
+class Maxwell3D;
+class MaxwellCompute;
+} // namespace Engines
+
 enum class EngineID {
 enum class EngineID {
     FERMI_TWOD_A = 0x902D, // 2D Engine
     FERMI_TWOD_A = 0x902D, // 2D Engine
     MAXWELL_B = 0xB197,    // 3D Engine
     MAXWELL_B = 0xB197,    // 3D Engine
@@ -25,13 +28,8 @@ enum class EngineID {
 
 
 class GPU final {
 class GPU final {
 public:
 public:
-    GPU() {
-        memory_manager = std::make_unique<MemoryManager>();
-        maxwell_3d = std::make_unique<Engines::Maxwell3D>(*memory_manager);
-        fermi_2d = std::make_unique<Engines::Fermi2D>();
-        maxwell_compute = std::make_unique<Engines::MaxwellCompute>();
-    }
-    ~GPU() = default;
+    GPU();
+    ~GPU();
 
 
     /// Processes a command list stored at the specified address in GPU memory.
     /// Processes a command list stored at the specified address in GPU memory.
     void ProcessCommandList(GPUVAddr address, u32 size);
     void ProcessCommandList(GPUVAddr address, u32 size);