summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt37
-rw-r--r--src/common/zstd_compression.cpp2
-rw-r--r--src/core/frontend/emu_window.cpp2
-rw-r--r--src/core/frontend/emu_window.h2
-rw-r--r--src/core/hle/service/audio/audctl.cpp4
-rw-r--r--src/core/memory.h9
-rw-r--r--src/core/telemetry_session.cpp17
-rw-r--r--src/core/telemetry_session.h1
-rw-r--r--src/video_core/CMakeLists.txt2
-rw-r--r--src/video_core/engines/engine_upload.cpp48
-rw-r--r--src/video_core/engines/engine_upload.h75
-rw-r--r--src/video_core/engines/fermi_2d.h6
-rw-r--r--src/video_core/engines/kepler_compute.cpp37
-rw-r--r--src/video_core/engines/kepler_compute.h175
-rw-r--r--src/video_core/engines/kepler_memory.cpp45
-rw-r--r--src/video_core/engines/kepler_memory.h66
-rw-r--r--src/video_core/engines/maxwell_3d.cpp16
-rw-r--r--src/video_core/engines/maxwell_3d.h25
-rw-r--r--src/video_core/engines/maxwell_dma.cpp83
-rw-r--r--src/video_core/engines/maxwell_dma.h43
-rw-r--r--src/video_core/gpu.cpp4
-rw-r--r--src/video_core/gpu_thread.cpp2
-rw-r--r--src/video_core/memory_manager.cpp6
-rw-r--r--src/video_core/memory_manager.h31
-rw-r--r--src/video_core/rasterizer_cache.h7
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.h6
-rw-r--r--src/video_core/renderer_opengl/gl_global_cache.h7
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp4
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp26
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h28
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.h7
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp11
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.cpp5
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.h7
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_decompiler.cpp1
-rw-r--r--src/video_core/shader/decode/texture.cpp2
-rw-r--r--src/video_core/textures/astc.cpp12
-rw-r--r--src/yuzu/compatdb.cpp6
-rw-r--r--src/yuzu/configuration/configure_dialog.cpp4
-rw-r--r--src/yuzu/configuration/configure_graphics.cpp8
-rw-r--r--src/yuzu/hotkeys.h2
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp6
-rw-r--r--src/yuzu_cmd/yuzu.cpp1
44 files changed, 631 insertions, 259 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 9aea4af87..04018233f 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -21,15 +21,29 @@ if (MSVC)
21 # Ensure that projects build with Unicode support. 21 # Ensure that projects build with Unicode support.
22 add_definitions(-DUNICODE -D_UNICODE) 22 add_definitions(-DUNICODE -D_UNICODE)
23 23
24 # /W3 - Level 3 warnings 24 # /W3 - Level 3 warnings
25 # /MP - Multi-threaded compilation 25 # /MP - Multi-threaded compilation
26 # /Zi - Output debugging information 26 # /Zi - Output debugging information
27 # /Zo - enhanced debug info for optimized builds 27 # /Zo - Enhanced debug info for optimized builds
28 # /permissive- - enables stricter C++ standards conformance checks 28 # /permissive- - Enables stricter C++ standards conformance checks
29 # /EHsc - C++-only exception handling semantics 29 # /EHsc - C++-only exception handling semantics
30 # /Zc:throwingNew - let codegen assume `operator new` will never return null 30 # /volatile:iso - Use strict standards-compliant volatile semantics.
31 # /Zc:inline - let codegen omit inline functions in object files 31 # /Zc:externConstexpr - Allow extern constexpr variables to have external linkage, like the standard mandates
32 add_compile_options(/W3 /MP /Zi /Zo /permissive- /EHsc /std:c++latest /Zc:throwingNew,inline) 32 # /Zc:inline - Let codegen omit inline functions in object files
33 # /Zc:throwingNew - Let codegen assume `operator new` (without std::nothrow) will never return null
34 add_compile_options(
35 /W3
36 /MP
37 /Zi
38 /Zo
39 /permissive-
40 /EHsc
41 /std:c++latest
42 /volatile:iso
43 /Zc:externConstexpr
44 /Zc:inline
45 /Zc:throwingNew
46 )
33 47
34 # /GS- - No stack buffer overflow checks 48 # /GS- - No stack buffer overflow checks
35 add_compile_options("$<$<CONFIG:Release>:/GS->") 49 add_compile_options("$<$<CONFIG:Release>:/GS->")
@@ -37,7 +51,10 @@ if (MSVC)
37 set(CMAKE_EXE_LINKER_FLAGS_DEBUG "/DEBUG /MANIFEST:NO" CACHE STRING "" FORCE) 51 set(CMAKE_EXE_LINKER_FLAGS_DEBUG "/DEBUG /MANIFEST:NO" CACHE STRING "" FORCE)
38 set(CMAKE_EXE_LINKER_FLAGS_RELEASE "/DEBUG /MANIFEST:NO /INCREMENTAL:NO /OPT:REF,ICF" CACHE STRING "" FORCE) 52 set(CMAKE_EXE_LINKER_FLAGS_RELEASE "/DEBUG /MANIFEST:NO /INCREMENTAL:NO /OPT:REF,ICF" CACHE STRING "" FORCE)
39else() 53else()
40 add_compile_options("-Wno-attributes") 54 add_compile_options(
55 -Wall
56 -Wno-attributes
57 )
41 58
42 if (APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL Clang) 59 if (APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL Clang)
43 add_compile_options("-stdlib=libc++") 60 add_compile_options("-stdlib=libc++")
diff --git a/src/common/zstd_compression.cpp b/src/common/zstd_compression.cpp
index 60a35c67c..978526492 100644
--- a/src/common/zstd_compression.cpp
+++ b/src/common/zstd_compression.cpp
@@ -2,8 +2,6 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once
6
7#include <algorithm> 5#include <algorithm>
8#include <zstd.h> 6#include <zstd.h>
9 7
diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp
index 1320bbe77..eda466a5d 100644
--- a/src/core/frontend/emu_window.cpp
+++ b/src/core/frontend/emu_window.cpp
@@ -10,6 +10,8 @@
10 10
11namespace Core::Frontend { 11namespace Core::Frontend {
12 12
13GraphicsContext::~GraphicsContext() = default;
14
13class EmuWindow::TouchState : public Input::Factory<Input::TouchDevice>, 15class EmuWindow::TouchState : public Input::Factory<Input::TouchDevice>,
14 public std::enable_shared_from_this<TouchState> { 16 public std::enable_shared_from_this<TouchState> {
15public: 17public:
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h
index 70a522556..e2c290dc1 100644
--- a/src/core/frontend/emu_window.h
+++ b/src/core/frontend/emu_window.h
@@ -19,6 +19,8 @@ namespace Core::Frontend {
19 */ 19 */
20class GraphicsContext { 20class GraphicsContext {
21public: 21public:
22 virtual ~GraphicsContext();
23
22 /// Makes the graphics context current for the caller thread 24 /// Makes the graphics context current for the caller thread
23 virtual void MakeCurrent() = 0; 25 virtual void MakeCurrent() = 0;
24 26
diff --git a/src/core/hle/service/audio/audctl.cpp b/src/core/hle/service/audio/audctl.cpp
index f43e512e9..6a01d4d29 100644
--- a/src/core/hle/service/audio/audctl.cpp
+++ b/src/core/hle/service/audio/audctl.cpp
@@ -50,7 +50,7 @@ void AudCtl::GetTargetVolumeMin(Kernel::HLERequestContext& ctx) {
50 LOG_DEBUG(Audio, "called."); 50 LOG_DEBUG(Audio, "called.");
51 51
52 // This service function is currently hardcoded on the 52 // This service function is currently hardcoded on the
53 // actual console to this value (as of 6.0.0). 53 // actual console to this value (as of 8.0.0).
54 constexpr s32 target_min_volume = 0; 54 constexpr s32 target_min_volume = 0;
55 55
56 IPC::ResponseBuilder rb{ctx, 3}; 56 IPC::ResponseBuilder rb{ctx, 3};
@@ -62,7 +62,7 @@ void AudCtl::GetTargetVolumeMax(Kernel::HLERequestContext& ctx) {
62 LOG_DEBUG(Audio, "called."); 62 LOG_DEBUG(Audio, "called.");
63 63
64 // This service function is currently hardcoded on the 64 // This service function is currently hardcoded on the
65 // actual console to this value (as of 6.0.0). 65 // actual console to this value (as of 8.0.0).
66 constexpr s32 target_max_volume = 15; 66 constexpr s32 target_max_volume = 15;
67 67
68 IPC::ResponseBuilder rb{ctx, 3}; 68 IPC::ResponseBuilder rb{ctx, 3};
diff --git a/src/core/memory.h b/src/core/memory.h
index b9fa18b1d..04e2c5f1d 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -72,15 +72,6 @@ u8* GetPointer(VAddr vaddr);
72 72
73std::string ReadCString(VAddr vaddr, std::size_t max_length); 73std::string ReadCString(VAddr vaddr, std::size_t max_length);
74 74
75enum class FlushMode {
76 /// Write back modified surfaces to RAM
77 Flush,
78 /// Remove region from the cache
79 Invalidate,
80 /// Write back modified surfaces to RAM, and also remove them from the cache
81 FlushAndInvalidate,
82};
83
84/** 75/**
85 * Mark each page touching the region as cached. 76 * Mark each page touching the region as cached.
86 */ 77 */
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index e1db06811..4b17bada5 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -102,12 +102,6 @@ bool VerifyLogin(const std::string& username, const std::string& token) {
102} 102}
103 103
104TelemetrySession::TelemetrySession() { 104TelemetrySession::TelemetrySession() {
105#ifdef ENABLE_WEB_SERVICE
106 backend = std::make_unique<WebService::TelemetryJson>(
107 Settings::values.web_api_url, Settings::values.yuzu_username, Settings::values.yuzu_token);
108#else
109 backend = std::make_unique<Telemetry::NullVisitor>();
110#endif
111 // Log one-time top-level information 105 // Log one-time top-level information
112 AddField(Telemetry::FieldType::None, "TelemetryId", GetTelemetryId()); 106 AddField(Telemetry::FieldType::None, "TelemetryId", GetTelemetryId());
113 107
@@ -175,9 +169,14 @@ TelemetrySession::~TelemetrySession() {
175 .count()}; 169 .count()};
176 AddField(Telemetry::FieldType::Session, "Shutdown_Time", shutdown_time); 170 AddField(Telemetry::FieldType::Session, "Shutdown_Time", shutdown_time);
177 171
172#ifdef ENABLE_WEB_SERVICE
173 auto backend = std::make_unique<WebService::TelemetryJson>(
174 Settings::values.web_api_url, Settings::values.yuzu_username, Settings::values.yuzu_token);
175#else
176 auto backend = std::make_unique<Telemetry::NullVisitor>();
177#endif
178
178 // Complete the session, submitting to web service if necessary 179 // Complete the session, submitting to web service if necessary
179 // This is just a placeholder to wrap up the session once the core completes and this is
180 // destroyed. This will be moved elsewhere once we are actually doing real I/O with the service.
181 field_collection.Accept(*backend); 180 field_collection.Accept(*backend);
182 if (Settings::values.enable_telemetry) 181 if (Settings::values.enable_telemetry)
183 backend->Complete(); 182 backend->Complete();
@@ -186,6 +185,8 @@ TelemetrySession::~TelemetrySession() {
186 185
187bool TelemetrySession::SubmitTestcase() { 186bool TelemetrySession::SubmitTestcase() {
188#ifdef ENABLE_WEB_SERVICE 187#ifdef ENABLE_WEB_SERVICE
188 auto backend = std::make_unique<WebService::TelemetryJson>(
189 Settings::values.web_api_url, Settings::values.yuzu_username, Settings::values.yuzu_token);
189 field_collection.Accept(*backend); 190 field_collection.Accept(*backend);
190 return backend->SubmitTestcase(); 191 return backend->SubmitTestcase();
191#else 192#else
diff --git a/src/core/telemetry_session.h b/src/core/telemetry_session.h
index 023612b79..cae5a45a0 100644
--- a/src/core/telemetry_session.h
+++ b/src/core/telemetry_session.h
@@ -39,7 +39,6 @@ public:
39 39
40private: 40private:
41 Telemetry::FieldCollection field_collection; ///< Tracks all added fields for the session 41 Telemetry::FieldCollection field_collection; ///< Tracks all added fields for the session
42 std::unique_ptr<Telemetry::VisitorInterface> backend; ///< Backend interface that logs fields
43}; 42};
44 43
45/** 44/**
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 6821f275d..1e010e4da 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -3,6 +3,8 @@ add_library(video_core STATIC
3 dma_pusher.h 3 dma_pusher.h
4 debug_utils/debug_utils.cpp 4 debug_utils/debug_utils.cpp
5 debug_utils/debug_utils.h 5 debug_utils/debug_utils.h
6 engines/engine_upload.cpp
7 engines/engine_upload.h
6 engines/fermi_2d.cpp 8 engines/fermi_2d.cpp
7 engines/fermi_2d.h 9 engines/fermi_2d.h
8 engines/kepler_compute.cpp 10 engines/kepler_compute.cpp
diff --git a/src/video_core/engines/engine_upload.cpp b/src/video_core/engines/engine_upload.cpp
new file mode 100644
index 000000000..f8aa4ff55
--- /dev/null
+++ b/src/video_core/engines/engine_upload.cpp
@@ -0,0 +1,48 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/assert.h"
6#include "video_core/engines/engine_upload.h"
7#include "video_core/memory_manager.h"
8#include "video_core/textures/decoders.h"
9
10namespace Tegra::Engines::Upload {
11
12State::State(MemoryManager& memory_manager, Registers& regs)
13 : memory_manager(memory_manager), regs(regs) {}
14
15void State::ProcessExec(const bool is_linear) {
16 write_offset = 0;
17 copy_size = regs.line_length_in * regs.line_count;
18 inner_buffer.resize(copy_size);
19 this->is_linear = is_linear;
20}
21
22void State::ProcessData(const u32 data, const bool is_last_call) {
23 const u32 sub_copy_size = std::min(4U, copy_size - write_offset);
24 std::memcpy(&inner_buffer[write_offset], &data, sub_copy_size);
25 write_offset += sub_copy_size;
26 if (!is_last_call) {
27 return;
28 }
29 const GPUVAddr address{regs.dest.Address()};
30 if (is_linear) {
31 memory_manager.WriteBlock(address, inner_buffer.data(), copy_size);
32 } else {
33 UNIMPLEMENTED_IF(regs.dest.z != 0);
34 UNIMPLEMENTED_IF(regs.dest.depth != 1);
35 UNIMPLEMENTED_IF(regs.dest.BlockWidth() != 1);
36 UNIMPLEMENTED_IF(regs.dest.BlockDepth() != 1);
37 const std::size_t dst_size = Tegra::Texture::CalculateSize(
38 true, 1, regs.dest.width, regs.dest.height, 1, regs.dest.BlockHeight(), 1);
39 tmp_buffer.resize(dst_size);
40 memory_manager.ReadBlock(address, tmp_buffer.data(), dst_size);
41 Tegra::Texture::SwizzleKepler(regs.dest.width, regs.dest.height, regs.dest.x, regs.dest.y,
42 regs.dest.BlockHeight(), copy_size, inner_buffer.data(),
43 tmp_buffer.data());
44 memory_manager.WriteBlock(address, tmp_buffer.data(), dst_size);
45 }
46}
47
48} // namespace Tegra::Engines::Upload
diff --git a/src/video_core/engines/engine_upload.h b/src/video_core/engines/engine_upload.h
new file mode 100644
index 000000000..9c6e0d21c
--- /dev/null
+++ b/src/video_core/engines/engine_upload.h
@@ -0,0 +1,75 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <cstddef>
8#include <vector>
9#include "common/bit_field.h"
10#include "common/common_funcs.h"
11#include "common/common_types.h"
12
13namespace Tegra {
14class MemoryManager;
15}
16
17namespace Tegra::Engines::Upload {
18
19struct Registers {
20 u32 line_length_in;
21 u32 line_count;
22
23 struct {
24 u32 address_high;
25 u32 address_low;
26 u32 pitch;
27 union {
28 BitField<0, 4, u32> block_width;
29 BitField<4, 4, u32> block_height;
30 BitField<8, 4, u32> block_depth;
31 };
32 u32 width;
33 u32 height;
34 u32 depth;
35 u32 z;
36 u32 x;
37 u32 y;
38
39 GPUVAddr Address() const {
40 return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | address_low);
41 }
42
43 u32 BlockWidth() const {
44 return 1U << block_width.Value();
45 }
46
47 u32 BlockHeight() const {
48 return 1U << block_height.Value();
49 }
50
51 u32 BlockDepth() const {
52 return 1U << block_depth.Value();
53 }
54 } dest;
55};
56
57class State {
58public:
59 State(MemoryManager& memory_manager, Registers& regs);
60 ~State() = default;
61
62 void ProcessExec(const bool is_linear);
63 void ProcessData(const u32 data, const bool is_last_call);
64
65private:
66 u32 write_offset = 0;
67 u32 copy_size = 0;
68 std::vector<u8> inner_buffer;
69 std::vector<u8> tmp_buffer;
70 bool is_linear = false;
71 Registers& regs;
72 MemoryManager& memory_manager;
73};
74
75} // namespace Tegra::Engines::Upload
diff --git a/src/video_core/engines/fermi_2d.h b/src/video_core/engines/fermi_2d.h
index 2e51b7f13..45f59a4d9 100644
--- a/src/video_core/engines/fermi_2d.h
+++ b/src/video_core/engines/fermi_2d.h
@@ -21,6 +21,12 @@ class RasterizerInterface;
21 21
22namespace Tegra::Engines { 22namespace Tegra::Engines {
23 23
24/**
25 * This Engine is known as G80_2D. Documentation can be found in:
26 * https://github.com/envytools/envytools/blob/master/rnndb/graph/g80_2d.xml
27 * https://cgit.freedesktop.org/mesa/mesa/tree/src/gallium/drivers/nouveau/nv50/nv50_2d.xml.h
28 */
29
24#define FERMI2D_REG_INDEX(field_name) \ 30#define FERMI2D_REG_INDEX(field_name) \
25 (offsetof(Tegra::Engines::Fermi2D::Regs, field_name) / sizeof(u32)) 31 (offsetof(Tegra::Engines::Fermi2D::Regs, field_name) / sizeof(u32))
26 32
diff --git a/src/video_core/engines/kepler_compute.cpp b/src/video_core/engines/kepler_compute.cpp
index b1d950460..7404a8163 100644
--- a/src/video_core/engines/kepler_compute.cpp
+++ b/src/video_core/engines/kepler_compute.cpp
@@ -4,12 +4,21 @@
4 4
5#include "common/assert.h" 5#include "common/assert.h"
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/core.h"
7#include "video_core/engines/kepler_compute.h" 8#include "video_core/engines/kepler_compute.h"
9#include "video_core/engines/maxwell_3d.h"
8#include "video_core/memory_manager.h" 10#include "video_core/memory_manager.h"
11#include "video_core/rasterizer_interface.h"
12#include "video_core/renderer_base.h"
13#include "video_core/textures/decoders.h"
9 14
10namespace Tegra::Engines { 15namespace Tegra::Engines {
11 16
12KeplerCompute::KeplerCompute(MemoryManager& memory_manager) : memory_manager{memory_manager} {} 17KeplerCompute::KeplerCompute(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
18 MemoryManager& memory_manager)
19 : system{system}, rasterizer{rasterizer}, memory_manager{memory_manager}, upload_state{
20 memory_manager,
21 regs.upload} {}
13 22
14KeplerCompute::~KeplerCompute() = default; 23KeplerCompute::~KeplerCompute() = default;
15 24
@@ -20,14 +29,34 @@ void KeplerCompute::CallMethod(const GPU::MethodCall& method_call) {
20 regs.reg_array[method_call.method] = method_call.argument; 29 regs.reg_array[method_call.method] = method_call.argument;
21 30
22 switch (method_call.method) { 31 switch (method_call.method) {
32 case KEPLER_COMPUTE_REG_INDEX(exec_upload): {
33 upload_state.ProcessExec(regs.exec_upload.linear != 0);
34 break;
35 }
36 case KEPLER_COMPUTE_REG_INDEX(data_upload): {
37 const bool is_last_call = method_call.IsLastCall();
38 upload_state.ProcessData(method_call.argument, is_last_call);
39 if (is_last_call) {
40 system.GPU().Maxwell3D().dirty_flags.OnMemoryWrite();
41 }
42 break;
43 }
23 case KEPLER_COMPUTE_REG_INDEX(launch): 44 case KEPLER_COMPUTE_REG_INDEX(launch):
24 // Abort execution since compute shaders can be used to alter game memory (e.g. CUDA 45 ProcessLaunch();
25 // kernels)
26 UNREACHABLE_MSG("Compute shaders are not implemented");
27 break; 46 break;
28 default: 47 default:
29 break; 48 break;
30 } 49 }
31} 50}
32 51
52void KeplerCompute::ProcessLaunch() {
53
54 const GPUVAddr launch_desc_loc = regs.launch_desc_loc.Address();
55 memory_manager.ReadBlockUnsafe(launch_desc_loc, &launch_description,
56 LaunchParams::NUM_LAUNCH_PARAMETERS * sizeof(u32));
57
58 const GPUVAddr code_loc = regs.code_loc.Address() + launch_description.program_start;
59 LOG_WARNING(HW_GPU, "Compute Kernel Execute at Address 0x{:016x}, STUBBED", code_loc);
60}
61
33} // namespace Tegra::Engines 62} // namespace Tegra::Engines
diff --git a/src/video_core/engines/kepler_compute.h b/src/video_core/engines/kepler_compute.h
index fb6cdf432..5250b8d9b 100644
--- a/src/video_core/engines/kepler_compute.h
+++ b/src/video_core/engines/kepler_compute.h
@@ -6,22 +6,40 @@
6 6
7#include <array> 7#include <array>
8#include <cstddef> 8#include <cstddef>
9#include <vector>
10#include "common/bit_field.h"
9#include "common/common_funcs.h" 11#include "common/common_funcs.h"
10#include "common/common_types.h" 12#include "common/common_types.h"
13#include "video_core/engines/engine_upload.h"
11#include "video_core/gpu.h" 14#include "video_core/gpu.h"
12 15
16namespace Core {
17class System;
18}
19
13namespace Tegra { 20namespace Tegra {
14class MemoryManager; 21class MemoryManager;
15} 22}
16 23
24namespace VideoCore {
25class RasterizerInterface;
26}
27
17namespace Tegra::Engines { 28namespace Tegra::Engines {
18 29
30/**
31 * This Engine is known as GK104_Compute. Documentation can be found in:
32 * https://github.com/envytools/envytools/blob/master/rnndb/graph/gk104_compute.xml
33 * https://cgit.freedesktop.org/mesa/mesa/tree/src/gallium/drivers/nouveau/nvc0/nve4_compute.xml.h
34 */
35
19#define KEPLER_COMPUTE_REG_INDEX(field_name) \ 36#define KEPLER_COMPUTE_REG_INDEX(field_name) \
20 (offsetof(Tegra::Engines::KeplerCompute::Regs, field_name) / sizeof(u32)) 37 (offsetof(Tegra::Engines::KeplerCompute::Regs, field_name) / sizeof(u32))
21 38
22class KeplerCompute final { 39class KeplerCompute final {
23public: 40public:
24 explicit KeplerCompute(MemoryManager& memory_manager); 41 explicit KeplerCompute(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
42 MemoryManager& memory_manager);
25 ~KeplerCompute(); 43 ~KeplerCompute();
26 44
27 static constexpr std::size_t NumConstBuffers = 8; 45 static constexpr std::size_t NumConstBuffers = 8;
@@ -31,30 +49,181 @@ public:
31 49
32 union { 50 union {
33 struct { 51 struct {
34 INSERT_PADDING_WORDS(0xAF); 52 INSERT_PADDING_WORDS(0x60);
53
54 Upload::Registers upload;
55
56 struct {
57 union {
58 BitField<0, 1, u32> linear;
59 };
60 } exec_upload;
61
62 u32 data_upload;
63
64 INSERT_PADDING_WORDS(0x3F);
65
66 struct {
67 u32 address;
68 GPUVAddr Address() const {
69 return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address) << 8));
70 }
71 } launch_desc_loc;
72
73 INSERT_PADDING_WORDS(0x1);
35 74
36 u32 launch; 75 u32 launch;
37 76
38 INSERT_PADDING_WORDS(0xC48); 77 INSERT_PADDING_WORDS(0x4A7);
78
79 struct {
80 u32 address_high;
81 u32 address_low;
82 u32 limit;
83 GPUVAddr Address() const {
84 return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) |
85 address_low);
86 }
87 } tsc;
88
89 INSERT_PADDING_WORDS(0x3);
90
91 struct {
92 u32 address_high;
93 u32 address_low;
94 u32 limit;
95 GPUVAddr Address() const {
96 return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) |
97 address_low);
98 }
99 } tic;
100
101 INSERT_PADDING_WORDS(0x22);
102
103 struct {
104 u32 address_high;
105 u32 address_low;
106 GPUVAddr Address() const {
107 return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) |
108 address_low);
109 }
110 } code_loc;
111
112 INSERT_PADDING_WORDS(0x3FE);
113
114 u32 texture_const_buffer_index;
115
116 INSERT_PADDING_WORDS(0x374);
39 }; 117 };
40 std::array<u32, NUM_REGS> reg_array; 118 std::array<u32, NUM_REGS> reg_array;
41 }; 119 };
42 } regs{}; 120 } regs{};
121
122 struct LaunchParams {
123 static constexpr std::size_t NUM_LAUNCH_PARAMETERS = 0x40;
124
125 INSERT_PADDING_WORDS(0x8);
126
127 u32 program_start;
128
129 INSERT_PADDING_WORDS(0x2);
130
131 BitField<30, 1, u32> linked_tsc;
132
133 BitField<0, 31, u32> grid_dim_x;
134 union {
135 BitField<0, 16, u32> grid_dim_y;
136 BitField<16, 16, u32> grid_dim_z;
137 };
138
139 INSERT_PADDING_WORDS(0x3);
140
141 BitField<0, 16, u32> shared_alloc;
142
143 BitField<0, 31, u32> block_dim_x;
144 union {
145 BitField<0, 16, u32> block_dim_y;
146 BitField<16, 16, u32> block_dim_z;
147 };
148
149 union {
150 BitField<0, 8, u32> const_buffer_enable_mask;
151 BitField<29, 2, u32> cache_layout;
152 } memory_config;
153
154 INSERT_PADDING_WORDS(0x8);
155
156 struct {
157 u32 address_low;
158 union {
159 BitField<0, 8, u32> address_high;
160 BitField<15, 17, u32> size;
161 };
162 GPUVAddr Address() const {
163 return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high.Value()) << 32) |
164 address_low);
165 }
166 } const_buffer_config[8];
167
168 union {
169 BitField<0, 20, u32> local_pos_alloc;
170 BitField<27, 5, u32> barrier_alloc;
171 };
172
173 union {
174 BitField<0, 20, u32> local_neg_alloc;
175 BitField<24, 5, u32> gpr_alloc;
176 };
177
178 INSERT_PADDING_WORDS(0x11);
179 } launch_description;
180
181 struct {
182 u32 write_offset = 0;
183 u32 copy_size = 0;
184 std::vector<u8> inner_buffer;
185 } state{};
186
43 static_assert(sizeof(Regs) == Regs::NUM_REGS * sizeof(u32), 187 static_assert(sizeof(Regs) == Regs::NUM_REGS * sizeof(u32),
44 "KeplerCompute Regs has wrong size"); 188 "KeplerCompute Regs has wrong size");
45 189
190 static_assert(sizeof(LaunchParams) == LaunchParams::NUM_LAUNCH_PARAMETERS * sizeof(u32),
191 "KeplerCompute LaunchParams has wrong size");
192
46 /// Write the value to the register identified by method. 193 /// Write the value to the register identified by method.
47 void CallMethod(const GPU::MethodCall& method_call); 194 void CallMethod(const GPU::MethodCall& method_call);
48 195
49private: 196private:
197 Core::System& system;
198 VideoCore::RasterizerInterface& rasterizer;
50 MemoryManager& memory_manager; 199 MemoryManager& memory_manager;
200 Upload::State upload_state;
201
202 void ProcessLaunch();
51}; 203};
52 204
53#define ASSERT_REG_POSITION(field_name, position) \ 205#define ASSERT_REG_POSITION(field_name, position) \
54 static_assert(offsetof(KeplerCompute::Regs, field_name) == position * 4, \ 206 static_assert(offsetof(KeplerCompute::Regs, field_name) == position * 4, \
55 "Field " #field_name " has invalid position") 207 "Field " #field_name " has invalid position")
56 208
209#define ASSERT_LAUNCH_PARAM_POSITION(field_name, position) \
210 static_assert(offsetof(KeplerCompute::LaunchParams, field_name) == position * 4, \
211 "Field " #field_name " has invalid position")
212
213ASSERT_REG_POSITION(upload, 0x60);
214ASSERT_REG_POSITION(exec_upload, 0x6C);
215ASSERT_REG_POSITION(data_upload, 0x6D);
57ASSERT_REG_POSITION(launch, 0xAF); 216ASSERT_REG_POSITION(launch, 0xAF);
217ASSERT_REG_POSITION(tsc, 0x557);
218ASSERT_REG_POSITION(tic, 0x55D);
219ASSERT_REG_POSITION(code_loc, 0x582);
220ASSERT_REG_POSITION(texture_const_buffer_index, 0x982);
221ASSERT_LAUNCH_PARAM_POSITION(program_start, 0x8);
222ASSERT_LAUNCH_PARAM_POSITION(grid_dim_x, 0xC);
223ASSERT_LAUNCH_PARAM_POSITION(shared_alloc, 0x11);
224ASSERT_LAUNCH_PARAM_POSITION(block_dim_x, 0x12);
225ASSERT_LAUNCH_PARAM_POSITION(memory_config, 0x14);
226ASSERT_LAUNCH_PARAM_POSITION(const_buffer_config, 0x1D);
58 227
59#undef ASSERT_REG_POSITION 228#undef ASSERT_REG_POSITION
60 229
diff --git a/src/video_core/engines/kepler_memory.cpp b/src/video_core/engines/kepler_memory.cpp
index 7387886a3..0561f676c 100644
--- a/src/video_core/engines/kepler_memory.cpp
+++ b/src/video_core/engines/kepler_memory.cpp
@@ -14,9 +14,8 @@
14 14
15namespace Tegra::Engines { 15namespace Tegra::Engines {
16 16
17KeplerMemory::KeplerMemory(Core::System& system, VideoCore::RasterizerInterface& rasterizer, 17KeplerMemory::KeplerMemory(Core::System& system, MemoryManager& memory_manager)
18 MemoryManager& memory_manager) 18 : system{system}, memory_manager{memory_manager}, upload_state{memory_manager, regs.upload} {}
19 : system{system}, rasterizer{rasterizer}, memory_manager{memory_manager} {}
20 19
21KeplerMemory::~KeplerMemory() = default; 20KeplerMemory::~KeplerMemory() = default;
22 21
@@ -28,46 +27,18 @@ void KeplerMemory::CallMethod(const GPU::MethodCall& method_call) {
28 27
29 switch (method_call.method) { 28 switch (method_call.method) {
30 case KEPLERMEMORY_REG_INDEX(exec): { 29 case KEPLERMEMORY_REG_INDEX(exec): {
31 ProcessExec(); 30 upload_state.ProcessExec(regs.exec.linear != 0);
32 break; 31 break;
33 } 32 }
34 case KEPLERMEMORY_REG_INDEX(data): { 33 case KEPLERMEMORY_REG_INDEX(data): {
35 ProcessData(method_call.argument, method_call.IsLastCall()); 34 const bool is_last_call = method_call.IsLastCall();
35 upload_state.ProcessData(method_call.argument, is_last_call);
36 if (is_last_call) {
37 system.GPU().Maxwell3D().dirty_flags.OnMemoryWrite();
38 }
36 break; 39 break;
37 } 40 }
38 } 41 }
39} 42}
40 43
41void KeplerMemory::ProcessExec() {
42 state.write_offset = 0;
43 state.copy_size = regs.line_length_in * regs.line_count;
44 state.inner_buffer.resize(state.copy_size);
45}
46
47void KeplerMemory::ProcessData(u32 data, bool is_last_call) {
48 const u32 sub_copy_size = std::min(4U, state.copy_size - state.write_offset);
49 std::memcpy(&state.inner_buffer[state.write_offset], &regs.data, sub_copy_size);
50 state.write_offset += sub_copy_size;
51 if (is_last_call) {
52 const GPUVAddr address{regs.dest.Address()};
53 if (regs.exec.linear != 0) {
54 memory_manager.WriteBlock(address, state.inner_buffer.data(), state.copy_size);
55 } else {
56 UNIMPLEMENTED_IF(regs.dest.z != 0);
57 UNIMPLEMENTED_IF(regs.dest.depth != 1);
58 UNIMPLEMENTED_IF(regs.dest.BlockWidth() != 1);
59 UNIMPLEMENTED_IF(regs.dest.BlockDepth() != 1);
60 const std::size_t dst_size = Tegra::Texture::CalculateSize(
61 true, 1, regs.dest.width, regs.dest.height, 1, regs.dest.BlockHeight(), 1);
62 std::vector<u8> tmp_buffer(dst_size);
63 memory_manager.ReadBlock(address, tmp_buffer.data(), dst_size);
64 Tegra::Texture::SwizzleKepler(regs.dest.width, regs.dest.height, regs.dest.x,
65 regs.dest.y, regs.dest.BlockHeight(), state.copy_size,
66 state.inner_buffer.data(), tmp_buffer.data());
67 memory_manager.WriteBlock(address, tmp_buffer.data(), dst_size);
68 }
69 system.GPU().Maxwell3D().dirty_flags.OnMemoryWrite();
70 }
71}
72
73} // namespace Tegra::Engines 44} // namespace Tegra::Engines
diff --git a/src/video_core/engines/kepler_memory.h b/src/video_core/engines/kepler_memory.h
index 5f892ddad..f3bc675a9 100644
--- a/src/video_core/engines/kepler_memory.h
+++ b/src/video_core/engines/kepler_memory.h
@@ -10,6 +10,7 @@
10#include "common/bit_field.h" 10#include "common/bit_field.h"
11#include "common/common_funcs.h" 11#include "common/common_funcs.h"
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "video_core/engines/engine_upload.h"
13#include "video_core/gpu.h" 14#include "video_core/gpu.h"
14 15
15namespace Core { 16namespace Core {
@@ -20,19 +21,20 @@ namespace Tegra {
20class MemoryManager; 21class MemoryManager;
21} 22}
22 23
23namespace VideoCore {
24class RasterizerInterface;
25}
26
27namespace Tegra::Engines { 24namespace Tegra::Engines {
28 25
26/**
27 * This Engine is known as P2MF. Documentation can be found in:
28 * https://github.com/envytools/envytools/blob/master/rnndb/graph/gk104_p2mf.xml
29 * https://cgit.freedesktop.org/mesa/mesa/tree/src/gallium/drivers/nouveau/nvc0/nve4_p2mf.xml.h
30 */
31
29#define KEPLERMEMORY_REG_INDEX(field_name) \ 32#define KEPLERMEMORY_REG_INDEX(field_name) \
30 (offsetof(Tegra::Engines::KeplerMemory::Regs, field_name) / sizeof(u32)) 33 (offsetof(Tegra::Engines::KeplerMemory::Regs, field_name) / sizeof(u32))
31 34
32class KeplerMemory final { 35class KeplerMemory final {
33public: 36public:
34 KeplerMemory(Core::System& system, VideoCore::RasterizerInterface& rasterizer, 37 KeplerMemory(Core::System& system, MemoryManager& memory_manager);
35 MemoryManager& memory_manager);
36 ~KeplerMemory(); 38 ~KeplerMemory();
37 39
38 /// Write the value to the register identified by method. 40 /// Write the value to the register identified by method.
@@ -45,42 +47,7 @@ public:
45 struct { 47 struct {
46 INSERT_PADDING_WORDS(0x60); 48 INSERT_PADDING_WORDS(0x60);
47 49
48 u32 line_length_in; 50 Upload::Registers upload;
49 u32 line_count;
50
51 struct {
52 u32 address_high;
53 u32 address_low;
54 u32 pitch;
55 union {
56 BitField<0, 4, u32> block_width;
57 BitField<4, 4, u32> block_height;
58 BitField<8, 4, u32> block_depth;
59 };
60 u32 width;
61 u32 height;
62 u32 depth;
63 u32 z;
64 u32 x;
65 u32 y;
66
67 GPUVAddr Address() const {
68 return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) |
69 address_low);
70 }
71
72 u32 BlockWidth() const {
73 return 1U << block_width.Value();
74 }
75
76 u32 BlockHeight() const {
77 return 1U << block_height.Value();
78 }
79
80 u32 BlockDepth() const {
81 return 1U << block_depth.Value();
82 }
83 } dest;
84 51
85 struct { 52 struct {
86 union { 53 union {
@@ -96,28 +63,17 @@ public:
96 }; 63 };
97 } regs{}; 64 } regs{};
98 65
99 struct {
100 u32 write_offset = 0;
101 u32 copy_size = 0;
102 std::vector<u8> inner_buffer;
103 } state{};
104
105private: 66private:
106 Core::System& system; 67 Core::System& system;
107 VideoCore::RasterizerInterface& rasterizer;
108 MemoryManager& memory_manager; 68 MemoryManager& memory_manager;
109 69 Upload::State upload_state;
110 void ProcessExec();
111 void ProcessData(u32 data, bool is_last_call);
112}; 70};
113 71
114#define ASSERT_REG_POSITION(field_name, position) \ 72#define ASSERT_REG_POSITION(field_name, position) \
115 static_assert(offsetof(KeplerMemory::Regs, field_name) == position * 4, \ 73 static_assert(offsetof(KeplerMemory::Regs, field_name) == position * 4, \
116 "Field " #field_name " has invalid position") 74 "Field " #field_name " has invalid position")
117 75
118ASSERT_REG_POSITION(line_length_in, 0x60); 76ASSERT_REG_POSITION(upload, 0x60);
119ASSERT_REG_POSITION(line_count, 0x61);
120ASSERT_REG_POSITION(dest, 0x62);
121ASSERT_REG_POSITION(exec, 0x6C); 77ASSERT_REG_POSITION(exec, 0x6C);
122ASSERT_REG_POSITION(data, 0x6D); 78ASSERT_REG_POSITION(data, 0x6D);
123#undef ASSERT_REG_POSITION 79#undef ASSERT_REG_POSITION
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 9780417f2..d7b586db9 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -20,8 +20,8 @@ constexpr u32 MacroRegistersStart = 0xE00;
20 20
21Maxwell3D::Maxwell3D(Core::System& system, VideoCore::RasterizerInterface& rasterizer, 21Maxwell3D::Maxwell3D(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
22 MemoryManager& memory_manager) 22 MemoryManager& memory_manager)
23 : system{system}, rasterizer{rasterizer}, memory_manager{memory_manager}, macro_interpreter{ 23 : system{system}, rasterizer{rasterizer}, memory_manager{memory_manager},
24 *this} { 24 macro_interpreter{*this}, upload_state{memory_manager, regs.upload} {
25 InitializeRegisterDefaults(); 25 InitializeRegisterDefaults();
26} 26}
27 27
@@ -253,6 +253,18 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
253 ProcessSyncPoint(); 253 ProcessSyncPoint();
254 break; 254 break;
255 } 255 }
256 case MAXWELL3D_REG_INDEX(exec_upload): {
257 upload_state.ProcessExec(regs.exec_upload.linear != 0);
258 break;
259 }
260 case MAXWELL3D_REG_INDEX(data_upload): {
261 const bool is_last_call = method_call.IsLastCall();
262 upload_state.ProcessData(method_call.argument, is_last_call);
263 if (is_last_call) {
264 dirty_flags.OnMemoryWrite();
265 }
266 break;
267 }
256 default: 268 default:
257 break; 269 break;
258 } 270 }
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 85d309d9b..4883b582a 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -14,6 +14,7 @@
14#include "common/common_funcs.h" 14#include "common/common_funcs.h"
15#include "common/common_types.h" 15#include "common/common_types.h"
16#include "common/math_util.h" 16#include "common/math_util.h"
17#include "video_core/engines/engine_upload.h"
17#include "video_core/gpu.h" 18#include "video_core/gpu.h"
18#include "video_core/macro_interpreter.h" 19#include "video_core/macro_interpreter.h"
19#include "video_core/textures/texture.h" 20#include "video_core/textures/texture.h"
@@ -32,6 +33,12 @@ class RasterizerInterface;
32 33
33namespace Tegra::Engines { 34namespace Tegra::Engines {
34 35
36/**
37 * This Engine is known as GF100_3D. Documentation can be found in:
38 * https://github.com/envytools/envytools/blob/master/rnndb/graph/gf100_3d.xml
39 * https://cgit.freedesktop.org/mesa/mesa/tree/src/gallium/drivers/nouveau/nvc0/nvc0_3d.xml.h
40 */
41
35#define MAXWELL3D_REG_INDEX(field_name) \ 42#define MAXWELL3D_REG_INDEX(field_name) \
36 (offsetof(Tegra::Engines::Maxwell3D::Regs, field_name) / sizeof(u32)) 43 (offsetof(Tegra::Engines::Maxwell3D::Regs, field_name) / sizeof(u32))
37 44
@@ -580,7 +587,18 @@ public:
580 u32 bind; 587 u32 bind;
581 } macros; 588 } macros;
582 589
583 INSERT_PADDING_WORDS(0x69); 590 INSERT_PADDING_WORDS(0x17);
591
592 Upload::Registers upload;
593 struct {
594 union {
595 BitField<0, 1, u32> linear;
596 };
597 } exec_upload;
598
599 u32 data_upload;
600
601 INSERT_PADDING_WORDS(0x44);
584 602
585 struct { 603 struct {
586 union { 604 union {
@@ -1176,6 +1194,8 @@ private:
1176 /// Interpreter for the macro codes uploaded to the GPU. 1194 /// Interpreter for the macro codes uploaded to the GPU.
1177 MacroInterpreter macro_interpreter; 1195 MacroInterpreter macro_interpreter;
1178 1196
1197 Upload::State upload_state;
1198
1179 /// Retrieves information about a specific TIC entry from the TIC buffer. 1199 /// Retrieves information about a specific TIC entry from the TIC buffer.
1180 Texture::TICEntry GetTICEntry(u32 tic_index) const; 1200 Texture::TICEntry GetTICEntry(u32 tic_index) const;
1181 1201
@@ -1219,6 +1239,9 @@ private:
1219 "Field " #field_name " has invalid position") 1239 "Field " #field_name " has invalid position")
1220 1240
1221ASSERT_REG_POSITION(macros, 0x45); 1241ASSERT_REG_POSITION(macros, 0x45);
1242ASSERT_REG_POSITION(upload, 0x60);
1243ASSERT_REG_POSITION(exec_upload, 0x6C);
1244ASSERT_REG_POSITION(data_upload, 0x6D);
1222ASSERT_REG_POSITION(sync_info, 0xB2); 1245ASSERT_REG_POSITION(sync_info, 0xB2);
1223ASSERT_REG_POSITION(tfb_enabled, 0x1D1); 1246ASSERT_REG_POSITION(tfb_enabled, 0x1D1);
1224ASSERT_REG_POSITION(rt, 0x200); 1247ASSERT_REG_POSITION(rt, 0x200);
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp
index 2426d0067..3a5dfef0c 100644
--- a/src/video_core/engines/maxwell_dma.cpp
+++ b/src/video_core/engines/maxwell_dma.cpp
@@ -83,57 +83,66 @@ void MaxwellDMA::HandleCopy() {
83 83
84 ASSERT(regs.exec.enable_2d == 1); 84 ASSERT(regs.exec.enable_2d == 1);
85 85
86 const std::size_t copy_size = regs.x_count * regs.y_count; 86 if (regs.exec.is_dst_linear && !regs.exec.is_src_linear) {
87 ASSERT(regs.src_params.size_z == 1);
88 // If the input is tiled and the output is linear, deswizzle the input and copy it over.
89 const u32 src_bytes_per_pixel = regs.src_pitch / regs.src_params.size_x;
90 const std::size_t src_size = Texture::CalculateSize(
91 true, src_bytes_per_pixel, regs.src_params.size_x, regs.src_params.size_y,
92 regs.src_params.size_z, regs.src_params.BlockHeight(), regs.src_params.BlockDepth());
87 93
88 auto source_ptr{memory_manager.GetPointer(source)}; 94 const std::size_t dst_size = regs.dst_pitch * regs.y_count;
89 auto dst_ptr{memory_manager.GetPointer(dest)};
90 95
91 if (!source_ptr) { 96 if (read_buffer.size() < src_size) {
92 LOG_ERROR(HW_GPU, "source_ptr is invalid"); 97 read_buffer.resize(src_size);
93 return; 98 }
94 }
95 99
96 if (!dst_ptr) { 100 if (write_buffer.size() < dst_size) {
97 LOG_ERROR(HW_GPU, "dst_ptr is invalid"); 101 write_buffer.resize(dst_size);
98 return; 102 }
99 }
100 103
101 const auto FlushAndInvalidate = [&](u32 src_size, u64 dst_size) { 104 memory_manager.ReadBlock(source, read_buffer.data(), src_size);
102 // TODO(Subv): For now, manually flush the regions until we implement GPU-accelerated 105 memory_manager.ReadBlock(dest, write_buffer.data(), dst_size);
103 // copying.
104 rasterizer.FlushRegion(ToCacheAddr(source_ptr), src_size);
105 106
106 // We have to invalidate the destination region to evict any outdated surfaces from the 107 Texture::UnswizzleSubrect(regs.x_count, regs.y_count, regs.dst_pitch,
107 // cache. We do this before actually writing the new data because the destination address 108 regs.src_params.size_x, src_bytes_per_pixel, read_buffer.data(),
108 // might contain a dirty surface that will have to be written back to memory. 109 write_buffer.data(), regs.src_params.BlockHeight(),
109 rasterizer.InvalidateRegion(ToCacheAddr(dst_ptr), dst_size); 110 regs.src_params.pos_x, regs.src_params.pos_y);
110 };
111 111
112 if (regs.exec.is_dst_linear && !regs.exec.is_src_linear) { 112 memory_manager.WriteBlock(dest, write_buffer.data(), dst_size);
113 ASSERT(regs.src_params.size_z == 1); 113 } else {
114 // If the input is tiled and the output is linear, deswizzle the input and copy it over. 114 ASSERT(regs.dst_params.BlockDepth() == 1);
115 115
116 const u32 src_bytes_per_pixel = regs.src_pitch / regs.src_params.size_x; 116 const u32 src_bytes_per_pixel = regs.src_pitch / regs.x_count;
117 117
118 FlushAndInvalidate(regs.src_pitch * regs.src_params.size_y, 118 const std::size_t dst_size = Texture::CalculateSize(
119 copy_size * src_bytes_per_pixel); 119 true, src_bytes_per_pixel, regs.dst_params.size_x, regs.dst_params.size_y,
120 regs.dst_params.size_z, regs.dst_params.BlockHeight(), regs.dst_params.BlockDepth());
120 121
121 Texture::UnswizzleSubrect(regs.x_count, regs.y_count, regs.dst_pitch, 122 const std::size_t dst_layer_size = Texture::CalculateSize(
122 regs.src_params.size_x, src_bytes_per_pixel, source_ptr, dst_ptr, 123 true, src_bytes_per_pixel, regs.dst_params.size_x, regs.dst_params.size_y, 1,
123 regs.src_params.BlockHeight(), regs.src_params.pos_x, 124 regs.dst_params.BlockHeight(), regs.dst_params.BlockDepth());
124 regs.src_params.pos_y);
125 } else {
126 ASSERT(regs.dst_params.size_z == 1);
127 ASSERT(regs.src_pitch == regs.x_count);
128 125
129 const u32 src_bpp = regs.src_pitch / regs.x_count; 126 const std::size_t src_size = regs.src_pitch * regs.y_count;
130 127
131 FlushAndInvalidate(regs.src_pitch * regs.y_count, 128 if (read_buffer.size() < src_size) {
132 regs.dst_params.size_x * regs.dst_params.size_y * src_bpp); 129 read_buffer.resize(src_size);
130 }
131
132 if (write_buffer.size() < dst_size) {
133 write_buffer.resize(dst_size);
134 }
135
136 memory_manager.ReadBlock(source, read_buffer.data(), src_size);
137 memory_manager.ReadBlock(dest, write_buffer.data(), dst_size);
133 138
134 // If the input is linear and the output is tiled, swizzle the input and copy it over. 139 // If the input is linear and the output is tiled, swizzle the input and copy it over.
135 Texture::SwizzleSubrect(regs.x_count, regs.y_count, regs.src_pitch, regs.dst_params.size_x, 140 Texture::SwizzleSubrect(regs.x_count, regs.y_count, regs.src_pitch, regs.dst_params.size_x,
136 src_bpp, dst_ptr, source_ptr, regs.dst_params.BlockHeight()); 141 src_bytes_per_pixel,
142 write_buffer.data() + dst_layer_size * regs.dst_params.pos_z,
143 read_buffer.data(), regs.dst_params.BlockHeight());
144
145 memory_manager.WriteBlock(dest, write_buffer.data(), dst_size);
137 } 146 }
138} 147}
139 148
diff --git a/src/video_core/engines/maxwell_dma.h b/src/video_core/engines/maxwell_dma.h
index c6b649842..e5942f671 100644
--- a/src/video_core/engines/maxwell_dma.h
+++ b/src/video_core/engines/maxwell_dma.h
@@ -6,6 +6,7 @@
6 6
7#include <array> 7#include <array>
8#include <cstddef> 8#include <cstddef>
9#include <vector>
9#include "common/bit_field.h" 10#include "common/bit_field.h"
10#include "common/common_funcs.h" 11#include "common/common_funcs.h"
11#include "common/common_types.h" 12#include "common/common_types.h"
@@ -25,6 +26,11 @@ class RasterizerInterface;
25 26
26namespace Tegra::Engines { 27namespace Tegra::Engines {
27 28
29/**
30 * This Engine is known as GK104_Copy. Documentation can be found in:
31 * https://github.com/envytools/envytools/blob/master/rnndb/fifo/gk104_copy.xml
32 */
33
28class MaxwellDMA final { 34class MaxwellDMA final {
29public: 35public:
30 explicit MaxwellDMA(Core::System& system, VideoCore::RasterizerInterface& rasterizer, 36 explicit MaxwellDMA(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
@@ -63,6 +69,16 @@ public:
63 69
64 static_assert(sizeof(Parameters) == 24, "Parameters has wrong size"); 70 static_assert(sizeof(Parameters) == 24, "Parameters has wrong size");
65 71
72 enum class ComponentMode : u32 {
73 Src0 = 0,
74 Src1 = 1,
75 Src2 = 2,
76 Src3 = 3,
77 Const0 = 4,
78 Const1 = 5,
79 Zero = 6,
80 };
81
66 enum class CopyMode : u32 { 82 enum class CopyMode : u32 {
67 None = 0, 83 None = 0,
68 Unk1 = 1, 84 Unk1 = 1,
@@ -128,7 +144,26 @@ public:
128 u32 x_count; 144 u32 x_count;
129 u32 y_count; 145 u32 y_count;
130 146
131 INSERT_PADDING_WORDS(0xBB); 147 INSERT_PADDING_WORDS(0xB8);
148
149 u32 const0;
150 u32 const1;
151 union {
152 BitField<0, 4, ComponentMode> component0;
153 BitField<4, 4, ComponentMode> component1;
154 BitField<8, 4, ComponentMode> component2;
155 BitField<12, 4, ComponentMode> component3;
156 BitField<16, 2, u32> component_size;
157 BitField<20, 3, u32> src_num_components;
158 BitField<24, 3, u32> dst_num_components;
159
160 u32 SrcBytePerPixel() const {
161 return src_num_components.Value() * component_size.Value();
162 }
163 u32 DstBytePerPixel() const {
164 return dst_num_components.Value() * component_size.Value();
165 }
166 } swizzle_config;
132 167
133 Parameters dst_params; 168 Parameters dst_params;
134 169
@@ -149,6 +184,9 @@ private:
149 184
150 MemoryManager& memory_manager; 185 MemoryManager& memory_manager;
151 186
187 std::vector<u8> read_buffer;
188 std::vector<u8> write_buffer;
189
152 /// Performs the copy from the source buffer to the destination buffer as configured in the 190 /// Performs the copy from the source buffer to the destination buffer as configured in the
153 /// registers. 191 /// registers.
154 void HandleCopy(); 192 void HandleCopy();
@@ -165,6 +203,9 @@ ASSERT_REG_POSITION(src_pitch, 0x104);
165ASSERT_REG_POSITION(dst_pitch, 0x105); 203ASSERT_REG_POSITION(dst_pitch, 0x105);
166ASSERT_REG_POSITION(x_count, 0x106); 204ASSERT_REG_POSITION(x_count, 0x106);
167ASSERT_REG_POSITION(y_count, 0x107); 205ASSERT_REG_POSITION(y_count, 0x107);
206ASSERT_REG_POSITION(const0, 0x1C0);
207ASSERT_REG_POSITION(const1, 0x1C1);
208ASSERT_REG_POSITION(swizzle_config, 0x1C2);
168ASSERT_REG_POSITION(dst_params, 0x1C3); 209ASSERT_REG_POSITION(dst_params, 0x1C3);
169ASSERT_REG_POSITION(src_params, 0x1CA); 210ASSERT_REG_POSITION(src_params, 0x1CA);
170 211
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 4461083ff..52706505b 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -35,9 +35,9 @@ GPU::GPU(Core::System& system, VideoCore::RendererBase& renderer) : renderer{ren
35 dma_pusher = std::make_unique<Tegra::DmaPusher>(*this); 35 dma_pusher = std::make_unique<Tegra::DmaPusher>(*this);
36 maxwell_3d = std::make_unique<Engines::Maxwell3D>(system, rasterizer, *memory_manager); 36 maxwell_3d = std::make_unique<Engines::Maxwell3D>(system, rasterizer, *memory_manager);
37 fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer, *memory_manager); 37 fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer, *memory_manager);
38 kepler_compute = std::make_unique<Engines::KeplerCompute>(*memory_manager); 38 kepler_compute = std::make_unique<Engines::KeplerCompute>(system, rasterizer, *memory_manager);
39 maxwell_dma = std::make_unique<Engines::MaxwellDMA>(system, rasterizer, *memory_manager); 39 maxwell_dma = std::make_unique<Engines::MaxwellDMA>(system, rasterizer, *memory_manager);
40 kepler_memory = std::make_unique<Engines::KeplerMemory>(system, rasterizer, *memory_manager); 40 kepler_memory = std::make_unique<Engines::KeplerMemory>(system, *memory_manager);
41} 41}
42 42
43GPU::~GPU() = default; 43GPU::~GPU() = default;
diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp
index c9a2077de..03856013f 100644
--- a/src/video_core/gpu_thread.cpp
+++ b/src/video_core/gpu_thread.cpp
@@ -44,7 +44,7 @@ static void RunThread(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_p
44 renderer.Rasterizer().FlushRegion(data->addr, data->size); 44 renderer.Rasterizer().FlushRegion(data->addr, data->size);
45 } else if (const auto data = std::get_if<InvalidateRegionCommand>(&next.data)) { 45 } else if (const auto data = std::get_if<InvalidateRegionCommand>(&next.data)) {
46 renderer.Rasterizer().InvalidateRegion(data->addr, data->size); 46 renderer.Rasterizer().InvalidateRegion(data->addr, data->size);
47 } else if (const auto data = std::get_if<EndProcessingCommand>(&next.data)) { 47 } else if (std::holds_alternative<EndProcessingCommand>(next.data)) {
48 return; 48 return;
49 } else { 49 } else {
50 UNREACHABLE(); 50 UNREACHABLE();
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp
index 6c98c6701..5d8d126c1 100644
--- a/src/video_core/memory_manager.cpp
+++ b/src/video_core/memory_manager.cpp
@@ -25,6 +25,8 @@ MemoryManager::MemoryManager(VideoCore::RasterizerInterface& rasterizer) : raste
25 UpdatePageTableForVMA(initial_vma); 25 UpdatePageTableForVMA(initial_vma);
26} 26}
27 27
28MemoryManager::~MemoryManager() = default;
29
28GPUVAddr MemoryManager::AllocateSpace(u64 size, u64 align) { 30GPUVAddr MemoryManager::AllocateSpace(u64 size, u64 align) {
29 const u64 aligned_size{Common::AlignUp(size, page_size)}; 31 const u64 aligned_size{Common::AlignUp(size, page_size)};
30 const GPUVAddr gpu_addr{FindFreeRegion(address_space_base, aligned_size)}; 32 const GPUVAddr gpu_addr{FindFreeRegion(address_space_base, aligned_size)};
@@ -199,11 +201,11 @@ const u8* MemoryManager::GetPointer(GPUVAddr addr) const {
199 return {}; 201 return {};
200} 202}
201 203
202bool MemoryManager::IsBlockContinous(const GPUVAddr start, const std::size_t size) { 204bool MemoryManager::IsBlockContinuous(const GPUVAddr start, const std::size_t size) const {
203 const GPUVAddr end = start + size; 205 const GPUVAddr end = start + size;
204 const auto host_ptr_start = reinterpret_cast<std::uintptr_t>(GetPointer(start)); 206 const auto host_ptr_start = reinterpret_cast<std::uintptr_t>(GetPointer(start));
205 const auto host_ptr_end = reinterpret_cast<std::uintptr_t>(GetPointer(end)); 207 const auto host_ptr_end = reinterpret_cast<std::uintptr_t>(GetPointer(end));
206 const std::size_t range = static_cast<std::size_t>(host_ptr_end - host_ptr_start); 208 const auto range = static_cast<std::size_t>(host_ptr_end - host_ptr_start);
207 return range == size; 209 return range == size;
208} 210}
209 211
diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h
index e4f0c4bd6..113f9d8f3 100644
--- a/src/video_core/memory_manager.h
+++ b/src/video_core/memory_manager.h
@@ -47,7 +47,8 @@ struct VirtualMemoryArea {
47 47
48class MemoryManager final { 48class MemoryManager final {
49public: 49public:
50 MemoryManager(VideoCore::RasterizerInterface& rasterizer); 50 explicit MemoryManager(VideoCore::RasterizerInterface& rasterizer);
51 ~MemoryManager();
51 52
52 GPUVAddr AllocateSpace(u64 size, u64 align); 53 GPUVAddr AllocateSpace(u64 size, u64 align);
53 GPUVAddr AllocateSpace(GPUVAddr addr, u64 size, u64 align); 54 GPUVAddr AllocateSpace(GPUVAddr addr, u64 size, u64 align);
@@ -65,18 +66,18 @@ public:
65 u8* GetPointer(GPUVAddr addr); 66 u8* GetPointer(GPUVAddr addr);
66 const u8* GetPointer(GPUVAddr addr) const; 67 const u8* GetPointer(GPUVAddr addr) const;
67 68
68 // Returns true if the block is continous in host memory, false otherwise 69 /// Returns true if the block is continuous in host memory, false otherwise
69 bool IsBlockContinous(const GPUVAddr start, const std::size_t size); 70 bool IsBlockContinuous(GPUVAddr start, std::size_t size) const;
70 71
71 /** 72 /**
72 * ReadBlock and WriteBlock are full read and write operations over virtual 73 * ReadBlock and WriteBlock are full read and write operations over virtual
73 * GPU Memory. It's important to use these when GPU memory may not be continous 74 * GPU Memory. It's important to use these when GPU memory may not be continuous
74 * in the Host Memory counterpart. Note: This functions cause Host GPU Memory 75 * in the Host Memory counterpart. Note: This functions cause Host GPU Memory
75 * Flushes and Invalidations, respectively to each operation. 76 * Flushes and Invalidations, respectively to each operation.
76 */ 77 */
77 void ReadBlock(GPUVAddr src_addr, void* dest_buffer, const std::size_t size) const; 78 void ReadBlock(GPUVAddr src_addr, void* dest_buffer, std::size_t size) const;
78 void WriteBlock(GPUVAddr dest_addr, const void* src_buffer, const std::size_t size); 79 void WriteBlock(GPUVAddr dest_addr, const void* src_buffer, std::size_t size);
79 void CopyBlock(GPUVAddr dest_addr, GPUVAddr src_addr, const std::size_t size); 80 void CopyBlock(GPUVAddr dest_addr, GPUVAddr src_addr, std::size_t size);
80 81
81 /** 82 /**
82 * ReadBlockUnsafe and WriteBlockUnsafe are special versions of ReadBlock and 83 * ReadBlockUnsafe and WriteBlockUnsafe are special versions of ReadBlock and
@@ -88,9 +89,9 @@ public:
88 * WriteBlockUnsafe instead of WriteBlock since it shouldn't invalidate the texture 89 * WriteBlockUnsafe instead of WriteBlock since it shouldn't invalidate the texture
89 * being flushed. 90 * being flushed.
90 */ 91 */
91 void ReadBlockUnsafe(GPUVAddr src_addr, void* dest_buffer, const std::size_t size) const; 92 void ReadBlockUnsafe(GPUVAddr src_addr, void* dest_buffer, std::size_t size) const;
92 void WriteBlockUnsafe(GPUVAddr dest_addr, const void* src_buffer, const std::size_t size); 93 void WriteBlockUnsafe(GPUVAddr dest_addr, const void* src_buffer, std::size_t size);
93 void CopyBlockUnsafe(GPUVAddr dest_addr, GPUVAddr src_addr, const std::size_t size); 94 void CopyBlockUnsafe(GPUVAddr dest_addr, GPUVAddr src_addr, std::size_t size);
94 95
95private: 96private:
96 using VMAMap = std::map<GPUVAddr, VirtualMemoryArea>; 97 using VMAMap = std::map<GPUVAddr, VirtualMemoryArea>;
@@ -111,10 +112,10 @@ private:
111 /** 112 /**
112 * Maps an unmanaged host memory pointer at a given address. 113 * Maps an unmanaged host memory pointer at a given address.
113 * 114 *
114 * @param target The guest address to start the mapping at. 115 * @param target The guest address to start the mapping at.
115 * @param memory The memory to be mapped. 116 * @param memory The memory to be mapped.
116 * @param size Size of the mapping. 117 * @param size Size of the mapping in bytes.
117 * @param state MemoryState tag to attach to the VMA. 118 * @param backing_addr The base address of the range to back this mapping.
118 */ 119 */
119 VMAHandle MapBackingMemory(GPUVAddr target, u8* memory, u64 size, VAddr backing_addr); 120 VMAHandle MapBackingMemory(GPUVAddr target, u8* memory, u64 size, VAddr backing_addr);
120 121
@@ -124,7 +125,7 @@ private:
124 /// Converts a VMAHandle to a mutable VMAIter. 125 /// Converts a VMAHandle to a mutable VMAIter.
125 VMAIter StripIterConstness(const VMAHandle& iter); 126 VMAIter StripIterConstness(const VMAHandle& iter);
126 127
127 /// Marks as the specfied VMA as allocated. 128 /// Marks as the specified VMA as allocated.
128 VMAIter Allocate(VMAIter vma); 129 VMAIter Allocate(VMAIter vma);
129 130
130 /** 131 /**
diff --git a/src/video_core/rasterizer_cache.h b/src/video_core/rasterizer_cache.h
index 291772186..f820f3ed9 100644
--- a/src/video_core/rasterizer_cache.h
+++ b/src/video_core/rasterizer_cache.h
@@ -37,9 +37,6 @@ public:
37 /// Gets the size of the shader in guest memory, required for cache management 37 /// Gets the size of the shader in guest memory, required for cache management
38 virtual std::size_t GetSizeInBytes() const = 0; 38 virtual std::size_t GetSizeInBytes() const = 0;
39 39
40 /// Wriets any cached resources back to memory
41 virtual void Flush() = 0;
42
43 /// Sets whether the cached object should be considered registered 40 /// Sets whether the cached object should be considered registered
44 void SetIsRegistered(bool registered) { 41 void SetIsRegistered(bool registered) {
45 is_registered = registered; 42 is_registered = registered;
@@ -158,6 +155,8 @@ protected:
158 return ++modified_ticks; 155 return ++modified_ticks;
159 } 156 }
160 157
158 virtual void FlushObjectInner(const T& object) = 0;
159
161 /// Flushes the specified object, updating appropriate cache state as needed 160 /// Flushes the specified object, updating appropriate cache state as needed
162 void FlushObject(const T& object) { 161 void FlushObject(const T& object) {
163 std::lock_guard lock{mutex}; 162 std::lock_guard lock{mutex};
@@ -165,7 +164,7 @@ protected:
165 if (!object->IsDirty()) { 164 if (!object->IsDirty()) {
166 return; 165 return;
167 } 166 }
168 object->Flush(); 167 FlushObjectInner(object);
169 object->MarkAsModified(false, *this); 168 object->MarkAsModified(false, *this);
170 } 169 }
171 170
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.h b/src/video_core/renderer_opengl/gl_buffer_cache.h
index fc33aa433..f9247a40e 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.h
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.h
@@ -42,9 +42,6 @@ public:
42 return alignment; 42 return alignment;
43 } 43 }
44 44
45 // We do not have to flush this cache as things in it are never modified by us.
46 void Flush() override {}
47
48private: 45private:
49 VAddr cpu_addr{}; 46 VAddr cpu_addr{};
50 std::size_t size{}; 47 std::size_t size{};
@@ -75,6 +72,9 @@ public:
75protected: 72protected:
76 void AlignBuffer(std::size_t alignment); 73 void AlignBuffer(std::size_t alignment);
77 74
75 // We do not have to flush this cache as things in it are never modified by us.
76 void FlushObjectInner(const std::shared_ptr<CachedBufferEntry>& object) override {}
77
78private: 78private:
79 OGLStreamBuffer stream_buffer; 79 OGLStreamBuffer stream_buffer;
80 80
diff --git a/src/video_core/renderer_opengl/gl_global_cache.h b/src/video_core/renderer_opengl/gl_global_cache.h
index 196e6e278..2d467a240 100644
--- a/src/video_core/renderer_opengl/gl_global_cache.h
+++ b/src/video_core/renderer_opengl/gl_global_cache.h
@@ -46,7 +46,7 @@ public:
46 /// Reloads the global region from guest memory 46 /// Reloads the global region from guest memory
47 void Reload(u32 size_); 47 void Reload(u32 size_);
48 48
49 void Flush() override; 49 void Flush();
50 50
51private: 51private:
52 VAddr cpu_addr{}; 52 VAddr cpu_addr{};
@@ -65,6 +65,11 @@ public:
65 GlobalRegion GetGlobalRegion(const GLShader::GlobalMemoryEntry& descriptor, 65 GlobalRegion GetGlobalRegion(const GLShader::GlobalMemoryEntry& descriptor,
66 Tegra::Engines::Maxwell3D::Regs::ShaderStage stage); 66 Tegra::Engines::Maxwell3D::Regs::ShaderStage stage);
67 67
68protected:
69 void FlushObjectInner(const GlobalRegion& object) override {
70 object->Flush();
71 }
72
68private: 73private:
69 GlobalRegion TryGetReservedGlobalRegion(CacheAddr addr, u32 size) const; 74 GlobalRegion TryGetReservedGlobalRegion(CacheAddr addr, u32 size) const;
70 GlobalRegion GetUncachedGlobalRegion(GPUVAddr addr, u8* host_ptr, u32 size); 75 GlobalRegion GetUncachedGlobalRegion(GPUVAddr addr, u8* host_ptr, u32 size);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index db73e746c..3cc945235 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -922,8 +922,8 @@ void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) {
922 viewport.y = viewport_rect.bottom; 922 viewport.y = viewport_rect.bottom;
923 viewport.width = viewport_rect.GetWidth(); 923 viewport.width = viewport_rect.GetWidth();
924 viewport.height = viewport_rect.GetHeight(); 924 viewport.height = viewport_rect.GetHeight();
925 viewport.depth_range_far = regs.viewports[i].depth_range_far; 925 viewport.depth_range_far = src.depth_range_far;
926 viewport.depth_range_near = regs.viewports[i].depth_range_near; 926 viewport.depth_range_near = src.depth_range_near;
927 } 927 }
928 state.depth_clamp.far_plane = regs.view_volume_clip_control.depth_clamp_far != 0; 928 state.depth_clamp.far_plane = regs.view_volume_clip_control.depth_clamp_far != 0;
929 state.depth_clamp.near_plane = regs.view_volume_clip_control.depth_clamp_near != 0; 929 state.depth_clamp.near_plane = regs.view_volume_clip_control.depth_clamp_near != 0;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 5a25f5b37..a7681902e 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -628,9 +628,11 @@ CachedSurface::CachedSurface(const SurfaceParams& params)
628} 628}
629 629
630MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 192, 64)); 630MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 192, 64));
631void CachedSurface::LoadGLBuffer() { 631void CachedSurface::LoadGLBuffer(RasterizerTemporaryMemory& res_cache_tmp_mem) {
632 MICROPROFILE_SCOPE(OpenGL_SurfaceLoad); 632 MICROPROFILE_SCOPE(OpenGL_SurfaceLoad);
633 gl_buffer.resize(params.max_mip_level); 633 auto& gl_buffer = res_cache_tmp_mem.gl_buffer;
634 if (gl_buffer.size() < params.max_mip_level)
635 gl_buffer.resize(params.max_mip_level);
634 for (u32 i = 0; i < params.max_mip_level; i++) 636 for (u32 i = 0; i < params.max_mip_level; i++)
635 gl_buffer[i].resize(params.GetMipmapSizeGL(i)); 637 gl_buffer[i].resize(params.GetMipmapSizeGL(i));
636 if (params.is_tiled) { 638 if (params.is_tiled) {
@@ -671,13 +673,13 @@ void CachedSurface::LoadGLBuffer() {
671} 673}
672 674
673MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64)); 675MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64));
674void CachedSurface::FlushGLBuffer() { 676void CachedSurface::FlushGLBuffer(RasterizerTemporaryMemory& res_cache_tmp_mem) {
675 MICROPROFILE_SCOPE(OpenGL_SurfaceFlush); 677 MICROPROFILE_SCOPE(OpenGL_SurfaceFlush);
676 678
677 ASSERT_MSG(!IsPixelFormatASTC(params.pixel_format), "Unimplemented"); 679 ASSERT_MSG(!IsPixelFormatASTC(params.pixel_format), "Unimplemented");
678 680
681 auto& gl_buffer = res_cache_tmp_mem.gl_buffer;
679 // OpenGL temporary buffer needs to be big enough to store raw texture size 682 // OpenGL temporary buffer needs to be big enough to store raw texture size
680 gl_buffer.resize(1);
681 gl_buffer[0].resize(GetSizeInBytes()); 683 gl_buffer[0].resize(GetSizeInBytes());
682 684
683 const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type); 685 const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type);
@@ -713,10 +715,12 @@ void CachedSurface::FlushGLBuffer() {
713 } 715 }
714} 716}
715 717
716void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle, 718void CachedSurface::UploadGLMipmapTexture(RasterizerTemporaryMemory& res_cache_tmp_mem, u32 mip_map,
717 GLuint draw_fb_handle) { 719 GLuint read_fb_handle, GLuint draw_fb_handle) {
718 const auto& rect{params.GetRect(mip_map)}; 720 const auto& rect{params.GetRect(mip_map)};
719 721
722 auto& gl_buffer = res_cache_tmp_mem.gl_buffer;
723
720 // Load data from memory to the surface 724 // Load data from memory to the surface
721 const auto x0 = static_cast<GLint>(rect.left); 725 const auto x0 = static_cast<GLint>(rect.left);
722 const auto y0 = static_cast<GLint>(rect.bottom); 726 const auto y0 = static_cast<GLint>(rect.bottom);
@@ -801,7 +805,6 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
801 tuple.type, &gl_buffer[mip_map][buffer_offset]); 805 tuple.type, &gl_buffer[mip_map][buffer_offset]);
802 break; 806 break;
803 case SurfaceTarget::TextureCubemap: { 807 case SurfaceTarget::TextureCubemap: {
804 std::size_t start = buffer_offset;
805 for (std::size_t face = 0; face < params.depth; ++face) { 808 for (std::size_t face = 0; face < params.depth; ++face) {
806 glTextureSubImage3D(texture.handle, mip_map, x0, y0, static_cast<GLint>(face), 809 glTextureSubImage3D(texture.handle, mip_map, x0, y0, static_cast<GLint>(face),
807 static_cast<GLsizei>(rect.GetWidth()), 810 static_cast<GLsizei>(rect.GetWidth()),
@@ -845,11 +848,12 @@ void CachedSurface::EnsureTextureDiscrepantView() {
845} 848}
846 849
847MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 192, 64)); 850MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 192, 64));
848void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle) { 851void CachedSurface::UploadGLTexture(RasterizerTemporaryMemory& res_cache_tmp_mem,
852 GLuint read_fb_handle, GLuint draw_fb_handle) {
849 MICROPROFILE_SCOPE(OpenGL_TextureUL); 853 MICROPROFILE_SCOPE(OpenGL_TextureUL);
850 854
851 for (u32 i = 0; i < params.max_mip_level; i++) 855 for (u32 i = 0; i < params.max_mip_level; i++)
852 UploadGLMipmapTexture(i, read_fb_handle, draw_fb_handle); 856 UploadGLMipmapTexture(res_cache_tmp_mem, i, read_fb_handle, draw_fb_handle);
853} 857}
854 858
855void CachedSurface::UpdateSwizzle(Tegra::Texture::SwizzleSource swizzle_x, 859void CachedSurface::UpdateSwizzle(Tegra::Texture::SwizzleSource swizzle_x,
@@ -929,8 +933,8 @@ Surface RasterizerCacheOpenGL::GetColorBufferSurface(std::size_t index, bool pre
929} 933}
930 934
931void RasterizerCacheOpenGL::LoadSurface(const Surface& surface) { 935void RasterizerCacheOpenGL::LoadSurface(const Surface& surface) {
932 surface->LoadGLBuffer(); 936 surface->LoadGLBuffer(temporal_memory);
933 surface->UploadGLTexture(read_framebuffer.handle, draw_framebuffer.handle); 937 surface->UploadGLTexture(temporal_memory, read_framebuffer.handle, draw_framebuffer.handle);
934 surface->MarkAsModified(false, *this); 938 surface->MarkAsModified(false, *this);
935 surface->MarkForReload(false); 939 surface->MarkForReload(false);
936} 940}
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index db280dbb3..6263ef3e7 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -355,6 +355,12 @@ namespace OpenGL {
355 355
356class RasterizerOpenGL; 356class RasterizerOpenGL;
357 357
358// This is used to store temporary big buffers,
359// instead of creating/destroying all the time
360struct RasterizerTemporaryMemory {
361 std::vector<std::vector<u8>> gl_buffer;
362};
363
358class CachedSurface final : public RasterizerCacheObject { 364class CachedSurface final : public RasterizerCacheObject {
359public: 365public:
360 explicit CachedSurface(const SurfaceParams& params); 366 explicit CachedSurface(const SurfaceParams& params);
@@ -371,10 +377,6 @@ public:
371 return memory_size; 377 return memory_size;
372 } 378 }
373 379
374 void Flush() override {
375 FlushGLBuffer();
376 }
377
378 const OGLTexture& Texture() const { 380 const OGLTexture& Texture() const {
379 return texture; 381 return texture;
380 } 382 }
@@ -397,11 +399,12 @@ public:
397 } 399 }
398 400
399 // Read/Write data in Switch memory to/from gl_buffer 401 // Read/Write data in Switch memory to/from gl_buffer
400 void LoadGLBuffer(); 402 void LoadGLBuffer(RasterizerTemporaryMemory& res_cache_tmp_mem);
401 void FlushGLBuffer(); 403 void FlushGLBuffer(RasterizerTemporaryMemory& res_cache_tmp_mem);
402 404
403 // Upload data in gl_buffer to this surface's texture 405 // Upload data in gl_buffer to this surface's texture
404 void UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle); 406 void UploadGLTexture(RasterizerTemporaryMemory& res_cache_tmp_mem, GLuint read_fb_handle,
407 GLuint draw_fb_handle);
405 408
406 void UpdateSwizzle(Tegra::Texture::SwizzleSource swizzle_x, 409 void UpdateSwizzle(Tegra::Texture::SwizzleSource swizzle_x,
407 Tegra::Texture::SwizzleSource swizzle_y, 410 Tegra::Texture::SwizzleSource swizzle_y,
@@ -429,13 +432,13 @@ public:
429 } 432 }
430 433
431private: 434private:
432 void UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle, GLuint draw_fb_handle); 435 void UploadGLMipmapTexture(RasterizerTemporaryMemory& res_cache_tmp_mem, u32 mip_map,
436 GLuint read_fb_handle, GLuint draw_fb_handle);
433 437
434 void EnsureTextureDiscrepantView(); 438 void EnsureTextureDiscrepantView();
435 439
436 OGLTexture texture; 440 OGLTexture texture;
437 OGLTexture discrepant_view; 441 OGLTexture discrepant_view;
438 std::vector<std::vector<u8>> gl_buffer;
439 SurfaceParams params{}; 442 SurfaceParams params{};
440 GLenum gl_target{}; 443 GLenum gl_target{};
441 GLenum gl_internal_format{}; 444 GLenum gl_internal_format{};
@@ -473,6 +476,11 @@ public:
473 void SignalPreDrawCall(); 476 void SignalPreDrawCall();
474 void SignalPostDrawCall(); 477 void SignalPostDrawCall();
475 478
479protected:
480 void FlushObjectInner(const Surface& object) override {
481 object->FlushGLBuffer(temporal_memory);
482 }
483
476private: 484private:
477 void LoadSurface(const Surface& surface); 485 void LoadSurface(const Surface& surface);
478 Surface GetSurface(const SurfaceParams& params, bool preserve_contents = true); 486 Surface GetSurface(const SurfaceParams& params, bool preserve_contents = true);
@@ -519,6 +527,8 @@ private:
519 std::array<Surface, Maxwell::NumRenderTargets> current_color_buffers; 527 std::array<Surface, Maxwell::NumRenderTargets> current_color_buffers;
520 Surface last_depth_buffer; 528 Surface last_depth_buffer;
521 529
530 RasterizerTemporaryMemory temporal_memory;
531
522 using SurfaceIntervalCache = boost::icl::interval_map<CacheAddr, Surface>; 532 using SurfaceIntervalCache = boost::icl::interval_map<CacheAddr, Surface>;
523 using SurfaceInterval = typename SurfaceIntervalCache::interval_type; 533 using SurfaceInterval = typename SurfaceIntervalCache::interval_type;
524 534
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index b1c8f7c35..f700dc89a 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -345,7 +345,7 @@ ShaderDiskCacheUsage CachedShader::GetUsage(GLenum primitive_mode,
345 345
346ShaderCacheOpenGL::ShaderCacheOpenGL(RasterizerOpenGL& rasterizer, Core::System& system, 346ShaderCacheOpenGL::ShaderCacheOpenGL(RasterizerOpenGL& rasterizer, Core::System& system,
347 const Device& device) 347 const Device& device)
348 : RasterizerCache{rasterizer}, disk_cache{system}, device{device} {} 348 : RasterizerCache{rasterizer}, device{device}, disk_cache{system} {}
349 349
350void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading, 350void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading,
351 const VideoCore::DiskResourceLoadCallback& callback) { 351 const VideoCore::DiskResourceLoadCallback& callback) {
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h
index a332087f8..31b979987 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.h
+++ b/src/video_core/renderer_opengl/gl_shader_cache.h
@@ -57,9 +57,6 @@ public:
57 return shader_length; 57 return shader_length;
58 } 58 }
59 59
60 // We do not have to flush this cache as things in it are never modified by us.
61 void Flush() override {}
62
63 /// Gets the shader entries for the shader 60 /// Gets the shader entries for the shader
64 const GLShader::ShaderEntries& GetShaderEntries() const { 61 const GLShader::ShaderEntries& GetShaderEntries() const {
65 return entries; 62 return entries;
@@ -123,6 +120,10 @@ public:
123 /// Gets the current specified shader stage program 120 /// Gets the current specified shader stage program
124 Shader GetStageProgram(Maxwell::ShaderProgram program); 121 Shader GetStageProgram(Maxwell::ShaderProgram program);
125 122
123protected:
124 // We do not have to flush this cache as things in it are never modified by us.
125 void FlushObjectInner(const Shader& object) override {}
126
126private: 127private:
127 std::unordered_map<u64, UnspecializedShader> GenerateUnspecializedShaders( 128 std::unordered_map<u64, UnspecializedShader> GenerateUnspecializedShaders(
128 const std::atomic_bool& stop_loading, const VideoCore::DiskResourceLoadCallback& callback, 129 const std::atomic_bool& stop_loading, const VideoCore::DiskResourceLoadCallback& callback,
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index ef1a1995f..1a62795e1 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -871,17 +871,6 @@ private:
871 return {}; 871 return {};
872 } 872 }
873 873
874 std::string Composite(Operation operation) {
875 std::string value = "vec4(";
876 for (std::size_t i = 0; i < 4; ++i) {
877 value += Visit(operation[i]);
878 if (i < 3)
879 value += ", ";
880 }
881 value += ')';
882 return value;
883 }
884
885 template <Type type> 874 template <Type type>
886 std::string Add(Operation operation) { 875 std::string Add(Operation operation) {
887 return GenerateBinaryInfix(operation, "+", type, type, type); 876 return GenerateBinaryInfix(operation, "+", type, type, type);
diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
index ed7afc4a0..254c0d499 100644
--- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
@@ -475,7 +475,10 @@ void ShaderDiskCacheOpenGL::SaveUsage(const ShaderDiskCacheUsage& usage) {
475 ASSERT_MSG(it != transferable.end(), "Saving shader usage without storing raw previously"); 475 ASSERT_MSG(it != transferable.end(), "Saving shader usage without storing raw previously");
476 476
477 auto& usages{it->second}; 477 auto& usages{it->second};
478 ASSERT(usages.find(usage) == usages.end()); 478 if (usages.find(usage) != usages.end()) {
479 // Skip this variant since the shader is already stored.
480 return;
481 }
479 usages.insert(usage); 482 usages.insert(usage);
480 483
481 FileUtil::IOFile file = AppendTransferableFile(); 484 FileUtil::IOFile file = AppendTransferableFile();
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h
index 08b786aad..3edf460df 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.h
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h
@@ -49,9 +49,6 @@ public:
49 return alignment; 49 return alignment;
50 } 50 }
51 51
52 // We do not have to flush this cache as things in it are never modified by us.
53 void Flush() override {}
54
55private: 52private:
56 VAddr cpu_addr{}; 53 VAddr cpu_addr{};
57 std::size_t size{}; 54 std::size_t size{};
@@ -87,6 +84,10 @@ public:
87 return buffer_handle; 84 return buffer_handle;
88 } 85 }
89 86
87protected:
88 // We do not have to flush this cache as things in it are never modified by us.
89 void FlushObjectInner(const std::shared_ptr<CachedBufferEntry>& object) override {}
90
90private: 91private:
91 void AlignBuffer(std::size_t alignment); 92 void AlignBuffer(std::size_t alignment);
92 93
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
index 23d9b10db..a11000f6b 100644
--- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
+++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
@@ -315,7 +315,6 @@ private:
315 constexpr std::array<const char*, INTERNAL_FLAGS_COUNT> names = {"zero", "sign", "carry", 315 constexpr std::array<const char*, INTERNAL_FLAGS_COUNT> names = {"zero", "sign", "carry",
316 "overflow"}; 316 "overflow"};
317 for (std::size_t flag = 0; flag < INTERNAL_FLAGS_COUNT; ++flag) { 317 for (std::size_t flag = 0; flag < INTERNAL_FLAGS_COUNT; ++flag) {
318 const auto flag_code = static_cast<InternalFlag>(flag);
319 const Id id = OpVariable(t_prv_bool, spv::StorageClass::Private, v_false); 318 const Id id = OpVariable(t_prv_bool, spv::StorageClass::Private, v_false);
320 internal_flags[flag] = AddGlobalVariable(Name(id, names[flag])); 319 internal_flags[flag] = AddGlobalVariable(Name(id, names[flag]));
321 } 320 }
diff --git a/src/video_core/shader/decode/texture.cpp b/src/video_core/shader/decode/texture.cpp
index 819cc6131..5b033126d 100644
--- a/src/video_core/shader/decode/texture.cpp
+++ b/src/video_core/shader/decode/texture.cpp
@@ -540,8 +540,6 @@ Node4 ShaderIR::GetTexsCode(Instruction instr, TextureType texture_type,
540Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool depth_compare, 540Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool depth_compare,
541 bool is_array, bool is_aoffi) { 541 bool is_array, bool is_aoffi) {
542 const std::size_t coord_count = GetCoordCount(texture_type); 542 const std::size_t coord_count = GetCoordCount(texture_type);
543 const std::size_t total_coord_count = coord_count + (is_array ? 1 : 0);
544 const std::size_t total_reg_count = total_coord_count + (depth_compare ? 1 : 0);
545 543
546 // If enabled arrays index is always stored in the gpr8 field 544 // If enabled arrays index is always stored in the gpr8 field
547 const u64 array_register = instr.gpr8.Value(); 545 const u64 array_register = instr.gpr8.Value();
diff --git a/src/video_core/textures/astc.cpp b/src/video_core/textures/astc.cpp
index b508d64e9..a9b8f69af 100644
--- a/src/video_core/textures/astc.cpp
+++ b/src/video_core/textures/astc.cpp
@@ -25,8 +25,8 @@
25 25
26class InputBitStream { 26class InputBitStream {
27public: 27public:
28 explicit InputBitStream(const unsigned char* ptr, int nBits = 0, int start_offset = 0) 28 explicit InputBitStream(const unsigned char* ptr, int start_offset = 0)
29 : m_NumBits(nBits), m_CurByte(ptr), m_NextBit(start_offset % 8) {} 29 : m_CurByte(ptr), m_NextBit(start_offset % 8) {}
30 30
31 ~InputBitStream() = default; 31 ~InputBitStream() = default;
32 32
@@ -55,12 +55,9 @@ public:
55 } 55 }
56 56
57private: 57private:
58 const int m_NumBits;
59 const unsigned char* m_CurByte; 58 const unsigned char* m_CurByte;
60 int m_NextBit = 0; 59 int m_NextBit = 0;
61 int m_BitsRead = 0; 60 int m_BitsRead = 0;
62
63 bool done = false;
64}; 61};
65 62
66class OutputBitStream { 63class OutputBitStream {
@@ -114,7 +111,6 @@ private:
114 const int m_NumBits; 111 const int m_NumBits;
115 unsigned char* m_CurByte; 112 unsigned char* m_CurByte;
116 int m_NextBit = 0; 113 int m_NextBit = 0;
117 int m_BitsRead = 0;
118 114
119 bool done = false; 115 bool done = false;
120}; 116};
@@ -1616,6 +1612,7 @@ namespace Tegra::Texture::ASTC {
1616std::vector<uint8_t> Decompress(const uint8_t* data, uint32_t width, uint32_t height, 1612std::vector<uint8_t> Decompress(const uint8_t* data, uint32_t width, uint32_t height,
1617 uint32_t depth, uint32_t block_width, uint32_t block_height) { 1613 uint32_t depth, uint32_t block_width, uint32_t block_height) {
1618 uint32_t blockIdx = 0; 1614 uint32_t blockIdx = 0;
1615 std::size_t depth_offset = 0;
1619 std::vector<uint8_t> outData(height * width * depth * 4); 1616 std::vector<uint8_t> outData(height * width * depth * 4);
1620 for (uint32_t k = 0; k < depth; k++) { 1617 for (uint32_t k = 0; k < depth; k++) {
1621 for (uint32_t j = 0; j < height; j += block_height) { 1618 for (uint32_t j = 0; j < height; j += block_height) {
@@ -1630,7 +1627,7 @@ std::vector<uint8_t> Decompress(const uint8_t* data, uint32_t width, uint32_t he
1630 uint32_t decompWidth = std::min(block_width, width - i); 1627 uint32_t decompWidth = std::min(block_width, width - i);
1631 uint32_t decompHeight = std::min(block_height, height - j); 1628 uint32_t decompHeight = std::min(block_height, height - j);
1632 1629
1633 uint8_t* outRow = outData.data() + (j * width + i) * 4; 1630 uint8_t* outRow = depth_offset + outData.data() + (j * width + i) * 4;
1634 for (uint32_t jj = 0; jj < decompHeight; jj++) { 1631 for (uint32_t jj = 0; jj < decompHeight; jj++) {
1635 memcpy(outRow + jj * width * 4, uncompData + jj * block_width, decompWidth * 4); 1632 memcpy(outRow + jj * width * 4, uncompData + jj * block_width, decompWidth * 4);
1636 } 1633 }
@@ -1638,6 +1635,7 @@ std::vector<uint8_t> Decompress(const uint8_t* data, uint32_t width, uint32_t he
1638 blockIdx++; 1635 blockIdx++;
1639 } 1636 }
1640 } 1637 }
1638 depth_offset += height * width * 4;
1641 } 1639 }
1642 1640
1643 return outData; 1641 return outData;
diff --git a/src/yuzu/compatdb.cpp b/src/yuzu/compatdb.cpp
index c8b0a5ec0..5477f050c 100644
--- a/src/yuzu/compatdb.cpp
+++ b/src/yuzu/compatdb.cpp
@@ -58,7 +58,7 @@ void CompatDB::Submit() {
58 58
59 button(NextButton)->setEnabled(false); 59 button(NextButton)->setEnabled(false);
60 button(NextButton)->setText(tr("Submitting")); 60 button(NextButton)->setText(tr("Submitting"));
61 button(QWizard::CancelButton)->setVisible(false); 61 button(CancelButton)->setVisible(false);
62 62
63 testcase_watcher.setFuture(QtConcurrent::run( 63 testcase_watcher.setFuture(QtConcurrent::run(
64 [] { return Core::System::GetInstance().TelemetrySession().SubmitTestcase(); })); 64 [] { return Core::System::GetInstance().TelemetrySession().SubmitTestcase(); }));
@@ -74,12 +74,12 @@ void CompatDB::OnTestcaseSubmitted() {
74 tr("An error occured while sending the Testcase")); 74 tr("An error occured while sending the Testcase"));
75 button(NextButton)->setEnabled(true); 75 button(NextButton)->setEnabled(true);
76 button(NextButton)->setText(tr("Next")); 76 button(NextButton)->setText(tr("Next"));
77 button(QWizard::CancelButton)->setVisible(true); 77 button(CancelButton)->setVisible(true);
78 } else { 78 } else {
79 next(); 79 next();
80 // older versions of QT don't support the "NoCancelButtonOnLastPage" option, this is a 80 // older versions of QT don't support the "NoCancelButtonOnLastPage" option, this is a
81 // workaround 81 // workaround
82 button(QWizard::CancelButton)->setVisible(false); 82 button(CancelButton)->setVisible(false);
83 } 83 }
84} 84}
85 85
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp
index a5218b051..32c05b797 100644
--- a/src/yuzu/configuration/configure_dialog.cpp
+++ b/src/yuzu/configuration/configure_dialog.cpp
@@ -17,8 +17,12 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry)
17 ui->hotkeysTab->Populate(registry); 17 ui->hotkeysTab->Populate(registry);
18 this->setConfiguration(); 18 this->setConfiguration();
19 this->PopulateSelectionList(); 19 this->PopulateSelectionList();
20
21 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
22
20 connect(ui->selectorList, &QListWidget::itemSelectionChanged, this, 23 connect(ui->selectorList, &QListWidget::itemSelectionChanged, this,
21 &ConfigureDialog::UpdateVisibleTabs); 24 &ConfigureDialog::UpdateVisibleTabs);
25
22 adjustSize(); 26 adjustSize();
23 ui->selectorList->setCurrentRow(0); 27 ui->selectorList->setCurrentRow(0);
24 28
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp
index c299c0b5b..08ea41b0f 100644
--- a/src/yuzu/configuration/configure_graphics.cpp
+++ b/src/yuzu/configuration/configure_graphics.cpp
@@ -69,16 +69,20 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent)
69ConfigureGraphics::~ConfigureGraphics() = default; 69ConfigureGraphics::~ConfigureGraphics() = default;
70 70
71void ConfigureGraphics::setConfiguration() { 71void ConfigureGraphics::setConfiguration() {
72 const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
73
72 ui->resolution_factor_combobox->setCurrentIndex( 74 ui->resolution_factor_combobox->setCurrentIndex(
73 static_cast<int>(FromResolutionFactor(Settings::values.resolution_factor))); 75 static_cast<int>(FromResolutionFactor(Settings::values.resolution_factor)));
74 ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit); 76 ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit);
75 ui->frame_limit->setValue(Settings::values.frame_limit); 77 ui->frame_limit->setValue(Settings::values.frame_limit);
78 ui->use_compatibility_profile->setEnabled(runtime_lock);
76 ui->use_compatibility_profile->setChecked(Settings::values.use_compatibility_profile); 79 ui->use_compatibility_profile->setChecked(Settings::values.use_compatibility_profile);
80 ui->use_disk_shader_cache->setEnabled(runtime_lock);
77 ui->use_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache); 81 ui->use_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache);
78 ui->use_accurate_gpu_emulation->setChecked(Settings::values.use_accurate_gpu_emulation); 82 ui->use_accurate_gpu_emulation->setChecked(Settings::values.use_accurate_gpu_emulation);
79 ui->use_asynchronous_gpu_emulation->setEnabled(!Core::System::GetInstance().IsPoweredOn()); 83 ui->use_asynchronous_gpu_emulation->setEnabled(runtime_lock);
80 ui->use_asynchronous_gpu_emulation->setChecked(Settings::values.use_asynchronous_gpu_emulation); 84 ui->use_asynchronous_gpu_emulation->setChecked(Settings::values.use_asynchronous_gpu_emulation);
81 ui->force_30fps_mode->setEnabled(!Core::System::GetInstance().IsPoweredOn()); 85 ui->force_30fps_mode->setEnabled(runtime_lock);
82 ui->force_30fps_mode->setChecked(Settings::values.force_30fps_mode); 86 ui->force_30fps_mode->setChecked(Settings::values.force_30fps_mode);
83 UpdateBackgroundColorButton(QColor::fromRgbF(Settings::values.bg_red, Settings::values.bg_green, 87 UpdateBackgroundColorButton(QColor::fromRgbF(Settings::values.bg_red, Settings::values.bg_green,
84 Settings::values.bg_blue)); 88 Settings::values.bg_blue));
diff --git a/src/yuzu/hotkeys.h b/src/yuzu/hotkeys.h
index 4f526dc7e..248fadaf3 100644
--- a/src/yuzu/hotkeys.h
+++ b/src/yuzu/hotkeys.h
@@ -67,8 +67,6 @@ public:
67 67
68private: 68private:
69 struct Hotkey { 69 struct Hotkey {
70 Hotkey() : shortcut(nullptr), context(Qt::WindowShortcut) {}
71
72 QKeySequence keyseq; 70 QKeySequence keyseq;
73 QShortcut* shortcut = nullptr; 71 QShortcut* shortcut = nullptr;
74 Qt::ShortcutContext context = Qt::WindowShortcut; 72 Qt::ShortcutContext context = Qt::WindowShortcut;
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
index 68a176032..8f104062d 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
@@ -176,9 +176,13 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) {
176 176
177 SDL_SetMainReady(); 177 SDL_SetMainReady();
178 178
179 const SDL_GLprofile profile = Settings::values.use_compatibility_profile
180 ? SDL_GL_CONTEXT_PROFILE_COMPATIBILITY
181 : SDL_GL_CONTEXT_PROFILE_CORE;
182
179 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); 183 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
180 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); 184 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
181 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); 185 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profile);
182 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); 186 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
183 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); 187 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
184 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); 188 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index a1d7879b1..d3734927b 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -222,6 +222,7 @@ int main(int argc, char** argv) {
222 222
223 system.TelemetrySession().AddField(Telemetry::FieldType::App, "Frontend", "SDL"); 223 system.TelemetrySession().AddField(Telemetry::FieldType::App, "Frontend", "SDL");
224 224
225 emu_window->MakeCurrent();
225 system.Renderer().Rasterizer().LoadDiskResources(); 226 system.Renderer().Rasterizer().LoadDiskResources();
226 227
227 while (emu_window->IsOpen()) { 228 while (emu_window->IsOpen()) {