summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp2
-rw-r--r--src/video_core/gpu.cpp12
-rw-r--r--src/video_core/gpu.h9
-rw-r--r--src/video_core/gpu_asynch.cpp5
-rw-r--r--src/video_core/gpu_asynch.h5
-rw-r--r--src/video_core/gpu_synch.cpp5
-rw-r--r--src/video_core/gpu_synch.h5
-rw-r--r--src/video_core/gpu_thread.cpp8
-rw-r--r--src/video_core/gpu_thread.h3
-rw-r--r--src/video_core/morton.cpp116
-rw-r--r--src/video_core/morton.h3
-rw-r--r--src/video_core/renderer_base.h3
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp89
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h5
-rw-r--r--src/video_core/surface.cpp5
15 files changed, 71 insertions, 204 deletions
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
index 76494f0b7..926a1285d 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -37,7 +37,7 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u3
37 transform, crop_rect}; 37 transform, crop_rect};
38 38
39 system.GetPerfStats().EndGameFrame(); 39 system.GetPerfStats().EndGameFrame();
40 system.GPU().SwapBuffers(framebuffer); 40 system.GPU().SwapBuffers(&framebuffer);
41} 41}
42 42
43} // namespace Service::Nvidia::Devices 43} // namespace Service::Nvidia::Devices
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 8d9db45f5..2c47541cb 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -17,18 +17,6 @@
17 17
18namespace Tegra { 18namespace Tegra {
19 19
20u32 FramebufferConfig::BytesPerPixel(PixelFormat format) {
21 switch (format) {
22 case PixelFormat::ABGR8:
23 case PixelFormat::BGRA8:
24 return 4;
25 default:
26 return 4;
27 }
28
29 UNREACHABLE();
30}
31
32GPU::GPU(Core::System& system, VideoCore::RendererBase& renderer, bool is_async) 20GPU::GPU(Core::System& system, VideoCore::RendererBase& renderer, bool is_async)
33 : system{system}, renderer{renderer}, is_async{is_async} { 21 : system{system}, renderer{renderer}, is_async{is_async} {
34 auto& rasterizer{renderer.Rasterizer()}; 22 auto& rasterizer{renderer.Rasterizer()};
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index 544340ecd..78bc0601a 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -95,14 +95,10 @@ class DebugContext;
95struct FramebufferConfig { 95struct FramebufferConfig {
96 enum class PixelFormat : u32 { 96 enum class PixelFormat : u32 {
97 ABGR8 = 1, 97 ABGR8 = 1,
98 RGB565 = 4,
98 BGRA8 = 5, 99 BGRA8 = 5,
99 }; 100 };
100 101
101 /**
102 * Returns the number of bytes per pixel.
103 */
104 static u32 BytesPerPixel(PixelFormat format);
105
106 VAddr address; 102 VAddr address;
107 u32 offset; 103 u32 offset;
108 u32 width; 104 u32 width;
@@ -253,8 +249,7 @@ public:
253 virtual void PushGPUEntries(Tegra::CommandList&& entries) = 0; 249 virtual void PushGPUEntries(Tegra::CommandList&& entries) = 0;
254 250
255 /// Swap buffers (render frame) 251 /// Swap buffers (render frame)
256 virtual void SwapBuffers( 252 virtual void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) = 0;
257 std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer) = 0;
258 253
259 /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory 254 /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory
260 virtual void FlushRegion(CacheAddr addr, u64 size) = 0; 255 virtual void FlushRegion(CacheAddr addr, u64 size) = 0;
diff --git a/src/video_core/gpu_asynch.cpp b/src/video_core/gpu_asynch.cpp
index ea67be831..f2a3a390e 100644
--- a/src/video_core/gpu_asynch.cpp
+++ b/src/video_core/gpu_asynch.cpp
@@ -23,9 +23,8 @@ void GPUAsynch::PushGPUEntries(Tegra::CommandList&& entries) {
23 gpu_thread.SubmitList(std::move(entries)); 23 gpu_thread.SubmitList(std::move(entries));
24} 24}
25 25
26void GPUAsynch::SwapBuffers( 26void GPUAsynch::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
27 std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer) { 27 gpu_thread.SwapBuffers(framebuffer);
28 gpu_thread.SwapBuffers(std::move(framebuffer));
29} 28}
30 29
31void GPUAsynch::FlushRegion(CacheAddr addr, u64 size) { 30void GPUAsynch::FlushRegion(CacheAddr addr, u64 size) {
diff --git a/src/video_core/gpu_asynch.h b/src/video_core/gpu_asynch.h
index 36377d677..a12f9bac4 100644
--- a/src/video_core/gpu_asynch.h
+++ b/src/video_core/gpu_asynch.h
@@ -14,15 +14,14 @@ class RendererBase;
14namespace VideoCommon { 14namespace VideoCommon {
15 15
16/// Implementation of GPU interface that runs the GPU asynchronously 16/// Implementation of GPU interface that runs the GPU asynchronously
17class GPUAsynch : public Tegra::GPU { 17class GPUAsynch final : public Tegra::GPU {
18public: 18public:
19 explicit GPUAsynch(Core::System& system, VideoCore::RendererBase& renderer); 19 explicit GPUAsynch(Core::System& system, VideoCore::RendererBase& renderer);
20 ~GPUAsynch() override; 20 ~GPUAsynch() override;
21 21
22 void Start() override; 22 void Start() override;
23 void PushGPUEntries(Tegra::CommandList&& entries) override; 23 void PushGPUEntries(Tegra::CommandList&& entries) override;
24 void SwapBuffers( 24 void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override;
25 std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer) override;
26 void FlushRegion(CacheAddr addr, u64 size) override; 25 void FlushRegion(CacheAddr addr, u64 size) override;
27 void InvalidateRegion(CacheAddr addr, u64 size) override; 26 void InvalidateRegion(CacheAddr addr, u64 size) override;
28 void FlushAndInvalidateRegion(CacheAddr addr, u64 size) override; 27 void FlushAndInvalidateRegion(CacheAddr addr, u64 size) override;
diff --git a/src/video_core/gpu_synch.cpp b/src/video_core/gpu_synch.cpp
index d4ead9c47..d48221077 100644
--- a/src/video_core/gpu_synch.cpp
+++ b/src/video_core/gpu_synch.cpp
@@ -19,9 +19,8 @@ void GPUSynch::PushGPUEntries(Tegra::CommandList&& entries) {
19 dma_pusher->DispatchCalls(); 19 dma_pusher->DispatchCalls();
20} 20}
21 21
22void GPUSynch::SwapBuffers( 22void GPUSynch::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
23 std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer) { 23 renderer.SwapBuffers(framebuffer);
24 renderer.SwapBuffers(std::move(framebuffer));
25} 24}
26 25
27void GPUSynch::FlushRegion(CacheAddr addr, u64 size) { 26void GPUSynch::FlushRegion(CacheAddr addr, u64 size) {
diff --git a/src/video_core/gpu_synch.h b/src/video_core/gpu_synch.h
index 07bcc47f1..5eb1c461c 100644
--- a/src/video_core/gpu_synch.h
+++ b/src/video_core/gpu_synch.h
@@ -13,15 +13,14 @@ class RendererBase;
13namespace VideoCommon { 13namespace VideoCommon {
14 14
15/// Implementation of GPU interface that runs the GPU synchronously 15/// Implementation of GPU interface that runs the GPU synchronously
16class GPUSynch : public Tegra::GPU { 16class GPUSynch final : public Tegra::GPU {
17public: 17public:
18 explicit GPUSynch(Core::System& system, VideoCore::RendererBase& renderer); 18 explicit GPUSynch(Core::System& system, VideoCore::RendererBase& renderer);
19 ~GPUSynch() override; 19 ~GPUSynch() override;
20 20
21 void Start() override; 21 void Start() override;
22 void PushGPUEntries(Tegra::CommandList&& entries) override; 22 void PushGPUEntries(Tegra::CommandList&& entries) override;
23 void SwapBuffers( 23 void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override;
24 std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer) override;
25 void FlushRegion(CacheAddr addr, u64 size) override; 24 void FlushRegion(CacheAddr addr, u64 size) override;
26 void InvalidateRegion(CacheAddr addr, u64 size) override; 25 void InvalidateRegion(CacheAddr addr, u64 size) override;
27 void FlushAndInvalidateRegion(CacheAddr addr, u64 size) override; 26 void FlushAndInvalidateRegion(CacheAddr addr, u64 size) override;
diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp
index b441e92b0..5f039e4fd 100644
--- a/src/video_core/gpu_thread.cpp
+++ b/src/video_core/gpu_thread.cpp
@@ -39,7 +39,7 @@ static void RunThread(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_p
39 dma_pusher.Push(std::move(submit_list->entries)); 39 dma_pusher.Push(std::move(submit_list->entries));
40 dma_pusher.DispatchCalls(); 40 dma_pusher.DispatchCalls();
41 } else if (const auto data = std::get_if<SwapBuffersCommand>(&next.data)) { 41 } else if (const auto data = std::get_if<SwapBuffersCommand>(&next.data)) {
42 renderer.SwapBuffers(std::move(data->framebuffer)); 42 renderer.SwapBuffers(data->framebuffer ? &*data->framebuffer : nullptr);
43 } else if (const auto data = std::get_if<FlushRegionCommand>(&next.data)) { 43 } else if (const auto data = std::get_if<FlushRegionCommand>(&next.data)) {
44 renderer.Rasterizer().FlushRegion(data->addr, data->size); 44 renderer.Rasterizer().FlushRegion(data->addr, data->size);
45 } else if (const auto data = std::get_if<InvalidateRegionCommand>(&next.data)) { 45 } else if (const auto data = std::get_if<InvalidateRegionCommand>(&next.data)) {
@@ -78,9 +78,9 @@ void ThreadManager::SubmitList(Tegra::CommandList&& entries) {
78 system.CoreTiming().ScheduleEvent(synchronization_ticks, synchronization_event, fence); 78 system.CoreTiming().ScheduleEvent(synchronization_ticks, synchronization_event, fence);
79} 79}
80 80
81void ThreadManager::SwapBuffers( 81void ThreadManager::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
82 std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer) { 82 PushCommand(SwapBuffersCommand(framebuffer ? *framebuffer
83 PushCommand(SwapBuffersCommand(std::move(framebuffer))); 83 : std::optional<const Tegra::FramebufferConfig>{}));
84} 84}
85 85
86void ThreadManager::FlushRegion(CacheAddr addr, u64 size) { 86void ThreadManager::FlushRegion(CacheAddr addr, u64 size) {
diff --git a/src/video_core/gpu_thread.h b/src/video_core/gpu_thread.h
index 1d9d0c39e..3ae0ec9f3 100644
--- a/src/video_core/gpu_thread.h
+++ b/src/video_core/gpu_thread.h
@@ -110,8 +110,7 @@ public:
110 void SubmitList(Tegra::CommandList&& entries); 110 void SubmitList(Tegra::CommandList&& entries);
111 111
112 /// Swap buffers (render frame) 112 /// Swap buffers (render frame)
113 void SwapBuffers( 113 void SwapBuffers(const Tegra::FramebufferConfig* framebuffer);
114 std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer);
115 114
116 /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory 115 /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory
117 void FlushRegion(CacheAddr addr, u64 size); 116 void FlushRegion(CacheAddr addr, u64 size);
diff --git a/src/video_core/morton.cpp b/src/video_core/morton.cpp
index 3e91cbc83..084f85e67 100644
--- a/src/video_core/morton.cpp
+++ b/src/video_core/morton.cpp
@@ -25,8 +25,8 @@ static void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth
25 25
26 // With the BCn formats (DXT and DXN), each 4x4 tile is swizzled instead of just individual 26 // With the BCn formats (DXT and DXN), each 4x4 tile is swizzled instead of just individual
27 // pixel values. 27 // pixel values.
28 const u32 tile_size_x{GetDefaultBlockWidth(format)}; 28 constexpr u32 tile_size_x{GetDefaultBlockWidth(format)};
29 const u32 tile_size_y{GetDefaultBlockHeight(format)}; 29 constexpr u32 tile_size_y{GetDefaultBlockHeight(format)};
30 30
31 if constexpr (morton_to_linear) { 31 if constexpr (morton_to_linear) {
32 Tegra::Texture::UnswizzleTexture(buffer, addr, tile_size_x, tile_size_y, bytes_per_pixel, 32 Tegra::Texture::UnswizzleTexture(buffer, addr, tile_size_x, tile_size_y, bytes_per_pixel,
@@ -186,99 +186,6 @@ static MortonCopyFn GetSwizzleFunction(MortonSwizzleMode mode, Surface::PixelFor
186 return morton_to_linear_fns[static_cast<std::size_t>(format)]; 186 return morton_to_linear_fns[static_cast<std::size_t>(format)];
187} 187}
188 188
189static u32 MortonInterleave128(u32 x, u32 y) {
190 // 128x128 Z-Order coordinate from 2D coordinates
191 static constexpr u32 xlut[] = {
192 0x0000, 0x0001, 0x0002, 0x0003, 0x0008, 0x0009, 0x000a, 0x000b, 0x0040, 0x0041, 0x0042,
193 0x0043, 0x0048, 0x0049, 0x004a, 0x004b, 0x0800, 0x0801, 0x0802, 0x0803, 0x0808, 0x0809,
194 0x080a, 0x080b, 0x0840, 0x0841, 0x0842, 0x0843, 0x0848, 0x0849, 0x084a, 0x084b, 0x1000,
195 0x1001, 0x1002, 0x1003, 0x1008, 0x1009, 0x100a, 0x100b, 0x1040, 0x1041, 0x1042, 0x1043,
196 0x1048, 0x1049, 0x104a, 0x104b, 0x1800, 0x1801, 0x1802, 0x1803, 0x1808, 0x1809, 0x180a,
197 0x180b, 0x1840, 0x1841, 0x1842, 0x1843, 0x1848, 0x1849, 0x184a, 0x184b, 0x2000, 0x2001,
198 0x2002, 0x2003, 0x2008, 0x2009, 0x200a, 0x200b, 0x2040, 0x2041, 0x2042, 0x2043, 0x2048,
199 0x2049, 0x204a, 0x204b, 0x2800, 0x2801, 0x2802, 0x2803, 0x2808, 0x2809, 0x280a, 0x280b,
200 0x2840, 0x2841, 0x2842, 0x2843, 0x2848, 0x2849, 0x284a, 0x284b, 0x3000, 0x3001, 0x3002,
201 0x3003, 0x3008, 0x3009, 0x300a, 0x300b, 0x3040, 0x3041, 0x3042, 0x3043, 0x3048, 0x3049,
202 0x304a, 0x304b, 0x3800, 0x3801, 0x3802, 0x3803, 0x3808, 0x3809, 0x380a, 0x380b, 0x3840,
203 0x3841, 0x3842, 0x3843, 0x3848, 0x3849, 0x384a, 0x384b, 0x0000, 0x0001, 0x0002, 0x0003,
204 0x0008, 0x0009, 0x000a, 0x000b, 0x0040, 0x0041, 0x0042, 0x0043, 0x0048, 0x0049, 0x004a,
205 0x004b, 0x0800, 0x0801, 0x0802, 0x0803, 0x0808, 0x0809, 0x080a, 0x080b, 0x0840, 0x0841,
206 0x0842, 0x0843, 0x0848, 0x0849, 0x084a, 0x084b, 0x1000, 0x1001, 0x1002, 0x1003, 0x1008,
207 0x1009, 0x100a, 0x100b, 0x1040, 0x1041, 0x1042, 0x1043, 0x1048, 0x1049, 0x104a, 0x104b,
208 0x1800, 0x1801, 0x1802, 0x1803, 0x1808, 0x1809, 0x180a, 0x180b, 0x1840, 0x1841, 0x1842,
209 0x1843, 0x1848, 0x1849, 0x184a, 0x184b, 0x2000, 0x2001, 0x2002, 0x2003, 0x2008, 0x2009,
210 0x200a, 0x200b, 0x2040, 0x2041, 0x2042, 0x2043, 0x2048, 0x2049, 0x204a, 0x204b, 0x2800,
211 0x2801, 0x2802, 0x2803, 0x2808, 0x2809, 0x280a, 0x280b, 0x2840, 0x2841, 0x2842, 0x2843,
212 0x2848, 0x2849, 0x284a, 0x284b, 0x3000, 0x3001, 0x3002, 0x3003, 0x3008, 0x3009, 0x300a,
213 0x300b, 0x3040, 0x3041, 0x3042, 0x3043, 0x3048, 0x3049, 0x304a, 0x304b, 0x3800, 0x3801,
214 0x3802, 0x3803, 0x3808, 0x3809, 0x380a, 0x380b, 0x3840, 0x3841, 0x3842, 0x3843, 0x3848,
215 0x3849, 0x384a, 0x384b, 0x0000, 0x0001, 0x0002, 0x0003, 0x0008, 0x0009, 0x000a, 0x000b,
216 0x0040, 0x0041, 0x0042, 0x0043, 0x0048, 0x0049, 0x004a, 0x004b, 0x0800, 0x0801, 0x0802,
217 0x0803, 0x0808, 0x0809, 0x080a, 0x080b, 0x0840, 0x0841, 0x0842, 0x0843, 0x0848, 0x0849,
218 0x084a, 0x084b, 0x1000, 0x1001, 0x1002, 0x1003, 0x1008, 0x1009, 0x100a, 0x100b, 0x1040,
219 0x1041, 0x1042, 0x1043, 0x1048, 0x1049, 0x104a, 0x104b, 0x1800, 0x1801, 0x1802, 0x1803,
220 0x1808, 0x1809, 0x180a, 0x180b, 0x1840, 0x1841, 0x1842, 0x1843, 0x1848, 0x1849, 0x184a,
221 0x184b, 0x2000, 0x2001, 0x2002, 0x2003, 0x2008, 0x2009, 0x200a, 0x200b, 0x2040, 0x2041,
222 0x2042, 0x2043, 0x2048, 0x2049, 0x204a, 0x204b, 0x2800, 0x2801, 0x2802, 0x2803, 0x2808,
223 0x2809, 0x280a, 0x280b, 0x2840, 0x2841, 0x2842, 0x2843, 0x2848, 0x2849, 0x284a, 0x284b,
224 0x3000, 0x3001, 0x3002, 0x3003, 0x3008, 0x3009, 0x300a, 0x300b, 0x3040, 0x3041, 0x3042,
225 0x3043, 0x3048, 0x3049, 0x304a, 0x304b, 0x3800, 0x3801, 0x3802, 0x3803, 0x3808, 0x3809,
226 0x380a, 0x380b, 0x3840, 0x3841, 0x3842, 0x3843, 0x3848, 0x3849, 0x384a, 0x384b,
227 };
228 static constexpr u32 ylut[] = {
229 0x0000, 0x0004, 0x0010, 0x0014, 0x0020, 0x0024, 0x0030, 0x0034, 0x0080, 0x0084, 0x0090,
230 0x0094, 0x00a0, 0x00a4, 0x00b0, 0x00b4, 0x0100, 0x0104, 0x0110, 0x0114, 0x0120, 0x0124,
231 0x0130, 0x0134, 0x0180, 0x0184, 0x0190, 0x0194, 0x01a0, 0x01a4, 0x01b0, 0x01b4, 0x0200,
232 0x0204, 0x0210, 0x0214, 0x0220, 0x0224, 0x0230, 0x0234, 0x0280, 0x0284, 0x0290, 0x0294,
233 0x02a0, 0x02a4, 0x02b0, 0x02b4, 0x0300, 0x0304, 0x0310, 0x0314, 0x0320, 0x0324, 0x0330,
234 0x0334, 0x0380, 0x0384, 0x0390, 0x0394, 0x03a0, 0x03a4, 0x03b0, 0x03b4, 0x0400, 0x0404,
235 0x0410, 0x0414, 0x0420, 0x0424, 0x0430, 0x0434, 0x0480, 0x0484, 0x0490, 0x0494, 0x04a0,
236 0x04a4, 0x04b0, 0x04b4, 0x0500, 0x0504, 0x0510, 0x0514, 0x0520, 0x0524, 0x0530, 0x0534,
237 0x0580, 0x0584, 0x0590, 0x0594, 0x05a0, 0x05a4, 0x05b0, 0x05b4, 0x0600, 0x0604, 0x0610,
238 0x0614, 0x0620, 0x0624, 0x0630, 0x0634, 0x0680, 0x0684, 0x0690, 0x0694, 0x06a0, 0x06a4,
239 0x06b0, 0x06b4, 0x0700, 0x0704, 0x0710, 0x0714, 0x0720, 0x0724, 0x0730, 0x0734, 0x0780,
240 0x0784, 0x0790, 0x0794, 0x07a0, 0x07a4, 0x07b0, 0x07b4, 0x0000, 0x0004, 0x0010, 0x0014,
241 0x0020, 0x0024, 0x0030, 0x0034, 0x0080, 0x0084, 0x0090, 0x0094, 0x00a0, 0x00a4, 0x00b0,
242 0x00b4, 0x0100, 0x0104, 0x0110, 0x0114, 0x0120, 0x0124, 0x0130, 0x0134, 0x0180, 0x0184,
243 0x0190, 0x0194, 0x01a0, 0x01a4, 0x01b0, 0x01b4, 0x0200, 0x0204, 0x0210, 0x0214, 0x0220,
244 0x0224, 0x0230, 0x0234, 0x0280, 0x0284, 0x0290, 0x0294, 0x02a0, 0x02a4, 0x02b0, 0x02b4,
245 0x0300, 0x0304, 0x0310, 0x0314, 0x0320, 0x0324, 0x0330, 0x0334, 0x0380, 0x0384, 0x0390,
246 0x0394, 0x03a0, 0x03a4, 0x03b0, 0x03b4, 0x0400, 0x0404, 0x0410, 0x0414, 0x0420, 0x0424,
247 0x0430, 0x0434, 0x0480, 0x0484, 0x0490, 0x0494, 0x04a0, 0x04a4, 0x04b0, 0x04b4, 0x0500,
248 0x0504, 0x0510, 0x0514, 0x0520, 0x0524, 0x0530, 0x0534, 0x0580, 0x0584, 0x0590, 0x0594,
249 0x05a0, 0x05a4, 0x05b0, 0x05b4, 0x0600, 0x0604, 0x0610, 0x0614, 0x0620, 0x0624, 0x0630,
250 0x0634, 0x0680, 0x0684, 0x0690, 0x0694, 0x06a0, 0x06a4, 0x06b0, 0x06b4, 0x0700, 0x0704,
251 0x0710, 0x0714, 0x0720, 0x0724, 0x0730, 0x0734, 0x0780, 0x0784, 0x0790, 0x0794, 0x07a0,
252 0x07a4, 0x07b0, 0x07b4, 0x0000, 0x0004, 0x0010, 0x0014, 0x0020, 0x0024, 0x0030, 0x0034,
253 0x0080, 0x0084, 0x0090, 0x0094, 0x00a0, 0x00a4, 0x00b0, 0x00b4, 0x0100, 0x0104, 0x0110,
254 0x0114, 0x0120, 0x0124, 0x0130, 0x0134, 0x0180, 0x0184, 0x0190, 0x0194, 0x01a0, 0x01a4,
255 0x01b0, 0x01b4, 0x0200, 0x0204, 0x0210, 0x0214, 0x0220, 0x0224, 0x0230, 0x0234, 0x0280,
256 0x0284, 0x0290, 0x0294, 0x02a0, 0x02a4, 0x02b0, 0x02b4, 0x0300, 0x0304, 0x0310, 0x0314,
257 0x0320, 0x0324, 0x0330, 0x0334, 0x0380, 0x0384, 0x0390, 0x0394, 0x03a0, 0x03a4, 0x03b0,
258 0x03b4, 0x0400, 0x0404, 0x0410, 0x0414, 0x0420, 0x0424, 0x0430, 0x0434, 0x0480, 0x0484,
259 0x0490, 0x0494, 0x04a0, 0x04a4, 0x04b0, 0x04b4, 0x0500, 0x0504, 0x0510, 0x0514, 0x0520,
260 0x0524, 0x0530, 0x0534, 0x0580, 0x0584, 0x0590, 0x0594, 0x05a0, 0x05a4, 0x05b0, 0x05b4,
261 0x0600, 0x0604, 0x0610, 0x0614, 0x0620, 0x0624, 0x0630, 0x0634, 0x0680, 0x0684, 0x0690,
262 0x0694, 0x06a0, 0x06a4, 0x06b0, 0x06b4, 0x0700, 0x0704, 0x0710, 0x0714, 0x0720, 0x0724,
263 0x0730, 0x0734, 0x0780, 0x0784, 0x0790, 0x0794, 0x07a0, 0x07a4, 0x07b0, 0x07b4,
264 };
265 return xlut[x % 128] + ylut[y % 128];
266}
267
268static u32 GetMortonOffset128(u32 x, u32 y, u32 bytes_per_pixel) {
269 // Calculates the offset of the position of the pixel in Morton order
270 // Framebuffer images are split into 128x128 tiles.
271
272 constexpr u32 block_height = 128;
273 const u32 coarse_x = x & ~127;
274
275 const u32 i = MortonInterleave128(x, y);
276
277 const u32 offset = coarse_x * block_height;
278
279 return (i + offset) * bytes_per_pixel;
280}
281
282void MortonSwizzle(MortonSwizzleMode mode, Surface::PixelFormat format, u32 stride, 189void MortonSwizzle(MortonSwizzleMode mode, Surface::PixelFormat format, u32 stride,
283 u32 block_height, u32 height, u32 block_depth, u32 depth, u32 tile_width_spacing, 190 u32 block_height, u32 height, u32 block_depth, u32 depth, u32 tile_width_spacing,
284 u8* buffer, u8* addr) { 191 u8* buffer, u8* addr) {
@@ -286,23 +193,4 @@ void MortonSwizzle(MortonSwizzleMode mode, Surface::PixelFormat format, u32 stri
286 tile_width_spacing, buffer, addr); 193 tile_width_spacing, buffer, addr);
287} 194}
288 195
289void MortonCopyPixels128(MortonSwizzleMode mode, u32 width, u32 height, u32 bytes_per_pixel,
290 u32 linear_bytes_per_pixel, u8* morton_data, u8* linear_data) {
291 const bool morton_to_linear = mode == MortonSwizzleMode::MortonToLinear;
292 u8* data_ptrs[2];
293 for (u32 y = 0; y < height; ++y) {
294 for (u32 x = 0; x < width; ++x) {
295 const u32 coarse_y = y & ~127;
296 const u32 morton_offset =
297 GetMortonOffset128(x, y, bytes_per_pixel) + coarse_y * width * bytes_per_pixel;
298 const u32 linear_pixel_index = (x + y * width) * linear_bytes_per_pixel;
299
300 data_ptrs[morton_to_linear ? 1 : 0] = morton_data + morton_offset;
301 data_ptrs[morton_to_linear ? 0 : 1] = &linear_data[linear_pixel_index];
302
303 std::memcpy(data_ptrs[0], data_ptrs[1], bytes_per_pixel);
304 }
305 }
306}
307
308} // namespace VideoCore 196} // namespace VideoCore
diff --git a/src/video_core/morton.h b/src/video_core/morton.h
index ee5b45555..b714a7e3f 100644
--- a/src/video_core/morton.h
+++ b/src/video_core/morton.h
@@ -15,7 +15,4 @@ void MortonSwizzle(MortonSwizzleMode mode, VideoCore::Surface::PixelFormat forma
15 u32 block_height, u32 height, u32 block_depth, u32 depth, u32 tile_width_spacing, 15 u32 block_height, u32 height, u32 block_depth, u32 depth, u32 tile_width_spacing,
16 u8* buffer, u8* addr); 16 u8* buffer, u8* addr);
17 17
18void MortonCopyPixels128(MortonSwizzleMode mode, u32 width, u32 height, u32 bytes_per_pixel,
19 u32 linear_bytes_per_pixel, u8* morton_data, u8* linear_data);
20
21} // namespace VideoCore 18} // namespace VideoCore
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h
index 1d54c3723..af1bebc4f 100644
--- a/src/video_core/renderer_base.h
+++ b/src/video_core/renderer_base.h
@@ -36,8 +36,7 @@ public:
36 virtual ~RendererBase(); 36 virtual ~RendererBase();
37 37
38 /// Swap buffers (render frame) 38 /// Swap buffers (render frame)
39 virtual void SwapBuffers( 39 virtual void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) = 0;
40 std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer) = 0;
41 40
42 /// Initialize the renderer 41 /// Initialize the renderer
43 virtual bool Init() = 0; 42 virtual bool Init() = 0;
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index a05cef3b9..af9684839 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -101,9 +101,7 @@ RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::Syst
101 101
102RendererOpenGL::~RendererOpenGL() = default; 102RendererOpenGL::~RendererOpenGL() = default;
103 103
104void RendererOpenGL::SwapBuffers( 104void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
105 std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer) {
106
107 system.GetPerfStats().EndSystemFrame(); 105 system.GetPerfStats().EndSystemFrame();
108 106
109 // Maintain the rasterizer's state as a priority 107 // Maintain the rasterizer's state as a priority
@@ -113,9 +111,9 @@ void RendererOpenGL::SwapBuffers(
113 111
114 if (framebuffer) { 112 if (framebuffer) {
115 // If framebuffer is provided, reload it from memory to a texture 113 // If framebuffer is provided, reload it from memory to a texture
116 if (screen_info.texture.width != (GLsizei)framebuffer->get().width || 114 if (screen_info.texture.width != static_cast<GLsizei>(framebuffer->width) ||
117 screen_info.texture.height != (GLsizei)framebuffer->get().height || 115 screen_info.texture.height != static_cast<GLsizei>(framebuffer->height) ||
118 screen_info.texture.pixel_format != framebuffer->get().pixel_format) { 116 screen_info.texture.pixel_format != framebuffer->pixel_format) {
119 // Reallocate texture if the framebuffer size has changed. 117 // Reallocate texture if the framebuffer size has changed.
120 // This is expected to not happen very often and hence should not be a 118 // This is expected to not happen very often and hence should not be a
121 // performance problem. 119 // performance problem.
@@ -149,43 +147,43 @@ void RendererOpenGL::SwapBuffers(
149 * Loads framebuffer from emulated memory into the active OpenGL texture. 147 * Loads framebuffer from emulated memory into the active OpenGL texture.
150 */ 148 */
151void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer) { 149void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer) {
152 const u32 bytes_per_pixel{Tegra::FramebufferConfig::BytesPerPixel(framebuffer.pixel_format)};
153 const u64 size_in_bytes{framebuffer.stride * framebuffer.height * bytes_per_pixel};
154 const VAddr framebuffer_addr{framebuffer.address + framebuffer.offset};
155
156 // Framebuffer orientation handling 150 // Framebuffer orientation handling
157 framebuffer_transform_flags = framebuffer.transform_flags; 151 framebuffer_transform_flags = framebuffer.transform_flags;
158 framebuffer_crop_rect = framebuffer.crop_rect; 152 framebuffer_crop_rect = framebuffer.crop_rect;
159 153
160 // Ensure no bad interactions with GL_UNPACK_ALIGNMENT, which by default 154 const VAddr framebuffer_addr{framebuffer.address + framebuffer.offset};
161 // only allows rows to have a memory alignement of 4. 155 if (rasterizer->AccelerateDisplay(framebuffer, framebuffer_addr, framebuffer.stride)) {
162 ASSERT(framebuffer.stride % 4 == 0); 156 return;
163 157 }
164 if (!rasterizer->AccelerateDisplay(framebuffer, framebuffer_addr, framebuffer.stride)) {
165 // Reset the screen info's display texture to its own permanent texture
166 screen_info.display_texture = screen_info.texture.resource.handle;
167
168 rasterizer->FlushRegion(ToCacheAddr(Memory::GetPointer(framebuffer_addr)), size_in_bytes);
169
170 constexpr u32 linear_bpp = 4;
171 VideoCore::MortonCopyPixels128(VideoCore::MortonSwizzleMode::MortonToLinear,
172 framebuffer.width, framebuffer.height, bytes_per_pixel,
173 linear_bpp, Memory::GetPointer(framebuffer_addr),
174 gl_framebuffer_data.data());
175
176 glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(framebuffer.stride));
177 158
178 // Update existing texture 159 // Reset the screen info's display texture to its own permanent texture
179 // TODO: Test what happens on hardware when you change the framebuffer dimensions so that 160 screen_info.display_texture = screen_info.texture.resource.handle;
180 // they differ from the LCD resolution.
181 // TODO: Applications could theoretically crash yuzu here by specifying too large
182 // framebuffer sizes. We should make sure that this cannot happen.
183 glTextureSubImage2D(screen_info.texture.resource.handle, 0, 0, 0, framebuffer.width,
184 framebuffer.height, screen_info.texture.gl_format,
185 screen_info.texture.gl_type, gl_framebuffer_data.data());
186 161
187 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 162 const auto pixel_format{
188 } 163 VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)};
164 const u32 bytes_per_pixel{VideoCore::Surface::GetBytesPerPixel(pixel_format)};
165 const u64 size_in_bytes{framebuffer.stride * framebuffer.height * bytes_per_pixel};
166 const auto host_ptr{Memory::GetPointer(framebuffer_addr)};
167 rasterizer->FlushRegion(ToCacheAddr(host_ptr), size_in_bytes);
168
169 // TODO(Rodrigo): Read this from HLE
170 constexpr u32 block_height_log2 = 4;
171 VideoCore::MortonSwizzle(VideoCore::MortonSwizzleMode::MortonToLinear, pixel_format,
172 framebuffer.stride, block_height_log2, framebuffer.height, 0, 1, 1,
173 gl_framebuffer_data.data(), host_ptr);
174
175 glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(framebuffer.stride));
176
177 // Update existing texture
178 // TODO: Test what happens on hardware when you change the framebuffer dimensions so that
179 // they differ from the LCD resolution.
180 // TODO: Applications could theoretically crash yuzu here by specifying too large
181 // framebuffer sizes. We should make sure that this cannot happen.
182 glTextureSubImage2D(screen_info.texture.resource.handle, 0, 0, 0, framebuffer.width,
183 framebuffer.height, screen_info.texture.gl_format,
184 screen_info.texture.gl_type, gl_framebuffer_data.data());
185
186 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
189} 187}
190 188
191/** 189/**
@@ -276,22 +274,29 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
276 texture.height = framebuffer.height; 274 texture.height = framebuffer.height;
277 texture.pixel_format = framebuffer.pixel_format; 275 texture.pixel_format = framebuffer.pixel_format;
278 276
277 const auto pixel_format{
278 VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)};
279 const u32 bytes_per_pixel{VideoCore::Surface::GetBytesPerPixel(pixel_format)};
280 gl_framebuffer_data.resize(texture.width * texture.height * bytes_per_pixel);
281
279 GLint internal_format; 282 GLint internal_format;
280 switch (framebuffer.pixel_format) { 283 switch (framebuffer.pixel_format) {
281 case Tegra::FramebufferConfig::PixelFormat::ABGR8: 284 case Tegra::FramebufferConfig::PixelFormat::ABGR8:
282 internal_format = GL_RGBA8; 285 internal_format = GL_RGBA8;
283 texture.gl_format = GL_RGBA; 286 texture.gl_format = GL_RGBA;
284 texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; 287 texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
285 gl_framebuffer_data.resize(texture.width * texture.height * 4); 288 break;
289 case Tegra::FramebufferConfig::PixelFormat::RGB565:
290 internal_format = GL_RGB565;
291 texture.gl_format = GL_RGB;
292 texture.gl_type = GL_UNSIGNED_SHORT_5_6_5;
286 break; 293 break;
287 default: 294 default:
288 internal_format = GL_RGBA8; 295 internal_format = GL_RGBA8;
289 texture.gl_format = GL_RGBA; 296 texture.gl_format = GL_RGBA;
290 texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; 297 texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
291 gl_framebuffer_data.resize(texture.width * texture.height * 4); 298 UNIMPLEMENTED_MSG("Unknown framebuffer pixel format: {}",
292 LOG_CRITICAL(Render_OpenGL, "Unknown framebuffer pixel format: {}", 299 static_cast<u32>(framebuffer.pixel_format));
293 static_cast<u32>(framebuffer.pixel_format));
294 UNREACHABLE();
295 } 300 }
296 301
297 texture.resource.Release(); 302 texture.resource.Release();
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h
index 4aebf2321..9bd086368 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.h
+++ b/src/video_core/renderer_opengl/renderer_opengl.h
@@ -43,14 +43,13 @@ struct ScreenInfo {
43 TextureInfo texture; 43 TextureInfo texture;
44}; 44};
45 45
46class RendererOpenGL : public VideoCore::RendererBase { 46class RendererOpenGL final : public VideoCore::RendererBase {
47public: 47public:
48 explicit RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system); 48 explicit RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system);
49 ~RendererOpenGL() override; 49 ~RendererOpenGL() override;
50 50
51 /// Swap buffers (render frame) 51 /// Swap buffers (render frame)
52 void SwapBuffers( 52 void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override;
53 std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer) override;
54 53
55 /// Initialize the renderer 54 /// Initialize the renderer
56 bool Init() override; 55 bool Init() override;
diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp
index c50f6354d..4ceb219be 100644
--- a/src/video_core/surface.cpp
+++ b/src/video_core/surface.cpp
@@ -445,11 +445,12 @@ PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat
445 switch (format) { 445 switch (format) {
446 case Tegra::FramebufferConfig::PixelFormat::ABGR8: 446 case Tegra::FramebufferConfig::PixelFormat::ABGR8:
447 return PixelFormat::ABGR8U; 447 return PixelFormat::ABGR8U;
448 case Tegra::FramebufferConfig::PixelFormat::RGB565:
449 return PixelFormat::B5G6R5U;
448 case Tegra::FramebufferConfig::PixelFormat::BGRA8: 450 case Tegra::FramebufferConfig::PixelFormat::BGRA8:
449 return PixelFormat::BGRA8; 451 return PixelFormat::BGRA8;
450 default: 452 default:
451 LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); 453 UNIMPLEMENTED_MSG("Unimplemented format={}", static_cast<u32>(format));
452 UNREACHABLE();
453 return PixelFormat::ABGR8U; 454 return PixelFormat::ABGR8U;
454 } 455 }
455} 456}