summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2018-03-23 23:30:48 -0400
committerGravatar GitHub2018-03-23 23:30:48 -0400
commita10baacf9e5ab48af7fb0ccbdc75371c9287d3ba (patch)
tree9ed56f99b9d2564f9250d3754e429eb0c8b43323 /src
parentMerge pull request #255 from Subv/sd_card (diff)
parentgl_rasterizer: Fake render in green, because it's cooler. (diff)
downloadyuzu-a10baacf9e5ab48af7fb0ccbdc75371c9287d3ba.tar.gz
yuzu-a10baacf9e5ab48af7fb0ccbdc75371c9287d3ba.tar.xz
yuzu-a10baacf9e5ab48af7fb0ccbdc75371c9287d3ba.zip
Merge pull request #265 from bunnei/tegra-progress-2
Tegra progress 2
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp11
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.h2
-rw-r--r--src/core/memory.cpp40
-rw-r--r--src/core/memory.h20
-rw-r--r--src/video_core/engines/maxwell_3d.h110
-rw-r--r--src/video_core/gpu.h36
-rw-r--r--src/video_core/rasterizer_interface.h10
-rw-r--r--src/video_core/renderer_base.cpp7
-rw-r--r--src/video_core/renderer_base.h40
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp140
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h24
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp67
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h34
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp219
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h13
-rw-r--r--src/video_core/utils.h112
-rw-r--r--src/video_core/video_core.h2
17 files changed, 591 insertions, 296 deletions
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
index 94530724e..87b3a2d74 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -26,14 +26,13 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u3
26 "Drawing from address %lx offset %08X Width %u Height %u Stride %u Format %u", addr, 26 "Drawing from address %lx offset %08X Width %u Height %u Stride %u Format %u", addr,
27 offset, width, height, stride, format); 27 offset, width, height, stride, format);
28 28
29 using PixelFormat = RendererBase::FramebufferInfo::PixelFormat; 29 using PixelFormat = Tegra::FramebufferConfig::PixelFormat;
30 using Flags = NVFlinger::BufferQueue::BufferTransformFlags; 30 const Tegra::FramebufferConfig framebuffer{
31 const bool flip_vertical = static_cast<u32>(transform) & static_cast<u32>(Flags::FlipV); 31 addr, offset, width, height, stride, static_cast<PixelFormat>(format), transform};
32 const RendererBase::FramebufferInfo framebuffer_info{
33 addr, offset, width, height, stride, static_cast<PixelFormat>(format), flip_vertical};
34 32
35 Core::System::GetInstance().perf_stats.EndGameFrame(); 33 Core::System::GetInstance().perf_stats.EndGameFrame();
36 VideoCore::g_renderer->SwapBuffers(framebuffer_info); 34
35 VideoCore::g_renderer->SwapBuffers(framebuffer);
37} 36}
38 37
39} // namespace Devices 38} // namespace Devices
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h
index 686eadca7..1de5767cb 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.h
+++ b/src/core/hle/service/nvflinger/buffer_queue.h
@@ -47,6 +47,8 @@ public:
47 ~BufferQueue() = default; 47 ~BufferQueue() = default;
48 48
49 enum class BufferTransformFlags : u32 { 49 enum class BufferTransformFlags : u32 {
50 /// No transform flags are set
51 Unset = 0x00,
50 /// Flip source image horizontally (around the vertical axis) 52 /// Flip source image horizontally (around the vertical axis)
51 FlipH = 0x01, 53 FlipH = 0x01,
52 /// Flip source image vertically (around the horizontal axis) 54 /// Flip source image vertically (around the horizontal axis)
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index a9beccb95..d6469dd3d 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -41,6 +41,9 @@ static void MapPages(PageTable& page_table, VAddr base, u64 size, u8* memory, Pa
41 LOG_DEBUG(HW_Memory, "Mapping %p onto %016" PRIX64 "-%016" PRIX64, memory, base * PAGE_SIZE, 41 LOG_DEBUG(HW_Memory, "Mapping %p onto %016" PRIX64 "-%016" PRIX64, memory, base * PAGE_SIZE,
42 (base + size) * PAGE_SIZE); 42 (base + size) * PAGE_SIZE);
43 43
44 RasterizerFlushVirtualRegion(base << PAGE_BITS, size * PAGE_SIZE,
45 FlushMode::FlushAndInvalidate);
46
44 VAddr end = base + size; 47 VAddr end = base + size;
45 while (base != end) { 48 while (base != end) {
46 ASSERT_MSG(base < PAGE_TABLE_NUM_ENTRIES, "out of range mapping at %016" PRIX64, base); 49 ASSERT_MSG(base < PAGE_TABLE_NUM_ENTRIES, "out of range mapping at %016" PRIX64, base);
@@ -288,6 +291,43 @@ u8* GetPhysicalPointer(PAddr address) {
288 return target_pointer; 291 return target_pointer;
289} 292}
290 293
294void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) {
295 // Since pages are unmapped on shutdown after video core is shutdown, the renderer may be
296 // null here
297 if (VideoCore::g_renderer == nullptr) {
298 return;
299 }
300
301 VAddr end = start + size;
302
303 auto CheckRegion = [&](VAddr region_start, VAddr region_end) {
304 if (start >= region_end || end <= region_start) {
305 // No overlap with region
306 return;
307 }
308
309 VAddr overlap_start = std::max(start, region_start);
310 VAddr overlap_end = std::min(end, region_end);
311 u64 overlap_size = overlap_end - overlap_start;
312
313 auto* rasterizer = VideoCore::g_renderer->Rasterizer();
314 switch (mode) {
315 case FlushMode::Flush:
316 rasterizer->FlushRegion(overlap_start, overlap_size);
317 break;
318 case FlushMode::Invalidate:
319 rasterizer->InvalidateRegion(overlap_start, overlap_size);
320 break;
321 case FlushMode::FlushAndInvalidate:
322 rasterizer->FlushAndInvalidateRegion(overlap_start, overlap_size);
323 break;
324 }
325 };
326
327 CheckRegion(PROCESS_IMAGE_VADDR, PROCESS_IMAGE_VADDR_END);
328 CheckRegion(HEAP_VADDR, HEAP_VADDR_END);
329}
330
291u8 Read8(const VAddr addr) { 331u8 Read8(const VAddr addr) {
292 return Read<u8>(addr); 332 return Read<u8>(addr);
293} 333}
diff --git a/src/core/memory.h b/src/core/memory.h
index f5bf0141f..4b9c482fe 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -36,7 +36,10 @@ enum class PageType : u8 {
36 Unmapped, 36 Unmapped,
37 /// Page is mapped to regular memory. This is the only type you can get pointers to. 37 /// Page is mapped to regular memory. This is the only type you can get pointers to.
38 Memory, 38 Memory,
39 /// Page is mapped to a memory hook, which intercepts read and write requests. 39 /// Page is mapped to regular memory, but also needs to check for rasterizer cache flushing and
40 /// invalidation
41 RasterizerCachedMemory,
42 /// Page is mapped to a I/O region. Writing and reading to this page is handled by functions.
40 Special, 43 Special,
41}; 44};
42 45
@@ -242,4 +245,19 @@ boost::optional<VAddr> PhysicalToVirtualAddress(PAddr addr);
242 */ 245 */
243u8* GetPhysicalPointer(PAddr address); 246u8* GetPhysicalPointer(PAddr address);
244 247
248enum class FlushMode {
249 /// Write back modified surfaces to RAM
250 Flush,
251 /// Remove region from the cache
252 Invalidate,
253 /// Write back modified surfaces to RAM, and also remove them from the cache
254 FlushAndInvalidate,
255};
256
257/**
258 * Flushes and invalidates any externally cached rasterizer resources touching the given virtual
259 * address region.
260 */
261void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode);
262
245} // namespace Memory 263} // namespace Memory
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index aab282b77..69ed56338 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -7,6 +7,7 @@
7#include <array> 7#include <array>
8#include <unordered_map> 8#include <unordered_map>
9#include <vector> 9#include <vector>
10#include "common/assert.h"
10#include "common/bit_field.h" 11#include "common/bit_field.h"
11#include "common/common_funcs.h" 12#include "common/common_funcs.h"
12#include "common/common_types.h" 13#include "common/common_types.h"
@@ -62,6 +63,107 @@ public:
62 Fragment = 4, 63 Fragment = 4,
63 }; 64 };
64 65
66 enum class VertexSize : u32 {
67 Size_32_32_32_32 = 0x01,
68 Size_32_32_32 = 0x02,
69 Size_16_16_16_16 = 0x03,
70 Size_32_32 = 0x04,
71 Size_16_16_16 = 0x05,
72 Size_8_8_8_8 = 0x0a,
73 Size_16_16 = 0x0f,
74 Size_32 = 0x12,
75 Size_8_8_8 = 0x13,
76 Size_8_8 = 0x18,
77 Size_16 = 0x1b,
78 Size_8 = 0x1d,
79 Size_10_10_10_2 = 0x30,
80 Size_11_11_10 = 0x31,
81 };
82
83 static std::string VertexSizeToString(VertexSize vertex_size) {
84 switch (vertex_size) {
85 case VertexSize::Size_32_32_32_32:
86 return "32_32_32_32";
87 case VertexSize::Size_32_32_32:
88 return "32_32_32";
89 case VertexSize::Size_16_16_16_16:
90 return "16_16_16_16";
91 case VertexSize::Size_32_32:
92 return "32_32";
93 case VertexSize::Size_16_16_16:
94 return "16_16_16";
95 case VertexSize::Size_8_8_8_8:
96 return "8_8_8_8";
97 case VertexSize::Size_16_16:
98 return "16_16";
99 case VertexSize::Size_32:
100 return "32";
101 case VertexSize::Size_8_8_8:
102 return "8_8_8";
103 case VertexSize::Size_8_8:
104 return "8_8";
105 case VertexSize::Size_16:
106 return "16";
107 case VertexSize::Size_8:
108 return "8";
109 case VertexSize::Size_10_10_10_2:
110 return "10_10_10_2";
111 case VertexSize::Size_11_11_10:
112 return "11_11_10";
113 }
114 UNIMPLEMENTED();
115 return {};
116 }
117
118 enum class VertexType : u32 {
119 SignedNorm = 1,
120 UnsignedNorm = 2,
121 SignedInt = 3,
122 UnsignedInt = 4,
123 UnsignedScaled = 5,
124 SignedScaled = 6,
125 Float = 7,
126 };
127
128 static std::string VertexTypeToString(VertexType vertex_type) {
129 switch (vertex_type) {
130 case VertexType::SignedNorm:
131 return "SignedNorm";
132 case VertexType::UnsignedNorm:
133 return "UnsignedNorm";
134 case VertexType::SignedInt:
135 return "SignedInt";
136 case VertexType::UnsignedInt:
137 return "UnsignedInt";
138 case VertexType::UnsignedScaled:
139 return "UnsignedScaled";
140 case VertexType::SignedScaled:
141 return "SignedScaled";
142 case VertexType::Float:
143 return "Float";
144 }
145 UNIMPLEMENTED();
146 return {};
147 }
148
149 enum class PrimitiveTopology : u32 {
150 Points = 0x0,
151 Lines = 0x1,
152 LineLoop = 0x2,
153 LineStrip = 0x3,
154 Triangles = 0x4,
155 TriangleStrip = 0x5,
156 TriangleFan = 0x6,
157 Quads = 0x7,
158 QuadStrip = 0x8,
159 Polygon = 0x9,
160 LinesAdjacency = 0xa,
161 LineStripAdjacency = 0xb,
162 TrianglesAdjacency = 0xc,
163 TriangleStripAdjacency = 0xd,
164 Patches = 0xe,
165 };
166
65 union { 167 union {
66 struct { 168 struct {
67 INSERT_PADDING_WORDS(0x200); 169 INSERT_PADDING_WORDS(0x200);
@@ -112,8 +214,8 @@ public:
112 BitField<0, 5, u32> buffer; 214 BitField<0, 5, u32> buffer;
113 BitField<6, 1, u32> constant; 215 BitField<6, 1, u32> constant;
114 BitField<7, 14, u32> offset; 216 BitField<7, 14, u32> offset;
115 BitField<21, 6, u32> size; 217 BitField<21, 6, VertexSize> size;
116 BitField<27, 3, u32> type; 218 BitField<27, 3, VertexType> type;
117 BitField<31, 1, u32> bgra; 219 BitField<31, 1, u32> bgra;
118 } vertex_attrib_format[NumVertexAttributes]; 220 } vertex_attrib_format[NumVertexAttributes];
119 221
@@ -163,13 +265,15 @@ public:
163 } 265 }
164 } code_address; 266 } code_address;
165 INSERT_PADDING_WORDS(1); 267 INSERT_PADDING_WORDS(1);
268
166 struct { 269 struct {
167 u32 vertex_end_gl; 270 u32 vertex_end_gl;
168 union { 271 union {
169 u32 vertex_begin_gl; 272 u32 vertex_begin_gl;
170 BitField<0, 16, u32> topology; 273 BitField<0, 16, PrimitiveTopology> topology;
171 }; 274 };
172 } draw; 275 } draw;
276
173 INSERT_PADDING_WORDS(0x139); 277 INSERT_PADDING_WORDS(0x139);
174 struct { 278 struct {
175 u32 query_address_high; 279 u32 query_address_high;
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index 2a9064ba3..206b3e05e 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -8,10 +8,42 @@
8#include <unordered_map> 8#include <unordered_map>
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 "video_core/memory_manager.h" 12#include "video_core/memory_manager.h"
12 13
13namespace Tegra { 14namespace Tegra {
14 15
16/**
17 * Struct describing framebuffer configuration
18 */
19struct FramebufferConfig {
20 enum class PixelFormat : u32 {
21 ABGR8 = 1,
22 };
23
24 /**
25 * Returns the number of bytes per pixel.
26 */
27 static u32 BytesPerPixel(PixelFormat format) {
28 switch (format) {
29 case PixelFormat::ABGR8:
30 return 4;
31 }
32
33 UNREACHABLE();
34 }
35
36 VAddr address;
37 u32 offset;
38 u32 width;
39 u32 height;
40 u32 stride;
41 PixelFormat pixel_format;
42
43 using TransformFlags = Service::NVFlinger::BufferQueue::BufferTransformFlags;
44 TransformFlags transform_flags;
45};
46
15namespace Engines { 47namespace Engines {
16class Fermi2D; 48class Fermi2D;
17class Maxwell3D; 49class Maxwell3D;
@@ -36,6 +68,10 @@ public:
36 68
37 std::unique_ptr<MemoryManager> memory_manager; 69 std::unique_ptr<MemoryManager> memory_manager;
38 70
71 Engines::Maxwell3D& Maxwell3D() {
72 return *maxwell_3d;
73 }
74
39private: 75private:
40 static constexpr u32 InvalidGraphMacroEntry = 0xFFFFFFFF; 76 static constexpr u32 InvalidGraphMacroEntry = 0xFFFFFFFF;
41 77
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h
index 6c7bd0826..a493e1d60 100644
--- a/src/video_core/rasterizer_interface.h
+++ b/src/video_core/rasterizer_interface.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "video_core/gpu.h"
8 9
9struct ScreenInfo; 10struct ScreenInfo;
10 11
@@ -24,14 +25,14 @@ public:
24 virtual void FlushAll() = 0; 25 virtual void FlushAll() = 0;
25 26
26 /// Notify rasterizer that any caches of the specified region should be flushed to 3DS memory 27 /// Notify rasterizer that any caches of the specified region should be flushed to 3DS memory
27 virtual void FlushRegion(PAddr addr, u32 size) = 0; 28 virtual void FlushRegion(VAddr addr, u64 size) = 0;
28 29
29 /// Notify rasterizer that any caches of the specified region should be invalidated 30 /// Notify rasterizer that any caches of the specified region should be invalidated
30 virtual void InvalidateRegion(PAddr addr, u32 size) = 0; 31 virtual void InvalidateRegion(VAddr addr, u64 size) = 0;
31 32
32 /// Notify rasterizer that any caches of the specified region should be flushed to 3DS memory 33 /// Notify rasterizer that any caches of the specified region should be flushed to 3DS memory
33 /// and invalidated 34 /// and invalidated
34 virtual void FlushAndInvalidateRegion(PAddr addr, u32 size) = 0; 35 virtual void FlushAndInvalidateRegion(VAddr addr, u64 size) = 0;
35 36
36 /// Attempt to use a faster method to perform a display transfer with is_texture_copy = 0 37 /// Attempt to use a faster method to perform a display transfer with is_texture_copy = 0
37 virtual bool AccelerateDisplayTransfer(const void* config) { 38 virtual bool AccelerateDisplayTransfer(const void* config) {
@@ -49,7 +50,8 @@ public:
49 } 50 }
50 51
51 /// Attempt to use a faster method to display the framebuffer to screen 52 /// Attempt to use a faster method to display the framebuffer to screen
52 virtual bool AccelerateDisplay(const void* config, PAddr framebuffer_addr, u32 pixel_stride, 53 virtual bool AccelerateDisplay(const Tegra::FramebufferConfig& framebuffer,
54 VAddr framebuffer_addr, u32 pixel_stride,
53 ScreenInfo& screen_info) { 55 ScreenInfo& screen_info) {
54 return false; 56 return false;
55 } 57 }
diff --git a/src/video_core/renderer_base.cpp b/src/video_core/renderer_base.cpp
index 51e1d45f9..30075b23c 100644
--- a/src/video_core/renderer_base.cpp
+++ b/src/video_core/renderer_base.cpp
@@ -5,6 +5,11 @@
5#include <atomic> 5#include <atomic>
6#include <memory> 6#include <memory>
7#include "video_core/renderer_base.h" 7#include "video_core/renderer_base.h"
8#include "video_core/renderer_opengl/gl_rasterizer.h"
8#include "video_core/video_core.h" 9#include "video_core/video_core.h"
9 10
10void RendererBase::RefreshRasterizerSetting() {} 11void RendererBase::RefreshRasterizerSetting() {
12 if (rasterizer == nullptr) {
13 rasterizer = std::make_unique<RasterizerOpenGL>();
14 }
15}
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h
index 2aba50eda..89a960eaf 100644
--- a/src/video_core/renderer_base.h
+++ b/src/video_core/renderer_base.h
@@ -8,6 +8,8 @@
8#include <boost/optional.hpp> 8#include <boost/optional.hpp>
9#include "common/assert.h" 9#include "common/assert.h"
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "video_core/gpu.h"
12#include "video_core/rasterizer_interface.h"
11 13
12class EmuWindow; 14class EmuWindow;
13 15
@@ -16,40 +18,10 @@ public:
16 /// Used to reference a framebuffer 18 /// Used to reference a framebuffer
17 enum kFramebuffer { kFramebuffer_VirtualXFB = 0, kFramebuffer_EFB, kFramebuffer_Texture }; 19 enum kFramebuffer { kFramebuffer_VirtualXFB = 0, kFramebuffer_EFB, kFramebuffer_Texture };
18 20
19 /**
20 * Struct describing framebuffer metadata
21 * TODO(bunnei): This struct belongs in the GPU code, but we don't have a good place for it yet.
22 */
23 struct FramebufferInfo {
24 enum class PixelFormat : u32 {
25 ABGR8 = 1,
26 };
27
28 /**
29 * Returns the number of bytes per pixel.
30 */
31 static u32 BytesPerPixel(PixelFormat format) {
32 switch (format) {
33 case PixelFormat::ABGR8:
34 return 4;
35 }
36
37 UNREACHABLE();
38 }
39
40 VAddr address;
41 u32 offset;
42 u32 width;
43 u32 height;
44 u32 stride;
45 PixelFormat pixel_format;
46 bool flip_vertical;
47 };
48
49 virtual ~RendererBase() {} 21 virtual ~RendererBase() {}
50 22
51 /// Swap buffers (render frame) 23 /// Swap buffers (render frame)
52 virtual void SwapBuffers(boost::optional<const FramebufferInfo&> framebuffer_info) = 0; 24 virtual void SwapBuffers(boost::optional<const Tegra::FramebufferConfig&> framebuffer) = 0;
53 25
54 /** 26 /**
55 * Set the emulator window to use for renderer 27 * Set the emulator window to use for renderer
@@ -74,12 +46,16 @@ public:
74 return m_current_frame; 46 return m_current_frame;
75 } 47 }
76 48
49 VideoCore::RasterizerInterface* Rasterizer() const {
50 return rasterizer.get();
51 }
52
77 void RefreshRasterizerSetting(); 53 void RefreshRasterizerSetting();
78 54
79protected: 55protected:
56 std::unique_ptr<VideoCore::RasterizerInterface> rasterizer;
80 f32 m_current_fps = 0.0f; ///< Current framerate, should be set by the renderer 57 f32 m_current_fps = 0.0f; ///< Current framerate, should be set by the renderer
81 int m_current_frame = 0; ///< Current frame, should be set by the renderer 58 int m_current_frame = 0; ///< Current frame, should be set by the renderer
82 59
83private: 60private:
84 bool opengl_rasterizer_active = false;
85}; 61};
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 24cfff229..286491b73 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -54,6 +54,8 @@ static void SetShaderUniformBlockBindings(GLuint shader) {
54} 54}
55 55
56RasterizerOpenGL::RasterizerOpenGL() { 56RasterizerOpenGL::RasterizerOpenGL() {
57 shader_dirty = true;
58
57 has_ARB_buffer_storage = false; 59 has_ARB_buffer_storage = false;
58 has_ARB_direct_state_access = false; 60 has_ARB_direct_state_access = false;
59 has_ARB_separate_shader_objects = false; 61 has_ARB_separate_shader_objects = false;
@@ -106,8 +108,6 @@ RasterizerOpenGL::RasterizerOpenGL() {
106 state.draw.vertex_buffer = stream_buffer->GetHandle(); 108 state.draw.vertex_buffer = stream_buffer->GetHandle();
107 109
108 pipeline.Create(); 110 pipeline.Create();
109 vs_input_index_min = 0;
110 vs_input_index_max = 0;
111 state.draw.program_pipeline = pipeline.handle; 111 state.draw.program_pipeline = pipeline.handle;
112 state.draw.shader_program = 0; 112 state.draw.shader_program = 0;
113 state.draw.vertex_array = hw_vao.handle; 113 state.draw.vertex_array = hw_vao.handle;
@@ -120,20 +120,14 @@ RasterizerOpenGL::RasterizerOpenGL() {
120 glBufferData(GL_UNIFORM_BUFFER, sizeof(VSUniformData), nullptr, GL_STREAM_COPY); 120 glBufferData(GL_UNIFORM_BUFFER, sizeof(VSUniformData), nullptr, GL_STREAM_COPY);
121 glBindBufferBase(GL_UNIFORM_BUFFER, 1, vs_uniform_buffer.handle); 121 glBindBufferBase(GL_UNIFORM_BUFFER, 1, vs_uniform_buffer.handle);
122 } else { 122 } else {
123 UNIMPLEMENTED(); 123 ASSERT_MSG(false, "Unimplemented");
124 } 124 }
125 125
126 accelerate_draw = AccelDraw::Disabled; 126 accelerate_draw = AccelDraw::Disabled;
127 127
128 glEnable(GL_BLEND); 128 glEnable(GL_BLEND);
129 129
130 // Sync fixed function OpenGL state 130 LOG_WARNING(HW_GPU, "Sync fixed function OpenGL state here when ready");
131 SyncClipEnabled();
132 SyncClipCoef();
133 SyncCullMode();
134 SyncBlendEnabled();
135 SyncBlendFuncs();
136 SyncBlendColor();
137} 131}
138 132
139RasterizerOpenGL::~RasterizerOpenGL() { 133RasterizerOpenGL::~RasterizerOpenGL() {
@@ -167,12 +161,12 @@ void RasterizerOpenGL::SetupVertexShader(VSUniformData* ub_ptr, GLintptr buffer_
167 161
168void RasterizerOpenGL::SetupFragmentShader(FSUniformData* ub_ptr, GLintptr buffer_offset) { 162void RasterizerOpenGL::SetupFragmentShader(FSUniformData* ub_ptr, GLintptr buffer_offset) {
169 MICROPROFILE_SCOPE(OpenGL_FS); 163 MICROPROFILE_SCOPE(OpenGL_FS);
170 UNIMPLEMENTED(); 164 ASSERT_MSG(false, "Unimplemented");
171} 165}
172 166
173bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) { 167bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) {
174 if (!has_ARB_separate_shader_objects) { 168 if (!has_ARB_separate_shader_objects) {
175 UNIMPLEMENTED(); 169 ASSERT_MSG(false, "Unimplemented");
176 return false; 170 return false;
177 } 171 }
178 172
@@ -194,17 +188,17 @@ void RasterizerOpenGL::FlushAll() {
194 res_cache.FlushAll(); 188 res_cache.FlushAll();
195} 189}
196 190
197void RasterizerOpenGL::FlushRegion(PAddr addr, u32 size) { 191void RasterizerOpenGL::FlushRegion(VAddr addr, u64 size) {
198 MICROPROFILE_SCOPE(OpenGL_CacheManagement); 192 MICROPROFILE_SCOPE(OpenGL_CacheManagement);
199 res_cache.FlushRegion(addr, size); 193 res_cache.FlushRegion(addr, size);
200} 194}
201 195
202void RasterizerOpenGL::InvalidateRegion(PAddr addr, u32 size) { 196void RasterizerOpenGL::InvalidateRegion(VAddr addr, u64 size) {
203 MICROPROFILE_SCOPE(OpenGL_CacheManagement); 197 MICROPROFILE_SCOPE(OpenGL_CacheManagement);
204 res_cache.InvalidateRegion(addr, size, nullptr); 198 res_cache.InvalidateRegion(addr, size, nullptr);
205} 199}
206 200
207void RasterizerOpenGL::FlushAndInvalidateRegion(PAddr addr, u32 size) { 201void RasterizerOpenGL::FlushAndInvalidateRegion(VAddr addr, u64 size) {
208 MICROPROFILE_SCOPE(OpenGL_CacheManagement); 202 MICROPROFILE_SCOPE(OpenGL_CacheManagement);
209 res_cache.FlushRegion(addr, size); 203 res_cache.FlushRegion(addr, size);
210 res_cache.InvalidateRegion(addr, size, nullptr); 204 res_cache.InvalidateRegion(addr, size, nullptr);
@@ -212,58 +206,144 @@ void RasterizerOpenGL::FlushAndInvalidateRegion(PAddr addr, u32 size) {
212 206
213bool RasterizerOpenGL::AccelerateDisplayTransfer(const void* config) { 207bool RasterizerOpenGL::AccelerateDisplayTransfer(const void* config) {
214 MICROPROFILE_SCOPE(OpenGL_Blits); 208 MICROPROFILE_SCOPE(OpenGL_Blits);
215 UNIMPLEMENTED(); 209 ASSERT_MSG(false, "Unimplemented");
216 return true; 210 return true;
217} 211}
218 212
219bool RasterizerOpenGL::AccelerateTextureCopy(const void* config) { 213bool RasterizerOpenGL::AccelerateTextureCopy(const void* config) {
220 UNIMPLEMENTED(); 214 ASSERT_MSG(false, "Unimplemented");
221 return true; 215 return true;
222} 216}
223 217
224bool RasterizerOpenGL::AccelerateFill(const void* config) { 218bool RasterizerOpenGL::AccelerateFill(const void* config) {
225 UNIMPLEMENTED(); 219 ASSERT_MSG(false, "Unimplemented");
226 return true; 220 return true;
227} 221}
228 222
229bool RasterizerOpenGL::AccelerateDisplay(const void* config, PAddr framebuffer_addr, 223bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& framebuffer,
230 u32 pixel_stride, ScreenInfo& screen_info) { 224 VAddr framebuffer_addr, u32 pixel_stride,
231 UNIMPLEMENTED(); 225 ScreenInfo& screen_info) {
226 if (framebuffer_addr == 0) {
227 return false;
228 }
229 MICROPROFILE_SCOPE(OpenGL_CacheManagement);
230
231 SurfaceParams src_params;
232 src_params.addr = framebuffer_addr;
233 src_params.width = std::min(framebuffer.width, pixel_stride);
234 src_params.height = framebuffer.height;
235 src_params.stride = pixel_stride;
236 src_params.is_tiled = false;
237 src_params.pixel_format =
238 SurfaceParams::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format);
239 src_params.UpdateParams();
240
241 MathUtil::Rectangle<u32> src_rect;
242 Surface src_surface;
243 std::tie(src_surface, src_rect) =
244 res_cache.GetSurfaceSubRect(src_params, ScaleMatch::Ignore, true);
245
246 if (src_surface == nullptr) {
247 return false;
248 }
249
250 u32 scaled_width = src_surface->GetScaledWidth();
251 u32 scaled_height = src_surface->GetScaledHeight();
252
253 screen_info.display_texcoords = MathUtil::Rectangle<float>(
254 (float)src_rect.bottom / (float)scaled_height, (float)src_rect.left / (float)scaled_width,
255 (float)src_rect.top / (float)scaled_height, (float)src_rect.right / (float)scaled_width);
256
257 screen_info.display_texture = src_surface->texture.handle;
258
232 return true; 259 return true;
233} 260}
234 261
235void RasterizerOpenGL::SetShader() { 262void RasterizerOpenGL::SetShader() {
236 UNIMPLEMENTED(); 263 // TODO(bunnei): The below sets up a static test shader for passing untransformed vertices to
264 // OpenGL for rendering. This should be removed/replaced when we start emulating Maxwell
265 // shaders.
266
267 static constexpr char vertex_shader[] = R"(
268#version 150 core
269
270in vec2 vert_position;
271in vec2 vert_tex_coord;
272out vec2 frag_tex_coord;
273
274void main() {
275 // Multiply input position by the rotscale part of the matrix and then manually translate by
276 // the last column. This is equivalent to using a full 3x3 matrix and expanding the vector
277 // to `vec3(vert_position.xy, 1.0)`
278 gl_Position = vec4(mat2(mat3x2(0.0015625f, 0.0, 0.0, -0.0027778, -1.0, 1.0)) * vert_position + mat3x2(0.0015625f, 0.0, 0.0, -0.0027778, -1.0, 1.0)[2], 0.0, 1.0);
279 frag_tex_coord = vert_tex_coord;
280}
281)";
282
283 static constexpr char fragment_shader[] = R"(
284#version 150 core
285
286in vec2 frag_tex_coord;
287out vec4 color;
288
289uniform sampler2D color_texture;
290
291void main() {
292 color = vec4(1.0, 0.0, 1.0, 0.0);
293}
294)";
295
296 if (current_shader) {
297 return;
298 }
299
300 LOG_ERROR(HW_GPU, "Emulated shaders are not supported! Using a passthrough shader.");
301
302 current_shader = &test_shader;
303 if (has_ARB_separate_shader_objects) {
304 test_shader.shader.Create(vertex_shader, nullptr, fragment_shader, {}, true);
305 glActiveShaderProgram(pipeline.handle, test_shader.shader.handle);
306 } else {
307 ASSERT_MSG(false, "Unimplemented");
308 }
309
310 state.draw.shader_program = test_shader.shader.handle;
311 state.Apply();
312
313 if (has_ARB_separate_shader_objects) {
314 state.draw.shader_program = 0;
315 state.Apply();
316 }
237} 317}
238 318
239void RasterizerOpenGL::SyncClipEnabled() { 319void RasterizerOpenGL::SyncClipEnabled() {
240 UNIMPLEMENTED(); 320 ASSERT_MSG(false, "Unimplemented");
241} 321}
242 322
243void RasterizerOpenGL::SyncClipCoef() { 323void RasterizerOpenGL::SyncClipCoef() {
244 UNIMPLEMENTED(); 324 ASSERT_MSG(false, "Unimplemented");
245} 325}
246 326
247void RasterizerOpenGL::SyncCullMode() { 327void RasterizerOpenGL::SyncCullMode() {
248 UNIMPLEMENTED(); 328 ASSERT_MSG(false, "Unimplemented");
249} 329}
250 330
251void RasterizerOpenGL::SyncDepthScale() { 331void RasterizerOpenGL::SyncDepthScale() {
252 UNIMPLEMENTED(); 332 ASSERT_MSG(false, "Unimplemented");
253} 333}
254 334
255void RasterizerOpenGL::SyncDepthOffset() { 335void RasterizerOpenGL::SyncDepthOffset() {
256 UNIMPLEMENTED(); 336 ASSERT_MSG(false, "Unimplemented");
257} 337}
258 338
259void RasterizerOpenGL::SyncBlendEnabled() { 339void RasterizerOpenGL::SyncBlendEnabled() {
260 UNIMPLEMENTED(); 340 ASSERT_MSG(false, "Unimplemented");
261} 341}
262 342
263void RasterizerOpenGL::SyncBlendFuncs() { 343void RasterizerOpenGL::SyncBlendFuncs() {
264 UNIMPLEMENTED(); 344 ASSERT_MSG(false, "Unimplemented");
265} 345}
266 346
267void RasterizerOpenGL::SyncBlendColor() { 347void RasterizerOpenGL::SyncBlendColor() {
268 UNIMPLEMENTED(); 348 ASSERT_MSG(false, "Unimplemented");
269} 349}
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 893fc530f..b387f383b 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -32,16 +32,22 @@ public:
32 void DrawTriangles() override; 32 void DrawTriangles() override;
33 void NotifyMaxwellRegisterChanged(u32 id) override; 33 void NotifyMaxwellRegisterChanged(u32 id) override;
34 void FlushAll() override; 34 void FlushAll() override;
35 void FlushRegion(PAddr addr, u32 size) override; 35 void FlushRegion(VAddr addr, u64 size) override;
36 void InvalidateRegion(PAddr addr, u32 size) override; 36 void InvalidateRegion(VAddr addr, u64 size) override;
37 void FlushAndInvalidateRegion(PAddr addr, u32 size) override; 37 void FlushAndInvalidateRegion(VAddr addr, u64 size) override;
38 bool AccelerateDisplayTransfer(const void* config) override; 38 bool AccelerateDisplayTransfer(const void* config) override;
39 bool AccelerateTextureCopy(const void* config) override; 39 bool AccelerateTextureCopy(const void* config) override;
40 bool AccelerateFill(const void* config) override; 40 bool AccelerateFill(const void* config) override;
41 bool AccelerateDisplay(const void* config, PAddr framebuffer_addr, u32 pixel_stride, 41 bool AccelerateDisplay(const Tegra::FramebufferConfig& framebuffer, VAddr framebuffer_addr,
42 ScreenInfo& screen_info) override; 42 u32 pixel_stride, ScreenInfo& screen_info) override;
43 bool AccelerateDrawBatch(bool is_indexed) override; 43 bool AccelerateDrawBatch(bool is_indexed) override;
44 44
45 /// OpenGL shader generated for a given Maxwell register state
46 struct MaxwellShader {
47 /// OpenGL shader resource
48 OGLShader shader;
49 };
50
45 struct VertexShader { 51 struct VertexShader {
46 OGLShader shader; 52 OGLShader shader;
47 }; 53 };
@@ -117,6 +123,12 @@ private:
117 123
118 RasterizerCacheOpenGL res_cache; 124 RasterizerCacheOpenGL res_cache;
119 125
126 /// Shader used for test renderering - to be removed once we have emulated shaders
127 MaxwellShader test_shader{};
128
129 const MaxwellShader* current_shader{};
130 bool shader_dirty{};
131
120 struct { 132 struct {
121 UniformData data; 133 UniformData data;
122 bool dirty; 134 bool dirty;
@@ -136,8 +148,6 @@ private:
136 static constexpr size_t STREAM_BUFFER_SIZE = 4 * 1024 * 1024; 148 static constexpr size_t STREAM_BUFFER_SIZE = 4 * 1024 * 1024;
137 std::unique_ptr<OGLStreamBuffer> stream_buffer; 149 std::unique_ptr<OGLStreamBuffer> stream_buffer;
138 150
139 GLint vs_input_index_min;
140 GLint vs_input_index_max;
141 GLsizeiptr vs_input_size; 151 GLsizeiptr vs_input_size;
142 152
143 void AnalyzeVertexArray(bool is_indexed); 153 void AnalyzeVertexArray(bool is_indexed);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 884637ca5..78fa7c051 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -22,6 +22,7 @@
22#include "common/scope_exit.h" 22#include "common/scope_exit.h"
23#include "common/vector_math.h" 23#include "common/vector_math.h"
24#include "core/frontend/emu_window.h" 24#include "core/frontend/emu_window.h"
25#include "core/hle/kernel/vm_manager.h"
25#include "core/memory.h" 26#include "core/memory.h"
26#include "core/settings.h" 27#include "core/settings.h"
27#include "video_core/renderer_opengl/gl_rasterizer_cache.h" 28#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
@@ -107,7 +108,7 @@ static void MortonCopyTile(u32 stride, u8* tile_buffer, u8* gl_buffer) {
107} 108}
108 109
109template <bool morton_to_gl, PixelFormat format> 110template <bool morton_to_gl, PixelFormat format>
110static void MortonCopy(u32 stride, u32 height, u8* gl_buffer, PAddr base, PAddr start, PAddr end) { 111static void MortonCopy(u32 stride, u32 height, u8* gl_buffer, VAddr base, VAddr start, VAddr end) {
111 constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / 8; 112 constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / 8;
112 constexpr u32 tile_size = bytes_per_pixel * 64; 113 constexpr u32 tile_size = bytes_per_pixel * 64;
113 114
@@ -115,9 +116,9 @@ static void MortonCopy(u32 stride, u32 height, u8* gl_buffer, PAddr base, PAddr
115 static_assert(gl_bytes_per_pixel >= bytes_per_pixel, ""); 116 static_assert(gl_bytes_per_pixel >= bytes_per_pixel, "");
116 gl_buffer += gl_bytes_per_pixel - bytes_per_pixel; 117 gl_buffer += gl_bytes_per_pixel - bytes_per_pixel;
117 118
118 const PAddr aligned_down_start = base + Common::AlignDown(start - base, tile_size); 119 const VAddr aligned_down_start = base + Common::AlignDown(start - base, tile_size);
119 const PAddr aligned_start = base + Common::AlignUp(start - base, tile_size); 120 const VAddr aligned_start = base + Common::AlignUp(start - base, tile_size);
120 const PAddr aligned_end = base + Common::AlignDown(end - base, tile_size); 121 const VAddr aligned_end = base + Common::AlignDown(end - base, tile_size);
121 122
122 ASSERT(!morton_to_gl || (aligned_start == start && aligned_end == end)); 123 ASSERT(!morton_to_gl || (aligned_start == start && aligned_end == end));
123 124
@@ -136,7 +137,7 @@ static void MortonCopy(u32 stride, u32 height, u8* gl_buffer, PAddr base, PAddr
136 } 137 }
137 }; 138 };
138 139
139 u8* tile_buffer = Memory::GetPhysicalPointer(start); 140 u8* tile_buffer = Memory::GetPointer(start);
140 141
141 if (start < aligned_start && !morton_to_gl) { 142 if (start < aligned_start && !morton_to_gl) {
142 std::array<u8, tile_size> tmp_buf; 143 std::array<u8, tile_size> tmp_buf;
@@ -162,7 +163,7 @@ static void MortonCopy(u32 stride, u32 height, u8* gl_buffer, PAddr base, PAddr
162 } 163 }
163} 164}
164 165
165static constexpr std::array<void (*)(u32, u32, u8*, PAddr, PAddr, PAddr), 18> morton_to_gl_fns = { 166static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 18> morton_to_gl_fns = {
166 MortonCopy<true, PixelFormat::RGBA8>, // 0 167 MortonCopy<true, PixelFormat::RGBA8>, // 0
167 MortonCopy<true, PixelFormat::RGB8>, // 1 168 MortonCopy<true, PixelFormat::RGB8>, // 1
168 MortonCopy<true, PixelFormat::RGB5A1>, // 2 169 MortonCopy<true, PixelFormat::RGB5A1>, // 2
@@ -183,7 +184,7 @@ static constexpr std::array<void (*)(u32, u32, u8*, PAddr, PAddr, PAddr), 18> mo
183 MortonCopy<true, PixelFormat::D24S8> // 17 184 MortonCopy<true, PixelFormat::D24S8> // 17
184}; 185};
185 186
186static constexpr std::array<void (*)(u32, u32, u8*, PAddr, PAddr, PAddr), 18> gl_to_morton_fns = { 187static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 18> gl_to_morton_fns = {
187 MortonCopy<false, PixelFormat::RGBA8>, // 0 188 MortonCopy<false, PixelFormat::RGBA8>, // 0
188 MortonCopy<false, PixelFormat::RGB8>, // 1 189 MortonCopy<false, PixelFormat::RGB8>, // 1
189 MortonCopy<false, PixelFormat::RGB5A1>, // 2 190 MortonCopy<false, PixelFormat::RGB5A1>, // 2
@@ -290,7 +291,7 @@ static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rec
290 291
291static bool FillSurface(const Surface& surface, const u8* fill_data, 292static bool FillSurface(const Surface& surface, const u8* fill_data,
292 const MathUtil::Rectangle<u32>& fill_rect, GLuint draw_fb_handle) { 293 const MathUtil::Rectangle<u32>& fill_rect, GLuint draw_fb_handle) {
293 UNIMPLEMENTED(); 294 ASSERT_MSG(false, "Unimplemented");
294 return true; 295 return true;
295} 296}
296 297
@@ -298,9 +299,9 @@ SurfaceParams SurfaceParams::FromInterval(SurfaceInterval interval) const {
298 SurfaceParams params = *this; 299 SurfaceParams params = *this;
299 const u32 tiled_size = is_tiled ? 8 : 1; 300 const u32 tiled_size = is_tiled ? 8 : 1;
300 const u64 stride_tiled_bytes = BytesInPixels(stride * tiled_size); 301 const u64 stride_tiled_bytes = BytesInPixels(stride * tiled_size);
301 PAddr aligned_start = 302 VAddr aligned_start =
302 addr + Common::AlignDown(boost::icl::first(interval) - addr, stride_tiled_bytes); 303 addr + Common::AlignDown(boost::icl::first(interval) - addr, stride_tiled_bytes);
303 PAddr aligned_end = 304 VAddr aligned_end =
304 addr + Common::AlignUp(boost::icl::last_next(interval) - addr, stride_tiled_bytes); 305 addr + Common::AlignUp(boost::icl::last_next(interval) - addr, stride_tiled_bytes);
305 306
306 if (aligned_end - aligned_start > stride_tiled_bytes) { 307 if (aligned_end - aligned_start > stride_tiled_bytes) {
@@ -527,10 +528,10 @@ void RasterizerCacheOpenGL::CopySurface(const Surface& src_surface, const Surfac
527} 528}
528 529
529MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192)); 530MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192));
530void CachedSurface::LoadGLBuffer(PAddr load_start, PAddr load_end) { 531void CachedSurface::LoadGLBuffer(VAddr load_start, VAddr load_end) {
531 ASSERT(type != SurfaceType::Fill); 532 ASSERT(type != SurfaceType::Fill);
532 533
533 const u8* const texture_src_data = Memory::GetPhysicalPointer(addr); 534 u8* texture_src_data = Memory::GetPointer(addr);
534 if (texture_src_data == nullptr) 535 if (texture_src_data == nullptr)
535 return; 536 return;
536 537
@@ -539,35 +540,25 @@ void CachedSurface::LoadGLBuffer(PAddr load_start, PAddr load_end) {
539 gl_buffer.reset(new u8[gl_buffer_size]); 540 gl_buffer.reset(new u8[gl_buffer_size]);
540 } 541 }
541 542
542 // TODO: Should probably be done in ::Memory:: and check for other regions too
543 if (load_start < Memory::VRAM_VADDR_END && load_end > Memory::VRAM_VADDR_END)
544 load_end = Memory::VRAM_VADDR_END;
545
546 if (load_start < Memory::VRAM_VADDR && load_end > Memory::VRAM_VADDR)
547 load_start = Memory::VRAM_VADDR;
548
549 MICROPROFILE_SCOPE(OpenGL_SurfaceLoad); 543 MICROPROFILE_SCOPE(OpenGL_SurfaceLoad);
550 544
551 ASSERT(load_start >= addr && load_end <= end); 545 ASSERT(load_start >= addr && load_end <= end);
552 const u32 start_offset = load_start - addr; 546 const u64 start_offset = load_start - addr;
553 547
554 if (!is_tiled) { 548 if (!is_tiled) {
555 ASSERT(type == SurfaceType::Color); 549 ASSERT(type == SurfaceType::Color);
556 std::memcpy(&gl_buffer[start_offset], texture_src_data + start_offset, 550 const u32 bytes_per_pixel{GetFormatBpp() >> 3};
557 load_end - load_start); 551 VideoCore::MortonCopyPixels128(width, height, bytes_per_pixel, 4,
552 texture_src_data + start_offset, &gl_buffer[start_offset],
553 true);
558 } else { 554 } else {
559 if (type == SurfaceType::Texture) { 555 ASSERT_MSG(false, "Unimplemented");
560 UNIMPLEMENTED();
561 } else {
562 morton_to_gl_fns[static_cast<size_t>(pixel_format)](stride, height, &gl_buffer[0], addr,
563 load_start, load_end);
564 }
565 } 556 }
566} 557}
567 558
568MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64)); 559MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64));
569void CachedSurface::FlushGLBuffer(PAddr flush_start, PAddr flush_end) { 560void CachedSurface::FlushGLBuffer(VAddr flush_start, VAddr flush_end) {
570 u8* const dst_buffer = Memory::GetPhysicalPointer(addr); 561 u8* const dst_buffer = Memory::GetPointer(addr);
571 if (dst_buffer == nullptr) 562 if (dst_buffer == nullptr)
572 return; 563 return;
573 564
@@ -1102,7 +1093,7 @@ SurfaceRect_Tuple RasterizerCacheOpenGL::GetSurfaceSubRect(const SurfaceParams&
1102} 1093}
1103 1094
1104Surface RasterizerCacheOpenGL::GetTextureSurface(const void* config) { 1095Surface RasterizerCacheOpenGL::GetTextureSurface(const void* config) {
1105 UNIMPLEMENTED(); 1096 ASSERT_MSG(false, "Unimplemented");
1106 return {}; 1097 return {};
1107} 1098}
1108 1099
@@ -1113,7 +1104,7 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(
1113} 1104}
1114 1105
1115Surface RasterizerCacheOpenGL::GetFillSurface(const void* config) { 1106Surface RasterizerCacheOpenGL::GetFillSurface(const void* config) {
1116 UNIMPLEMENTED(); 1107 ASSERT_MSG(false, "Unimplemented");
1117 return {}; 1108 return {};
1118} 1109}
1119 1110
@@ -1167,7 +1158,7 @@ void RasterizerCacheOpenGL::DuplicateSurface(const Surface& src_surface,
1167 } 1158 }
1168} 1159}
1169 1160
1170void RasterizerCacheOpenGL::ValidateSurface(const Surface& surface, PAddr addr, u64 size) { 1161void RasterizerCacheOpenGL::ValidateSurface(const Surface& surface, VAddr addr, u64 size) {
1171 if (size == 0) 1162 if (size == 0)
1172 return; 1163 return;
1173 1164
@@ -1227,7 +1218,7 @@ void RasterizerCacheOpenGL::ValidateSurface(const Surface& surface, PAddr addr,
1227 } 1218 }
1228} 1219}
1229 1220
1230void RasterizerCacheOpenGL::FlushRegion(PAddr addr, u64 size, Surface flush_surface) { 1221void RasterizerCacheOpenGL::FlushRegion(VAddr addr, u64 size, Surface flush_surface) {
1231 if (size == 0) 1222 if (size == 0)
1232 return; 1223 return;
1233 1224
@@ -1260,10 +1251,10 @@ void RasterizerCacheOpenGL::FlushRegion(PAddr addr, u64 size, Surface flush_surf
1260} 1251}
1261 1252
1262void RasterizerCacheOpenGL::FlushAll() { 1253void RasterizerCacheOpenGL::FlushAll() {
1263 FlushRegion(0, 0xFFFFFFFF); 1254 FlushRegion(0, Kernel::VMManager::MAX_ADDRESS);
1264} 1255}
1265 1256
1266void RasterizerCacheOpenGL::InvalidateRegion(PAddr addr, u64 size, const Surface& region_owner) { 1257void RasterizerCacheOpenGL::InvalidateRegion(VAddr addr, u64 size, const Surface& region_owner) {
1267 if (size == 0) 1258 if (size == 0)
1268 return; 1259 return;
1269 1260
@@ -1356,6 +1347,6 @@ void RasterizerCacheOpenGL::UnregisterSurface(const Surface& surface) {
1356 surface_cache.subtract({surface->GetInterval(), SurfaceSet{surface}}); 1347 surface_cache.subtract({surface->GetInterval(), SurfaceSet{surface}});
1357} 1348}
1358 1349
1359void RasterizerCacheOpenGL::UpdatePagesCachedCount(PAddr addr, u64 size, int delta) { 1350void RasterizerCacheOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
1360 UNIMPLEMENTED(); 1351 // ASSERT_MSG(false, "Unimplemented");
1361} 1352}
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index 17ce0fee7..14f3cdc38 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -22,15 +22,16 @@
22#include "common/common_funcs.h" 22#include "common/common_funcs.h"
23#include "common/common_types.h" 23#include "common/common_types.h"
24#include "common/math_util.h" 24#include "common/math_util.h"
25#include "video_core/gpu.h"
25#include "video_core/renderer_opengl/gl_resource_manager.h" 26#include "video_core/renderer_opengl/gl_resource_manager.h"
26 27
27struct CachedSurface; 28struct CachedSurface;
28using Surface = std::shared_ptr<CachedSurface>; 29using Surface = std::shared_ptr<CachedSurface>;
29using SurfaceSet = std::set<Surface>; 30using SurfaceSet = std::set<Surface>;
30 31
31using SurfaceRegions = boost::icl::interval_set<PAddr>; 32using SurfaceRegions = boost::icl::interval_set<VAddr>;
32using SurfaceMap = boost::icl::interval_map<PAddr, Surface>; 33using SurfaceMap = boost::icl::interval_map<VAddr, Surface>;
33using SurfaceCache = boost::icl::interval_map<PAddr, SurfaceSet>; 34using SurfaceCache = boost::icl::interval_map<VAddr, SurfaceSet>;
34 35
35using SurfaceInterval = SurfaceCache::interval_type; 36using SurfaceInterval = SurfaceCache::interval_type;
36static_assert(std::is_same<SurfaceRegions::interval_type, SurfaceCache::interval_type>() && 37static_assert(std::is_same<SurfaceRegions::interval_type, SurfaceCache::interval_type>() &&
@@ -115,6 +116,15 @@ struct SurfaceParams {
115 return GetFormatBpp(pixel_format); 116 return GetFormatBpp(pixel_format);
116 } 117 }
117 118
119 static PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) {
120 switch (format) {
121 case Tegra::FramebufferConfig::PixelFormat::ABGR8:
122 return PixelFormat::RGBA8;
123 default:
124 UNREACHABLE();
125 }
126 }
127
118 static bool CheckFormatsBlittable(PixelFormat pixel_format_a, PixelFormat pixel_format_b) { 128 static bool CheckFormatsBlittable(PixelFormat pixel_format_a, PixelFormat pixel_format_b) {
119 SurfaceType a_type = GetFormatType(pixel_format_a); 129 SurfaceType a_type = GetFormatType(pixel_format_a);
120 SurfaceType b_type = GetFormatType(pixel_format_b); 130 SurfaceType b_type = GetFormatType(pixel_format_b);
@@ -211,8 +221,8 @@ struct SurfaceParams {
211 MathUtil::Rectangle<u32> GetSubRect(const SurfaceParams& sub_surface) const; 221 MathUtil::Rectangle<u32> GetSubRect(const SurfaceParams& sub_surface) const;
212 MathUtil::Rectangle<u32> GetScaledSubRect(const SurfaceParams& sub_surface) const; 222 MathUtil::Rectangle<u32> GetScaledSubRect(const SurfaceParams& sub_surface) const;
213 223
214 PAddr addr = 0; 224 VAddr addr = 0;
215 PAddr end = 0; 225 VAddr end = 0;
216 u64 size = 0; 226 u64 size = 0;
217 227
218 u32 width = 0; 228 u32 width = 0;
@@ -257,9 +267,9 @@ struct CachedSurface : SurfaceParams {
257 std::unique_ptr<u8[]> gl_buffer; 267 std::unique_ptr<u8[]> gl_buffer;
258 size_t gl_buffer_size = 0; 268 size_t gl_buffer_size = 0;
259 269
260 // Read/Write data in 3DS memory to/from gl_buffer 270 // Read/Write data in Switch memory to/from gl_buffer
261 void LoadGLBuffer(PAddr load_start, PAddr load_end); 271 void LoadGLBuffer(VAddr load_start, VAddr load_end);
262 void FlushGLBuffer(PAddr flush_start, PAddr flush_end); 272 void FlushGLBuffer(VAddr flush_start, VAddr flush_end);
263 273
264 // Upload/Download data in gl_buffer in/to this surface's texture 274 // Upload/Download data in gl_buffer in/to this surface's texture
265 void UploadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint read_fb_handle, 275 void UploadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint read_fb_handle,
@@ -307,10 +317,10 @@ public:
307 SurfaceRect_Tuple GetTexCopySurface(const SurfaceParams& params); 317 SurfaceRect_Tuple GetTexCopySurface(const SurfaceParams& params);
308 318
309 /// Write any cached resources overlapping the region back to memory (if dirty) 319 /// Write any cached resources overlapping the region back to memory (if dirty)
310 void FlushRegion(PAddr addr, u64 size, Surface flush_surface = nullptr); 320 void FlushRegion(VAddr addr, u64 size, Surface flush_surface = nullptr);
311 321
312 /// Mark region as being invalidated by region_owner (nullptr if 3DS memory) 322 /// Mark region as being invalidated by region_owner (nullptr if 3DS memory)
313 void InvalidateRegion(PAddr addr, u64 size, const Surface& region_owner); 323 void InvalidateRegion(VAddr addr, u64 size, const Surface& region_owner);
314 324
315 /// Flush all cached resources tracked by this cache manager 325 /// Flush all cached resources tracked by this cache manager
316 void FlushAll(); 326 void FlushAll();
@@ -319,7 +329,7 @@ private:
319 void DuplicateSurface(const Surface& src_surface, const Surface& dest_surface); 329 void DuplicateSurface(const Surface& src_surface, const Surface& dest_surface);
320 330
321 /// Update surface's texture for given region when necessary 331 /// Update surface's texture for given region when necessary
322 void ValidateSurface(const Surface& surface, PAddr addr, u64 size); 332 void ValidateSurface(const Surface& surface, VAddr addr, u64 size);
323 333
324 /// Create a new surface 334 /// Create a new surface
325 Surface CreateSurface(const SurfaceParams& params); 335 Surface CreateSurface(const SurfaceParams& params);
@@ -331,7 +341,7 @@ private:
331 void UnregisterSurface(const Surface& surface); 341 void UnregisterSurface(const Surface& surface);
332 342
333 /// Increase/decrease the number of surface in pages touching the specified region 343 /// Increase/decrease the number of surface in pages touching the specified region
334 void UpdatePagesCachedCount(PAddr addr, u64 size, int delta); 344 void UpdatePagesCachedCount(VAddr addr, u64 size, int delta);
335 345
336 SurfaceCache surface_cache; 346 SurfaceCache surface_cache;
337 PageMap cached_pages; 347 PageMap cached_pages;
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 65d38ade5..1a24855d7 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -20,6 +20,7 @@
20#include "core/settings.h" 20#include "core/settings.h"
21#include "core/tracer/recorder.h" 21#include "core/tracer/recorder.h"
22#include "video_core/renderer_opengl/renderer_opengl.h" 22#include "video_core/renderer_opengl/renderer_opengl.h"
23#include "video_core/utils.h"
23#include "video_core/video_core.h" 24#include "video_core/video_core.h"
24 25
25static const char vertex_shader[] = R"( 26static const char vertex_shader[] = R"(
@@ -98,22 +99,22 @@ RendererOpenGL::RendererOpenGL() = default;
98RendererOpenGL::~RendererOpenGL() = default; 99RendererOpenGL::~RendererOpenGL() = default;
99 100
100/// Swap buffers (render frame) 101/// Swap buffers (render frame)
101void RendererOpenGL::SwapBuffers(boost::optional<const FramebufferInfo&> framebuffer_info) { 102void RendererOpenGL::SwapBuffers(boost::optional<const Tegra::FramebufferConfig&> framebuffer) {
102 // Maintain the rasterizer's state as a priority 103 // Maintain the rasterizer's state as a priority
103 OpenGLState prev_state = OpenGLState::GetCurState(); 104 OpenGLState prev_state = OpenGLState::GetCurState();
104 state.Apply(); 105 state.Apply();
105 106
106 if (framebuffer_info != boost::none) { 107 if (framebuffer != boost::none) {
107 // If framebuffer_info is provided, reload it from memory to a texture 108 // If framebuffer is provided, reload it from memory to a texture
108 if (screen_info.texture.width != (GLsizei)framebuffer_info->width || 109 if (screen_info.texture.width != (GLsizei)framebuffer->width ||
109 screen_info.texture.height != (GLsizei)framebuffer_info->height || 110 screen_info.texture.height != (GLsizei)framebuffer->height ||
110 screen_info.texture.pixel_format != framebuffer_info->pixel_format) { 111 screen_info.texture.pixel_format != framebuffer->pixel_format) {
111 // Reallocate texture if the framebuffer size has changed. 112 // Reallocate texture if the framebuffer size has changed.
112 // This is expected to not happen very often and hence should not be a 113 // This is expected to not happen very often and hence should not be a
113 // performance problem. 114 // performance problem.
114 ConfigureFramebufferTexture(screen_info.texture, *framebuffer_info); 115 ConfigureFramebufferTexture(screen_info.texture, *framebuffer);
115 } 116 }
116 LoadFBToScreenInfo(*framebuffer_info, screen_info); 117 LoadFBToScreenInfo(*framebuffer, screen_info);
117 } 118 }
118 119
119 DrawScreens(); 120 DrawScreens();
@@ -131,164 +132,59 @@ void RendererOpenGL::SwapBuffers(boost::optional<const FramebufferInfo&> framebu
131 RefreshRasterizerSetting(); 132 RefreshRasterizerSetting();
132} 133}
133 134
134static inline u32 MortonInterleave128(u32 x, u32 y) {
135 // 128x128 Z-Order coordinate from 2D coordinates
136 static constexpr u32 xlut[] = {
137 0x0000, 0x0001, 0x0002, 0x0003, 0x0008, 0x0009, 0x000a, 0x000b, 0x0040, 0x0041, 0x0042,
138 0x0043, 0x0048, 0x0049, 0x004a, 0x004b, 0x0800, 0x0801, 0x0802, 0x0803, 0x0808, 0x0809,
139 0x080a, 0x080b, 0x0840, 0x0841, 0x0842, 0x0843, 0x0848, 0x0849, 0x084a, 0x084b, 0x1000,
140 0x1001, 0x1002, 0x1003, 0x1008, 0x1009, 0x100a, 0x100b, 0x1040, 0x1041, 0x1042, 0x1043,
141 0x1048, 0x1049, 0x104a, 0x104b, 0x1800, 0x1801, 0x1802, 0x1803, 0x1808, 0x1809, 0x180a,
142 0x180b, 0x1840, 0x1841, 0x1842, 0x1843, 0x1848, 0x1849, 0x184a, 0x184b, 0x2000, 0x2001,
143 0x2002, 0x2003, 0x2008, 0x2009, 0x200a, 0x200b, 0x2040, 0x2041, 0x2042, 0x2043, 0x2048,
144 0x2049, 0x204a, 0x204b, 0x2800, 0x2801, 0x2802, 0x2803, 0x2808, 0x2809, 0x280a, 0x280b,
145 0x2840, 0x2841, 0x2842, 0x2843, 0x2848, 0x2849, 0x284a, 0x284b, 0x3000, 0x3001, 0x3002,
146 0x3003, 0x3008, 0x3009, 0x300a, 0x300b, 0x3040, 0x3041, 0x3042, 0x3043, 0x3048, 0x3049,
147 0x304a, 0x304b, 0x3800, 0x3801, 0x3802, 0x3803, 0x3808, 0x3809, 0x380a, 0x380b, 0x3840,
148 0x3841, 0x3842, 0x3843, 0x3848, 0x3849, 0x384a, 0x384b, 0x0000, 0x0001, 0x0002, 0x0003,
149 0x0008, 0x0009, 0x000a, 0x000b, 0x0040, 0x0041, 0x0042, 0x0043, 0x0048, 0x0049, 0x004a,
150 0x004b, 0x0800, 0x0801, 0x0802, 0x0803, 0x0808, 0x0809, 0x080a, 0x080b, 0x0840, 0x0841,
151 0x0842, 0x0843, 0x0848, 0x0849, 0x084a, 0x084b, 0x1000, 0x1001, 0x1002, 0x1003, 0x1008,
152 0x1009, 0x100a, 0x100b, 0x1040, 0x1041, 0x1042, 0x1043, 0x1048, 0x1049, 0x104a, 0x104b,
153 0x1800, 0x1801, 0x1802, 0x1803, 0x1808, 0x1809, 0x180a, 0x180b, 0x1840, 0x1841, 0x1842,
154 0x1843, 0x1848, 0x1849, 0x184a, 0x184b, 0x2000, 0x2001, 0x2002, 0x2003, 0x2008, 0x2009,
155 0x200a, 0x200b, 0x2040, 0x2041, 0x2042, 0x2043, 0x2048, 0x2049, 0x204a, 0x204b, 0x2800,
156 0x2801, 0x2802, 0x2803, 0x2808, 0x2809, 0x280a, 0x280b, 0x2840, 0x2841, 0x2842, 0x2843,
157 0x2848, 0x2849, 0x284a, 0x284b, 0x3000, 0x3001, 0x3002, 0x3003, 0x3008, 0x3009, 0x300a,
158 0x300b, 0x3040, 0x3041, 0x3042, 0x3043, 0x3048, 0x3049, 0x304a, 0x304b, 0x3800, 0x3801,
159 0x3802, 0x3803, 0x3808, 0x3809, 0x380a, 0x380b, 0x3840, 0x3841, 0x3842, 0x3843, 0x3848,
160 0x3849, 0x384a, 0x384b, 0x0000, 0x0001, 0x0002, 0x0003, 0x0008, 0x0009, 0x000a, 0x000b,
161 0x0040, 0x0041, 0x0042, 0x0043, 0x0048, 0x0049, 0x004a, 0x004b, 0x0800, 0x0801, 0x0802,
162 0x0803, 0x0808, 0x0809, 0x080a, 0x080b, 0x0840, 0x0841, 0x0842, 0x0843, 0x0848, 0x0849,
163 0x084a, 0x084b, 0x1000, 0x1001, 0x1002, 0x1003, 0x1008, 0x1009, 0x100a, 0x100b, 0x1040,
164 0x1041, 0x1042, 0x1043, 0x1048, 0x1049, 0x104a, 0x104b, 0x1800, 0x1801, 0x1802, 0x1803,
165 0x1808, 0x1809, 0x180a, 0x180b, 0x1840, 0x1841, 0x1842, 0x1843, 0x1848, 0x1849, 0x184a,
166 0x184b, 0x2000, 0x2001, 0x2002, 0x2003, 0x2008, 0x2009, 0x200a, 0x200b, 0x2040, 0x2041,
167 0x2042, 0x2043, 0x2048, 0x2049, 0x204a, 0x204b, 0x2800, 0x2801, 0x2802, 0x2803, 0x2808,
168 0x2809, 0x280a, 0x280b, 0x2840, 0x2841, 0x2842, 0x2843, 0x2848, 0x2849, 0x284a, 0x284b,
169 0x3000, 0x3001, 0x3002, 0x3003, 0x3008, 0x3009, 0x300a, 0x300b, 0x3040, 0x3041, 0x3042,
170 0x3043, 0x3048, 0x3049, 0x304a, 0x304b, 0x3800, 0x3801, 0x3802, 0x3803, 0x3808, 0x3809,
171 0x380a, 0x380b, 0x3840, 0x3841, 0x3842, 0x3843, 0x3848, 0x3849, 0x384a, 0x384b,
172 };
173 static constexpr u32 ylut[] = {
174 0x0000, 0x0004, 0x0010, 0x0014, 0x0020, 0x0024, 0x0030, 0x0034, 0x0080, 0x0084, 0x0090,
175 0x0094, 0x00a0, 0x00a4, 0x00b0, 0x00b4, 0x0100, 0x0104, 0x0110, 0x0114, 0x0120, 0x0124,
176 0x0130, 0x0134, 0x0180, 0x0184, 0x0190, 0x0194, 0x01a0, 0x01a4, 0x01b0, 0x01b4, 0x0200,
177 0x0204, 0x0210, 0x0214, 0x0220, 0x0224, 0x0230, 0x0234, 0x0280, 0x0284, 0x0290, 0x0294,
178 0x02a0, 0x02a4, 0x02b0, 0x02b4, 0x0300, 0x0304, 0x0310, 0x0314, 0x0320, 0x0324, 0x0330,
179 0x0334, 0x0380, 0x0384, 0x0390, 0x0394, 0x03a0, 0x03a4, 0x03b0, 0x03b4, 0x0400, 0x0404,
180 0x0410, 0x0414, 0x0420, 0x0424, 0x0430, 0x0434, 0x0480, 0x0484, 0x0490, 0x0494, 0x04a0,
181 0x04a4, 0x04b0, 0x04b4, 0x0500, 0x0504, 0x0510, 0x0514, 0x0520, 0x0524, 0x0530, 0x0534,
182 0x0580, 0x0584, 0x0590, 0x0594, 0x05a0, 0x05a4, 0x05b0, 0x05b4, 0x0600, 0x0604, 0x0610,
183 0x0614, 0x0620, 0x0624, 0x0630, 0x0634, 0x0680, 0x0684, 0x0690, 0x0694, 0x06a0, 0x06a4,
184 0x06b0, 0x06b4, 0x0700, 0x0704, 0x0710, 0x0714, 0x0720, 0x0724, 0x0730, 0x0734, 0x0780,
185 0x0784, 0x0790, 0x0794, 0x07a0, 0x07a4, 0x07b0, 0x07b4, 0x0000, 0x0004, 0x0010, 0x0014,
186 0x0020, 0x0024, 0x0030, 0x0034, 0x0080, 0x0084, 0x0090, 0x0094, 0x00a0, 0x00a4, 0x00b0,
187 0x00b4, 0x0100, 0x0104, 0x0110, 0x0114, 0x0120, 0x0124, 0x0130, 0x0134, 0x0180, 0x0184,
188 0x0190, 0x0194, 0x01a0, 0x01a4, 0x01b0, 0x01b4, 0x0200, 0x0204, 0x0210, 0x0214, 0x0220,
189 0x0224, 0x0230, 0x0234, 0x0280, 0x0284, 0x0290, 0x0294, 0x02a0, 0x02a4, 0x02b0, 0x02b4,
190 0x0300, 0x0304, 0x0310, 0x0314, 0x0320, 0x0324, 0x0330, 0x0334, 0x0380, 0x0384, 0x0390,
191 0x0394, 0x03a0, 0x03a4, 0x03b0, 0x03b4, 0x0400, 0x0404, 0x0410, 0x0414, 0x0420, 0x0424,
192 0x0430, 0x0434, 0x0480, 0x0484, 0x0490, 0x0494, 0x04a0, 0x04a4, 0x04b0, 0x04b4, 0x0500,
193 0x0504, 0x0510, 0x0514, 0x0520, 0x0524, 0x0530, 0x0534, 0x0580, 0x0584, 0x0590, 0x0594,
194 0x05a0, 0x05a4, 0x05b0, 0x05b4, 0x0600, 0x0604, 0x0610, 0x0614, 0x0620, 0x0624, 0x0630,
195 0x0634, 0x0680, 0x0684, 0x0690, 0x0694, 0x06a0, 0x06a4, 0x06b0, 0x06b4, 0x0700, 0x0704,
196 0x0710, 0x0714, 0x0720, 0x0724, 0x0730, 0x0734, 0x0780, 0x0784, 0x0790, 0x0794, 0x07a0,
197 0x07a4, 0x07b0, 0x07b4, 0x0000, 0x0004, 0x0010, 0x0014, 0x0020, 0x0024, 0x0030, 0x0034,
198 0x0080, 0x0084, 0x0090, 0x0094, 0x00a0, 0x00a4, 0x00b0, 0x00b4, 0x0100, 0x0104, 0x0110,
199 0x0114, 0x0120, 0x0124, 0x0130, 0x0134, 0x0180, 0x0184, 0x0190, 0x0194, 0x01a0, 0x01a4,
200 0x01b0, 0x01b4, 0x0200, 0x0204, 0x0210, 0x0214, 0x0220, 0x0224, 0x0230, 0x0234, 0x0280,
201 0x0284, 0x0290, 0x0294, 0x02a0, 0x02a4, 0x02b0, 0x02b4, 0x0300, 0x0304, 0x0310, 0x0314,
202 0x0320, 0x0324, 0x0330, 0x0334, 0x0380, 0x0384, 0x0390, 0x0394, 0x03a0, 0x03a4, 0x03b0,
203 0x03b4, 0x0400, 0x0404, 0x0410, 0x0414, 0x0420, 0x0424, 0x0430, 0x0434, 0x0480, 0x0484,
204 0x0490, 0x0494, 0x04a0, 0x04a4, 0x04b0, 0x04b4, 0x0500, 0x0504, 0x0510, 0x0514, 0x0520,
205 0x0524, 0x0530, 0x0534, 0x0580, 0x0584, 0x0590, 0x0594, 0x05a0, 0x05a4, 0x05b0, 0x05b4,
206 0x0600, 0x0604, 0x0610, 0x0614, 0x0620, 0x0624, 0x0630, 0x0634, 0x0680, 0x0684, 0x0690,
207 0x0694, 0x06a0, 0x06a4, 0x06b0, 0x06b4, 0x0700, 0x0704, 0x0710, 0x0714, 0x0720, 0x0724,
208 0x0730, 0x0734, 0x0780, 0x0784, 0x0790, 0x0794, 0x07a0, 0x07a4, 0x07b0, 0x07b4,
209 };
210 return xlut[x % 128] + ylut[y % 128];
211}
212
213static inline u32 GetMortonOffset128(u32 x, u32 y, u32 bytes_per_pixel) {
214 // Calculates the offset of the position of the pixel in Morton order
215 // Framebuffer images are split into 128x128 tiles.
216
217 const unsigned int block_height = 128;
218 const unsigned int coarse_x = x & ~127;
219
220 u32 i = MortonInterleave128(x, y);
221
222 const unsigned int offset = coarse_x * block_height;
223
224 return (i + offset) * bytes_per_pixel;
225}
226
227static void MortonCopyPixels128(u32 width, u32 height, u32 bytes_per_pixel, u32 gl_bytes_per_pixel,
228 u8* morton_data, u8* gl_data, bool morton_to_gl) {
229 u8* data_ptrs[2];
230 for (unsigned y = 0; y < height; ++y) {
231 for (unsigned x = 0; x < width; ++x) {
232 const u32 coarse_y = y & ~127;
233 u32 morton_offset =
234 GetMortonOffset128(x, y, bytes_per_pixel) + coarse_y * width * bytes_per_pixel;
235 u32 gl_pixel_index = (x + (height - 1 - y) * width) * gl_bytes_per_pixel;
236
237 data_ptrs[morton_to_gl] = morton_data + morton_offset;
238 data_ptrs[!morton_to_gl] = &gl_data[gl_pixel_index];
239
240 memcpy(data_ptrs[0], data_ptrs[1], bytes_per_pixel);
241 }
242 }
243}
244
245/** 135/**
246 * Loads framebuffer from emulated memory into the active OpenGL texture. 136 * Loads framebuffer from emulated memory into the active OpenGL texture.
247 */ 137 */
248void RendererOpenGL::LoadFBToScreenInfo(const FramebufferInfo& framebuffer_info, 138void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer,
249 ScreenInfo& screen_info) { 139 ScreenInfo& screen_info) {
250 const u32 bpp{FramebufferInfo::BytesPerPixel(framebuffer_info.pixel_format)}; 140 const u32 bytes_per_pixel{Tegra::FramebufferConfig::BytesPerPixel(framebuffer.pixel_format)};
251 const u32 size_in_bytes{framebuffer_info.stride * framebuffer_info.height * bpp}; 141 const u64 size_in_bytes{framebuffer.stride * framebuffer.height * bytes_per_pixel};
142 const VAddr framebuffer_addr{framebuffer.address + framebuffer.offset};
252 143
253 MortonCopyPixels128(framebuffer_info.width, framebuffer_info.height, bpp, 4, 144 // TODO(bunnei): The framebuffer region should only be invalidated if it is written to, not
254 Memory::GetPointer(framebuffer_info.address), gl_framebuffer_data.data(), 145 // every frame. When we find the right place for this, the below line can be removed.
255 true); 146 Memory::RasterizerFlushVirtualRegion(framebuffer_addr, size_in_bytes,
147 Memory::FlushMode::Invalidate);
256 148
257 LOG_TRACE(Render_OpenGL, "0x%08x bytes from 0x%llx(%dx%d), fmt %x", size_in_bytes, 149 // Framebuffer orientation handling
258 framebuffer_info.address, framebuffer_info.width, framebuffer_info.height, 150 framebuffer_transform_flags = framebuffer.transform_flags;
259 (int)framebuffer_info.pixel_format);
260 151
261 // Ensure no bad interactions with GL_UNPACK_ALIGNMENT, which by default 152 // Ensure no bad interactions with GL_UNPACK_ALIGNMENT, which by default
262 // only allows rows to have a memory alignement of 4. 153 // only allows rows to have a memory alignement of 4.
263 ASSERT(framebuffer_info.stride % 4 == 0); 154 ASSERT(framebuffer.stride % 4 == 0);
264 155
265 framebuffer_flip_vertical = framebuffer_info.flip_vertical; 156 if (!Rasterizer()->AccelerateDisplay(framebuffer, framebuffer_addr, framebuffer.stride,
157 screen_info)) {
158 // Reset the screen info's display texture to its own permanent texture
159 screen_info.display_texture = screen_info.texture.resource.handle;
160 screen_info.display_texcoords = MathUtil::Rectangle<float>(0.f, 0.f, 1.f, 1.f);
266 161
267 // Reset the screen info's display texture to its own permanent texture 162 Rasterizer()->FlushRegion(framebuffer_addr, size_in_bytes);
268 screen_info.display_texture = screen_info.texture.resource.handle;
269 screen_info.display_texcoords = MathUtil::Rectangle<float>(0.f, 0.f, 1.f, 1.f);
270 163
271 // Memory::RasterizerFlushRegion(framebuffer_info.address, size_in_bytes); 164 VideoCore::MortonCopyPixels128(framebuffer.width, framebuffer.height, bytes_per_pixel, 4,
165 Memory::GetPointer(framebuffer_addr),
166 gl_framebuffer_data.data(), true);
272 167
273 state.texture_units[0].texture_2d = screen_info.texture.resource.handle; 168 state.texture_units[0].texture_2d = screen_info.texture.resource.handle;
274 state.Apply(); 169 state.Apply();
275 170
276 glActiveTexture(GL_TEXTURE0); 171 glActiveTexture(GL_TEXTURE0);
277 glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)framebuffer_info.stride); 172 glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(framebuffer.stride));
278 173
279 // Update existing texture 174 // Update existing texture
280 // TODO: Test what happens on hardware when you change the framebuffer dimensions so that 175 // TODO: Test what happens on hardware when you change the framebuffer dimensions so that
281 // they differ from the LCD resolution. 176 // they differ from the LCD resolution.
282 // TODO: Applications could theoretically crash Citra here by specifying too large 177 // TODO: Applications could theoretically crash yuzu here by specifying too large
283 // framebuffer sizes. We should make sure that this cannot happen. 178 // framebuffer sizes. We should make sure that this cannot happen.
284 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, framebuffer_info.width, framebuffer_info.height, 179 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, framebuffer.width, framebuffer.height,
285 screen_info.texture.gl_format, screen_info.texture.gl_type, 180 screen_info.texture.gl_format, screen_info.texture.gl_type,
286 gl_framebuffer_data.data()); 181 gl_framebuffer_data.data());
287 182
288 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 183 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
289 184
290 state.texture_units[0].texture_2d = 0; 185 state.texture_units[0].texture_2d = 0;
291 state.Apply(); 186 state.Apply();
187 }
292} 188}
293 189
294/** 190/**
@@ -372,14 +268,14 @@ void RendererOpenGL::InitOpenGLObjects() {
372} 268}
373 269
374void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, 270void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
375 const FramebufferInfo& framebuffer_info) { 271 const Tegra::FramebufferConfig& framebuffer) {
376 272
377 texture.width = framebuffer_info.width; 273 texture.width = framebuffer.width;
378 texture.height = framebuffer_info.height; 274 texture.height = framebuffer.height;
379 275
380 GLint internal_format; 276 GLint internal_format;
381 switch (framebuffer_info.pixel_format) { 277 switch (framebuffer.pixel_format) {
382 case FramebufferInfo::PixelFormat::ABGR8: 278 case Tegra::FramebufferConfig::PixelFormat::ABGR8:
383 // Use RGBA8 and swap in the fragment shader 279 // Use RGBA8 and swap in the fragment shader
384 internal_format = GL_RGBA; 280 internal_format = GL_RGBA;
385 texture.gl_format = GL_RGBA; 281 texture.gl_format = GL_RGBA;
@@ -404,8 +300,19 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
404void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w, 300void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w,
405 float h) { 301 float h) {
406 const auto& texcoords = screen_info.display_texcoords; 302 const auto& texcoords = screen_info.display_texcoords;
407 const auto& left = framebuffer_flip_vertical ? texcoords.right : texcoords.left; 303 auto left = texcoords.left;
408 const auto& right = framebuffer_flip_vertical ? texcoords.left : texcoords.right; 304 auto right = texcoords.right;
305 if (framebuffer_transform_flags != Tegra::FramebufferConfig::TransformFlags::Unset)
306 if (framebuffer_transform_flags == Tegra::FramebufferConfig::TransformFlags::FlipV) {
307 // Flip the framebuffer vertically
308 left = texcoords.right;
309 right = texcoords.left;
310 } else {
311 // Other transformations are unsupported
312 LOG_CRITICAL(HW_GPU, "unsupported framebuffer_transform_flags=%d",
313 framebuffer_transform_flags);
314 UNIMPLEMENTED();
315 }
409 316
410 std::array<ScreenRectVertex, 4> vertices = {{ 317 std::array<ScreenRectVertex, 4> vertices = {{
411 ScreenRectVertex(x, y, texcoords.top, right), 318 ScreenRectVertex(x, y, texcoords.top, right),
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h
index 05bb3c5cf..29516baf4 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.h
+++ b/src/video_core/renderer_opengl/renderer_opengl.h
@@ -21,7 +21,7 @@ struct TextureInfo {
21 GLsizei height; 21 GLsizei height;
22 GLenum gl_format; 22 GLenum gl_format;
23 GLenum gl_type; 23 GLenum gl_type;
24 RendererBase::FramebufferInfo::PixelFormat pixel_format; 24 Tegra::FramebufferConfig::PixelFormat pixel_format;
25}; 25};
26 26
27/// Structure used for storing information about the display target for each 3DS screen 27/// Structure used for storing information about the display target for each 3DS screen
@@ -37,7 +37,7 @@ public:
37 ~RendererOpenGL() override; 37 ~RendererOpenGL() override;
38 38
39 /// Swap buffers (render frame) 39 /// Swap buffers (render frame)
40 void SwapBuffers(boost::optional<const FramebufferInfo&> framebuffer_info) override; 40 void SwapBuffers(boost::optional<const Tegra::FramebufferConfig&> framebuffer) override;
41 41
42 /** 42 /**
43 * Set the emulator window to use for renderer 43 * Set the emulator window to use for renderer
@@ -53,13 +53,14 @@ public:
53 53
54private: 54private:
55 void InitOpenGLObjects(); 55 void InitOpenGLObjects();
56 void ConfigureFramebufferTexture(TextureInfo& texture, const FramebufferInfo& framebuffer_info); 56 void ConfigureFramebufferTexture(TextureInfo& texture,
57 const Tegra::FramebufferConfig& framebuffer);
57 void DrawScreens(); 58 void DrawScreens();
58 void DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w, float h); 59 void DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w, float h);
59 void UpdateFramerate(); 60 void UpdateFramerate();
60 61
61 // Loads framebuffer from emulated memory into the display information structure 62 // Loads framebuffer from emulated memory into the display information structure
62 void LoadFBToScreenInfo(const FramebufferInfo& framebuffer_info, ScreenInfo& screen_info); 63 void LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer, ScreenInfo& screen_info);
63 // Fills active OpenGL texture with the given RGBA color. 64 // Fills active OpenGL texture with the given RGBA color.
64 void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a, 65 void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a,
65 const TextureInfo& texture); 66 const TextureInfo& texture);
@@ -87,6 +88,6 @@ private:
87 GLuint attrib_position; 88 GLuint attrib_position;
88 GLuint attrib_tex_coord; 89 GLuint attrib_tex_coord;
89 90
90 /// Flips the framebuffer vertically when true 91 /// Used for transforming the framebuffer orientation
91 bool framebuffer_flip_vertical; 92 Tegra::FramebufferConfig::TransformFlags framebuffer_transform_flags;
92}; 93};
diff --git a/src/video_core/utils.h b/src/video_core/utils.h
index d94a10417..be0f7e22b 100644
--- a/src/video_core/utils.h
+++ b/src/video_core/utils.h
@@ -49,4 +49,116 @@ static inline u32 GetMortonOffset(u32 x, u32 y, u32 bytes_per_pixel) {
49 return (i + offset) * bytes_per_pixel; 49 return (i + offset) * bytes_per_pixel;
50} 50}
51 51
52static inline u32 MortonInterleave128(u32 x, u32 y) {
53 // 128x128 Z-Order coordinate from 2D coordinates
54 static constexpr u32 xlut[] = {
55 0x0000, 0x0001, 0x0002, 0x0003, 0x0008, 0x0009, 0x000a, 0x000b, 0x0040, 0x0041, 0x0042,
56 0x0043, 0x0048, 0x0049, 0x004a, 0x004b, 0x0800, 0x0801, 0x0802, 0x0803, 0x0808, 0x0809,
57 0x080a, 0x080b, 0x0840, 0x0841, 0x0842, 0x0843, 0x0848, 0x0849, 0x084a, 0x084b, 0x1000,
58 0x1001, 0x1002, 0x1003, 0x1008, 0x1009, 0x100a, 0x100b, 0x1040, 0x1041, 0x1042, 0x1043,
59 0x1048, 0x1049, 0x104a, 0x104b, 0x1800, 0x1801, 0x1802, 0x1803, 0x1808, 0x1809, 0x180a,
60 0x180b, 0x1840, 0x1841, 0x1842, 0x1843, 0x1848, 0x1849, 0x184a, 0x184b, 0x2000, 0x2001,
61 0x2002, 0x2003, 0x2008, 0x2009, 0x200a, 0x200b, 0x2040, 0x2041, 0x2042, 0x2043, 0x2048,
62 0x2049, 0x204a, 0x204b, 0x2800, 0x2801, 0x2802, 0x2803, 0x2808, 0x2809, 0x280a, 0x280b,
63 0x2840, 0x2841, 0x2842, 0x2843, 0x2848, 0x2849, 0x284a, 0x284b, 0x3000, 0x3001, 0x3002,
64 0x3003, 0x3008, 0x3009, 0x300a, 0x300b, 0x3040, 0x3041, 0x3042, 0x3043, 0x3048, 0x3049,
65 0x304a, 0x304b, 0x3800, 0x3801, 0x3802, 0x3803, 0x3808, 0x3809, 0x380a, 0x380b, 0x3840,
66 0x3841, 0x3842, 0x3843, 0x3848, 0x3849, 0x384a, 0x384b, 0x0000, 0x0001, 0x0002, 0x0003,
67 0x0008, 0x0009, 0x000a, 0x000b, 0x0040, 0x0041, 0x0042, 0x0043, 0x0048, 0x0049, 0x004a,
68 0x004b, 0x0800, 0x0801, 0x0802, 0x0803, 0x0808, 0x0809, 0x080a, 0x080b, 0x0840, 0x0841,
69 0x0842, 0x0843, 0x0848, 0x0849, 0x084a, 0x084b, 0x1000, 0x1001, 0x1002, 0x1003, 0x1008,
70 0x1009, 0x100a, 0x100b, 0x1040, 0x1041, 0x1042, 0x1043, 0x1048, 0x1049, 0x104a, 0x104b,
71 0x1800, 0x1801, 0x1802, 0x1803, 0x1808, 0x1809, 0x180a, 0x180b, 0x1840, 0x1841, 0x1842,
72 0x1843, 0x1848, 0x1849, 0x184a, 0x184b, 0x2000, 0x2001, 0x2002, 0x2003, 0x2008, 0x2009,
73 0x200a, 0x200b, 0x2040, 0x2041, 0x2042, 0x2043, 0x2048, 0x2049, 0x204a, 0x204b, 0x2800,
74 0x2801, 0x2802, 0x2803, 0x2808, 0x2809, 0x280a, 0x280b, 0x2840, 0x2841, 0x2842, 0x2843,
75 0x2848, 0x2849, 0x284a, 0x284b, 0x3000, 0x3001, 0x3002, 0x3003, 0x3008, 0x3009, 0x300a,
76 0x300b, 0x3040, 0x3041, 0x3042, 0x3043, 0x3048, 0x3049, 0x304a, 0x304b, 0x3800, 0x3801,
77 0x3802, 0x3803, 0x3808, 0x3809, 0x380a, 0x380b, 0x3840, 0x3841, 0x3842, 0x3843, 0x3848,
78 0x3849, 0x384a, 0x384b, 0x0000, 0x0001, 0x0002, 0x0003, 0x0008, 0x0009, 0x000a, 0x000b,
79 0x0040, 0x0041, 0x0042, 0x0043, 0x0048, 0x0049, 0x004a, 0x004b, 0x0800, 0x0801, 0x0802,
80 0x0803, 0x0808, 0x0809, 0x080a, 0x080b, 0x0840, 0x0841, 0x0842, 0x0843, 0x0848, 0x0849,
81 0x084a, 0x084b, 0x1000, 0x1001, 0x1002, 0x1003, 0x1008, 0x1009, 0x100a, 0x100b, 0x1040,
82 0x1041, 0x1042, 0x1043, 0x1048, 0x1049, 0x104a, 0x104b, 0x1800, 0x1801, 0x1802, 0x1803,
83 0x1808, 0x1809, 0x180a, 0x180b, 0x1840, 0x1841, 0x1842, 0x1843, 0x1848, 0x1849, 0x184a,
84 0x184b, 0x2000, 0x2001, 0x2002, 0x2003, 0x2008, 0x2009, 0x200a, 0x200b, 0x2040, 0x2041,
85 0x2042, 0x2043, 0x2048, 0x2049, 0x204a, 0x204b, 0x2800, 0x2801, 0x2802, 0x2803, 0x2808,
86 0x2809, 0x280a, 0x280b, 0x2840, 0x2841, 0x2842, 0x2843, 0x2848, 0x2849, 0x284a, 0x284b,
87 0x3000, 0x3001, 0x3002, 0x3003, 0x3008, 0x3009, 0x300a, 0x300b, 0x3040, 0x3041, 0x3042,
88 0x3043, 0x3048, 0x3049, 0x304a, 0x304b, 0x3800, 0x3801, 0x3802, 0x3803, 0x3808, 0x3809,
89 0x380a, 0x380b, 0x3840, 0x3841, 0x3842, 0x3843, 0x3848, 0x3849, 0x384a, 0x384b,
90 };
91 static constexpr u32 ylut[] = {
92 0x0000, 0x0004, 0x0010, 0x0014, 0x0020, 0x0024, 0x0030, 0x0034, 0x0080, 0x0084, 0x0090,
93 0x0094, 0x00a0, 0x00a4, 0x00b0, 0x00b4, 0x0100, 0x0104, 0x0110, 0x0114, 0x0120, 0x0124,
94 0x0130, 0x0134, 0x0180, 0x0184, 0x0190, 0x0194, 0x01a0, 0x01a4, 0x01b0, 0x01b4, 0x0200,
95 0x0204, 0x0210, 0x0214, 0x0220, 0x0224, 0x0230, 0x0234, 0x0280, 0x0284, 0x0290, 0x0294,
96 0x02a0, 0x02a4, 0x02b0, 0x02b4, 0x0300, 0x0304, 0x0310, 0x0314, 0x0320, 0x0324, 0x0330,
97 0x0334, 0x0380, 0x0384, 0x0390, 0x0394, 0x03a0, 0x03a4, 0x03b0, 0x03b4, 0x0400, 0x0404,
98 0x0410, 0x0414, 0x0420, 0x0424, 0x0430, 0x0434, 0x0480, 0x0484, 0x0490, 0x0494, 0x04a0,
99 0x04a4, 0x04b0, 0x04b4, 0x0500, 0x0504, 0x0510, 0x0514, 0x0520, 0x0524, 0x0530, 0x0534,
100 0x0580, 0x0584, 0x0590, 0x0594, 0x05a0, 0x05a4, 0x05b0, 0x05b4, 0x0600, 0x0604, 0x0610,
101 0x0614, 0x0620, 0x0624, 0x0630, 0x0634, 0x0680, 0x0684, 0x0690, 0x0694, 0x06a0, 0x06a4,
102 0x06b0, 0x06b4, 0x0700, 0x0704, 0x0710, 0x0714, 0x0720, 0x0724, 0x0730, 0x0734, 0x0780,
103 0x0784, 0x0790, 0x0794, 0x07a0, 0x07a4, 0x07b0, 0x07b4, 0x0000, 0x0004, 0x0010, 0x0014,
104 0x0020, 0x0024, 0x0030, 0x0034, 0x0080, 0x0084, 0x0090, 0x0094, 0x00a0, 0x00a4, 0x00b0,
105 0x00b4, 0x0100, 0x0104, 0x0110, 0x0114, 0x0120, 0x0124, 0x0130, 0x0134, 0x0180, 0x0184,
106 0x0190, 0x0194, 0x01a0, 0x01a4, 0x01b0, 0x01b4, 0x0200, 0x0204, 0x0210, 0x0214, 0x0220,
107 0x0224, 0x0230, 0x0234, 0x0280, 0x0284, 0x0290, 0x0294, 0x02a0, 0x02a4, 0x02b0, 0x02b4,
108 0x0300, 0x0304, 0x0310, 0x0314, 0x0320, 0x0324, 0x0330, 0x0334, 0x0380, 0x0384, 0x0390,
109 0x0394, 0x03a0, 0x03a4, 0x03b0, 0x03b4, 0x0400, 0x0404, 0x0410, 0x0414, 0x0420, 0x0424,
110 0x0430, 0x0434, 0x0480, 0x0484, 0x0490, 0x0494, 0x04a0, 0x04a4, 0x04b0, 0x04b4, 0x0500,
111 0x0504, 0x0510, 0x0514, 0x0520, 0x0524, 0x0530, 0x0534, 0x0580, 0x0584, 0x0590, 0x0594,
112 0x05a0, 0x05a4, 0x05b0, 0x05b4, 0x0600, 0x0604, 0x0610, 0x0614, 0x0620, 0x0624, 0x0630,
113 0x0634, 0x0680, 0x0684, 0x0690, 0x0694, 0x06a0, 0x06a4, 0x06b0, 0x06b4, 0x0700, 0x0704,
114 0x0710, 0x0714, 0x0720, 0x0724, 0x0730, 0x0734, 0x0780, 0x0784, 0x0790, 0x0794, 0x07a0,
115 0x07a4, 0x07b0, 0x07b4, 0x0000, 0x0004, 0x0010, 0x0014, 0x0020, 0x0024, 0x0030, 0x0034,
116 0x0080, 0x0084, 0x0090, 0x0094, 0x00a0, 0x00a4, 0x00b0, 0x00b4, 0x0100, 0x0104, 0x0110,
117 0x0114, 0x0120, 0x0124, 0x0130, 0x0134, 0x0180, 0x0184, 0x0190, 0x0194, 0x01a0, 0x01a4,
118 0x01b0, 0x01b4, 0x0200, 0x0204, 0x0210, 0x0214, 0x0220, 0x0224, 0x0230, 0x0234, 0x0280,
119 0x0284, 0x0290, 0x0294, 0x02a0, 0x02a4, 0x02b0, 0x02b4, 0x0300, 0x0304, 0x0310, 0x0314,
120 0x0320, 0x0324, 0x0330, 0x0334, 0x0380, 0x0384, 0x0390, 0x0394, 0x03a0, 0x03a4, 0x03b0,
121 0x03b4, 0x0400, 0x0404, 0x0410, 0x0414, 0x0420, 0x0424, 0x0430, 0x0434, 0x0480, 0x0484,
122 0x0490, 0x0494, 0x04a0, 0x04a4, 0x04b0, 0x04b4, 0x0500, 0x0504, 0x0510, 0x0514, 0x0520,
123 0x0524, 0x0530, 0x0534, 0x0580, 0x0584, 0x0590, 0x0594, 0x05a0, 0x05a4, 0x05b0, 0x05b4,
124 0x0600, 0x0604, 0x0610, 0x0614, 0x0620, 0x0624, 0x0630, 0x0634, 0x0680, 0x0684, 0x0690,
125 0x0694, 0x06a0, 0x06a4, 0x06b0, 0x06b4, 0x0700, 0x0704, 0x0710, 0x0714, 0x0720, 0x0724,
126 0x0730, 0x0734, 0x0780, 0x0784, 0x0790, 0x0794, 0x07a0, 0x07a4, 0x07b0, 0x07b4,
127 };
128 return xlut[x % 128] + ylut[y % 128];
129}
130
131static inline u32 GetMortonOffset128(u32 x, u32 y, u32 bytes_per_pixel) {
132 // Calculates the offset of the position of the pixel in Morton order
133 // Framebuffer images are split into 128x128 tiles.
134
135 const unsigned int block_height = 128;
136 const unsigned int coarse_x = x & ~127;
137
138 u32 i = MortonInterleave128(x, y);
139
140 const unsigned int offset = coarse_x * block_height;
141
142 return (i + offset) * bytes_per_pixel;
143}
144
145static inline void MortonCopyPixels128(u32 width, u32 height, u32 bytes_per_pixel,
146 u32 gl_bytes_per_pixel, u8* morton_data, u8* gl_data,
147 bool morton_to_gl) {
148 u8* data_ptrs[2];
149 for (unsigned y = 0; y < height; ++y) {
150 for (unsigned x = 0; x < width; ++x) {
151 const u32 coarse_y = y & ~127;
152 u32 morton_offset =
153 GetMortonOffset128(x, y, bytes_per_pixel) + coarse_y * width * bytes_per_pixel;
154 u32 gl_pixel_index = (x + (height - 1 - y) * width) * gl_bytes_per_pixel;
155
156 data_ptrs[morton_to_gl] = morton_data + morton_offset;
157 data_ptrs[!morton_to_gl] = &gl_data[gl_pixel_index];
158
159 memcpy(data_ptrs[0], data_ptrs[1], bytes_per_pixel);
160 }
161 }
162}
163
52} // namespace VideoCore 164} // namespace VideoCore
diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h
index 1fd90b9d0..37da62436 100644
--- a/src/video_core/video_core.h
+++ b/src/video_core/video_core.h
@@ -15,6 +15,8 @@ class RendererBase;
15 15
16namespace VideoCore { 16namespace VideoCore {
17 17
18enum class Renderer { Software, OpenGL };
19
18extern std::unique_ptr<RendererBase> g_renderer; ///< Renderer plugin 20extern std::unique_ptr<RendererBase> g_renderer; ///< Renderer plugin
19extern EmuWindow* g_emu_window; ///< Emu window 21extern EmuWindow* g_emu_window; ///< Emu window
20 22