diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | 15 | ||||
| -rw-r--r-- | src/video_core/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | src/video_core/command_processor.h | 53 | ||||
| -rw-r--r-- | src/video_core/dma_pusher.cpp | 123 | ||||
| -rw-r--r-- | src/video_core/dma_pusher.h | 99 | ||||
| -rw-r--r-- | src/video_core/engines/fermi_2d.cpp | 8 | ||||
| -rw-r--r-- | src/video_core/engines/fermi_2d.h | 2 | ||||
| -rw-r--r-- | src/video_core/engines/kepler_memory.cpp | 10 | ||||
| -rw-r--r-- | src/video_core/engines/kepler_memory.h | 3 | ||||
| -rw-r--r-- | src/video_core/engines/maxwell_3d.cpp | 53 | ||||
| -rw-r--r-- | src/video_core/engines/maxwell_3d.h | 2 | ||||
| -rw-r--r-- | src/video_core/engines/maxwell_compute.cpp | 8 | ||||
| -rw-r--r-- | src/video_core/engines/maxwell_compute.h | 3 | ||||
| -rw-r--r-- | src/video_core/engines/maxwell_dma.cpp | 8 | ||||
| -rw-r--r-- | src/video_core/engines/maxwell_dma.h | 2 | ||||
| -rw-r--r-- | src/video_core/gpu.cpp | 53 | ||||
| -rw-r--r-- | src/video_core/gpu.h | 27 | ||||
| -rw-r--r-- | src/video_core/macro_interpreter.cpp | 2 |
18 files changed, 365 insertions, 110 deletions
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 874d5e1c3..2e2b0ae1c 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | |||
| @@ -8,7 +8,6 @@ | |||
| 8 | #include "core/core.h" | 8 | #include "core/core.h" |
| 9 | #include "core/hle/service/nvdrv/devices/nvhost_gpu.h" | 9 | #include "core/hle/service/nvdrv/devices/nvhost_gpu.h" |
| 10 | #include "core/memory.h" | 10 | #include "core/memory.h" |
| 11 | #include "video_core/command_processor.h" | ||
| 12 | #include "video_core/gpu.h" | 11 | #include "video_core/gpu.h" |
| 13 | #include "video_core/memory_manager.h" | 12 | #include "video_core/memory_manager.h" |
| 14 | 13 | ||
| @@ -129,6 +128,12 @@ u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector< | |||
| 129 | return 0; | 128 | return 0; |
| 130 | } | 129 | } |
| 131 | 130 | ||
| 131 | static void PushGPUEntries(Tegra::CommandList&& entries) { | ||
| 132 | auto& dma_pusher{Core::System::GetInstance().GPU().DmaPusher()}; | ||
| 133 | dma_pusher.Push(std::move(entries)); | ||
| 134 | dma_pusher.DispatchCalls(); | ||
| 135 | } | ||
| 136 | |||
| 132 | u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output) { | 137 | u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output) { |
| 133 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { | 138 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { |
| 134 | UNIMPLEMENTED(); | 139 | UNIMPLEMENTED(); |
| @@ -142,11 +147,11 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp | |||
| 142 | params.num_entries * sizeof(Tegra::CommandListHeader), | 147 | params.num_entries * sizeof(Tegra::CommandListHeader), |
| 143 | "Incorrect input size"); | 148 | "Incorrect input size"); |
| 144 | 149 | ||
| 145 | std::vector<Tegra::CommandListHeader> entries(params.num_entries); | 150 | Tegra::CommandList entries(params.num_entries); |
| 146 | std::memcpy(entries.data(), &input[sizeof(IoctlSubmitGpfifo)], | 151 | std::memcpy(entries.data(), &input[sizeof(IoctlSubmitGpfifo)], |
| 147 | params.num_entries * sizeof(Tegra::CommandListHeader)); | 152 | params.num_entries * sizeof(Tegra::CommandListHeader)); |
| 148 | 153 | ||
| 149 | Core::System::GetInstance().GPU().ProcessCommandLists(entries); | 154 | PushGPUEntries(std::move(entries)); |
| 150 | 155 | ||
| 151 | params.fence_out.id = 0; | 156 | params.fence_out.id = 0; |
| 152 | params.fence_out.value = 0; | 157 | params.fence_out.value = 0; |
| @@ -163,11 +168,11 @@ u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output) | |||
| 163 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}", | 168 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}", |
| 164 | params.address, params.num_entries, params.flags); | 169 | params.address, params.num_entries, params.flags); |
| 165 | 170 | ||
| 166 | std::vector<Tegra::CommandListHeader> entries(params.num_entries); | 171 | Tegra::CommandList entries(params.num_entries); |
| 167 | Memory::ReadBlock(params.address, entries.data(), | 172 | Memory::ReadBlock(params.address, entries.data(), |
| 168 | params.num_entries * sizeof(Tegra::CommandListHeader)); | 173 | params.num_entries * sizeof(Tegra::CommandListHeader)); |
| 169 | 174 | ||
| 170 | Core::System::GetInstance().GPU().ProcessCommandLists(entries); | 175 | PushGPUEntries(std::move(entries)); |
| 171 | 176 | ||
| 172 | params.fence_out.id = 0; | 177 | params.fence_out.id = 0; |
| 173 | params.fence_out.value = 0; | 178 | params.fence_out.value = 0; |
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 3f906a517..0406fbcd9 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | add_library(video_core STATIC | 1 | add_library(video_core STATIC |
| 2 | command_processor.cpp | 2 | dma_pusher.cpp |
| 3 | command_processor.h | 3 | dma_pusher.h |
| 4 | debug_utils/debug_utils.cpp | 4 | debug_utils/debug_utils.cpp |
| 5 | debug_utils/debug_utils.h | 5 | debug_utils/debug_utils.h |
| 6 | engines/fermi_2d.cpp | 6 | engines/fermi_2d.cpp |
diff --git a/src/video_core/command_processor.h b/src/video_core/command_processor.h deleted file mode 100644 index bd766e77a..000000000 --- a/src/video_core/command_processor.h +++ /dev/null | |||
| @@ -1,53 +0,0 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <type_traits> | ||
| 8 | #include "common/bit_field.h" | ||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "video_core/memory_manager.h" | ||
| 11 | |||
| 12 | namespace Tegra { | ||
| 13 | |||
| 14 | enum class SubmissionMode : u32 { | ||
| 15 | IncreasingOld = 0, | ||
| 16 | Increasing = 1, | ||
| 17 | NonIncreasingOld = 2, | ||
| 18 | NonIncreasing = 3, | ||
| 19 | Inline = 4, | ||
| 20 | IncreaseOnce = 5 | ||
| 21 | }; | ||
| 22 | |||
| 23 | struct CommandListHeader { | ||
| 24 | u32 entry0; // gpu_va_lo | ||
| 25 | union { | ||
| 26 | u32 entry1; // gpu_va_hi | (unk_0x02 << 0x08) | (size << 0x0A) | (unk_0x01 << 0x1F) | ||
| 27 | BitField<0, 8, u32> gpu_va_hi; | ||
| 28 | BitField<8, 2, u32> unk1; | ||
| 29 | BitField<10, 21, u32> sz; | ||
| 30 | BitField<31, 1, u32> unk2; | ||
| 31 | }; | ||
| 32 | |||
| 33 | GPUVAddr Address() const { | ||
| 34 | return (static_cast<GPUVAddr>(gpu_va_hi) << 32) | entry0; | ||
| 35 | } | ||
| 36 | }; | ||
| 37 | static_assert(sizeof(CommandListHeader) == 8, "CommandListHeader is incorrect size"); | ||
| 38 | |||
| 39 | union CommandHeader { | ||
| 40 | u32 hex; | ||
| 41 | |||
| 42 | BitField<0, 13, u32> method; | ||
| 43 | BitField<13, 3, u32> subchannel; | ||
| 44 | |||
| 45 | BitField<16, 13, u32> arg_count; | ||
| 46 | BitField<16, 13, u32> inline_data; | ||
| 47 | |||
| 48 | BitField<29, 3, SubmissionMode> mode; | ||
| 49 | }; | ||
| 50 | static_assert(std::is_standard_layout_v<CommandHeader>, "CommandHeader is not standard layout"); | ||
| 51 | static_assert(sizeof(CommandHeader) == sizeof(u32), "CommandHeader has incorrect size!"); | ||
| 52 | |||
| 53 | } // namespace Tegra | ||
diff --git a/src/video_core/dma_pusher.cpp b/src/video_core/dma_pusher.cpp new file mode 100644 index 000000000..63a958f11 --- /dev/null +++ b/src/video_core/dma_pusher.cpp | |||
| @@ -0,0 +1,123 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/microprofile.h" | ||
| 6 | #include "core/core.h" | ||
| 7 | #include "core/memory.h" | ||
| 8 | #include "video_core/dma_pusher.h" | ||
| 9 | #include "video_core/engines/maxwell_3d.h" | ||
| 10 | #include "video_core/gpu.h" | ||
| 11 | |||
| 12 | namespace Tegra { | ||
| 13 | |||
| 14 | DmaPusher::DmaPusher(GPU& gpu) : gpu(gpu) {} | ||
| 15 | |||
| 16 | DmaPusher::~DmaPusher() = default; | ||
| 17 | |||
| 18 | MICROPROFILE_DEFINE(DispatchCalls, "GPU", "Execute command buffer", MP_RGB(128, 128, 192)); | ||
| 19 | |||
| 20 | void DmaPusher::DispatchCalls() { | ||
| 21 | MICROPROFILE_SCOPE(DispatchCalls); | ||
| 22 | |||
| 23 | // On entering GPU code, assume all memory may be touched by the ARM core. | ||
| 24 | gpu.Maxwell3D().dirty_flags.OnMemoryWrite(); | ||
| 25 | |||
| 26 | dma_pushbuffer_subindex = 0; | ||
| 27 | |||
| 28 | while (Core::System::GetInstance().IsPoweredOn()) { | ||
| 29 | if (!Step()) { | ||
| 30 | break; | ||
| 31 | } | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 35 | bool DmaPusher::Step() { | ||
| 36 | if (dma_get != dma_put) { | ||
| 37 | // Push buffer non-empty, read a word | ||
| 38 | const CommandHeader command_header{ | ||
| 39 | Memory::Read32(*gpu.MemoryManager().GpuToCpuAddress(dma_get))}; | ||
| 40 | |||
| 41 | dma_get += sizeof(u32); | ||
| 42 | |||
| 43 | if (!non_main) { | ||
| 44 | dma_mget = dma_get; | ||
| 45 | } | ||
| 46 | |||
| 47 | // now, see if we're in the middle of a command | ||
| 48 | if (dma_state.length_pending) { | ||
| 49 | // Second word of long non-inc methods command - method count | ||
| 50 | dma_state.length_pending = 0; | ||
| 51 | dma_state.method_count = command_header.method_count_; | ||
| 52 | } else if (dma_state.method_count) { | ||
| 53 | // Data word of methods command | ||
| 54 | CallMethod(command_header.argument); | ||
| 55 | |||
| 56 | if (!dma_state.non_incrementing) { | ||
| 57 | dma_state.method++; | ||
| 58 | } | ||
| 59 | |||
| 60 | if (dma_increment_once) { | ||
| 61 | dma_state.non_incrementing = true; | ||
| 62 | } | ||
| 63 | |||
| 64 | dma_state.method_count--; | ||
| 65 | } else { | ||
| 66 | // No command active - this is the first word of a new one | ||
| 67 | switch (command_header.mode) { | ||
| 68 | case SubmissionMode::Increasing: | ||
| 69 | SetState(command_header); | ||
| 70 | dma_state.non_incrementing = false; | ||
| 71 | dma_increment_once = false; | ||
| 72 | break; | ||
| 73 | case SubmissionMode::NonIncreasing: | ||
| 74 | SetState(command_header); | ||
| 75 | dma_state.non_incrementing = true; | ||
| 76 | dma_increment_once = false; | ||
| 77 | break; | ||
| 78 | case SubmissionMode::Inline: | ||
| 79 | dma_state.method = command_header.method; | ||
| 80 | dma_state.subchannel = command_header.subchannel; | ||
| 81 | CallMethod(command_header.arg_count); | ||
| 82 | dma_state.non_incrementing = true; | ||
| 83 | dma_increment_once = false; | ||
| 84 | break; | ||
| 85 | case SubmissionMode::IncreaseOnce: | ||
| 86 | SetState(command_header); | ||
| 87 | dma_state.non_incrementing = false; | ||
| 88 | dma_increment_once = true; | ||
| 89 | break; | ||
| 90 | } | ||
| 91 | } | ||
| 92 | } else if (ib_enable && !dma_pushbuffer.empty()) { | ||
| 93 | // Current pushbuffer empty, but we have more IB entries to read | ||
| 94 | const CommandList& command_list{dma_pushbuffer.front()}; | ||
| 95 | const CommandListHeader& command_list_header{command_list[dma_pushbuffer_subindex++]}; | ||
| 96 | dma_get = command_list_header.addr; | ||
| 97 | dma_put = dma_get + command_list_header.size * sizeof(u32); | ||
| 98 | non_main = command_list_header.is_non_main; | ||
| 99 | |||
| 100 | if (dma_pushbuffer_subindex >= command_list.size()) { | ||
| 101 | // We've gone through the current list, remove it from the queue | ||
| 102 | dma_pushbuffer.pop(); | ||
| 103 | dma_pushbuffer_subindex = 0; | ||
| 104 | } | ||
| 105 | } else { | ||
| 106 | // Otherwise, pushbuffer empty and IB empty or nonexistent - nothing to do | ||
| 107 | return {}; | ||
| 108 | } | ||
| 109 | |||
| 110 | return true; | ||
| 111 | } | ||
| 112 | |||
| 113 | void DmaPusher::SetState(const CommandHeader& command_header) { | ||
| 114 | dma_state.method = command_header.method; | ||
| 115 | dma_state.subchannel = command_header.subchannel; | ||
| 116 | dma_state.method_count = command_header.method_count; | ||
| 117 | } | ||
| 118 | |||
| 119 | void DmaPusher::CallMethod(u32 argument) const { | ||
| 120 | gpu.CallMethod({dma_state.method, argument, dma_state.subchannel, dma_state.method_count}); | ||
| 121 | } | ||
| 122 | |||
| 123 | } // namespace Tegra | ||
diff --git a/src/video_core/dma_pusher.h b/src/video_core/dma_pusher.h new file mode 100644 index 000000000..16e0697c4 --- /dev/null +++ b/src/video_core/dma_pusher.h | |||
| @@ -0,0 +1,99 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <vector> | ||
| 8 | #include <queue> | ||
| 9 | |||
| 10 | #include "common/bit_field.h" | ||
| 11 | #include "common/common_types.h" | ||
| 12 | #include "video_core/memory_manager.h" | ||
| 13 | |||
| 14 | namespace Tegra { | ||
| 15 | |||
| 16 | enum class SubmissionMode : u32 { | ||
| 17 | IncreasingOld = 0, | ||
| 18 | Increasing = 1, | ||
| 19 | NonIncreasingOld = 2, | ||
| 20 | NonIncreasing = 3, | ||
| 21 | Inline = 4, | ||
| 22 | IncreaseOnce = 5 | ||
| 23 | }; | ||
| 24 | |||
| 25 | struct CommandListHeader { | ||
| 26 | union { | ||
| 27 | u64 raw; | ||
| 28 | BitField<0, 40, GPUVAddr> addr; | ||
| 29 | BitField<41, 1, u64> is_non_main; | ||
| 30 | BitField<42, 21, u64> size; | ||
| 31 | }; | ||
| 32 | }; | ||
| 33 | static_assert(sizeof(CommandListHeader) == sizeof(u64), "CommandListHeader is incorrect size"); | ||
| 34 | |||
| 35 | union CommandHeader { | ||
| 36 | u32 argument; | ||
| 37 | BitField<0, 13, u32> method; | ||
| 38 | BitField<0, 24, u32> method_count_; | ||
| 39 | BitField<13, 3, u32> subchannel; | ||
| 40 | BitField<16, 13, u32> arg_count; | ||
| 41 | BitField<16, 13, u32> method_count; | ||
| 42 | BitField<29, 3, SubmissionMode> mode; | ||
| 43 | }; | ||
| 44 | static_assert(std::is_standard_layout_v<CommandHeader>, "CommandHeader is not standard layout"); | ||
| 45 | static_assert(sizeof(CommandHeader) == sizeof(u32), "CommandHeader has incorrect size!"); | ||
| 46 | |||
| 47 | class GPU; | ||
| 48 | |||
| 49 | using CommandList = std::vector<Tegra::CommandListHeader>; | ||
| 50 | |||
| 51 | /** | ||
| 52 | * The DmaPusher class implements DMA submission to FIFOs, providing an area of memory that the | ||
| 53 | * emulated app fills with commands and tells PFIFO to process. The pushbuffers are then assembled | ||
| 54 | * into a "command stream" consisting of 32-bit words that make up "commands". | ||
| 55 | * See https://envytools.readthedocs.io/en/latest/hw/fifo/dma-pusher.html#fifo-dma-pusher for | ||
| 56 | * details on this implementation. | ||
| 57 | */ | ||
| 58 | class DmaPusher { | ||
| 59 | public: | ||
| 60 | explicit DmaPusher(GPU& gpu); | ||
| 61 | ~DmaPusher(); | ||
| 62 | |||
| 63 | void Push(CommandList&& entries) { | ||
| 64 | dma_pushbuffer.push(std::move(entries)); | ||
| 65 | } | ||
| 66 | |||
| 67 | void DispatchCalls(); | ||
| 68 | |||
| 69 | private: | ||
| 70 | bool Step(); | ||
| 71 | |||
| 72 | void SetState(const CommandHeader& command_header); | ||
| 73 | |||
| 74 | void CallMethod(u32 argument) const; | ||
| 75 | |||
| 76 | GPU& gpu; | ||
| 77 | |||
| 78 | std::queue<CommandList> dma_pushbuffer; ///< Queue of command lists to be processed | ||
| 79 | std::size_t dma_pushbuffer_subindex{}; ///< Index within a command list within the pushbuffer | ||
| 80 | |||
| 81 | struct DmaState { | ||
| 82 | u32 method; ///< Current method | ||
| 83 | u32 subchannel; ///< Current subchannel | ||
| 84 | u32 method_count; ///< Current method count | ||
| 85 | u32 length_pending; ///< Large NI command length pending | ||
| 86 | bool non_incrementing; ///< Current command’s NI flag | ||
| 87 | }; | ||
| 88 | |||
| 89 | DmaState dma_state{}; | ||
| 90 | bool dma_increment_once{}; | ||
| 91 | |||
| 92 | GPUVAddr dma_put{}; ///< pushbuffer current end address | ||
| 93 | GPUVAddr dma_get{}; ///< pushbuffer current read address | ||
| 94 | GPUVAddr dma_mget{}; ///< main pushbuffer last read address | ||
| 95 | bool ib_enable{true}; ///< IB mode enabled | ||
| 96 | bool non_main{}; ///< non-main pushbuffer active | ||
| 97 | }; | ||
| 98 | |||
| 99 | } // namespace Tegra | ||
diff --git a/src/video_core/engines/fermi_2d.cpp b/src/video_core/engines/fermi_2d.cpp index e7721a2be..80f70e332 100644 --- a/src/video_core/engines/fermi_2d.cpp +++ b/src/video_core/engines/fermi_2d.cpp | |||
| @@ -14,13 +14,13 @@ namespace Tegra::Engines { | |||
| 14 | Fermi2D::Fermi2D(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager) | 14 | Fermi2D::Fermi2D(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager) |
| 15 | : memory_manager(memory_manager), rasterizer{rasterizer} {} | 15 | : memory_manager(memory_manager), rasterizer{rasterizer} {} |
| 16 | 16 | ||
| 17 | void Fermi2D::WriteReg(u32 method, u32 value) { | 17 | void Fermi2D::CallMethod(const GPU::MethodCall& method_call) { |
| 18 | ASSERT_MSG(method < Regs::NUM_REGS, | 18 | ASSERT_MSG(method_call.method < Regs::NUM_REGS, |
| 19 | "Invalid Fermi2D register, increase the size of the Regs structure"); | 19 | "Invalid Fermi2D register, increase the size of the Regs structure"); |
| 20 | 20 | ||
| 21 | regs.reg_array[method] = value; | 21 | regs.reg_array[method_call.method] = method_call.argument; |
| 22 | 22 | ||
| 23 | switch (method) { | 23 | switch (method_call.method) { |
| 24 | case FERMI2D_REG_INDEX(trigger): { | 24 | case FERMI2D_REG_INDEX(trigger): { |
| 25 | HandleSurfaceCopy(); | 25 | HandleSurfaceCopy(); |
| 26 | break; | 26 | break; |
diff --git a/src/video_core/engines/fermi_2d.h b/src/video_core/engines/fermi_2d.h index 2a6e8bbbb..50009bf75 100644 --- a/src/video_core/engines/fermi_2d.h +++ b/src/video_core/engines/fermi_2d.h | |||
| @@ -27,7 +27,7 @@ public: | |||
| 27 | ~Fermi2D() = default; | 27 | ~Fermi2D() = default; |
| 28 | 28 | ||
| 29 | /// Write the value to the register identified by method. | 29 | /// Write the value to the register identified by method. |
| 30 | void WriteReg(u32 method, u32 value); | 30 | void CallMethod(const GPU::MethodCall& method_call); |
| 31 | 31 | ||
| 32 | struct Regs { | 32 | struct Regs { |
| 33 | static constexpr std::size_t NUM_REGS = 0x258; | 33 | static constexpr std::size_t NUM_REGS = 0x258; |
diff --git a/src/video_core/engines/kepler_memory.cpp b/src/video_core/engines/kepler_memory.cpp index 2adbc9eaf..4880191fc 100644 --- a/src/video_core/engines/kepler_memory.cpp +++ b/src/video_core/engines/kepler_memory.cpp | |||
| @@ -17,19 +17,19 @@ KeplerMemory::KeplerMemory(VideoCore::RasterizerInterface& rasterizer, | |||
| 17 | 17 | ||
| 18 | KeplerMemory::~KeplerMemory() = default; | 18 | KeplerMemory::~KeplerMemory() = default; |
| 19 | 19 | ||
| 20 | void KeplerMemory::WriteReg(u32 method, u32 value) { | 20 | void KeplerMemory::CallMethod(const GPU::MethodCall& method_call) { |
| 21 | ASSERT_MSG(method < Regs::NUM_REGS, | 21 | ASSERT_MSG(method_call.method < Regs::NUM_REGS, |
| 22 | "Invalid KeplerMemory register, increase the size of the Regs structure"); | 22 | "Invalid KeplerMemory register, increase the size of the Regs structure"); |
| 23 | 23 | ||
| 24 | regs.reg_array[method] = value; | 24 | regs.reg_array[method_call.method] = method_call.argument; |
| 25 | 25 | ||
| 26 | switch (method) { | 26 | switch (method_call.method) { |
| 27 | case KEPLERMEMORY_REG_INDEX(exec): { | 27 | case KEPLERMEMORY_REG_INDEX(exec): { |
| 28 | state.write_offset = 0; | 28 | state.write_offset = 0; |
| 29 | break; | 29 | break; |
| 30 | } | 30 | } |
| 31 | case KEPLERMEMORY_REG_INDEX(data): { | 31 | case KEPLERMEMORY_REG_INDEX(data): { |
| 32 | ProcessData(value); | 32 | ProcessData(method_call.argument); |
| 33 | break; | 33 | break; |
| 34 | } | 34 | } |
| 35 | } | 35 | } |
diff --git a/src/video_core/engines/kepler_memory.h b/src/video_core/engines/kepler_memory.h index bf4a13cff..fe9ebc5b9 100644 --- a/src/video_core/engines/kepler_memory.h +++ b/src/video_core/engines/kepler_memory.h | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "common/bit_field.h" | 9 | #include "common/bit_field.h" |
| 10 | #include "common/common_funcs.h" | 10 | #include "common/common_funcs.h" |
| 11 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 12 | #include "video_core/gpu.h" | ||
| 12 | #include "video_core/memory_manager.h" | 13 | #include "video_core/memory_manager.h" |
| 13 | 14 | ||
| 14 | namespace VideoCore { | 15 | namespace VideoCore { |
| @@ -26,7 +27,7 @@ public: | |||
| 26 | ~KeplerMemory(); | 27 | ~KeplerMemory(); |
| 27 | 28 | ||
| 28 | /// Write the value to the register identified by method. | 29 | /// Write the value to the register identified by method. |
| 29 | void WriteReg(u32 method, u32 value); | 30 | void CallMethod(const GPU::MethodCall& method_call); |
| 30 | 31 | ||
| 31 | struct Regs { | 32 | struct Regs { |
| 32 | static constexpr size_t NUM_REGS = 0x7F; | 33 | static constexpr size_t NUM_REGS = 0x7F; |
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index f0a5470b9..b19b3a75a 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -97,71 +97,74 @@ void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) { | |||
| 97 | macro_interpreter.Execute(search->second, std::move(parameters)); | 97 | macro_interpreter.Execute(search->second, std::move(parameters)); |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) { | 100 | void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) { |
| 101 | auto debug_context = Core::System::GetInstance().GetGPUDebugContext(); | 101 | auto debug_context = Core::System::GetInstance().GetGPUDebugContext(); |
| 102 | 102 | ||
| 103 | // It is an error to write to a register other than the current macro's ARG register before it | 103 | // It is an error to write to a register other than the current macro's ARG register before it |
| 104 | // has finished execution. | 104 | // has finished execution. |
| 105 | if (executing_macro != 0) { | 105 | if (executing_macro != 0) { |
| 106 | ASSERT(method == executing_macro + 1); | 106 | ASSERT(method_call.method == executing_macro + 1); |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | // Methods after 0xE00 are special, they're actually triggers for some microcode that was | 109 | // Methods after 0xE00 are special, they're actually triggers for some microcode that was |
| 110 | // uploaded to the GPU during initialization. | 110 | // uploaded to the GPU during initialization. |
| 111 | if (method >= MacroRegistersStart) { | 111 | if (method_call.method >= MacroRegistersStart) { |
| 112 | // We're trying to execute a macro | 112 | // We're trying to execute a macro |
| 113 | if (executing_macro == 0) { | 113 | if (executing_macro == 0) { |
| 114 | // A macro call must begin by writing the macro method's register, not its argument. | 114 | // A macro call must begin by writing the macro method's register, not its argument. |
| 115 | ASSERT_MSG((method % 2) == 0, | 115 | ASSERT_MSG((method_call.method % 2) == 0, |
| 116 | "Can't start macro execution by writing to the ARGS register"); | 116 | "Can't start macro execution by writing to the ARGS register"); |
| 117 | executing_macro = method; | 117 | executing_macro = method_call.method; |
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | macro_params.push_back(value); | 120 | macro_params.push_back(method_call.argument); |
| 121 | 121 | ||
| 122 | // Call the macro when there are no more parameters in the command buffer | 122 | // Call the macro when there are no more parameters in the command buffer |
| 123 | if (remaining_params == 0) { | 123 | if (method_call.IsLastCall()) { |
| 124 | CallMacroMethod(executing_macro, std::move(macro_params)); | 124 | CallMacroMethod(executing_macro, std::move(macro_params)); |
| 125 | } | 125 | } |
| 126 | return; | 126 | return; |
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | ASSERT_MSG(method < Regs::NUM_REGS, | 129 | ASSERT_MSG(method_call.method < Regs::NUM_REGS, |
| 130 | "Invalid Maxwell3D register, increase the size of the Regs structure"); | 130 | "Invalid Maxwell3D register, increase the size of the Regs structure"); |
| 131 | 131 | ||
| 132 | if (debug_context) { | 132 | if (debug_context) { |
| 133 | debug_context->OnEvent(Tegra::DebugContext::Event::MaxwellCommandLoaded, nullptr); | 133 | debug_context->OnEvent(Tegra::DebugContext::Event::MaxwellCommandLoaded, nullptr); |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | if (regs.reg_array[method] != value) { | 136 | if (regs.reg_array[method_call.method] != method_call.argument) { |
| 137 | regs.reg_array[method] = value; | 137 | regs.reg_array[method_call.method] = method_call.argument; |
| 138 | // Vertex format | 138 | // Vertex format |
| 139 | if (method >= MAXWELL3D_REG_INDEX(vertex_attrib_format) && | 139 | if (method_call.method >= MAXWELL3D_REG_INDEX(vertex_attrib_format) && |
| 140 | method < MAXWELL3D_REG_INDEX(vertex_attrib_format) + regs.vertex_attrib_format.size()) { | 140 | method_call.method < |
| 141 | MAXWELL3D_REG_INDEX(vertex_attrib_format) + regs.vertex_attrib_format.size()) { | ||
| 141 | dirty_flags.vertex_attrib_format = true; | 142 | dirty_flags.vertex_attrib_format = true; |
| 142 | } | 143 | } |
| 143 | 144 | ||
| 144 | // Vertex buffer | 145 | // Vertex buffer |
| 145 | if (method >= MAXWELL3D_REG_INDEX(vertex_array) && | 146 | if (method_call.method >= MAXWELL3D_REG_INDEX(vertex_array) && |
| 146 | method < MAXWELL3D_REG_INDEX(vertex_array) + 4 * 32) { | 147 | method_call.method < MAXWELL3D_REG_INDEX(vertex_array) + 4 * 32) { |
| 147 | dirty_flags.vertex_array |= 1u << ((method - MAXWELL3D_REG_INDEX(vertex_array)) >> 2); | ||
| 148 | } else if (method >= MAXWELL3D_REG_INDEX(vertex_array_limit) && | ||
| 149 | method < MAXWELL3D_REG_INDEX(vertex_array_limit) + 2 * 32) { | ||
| 150 | dirty_flags.vertex_array |= | 148 | dirty_flags.vertex_array |= |
| 151 | 1u << ((method - MAXWELL3D_REG_INDEX(vertex_array_limit)) >> 1); | 149 | 1u << ((method_call.method - MAXWELL3D_REG_INDEX(vertex_array)) >> 2); |
| 152 | } else if (method >= MAXWELL3D_REG_INDEX(instanced_arrays) && | 150 | } else if (method_call.method >= MAXWELL3D_REG_INDEX(vertex_array_limit) && |
| 153 | method < MAXWELL3D_REG_INDEX(instanced_arrays) + 32) { | 151 | method_call.method < MAXWELL3D_REG_INDEX(vertex_array_limit) + 2 * 32) { |
| 154 | dirty_flags.vertex_array |= 1u << (method - MAXWELL3D_REG_INDEX(instanced_arrays)); | 152 | dirty_flags.vertex_array |= |
| 153 | 1u << ((method_call.method - MAXWELL3D_REG_INDEX(vertex_array_limit)) >> 1); | ||
| 154 | } else if (method_call.method >= MAXWELL3D_REG_INDEX(instanced_arrays) && | ||
| 155 | method_call.method < MAXWELL3D_REG_INDEX(instanced_arrays) + 32) { | ||
| 156 | dirty_flags.vertex_array |= | ||
| 157 | 1u << (method_call.method - MAXWELL3D_REG_INDEX(instanced_arrays)); | ||
| 155 | } | 158 | } |
| 156 | } | 159 | } |
| 157 | 160 | ||
| 158 | switch (method) { | 161 | switch (method_call.method) { |
| 159 | case MAXWELL3D_REG_INDEX(macros.data): { | 162 | case MAXWELL3D_REG_INDEX(macros.data): { |
| 160 | ProcessMacroUpload(value); | 163 | ProcessMacroUpload(method_call.argument); |
| 161 | break; | 164 | break; |
| 162 | } | 165 | } |
| 163 | case MAXWELL3D_REG_INDEX(macros.bind): { | 166 | case MAXWELL3D_REG_INDEX(macros.bind): { |
| 164 | ProcessMacroBind(value); | 167 | ProcessMacroBind(method_call.argument); |
| 165 | break; | 168 | break; |
| 166 | } | 169 | } |
| 167 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[0]): | 170 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[0]): |
| @@ -180,7 +183,7 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) { | |||
| 180 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[13]): | 183 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[13]): |
| 181 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[14]): | 184 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[14]): |
| 182 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[15]): { | 185 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[15]): { |
| 183 | ProcessCBData(value); | 186 | ProcessCBData(method_call.argument); |
| 184 | break; | 187 | break; |
| 185 | } | 188 | } |
| 186 | case MAXWELL3D_REG_INDEX(cb_bind[0].raw_config): { | 189 | case MAXWELL3D_REG_INDEX(cb_bind[0].raw_config): { |
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 9324d9710..84471f181 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -1080,7 +1080,7 @@ public: | |||
| 1080 | u32 GetRegisterValue(u32 method) const; | 1080 | u32 GetRegisterValue(u32 method) const; |
| 1081 | 1081 | ||
| 1082 | /// Write the value to the register identified by method. | 1082 | /// Write the value to the register identified by method. |
| 1083 | void WriteReg(u32 method, u32 value, u32 remaining_params); | 1083 | void CallMethod(const GPU::MethodCall& method_call); |
| 1084 | 1084 | ||
| 1085 | /// Returns a list of enabled textures for the specified shader stage. | 1085 | /// Returns a list of enabled textures for the specified shader stage. |
| 1086 | std::vector<Texture::FullTextureInfo> GetStageTextures(Regs::ShaderStage stage) const; | 1086 | std::vector<Texture::FullTextureInfo> GetStageTextures(Regs::ShaderStage stage) const; |
diff --git a/src/video_core/engines/maxwell_compute.cpp b/src/video_core/engines/maxwell_compute.cpp index 8b5f08351..656db6a61 100644 --- a/src/video_core/engines/maxwell_compute.cpp +++ b/src/video_core/engines/maxwell_compute.cpp | |||
| @@ -8,13 +8,13 @@ | |||
| 8 | 8 | ||
| 9 | namespace Tegra::Engines { | 9 | namespace Tegra::Engines { |
| 10 | 10 | ||
| 11 | void MaxwellCompute::WriteReg(u32 method, u32 value) { | 11 | void MaxwellCompute::CallMethod(const GPU::MethodCall& method_call) { |
| 12 | ASSERT_MSG(method < Regs::NUM_REGS, | 12 | ASSERT_MSG(method_call.method < Regs::NUM_REGS, |
| 13 | "Invalid MaxwellCompute register, increase the size of the Regs structure"); | 13 | "Invalid MaxwellCompute register, increase the size of the Regs structure"); |
| 14 | 14 | ||
| 15 | regs.reg_array[method] = value; | 15 | regs.reg_array[method_call.method] = method_call.argument; |
| 16 | 16 | ||
| 17 | switch (method) { | 17 | switch (method_call.method) { |
| 18 | case MAXWELL_COMPUTE_REG_INDEX(compute): { | 18 | case MAXWELL_COMPUTE_REG_INDEX(compute): { |
| 19 | LOG_CRITICAL(HW_GPU, "Compute shaders are not implemented"); | 19 | LOG_CRITICAL(HW_GPU, "Compute shaders are not implemented"); |
| 20 | UNREACHABLE(); | 20 | UNREACHABLE(); |
diff --git a/src/video_core/engines/maxwell_compute.h b/src/video_core/engines/maxwell_compute.h index 6ea934fb9..1d71f11bd 100644 --- a/src/video_core/engines/maxwell_compute.h +++ b/src/video_core/engines/maxwell_compute.h | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "common/bit_field.h" | 9 | #include "common/bit_field.h" |
| 10 | #include "common/common_funcs.h" | 10 | #include "common/common_funcs.h" |
| 11 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 12 | #include "video_core/gpu.h" | ||
| 12 | 13 | ||
| 13 | namespace Tegra::Engines { | 14 | namespace Tegra::Engines { |
| 14 | 15 | ||
| @@ -42,7 +43,7 @@ public: | |||
| 42 | "MaxwellCompute Regs has wrong size"); | 43 | "MaxwellCompute Regs has wrong size"); |
| 43 | 44 | ||
| 44 | /// Write the value to the register identified by method. | 45 | /// Write the value to the register identified by method. |
| 45 | void WriteReg(u32 method, u32 value); | 46 | void CallMethod(const GPU::MethodCall& method_call); |
| 46 | }; | 47 | }; |
| 47 | 48 | ||
| 48 | #define ASSERT_REG_POSITION(field_name, position) \ | 49 | #define ASSERT_REG_POSITION(field_name, position) \ |
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp index a34e884fe..06462f570 100644 --- a/src/video_core/engines/maxwell_dma.cpp +++ b/src/video_core/engines/maxwell_dma.cpp | |||
| @@ -14,16 +14,16 @@ namespace Tegra::Engines { | |||
| 14 | MaxwellDMA::MaxwellDMA(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager) | 14 | MaxwellDMA::MaxwellDMA(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager) |
| 15 | : memory_manager(memory_manager), rasterizer{rasterizer} {} | 15 | : memory_manager(memory_manager), rasterizer{rasterizer} {} |
| 16 | 16 | ||
| 17 | void MaxwellDMA::WriteReg(u32 method, u32 value) { | 17 | void MaxwellDMA::CallMethod(const GPU::MethodCall& method_call) { |
| 18 | ASSERT_MSG(method < Regs::NUM_REGS, | 18 | ASSERT_MSG(method_call.method < Regs::NUM_REGS, |
| 19 | "Invalid MaxwellDMA register, increase the size of the Regs structure"); | 19 | "Invalid MaxwellDMA register, increase the size of the Regs structure"); |
| 20 | 20 | ||
| 21 | regs.reg_array[method] = value; | 21 | regs.reg_array[method_call.method] = method_call.argument; |
| 22 | 22 | ||
| 23 | #define MAXWELLDMA_REG_INDEX(field_name) \ | 23 | #define MAXWELLDMA_REG_INDEX(field_name) \ |
| 24 | (offsetof(Tegra::Engines::MaxwellDMA::Regs, field_name) / sizeof(u32)) | 24 | (offsetof(Tegra::Engines::MaxwellDMA::Regs, field_name) / sizeof(u32)) |
| 25 | 25 | ||
| 26 | switch (method) { | 26 | switch (method_call.method) { |
| 27 | case MAXWELLDMA_REG_INDEX(exec): { | 27 | case MAXWELLDMA_REG_INDEX(exec): { |
| 28 | HandleCopy(); | 28 | HandleCopy(); |
| 29 | break; | 29 | break; |
diff --git a/src/video_core/engines/maxwell_dma.h b/src/video_core/engines/maxwell_dma.h index 5f3704f05..1f8cd65d2 100644 --- a/src/video_core/engines/maxwell_dma.h +++ b/src/video_core/engines/maxwell_dma.h | |||
| @@ -24,7 +24,7 @@ public: | |||
| 24 | ~MaxwellDMA() = default; | 24 | ~MaxwellDMA() = default; |
| 25 | 25 | ||
| 26 | /// Write the value to the register identified by method. | 26 | /// Write the value to the register identified by method. |
| 27 | void WriteReg(u32 method, u32 value); | 27 | void CallMethod(const GPU::MethodCall& method_call); |
| 28 | 28 | ||
| 29 | struct Regs { | 29 | struct Regs { |
| 30 | static constexpr std::size_t NUM_REGS = 0x1D6; | 30 | static constexpr std::size_t NUM_REGS = 0x1D6; |
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index 51b3904f6..6c81dee64 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp | |||
| @@ -26,6 +26,7 @@ u32 FramebufferConfig::BytesPerPixel(PixelFormat format) { | |||
| 26 | 26 | ||
| 27 | GPU::GPU(VideoCore::RasterizerInterface& rasterizer) { | 27 | GPU::GPU(VideoCore::RasterizerInterface& rasterizer) { |
| 28 | memory_manager = std::make_unique<Tegra::MemoryManager>(); | 28 | memory_manager = std::make_unique<Tegra::MemoryManager>(); |
| 29 | dma_pusher = std::make_unique<Tegra::DmaPusher>(*this); | ||
| 29 | maxwell_3d = std::make_unique<Engines::Maxwell3D>(rasterizer, *memory_manager); | 30 | maxwell_3d = std::make_unique<Engines::Maxwell3D>(rasterizer, *memory_manager); |
| 30 | fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer, *memory_manager); | 31 | fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer, *memory_manager); |
| 31 | maxwell_compute = std::make_unique<Engines::MaxwellCompute>(); | 32 | maxwell_compute = std::make_unique<Engines::MaxwellCompute>(); |
| @@ -51,6 +52,14 @@ const MemoryManager& GPU::MemoryManager() const { | |||
| 51 | return *memory_manager; | 52 | return *memory_manager; |
| 52 | } | 53 | } |
| 53 | 54 | ||
| 55 | DmaPusher& GPU::DmaPusher() { | ||
| 56 | return *dma_pusher; | ||
| 57 | } | ||
| 58 | |||
| 59 | const DmaPusher& GPU::DmaPusher() const { | ||
| 60 | return *dma_pusher; | ||
| 61 | } | ||
| 62 | |||
| 54 | u32 RenderTargetBytesPerPixel(RenderTargetFormat format) { | 63 | u32 RenderTargetBytesPerPixel(RenderTargetFormat format) { |
| 55 | ASSERT(format != RenderTargetFormat::NONE); | 64 | ASSERT(format != RenderTargetFormat::NONE); |
| 56 | 65 | ||
| @@ -113,4 +122,48 @@ u32 DepthFormatBytesPerPixel(DepthFormat format) { | |||
| 113 | } | 122 | } |
| 114 | } | 123 | } |
| 115 | 124 | ||
| 125 | enum class BufferMethods { | ||
| 126 | BindObject = 0, | ||
| 127 | CountBufferMethods = 0x40, | ||
| 128 | }; | ||
| 129 | |||
| 130 | void GPU::CallMethod(const MethodCall& method_call) { | ||
| 131 | LOG_TRACE(HW_GPU, | ||
| 132 | "Processing method {:08X} on subchannel {} value " | ||
| 133 | "{:08X} remaining params {}", | ||
| 134 | MethCall.method, MethCall.subchannel, value, remaining_params); | ||
| 135 | |||
| 136 | ASSERT(method_call.subchannel < bound_engines.size()); | ||
| 137 | |||
| 138 | if (method_call.method == static_cast<u32>(BufferMethods::BindObject)) { | ||
| 139 | // Bind the current subchannel to the desired engine id. | ||
| 140 | LOG_DEBUG(HW_GPU, "Binding subchannel {} to engine {}", method_call.subchannel, | ||
| 141 | method_call.argument); | ||
| 142 | bound_engines[method_call.subchannel] = static_cast<EngineID>(method_call.argument); | ||
| 143 | return; | ||
| 144 | } | ||
| 145 | |||
| 146 | const EngineID engine = bound_engines[method_call.subchannel]; | ||
| 147 | |||
| 148 | switch (engine) { | ||
| 149 | case EngineID::FERMI_TWOD_A: | ||
| 150 | fermi_2d->CallMethod(method_call); | ||
| 151 | break; | ||
| 152 | case EngineID::MAXWELL_B: | ||
| 153 | maxwell_3d->CallMethod(method_call); | ||
| 154 | break; | ||
| 155 | case EngineID::MAXWELL_COMPUTE_B: | ||
| 156 | maxwell_compute->CallMethod(method_call); | ||
| 157 | break; | ||
| 158 | case EngineID::MAXWELL_DMA_COPY_A: | ||
| 159 | maxwell_dma->CallMethod(method_call); | ||
| 160 | break; | ||
| 161 | case EngineID::KEPLER_INLINE_TO_MEMORY_B: | ||
| 162 | kepler_memory->CallMethod(method_call); | ||
| 163 | break; | ||
| 164 | default: | ||
| 165 | UNIMPLEMENTED_MSG("Unimplemented engine"); | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 116 | } // namespace Tegra | 169 | } // namespace Tegra |
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index 5cc1e19ca..af5ccd1e9 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include <vector> | 9 | #include <vector> |
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "core/hle/service/nvflinger/buffer_queue.h" | 11 | #include "core/hle/service/nvflinger/buffer_queue.h" |
| 12 | #include "video_core/dma_pusher.h" | ||
| 12 | #include "video_core/memory_manager.h" | 13 | #include "video_core/memory_manager.h" |
| 13 | 14 | ||
| 14 | namespace VideoCore { | 15 | namespace VideoCore { |
| @@ -119,8 +120,23 @@ public: | |||
| 119 | explicit GPU(VideoCore::RasterizerInterface& rasterizer); | 120 | explicit GPU(VideoCore::RasterizerInterface& rasterizer); |
| 120 | ~GPU(); | 121 | ~GPU(); |
| 121 | 122 | ||
| 122 | /// Processes a command list stored at the specified address in GPU memory. | 123 | struct MethodCall { |
| 123 | void ProcessCommandLists(const std::vector<CommandListHeader>& commands); | 124 | u32 method{}; |
| 125 | u32 argument{}; | ||
| 126 | u32 subchannel{}; | ||
| 127 | u32 method_count{}; | ||
| 128 | |||
| 129 | bool IsLastCall() const { | ||
| 130 | return method_count <= 1; | ||
| 131 | } | ||
| 132 | |||
| 133 | MethodCall(u32 method, u32 argument, u32 subchannel = 0, u32 method_count = 0) | ||
| 134 | : method(method), argument(argument), subchannel(subchannel), | ||
| 135 | method_count(method_count) {} | ||
| 136 | }; | ||
| 137 | |||
| 138 | /// Calls a GPU method. | ||
| 139 | void CallMethod(const MethodCall& method_call); | ||
| 124 | 140 | ||
| 125 | /// Returns a reference to the Maxwell3D GPU engine. | 141 | /// Returns a reference to the Maxwell3D GPU engine. |
| 126 | Engines::Maxwell3D& Maxwell3D(); | 142 | Engines::Maxwell3D& Maxwell3D(); |
| @@ -134,7 +150,14 @@ public: | |||
| 134 | /// Returns a const reference to the GPU memory manager. | 150 | /// Returns a const reference to the GPU memory manager. |
| 135 | const Tegra::MemoryManager& MemoryManager() const; | 151 | const Tegra::MemoryManager& MemoryManager() const; |
| 136 | 152 | ||
| 153 | /// Returns a reference to the GPU DMA pusher. | ||
| 154 | Tegra::DmaPusher& DmaPusher(); | ||
| 155 | |||
| 156 | /// Returns a const reference to the GPU DMA pusher. | ||
| 157 | const Tegra::DmaPusher& DmaPusher() const; | ||
| 158 | |||
| 137 | private: | 159 | private: |
| 160 | std::unique_ptr<Tegra::DmaPusher> dma_pusher; | ||
| 138 | std::unique_ptr<Tegra::MemoryManager> memory_manager; | 161 | std::unique_ptr<Tegra::MemoryManager> memory_manager; |
| 139 | 162 | ||
| 140 | /// Mapping of command subchannels to their bound engine ids. | 163 | /// Mapping of command subchannels to their bound engine ids. |
diff --git a/src/video_core/macro_interpreter.cpp b/src/video_core/macro_interpreter.cpp index 2b0dea5cd..9c55e9f1e 100644 --- a/src/video_core/macro_interpreter.cpp +++ b/src/video_core/macro_interpreter.cpp | |||
| @@ -250,7 +250,7 @@ void MacroInterpreter::SetMethodAddress(u32 address) { | |||
| 250 | } | 250 | } |
| 251 | 251 | ||
| 252 | void MacroInterpreter::Send(u32 value) { | 252 | void MacroInterpreter::Send(u32 value) { |
| 253 | maxwell3d.WriteReg(method_address.address, value, 0); | 253 | maxwell3d.CallMethod({method_address.address, value}); |
| 254 | // Increment the method address by the method increment. | 254 | // Increment the method address by the method increment. |
| 255 | method_address.address.Assign(method_address.address.Value() + | 255 | method_address.address.Assign(method_address.address.Value() + |
| 256 | method_address.increment.Value()); | 256 | method_address.increment.Value()); |