diff options
| author | 2018-03-23 23:30:48 -0400 | |
|---|---|---|
| committer | 2018-03-23 23:30:48 -0400 | |
| commit | a10baacf9e5ab48af7fb0ccbdc75371c9287d3ba (patch) | |
| tree | 9ed56f99b9d2564f9250d3754e429eb0c8b43323 /src | |
| parent | Merge pull request #255 from Subv/sd_card (diff) | |
| parent | gl_rasterizer: Fake render in green, because it's cooler. (diff) | |
| download | yuzu-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.cpp | 11 | ||||
| -rw-r--r-- | src/core/hle/service/nvflinger/buffer_queue.h | 2 | ||||
| -rw-r--r-- | src/core/memory.cpp | 40 | ||||
| -rw-r--r-- | src/core/memory.h | 20 | ||||
| -rw-r--r-- | src/video_core/engines/maxwell_3d.h | 110 | ||||
| -rw-r--r-- | src/video_core/gpu.h | 36 | ||||
| -rw-r--r-- | src/video_core/rasterizer_interface.h | 10 | ||||
| -rw-r--r-- | src/video_core/renderer_base.cpp | 7 | ||||
| -rw-r--r-- | src/video_core/renderer_base.h | 40 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 140 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 24 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 67 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.h | 34 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 219 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.h | 13 | ||||
| -rw-r--r-- | src/video_core/utils.h | 112 | ||||
| -rw-r--r-- | src/video_core/video_core.h | 2 |
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 | ||
| 294 | void 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 | |||
| 291 | u8 Read8(const VAddr addr) { | 331 | u8 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 | */ |
| 243 | u8* GetPhysicalPointer(PAddr address); | 246 | u8* GetPhysicalPointer(PAddr address); |
| 244 | 247 | ||
| 248 | enum 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 | */ | ||
| 261 | void 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 | ||
| 13 | namespace Tegra { | 14 | namespace Tegra { |
| 14 | 15 | ||
| 16 | /** | ||
| 17 | * Struct describing framebuffer configuration | ||
| 18 | */ | ||
| 19 | struct 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 | |||
| 15 | namespace Engines { | 47 | namespace Engines { |
| 16 | class Fermi2D; | 48 | class Fermi2D; |
| 17 | class Maxwell3D; | 49 | class 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 | |||
| 39 | private: | 75 | private: |
| 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 | ||
| 9 | struct ScreenInfo; | 10 | struct 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 | ||
| 10 | void RendererBase::RefreshRasterizerSetting() {} | 11 | void 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 | ||
| 12 | class EmuWindow; | 14 | class 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 | ||
| 79 | protected: | 55 | protected: |
| 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 | ||
| 83 | private: | 60 | private: |
| 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 | ||
| 56 | RasterizerOpenGL::RasterizerOpenGL() { | 56 | RasterizerOpenGL::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 | ||
| 139 | RasterizerOpenGL::~RasterizerOpenGL() { | 133 | RasterizerOpenGL::~RasterizerOpenGL() { |
| @@ -167,12 +161,12 @@ void RasterizerOpenGL::SetupVertexShader(VSUniformData* ub_ptr, GLintptr buffer_ | |||
| 167 | 161 | ||
| 168 | void RasterizerOpenGL::SetupFragmentShader(FSUniformData* ub_ptr, GLintptr buffer_offset) { | 162 | void 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 | ||
| 173 | bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) { | 167 | bool 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 | ||
| 197 | void RasterizerOpenGL::FlushRegion(PAddr addr, u32 size) { | 191 | void 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 | ||
| 202 | void RasterizerOpenGL::InvalidateRegion(PAddr addr, u32 size) { | 196 | void 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 | ||
| 207 | void RasterizerOpenGL::FlushAndInvalidateRegion(PAddr addr, u32 size) { | 201 | void 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 | ||
| 213 | bool RasterizerOpenGL::AccelerateDisplayTransfer(const void* config) { | 207 | bool 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 | ||
| 219 | bool RasterizerOpenGL::AccelerateTextureCopy(const void* config) { | 213 | bool RasterizerOpenGL::AccelerateTextureCopy(const void* config) { |
| 220 | UNIMPLEMENTED(); | 214 | ASSERT_MSG(false, "Unimplemented"); |
| 221 | return true; | 215 | return true; |
| 222 | } | 216 | } |
| 223 | 217 | ||
| 224 | bool RasterizerOpenGL::AccelerateFill(const void* config) { | 218 | bool RasterizerOpenGL::AccelerateFill(const void* config) { |
| 225 | UNIMPLEMENTED(); | 219 | ASSERT_MSG(false, "Unimplemented"); |
| 226 | return true; | 220 | return true; |
| 227 | } | 221 | } |
| 228 | 222 | ||
| 229 | bool RasterizerOpenGL::AccelerateDisplay(const void* config, PAddr framebuffer_addr, | 223 | bool 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 | ||
| 235 | void RasterizerOpenGL::SetShader() { | 262 | void 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 | |||
| 270 | in vec2 vert_position; | ||
| 271 | in vec2 vert_tex_coord; | ||
| 272 | out vec2 frag_tex_coord; | ||
| 273 | |||
| 274 | void 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 | |||
| 286 | in vec2 frag_tex_coord; | ||
| 287 | out vec4 color; | ||
| 288 | |||
| 289 | uniform sampler2D color_texture; | ||
| 290 | |||
| 291 | void 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 | ||
| 239 | void RasterizerOpenGL::SyncClipEnabled() { | 319 | void RasterizerOpenGL::SyncClipEnabled() { |
| 240 | UNIMPLEMENTED(); | 320 | ASSERT_MSG(false, "Unimplemented"); |
| 241 | } | 321 | } |
| 242 | 322 | ||
| 243 | void RasterizerOpenGL::SyncClipCoef() { | 323 | void RasterizerOpenGL::SyncClipCoef() { |
| 244 | UNIMPLEMENTED(); | 324 | ASSERT_MSG(false, "Unimplemented"); |
| 245 | } | 325 | } |
| 246 | 326 | ||
| 247 | void RasterizerOpenGL::SyncCullMode() { | 327 | void RasterizerOpenGL::SyncCullMode() { |
| 248 | UNIMPLEMENTED(); | 328 | ASSERT_MSG(false, "Unimplemented"); |
| 249 | } | 329 | } |
| 250 | 330 | ||
| 251 | void RasterizerOpenGL::SyncDepthScale() { | 331 | void RasterizerOpenGL::SyncDepthScale() { |
| 252 | UNIMPLEMENTED(); | 332 | ASSERT_MSG(false, "Unimplemented"); |
| 253 | } | 333 | } |
| 254 | 334 | ||
| 255 | void RasterizerOpenGL::SyncDepthOffset() { | 335 | void RasterizerOpenGL::SyncDepthOffset() { |
| 256 | UNIMPLEMENTED(); | 336 | ASSERT_MSG(false, "Unimplemented"); |
| 257 | } | 337 | } |
| 258 | 338 | ||
| 259 | void RasterizerOpenGL::SyncBlendEnabled() { | 339 | void RasterizerOpenGL::SyncBlendEnabled() { |
| 260 | UNIMPLEMENTED(); | 340 | ASSERT_MSG(false, "Unimplemented"); |
| 261 | } | 341 | } |
| 262 | 342 | ||
| 263 | void RasterizerOpenGL::SyncBlendFuncs() { | 343 | void RasterizerOpenGL::SyncBlendFuncs() { |
| 264 | UNIMPLEMENTED(); | 344 | ASSERT_MSG(false, "Unimplemented"); |
| 265 | } | 345 | } |
| 266 | 346 | ||
| 267 | void RasterizerOpenGL::SyncBlendColor() { | 347 | void 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 | ||
| 109 | template <bool morton_to_gl, PixelFormat format> | 110 | template <bool morton_to_gl, PixelFormat format> |
| 110 | static void MortonCopy(u32 stride, u32 height, u8* gl_buffer, PAddr base, PAddr start, PAddr end) { | 111 | static 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 | ||
| 165 | static constexpr std::array<void (*)(u32, u32, u8*, PAddr, PAddr, PAddr), 18> morton_to_gl_fns = { | 166 | static 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 | ||
| 186 | static constexpr std::array<void (*)(u32, u32, u8*, PAddr, PAddr, PAddr), 18> gl_to_morton_fns = { | 187 | static 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 | ||
| 291 | static bool FillSurface(const Surface& surface, const u8* fill_data, | 292 | static 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 | ||
| 529 | MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192)); | 530 | MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192)); |
| 530 | void CachedSurface::LoadGLBuffer(PAddr load_start, PAddr load_end) { | 531 | void 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 | ||
| 568 | MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64)); | 559 | MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64)); |
| 569 | void CachedSurface::FlushGLBuffer(PAddr flush_start, PAddr flush_end) { | 560 | void 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 | ||
| 1104 | Surface RasterizerCacheOpenGL::GetTextureSurface(const void* config) { | 1095 | Surface 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 | ||
| 1115 | Surface RasterizerCacheOpenGL::GetFillSurface(const void* config) { | 1106 | Surface 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 | ||
| 1170 | void RasterizerCacheOpenGL::ValidateSurface(const Surface& surface, PAddr addr, u64 size) { | 1161 | void 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 | ||
| 1230 | void RasterizerCacheOpenGL::FlushRegion(PAddr addr, u64 size, Surface flush_surface) { | 1221 | void 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 | ||
| 1262 | void RasterizerCacheOpenGL::FlushAll() { | 1253 | void RasterizerCacheOpenGL::FlushAll() { |
| 1263 | FlushRegion(0, 0xFFFFFFFF); | 1254 | FlushRegion(0, Kernel::VMManager::MAX_ADDRESS); |
| 1264 | } | 1255 | } |
| 1265 | 1256 | ||
| 1266 | void RasterizerCacheOpenGL::InvalidateRegion(PAddr addr, u64 size, const Surface& region_owner) { | 1257 | void 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 | ||
| 1359 | void RasterizerCacheOpenGL::UpdatePagesCachedCount(PAddr addr, u64 size, int delta) { | 1350 | void 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 | ||
| 27 | struct CachedSurface; | 28 | struct CachedSurface; |
| 28 | using Surface = std::shared_ptr<CachedSurface>; | 29 | using Surface = std::shared_ptr<CachedSurface>; |
| 29 | using SurfaceSet = std::set<Surface>; | 30 | using SurfaceSet = std::set<Surface>; |
| 30 | 31 | ||
| 31 | using SurfaceRegions = boost::icl::interval_set<PAddr>; | 32 | using SurfaceRegions = boost::icl::interval_set<VAddr>; |
| 32 | using SurfaceMap = boost::icl::interval_map<PAddr, Surface>; | 33 | using SurfaceMap = boost::icl::interval_map<VAddr, Surface>; |
| 33 | using SurfaceCache = boost::icl::interval_map<PAddr, SurfaceSet>; | 34 | using SurfaceCache = boost::icl::interval_map<VAddr, SurfaceSet>; |
| 34 | 35 | ||
| 35 | using SurfaceInterval = SurfaceCache::interval_type; | 36 | using SurfaceInterval = SurfaceCache::interval_type; |
| 36 | static_assert(std::is_same<SurfaceRegions::interval_type, SurfaceCache::interval_type>() && | 37 | static_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 | ||
| 25 | static const char vertex_shader[] = R"( | 26 | static const char vertex_shader[] = R"( |
| @@ -98,22 +99,22 @@ RendererOpenGL::RendererOpenGL() = default; | |||
| 98 | RendererOpenGL::~RendererOpenGL() = default; | 99 | RendererOpenGL::~RendererOpenGL() = default; |
| 99 | 100 | ||
| 100 | /// Swap buffers (render frame) | 101 | /// Swap buffers (render frame) |
| 101 | void RendererOpenGL::SwapBuffers(boost::optional<const FramebufferInfo&> framebuffer_info) { | 102 | void 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 | ||
| 134 | static 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 | |||
| 213 | static 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 | |||
| 227 | static 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 | */ |
| 248 | void RendererOpenGL::LoadFBToScreenInfo(const FramebufferInfo& framebuffer_info, | 138 | void 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 | ||
| 374 | void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, | 270 | void 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, | |||
| 404 | void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w, | 300 | void 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 | ||
| 54 | private: | 54 | private: |
| 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 | ||
| 52 | static 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 | |||
| 131 | static 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 | |||
| 145 | static 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 | ||
| 16 | namespace VideoCore { | 16 | namespace VideoCore { |
| 17 | 17 | ||
| 18 | enum class Renderer { Software, OpenGL }; | ||
| 19 | |||
| 18 | extern std::unique_ptr<RendererBase> g_renderer; ///< Renderer plugin | 20 | extern std::unique_ptr<RendererBase> g_renderer; ///< Renderer plugin |
| 19 | extern EmuWindow* g_emu_window; ///< Emu window | 21 | extern EmuWindow* g_emu_window; ///< Emu window |
| 20 | 22 | ||