diff options
| author | 2018-10-17 21:29:10 -0400 | |
|---|---|---|
| committer | 2018-10-18 22:41:53 -0400 | |
| commit | 7e665c2721863fe9784dd3de4aa430434fb10cff (patch) | |
| tree | 4b8c4101ff74bd76794e298715f7aac8e2168396 | |
| parent | decoders: Introduce functions for un/swizzling subrects. (diff) | |
| download | yuzu-7e665c2721863fe9784dd3de4aa430434fb10cff.tar.gz yuzu-7e665c2721863fe9784dd3de4aa430434fb10cff.tar.xz yuzu-7e665c2721863fe9784dd3de4aa430434fb10cff.zip | |
GPU: Improved implementation of maxwell DMA (Subv).
| -rw-r--r-- | src/video_core/engines/maxwell_dma.cpp | 73 | ||||
| -rw-r--r-- | src/video_core/engines/maxwell_dma.h | 8 | ||||
| -rw-r--r-- | src/video_core/gpu.cpp | 2 |
3 files changed, 66 insertions, 17 deletions
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp index bf2a21bb6..103cd110e 100644 --- a/src/video_core/engines/maxwell_dma.cpp +++ b/src/video_core/engines/maxwell_dma.cpp | |||
| @@ -4,12 +4,14 @@ | |||
| 4 | 4 | ||
| 5 | #include "core/memory.h" | 5 | #include "core/memory.h" |
| 6 | #include "video_core/engines/maxwell_dma.h" | 6 | #include "video_core/engines/maxwell_dma.h" |
| 7 | #include "video_core/rasterizer_interface.h" | ||
| 7 | #include "video_core/textures/decoders.h" | 8 | #include "video_core/textures/decoders.h" |
| 8 | 9 | ||
| 9 | namespace Tegra { | 10 | namespace Tegra { |
| 10 | namespace Engines { | 11 | namespace Engines { |
| 11 | 12 | ||
| 12 | MaxwellDMA::MaxwellDMA(MemoryManager& memory_manager) : memory_manager(memory_manager) {} | 13 | MaxwellDMA::MaxwellDMA(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager) |
| 14 | : memory_manager(memory_manager), rasterizer{rasterizer} {} | ||
| 13 | 15 | ||
| 14 | void MaxwellDMA::WriteReg(u32 method, u32 value) { | 16 | void MaxwellDMA::WriteReg(u32 method, u32 value) { |
| 15 | ASSERT_MSG(method < Regs::NUM_REGS, | 17 | ASSERT_MSG(method < Regs::NUM_REGS, |
| @@ -44,38 +46,79 @@ void MaxwellDMA::HandleCopy() { | |||
| 44 | ASSERT(regs.exec.query_mode == Regs::QueryMode::None); | 46 | ASSERT(regs.exec.query_mode == Regs::QueryMode::None); |
| 45 | ASSERT(regs.exec.query_intr == Regs::QueryIntr::None); | 47 | ASSERT(regs.exec.query_intr == Regs::QueryIntr::None); |
| 46 | ASSERT(regs.exec.copy_mode == Regs::CopyMode::Unk2); | 48 | ASSERT(regs.exec.copy_mode == Regs::CopyMode::Unk2); |
| 47 | ASSERT(regs.src_params.pos_x == 0); | ||
| 48 | ASSERT(regs.src_params.pos_y == 0); | ||
| 49 | ASSERT(regs.dst_params.pos_x == 0); | 49 | ASSERT(regs.dst_params.pos_x == 0); |
| 50 | ASSERT(regs.dst_params.pos_y == 0); | 50 | ASSERT(regs.dst_params.pos_y == 0); |
| 51 | 51 | ||
| 52 | if (regs.exec.is_dst_linear == regs.exec.is_src_linear) { | 52 | if (!regs.exec.is_dst_linear && !regs.exec.is_src_linear) { |
| 53 | std::size_t copy_size = regs.x_count; | 53 | // If both the source and the destination are in block layout, assert. |
| 54 | UNREACHABLE_MSG("Tiled->Tiled DMA transfers are not yet implemented"); | ||
| 55 | return; | ||
| 56 | } | ||
| 54 | 57 | ||
| 58 | if (regs.exec.is_dst_linear && regs.exec.is_src_linear) { | ||
| 55 | // When the enable_2d bit is disabled, the copy is performed as if we were copying a 1D | 59 | // When the enable_2d bit is disabled, the copy is performed as if we were copying a 1D |
| 56 | // buffer of length `x_count`, otherwise we copy a 2D buffer of size (x_count, y_count). | 60 | // buffer of length `x_count`, otherwise we copy a 2D image of dimensions (x_count, |
| 57 | if (regs.exec.enable_2d) { | 61 | // y_count). |
| 58 | copy_size = copy_size * regs.y_count; | 62 | if (!regs.exec.enable_2d) { |
| 63 | Memory::CopyBlock(dest_cpu, source_cpu, regs.x_count); | ||
| 64 | return; | ||
| 59 | } | 65 | } |
| 60 | 66 | ||
| 61 | Memory::CopyBlock(dest_cpu, source_cpu, copy_size); | 67 | // If both the source and the destination are in linear layout, perform a line-by-line |
| 68 | // copy. We're going to take a subrect of size (x_count, y_count) from the source | ||
| 69 | // rectangle. There is no need to manually flush/invalidate the regions because | ||
| 70 | // CopyBlock does that for us. | ||
| 71 | for (u32 line = 0; line < regs.y_count; ++line) { | ||
| 72 | const VAddr source_line = source_cpu + line * regs.src_pitch; | ||
| 73 | const VAddr dest_line = dest_cpu + line * regs.dst_pitch; | ||
| 74 | Memory::CopyBlock(dest_line, source_line, regs.x_count); | ||
| 75 | } | ||
| 62 | return; | 76 | return; |
| 63 | } | 77 | } |
| 64 | 78 | ||
| 65 | ASSERT(regs.exec.enable_2d == 1); | 79 | ASSERT(regs.exec.enable_2d == 1); |
| 80 | |||
| 81 | std::size_t copy_size = regs.x_count * regs.y_count; | ||
| 82 | |||
| 83 | const auto FlushAndInvalidate = [&](u32 src_size, u32 dst_size) { | ||
| 84 | // TODO(Subv): For now, manually flush the regions until we implement GPU-accelerated | ||
| 85 | // copying. | ||
| 86 | rasterizer.FlushRegion(source_cpu, src_size); | ||
| 87 | |||
| 88 | // We have to invalidate the destination region to evict any outdated surfaces from the | ||
| 89 | // cache. We do this before actually writing the new data because the destination address | ||
| 90 | // might contain a dirty surface that will have to be written back to memory. | ||
| 91 | rasterizer.InvalidateRegion(dest_cpu, dst_size); | ||
| 92 | }; | ||
| 93 | |||
| 66 | u8* src_buffer = Memory::GetPointer(source_cpu); | 94 | u8* src_buffer = Memory::GetPointer(source_cpu); |
| 67 | u8* dst_buffer = Memory::GetPointer(dest_cpu); | 95 | u8* dst_buffer = Memory::GetPointer(dest_cpu); |
| 68 | 96 | ||
| 69 | if (regs.exec.is_dst_linear && !regs.exec.is_src_linear) { | 97 | if (regs.exec.is_dst_linear && !regs.exec.is_src_linear) { |
| 98 | ASSERT(regs.src_params.size_z == 1); | ||
| 70 | // If the input is tiled and the output is linear, deswizzle the input and copy it over. | 99 | // If the input is tiled and the output is linear, deswizzle the input and copy it over. |
| 71 | Texture::CopySwizzledData(regs.src_params.size_x, regs.src_params.size_y, | 100 | |
| 72 | regs.src_params.size_z, 1, 1, src_buffer, dst_buffer, true, | 101 | u32 src_bytes_per_pixel = regs.src_pitch / regs.src_params.size_x; |
| 73 | regs.src_params.BlockHeight(), regs.src_params.BlockDepth()); | 102 | |
| 103 | FlushAndInvalidate(regs.src_pitch * regs.src_params.size_y, | ||
| 104 | copy_size * src_bytes_per_pixel); | ||
| 105 | |||
| 106 | Texture::UnswizzleSubrect(regs.x_count, regs.y_count, regs.dst_pitch, | ||
| 107 | regs.src_params.size_x, src_bytes_per_pixel, source_cpu, dest_cpu, | ||
| 108 | regs.src_params.BlockHeight(), regs.src_params.pos_x, | ||
| 109 | regs.src_params.pos_y); | ||
| 74 | } else { | 110 | } else { |
| 111 | ASSERT(regs.dst_params.size_z == 1); | ||
| 112 | ASSERT(regs.src_pitch == regs.x_count); | ||
| 113 | |||
| 114 | u32 src_bpp = regs.src_pitch / regs.x_count; | ||
| 115 | |||
| 116 | FlushAndInvalidate(regs.src_pitch * regs.y_count, | ||
| 117 | regs.dst_params.size_x * regs.dst_params.size_y * src_bpp); | ||
| 118 | |||
| 75 | // If the input is linear and the output is tiled, swizzle the input and copy it over. | 119 | // If the input is linear and the output is tiled, swizzle the input and copy it over. |
| 76 | Texture::CopySwizzledData(regs.dst_params.size_x, regs.dst_params.size_y, | 120 | Texture::SwizzleSubrect(regs.x_count, regs.y_count, regs.src_pitch, regs.dst_params.size_x, |
| 77 | regs.dst_params.size_z, 1, 1, dst_buffer, src_buffer, false, | 121 | src_bpp, dest_cpu, source_cpu, regs.dst_params.BlockHeight()); |
| 78 | regs.dst_params.BlockHeight(), regs.dst_params.BlockDepth()); | ||
| 79 | } | 122 | } |
| 80 | } | 123 | } |
| 81 | 124 | ||
diff --git a/src/video_core/engines/maxwell_dma.h b/src/video_core/engines/maxwell_dma.h index df19e02e2..5f3704f05 100644 --- a/src/video_core/engines/maxwell_dma.h +++ b/src/video_core/engines/maxwell_dma.h | |||
| @@ -12,11 +12,15 @@ | |||
| 12 | #include "video_core/gpu.h" | 12 | #include "video_core/gpu.h" |
| 13 | #include "video_core/memory_manager.h" | 13 | #include "video_core/memory_manager.h" |
| 14 | 14 | ||
| 15 | namespace VideoCore { | ||
| 16 | class RasterizerInterface; | ||
| 17 | } | ||
| 18 | |||
| 15 | namespace Tegra::Engines { | 19 | namespace Tegra::Engines { |
| 16 | 20 | ||
| 17 | class MaxwellDMA final { | 21 | class MaxwellDMA final { |
| 18 | public: | 22 | public: |
| 19 | explicit MaxwellDMA(MemoryManager& memory_manager); | 23 | explicit MaxwellDMA(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager); |
| 20 | ~MaxwellDMA() = default; | 24 | ~MaxwellDMA() = default; |
| 21 | 25 | ||
| 22 | /// Write the value to the register identified by method. | 26 | /// Write the value to the register identified by method. |
| @@ -133,6 +137,8 @@ public: | |||
| 133 | MemoryManager& memory_manager; | 137 | MemoryManager& memory_manager; |
| 134 | 138 | ||
| 135 | private: | 139 | private: |
| 140 | VideoCore::RasterizerInterface& rasterizer; | ||
| 141 | |||
| 136 | /// Performs the copy from the source buffer to the destination buffer as configured in the | 142 | /// Performs the copy from the source buffer to the destination buffer as configured in the |
| 137 | /// registers. | 143 | /// registers. |
| 138 | void HandleCopy(); | 144 | void HandleCopy(); |
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index 2d70a833b..83c7e5b0b 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp | |||
| @@ -27,7 +27,7 @@ GPU::GPU(VideoCore::RasterizerInterface& rasterizer) { | |||
| 27 | maxwell_3d = std::make_unique<Engines::Maxwell3D>(rasterizer, *memory_manager); | 27 | maxwell_3d = std::make_unique<Engines::Maxwell3D>(rasterizer, *memory_manager); |
| 28 | fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer, *memory_manager); | 28 | fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer, *memory_manager); |
| 29 | maxwell_compute = std::make_unique<Engines::MaxwellCompute>(); | 29 | maxwell_compute = std::make_unique<Engines::MaxwellCompute>(); |
| 30 | maxwell_dma = std::make_unique<Engines::MaxwellDMA>(*memory_manager); | 30 | maxwell_dma = std::make_unique<Engines::MaxwellDMA>(rasterizer, *memory_manager); |
| 31 | kepler_memory = std::make_unique<Engines::KeplerMemory>(rasterizer, *memory_manager); | 31 | kepler_memory = std::make_unique<Engines::KeplerMemory>(rasterizer, *memory_manager); |
| 32 | } | 32 | } |
| 33 | 33 | ||