summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
m---------externals/Vulkan-Headers0
-rw-r--r--src/core/CMakeLists.txt4
-rw-r--r--src/core/core.cpp2
-rw-r--r--src/core/crypto/key_manager.cpp3
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp44
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h43
-rw-r--r--src/core/hle/service/vi/display/vi_display.cpp22
-rw-r--r--src/core/hle/service/vi/display/vi_display.h28
-rw-r--r--src/core/hle/service/vi/layer/vi_layer.cpp14
-rw-r--r--src/core/hle/service/vi/layer/vi_layer.h25
-rw-r--r--src/video_core/CMakeLists.txt6
-rw-r--r--src/video_core/engines/kepler_memory.cpp7
-rw-r--r--src/video_core/engines/kepler_memory.h9
-rw-r--r--src/video_core/engines/maxwell_3d.cpp12
-rw-r--r--src/video_core/engines/maxwell_3d.h9
-rw-r--r--src/video_core/engines/maxwell_dma.cpp8
-rw-r--r--src/video_core/engines/maxwell_dma.h10
-rw-r--r--src/video_core/gpu.cpp8
-rw-r--r--src/video_core/gpu.h7
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp144
-rw-r--r--src/video_core/renderer_vulkan/vk_memory_manager.cpp252
-rw-r--r--src/video_core/renderer_vulkan/vk_memory_manager.h87
-rw-r--r--src/video_core/renderer_vulkan/vk_scheduler.cpp60
-rw-r--r--src/video_core/renderer_vulkan/vk_scheduler.h69
25 files changed, 709 insertions, 166 deletions
diff --git a/externals/Vulkan-Headers b/externals/Vulkan-Headers
Subproject 7f02d9bb810f371de0fe833c80004c34f7ff8c5 Subproject 15e5c4db7500b936ae758236f2e72fc1aec2202
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index f61bcd40d..988356c65 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -400,6 +400,10 @@ add_library(core STATIC
400 hle/service/time/time.h 400 hle/service/time/time.h
401 hle/service/usb/usb.cpp 401 hle/service/usb/usb.cpp
402 hle/service/usb/usb.h 402 hle/service/usb/usb.h
403 hle/service/vi/display/vi_display.cpp
404 hle/service/vi/display/vi_display.h
405 hle/service/vi/layer/vi_layer.cpp
406 hle/service/vi/layer/vi_layer.h
403 hle/service/vi/vi.cpp 407 hle/service/vi/vi.cpp
404 hle/service/vi/vi.h 408 hle/service/vi/vi.h
405 hle/service/vi/vi_m.cpp 409 hle/service/vi/vi_m.cpp
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 8aa0932c5..ab7181a05 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -128,7 +128,7 @@ struct System::Impl {
128 return ResultStatus::ErrorVideoCore; 128 return ResultStatus::ErrorVideoCore;
129 } 129 }
130 130
131 gpu_core = std::make_unique<Tegra::GPU>(renderer->Rasterizer()); 131 gpu_core = std::make_unique<Tegra::GPU>(system, renderer->Rasterizer());
132 132
133 cpu_core_manager.Initialize(system); 133 cpu_core_manager.Initialize(system);
134 is_powered_on = true; 134 is_powered_on = true;
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp
index ca12fb4ab..dfac9a4b3 100644
--- a/src/core/crypto/key_manager.cpp
+++ b/src/core/crypto/key_manager.cpp
@@ -398,7 +398,8 @@ static bool ValidCryptoRevisionString(std::string_view base, size_t begin, size_
398} 398}
399 399
400void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) { 400void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) {
401 std::ifstream file(filename); 401 std::ifstream file;
402 OpenFStream(file, filename, std::ios_base::in);
402 if (!file.is_open()) 403 if (!file.is_open())
403 return; 404 return;
404 405
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 3babc3f7c..b5d452db1 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -14,11 +14,12 @@
14#include "core/core_timing_util.h" 14#include "core/core_timing_util.h"
15#include "core/hle/kernel/kernel.h" 15#include "core/hle/kernel/kernel.h"
16#include "core/hle/kernel/readable_event.h" 16#include "core/hle/kernel/readable_event.h"
17#include "core/hle/kernel/writable_event.h"
18#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" 17#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
19#include "core/hle/service/nvdrv/nvdrv.h" 18#include "core/hle/service/nvdrv/nvdrv.h"
20#include "core/hle/service/nvflinger/buffer_queue.h" 19#include "core/hle/service/nvflinger/buffer_queue.h"
21#include "core/hle/service/nvflinger/nvflinger.h" 20#include "core/hle/service/nvflinger/nvflinger.h"
21#include "core/hle/service/vi/display/vi_display.h"
22#include "core/hle/service/vi/layer/vi_layer.h"
22#include "core/perf_stats.h" 23#include "core/perf_stats.h"
23#include "video_core/renderer_base.h" 24#include "video_core/renderer_base.h"
24 25
@@ -27,7 +28,9 @@ namespace Service::NVFlinger {
27constexpr std::size_t SCREEN_REFRESH_RATE = 60; 28constexpr std::size_t SCREEN_REFRESH_RATE = 60;
28constexpr u64 frame_ticks = static_cast<u64>(Core::Timing::BASE_CLOCK_RATE / SCREEN_REFRESH_RATE); 29constexpr u64 frame_ticks = static_cast<u64>(Core::Timing::BASE_CLOCK_RATE / SCREEN_REFRESH_RATE);
29 30
30NVFlinger::NVFlinger(Core::Timing::CoreTiming& core_timing) : core_timing{core_timing} { 31NVFlinger::NVFlinger(Core::Timing::CoreTiming& core_timing)
32 : displays{{0, "Default"}, {1, "External"}, {2, "Edid"}, {3, "Internal"}, {4, "Null"}},
33 core_timing{core_timing} {
31 // Schedule the screen composition events 34 // Schedule the screen composition events
32 composition_event = 35 composition_event =
33 core_timing.RegisterEvent("ScreenComposition", [this](u64 userdata, int cycles_late) { 36 core_timing.RegisterEvent("ScreenComposition", [this](u64 userdata, int cycles_late) {
@@ -53,7 +56,7 @@ std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) {
53 ASSERT(name == "Default"); 56 ASSERT(name == "Default");
54 57
55 const auto itr = std::find_if(displays.begin(), displays.end(), 58 const auto itr = std::find_if(displays.begin(), displays.end(),
56 [&](const Display& display) { return display.name == name; }); 59 [&](const VI::Display& display) { return display.name == name; });
57 if (itr == displays.end()) { 60 if (itr == displays.end()) {
58 return {}; 61 return {};
59 } 62 }
@@ -106,9 +109,10 @@ std::shared_ptr<BufferQueue> NVFlinger::FindBufferQueue(u32 id) const {
106 return *itr; 109 return *itr;
107} 110}
108 111
109Display* NVFlinger::FindDisplay(u64 display_id) { 112VI::Display* NVFlinger::FindDisplay(u64 display_id) {
110 const auto itr = std::find_if(displays.begin(), displays.end(), 113 const auto itr =
111 [&](const Display& display) { return display.id == display_id; }); 114 std::find_if(displays.begin(), displays.end(),
115 [&](const VI::Display& display) { return display.id == display_id; });
112 116
113 if (itr == displays.end()) { 117 if (itr == displays.end()) {
114 return nullptr; 118 return nullptr;
@@ -117,9 +121,10 @@ Display* NVFlinger::FindDisplay(u64 display_id) {
117 return &*itr; 121 return &*itr;
118} 122}
119 123
120const Display* NVFlinger::FindDisplay(u64 display_id) const { 124const VI::Display* NVFlinger::FindDisplay(u64 display_id) const {
121 const auto itr = std::find_if(displays.begin(), displays.end(), 125 const auto itr =
122 [&](const Display& display) { return display.id == display_id; }); 126 std::find_if(displays.begin(), displays.end(),
127 [&](const VI::Display& display) { return display.id == display_id; });
123 128
124 if (itr == displays.end()) { 129 if (itr == displays.end()) {
125 return nullptr; 130 return nullptr;
@@ -128,7 +133,7 @@ const Display* NVFlinger::FindDisplay(u64 display_id) const {
128 return &*itr; 133 return &*itr;
129} 134}
130 135
131Layer* NVFlinger::FindLayer(u64 display_id, u64 layer_id) { 136VI::Layer* NVFlinger::FindLayer(u64 display_id, u64 layer_id) {
132 auto* const display = FindDisplay(display_id); 137 auto* const display = FindDisplay(display_id);
133 138
134 if (display == nullptr) { 139 if (display == nullptr) {
@@ -136,7 +141,7 @@ Layer* NVFlinger::FindLayer(u64 display_id, u64 layer_id) {
136 } 141 }
137 142
138 const auto itr = std::find_if(display->layers.begin(), display->layers.end(), 143 const auto itr = std::find_if(display->layers.begin(), display->layers.end(),
139 [&](const Layer& layer) { return layer.id == layer_id; }); 144 [&](const VI::Layer& layer) { return layer.id == layer_id; });
140 145
141 if (itr == display->layers.end()) { 146 if (itr == display->layers.end()) {
142 return nullptr; 147 return nullptr;
@@ -145,7 +150,7 @@ Layer* NVFlinger::FindLayer(u64 display_id, u64 layer_id) {
145 return &*itr; 150 return &*itr;
146} 151}
147 152
148const Layer* NVFlinger::FindLayer(u64 display_id, u64 layer_id) const { 153const VI::Layer* NVFlinger::FindLayer(u64 display_id, u64 layer_id) const {
149 const auto* const display = FindDisplay(display_id); 154 const auto* const display = FindDisplay(display_id);
150 155
151 if (display == nullptr) { 156 if (display == nullptr) {
@@ -153,7 +158,7 @@ const Layer* NVFlinger::FindLayer(u64 display_id, u64 layer_id) const {
153 } 158 }
154 159
155 const auto itr = std::find_if(display->layers.begin(), display->layers.end(), 160 const auto itr = std::find_if(display->layers.begin(), display->layers.end(),
156 [&](const Layer& layer) { return layer.id == layer_id; }); 161 [&](const VI::Layer& layer) { return layer.id == layer_id; });
157 162
158 if (itr == display->layers.end()) { 163 if (itr == display->layers.end()) {
159 return nullptr; 164 return nullptr;
@@ -174,7 +179,7 @@ void NVFlinger::Compose() {
174 // TODO(Subv): Support more than 1 layer. 179 // TODO(Subv): Support more than 1 layer.
175 ASSERT_MSG(display.layers.size() == 1, "Max 1 layer per display is supported"); 180 ASSERT_MSG(display.layers.size() == 1, "Max 1 layer per display is supported");
176 181
177 Layer& layer = display.layers[0]; 182 VI::Layer& layer = display.layers[0];
178 auto& buffer_queue = layer.buffer_queue; 183 auto& buffer_queue = layer.buffer_queue;
179 184
180 // Search for a queued buffer and acquire it 185 // Search for a queued buffer and acquire it
@@ -207,15 +212,4 @@ void NVFlinger::Compose() {
207 } 212 }
208} 213}
209 214
210Layer::Layer(u64 id, std::shared_ptr<BufferQueue> queue) : id(id), buffer_queue(std::move(queue)) {}
211Layer::~Layer() = default;
212
213Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) {
214 auto& kernel = Core::System::GetInstance().Kernel();
215 vsync_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
216 fmt::format("Display VSync Event {}", id));
217}
218
219Display::~Display() = default;
220
221} // namespace Service::NVFlinger 215} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index 437aa592d..2e000af91 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -4,7 +4,6 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
8#include <memory> 7#include <memory>
9#include <optional> 8#include <optional>
10#include <string> 9#include <string>
@@ -26,31 +25,17 @@ class WritableEvent;
26 25
27namespace Service::Nvidia { 26namespace Service::Nvidia {
28class Module; 27class Module;
29} 28} // namespace Service::Nvidia
29
30namespace Service::VI {
31struct Display;
32struct Layer;
33} // namespace Service::VI
30 34
31namespace Service::NVFlinger { 35namespace Service::NVFlinger {
32 36
33class BufferQueue; 37class BufferQueue;
34 38
35struct Layer {
36 Layer(u64 id, std::shared_ptr<BufferQueue> queue);
37 ~Layer();
38
39 u64 id;
40 std::shared_ptr<BufferQueue> buffer_queue;
41};
42
43struct Display {
44 Display(u64 id, std::string name);
45 ~Display();
46
47 u64 id;
48 std::string name;
49
50 std::vector<Layer> layers;
51 Kernel::EventPair vsync_event;
52};
53
54class NVFlinger final { 39class NVFlinger final {
55public: 40public:
56 explicit NVFlinger(Core::Timing::CoreTiming& core_timing); 41 explicit NVFlinger(Core::Timing::CoreTiming& core_timing);
@@ -88,26 +73,20 @@ public:
88 73
89private: 74private:
90 /// Finds the display identified by the specified ID. 75 /// Finds the display identified by the specified ID.
91 Display* FindDisplay(u64 display_id); 76 VI::Display* FindDisplay(u64 display_id);
92 77
93 /// Finds the display identified by the specified ID. 78 /// Finds the display identified by the specified ID.
94 const Display* FindDisplay(u64 display_id) const; 79 const VI::Display* FindDisplay(u64 display_id) const;
95 80
96 /// Finds the layer identified by the specified ID in the desired display. 81 /// Finds the layer identified by the specified ID in the desired display.
97 Layer* FindLayer(u64 display_id, u64 layer_id); 82 VI::Layer* FindLayer(u64 display_id, u64 layer_id);
98 83
99 /// Finds the layer identified by the specified ID in the desired display. 84 /// Finds the layer identified by the specified ID in the desired display.
100 const Layer* FindLayer(u64 display_id, u64 layer_id) const; 85 const VI::Layer* FindLayer(u64 display_id, u64 layer_id) const;
101 86
102 std::shared_ptr<Nvidia::Module> nvdrv; 87 std::shared_ptr<Nvidia::Module> nvdrv;
103 88
104 std::array<Display, 5> displays{{ 89 std::vector<VI::Display> displays;
105 {0, "Default"},
106 {1, "External"},
107 {2, "Edid"},
108 {3, "Internal"},
109 {4, "Null"},
110 }};
111 std::vector<std::shared_ptr<BufferQueue>> buffer_queues; 90 std::vector<std::shared_ptr<BufferQueue>> buffer_queues;
112 91
113 /// Id to use for the next layer that is created, this counter is shared among all displays. 92 /// Id to use for the next layer that is created, this counter is shared among all displays.
diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp
new file mode 100644
index 000000000..a108e468f
--- /dev/null
+++ b/src/core/hle/service/vi/display/vi_display.cpp
@@ -0,0 +1,22 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <fmt/format.h>
6
7#include "core/core.h"
8#include "core/hle/kernel/readable_event.h"
9#include "core/hle/service/vi/display/vi_display.h"
10#include "core/hle/service/vi/layer/vi_layer.h"
11
12namespace Service::VI {
13
14Display::Display(u64 id, std::string name) : id{id}, name{std::move(name)} {
15 auto& kernel = Core::System::GetInstance().Kernel();
16 vsync_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
17 fmt::format("Display VSync Event {}", id));
18}
19
20Display::~Display() = default;
21
22} // namespace Service::VI
diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h
new file mode 100644
index 000000000..df44db306
--- /dev/null
+++ b/src/core/hle/service/vi/display/vi_display.h
@@ -0,0 +1,28 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <string>
8#include <vector>
9
10#include "common/common_types.h"
11#include "core/hle/kernel/writable_event.h"
12
13namespace Service::VI {
14
15struct Layer;
16
17struct Display {
18 Display(u64 id, std::string name);
19 ~Display();
20
21 u64 id;
22 std::string name;
23
24 std::vector<Layer> layers;
25 Kernel::EventPair vsync_event;
26};
27
28} // namespace Service::VI
diff --git a/src/core/hle/service/vi/layer/vi_layer.cpp b/src/core/hle/service/vi/layer/vi_layer.cpp
new file mode 100644
index 000000000..3a83e5b95
--- /dev/null
+++ b/src/core/hle/service/vi/layer/vi_layer.cpp
@@ -0,0 +1,14 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/service/vi/layer/vi_layer.h"
6
7namespace Service::VI {
8
9Layer::Layer(u64 id, std::shared_ptr<NVFlinger::BufferQueue> queue)
10 : id{id}, buffer_queue{std::move(queue)} {}
11
12Layer::~Layer() = default;
13
14} // namespace Service::VI
diff --git a/src/core/hle/service/vi/layer/vi_layer.h b/src/core/hle/service/vi/layer/vi_layer.h
new file mode 100644
index 000000000..df328e09f
--- /dev/null
+++ b/src/core/hle/service/vi/layer/vi_layer.h
@@ -0,0 +1,25 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8
9#include "common/common_types.h"
10
11namespace Service::NVFlinger {
12class BufferQueue;
13}
14
15namespace Service::VI {
16
17struct Layer {
18 Layer(u64 id, std::shared_ptr<NVFlinger::BufferQueue> queue);
19 ~Layer();
20
21 u64 id;
22 std::shared_ptr<NVFlinger::BufferQueue> buffer_queue;
23};
24
25} // namespace Service::VI
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 59319f206..6036d6ed3 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -106,8 +106,12 @@ if (ENABLE_VULKAN)
106 renderer_vulkan/declarations.h 106 renderer_vulkan/declarations.h
107 renderer_vulkan/vk_device.cpp 107 renderer_vulkan/vk_device.cpp
108 renderer_vulkan/vk_device.h 108 renderer_vulkan/vk_device.h
109 renderer_vulkan/vk_memory_manager.cpp
110 renderer_vulkan/vk_memory_manager.h
109 renderer_vulkan/vk_resource_manager.cpp 111 renderer_vulkan/vk_resource_manager.cpp
110 renderer_vulkan/vk_resource_manager.h) 112 renderer_vulkan/vk_resource_manager.h
113 renderer_vulkan/vk_scheduler.cpp
114 renderer_vulkan/vk_scheduler.h)
111 115
112 target_include_directories(video_core PRIVATE ../../externals/Vulkan-Headers/include) 116 target_include_directories(video_core PRIVATE ../../externals/Vulkan-Headers/include)
113 target_compile_definitions(video_core PRIVATE HAS_VULKAN) 117 target_compile_definitions(video_core PRIVATE HAS_VULKAN)
diff --git a/src/video_core/engines/kepler_memory.cpp b/src/video_core/engines/kepler_memory.cpp
index 5c1029ddf..4f6126116 100644
--- a/src/video_core/engines/kepler_memory.cpp
+++ b/src/video_core/engines/kepler_memory.cpp
@@ -2,6 +2,7 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/assert.h"
5#include "common/logging/log.h" 6#include "common/logging/log.h"
6#include "core/core.h" 7#include "core/core.h"
7#include "core/memory.h" 8#include "core/memory.h"
@@ -11,9 +12,9 @@
11 12
12namespace Tegra::Engines { 13namespace Tegra::Engines {
13 14
14KeplerMemory::KeplerMemory(VideoCore::RasterizerInterface& rasterizer, 15KeplerMemory::KeplerMemory(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
15 MemoryManager& memory_manager) 16 MemoryManager& memory_manager)
16 : memory_manager(memory_manager), rasterizer{rasterizer} {} 17 : system{system}, memory_manager(memory_manager), rasterizer{rasterizer} {}
17 18
18KeplerMemory::~KeplerMemory() = default; 19KeplerMemory::~KeplerMemory() = default;
19 20
@@ -50,7 +51,7 @@ void KeplerMemory::ProcessData(u32 data) {
50 rasterizer.InvalidateRegion(*dest_address, sizeof(u32)); 51 rasterizer.InvalidateRegion(*dest_address, sizeof(u32));
51 52
52 Memory::Write32(*dest_address, data); 53 Memory::Write32(*dest_address, data);
53 Core::System::GetInstance().GPU().Maxwell3D().dirty_flags.OnMemoryWrite(); 54 system.GPU().Maxwell3D().dirty_flags.OnMemoryWrite();
54 55
55 state.write_offset++; 56 state.write_offset++;
56} 57}
diff --git a/src/video_core/engines/kepler_memory.h b/src/video_core/engines/kepler_memory.h
index fe9ebc5b9..f680c2ad9 100644
--- a/src/video_core/engines/kepler_memory.h
+++ b/src/video_core/engines/kepler_memory.h
@@ -5,13 +5,16 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include "common/assert.h"
9#include "common/bit_field.h" 8#include "common/bit_field.h"
10#include "common/common_funcs.h" 9#include "common/common_funcs.h"
11#include "common/common_types.h" 10#include "common/common_types.h"
12#include "video_core/gpu.h" 11#include "video_core/gpu.h"
13#include "video_core/memory_manager.h" 12#include "video_core/memory_manager.h"
14 13
14namespace Core {
15class System;
16}
17
15namespace VideoCore { 18namespace VideoCore {
16class RasterizerInterface; 19class RasterizerInterface;
17} 20}
@@ -23,7 +26,8 @@ namespace Tegra::Engines {
23 26
24class KeplerMemory final { 27class KeplerMemory final {
25public: 28public:
26 KeplerMemory(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager); 29 KeplerMemory(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
30 MemoryManager& memory_manager);
27 ~KeplerMemory(); 31 ~KeplerMemory();
28 32
29 /// Write the value to the register identified by method. 33 /// Write the value to the register identified by method.
@@ -76,6 +80,7 @@ public:
76 } state{}; 80 } state{};
77 81
78private: 82private:
83 Core::System& system;
79 MemoryManager& memory_manager; 84 MemoryManager& memory_manager;
80 VideoCore::RasterizerInterface& rasterizer; 85 VideoCore::RasterizerInterface& rasterizer;
81 86
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 86ede5faa..2d2136067 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -19,8 +19,10 @@ namespace Tegra::Engines {
19/// First register id that is actually a Macro call. 19/// First register id that is actually a Macro call.
20constexpr u32 MacroRegistersStart = 0xE00; 20constexpr u32 MacroRegistersStart = 0xE00;
21 21
22Maxwell3D::Maxwell3D(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager) 22Maxwell3D::Maxwell3D(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
23 : memory_manager(memory_manager), rasterizer{rasterizer}, macro_interpreter(*this) { 23 MemoryManager& memory_manager)
24 : memory_manager(memory_manager), system{system}, rasterizer{rasterizer},
25 macro_interpreter(*this) {
24 InitializeRegisterDefaults(); 26 InitializeRegisterDefaults();
25} 27}
26 28
@@ -103,7 +105,7 @@ void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) {
103} 105}
104 106
105void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) { 107void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
106 auto debug_context = Core::System::GetInstance().GetGPUDebugContext(); 108 auto debug_context = system.GetGPUDebugContext();
107 109
108 // It is an error to write to a register other than the current macro's ARG register before it 110 // It is an error to write to a register other than the current macro's ARG register before it
109 // has finished execution. 111 // has finished execution.
@@ -317,7 +319,7 @@ void Maxwell3D::ProcessQueryGet() {
317 LongQueryResult query_result{}; 319 LongQueryResult query_result{};
318 query_result.value = result; 320 query_result.value = result;
319 // TODO(Subv): Generate a real GPU timestamp and write it here instead of CoreTiming 321 // TODO(Subv): Generate a real GPU timestamp and write it here instead of CoreTiming
320 query_result.timestamp = Core::System::GetInstance().CoreTiming().GetTicks(); 322 query_result.timestamp = system.CoreTiming().GetTicks();
321 Memory::WriteBlock(*address, &query_result, sizeof(query_result)); 323 Memory::WriteBlock(*address, &query_result, sizeof(query_result));
322 } 324 }
323 dirty_flags.OnMemoryWrite(); 325 dirty_flags.OnMemoryWrite();
@@ -334,7 +336,7 @@ void Maxwell3D::DrawArrays() {
334 regs.vertex_buffer.count); 336 regs.vertex_buffer.count);
335 ASSERT_MSG(!(regs.index_array.count && regs.vertex_buffer.count), "Both indexed and direct?"); 337 ASSERT_MSG(!(regs.index_array.count && regs.vertex_buffer.count), "Both indexed and direct?");
336 338
337 auto debug_context = Core::System::GetInstance().GetGPUDebugContext(); 339 auto debug_context = system.GetGPUDebugContext();
338 340
339 if (debug_context) { 341 if (debug_context) {
340 debug_context->OnEvent(Tegra::DebugContext::Event::IncomingPrimitiveBatch, nullptr); 342 debug_context->OnEvent(Tegra::DebugContext::Event::IncomingPrimitiveBatch, nullptr);
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 1f76aa670..0e3873ffd 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -17,6 +17,10 @@
17#include "video_core/memory_manager.h" 17#include "video_core/memory_manager.h"
18#include "video_core/textures/texture.h" 18#include "video_core/textures/texture.h"
19 19
20namespace Core {
21class System;
22}
23
20namespace VideoCore { 24namespace VideoCore {
21class RasterizerInterface; 25class RasterizerInterface;
22} 26}
@@ -28,7 +32,8 @@ namespace Tegra::Engines {
28 32
29class Maxwell3D final { 33class Maxwell3D final {
30public: 34public:
31 explicit Maxwell3D(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager); 35 explicit Maxwell3D(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
36 MemoryManager& memory_manager);
32 ~Maxwell3D() = default; 37 ~Maxwell3D() = default;
33 38
34 /// Register structure of the Maxwell3D engine. 39 /// Register structure of the Maxwell3D engine.
@@ -1131,6 +1136,8 @@ public:
1131private: 1136private:
1132 void InitializeRegisterDefaults(); 1137 void InitializeRegisterDefaults();
1133 1138
1139 Core::System& system;
1140
1134 VideoCore::RasterizerInterface& rasterizer; 1141 VideoCore::RasterizerInterface& rasterizer;
1135 1142
1136 /// Start offsets of each macro in macro_memory 1143 /// Start offsets of each macro in macro_memory
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp
index d6c41a5ae..529a14ec7 100644
--- a/src/video_core/engines/maxwell_dma.cpp
+++ b/src/video_core/engines/maxwell_dma.cpp
@@ -2,6 +2,7 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/assert.h"
5#include "core/core.h" 6#include "core/core.h"
6#include "core/memory.h" 7#include "core/memory.h"
7#include "video_core/engines/maxwell_3d.h" 8#include "video_core/engines/maxwell_3d.h"
@@ -11,8 +12,9 @@
11 12
12namespace Tegra::Engines { 13namespace Tegra::Engines {
13 14
14MaxwellDMA::MaxwellDMA(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager) 15MaxwellDMA::MaxwellDMA(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
15 : memory_manager(memory_manager), rasterizer{rasterizer} {} 16 MemoryManager& memory_manager)
17 : memory_manager(memory_manager), system{system}, rasterizer{rasterizer} {}
16 18
17void MaxwellDMA::CallMethod(const GPU::MethodCall& method_call) { 19void MaxwellDMA::CallMethod(const GPU::MethodCall& method_call) {
18 ASSERT_MSG(method_call.method < Regs::NUM_REGS, 20 ASSERT_MSG(method_call.method < Regs::NUM_REGS,
@@ -59,7 +61,7 @@ void MaxwellDMA::HandleCopy() {
59 } 61 }
60 62
61 // All copies here update the main memory, so mark all rasterizer states as invalid. 63 // All copies here update the main memory, so mark all rasterizer states as invalid.
62 Core::System::GetInstance().GPU().Maxwell3D().dirty_flags.OnMemoryWrite(); 64 system.GPU().Maxwell3D().dirty_flags.OnMemoryWrite();
63 65
64 if (regs.exec.is_dst_linear && regs.exec.is_src_linear) { 66 if (regs.exec.is_dst_linear && regs.exec.is_src_linear) {
65 // When the enable_2d bit is disabled, the copy is performed as if we were copying a 1D 67 // When the enable_2d bit is disabled, the copy is performed as if we were copying a 1D
diff --git a/src/video_core/engines/maxwell_dma.h b/src/video_core/engines/maxwell_dma.h
index 1f8cd65d2..cf75aeb12 100644
--- a/src/video_core/engines/maxwell_dma.h
+++ b/src/video_core/engines/maxwell_dma.h
@@ -5,13 +5,16 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include "common/assert.h"
9#include "common/bit_field.h" 8#include "common/bit_field.h"
10#include "common/common_funcs.h" 9#include "common/common_funcs.h"
11#include "common/common_types.h" 10#include "common/common_types.h"
12#include "video_core/gpu.h" 11#include "video_core/gpu.h"
13#include "video_core/memory_manager.h" 12#include "video_core/memory_manager.h"
14 13
14namespace Core {
15class System;
16}
17
15namespace VideoCore { 18namespace VideoCore {
16class RasterizerInterface; 19class RasterizerInterface;
17} 20}
@@ -20,7 +23,8 @@ namespace Tegra::Engines {
20 23
21class MaxwellDMA final { 24class MaxwellDMA final {
22public: 25public:
23 explicit MaxwellDMA(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager); 26 explicit MaxwellDMA(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
27 MemoryManager& memory_manager);
24 ~MaxwellDMA() = default; 28 ~MaxwellDMA() = default;
25 29
26 /// Write the value to the register identified by method. 30 /// Write the value to the register identified by method.
@@ -137,6 +141,8 @@ public:
137 MemoryManager& memory_manager; 141 MemoryManager& memory_manager;
138 142
139private: 143private:
144 Core::System& system;
145
140 VideoCore::RasterizerInterface& rasterizer; 146 VideoCore::RasterizerInterface& rasterizer;
141 147
142 /// Performs the copy from the source buffer to the destination buffer as configured in the 148 /// Performs the copy from the source buffer to the destination buffer as configured in the
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index b86265dfe..ac30d1a89 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -28,14 +28,14 @@ u32 FramebufferConfig::BytesPerPixel(PixelFormat format) {
28 UNREACHABLE(); 28 UNREACHABLE();
29} 29}
30 30
31GPU::GPU(VideoCore::RasterizerInterface& rasterizer) { 31GPU::GPU(Core::System& system, VideoCore::RasterizerInterface& rasterizer) {
32 memory_manager = std::make_unique<Tegra::MemoryManager>(); 32 memory_manager = std::make_unique<Tegra::MemoryManager>();
33 dma_pusher = std::make_unique<Tegra::DmaPusher>(*this); 33 dma_pusher = std::make_unique<Tegra::DmaPusher>(*this);
34 maxwell_3d = std::make_unique<Engines::Maxwell3D>(rasterizer, *memory_manager); 34 maxwell_3d = std::make_unique<Engines::Maxwell3D>(system, rasterizer, *memory_manager);
35 fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer, *memory_manager); 35 fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer, *memory_manager);
36 kepler_compute = std::make_unique<Engines::KeplerCompute>(*memory_manager); 36 kepler_compute = std::make_unique<Engines::KeplerCompute>(*memory_manager);
37 maxwell_dma = std::make_unique<Engines::MaxwellDMA>(rasterizer, *memory_manager); 37 maxwell_dma = std::make_unique<Engines::MaxwellDMA>(system, rasterizer, *memory_manager);
38 kepler_memory = std::make_unique<Engines::KeplerMemory>(rasterizer, *memory_manager); 38 kepler_memory = std::make_unique<Engines::KeplerMemory>(system, rasterizer, *memory_manager);
39} 39}
40 40
41GPU::~GPU() = default; 41GPU::~GPU() = default;
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index a482196ea..0f5bfdcbf 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -6,12 +6,15 @@
6 6
7#include <array> 7#include <array>
8#include <memory> 8#include <memory>
9#include <vector>
10#include "common/common_types.h" 9#include "common/common_types.h"
11#include "core/hle/service/nvflinger/buffer_queue.h" 10#include "core/hle/service/nvflinger/buffer_queue.h"
12#include "video_core/dma_pusher.h" 11#include "video_core/dma_pusher.h"
13#include "video_core/memory_manager.h" 12#include "video_core/memory_manager.h"
14 13
14namespace Core {
15class System;
16}
17
15namespace VideoCore { 18namespace VideoCore {
16class RasterizerInterface; 19class RasterizerInterface;
17} 20}
@@ -118,7 +121,7 @@ enum class EngineID {
118 121
119class GPU final { 122class GPU final {
120public: 123public:
121 explicit GPU(VideoCore::RasterizerInterface& rasterizer); 124 explicit GPU(Core::System& system, VideoCore::RasterizerInterface& rasterizer);
122 ~GPU(); 125 ~GPU();
123 126
124 struct MethodCall { 127 struct MethodCall {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 59f671048..74200914e 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -423,7 +423,7 @@ void SwizzleFunc(const MortonSwizzleMode& mode, const SurfaceParams& params,
423 for (u32 i = 0; i < params.depth; i++) { 423 for (u32 i = 0; i < params.depth; i++) {
424 MortonSwizzle(mode, params.pixel_format, params.MipWidth(mip_level), 424 MortonSwizzle(mode, params.pixel_format, params.MipWidth(mip_level),
425 params.MipBlockHeight(mip_level), params.MipHeight(mip_level), 425 params.MipBlockHeight(mip_level), params.MipHeight(mip_level),
426 params.MipBlockDepth(mip_level), params.tile_width_spacing, 1, 426 params.MipBlockDepth(mip_level), 1, params.tile_width_spacing,
427 gl_buffer.data() + offset_gl, gl_size, params.addr + offset); 427 gl_buffer.data() + offset_gl, gl_size, params.addr + offset);
428 offset += layer_size; 428 offset += layer_size;
429 offset_gl += gl_size; 429 offset_gl += gl_size;
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index 81af803bc..219f08053 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -11,7 +11,9 @@
11namespace OpenGL { 11namespace OpenGL {
12 12
13OpenGLState OpenGLState::cur_state; 13OpenGLState OpenGLState::cur_state;
14
14bool OpenGLState::s_rgb_used; 15bool OpenGLState::s_rgb_used;
16
15OpenGLState::OpenGLState() { 17OpenGLState::OpenGLState() {
16 // These all match default OpenGL values 18 // These all match default OpenGL values
17 geometry_shaders.enabled = false; 19 geometry_shaders.enabled = false;
@@ -112,7 +114,6 @@ void OpenGLState::ApplyDefaultState() {
112} 114}
113 115
114void OpenGLState::ApplySRgb() const { 116void OpenGLState::ApplySRgb() const {
115 // sRGB
116 if (framebuffer_srgb.enabled != cur_state.framebuffer_srgb.enabled) { 117 if (framebuffer_srgb.enabled != cur_state.framebuffer_srgb.enabled) {
117 if (framebuffer_srgb.enabled) { 118 if (framebuffer_srgb.enabled) {
118 // Track if sRGB is used 119 // Track if sRGB is used
@@ -125,23 +126,20 @@ void OpenGLState::ApplySRgb() const {
125} 126}
126 127
127void OpenGLState::ApplyCulling() const { 128void OpenGLState::ApplyCulling() const {
128 // Culling 129 if (cull.enabled != cur_state.cull.enabled) {
129 const bool cull_changed = cull.enabled != cur_state.cull.enabled;
130 if (cull_changed) {
131 if (cull.enabled) { 130 if (cull.enabled) {
132 glEnable(GL_CULL_FACE); 131 glEnable(GL_CULL_FACE);
133 } else { 132 } else {
134 glDisable(GL_CULL_FACE); 133 glDisable(GL_CULL_FACE);
135 } 134 }
136 } 135 }
137 if (cull.enabled) {
138 if (cull_changed || cull.mode != cur_state.cull.mode) {
139 glCullFace(cull.mode);
140 }
141 136
142 if (cull_changed || cull.front_face != cur_state.cull.front_face) { 137 if (cull.mode != cur_state.cull.mode) {
143 glFrontFace(cull.front_face); 138 glCullFace(cull.mode);
144 } 139 }
140
141 if (cull.front_face != cur_state.cull.front_face) {
142 glFrontFace(cull.front_face);
145 } 143 }
146} 144}
147 145
@@ -172,72 +170,63 @@ void OpenGLState::ApplyColorMask() const {
172} 170}
173 171
174void OpenGLState::ApplyDepth() const { 172void OpenGLState::ApplyDepth() const {
175 // Depth test 173 if (depth.test_enabled != cur_state.depth.test_enabled) {
176 const bool depth_test_changed = depth.test_enabled != cur_state.depth.test_enabled;
177 if (depth_test_changed) {
178 if (depth.test_enabled) { 174 if (depth.test_enabled) {
179 glEnable(GL_DEPTH_TEST); 175 glEnable(GL_DEPTH_TEST);
180 } else { 176 } else {
181 glDisable(GL_DEPTH_TEST); 177 glDisable(GL_DEPTH_TEST);
182 } 178 }
183 } 179 }
184 if (depth.test_enabled && 180
185 (depth_test_changed || depth.test_func != cur_state.depth.test_func)) { 181 if (depth.test_func != cur_state.depth.test_func) {
186 glDepthFunc(depth.test_func); 182 glDepthFunc(depth.test_func);
187 } 183 }
188 // Depth mask 184
189 if (depth.write_mask != cur_state.depth.write_mask) { 185 if (depth.write_mask != cur_state.depth.write_mask) {
190 glDepthMask(depth.write_mask); 186 glDepthMask(depth.write_mask);
191 } 187 }
192} 188}
193 189
194void OpenGLState::ApplyPrimitiveRestart() const { 190void OpenGLState::ApplyPrimitiveRestart() const {
195 const bool primitive_restart_changed = 191 if (primitive_restart.enabled != cur_state.primitive_restart.enabled) {
196 primitive_restart.enabled != cur_state.primitive_restart.enabled;
197 if (primitive_restart_changed) {
198 if (primitive_restart.enabled) { 192 if (primitive_restart.enabled) {
199 glEnable(GL_PRIMITIVE_RESTART); 193 glEnable(GL_PRIMITIVE_RESTART);
200 } else { 194 } else {
201 glDisable(GL_PRIMITIVE_RESTART); 195 glDisable(GL_PRIMITIVE_RESTART);
202 } 196 }
203 } 197 }
204 if (primitive_restart_changed || 198
205 (primitive_restart.enabled && 199 if (primitive_restart.index != cur_state.primitive_restart.index) {
206 primitive_restart.index != cur_state.primitive_restart.index)) {
207 glPrimitiveRestartIndex(primitive_restart.index); 200 glPrimitiveRestartIndex(primitive_restart.index);
208 } 201 }
209} 202}
210 203
211void OpenGLState::ApplyStencilTest() const { 204void OpenGLState::ApplyStencilTest() const {
212 const bool stencil_test_changed = stencil.test_enabled != cur_state.stencil.test_enabled; 205 if (stencil.test_enabled != cur_state.stencil.test_enabled) {
213 if (stencil_test_changed) {
214 if (stencil.test_enabled) { 206 if (stencil.test_enabled) {
215 glEnable(GL_STENCIL_TEST); 207 glEnable(GL_STENCIL_TEST);
216 } else { 208 } else {
217 glDisable(GL_STENCIL_TEST); 209 glDisable(GL_STENCIL_TEST);
218 } 210 }
219 } 211 }
220 if (stencil.test_enabled) { 212
221 auto config_stencil = [stencil_test_changed](GLenum face, const auto& config, 213 const auto ConfigStencil = [](GLenum face, const auto& config, const auto& prev_config) {
222 const auto& prev_config) { 214 if (config.test_func != prev_config.test_func || config.test_ref != prev_config.test_ref ||
223 if (stencil_test_changed || config.test_func != prev_config.test_func || 215 config.test_mask != prev_config.test_mask) {
224 config.test_ref != prev_config.test_ref || 216 glStencilFuncSeparate(face, config.test_func, config.test_ref, config.test_mask);
225 config.test_mask != prev_config.test_mask) { 217 }
226 glStencilFuncSeparate(face, config.test_func, config.test_ref, config.test_mask); 218 if (config.action_depth_fail != prev_config.action_depth_fail ||
227 } 219 config.action_depth_pass != prev_config.action_depth_pass ||
228 if (stencil_test_changed || config.action_depth_fail != prev_config.action_depth_fail || 220 config.action_stencil_fail != prev_config.action_stencil_fail) {
229 config.action_depth_pass != prev_config.action_depth_pass || 221 glStencilOpSeparate(face, config.action_stencil_fail, config.action_depth_fail,
230 config.action_stencil_fail != prev_config.action_stencil_fail) { 222 config.action_depth_pass);
231 glStencilOpSeparate(face, config.action_stencil_fail, config.action_depth_fail, 223 }
232 config.action_depth_pass); 224 if (config.write_mask != prev_config.write_mask) {
233 } 225 glStencilMaskSeparate(face, config.write_mask);
234 if (config.write_mask != prev_config.write_mask) { 226 }
235 glStencilMaskSeparate(face, config.write_mask); 227 };
236 } 228 ConfigStencil(GL_FRONT, stencil.front, cur_state.stencil.front);
237 }; 229 ConfigStencil(GL_BACK, stencil.back, cur_state.stencil.back);
238 config_stencil(GL_FRONT, stencil.front, cur_state.stencil.front);
239 config_stencil(GL_BACK, stencil.back, cur_state.stencil.back);
240 }
241} 230}
242// Viewport does not affects glClearBuffer so emulate viewport using scissor test 231// Viewport does not affects glClearBuffer so emulate viewport using scissor test
243void OpenGLState::EmulateViewportWithScissor() { 232void OpenGLState::EmulateViewportWithScissor() {
@@ -278,19 +267,18 @@ void OpenGLState::ApplyViewport() const {
278 updated.depth_range_far != current.depth_range_far) { 267 updated.depth_range_far != current.depth_range_far) {
279 glDepthRangeIndexed(i, updated.depth_range_near, updated.depth_range_far); 268 glDepthRangeIndexed(i, updated.depth_range_near, updated.depth_range_far);
280 } 269 }
281 const bool scissor_changed = updated.scissor.enabled != current.scissor.enabled; 270
282 if (scissor_changed) { 271 if (updated.scissor.enabled != current.scissor.enabled) {
283 if (updated.scissor.enabled) { 272 if (updated.scissor.enabled) {
284 glEnablei(GL_SCISSOR_TEST, i); 273 glEnablei(GL_SCISSOR_TEST, i);
285 } else { 274 } else {
286 glDisablei(GL_SCISSOR_TEST, i); 275 glDisablei(GL_SCISSOR_TEST, i);
287 } 276 }
288 } 277 }
289 if (updated.scissor.enabled && 278
290 (scissor_changed || updated.scissor.x != current.scissor.x || 279 if (updated.scissor.x != current.scissor.x || updated.scissor.y != current.scissor.y ||
291 updated.scissor.y != current.scissor.y || 280 updated.scissor.width != current.scissor.width ||
292 updated.scissor.width != current.scissor.width || 281 updated.scissor.height != current.scissor.height) {
293 updated.scissor.height != current.scissor.height)) {
294 glScissorIndexed(i, updated.scissor.x, updated.scissor.y, updated.scissor.width, 282 glScissorIndexed(i, updated.scissor.x, updated.scissor.y, updated.scissor.width,
295 updated.scissor.height); 283 updated.scissor.height);
296 } 284 }
@@ -302,22 +290,23 @@ void OpenGLState::ApplyViewport() const {
302 updated.height != current.height) { 290 updated.height != current.height) {
303 glViewport(updated.x, updated.y, updated.width, updated.height); 291 glViewport(updated.x, updated.y, updated.width, updated.height);
304 } 292 }
293
305 if (updated.depth_range_near != current.depth_range_near || 294 if (updated.depth_range_near != current.depth_range_near ||
306 updated.depth_range_far != current.depth_range_far) { 295 updated.depth_range_far != current.depth_range_far) {
307 glDepthRange(updated.depth_range_near, updated.depth_range_far); 296 glDepthRange(updated.depth_range_near, updated.depth_range_far);
308 } 297 }
309 const bool scissor_changed = updated.scissor.enabled != current.scissor.enabled; 298
310 if (scissor_changed) { 299 if (updated.scissor.enabled != current.scissor.enabled) {
311 if (updated.scissor.enabled) { 300 if (updated.scissor.enabled) {
312 glEnable(GL_SCISSOR_TEST); 301 glEnable(GL_SCISSOR_TEST);
313 } else { 302 } else {
314 glDisable(GL_SCISSOR_TEST); 303 glDisable(GL_SCISSOR_TEST);
315 } 304 }
316 } 305 }
317 if (updated.scissor.enabled && (scissor_changed || updated.scissor.x != current.scissor.x || 306
318 updated.scissor.y != current.scissor.y || 307 if (updated.scissor.x != current.scissor.x || updated.scissor.y != current.scissor.y ||
319 updated.scissor.width != current.scissor.width || 308 updated.scissor.width != current.scissor.width ||
320 updated.scissor.height != current.scissor.height)) { 309 updated.scissor.height != current.scissor.height) {
321 glScissor(updated.scissor.x, updated.scissor.y, updated.scissor.width, 310 glScissor(updated.scissor.x, updated.scissor.y, updated.scissor.width,
322 updated.scissor.height); 311 updated.scissor.height);
323 } 312 }
@@ -327,8 +316,7 @@ void OpenGLState::ApplyViewport() const {
327void OpenGLState::ApplyGlobalBlending() const { 316void OpenGLState::ApplyGlobalBlending() const {
328 const Blend& current = cur_state.blend[0]; 317 const Blend& current = cur_state.blend[0];
329 const Blend& updated = blend[0]; 318 const Blend& updated = blend[0];
330 const bool blend_changed = updated.enabled != current.enabled; 319 if (updated.enabled != current.enabled) {
331 if (blend_changed) {
332 if (updated.enabled) { 320 if (updated.enabled) {
333 glEnable(GL_BLEND); 321 glEnable(GL_BLEND);
334 } else { 322 } else {
@@ -338,15 +326,14 @@ void OpenGLState::ApplyGlobalBlending() const {
338 if (!updated.enabled) { 326 if (!updated.enabled) {
339 return; 327 return;
340 } 328 }
341 if (blend_changed || updated.src_rgb_func != current.src_rgb_func || 329 if (updated.src_rgb_func != current.src_rgb_func ||
342 updated.dst_rgb_func != current.dst_rgb_func || updated.src_a_func != current.src_a_func || 330 updated.dst_rgb_func != current.dst_rgb_func || updated.src_a_func != current.src_a_func ||
343 updated.dst_a_func != current.dst_a_func) { 331 updated.dst_a_func != current.dst_a_func) {
344 glBlendFuncSeparate(updated.src_rgb_func, updated.dst_rgb_func, updated.src_a_func, 332 glBlendFuncSeparate(updated.src_rgb_func, updated.dst_rgb_func, updated.src_a_func,
345 updated.dst_a_func); 333 updated.dst_a_func);
346 } 334 }
347 335
348 if (blend_changed || updated.rgb_equation != current.rgb_equation || 336 if (updated.rgb_equation != current.rgb_equation || updated.a_equation != current.a_equation) {
349 updated.a_equation != current.a_equation) {
350 glBlendEquationSeparate(updated.rgb_equation, updated.a_equation); 337 glBlendEquationSeparate(updated.rgb_equation, updated.a_equation);
351 } 338 }
352} 339}
@@ -354,26 +341,22 @@ void OpenGLState::ApplyGlobalBlending() const {
354void OpenGLState::ApplyTargetBlending(std::size_t target, bool force) const { 341void OpenGLState::ApplyTargetBlending(std::size_t target, bool force) const {
355 const Blend& updated = blend[target]; 342 const Blend& updated = blend[target];
356 const Blend& current = cur_state.blend[target]; 343 const Blend& current = cur_state.blend[target];
357 const bool blend_changed = updated.enabled != current.enabled || force; 344 if (updated.enabled != current.enabled || force) {
358 if (blend_changed) {
359 if (updated.enabled) { 345 if (updated.enabled) {
360 glEnablei(GL_BLEND, static_cast<GLuint>(target)); 346 glEnablei(GL_BLEND, static_cast<GLuint>(target));
361 } else { 347 } else {
362 glDisablei(GL_BLEND, static_cast<GLuint>(target)); 348 glDisablei(GL_BLEND, static_cast<GLuint>(target));
363 } 349 }
364 } 350 }
365 if (!updated.enabled) { 351
366 return; 352 if (updated.src_rgb_func != current.src_rgb_func ||
367 }
368 if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
369 updated.dst_rgb_func != current.dst_rgb_func || updated.src_a_func != current.src_a_func || 353 updated.dst_rgb_func != current.dst_rgb_func || updated.src_a_func != current.src_a_func ||
370 updated.dst_a_func != current.dst_a_func) { 354 updated.dst_a_func != current.dst_a_func) {
371 glBlendFuncSeparatei(static_cast<GLuint>(target), updated.src_rgb_func, 355 glBlendFuncSeparatei(static_cast<GLuint>(target), updated.src_rgb_func,
372 updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func); 356 updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func);
373 } 357 }
374 358
375 if (blend_changed || updated.rgb_equation != current.rgb_equation || 359 if (updated.rgb_equation != current.rgb_equation || updated.a_equation != current.a_equation) {
376 updated.a_equation != current.a_equation) {
377 glBlendEquationSeparatei(static_cast<GLuint>(target), updated.rgb_equation, 360 glBlendEquationSeparatei(static_cast<GLuint>(target), updated.rgb_equation,
378 updated.a_equation); 361 updated.a_equation);
379 } 362 }
@@ -397,8 +380,7 @@ void OpenGLState::ApplyBlending() const {
397} 380}
398 381
399void OpenGLState::ApplyLogicOp() const { 382void OpenGLState::ApplyLogicOp() const {
400 const bool logic_op_changed = logic_op.enabled != cur_state.logic_op.enabled; 383 if (logic_op.enabled != cur_state.logic_op.enabled) {
401 if (logic_op_changed) {
402 if (logic_op.enabled) { 384 if (logic_op.enabled) {
403 glEnable(GL_COLOR_LOGIC_OP); 385 glEnable(GL_COLOR_LOGIC_OP);
404 } else { 386 } else {
@@ -406,14 +388,12 @@ void OpenGLState::ApplyLogicOp() const {
406 } 388 }
407 } 389 }
408 390
409 if (logic_op.enabled && 391 if (logic_op.operation != cur_state.logic_op.operation) {
410 (logic_op_changed || logic_op.operation != cur_state.logic_op.operation)) {
411 glLogicOp(logic_op.operation); 392 glLogicOp(logic_op.operation);
412 } 393 }
413} 394}
414 395
415void OpenGLState::ApplyPolygonOffset() const { 396void OpenGLState::ApplyPolygonOffset() const {
416
417 const bool fill_enable_changed = 397 const bool fill_enable_changed =
418 polygon_offset.fill_enable != cur_state.polygon_offset.fill_enable; 398 polygon_offset.fill_enable != cur_state.polygon_offset.fill_enable;
419 const bool line_enable_changed = 399 const bool line_enable_changed =
@@ -448,9 +428,7 @@ void OpenGLState::ApplyPolygonOffset() const {
448 } 428 }
449 } 429 }
450 430
451 if ((polygon_offset.fill_enable || polygon_offset.line_enable || polygon_offset.point_enable) && 431 if (factor_changed || units_changed || clamp_changed) {
452 (factor_changed || units_changed || clamp_changed)) {
453
454 if (GLAD_GL_EXT_polygon_offset_clamp && polygon_offset.clamp != 0) { 432 if (GLAD_GL_EXT_polygon_offset_clamp && polygon_offset.clamp != 0) {
455 glPolygonOffsetClamp(polygon_offset.factor, polygon_offset.units, polygon_offset.clamp); 433 glPolygonOffsetClamp(polygon_offset.factor, polygon_offset.units, polygon_offset.clamp);
456 } else { 434 } else {
@@ -528,9 +506,9 @@ void OpenGLState::ApplyDepthClamp() const {
528 depth_clamp.near_plane == cur_state.depth_clamp.near_plane) { 506 depth_clamp.near_plane == cur_state.depth_clamp.near_plane) {
529 return; 507 return;
530 } 508 }
531 if (depth_clamp.far_plane != depth_clamp.near_plane) { 509 UNIMPLEMENTED_IF_MSG(depth_clamp.far_plane != depth_clamp.near_plane,
532 UNIMPLEMENTED_MSG("Unimplemented Depth Clamp Separation!"); 510 "Unimplemented Depth Clamp Separation!");
533 } 511
534 if (depth_clamp.far_plane || depth_clamp.near_plane) { 512 if (depth_clamp.far_plane || depth_clamp.near_plane) {
535 glEnable(GL_DEPTH_CLAMP); 513 glEnable(GL_DEPTH_CLAMP);
536 } else { 514 } else {
diff --git a/src/video_core/renderer_vulkan/vk_memory_manager.cpp b/src/video_core/renderer_vulkan/vk_memory_manager.cpp
new file mode 100644
index 000000000..17ee93b91
--- /dev/null
+++ b/src/video_core/renderer_vulkan/vk_memory_manager.cpp
@@ -0,0 +1,252 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <optional>
7#include <tuple>
8#include <vector>
9#include "common/alignment.h"
10#include "common/assert.h"
11#include "common/common_types.h"
12#include "common/logging/log.h"
13#include "video_core/renderer_vulkan/declarations.h"
14#include "video_core/renderer_vulkan/vk_device.h"
15#include "video_core/renderer_vulkan/vk_memory_manager.h"
16
17namespace Vulkan {
18
19// TODO(Rodrigo): Fine tune this number
20constexpr u64 ALLOC_CHUNK_SIZE = 64 * 1024 * 1024;
21
22class VKMemoryAllocation final {
23public:
24 explicit VKMemoryAllocation(const VKDevice& device, vk::DeviceMemory memory,
25 vk::MemoryPropertyFlags properties, u64 alloc_size, u32 type)
26 : device{device}, memory{memory}, properties{properties}, alloc_size{alloc_size},
27 shifted_type{ShiftType(type)}, is_mappable{properties &
28 vk::MemoryPropertyFlagBits::eHostVisible} {
29 if (is_mappable) {
30 const auto dev = device.GetLogical();
31 const auto& dld = device.GetDispatchLoader();
32 base_address = static_cast<u8*>(dev.mapMemory(memory, 0, alloc_size, {}, dld));
33 }
34 }
35
36 ~VKMemoryAllocation() {
37 const auto dev = device.GetLogical();
38 const auto& dld = device.GetDispatchLoader();
39 if (is_mappable)
40 dev.unmapMemory(memory, dld);
41 dev.free(memory, nullptr, dld);
42 }
43
44 VKMemoryCommit Commit(vk::DeviceSize commit_size, vk::DeviceSize alignment) {
45 auto found = TryFindFreeSection(free_iterator, alloc_size, static_cast<u64>(commit_size),
46 static_cast<u64>(alignment));
47 if (!found) {
48 found = TryFindFreeSection(0, free_iterator, static_cast<u64>(commit_size),
49 static_cast<u64>(alignment));
50 if (!found) {
51 // Signal out of memory, it'll try to do more allocations.
52 return nullptr;
53 }
54 }
55 u8* address = is_mappable ? base_address + *found : nullptr;
56 auto commit = std::make_unique<VKMemoryCommitImpl>(this, memory, address, *found,
57 *found + commit_size);
58 commits.push_back(commit.get());
59
60 // Last commit's address is highly probable to be free.
61 free_iterator = *found + commit_size;
62
63 return commit;
64 }
65
66 void Free(const VKMemoryCommitImpl* commit) {
67 ASSERT(commit);
68 const auto it =
69 std::find_if(commits.begin(), commits.end(),
70 [&](const auto& stored_commit) { return stored_commit == commit; });
71 if (it == commits.end()) {
72 LOG_CRITICAL(Render_Vulkan, "Freeing unallocated commit!");
73 UNREACHABLE();
74 return;
75 }
76 commits.erase(it);
77 }
78
79 /// Returns whether this allocation is compatible with the arguments.
80 bool IsCompatible(vk::MemoryPropertyFlags wanted_properties, u32 type_mask) const {
81 return (wanted_properties & properties) != vk::MemoryPropertyFlagBits(0) &&
82 (type_mask & shifted_type) != 0;
83 }
84
85private:
86 static constexpr u32 ShiftType(u32 type) {
87 return 1U << type;
88 }
89
90 /// A memory allocator, it may return a free region between "start" and "end" with the solicited
91 /// requeriments.
92 std::optional<u64> TryFindFreeSection(u64 start, u64 end, u64 size, u64 alignment) const {
93 u64 iterator = start;
94 while (iterator + size < end) {
95 const u64 try_left = Common::AlignUp(iterator, alignment);
96 const u64 try_right = try_left + size;
97
98 bool overlap = false;
99 for (const auto& commit : commits) {
100 const auto [commit_left, commit_right] = commit->interval;
101 if (try_left < commit_right && commit_left < try_right) {
102 // There's an overlap, continue the search where the overlapping commit ends.
103 iterator = commit_right;
104 overlap = true;
105 break;
106 }
107 }
108 if (!overlap) {
109 // A free address has been found.
110 return try_left;
111 }
112 }
113 // No free regions where found, return an empty optional.
114 return std::nullopt;
115 }
116
117 const VKDevice& device; ///< Vulkan device.
118 const vk::DeviceMemory memory; ///< Vulkan memory allocation handler.
119 const vk::MemoryPropertyFlags properties; ///< Vulkan properties.
120 const u64 alloc_size; ///< Size of this allocation.
121 const u32 shifted_type; ///< Stored Vulkan type of this allocation, shifted.
122 const bool is_mappable; ///< Whether the allocation is mappable.
123
124 /// Base address of the mapped pointer.
125 u8* base_address{};
126
127 /// Hints where the next free region is likely going to be.
128 u64 free_iterator{};
129
130 /// Stores all commits done from this allocation.
131 std::vector<const VKMemoryCommitImpl*> commits;
132};
133
134VKMemoryManager::VKMemoryManager(const VKDevice& device)
135 : device{device}, props{device.GetPhysical().getMemoryProperties(device.GetDispatchLoader())},
136 is_memory_unified{GetMemoryUnified(props)} {}
137
138VKMemoryManager::~VKMemoryManager() = default;
139
140VKMemoryCommit VKMemoryManager::Commit(const vk::MemoryRequirements& reqs, bool host_visible) {
141 ASSERT(reqs.size < ALLOC_CHUNK_SIZE);
142
143 // When a host visible commit is asked, search for host visible and coherent, otherwise search
144 // for a fast device local type.
145 const vk::MemoryPropertyFlags wanted_properties =
146 host_visible
147 ? vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent
148 : vk::MemoryPropertyFlagBits::eDeviceLocal;
149
150 const auto TryCommit = [&]() -> VKMemoryCommit {
151 for (auto& alloc : allocs) {
152 if (!alloc->IsCompatible(wanted_properties, reqs.memoryTypeBits))
153 continue;
154
155 if (auto commit = alloc->Commit(reqs.size, reqs.alignment); commit) {
156 return commit;
157 }
158 }
159 return {};
160 };
161
162 if (auto commit = TryCommit(); commit) {
163 return commit;
164 }
165
166 // Commit has failed, allocate more memory.
167 if (!AllocMemory(wanted_properties, reqs.memoryTypeBits, ALLOC_CHUNK_SIZE)) {
168 // TODO(Rodrigo): Try to use host memory.
169 LOG_CRITICAL(Render_Vulkan, "Ran out of memory!");
170 UNREACHABLE();
171 }
172
173 // Commit again, this time it won't fail since there's a fresh allocation above. If it does,
174 // there's a bug.
175 auto commit = TryCommit();
176 ASSERT(commit);
177 return commit;
178}
179
180VKMemoryCommit VKMemoryManager::Commit(vk::Buffer buffer, bool host_visible) {
181 const auto dev = device.GetLogical();
182 const auto& dld = device.GetDispatchLoader();
183 const auto requeriments = dev.getBufferMemoryRequirements(buffer, dld);
184 auto commit = Commit(requeriments, host_visible);
185 dev.bindBufferMemory(buffer, commit->GetMemory(), commit->GetOffset(), dld);
186 return commit;
187}
188
189VKMemoryCommit VKMemoryManager::Commit(vk::Image image, bool host_visible) {
190 const auto dev = device.GetLogical();
191 const auto& dld = device.GetDispatchLoader();
192 const auto requeriments = dev.getImageMemoryRequirements(image, dld);
193 auto commit = Commit(requeriments, host_visible);
194 dev.bindImageMemory(image, commit->GetMemory(), commit->GetOffset(), dld);
195 return commit;
196}
197
198bool VKMemoryManager::AllocMemory(vk::MemoryPropertyFlags wanted_properties, u32 type_mask,
199 u64 size) {
200 const u32 type = [&]() {
201 for (u32 type_index = 0; type_index < props.memoryTypeCount; ++type_index) {
202 const auto flags = props.memoryTypes[type_index].propertyFlags;
203 if ((type_mask & (1U << type_index)) && (flags & wanted_properties)) {
204 // The type matches in type and in the wanted properties.
205 return type_index;
206 }
207 }
208 LOG_CRITICAL(Render_Vulkan, "Couldn't find a compatible memory type!");
209 UNREACHABLE();
210 return 0u;
211 }();
212
213 const auto dev = device.GetLogical();
214 const auto& dld = device.GetDispatchLoader();
215
216 // Try to allocate found type.
217 const vk::MemoryAllocateInfo memory_ai(size, type);
218 vk::DeviceMemory memory;
219 if (const vk::Result res = dev.allocateMemory(&memory_ai, nullptr, &memory, dld);
220 res != vk::Result::eSuccess) {
221 LOG_CRITICAL(Render_Vulkan, "Device allocation failed with code {}!", vk::to_string(res));
222 return false;
223 }
224 allocs.push_back(
225 std::make_unique<VKMemoryAllocation>(device, memory, wanted_properties, size, type));
226 return true;
227}
228
229/*static*/ bool VKMemoryManager::GetMemoryUnified(const vk::PhysicalDeviceMemoryProperties& props) {
230 for (u32 heap_index = 0; heap_index < props.memoryHeapCount; ++heap_index) {
231 if (!(props.memoryHeaps[heap_index].flags & vk::MemoryHeapFlagBits::eDeviceLocal)) {
232 // Memory is considered unified when heaps are device local only.
233 return false;
234 }
235 }
236 return true;
237}
238
239VKMemoryCommitImpl::VKMemoryCommitImpl(VKMemoryAllocation* allocation, vk::DeviceMemory memory,
240 u8* data, u64 begin, u64 end)
241 : allocation{allocation}, memory{memory}, data{data}, interval(std::make_pair(begin, end)) {}
242
243VKMemoryCommitImpl::~VKMemoryCommitImpl() {
244 allocation->Free(this);
245}
246
247u8* VKMemoryCommitImpl::GetData() const {
248 ASSERT_MSG(data != nullptr, "Trying to access an unmapped commit.");
249 return data;
250}
251
252} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_memory_manager.h b/src/video_core/renderer_vulkan/vk_memory_manager.h
new file mode 100644
index 000000000..073597b35
--- /dev/null
+++ b/src/video_core/renderer_vulkan/vk_memory_manager.h
@@ -0,0 +1,87 @@
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 <memory>
8#include <utility>
9#include <vector>
10#include "common/common_types.h"
11#include "video_core/renderer_vulkan/declarations.h"
12
13namespace Vulkan {
14
15class VKDevice;
16class VKMemoryAllocation;
17class VKMemoryCommitImpl;
18
19using VKMemoryCommit = std::unique_ptr<VKMemoryCommitImpl>;
20
21class VKMemoryManager final {
22public:
23 explicit VKMemoryManager(const VKDevice& device);
24 ~VKMemoryManager();
25
26 /**
27 * Commits a memory with the specified requeriments.
28 * @param reqs Requeriments returned from a Vulkan call.
29 * @param host_visible Signals the allocator that it *must* use host visible and coherent
30 * memory. When passing false, it will try to allocate device local memory.
31 * @returns A memory commit.
32 */
33 VKMemoryCommit Commit(const vk::MemoryRequirements& reqs, bool host_visible);
34
35 /// Commits memory required by the buffer and binds it.
36 VKMemoryCommit Commit(vk::Buffer buffer, bool host_visible);
37
38 /// Commits memory required by the image and binds it.
39 VKMemoryCommit Commit(vk::Image image, bool host_visible);
40
41 /// Returns true if the memory allocations are done always in host visible and coherent memory.
42 bool IsMemoryUnified() const {
43 return is_memory_unified;
44 }
45
46private:
47 /// Allocates a chunk of memory.
48 bool AllocMemory(vk::MemoryPropertyFlags wanted_properties, u32 type_mask, u64 size);
49
50 /// Returns true if the device uses an unified memory model.
51 static bool GetMemoryUnified(const vk::PhysicalDeviceMemoryProperties& props);
52
53 const VKDevice& device; ///< Device handler.
54 const vk::PhysicalDeviceMemoryProperties props; ///< Physical device properties.
55 const bool is_memory_unified; ///< True if memory model is unified.
56 std::vector<std::unique_ptr<VKMemoryAllocation>> allocs; ///< Current allocations.
57};
58
59class VKMemoryCommitImpl final {
60 friend VKMemoryAllocation;
61
62public:
63 explicit VKMemoryCommitImpl(VKMemoryAllocation* allocation, vk::DeviceMemory memory, u8* data,
64 u64 begin, u64 end);
65 ~VKMemoryCommitImpl();
66
67 /// Returns the writeable memory map. The commit has to be mappable.
68 u8* GetData() const;
69
70 /// Returns the Vulkan memory handler.
71 vk::DeviceMemory GetMemory() const {
72 return memory;
73 }
74
75 /// Returns the start position of the commit relative to the allocation.
76 vk::DeviceSize GetOffset() const {
77 return static_cast<vk::DeviceSize>(interval.first);
78 }
79
80private:
81 std::pair<u64, u64> interval{}; ///< Interval where the commit exists.
82 vk::DeviceMemory memory; ///< Vulkan device memory handler.
83 VKMemoryAllocation* allocation{}; ///< Pointer to the large memory allocation.
84 u8* data{}; ///< Pointer to the host mapped memory, it has the commit offset included.
85};
86
87} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp
new file mode 100644
index 000000000..f1fea1871
--- /dev/null
+++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp
@@ -0,0 +1,60 @@
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 "common/logging/log.h"
7#include "video_core/renderer_vulkan/declarations.h"
8#include "video_core/renderer_vulkan/vk_device.h"
9#include "video_core/renderer_vulkan/vk_resource_manager.h"
10#include "video_core/renderer_vulkan/vk_scheduler.h"
11
12namespace Vulkan {
13
14VKScheduler::VKScheduler(const VKDevice& device, VKResourceManager& resource_manager)
15 : device{device}, resource_manager{resource_manager} {
16 next_fence = &resource_manager.CommitFence();
17 AllocateNewContext();
18}
19
20VKScheduler::~VKScheduler() = default;
21
22VKExecutionContext VKScheduler::GetExecutionContext() const {
23 return VKExecutionContext(current_fence, current_cmdbuf);
24}
25
26VKExecutionContext VKScheduler::Flush(vk::Semaphore semaphore) {
27 SubmitExecution(semaphore);
28 current_fence->Release();
29 AllocateNewContext();
30 return GetExecutionContext();
31}
32
33VKExecutionContext VKScheduler::Finish(vk::Semaphore semaphore) {
34 SubmitExecution(semaphore);
35 current_fence->Wait();
36 current_fence->Release();
37 AllocateNewContext();
38 return GetExecutionContext();
39}
40
41void VKScheduler::SubmitExecution(vk::Semaphore semaphore) {
42 const auto& dld = device.GetDispatchLoader();
43 current_cmdbuf.end(dld);
44
45 const auto queue = device.GetGraphicsQueue();
46 const vk::SubmitInfo submit_info(0, nullptr, nullptr, 1, &current_cmdbuf, semaphore ? 1u : 0u,
47 &semaphore);
48 queue.submit({submit_info}, *current_fence, dld);
49}
50
51void VKScheduler::AllocateNewContext() {
52 current_fence = next_fence;
53 current_cmdbuf = resource_manager.CommitCommandBuffer(*current_fence);
54 next_fence = &resource_manager.CommitFence();
55
56 const auto& dld = device.GetDispatchLoader();
57 current_cmdbuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}, dld);
58}
59
60} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h
new file mode 100644
index 000000000..cfaf5376f
--- /dev/null
+++ b/src/video_core/renderer_vulkan/vk_scheduler.h
@@ -0,0 +1,69 @@
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 "common/common_types.h"
8#include "video_core/renderer_vulkan/declarations.h"
9
10namespace Vulkan {
11
12class VKDevice;
13class VKExecutionContext;
14class VKFence;
15class VKResourceManager;
16
17/// The scheduler abstracts command buffer and fence management with an interface that's able to do
18/// OpenGL-like operations on Vulkan command buffers.
19class VKScheduler {
20public:
21 explicit VKScheduler(const VKDevice& device, VKResourceManager& resource_manager);
22 ~VKScheduler();
23
24 /// Gets the current execution context.
25 [[nodiscard]] VKExecutionContext GetExecutionContext() const;
26
27 /// Sends the current execution context to the GPU. It invalidates the current execution context
28 /// and returns a new one.
29 VKExecutionContext Flush(vk::Semaphore semaphore = nullptr);
30
31 /// Sends the current execution context to the GPU and waits for it to complete. It invalidates
32 /// the current execution context and returns a new one.
33 VKExecutionContext Finish(vk::Semaphore semaphore = nullptr);
34
35private:
36 void SubmitExecution(vk::Semaphore semaphore);
37
38 void AllocateNewContext();
39
40 const VKDevice& device;
41 VKResourceManager& resource_manager;
42 vk::CommandBuffer current_cmdbuf;
43 VKFence* current_fence = nullptr;
44 VKFence* next_fence = nullptr;
45};
46
47class VKExecutionContext {
48 friend class VKScheduler;
49
50public:
51 VKExecutionContext() = default;
52
53 VKFence& GetFence() const {
54 return *fence;
55 }
56
57 vk::CommandBuffer GetCommandBuffer() const {
58 return cmdbuf;
59 }
60
61private:
62 explicit VKExecutionContext(VKFence* fence, vk::CommandBuffer cmdbuf)
63 : fence{fence}, cmdbuf{cmdbuf} {}
64
65 VKFence* fence{};
66 vk::CommandBuffer cmdbuf;
67};
68
69} // namespace Vulkan