Просмотр исходного кода

video_core: Reintroduce dirty flags infrastructure

ReinUsesLisp 6 лет назад
Родитель
Сommit
eed789d0d1

+ 1 - 0
src/core/core.cpp

@@ -174,6 +174,7 @@ struct System::Impl {
         }
         interrupt_manager = std::make_unique<Core::Hardware::InterruptManager>(system);
         gpu_core = VideoCore::CreateGPU(system);
+        renderer->Rasterizer().SetupDirtyFlags();
 
         is_powered_on = true;
         exit_lock = false;

+ 1 - 0
src/video_core/CMakeLists.txt

@@ -2,6 +2,7 @@ add_library(video_core STATIC
     buffer_cache/buffer_block.h
     buffer_cache/buffer_cache.h
     buffer_cache/map_interval.h
+    dirty_flags.h
     dma_pusher.cpp
     dma_pusher.h
     engines/const_buffer_engine_interface.h

+ 28 - 0
src/video_core/dirty_flags.h

@@ -0,0 +1,28 @@
+// Copyright 2019 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+
+namespace VideoCommon::Dirty {
+
+enum : u8 {
+    NullEntry = 0,
+
+    RenderTargets,
+    ColorBuffer0,
+    ColorBuffer1,
+    ColorBuffer2,
+    ColorBuffer3,
+    ColorBuffer4,
+    ColorBuffer5,
+    ColorBuffer6,
+    ColorBuffer7,
+    ZetaBuffer,
+
+    LastCommonEntry,
+};
+
+} // namespace VideoCommon::Dirty

+ 3 - 0
src/video_core/dma_pusher.cpp

@@ -21,6 +21,9 @@ MICROPROFILE_DEFINE(DispatchCalls, "GPU", "Execute command buffer", MP_RGB(128,
 void DmaPusher::DispatchCalls() {
     MICROPROFILE_SCOPE(DispatchCalls);
 
+    // On entering GPU code, assume all memory may be touched by the ARM core.
+    gpu.Maxwell3D().OnMemoryWrite();
+
     dma_pushbuffer_subindex = 0;
 
     while (Core::System::GetInstance().IsPoweredOn()) {

+ 3 - 0
src/video_core/engines/kepler_compute.cpp

@@ -38,6 +38,9 @@ void KeplerCompute::CallMethod(const GPU::MethodCall& method_call) {
     case KEPLER_COMPUTE_REG_INDEX(data_upload): {
         const bool is_last_call = method_call.IsLastCall();
         upload_state.ProcessData(method_call.argument, is_last_call);
+        if (is_last_call) {
+            system.GPU().Maxwell3D().OnMemoryWrite();
+        }
         break;
     }
     case KEPLER_COMPUTE_REG_INDEX(launch):

+ 3 - 0
src/video_core/engines/kepler_memory.cpp

@@ -33,6 +33,9 @@ void KeplerMemory::CallMethod(const GPU::MethodCall& method_call) {
     case KEPLERMEMORY_REG_INDEX(data): {
         const bool is_last_call = method_call.IsLastCall();
         upload_state.ProcessData(method_call.argument, is_last_call);
+        if (is_last_call) {
+            system.GPU().Maxwell3D().OnMemoryWrite();
+        }
         break;
     }
     }

+ 13 - 1
src/video_core/engines/maxwell_3d.cpp

@@ -26,6 +26,8 @@ Maxwell3D::Maxwell3D(Core::System& system, VideoCore::RasterizerInterface& raste
                      MemoryManager& memory_manager)
     : system{system}, rasterizer{rasterizer}, memory_manager{memory_manager},
       macro_interpreter{*this}, upload_state{memory_manager, regs.upload} {
+    dirty.flags.flip();
+
     InitializeRegisterDefaults();
 }
 
@@ -158,7 +160,13 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
     ASSERT_MSG(method < Regs::NUM_REGS,
                "Invalid Maxwell3D register, increase the size of the Regs structure");
 
-    regs.reg_array[method] = method_call.argument;
+    if (regs.reg_array[method] != method_call.argument) {
+        regs.reg_array[method] = method_call.argument;
+
+        for (const auto& table : dirty.tables) {
+            dirty.flags[table[method]] = true;
+        }
+    }
 
     switch (method) {
     case MAXWELL3D_REG_INDEX(macros.data): {
@@ -243,6 +251,9 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
     case MAXWELL3D_REG_INDEX(data_upload): {
         const bool is_last_call = method_call.IsLastCall();
         upload_state.ProcessData(method_call.argument, is_last_call);
+        if (is_last_call) {
+            OnMemoryWrite();
+        }
         break;
     }
     default:
@@ -549,6 +560,7 @@ void Maxwell3D::FinishCBData() {
 
     const u32 id = cb_data_state.id;
     memory_manager.WriteBlock(address, cb_data_state.buffer[id].data(), size);
+    OnMemoryWrite();
 
     cb_data_state.id = null_cb_data;
     cb_data_state.current = null_cb_data;

+ 14 - 0
src/video_core/engines/maxwell_3d.h

@@ -6,6 +6,7 @@
 
 #include <array>
 #include <bitset>
+#include <limits>
 #include <optional>
 #include <type_traits>
 #include <unordered_map>
@@ -1274,6 +1275,13 @@ public:
         return execute_on;
     }
 
+    /// Notify a memory write has happened.
+    void OnMemoryWrite() {
+        for (const u8 store : dirty.on_write_stores) {
+            dirty.flags[store] = true;
+        }
+    }
+
     enum class MMEDrawMode : u32 {
         Undefined,
         Array,
@@ -1289,6 +1297,12 @@ public:
         u32 gl_end_count{};
     } mme_draw;
 
+    struct {
+        std::bitset<std::numeric_limits<u8>::max()> flags;
+        std::array<std::array<u8, Regs::NUM_REGS>, 3> tables{};
+        std::array<u8, 32> on_write_stores{};
+    } dirty;
+
 private:
     void InitializeRegisterDefaults();
 

+ 3 - 0
src/video_core/engines/maxwell_dma.cpp

@@ -56,6 +56,9 @@ void MaxwellDMA::HandleCopy() {
         return;
     }
 
+    // All copies here update the main memory, so mark all rasterizer states as invalid.
+    system.GPU().Maxwell3D().OnMemoryWrite();
+
     if (regs.exec.is_dst_linear && regs.exec.is_src_linear) {
         // When the enable_2d bit is disabled, the copy is performed as if we were copying a 1D
         // buffer of length `x_count`, otherwise we copy a 2D image of dimensions (x_count,

+ 3 - 0
src/video_core/rasterizer_interface.h

@@ -89,6 +89,9 @@ public:
     virtual void LoadDiskResources(const std::atomic_bool& stop_loading = false,
                                    const DiskResourceLoadCallback& callback = {}) {}
 
+    /// Initializes renderer dirty flags
+    virtual void SetupDirtyFlags() {}
+
     /// Grant access to the Guest Driver Profile for recording/obtaining info on the guest driver.
     GuestDriverProfile& AccessGuestDriverProfile() {
         return guest_driver_profile;