summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2018-04-25 20:40:17 -0400
committerGravatar GitHub2018-04-25 20:40:17 -0400
commit42d43ea741886b9592fd7dfd57c33228afacf44c (patch)
treeabfeb405b9c710816ad9ea8e06ea14854c0eb4a9 /src
parentMerge pull request #395 from lioncash/file-sys (diff)
parentGPU: Partially implemented the Fermi2D surface copy operation. (diff)
downloadyuzu-42d43ea741886b9592fd7dfd57c33228afacf44c.tar.gz
yuzu-42d43ea741886b9592fd7dfd57c33228afacf44c.tar.xz
yuzu-42d43ea741886b9592fd7dfd57c33228afacf44c.zip
Merge pull request #387 from Subv/maxwell_2d
GPU: Partially implemented the 2D surface copy engine
Diffstat (limited to 'src')
-rw-r--r--src/core/memory.cpp4
-rw-r--r--src/video_core/command_processor.cpp27
-rw-r--r--src/video_core/engines/fermi_2d.cpp61
-rw-r--r--src/video_core/engines/fermi_2d.h89
-rw-r--r--src/video_core/engines/maxwell_3d.cpp20
-rw-r--r--src/video_core/engines/maxwell_3d.h21
-rw-r--r--src/video_core/gpu.cpp14
-rw-r--r--src/video_core/gpu.h10
-rw-r--r--src/video_core/textures/decoders.cpp5
-rw-r--r--src/video_core/textures/decoders.h4
10 files changed, 203 insertions, 52 deletions
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index d7c0080fa..2afa0916d 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -659,6 +659,10 @@ void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
659 } 659 }
660} 660}
661 661
662void CopyBlock(VAddr dest_addr, VAddr src_addr, size_t size) {
663 CopyBlock(*Core::CurrentProcess(), dest_addr, src_addr, size);
664}
665
662boost::optional<PAddr> TryVirtualToPhysicalAddress(const VAddr addr) { 666boost::optional<PAddr> TryVirtualToPhysicalAddress(const VAddr addr) {
663 if (addr == 0) { 667 if (addr == 0) {
664 return 0; 668 return 0;
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index f6a88f031..2eaece298 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -24,10 +24,7 @@ namespace Tegra {
24 24
25enum class BufferMethods { 25enum class BufferMethods {
26 BindObject = 0, 26 BindObject = 0,
27 SetGraphMacroCode = 0x45, 27 CountBufferMethods = 0x40,
28 SetGraphMacroCodeArg = 0x46,
29 SetGraphMacroEntry = 0x47,
30 CountBufferMethods = 0x100,
31}; 28};
32 29
33void GPU::WriteReg(u32 method, u32 subchannel, u32 value, u32 remaining_params) { 30void GPU::WriteReg(u32 method, u32 subchannel, u32 value, u32 remaining_params) {
@@ -36,28 +33,6 @@ void GPU::WriteReg(u32 method, u32 subchannel, u32 value, u32 remaining_params)
36 "{:08X} remaining params {}", 33 "{:08X} remaining params {}",
37 method, subchannel, value, remaining_params); 34 method, subchannel, value, remaining_params);
38 35
39 if (method == static_cast<u32>(BufferMethods::SetGraphMacroEntry)) {
40 // Prepare to upload a new macro, reset the upload counter.
41 NGLOG_DEBUG(HW_GPU, "Uploading GPU macro {:08X}", value);
42 current_macro_entry = value;
43 current_macro_code.clear();
44 return;
45 }
46
47 if (method == static_cast<u32>(BufferMethods::SetGraphMacroCodeArg)) {
48 // Append a new code word to the current macro.
49 current_macro_code.push_back(value);
50
51 // There are no more params remaining, submit the code to the 3D engine.
52 if (remaining_params == 0) {
53 maxwell_3d->SubmitMacroCode(current_macro_entry, std::move(current_macro_code));
54 current_macro_entry = InvalidGraphMacroEntry;
55 current_macro_code.clear();
56 }
57
58 return;
59 }
60
61 if (method == static_cast<u32>(BufferMethods::BindObject)) { 36 if (method == static_cast<u32>(BufferMethods::BindObject)) {
62 // Bind the current subchannel to the desired engine id. 37 // Bind the current subchannel to the desired engine id.
63 NGLOG_DEBUG(HW_GPU, "Binding subchannel {} to engine {}", subchannel, value); 38 NGLOG_DEBUG(HW_GPU, "Binding subchannel {} to engine {}", subchannel, value);
diff --git a/src/video_core/engines/fermi_2d.cpp b/src/video_core/engines/fermi_2d.cpp
index 7aab163dc..9019f2504 100644
--- a/src/video_core/engines/fermi_2d.cpp
+++ b/src/video_core/engines/fermi_2d.cpp
@@ -2,12 +2,71 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/memory.h"
5#include "video_core/engines/fermi_2d.h" 6#include "video_core/engines/fermi_2d.h"
7#include "video_core/textures/decoders.h"
6 8
7namespace Tegra { 9namespace Tegra {
8namespace Engines { 10namespace Engines {
9 11
10void Fermi2D::WriteReg(u32 method, u32 value) {} 12Fermi2D::Fermi2D(MemoryManager& memory_manager) : memory_manager(memory_manager) {}
13
14void Fermi2D::WriteReg(u32 method, u32 value) {
15 ASSERT_MSG(method < Regs::NUM_REGS,
16 "Invalid Fermi2D register, increase the size of the Regs structure");
17
18 regs.reg_array[method] = value;
19
20 switch (method) {
21 case FERMI2D_REG_INDEX(trigger): {
22 HandleSurfaceCopy();
23 break;
24 }
25 }
26}
27
28void Fermi2D::HandleSurfaceCopy() {
29 NGLOG_WARNING(HW_GPU, "Requested a surface copy with operation {}",
30 static_cast<u32>(regs.operation));
31
32 const GPUVAddr source = regs.src.Address();
33 const GPUVAddr dest = regs.dst.Address();
34
35 // TODO(Subv): Only same-format and same-size copies are allowed for now.
36 ASSERT(regs.src.format == regs.dst.format);
37 ASSERT(regs.src.width * regs.src.height == regs.dst.width * regs.dst.height);
38
39 // TODO(Subv): Only raw copies are implemented.
40 ASSERT(regs.operation == Regs::Operation::SrcCopy);
41
42 const VAddr source_cpu = *memory_manager.GpuToCpuAddress(source);
43 const VAddr dest_cpu = *memory_manager.GpuToCpuAddress(dest);
44
45 u32 src_bytes_per_pixel = RenderTargetBytesPerPixel(regs.src.format);
46 u32 dst_bytes_per_pixel = RenderTargetBytesPerPixel(regs.dst.format);
47
48 if (regs.src.linear == regs.dst.linear) {
49 // If the input layout and the output layout are the same, just perform a raw copy.
50 Memory::CopyBlock(dest_cpu, source_cpu,
51 src_bytes_per_pixel * regs.dst.width * regs.dst.height);
52 return;
53 }
54
55 u8* src_buffer = Memory::GetPointer(source_cpu);
56 u8* dst_buffer = Memory::GetPointer(dest_cpu);
57
58 if (!regs.src.linear && regs.dst.linear) {
59 // If the input is tiled and the output is linear, deswizzle the input and copy it over.
60 Texture::CopySwizzledData(regs.src.width, regs.src.height, src_bytes_per_pixel,
61 dst_bytes_per_pixel, src_buffer, dst_buffer, true,
62 regs.src.block_height);
63 } else {
64 // If the input is linear and the output is tiled, swizzle the input and copy it over.
65 Texture::CopySwizzledData(regs.src.width, regs.src.height, src_bytes_per_pixel,
66 dst_bytes_per_pixel, dst_buffer, src_buffer, false,
67 regs.dst.block_height);
68 }
69}
11 70
12} // namespace Engines 71} // namespace Engines
13} // namespace Tegra 72} // namespace Tegra
diff --git a/src/video_core/engines/fermi_2d.h b/src/video_core/engines/fermi_2d.h
index 8967ddede..0c5b413cc 100644
--- a/src/video_core/engines/fermi_2d.h
+++ b/src/video_core/engines/fermi_2d.h
@@ -4,19 +4,106 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
8#include "common/assert.h"
9#include "common/bit_field.h"
10#include "common/common_funcs.h"
7#include "common/common_types.h" 11#include "common/common_types.h"
12#include "video_core/gpu.h"
13#include "video_core/memory_manager.h"
8 14
9namespace Tegra { 15namespace Tegra {
10namespace Engines { 16namespace Engines {
11 17
18#define FERMI2D_REG_INDEX(field_name) \
19 (offsetof(Tegra::Engines::Fermi2D::Regs, field_name) / sizeof(u32))
20
12class Fermi2D final { 21class Fermi2D final {
13public: 22public:
14 Fermi2D() = default; 23 explicit Fermi2D(MemoryManager& memory_manager);
15 ~Fermi2D() = default; 24 ~Fermi2D() = default;
16 25
17 /// Write the value to the register identified by method. 26 /// Write the value to the register identified by method.
18 void WriteReg(u32 method, u32 value); 27 void WriteReg(u32 method, u32 value);
28
29 struct Regs {
30 static constexpr size_t NUM_REGS = 0x258;
31
32 struct Surface {
33 RenderTargetFormat format;
34 BitField<0, 1, u32> linear;
35 union {
36 BitField<0, 4, u32> block_depth;
37 BitField<4, 4, u32> block_height;
38 BitField<8, 4, u32> block_width;
39 };
40 u32 depth;
41 u32 layer;
42 u32 pitch;
43 u32 width;
44 u32 height;
45 u32 address_high;
46 u32 address_low;
47
48 GPUVAddr Address() const {
49 return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) |
50 address_low);
51 }
52 };
53 static_assert(sizeof(Surface) == 0x28, "Surface has incorrect size");
54
55 enum class Operation : u32 {
56 SrcCopyAnd = 0,
57 ROPAnd = 1,
58 Blend = 2,
59 SrcCopy = 3,
60 ROP = 4,
61 SrcCopyPremult = 5,
62 BlendPremult = 6,
63 };
64
65 union {
66 struct {
67 INSERT_PADDING_WORDS(0x80);
68
69 Surface dst;
70
71 INSERT_PADDING_WORDS(2);
72
73 Surface src;
74
75 INSERT_PADDING_WORDS(0x15);
76
77 Operation operation;
78
79 INSERT_PADDING_WORDS(0x9);
80
81 // TODO(Subv): This is only a guess.
82 u32 trigger;
83
84 INSERT_PADDING_WORDS(0x1A3);
85 };
86 std::array<u32, NUM_REGS> reg_array;
87 };
88 } regs{};
89
90 MemoryManager& memory_manager;
91
92private:
93 /// Performs the copy from the source surface to the destination surface as configured in the
94 /// registers.
95 void HandleSurfaceCopy();
19}; 96};
20 97
98#define ASSERT_REG_POSITION(field_name, position) \
99 static_assert(offsetof(Fermi2D::Regs, field_name) == position * 4, \
100 "Field " #field_name " has invalid position")
101
102ASSERT_REG_POSITION(dst, 0x80);
103ASSERT_REG_POSITION(src, 0x8C);
104ASSERT_REG_POSITION(operation, 0xAB);
105ASSERT_REG_POSITION(trigger, 0xB5);
106#undef ASSERT_REG_POSITION
107
21} // namespace Engines 108} // namespace Engines
22} // namespace Tegra 109} // namespace Tegra
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 2acbb9cd6..4306b894f 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -22,10 +22,6 @@ constexpr u32 MacroRegistersStart = 0xE00;
22Maxwell3D::Maxwell3D(MemoryManager& memory_manager) 22Maxwell3D::Maxwell3D(MemoryManager& memory_manager)
23 : memory_manager(memory_manager), macro_interpreter(*this) {} 23 : memory_manager(memory_manager), macro_interpreter(*this) {}
24 24
25void Maxwell3D::SubmitMacroCode(u32 entry, std::vector<u32> code) {
26 uploaded_macros[entry * 2 + MacroRegistersStart] = std::move(code);
27}
28
29void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) { 25void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) {
30 auto macro_code = uploaded_macros.find(method); 26 auto macro_code = uploaded_macros.find(method);
31 // The requested macro must have been uploaded already. 27 // The requested macro must have been uploaded already.
@@ -37,9 +33,6 @@ void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) {
37} 33}
38 34
39void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) { 35void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
40 ASSERT_MSG(method < Regs::NUM_REGS,
41 "Invalid Maxwell3D register, increase the size of the Regs structure");
42
43 auto debug_context = Core::System::GetInstance().GetGPUDebugContext(); 36 auto debug_context = Core::System::GetInstance().GetGPUDebugContext();
44 37
45 // It is an error to write to a register other than the current macro's ARG register before it 38 // It is an error to write to a register other than the current macro's ARG register before it
@@ -68,6 +61,9 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
68 return; 61 return;
69 } 62 }
70 63
64 ASSERT_MSG(method < Regs::NUM_REGS,
65 "Invalid Maxwell3D register, increase the size of the Regs structure");
66
71 if (debug_context) { 67 if (debug_context) {
72 debug_context->OnEvent(Tegra::DebugContext::Event::MaxwellCommandLoaded, nullptr); 68 debug_context->OnEvent(Tegra::DebugContext::Event::MaxwellCommandLoaded, nullptr);
73 } 69 }
@@ -75,6 +71,10 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
75 regs.reg_array[method] = value; 71 regs.reg_array[method] = value;
76 72
77 switch (method) { 73 switch (method) {
74 case MAXWELL3D_REG_INDEX(macros.data): {
75 ProcessMacroUpload(value);
76 break;
77 }
78 case MAXWELL3D_REG_INDEX(code_address.code_address_high): 78 case MAXWELL3D_REG_INDEX(code_address.code_address_high):
79 case MAXWELL3D_REG_INDEX(code_address.code_address_low): { 79 case MAXWELL3D_REG_INDEX(code_address.code_address_low): {
80 // Note: For some reason games (like Puyo Puyo Tetris) seem to write 0 to the CODE_ADDRESS 80 // Note: For some reason games (like Puyo Puyo Tetris) seem to write 0 to the CODE_ADDRESS
@@ -141,6 +141,12 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
141 } 141 }
142} 142}
143 143
144void Maxwell3D::ProcessMacroUpload(u32 data) {
145 // Store the uploaded macro code to interpret them when they're called.
146 auto& macro = uploaded_macros[regs.macros.entry * 2 + MacroRegistersStart];
147 macro.push_back(data);
148}
149
144void Maxwell3D::ProcessQueryGet() { 150void Maxwell3D::ProcessQueryGet() {
145 GPUVAddr sequence_address = regs.query.QueryAddress(); 151 GPUVAddr sequence_address = regs.query.QueryAddress();
146 // Since the sequence address is given as a GPU VAddr, we have to convert it to an application 152 // Since the sequence address is given as a GPU VAddr, we have to convert it to an application
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index a022665eb..5cf62fb01 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -31,7 +31,7 @@ public:
31 /// Register structure of the Maxwell3D engine. 31 /// Register structure of the Maxwell3D engine.
32 /// TODO(Subv): This structure will need to be made bigger as more registers are discovered. 32 /// TODO(Subv): This structure will need to be made bigger as more registers are discovered.
33 struct Regs { 33 struct Regs {
34 static constexpr size_t NUM_REGS = 0xE36; 34 static constexpr size_t NUM_REGS = 0xE00;
35 35
36 static constexpr size_t NumRenderTargets = 8; 36 static constexpr size_t NumRenderTargets = 8;
37 static constexpr size_t NumViewports = 16; 37 static constexpr size_t NumViewports = 16;
@@ -322,7 +322,15 @@ public:
322 322
323 union { 323 union {
324 struct { 324 struct {
325 INSERT_PADDING_WORDS(0x200); 325 INSERT_PADDING_WORDS(0x45);
326
327 struct {
328 INSERT_PADDING_WORDS(1);
329 u32 data;
330 u32 entry;
331 } macros;
332
333 INSERT_PADDING_WORDS(0x1B8);
326 334
327 struct { 335 struct {
328 u32 address_high; 336 u32 address_high;
@@ -605,7 +613,7 @@ public:
605 u32 size[MaxShaderStage]; 613 u32 size[MaxShaderStage];
606 } tex_info_buffers; 614 } tex_info_buffers;
607 615
608 INSERT_PADDING_WORDS(0x102); 616 INSERT_PADDING_WORDS(0xCC);
609 }; 617 };
610 std::array<u32, NUM_REGS> reg_array; 618 std::array<u32, NUM_REGS> reg_array;
611 }; 619 };
@@ -637,9 +645,6 @@ public:
637 /// Write the value to the register identified by method. 645 /// Write the value to the register identified by method.
638 void WriteReg(u32 method, u32 value, u32 remaining_params); 646 void WriteReg(u32 method, u32 value, u32 remaining_params);
639 647
640 /// Uploads the code for a GPU macro program associated with the specified entry.
641 void SubmitMacroCode(u32 entry, std::vector<u32> code);
642
643 /// Returns a list of enabled textures for the specified shader stage. 648 /// Returns a list of enabled textures for the specified shader stage.
644 std::vector<Texture::FullTextureInfo> GetStageTextures(Regs::ShaderStage stage) const; 649 std::vector<Texture::FullTextureInfo> GetStageTextures(Regs::ShaderStage stage) const;
645 650
@@ -670,6 +675,9 @@ private:
670 */ 675 */
671 void CallMacroMethod(u32 method, std::vector<u32> parameters); 676 void CallMacroMethod(u32 method, std::vector<u32> parameters);
672 677
678 /// Handles writes to the macro uploading registers.
679 void ProcessMacroUpload(u32 data);
680
673 /// Handles a write to the QUERY_GET register. 681 /// Handles a write to the QUERY_GET register.
674 void ProcessQueryGet(); 682 void ProcessQueryGet();
675 683
@@ -687,6 +695,7 @@ private:
687 static_assert(offsetof(Maxwell3D::Regs, field_name) == position * 4, \ 695 static_assert(offsetof(Maxwell3D::Regs, field_name) == position * 4, \
688 "Field " #field_name " has invalid position") 696 "Field " #field_name " has invalid position")
689 697
698ASSERT_REG_POSITION(macros, 0x45);
690ASSERT_REG_POSITION(rt, 0x200); 699ASSERT_REG_POSITION(rt, 0x200);
691ASSERT_REG_POSITION(viewport_transform[0], 0x280); 700ASSERT_REG_POSITION(viewport_transform[0], 0x280);
692ASSERT_REG_POSITION(viewport, 0x300); 701ASSERT_REG_POSITION(viewport, 0x300);
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 9463cd5d6..9eb143918 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -12,7 +12,7 @@ namespace Tegra {
12GPU::GPU() { 12GPU::GPU() {
13 memory_manager = std::make_unique<MemoryManager>(); 13 memory_manager = std::make_unique<MemoryManager>();
14 maxwell_3d = std::make_unique<Engines::Maxwell3D>(*memory_manager); 14 maxwell_3d = std::make_unique<Engines::Maxwell3D>(*memory_manager);
15 fermi_2d = std::make_unique<Engines::Fermi2D>(); 15 fermi_2d = std::make_unique<Engines::Fermi2D>(*memory_manager);
16 maxwell_compute = std::make_unique<Engines::MaxwellCompute>(); 16 maxwell_compute = std::make_unique<Engines::MaxwellCompute>();
17} 17}
18 18
@@ -22,4 +22,16 @@ const Tegra::Engines::Maxwell3D& GPU::Get3DEngine() const {
22 return *maxwell_3d; 22 return *maxwell_3d;
23} 23}
24 24
25u32 RenderTargetBytesPerPixel(RenderTargetFormat format) {
26 ASSERT(format != RenderTargetFormat::NONE);
27
28 switch (format) {
29 case RenderTargetFormat::RGBA8_UNORM:
30 case RenderTargetFormat::RGB10_A2_UNORM:
31 return 4;
32 default:
33 UNIMPLEMENTED_MSG("Unimplemented render target format %u", static_cast<u32>(format));
34 }
35}
36
25} // namespace Tegra 37} // namespace Tegra
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index 2888daedc..f168a5171 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -21,6 +21,9 @@ enum class RenderTargetFormat : u32 {
21 RGBA8_SRGB = 0xD6, 21 RGBA8_SRGB = 0xD6,
22}; 22};
23 23
24/// Returns the number of bytes per pixel of each rendertarget format.
25u32 RenderTargetBytesPerPixel(RenderTargetFormat format);
26
24class DebugContext; 27class DebugContext;
25 28
26/** 29/**
@@ -86,8 +89,6 @@ public:
86 } 89 }
87 90
88private: 91private:
89 static constexpr u32 InvalidGraphMacroEntry = 0xFFFFFFFF;
90
91 /// Writes a single register in the engine bound to the specified subchannel 92 /// Writes a single register in the engine bound to the specified subchannel
92 void WriteReg(u32 method, u32 subchannel, u32 value, u32 remaining_params); 93 void WriteReg(u32 method, u32 subchannel, u32 value, u32 remaining_params);
93 94
@@ -100,11 +101,6 @@ private:
100 std::unique_ptr<Engines::Fermi2D> fermi_2d; 101 std::unique_ptr<Engines::Fermi2D> fermi_2d;
101 /// Compute engine 102 /// Compute engine
102 std::unique_ptr<Engines::MaxwellCompute> maxwell_compute; 103 std::unique_ptr<Engines::MaxwellCompute> maxwell_compute;
103
104 /// Entry of the macro that is currently being uploaded
105 u32 current_macro_entry = InvalidGraphMacroEntry;
106 /// Code being uploaded for the current macro
107 std::vector<u32> current_macro_code;
108}; 104};
109 105
110} // namespace Tegra 106} // namespace Tegra
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp
index 9c3ae875c..8b39b2bdf 100644
--- a/src/video_core/textures/decoders.cpp
+++ b/src/video_core/textures/decoders.cpp
@@ -27,9 +27,8 @@ static u32 GetSwizzleOffset(u32 x, u32 y, u32 image_width, u32 bytes_per_pixel,
27 return address; 27 return address;
28} 28}
29 29
30static void CopySwizzledData(u32 width, u32 height, u32 bytes_per_pixel, u32 out_bytes_per_pixel, 30void CopySwizzledData(u32 width, u32 height, u32 bytes_per_pixel, u32 out_bytes_per_pixel,
31 u8* swizzled_data, u8* unswizzled_data, bool unswizzle, 31 u8* swizzled_data, u8* unswizzled_data, bool unswizzle, u32 block_height) {
32 u32 block_height) {
33 u8* data_ptrs[2]; 32 u8* data_ptrs[2];
34 for (unsigned y = 0; y < height; ++y) { 33 for (unsigned y = 0; y < height; ++y) {
35 for (unsigned x = 0; x < width; ++x) { 34 for (unsigned x = 0; x < width; ++x) {
diff --git a/src/video_core/textures/decoders.h b/src/video_core/textures/decoders.h
index a700911cf..2562c4b06 100644
--- a/src/video_core/textures/decoders.h
+++ b/src/video_core/textures/decoders.h
@@ -17,6 +17,10 @@ namespace Texture {
17std::vector<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width, u32 height, 17std::vector<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width, u32 height,
18 u32 block_height = TICEntry::DefaultBlockHeight); 18 u32 block_height = TICEntry::DefaultBlockHeight);
19 19
20/// Copies texture data from a buffer and performs swizzling/unswizzling as necessary.
21void CopySwizzledData(u32 width, u32 height, u32 bytes_per_pixel, u32 out_bytes_per_pixel,
22 u8* swizzled_data, u8* unswizzled_data, bool unswizzle, u32 block_height);
23
20/** 24/**
21 * Decodes an unswizzled texture into a A8R8G8B8 texture. 25 * Decodes an unswizzled texture into a A8R8G8B8 texture.
22 */ 26 */