summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/service/am/am.cpp77
-rw-r--r--src/core/hle/service/am/am.h29
-rw-r--r--src/core/hle/service/am/applet_ae.cpp34
-rw-r--r--src/core/hle/service/am/applet_ae.h6
-rw-r--r--src/core/hle/service/am/applet_oe.cpp21
-rw-r--r--src/core/hle/service/am/applet_oe.h6
-rw-r--r--src/core/settings.h4
-rw-r--r--src/video_core/CMakeLists.txt1
-rw-r--r--src/video_core/engines/maxwell_3d.cpp21
-rw-r--r--src/video_core/engines/maxwell_3d.h14
-rw-r--r--src/video_core/rasterizer_cache.cpp7
-rw-r--r--src/video_core/rasterizer_cache.h9
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.cpp4
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.h4
-rw-r--r--src/video_core/renderer_opengl/gl_primitive_assembler.cpp1
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp138
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h11
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp22
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h4
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp12
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.h17
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp32
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp4
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp8
-rw-r--r--src/video_core/renderer_opengl/gl_state.h4
-rw-r--r--src/video_core/renderer_opengl/maxwell_to_gl.h66
-rw-r--r--src/video_core/surface.cpp4
-rw-r--r--src/video_core/surface.h148
-rw-r--r--src/video_core/textures/decoders.cpp4
-rw-r--r--src/video_core/textures/texture.h13
-rw-r--r--src/yuzu/configuration/configure_general.cpp32
-rw-r--r--src/yuzu/configuration/configure_general.h1
-rw-r--r--src/yuzu/configuration/configure_system.cpp2
-rw-r--r--src/yuzu/main.cpp5
34 files changed, 524 insertions, 241 deletions
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index ac3ff9f20..0477ce66e 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -338,7 +338,54 @@ void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& c
338 LOG_WARNING(Service_AM, "(STUBBED) called"); 338 LOG_WARNING(Service_AM, "(STUBBED) called");
339} 339}
340 340
341ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter") { 341AppletMessageQueue::AppletMessageQueue() {
342 auto& kernel = Core::System::GetInstance().Kernel();
343 on_new_message = Kernel::Event::Create(kernel, Kernel::ResetType::Sticky,
344 "AMMessageQueue:OnMessageRecieved");
345 on_operation_mode_changed = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
346 "AMMessageQueue:OperationModeChanged");
347}
348
349AppletMessageQueue::~AppletMessageQueue() = default;
350
351const Kernel::SharedPtr<Kernel::Event>& AppletMessageQueue::GetMesssageRecieveEvent() const {
352 return on_new_message;
353}
354
355const Kernel::SharedPtr<Kernel::Event>& AppletMessageQueue::GetOperationModeChangedEvent() const {
356 return on_operation_mode_changed;
357}
358
359void AppletMessageQueue::PushMessage(AppletMessage msg) {
360 messages.push(msg);
361 on_new_message->Signal();
362}
363
364AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() {
365 if (messages.empty()) {
366 on_new_message->Clear();
367 return AppletMessage::NoMessage;
368 }
369 auto msg = messages.front();
370 messages.pop();
371 if (messages.empty()) {
372 on_new_message->Clear();
373 }
374 return msg;
375}
376
377std::size_t AppletMessageQueue::GetMessageCount() const {
378 return messages.size();
379}
380
381void AppletMessageQueue::OperationModeChanged() {
382 PushMessage(AppletMessage::OperationModeChanged);
383 PushMessage(AppletMessage::PerformanceModeChanged);
384 on_operation_mode_changed->Signal();
385}
386
387ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_queue)
388 : ServiceFramework("ICommonStateGetter"), msg_queue(std::move(msg_queue)) {
342 // clang-format off 389 // clang-format off
343 static const FunctionInfo functions[] = { 390 static const FunctionInfo functions[] = {
344 {0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"}, 391 {0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"},
@@ -388,21 +435,19 @@ void ICommonStateGetter::GetBootMode(Kernel::HLERequestContext& ctx) {
388} 435}
389 436
390void ICommonStateGetter::GetEventHandle(Kernel::HLERequestContext& ctx) { 437void ICommonStateGetter::GetEventHandle(Kernel::HLERequestContext& ctx) {
391 event->Signal();
392
393 IPC::ResponseBuilder rb{ctx, 2, 1}; 438 IPC::ResponseBuilder rb{ctx, 2, 1};
394 rb.Push(RESULT_SUCCESS); 439 rb.Push(RESULT_SUCCESS);
395 rb.PushCopyObjects(event); 440 rb.PushCopyObjects(msg_queue->GetMesssageRecieveEvent());
396 441
397 LOG_WARNING(Service_AM, "(STUBBED) called"); 442 LOG_DEBUG(Service_AM, "called");
398} 443}
399 444
400void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) { 445void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) {
401 IPC::ResponseBuilder rb{ctx, 3}; 446 IPC::ResponseBuilder rb{ctx, 3};
402 rb.Push(RESULT_SUCCESS); 447 rb.Push(RESULT_SUCCESS);
403 rb.Push<u32>(15); 448 rb.PushEnum<AppletMessageQueue::AppletMessage>(msg_queue->PopMessage());
404 449
405 LOG_WARNING(Service_AM, "(STUBBED) called"); 450 LOG_DEBUG(Service_AM, "called");
406} 451}
407 452
408void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) { 453void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) {
@@ -414,13 +459,11 @@ void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) {
414} 459}
415 460
416void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx) { 461void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx) {
417 event->Signal();
418
419 IPC::ResponseBuilder rb{ctx, 2, 1}; 462 IPC::ResponseBuilder rb{ctx, 2, 1};
420 rb.Push(RESULT_SUCCESS); 463 rb.Push(RESULT_SUCCESS);
421 rb.PushCopyObjects(event); 464 rb.PushCopyObjects(msg_queue->GetOperationModeChangedEvent());
422 465
423 LOG_WARNING(Service_AM, "(STUBBED) called"); 466 LOG_DEBUG(Service_AM, "called");
424} 467}
425 468
426void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx) { 469void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx) {
@@ -444,7 +487,7 @@ void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) {
444 rb.Push(RESULT_SUCCESS); 487 rb.Push(RESULT_SUCCESS);
445 rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld)); 488 rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld));
446 489
447 LOG_WARNING(Service_AM, "(STUBBED) called"); 490 LOG_DEBUG(Service_AM, "called");
448} 491}
449 492
450void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) { 493void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
@@ -454,7 +497,7 @@ void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
454 rb.Push(static_cast<u32>(use_docked_mode ? APM::PerformanceMode::Docked 497 rb.Push(static_cast<u32>(use_docked_mode ? APM::PerformanceMode::Docked
455 : APM::PerformanceMode::Handheld)); 498 : APM::PerformanceMode::Handheld));
456 499
457 LOG_WARNING(Service_AM, "(STUBBED) called"); 500 LOG_DEBUG(Service_AM, "called");
458} 501}
459 502
460class IStorageAccessor final : public ServiceFramework<IStorageAccessor> { 503class IStorageAccessor final : public ServiceFramework<IStorageAccessor> {
@@ -840,8 +883,12 @@ void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) {
840 883
841void InstallInterfaces(SM::ServiceManager& service_manager, 884void InstallInterfaces(SM::ServiceManager& service_manager,
842 std::shared_ptr<NVFlinger::NVFlinger> nvflinger) { 885 std::shared_ptr<NVFlinger::NVFlinger> nvflinger) {
843 std::make_shared<AppletAE>(nvflinger)->InstallAsService(service_manager); 886 auto message_queue = std::make_shared<AppletMessageQueue>();
844 std::make_shared<AppletOE>(nvflinger)->InstallAsService(service_manager); 887 message_queue->PushMessage(
888 AppletMessageQueue::AppletMessage::FocusStateChanged); // Needed on game boot
889
890 std::make_shared<AppletAE>(nvflinger, message_queue)->InstallAsService(service_manager);
891 std::make_shared<AppletOE>(nvflinger, message_queue)->InstallAsService(service_manager);
845 std::make_shared<IdleSys>()->InstallAsService(service_manager); 892 std::make_shared<IdleSys>()->InstallAsService(service_manager);
846 std::make_shared<OMM>()->InstallAsService(service_manager); 893 std::make_shared<OMM>()->InstallAsService(service_manager);
847 std::make_shared<SPSM>()->InstallAsService(service_manager); 894 std::make_shared<SPSM>()->InstallAsService(service_manager);
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 095f94851..2f1c20bce 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <memory> 7#include <memory>
8#include <queue>
8#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
9 10
10namespace Kernel { 11namespace Kernel {
@@ -39,6 +40,31 @@ enum SystemLanguage {
39 TraditionalChinese = 16, 40 TraditionalChinese = 16,
40}; 41};
41 42
43class AppletMessageQueue {
44public:
45 enum class AppletMessage : u32 {
46 NoMessage = 0,
47 FocusStateChanged = 15,
48 OperationModeChanged = 30,
49 PerformanceModeChanged = 31,
50 };
51
52 AppletMessageQueue();
53 ~AppletMessageQueue();
54
55 const Kernel::SharedPtr<Kernel::Event>& GetMesssageRecieveEvent() const;
56 const Kernel::SharedPtr<Kernel::Event>& GetOperationModeChangedEvent() const;
57 void PushMessage(AppletMessage msg);
58 AppletMessage PopMessage();
59 std::size_t GetMessageCount() const;
60 void OperationModeChanged();
61
62private:
63 std::queue<AppletMessage> messages;
64 Kernel::SharedPtr<Kernel::Event> on_new_message;
65 Kernel::SharedPtr<Kernel::Event> on_operation_mode_changed;
66};
67
42class IWindowController final : public ServiceFramework<IWindowController> { 68class IWindowController final : public ServiceFramework<IWindowController> {
43public: 69public:
44 IWindowController(); 70 IWindowController();
@@ -102,7 +128,7 @@ private:
102 128
103class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { 129class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
104public: 130public:
105 ICommonStateGetter(); 131 explicit ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_queue);
106 ~ICommonStateGetter() override; 132 ~ICommonStateGetter() override;
107 133
108private: 134private:
@@ -126,6 +152,7 @@ private:
126 void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx); 152 void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx);
127 153
128 Kernel::SharedPtr<Kernel::Event> event; 154 Kernel::SharedPtr<Kernel::Event> event;
155 std::shared_ptr<AppletMessageQueue> msg_queue;
129}; 156};
130 157
131class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> { 158class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp
index 68ea778e8..ec93e3529 100644
--- a/src/core/hle/service/am/applet_ae.cpp
+++ b/src/core/hle/service/am/applet_ae.cpp
@@ -12,8 +12,10 @@ namespace Service::AM {
12 12
13class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> { 13class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> {
14public: 14public:
15 explicit ILibraryAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) 15 explicit ILibraryAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
16 : ServiceFramework("ILibraryAppletProxy"), nvflinger(std::move(nvflinger)) { 16 std::shared_ptr<AppletMessageQueue> msg_queue)
17 : ServiceFramework("ILibraryAppletProxy"), nvflinger(std::move(nvflinger)),
18 msg_queue(std::move(msg_queue)) {
17 static const FunctionInfo functions[] = { 19 static const FunctionInfo functions[] = {
18 {0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, 20 {0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
19 {1, &ILibraryAppletProxy::GetSelfController, "GetSelfController"}, 21 {1, &ILibraryAppletProxy::GetSelfController, "GetSelfController"},
@@ -32,7 +34,7 @@ private:
32 void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { 34 void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
33 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 35 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
34 rb.Push(RESULT_SUCCESS); 36 rb.Push(RESULT_SUCCESS);
35 rb.PushIpcInterface<ICommonStateGetter>(); 37 rb.PushIpcInterface<ICommonStateGetter>(msg_queue);
36 LOG_DEBUG(Service_AM, "called"); 38 LOG_DEBUG(Service_AM, "called");
37 } 39 }
38 40
@@ -93,12 +95,15 @@ private:
93 } 95 }
94 96
95 std::shared_ptr<NVFlinger::NVFlinger> nvflinger; 97 std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
98 std::shared_ptr<AppletMessageQueue> msg_queue;
96}; 99};
97 100
98class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> { 101class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> {
99public: 102public:
100 explicit ISystemAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) 103 explicit ISystemAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
101 : ServiceFramework("ISystemAppletProxy"), nvflinger(std::move(nvflinger)) { 104 std::shared_ptr<AppletMessageQueue> msg_queue)
105 : ServiceFramework("ISystemAppletProxy"), nvflinger(std::move(nvflinger)),
106 msg_queue(std::move(msg_queue)) {
102 static const FunctionInfo functions[] = { 107 static const FunctionInfo functions[] = {
103 {0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, 108 {0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
104 {1, &ISystemAppletProxy::GetSelfController, "GetSelfController"}, 109 {1, &ISystemAppletProxy::GetSelfController, "GetSelfController"},
@@ -119,7 +124,7 @@ private:
119 void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { 124 void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
120 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 125 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
121 rb.Push(RESULT_SUCCESS); 126 rb.Push(RESULT_SUCCESS);
122 rb.PushIpcInterface<ICommonStateGetter>(); 127 rb.PushIpcInterface<ICommonStateGetter>(msg_queue);
123 LOG_DEBUG(Service_AM, "called"); 128 LOG_DEBUG(Service_AM, "called");
124 } 129 }
125 130
@@ -186,31 +191,34 @@ private:
186 LOG_DEBUG(Service_AM, "called"); 191 LOG_DEBUG(Service_AM, "called");
187 } 192 }
188 std::shared_ptr<NVFlinger::NVFlinger> nvflinger; 193 std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
194 std::shared_ptr<AppletMessageQueue> msg_queue;
189}; 195};
190 196
191void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) { 197void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) {
192 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 198 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
193 rb.Push(RESULT_SUCCESS); 199 rb.Push(RESULT_SUCCESS);
194 rb.PushIpcInterface<ISystemAppletProxy>(nvflinger); 200 rb.PushIpcInterface<ISystemAppletProxy>(nvflinger, msg_queue);
195 LOG_DEBUG(Service_AM, "called"); 201 LOG_DEBUG(Service_AM, "called");
196} 202}
197 203
198void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) { 204void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) {
199 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 205 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
200 rb.Push(RESULT_SUCCESS); 206 rb.Push(RESULT_SUCCESS);
201 rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger); 207 rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue);
202 LOG_DEBUG(Service_AM, "called"); 208 LOG_DEBUG(Service_AM, "called");
203} 209}
204 210
205void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) { 211void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) {
206 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 212 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
207 rb.Push(RESULT_SUCCESS); 213 rb.Push(RESULT_SUCCESS);
208 rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger); 214 rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue);
209 LOG_DEBUG(Service_AM, "called"); 215 LOG_DEBUG(Service_AM, "called");
210} 216}
211 217
212AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) 218AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
213 : ServiceFramework("appletAE"), nvflinger(std::move(nvflinger)) { 219 std::shared_ptr<AppletMessageQueue> msg_queue)
220 : ServiceFramework("appletAE"), nvflinger(std::move(nvflinger)),
221 msg_queue(std::move(msg_queue)) {
214 // clang-format off 222 // clang-format off
215 static const FunctionInfo functions[] = { 223 static const FunctionInfo functions[] = {
216 {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"}, 224 {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"},
@@ -228,4 +236,8 @@ AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
228 236
229AppletAE::~AppletAE() = default; 237AppletAE::~AppletAE() = default;
230 238
239const std::shared_ptr<AppletMessageQueue>& AppletAE::GetMessageQueue() const {
240 return msg_queue;
241}
242
231} // namespace Service::AM 243} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet_ae.h b/src/core/hle/service/am/applet_ae.h
index 1ed77baa4..902db2665 100644
--- a/src/core/hle/service/am/applet_ae.h
+++ b/src/core/hle/service/am/applet_ae.h
@@ -17,15 +17,19 @@ namespace AM {
17 17
18class AppletAE final : public ServiceFramework<AppletAE> { 18class AppletAE final : public ServiceFramework<AppletAE> {
19public: 19public:
20 explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger); 20 explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
21 std::shared_ptr<AppletMessageQueue> msg_queue);
21 ~AppletAE() override; 22 ~AppletAE() override;
22 23
24 const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const;
25
23private: 26private:
24 void OpenSystemAppletProxy(Kernel::HLERequestContext& ctx); 27 void OpenSystemAppletProxy(Kernel::HLERequestContext& ctx);
25 void OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx); 28 void OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx);
26 void OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx); 29 void OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx);
27 30
28 std::shared_ptr<NVFlinger::NVFlinger> nvflinger; 31 std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
32 std::shared_ptr<AppletMessageQueue> msg_queue;
29}; 33};
30 34
31} // namespace AM 35} // namespace AM
diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp
index 60717afd9..20c8d5fff 100644
--- a/src/core/hle/service/am/applet_oe.cpp
+++ b/src/core/hle/service/am/applet_oe.cpp
@@ -12,8 +12,10 @@ namespace Service::AM {
12 12
13class IApplicationProxy final : public ServiceFramework<IApplicationProxy> { 13class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
14public: 14public:
15 explicit IApplicationProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) 15 explicit IApplicationProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
16 : ServiceFramework("IApplicationProxy"), nvflinger(std::move(nvflinger)) { 16 std::shared_ptr<AppletMessageQueue> msg_queue)
17 : ServiceFramework("IApplicationProxy"), nvflinger(std::move(nvflinger)),
18 msg_queue(std::move(msg_queue)) {
17 // clang-format off 19 // clang-format off
18 static const FunctionInfo functions[] = { 20 static const FunctionInfo functions[] = {
19 {0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"}, 21 {0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"},
@@ -70,7 +72,7 @@ private:
70 void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { 72 void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
71 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 73 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
72 rb.Push(RESULT_SUCCESS); 74 rb.Push(RESULT_SUCCESS);
73 rb.PushIpcInterface<ICommonStateGetter>(); 75 rb.PushIpcInterface<ICommonStateGetter>(msg_queue);
74 LOG_DEBUG(Service_AM, "called"); 76 LOG_DEBUG(Service_AM, "called");
75 } 77 }
76 78
@@ -89,17 +91,20 @@ private:
89 } 91 }
90 92
91 std::shared_ptr<NVFlinger::NVFlinger> nvflinger; 93 std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
94 std::shared_ptr<AppletMessageQueue> msg_queue;
92}; 95};
93 96
94void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) { 97void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) {
95 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 98 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
96 rb.Push(RESULT_SUCCESS); 99 rb.Push(RESULT_SUCCESS);
97 rb.PushIpcInterface<IApplicationProxy>(nvflinger); 100 rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue);
98 LOG_DEBUG(Service_AM, "called"); 101 LOG_DEBUG(Service_AM, "called");
99} 102}
100 103
101AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) 104AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
102 : ServiceFramework("appletOE"), nvflinger(std::move(nvflinger)) { 105 std::shared_ptr<AppletMessageQueue> msg_queue)
106 : ServiceFramework("appletOE"), nvflinger(std::move(nvflinger)),
107 msg_queue(std::move(msg_queue)) {
103 static const FunctionInfo functions[] = { 108 static const FunctionInfo functions[] = {
104 {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"}, 109 {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"},
105 }; 110 };
@@ -108,4 +113,8 @@ AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
108 113
109AppletOE::~AppletOE() = default; 114AppletOE::~AppletOE() = default;
110 115
116const std::shared_ptr<AppletMessageQueue>& AppletOE::GetMessageQueue() const {
117 return msg_queue;
118}
119
111} // namespace Service::AM 120} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet_oe.h b/src/core/hle/service/am/applet_oe.h
index 60cfdfd9d..bbd0108ef 100644
--- a/src/core/hle/service/am/applet_oe.h
+++ b/src/core/hle/service/am/applet_oe.h
@@ -17,13 +17,17 @@ namespace AM {
17 17
18class AppletOE final : public ServiceFramework<AppletOE> { 18class AppletOE final : public ServiceFramework<AppletOE> {
19public: 19public:
20 explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger); 20 explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
21 std::shared_ptr<AppletMessageQueue> msg_queue);
21 ~AppletOE() override; 22 ~AppletOE() override;
22 23
24 const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const;
25
23private: 26private:
24 void OpenApplicationProxy(Kernel::HLERequestContext& ctx); 27 void OpenApplicationProxy(Kernel::HLERequestContext& ctx);
25 28
26 std::shared_ptr<NVFlinger::NVFlinger> nvflinger; 29 std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
30 std::shared_ptr<AppletMessageQueue> msg_queue;
27}; 31};
28 32
29} // namespace AM 33} // namespace AM
diff --git a/src/core/settings.h b/src/core/settings.h
index b5aeff29b..a8954647f 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -114,8 +114,8 @@ struct Values {
114 // System 114 // System
115 bool use_docked_mode; 115 bool use_docked_mode;
116 bool enable_nfc; 116 bool enable_nfc;
117 int current_user; 117 s32 current_user;
118 int language_index; 118 s32 language_index;
119 119
120 // Controls 120 // Controls
121 std::array<std::string, NativeButton::NumButtons> buttons; 121 std::array<std::string, NativeButton::NumButtons> buttons;
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 0b1cc1290..a780215c1 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -21,6 +21,7 @@ add_library(video_core STATIC
21 macro_interpreter.h 21 macro_interpreter.h
22 memory_manager.cpp 22 memory_manager.cpp
23 memory_manager.h 23 memory_manager.h
24 rasterizer_cache.cpp
24 rasterizer_cache.h 25 rasterizer_cache.h
25 rasterizer_interface.h 26 rasterizer_interface.h
26 renderer_base.cpp 27 renderer_base.cpp
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 2cd595f26..d1777b25b 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -53,6 +53,19 @@ void Maxwell3D::InitializeRegisterDefaults() {
53 regs.independent_blend[blend_index].factor_source_a = Regs::Blend::Factor::One; 53 regs.independent_blend[blend_index].factor_source_a = Regs::Blend::Factor::One;
54 regs.independent_blend[blend_index].factor_dest_a = Regs::Blend::Factor::Zero; 54 regs.independent_blend[blend_index].factor_dest_a = Regs::Blend::Factor::Zero;
55 } 55 }
56 regs.stencil_front_op_fail = Regs::StencilOp::Keep;
57 regs.stencil_front_op_zfail = Regs::StencilOp::Keep;
58 regs.stencil_front_op_zpass = Regs::StencilOp::Keep;
59 regs.stencil_front_func_func = Regs::ComparisonOp::Always;
60 regs.stencil_front_func_mask = 0xFFFFFFFF;
61 regs.stencil_front_mask = 0xFFFFFFFF;
62 regs.stencil_two_side_enable = 1;
63 regs.stencil_back_op_fail = Regs::StencilOp::Keep;
64 regs.stencil_back_op_zfail = Regs::StencilOp::Keep;
65 regs.stencil_back_op_zpass = Regs::StencilOp::Keep;
66 regs.stencil_back_func_func = Regs::ComparisonOp::Always;
67 regs.stencil_back_func_mask = 0xFFFFFFFF;
68 regs.stencil_back_mask = 0xFFFFFFFF;
56} 69}
57 70
58void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) { 71void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) {
@@ -108,8 +121,16 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
108 debug_context->OnEvent(Tegra::DebugContext::Event::MaxwellCommandLoaded, nullptr); 121 debug_context->OnEvent(Tegra::DebugContext::Event::MaxwellCommandLoaded, nullptr);
109 } 122 }
110 123
124 u32 old = regs.reg_array[method];
111 regs.reg_array[method] = value; 125 regs.reg_array[method] = value;
112 126
127 if (value != old) {
128 if (method >= MAXWELL3D_REG_INDEX(vertex_attrib_format) &&
129 method < MAXWELL3D_REG_INDEX(vertex_attrib_format) + regs.vertex_attrib_format.size()) {
130 dirty_flags.vertex_attrib_format = true;
131 }
132 }
133
113 switch (method) { 134 switch (method) {
114 case MAXWELL3D_REG_INDEX(macros.data): { 135 case MAXWELL3D_REG_INDEX(macros.data): {
115 ProcessMacroUpload(value); 136 ProcessMacroUpload(value);
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 0509ba3a2..91ca57883 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -345,6 +345,14 @@ public:
345 Invert = 6, 345 Invert = 6,
346 IncrWrap = 7, 346 IncrWrap = 7,
347 DecrWrap = 8, 347 DecrWrap = 8,
348 KeepOGL = 0x1E00,
349 ZeroOGL = 0,
350 ReplaceOGL = 0x1E01,
351 IncrOGL = 0x1E02,
352 DecrOGL = 0x1E03,
353 InvertOGL = 0x150A,
354 IncrWrapOGL = 0x8507,
355 DecrWrapOGL = 0x8508,
348 }; 356 };
349 357
350 enum class MemoryLayout : u32 { 358 enum class MemoryLayout : u32 {
@@ -1004,6 +1012,12 @@ public:
1004 State state{}; 1012 State state{};
1005 MemoryManager& memory_manager; 1013 MemoryManager& memory_manager;
1006 1014
1015 struct DirtyFlags {
1016 bool vertex_attrib_format = true;
1017 };
1018
1019 DirtyFlags dirty_flags;
1020
1007 /// Reads a register value located at the input method address 1021 /// Reads a register value located at the input method address
1008 u32 GetRegisterValue(u32 method) const; 1022 u32 GetRegisterValue(u32 method) const;
1009 1023
diff --git a/src/video_core/rasterizer_cache.cpp b/src/video_core/rasterizer_cache.cpp
new file mode 100644
index 000000000..093b2cdf4
--- /dev/null
+++ b/src/video_core/rasterizer_cache.cpp
@@ -0,0 +1,7 @@
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 "video_core/rasterizer_cache.h"
6
7RasterizerCacheObject::~RasterizerCacheObject() = default;
diff --git a/src/video_core/rasterizer_cache.h b/src/video_core/rasterizer_cache.h
index 0a3b3951e..6d41321fa 100644
--- a/src/video_core/rasterizer_cache.h
+++ b/src/video_core/rasterizer_cache.h
@@ -10,13 +10,13 @@
10#include <boost/range/iterator_range_core.hpp> 10#include <boost/range/iterator_range_core.hpp>
11 11
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "core/core.h"
14#include "core/settings.h" 13#include "core/settings.h"
15#include "video_core/rasterizer_interface.h" 14#include "video_core/rasterizer_interface.h"
16#include "video_core/renderer_base.h"
17 15
18class RasterizerCacheObject { 16class RasterizerCacheObject {
19public: 17public:
18 virtual ~RasterizerCacheObject();
19
20 /// Gets the address of the shader in guest memory, required for cache management 20 /// Gets the address of the shader in guest memory, required for cache management
21 virtual VAddr GetAddr() const = 0; 21 virtual VAddr GetAddr() const = 0;
22 22
@@ -64,6 +64,8 @@ class RasterizerCache : NonCopyable {
64 friend class RasterizerCacheObject; 64 friend class RasterizerCacheObject;
65 65
66public: 66public:
67 explicit RasterizerCache(VideoCore::RasterizerInterface& rasterizer) : rasterizer{rasterizer} {}
68
67 /// Write any cached resources overlapping the specified region back to memory 69 /// Write any cached resources overlapping the specified region back to memory
68 void FlushRegion(Tegra::GPUVAddr addr, size_t size) { 70 void FlushRegion(Tegra::GPUVAddr addr, size_t size) {
69 const auto& objects{GetSortedObjectsFromRegion(addr, size)}; 71 const auto& objects{GetSortedObjectsFromRegion(addr, size)};
@@ -109,14 +111,12 @@ protected:
109 void Register(const T& object) { 111 void Register(const T& object) {
110 object->SetIsRegistered(true); 112 object->SetIsRegistered(true);
111 object_cache.add({GetInterval(object), ObjectSet{object}}); 113 object_cache.add({GetInterval(object), ObjectSet{object}});
112 auto& rasterizer = Core::System::GetInstance().Renderer().Rasterizer();
113 rasterizer.UpdatePagesCachedCount(object->GetAddr(), object->GetSizeInBytes(), 1); 114 rasterizer.UpdatePagesCachedCount(object->GetAddr(), object->GetSizeInBytes(), 1);
114 } 115 }
115 116
116 /// Unregisters an object from the cache 117 /// Unregisters an object from the cache
117 void Unregister(const T& object) { 118 void Unregister(const T& object) {
118 object->SetIsRegistered(false); 119 object->SetIsRegistered(false);
119 auto& rasterizer = Core::System::GetInstance().Renderer().Rasterizer();
120 rasterizer.UpdatePagesCachedCount(object->GetAddr(), object->GetSizeInBytes(), -1); 120 rasterizer.UpdatePagesCachedCount(object->GetAddr(), object->GetSizeInBytes(), -1);
121 121
122 // Only flush if use_accurate_gpu_emulation is enabled, as it incurs a performance hit 122 // Only flush if use_accurate_gpu_emulation is enabled, as it incurs a performance hit
@@ -177,4 +177,5 @@ private:
177 177
178 ObjectCache object_cache; ///< Cache of objects 178 ObjectCache object_cache; ///< Cache of objects
179 u64 modified_ticks{}; ///< Counter of cache state ticks, used for in-order flushing 179 u64 modified_ticks{}; ///< Counter of cache state ticks, used for in-order flushing
180 VideoCore::RasterizerInterface& rasterizer;
180}; 181};
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
index 41a54b3e7..075192c3f 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
@@ -9,10 +9,12 @@
9#include "core/core.h" 9#include "core/core.h"
10#include "core/memory.h" 10#include "core/memory.h"
11#include "video_core/renderer_opengl/gl_buffer_cache.h" 11#include "video_core/renderer_opengl/gl_buffer_cache.h"
12#include "video_core/renderer_opengl/gl_rasterizer.h"
12 13
13namespace OpenGL { 14namespace OpenGL {
14 15
15OGLBufferCache::OGLBufferCache(std::size_t size) : stream_buffer(GL_ARRAY_BUFFER, size) {} 16OGLBufferCache::OGLBufferCache(RasterizerOpenGL& rasterizer, std::size_t size)
17 : RasterizerCache{rasterizer}, stream_buffer(GL_ARRAY_BUFFER, size) {}
16 18
17GLintptr OGLBufferCache::UploadMemory(Tegra::GPUVAddr gpu_addr, std::size_t size, 19GLintptr OGLBufferCache::UploadMemory(Tegra::GPUVAddr gpu_addr, std::size_t size,
18 std::size_t alignment, bool cache) { 20 std::size_t alignment, bool cache) {
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.h b/src/video_core/renderer_opengl/gl_buffer_cache.h
index be29dc8be..91fca3f6c 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.h
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.h
@@ -15,6 +15,8 @@
15 15
16namespace OpenGL { 16namespace OpenGL {
17 17
18class RasterizerOpenGL;
19
18struct CachedBufferEntry final : public RasterizerCacheObject { 20struct CachedBufferEntry final : public RasterizerCacheObject {
19 VAddr GetAddr() const override { 21 VAddr GetAddr() const override {
20 return addr; 22 return addr;
@@ -35,7 +37,7 @@ struct CachedBufferEntry final : public RasterizerCacheObject {
35 37
36class OGLBufferCache final : public RasterizerCache<std::shared_ptr<CachedBufferEntry>> { 38class OGLBufferCache final : public RasterizerCache<std::shared_ptr<CachedBufferEntry>> {
37public: 39public:
38 explicit OGLBufferCache(std::size_t size); 40 explicit OGLBufferCache(RasterizerOpenGL& rasterizer, std::size_t size);
39 41
40 /// Uploads data from a guest GPU address. Returns host's buffer offset where it's been 42 /// Uploads data from a guest GPU address. Returns host's buffer offset where it's been
41 /// allocated. 43 /// allocated.
diff --git a/src/video_core/renderer_opengl/gl_primitive_assembler.cpp b/src/video_core/renderer_opengl/gl_primitive_assembler.cpp
index 741f14bc3..d9ed08437 100644
--- a/src/video_core/renderer_opengl/gl_primitive_assembler.cpp
+++ b/src/video_core/renderer_opengl/gl_primitive_assembler.cpp
@@ -6,6 +6,7 @@
6#include <array> 6#include <array>
7#include "common/assert.h" 7#include "common/assert.h"
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "core/core.h"
9#include "core/memory.h" 10#include "core/memory.h"
10#include "video_core/renderer_opengl/gl_buffer_cache.h" 11#include "video_core/renderer_opengl/gl_buffer_cache.h"
11#include "video_core/renderer_opengl/gl_primitive_assembler.h" 12#include "video_core/renderer_opengl/gl_primitive_assembler.h"
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index bb263b6aa..54cc47a9b 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -33,7 +33,8 @@ using Maxwell = Tegra::Engines::Maxwell3D::Regs;
33using PixelFormat = VideoCore::Surface::PixelFormat; 33using PixelFormat = VideoCore::Surface::PixelFormat;
34using SurfaceType = VideoCore::Surface::SurfaceType; 34using SurfaceType = VideoCore::Surface::SurfaceType;
35 35
36MICROPROFILE_DEFINE(OpenGL_VAO, "OpenGL", "Vertex Array Setup", MP_RGB(128, 128, 192)); 36MICROPROFILE_DEFINE(OpenGL_VAO, "OpenGL", "Vertex Format Setup", MP_RGB(128, 128, 192));
37MICROPROFILE_DEFINE(OpenGL_VB, "OpenGL", "Vertex Buffer Setup", MP_RGB(128, 128, 192));
37MICROPROFILE_DEFINE(OpenGL_Shader, "OpenGL", "Shader Setup", MP_RGB(128, 128, 192)); 38MICROPROFILE_DEFINE(OpenGL_Shader, "OpenGL", "Shader Setup", MP_RGB(128, 128, 192));
38MICROPROFILE_DEFINE(OpenGL_UBO, "OpenGL", "Const Buffer Setup", MP_RGB(128, 128, 192)); 39MICROPROFILE_DEFINE(OpenGL_UBO, "OpenGL", "Const Buffer Setup", MP_RGB(128, 128, 192));
39MICROPROFILE_DEFINE(OpenGL_Index, "OpenGL", "Index Buffer Setup", MP_RGB(128, 128, 192)); 40MICROPROFILE_DEFINE(OpenGL_Index, "OpenGL", "Index Buffer Setup", MP_RGB(128, 128, 192));
@@ -79,7 +80,8 @@ struct DrawParameters {
79}; 80};
80 81
81RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo& info) 82RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo& info)
82 : emu_window{window}, screen_info{info}, buffer_cache(STREAM_BUFFER_SIZE) { 83 : res_cache{*this}, shader_cache{*this}, emu_window{window}, screen_info{info},
84 buffer_cache(*this, STREAM_BUFFER_SIZE) {
83 // Create sampler objects 85 // Create sampler objects
84 for (std::size_t i = 0; i < texture_samplers.size(); ++i) { 86 for (std::size_t i = 0; i < texture_samplers.size(); ++i) {
85 texture_samplers[i].Create(); 87 texture_samplers[i].Create();
@@ -122,18 +124,23 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo
122 124
123RasterizerOpenGL::~RasterizerOpenGL() {} 125RasterizerOpenGL::~RasterizerOpenGL() {}
124 126
125void RasterizerOpenGL::SetupVertexArrays() { 127void RasterizerOpenGL::SetupVertexFormat() {
126 MICROPROFILE_SCOPE(OpenGL_VAO); 128 auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
127 const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
128 const auto& regs = gpu.regs; 129 const auto& regs = gpu.regs;
129 130
131 if (!gpu.dirty_flags.vertex_attrib_format)
132 return;
133 gpu.dirty_flags.vertex_attrib_format = false;
134
135 MICROPROFILE_SCOPE(OpenGL_VAO);
136
130 auto [iter, is_cache_miss] = vertex_array_cache.try_emplace(regs.vertex_attrib_format); 137 auto [iter, is_cache_miss] = vertex_array_cache.try_emplace(regs.vertex_attrib_format);
131 auto& VAO = iter->second; 138 auto& VAO = iter->second;
132 139
133 if (is_cache_miss) { 140 if (is_cache_miss) {
134 VAO.Create(); 141 VAO.Create();
135 state.draw.vertex_array = VAO.handle; 142 state.draw.vertex_array = VAO.handle;
136 state.Apply(); 143 state.ApplyVertexBufferState();
137 144
138 // The index buffer binding is stored within the VAO. Stupid OpenGL, but easy to work 145 // The index buffer binding is stored within the VAO. Stupid OpenGL, but easy to work
139 // around. 146 // around.
@@ -175,8 +182,13 @@ void RasterizerOpenGL::SetupVertexArrays() {
175 } 182 }
176 } 183 }
177 state.draw.vertex_array = VAO.handle; 184 state.draw.vertex_array = VAO.handle;
178 state.draw.vertex_buffer = buffer_cache.GetHandle(); 185 state.ApplyVertexBufferState();
179 state.Apply(); 186}
187
188void RasterizerOpenGL::SetupVertexBuffer() {
189 MICROPROFILE_SCOPE(OpenGL_VB);
190 const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
191 const auto& regs = gpu.regs;
180 192
181 // Upload all guest vertex arrays sequentially to our buffer 193 // Upload all guest vertex arrays sequentially to our buffer
182 for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) { 194 for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) {
@@ -203,6 +215,9 @@ void RasterizerOpenGL::SetupVertexArrays() {
203 glVertexBindingDivisor(index, 0); 215 glVertexBindingDivisor(index, 0);
204 } 216 }
205 } 217 }
218
219 // Implicit set by glBindVertexBuffer. Stupid glstate handling...
220 state.draw.vertex_buffer = buffer_cache.GetHandle();
206} 221}
207 222
208DrawParameters RasterizerOpenGL::SetupDraw() { 223DrawParameters RasterizerOpenGL::SetupDraw() {
@@ -327,8 +342,6 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
327 index++; 342 index++;
328 } 343 }
329 } 344 }
330
331 state.Apply();
332} 345}
333 346
334std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const { 347std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const {
@@ -397,8 +410,8 @@ void RasterizerOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
397 cached_pages.add({pages_interval, delta}); 410 cached_pages.add({pages_interval, delta});
398} 411}
399 412
400void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_depth_fb, 413void RasterizerOpenGL::ConfigureFramebuffers(OpenGLState& current_state, bool using_color_fb,
401 bool preserve_contents, 414 bool using_depth_fb, bool preserve_contents,
402 std::optional<std::size_t> single_color_target) { 415 std::optional<std::size_t> single_color_target) {
403 MICROPROFILE_SCOPE(OpenGL_Framebuffer); 416 MICROPROFILE_SCOPE(OpenGL_Framebuffer);
404 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 417 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
@@ -414,9 +427,9 @@ void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_dep
414 ASSERT_MSG(regs.rt_separate_frag_data == 0, "Unimplemented"); 427 ASSERT_MSG(regs.rt_separate_frag_data == 0, "Unimplemented");
415 428
416 // Bind the framebuffer surfaces 429 // Bind the framebuffer surfaces
417 state.draw.draw_framebuffer = framebuffer.handle; 430 current_state.draw.draw_framebuffer = framebuffer.handle;
418 state.Apply(); 431 current_state.ApplyFramebufferState();
419 state.framebuffer_srgb.enabled = regs.framebuffer_srgb != 0; 432 current_state.framebuffer_srgb.enabled = regs.framebuffer_srgb != 0;
420 433
421 if (using_color_fb) { 434 if (using_color_fb) {
422 if (single_color_target) { 435 if (single_color_target) {
@@ -494,10 +507,7 @@ void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_dep
494 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 507 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
495 0); 508 0);
496 } 509 }
497 510 SyncViewport(current_state);
498 SyncViewport();
499
500 state.Apply();
501} 511}
502 512
503void RasterizerOpenGL::Clear() { 513void RasterizerOpenGL::Clear() {
@@ -510,22 +520,23 @@ void RasterizerOpenGL::Clear() {
510 bool use_stencil{}; 520 bool use_stencil{};
511 521
512 OpenGLState clear_state; 522 OpenGLState clear_state;
513 clear_state.draw.draw_framebuffer = framebuffer.handle;
514 clear_state.color_mask[0].red_enabled = regs.clear_buffers.R ? GL_TRUE : GL_FALSE;
515 clear_state.color_mask[0].green_enabled = regs.clear_buffers.G ? GL_TRUE : GL_FALSE;
516 clear_state.color_mask[0].blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE;
517 clear_state.color_mask[0].alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE;
518
519 if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B || 523 if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B ||
520 regs.clear_buffers.A) { 524 regs.clear_buffers.A) {
521 use_color = true; 525 use_color = true;
522 } 526 }
527 if (use_color) {
528 clear_state.color_mask[0].red_enabled = regs.clear_buffers.R ? GL_TRUE : GL_FALSE;
529 clear_state.color_mask[0].green_enabled = regs.clear_buffers.G ? GL_TRUE : GL_FALSE;
530 clear_state.color_mask[0].blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE;
531 clear_state.color_mask[0].alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE;
532 }
523 if (regs.clear_buffers.Z) { 533 if (regs.clear_buffers.Z) {
524 ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear Z but buffer is not enabled!"); 534 ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear Z but buffer is not enabled!");
525 use_depth = true; 535 use_depth = true;
526 536
527 // Always enable the depth write when clearing the depth buffer. The depth write mask is 537 // Always enable the depth write when clearing the depth buffer. The depth write mask is
528 // ignored when clearing the buffer in the Switch, but OpenGL obeys it so we set it to true. 538 // ignored when clearing the buffer in the Switch, but OpenGL obeys it so we set it to
539 // true.
529 clear_state.depth.test_enabled = true; 540 clear_state.depth.test_enabled = true;
530 clear_state.depth.test_func = GL_ALWAYS; 541 clear_state.depth.test_func = GL_ALWAYS;
531 } 542 }
@@ -542,11 +553,8 @@ void RasterizerOpenGL::Clear() {
542 553
543 ScopeAcquireGLContext acquire_context{emu_window}; 554 ScopeAcquireGLContext acquire_context{emu_window};
544 555
545 ConfigureFramebuffers(use_color, use_depth || use_stencil, false, 556 ConfigureFramebuffers(clear_state, use_color, use_depth || use_stencil, false,
546 regs.clear_buffers.RT.Value()); 557 regs.clear_buffers.RT.Value());
547 // Copy the sRGB setting to the clear state to avoid problem with
548 // specific driver implementations
549 clear_state.framebuffer_srgb.enabled = state.framebuffer_srgb.enabled;
550 clear_state.Apply(); 558 clear_state.Apply();
551 559
552 if (use_color) { 560 if (use_color) {
@@ -572,7 +580,7 @@ void RasterizerOpenGL::DrawArrays() {
572 580
573 ScopeAcquireGLContext acquire_context{emu_window}; 581 ScopeAcquireGLContext acquire_context{emu_window};
574 582
575 ConfigureFramebuffers(); 583 ConfigureFramebuffers(state);
576 SyncColorMask(); 584 SyncColorMask();
577 SyncDepthTestState(); 585 SyncDepthTestState();
578 SyncStencilTestState(); 586 SyncStencilTestState();
@@ -593,7 +601,7 @@ void RasterizerOpenGL::DrawArrays() {
593 const bool is_indexed = accelerate_draw == AccelDraw::Indexed; 601 const bool is_indexed = accelerate_draw == AccelDraw::Indexed;
594 602
595 state.draw.vertex_buffer = buffer_cache.GetHandle(); 603 state.draw.vertex_buffer = buffer_cache.GetHandle();
596 state.Apply(); 604 state.ApplyVertexBufferState();
597 605
598 std::size_t buffer_size = CalculateVertexArraysSize(); 606 std::size_t buffer_size = CalculateVertexArraysSize();
599 607
@@ -620,7 +628,8 @@ void RasterizerOpenGL::DrawArrays() {
620 628
621 buffer_cache.Map(buffer_size); 629 buffer_cache.Map(buffer_size);
622 630
623 SetupVertexArrays(); 631 SetupVertexFormat();
632 SetupVertexBuffer();
624 DrawParameters params = SetupDraw(); 633 DrawParameters params = SetupDraw();
625 SetupShaders(params.primitive_mode); 634 SetupShaders(params.primitive_mode);
626 635
@@ -724,9 +733,9 @@ void RasterizerOpenGL::SamplerInfo::Create() {
724 glSamplerParameteri(sampler.handle, GL_TEXTURE_COMPARE_FUNC, GL_NEVER); 733 glSamplerParameteri(sampler.handle, GL_TEXTURE_COMPARE_FUNC, GL_NEVER);
725} 734}
726 735
727void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntry& config) { 736void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::FullTextureInfo& info) {
728 const GLuint s = sampler.handle; 737 const GLuint s = sampler.handle;
729 738 const Tegra::Texture::TSCEntry& config = info.tsc;
730 if (mag_filter != config.mag_filter) { 739 if (mag_filter != config.mag_filter) {
731 mag_filter = config.mag_filter; 740 mag_filter = config.mag_filter;
732 glSamplerParameteri( 741 glSamplerParameteri(
@@ -777,6 +786,22 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr
777 glSamplerParameterfv(s, GL_TEXTURE_BORDER_COLOR, border_color.data()); 786 glSamplerParameterfv(s, GL_TEXTURE_BORDER_COLOR, border_color.data());
778 } 787 }
779 } 788 }
789 if (info.tic.use_header_opt_control == 0) {
790 if (GLAD_GL_ARB_texture_filter_anisotropic) {
791 glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY,
792 static_cast<float>(1 << info.tic.max_anisotropy.Value()));
793 } else if (GLAD_GL_EXT_texture_filter_anisotropic) {
794 glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY_EXT,
795 static_cast<float>(1 << info.tic.max_anisotropy.Value()));
796 }
797 glSamplerParameterf(s, GL_TEXTURE_MIN_LOD,
798 static_cast<float>(info.tic.res_min_mip_level.Value()));
799 glSamplerParameterf(s, GL_TEXTURE_MAX_LOD,
800 static_cast<float>(info.tic.res_max_mip_level.Value() == 0
801 ? 16
802 : info.tic.res_max_mip_level.Value()));
803 glSamplerParameterf(s, GL_TEXTURE_LOD_BIAS, info.tic.mip_lod_bias.Value() / 256.f);
804 }
780} 805}
781 806
782u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, Shader& shader, 807u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, Shader& shader,
@@ -874,7 +899,7 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader,
874 continue; 899 continue;
875 } 900 }
876 901
877 texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc); 902 texture_samplers[current_bindpoint].SyncWithConfig(texture);
878 Surface surface = res_cache.GetTextureSurface(texture, entry); 903 Surface surface = res_cache.GetTextureSurface(texture, entry);
879 if (surface != nullptr) { 904 if (surface != nullptr) {
880 state.texture_units[current_bindpoint].texture = surface->Texture().handle; 905 state.texture_units[current_bindpoint].texture = surface->Texture().handle;
@@ -896,15 +921,15 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader,
896 return current_unit + static_cast<u32>(entries.size()); 921 return current_unit + static_cast<u32>(entries.size());
897} 922}
898 923
899void RasterizerOpenGL::SyncViewport() { 924void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) {
900 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 925 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
901 for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { 926 for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
902 const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()}; 927 const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()};
903 auto& viewport = state.viewports[i]; 928 auto& viewport = current_state.viewports[i];
904 viewport.x = viewport_rect.left; 929 viewport.x = viewport_rect.left;
905 viewport.y = viewport_rect.bottom; 930 viewport.y = viewport_rect.bottom;
906 viewport.width = static_cast<GLsizei>(viewport_rect.GetWidth()); 931 viewport.width = static_cast<GLfloat>(viewport_rect.GetWidth());
907 viewport.height = static_cast<GLsizei>(viewport_rect.GetHeight()); 932 viewport.height = static_cast<GLfloat>(viewport_rect.GetHeight());
908 viewport.depth_range_far = regs.viewport[i].depth_range_far; 933 viewport.depth_range_far = regs.viewport[i].depth_range_far;
909 viewport.depth_range_near = regs.viewport[i].depth_range_near; 934 viewport.depth_range_near = regs.viewport[i].depth_range_near;
910 } 935 }
@@ -969,9 +994,6 @@ void RasterizerOpenGL::SyncStencilTestState() {
969 return; 994 return;
970 } 995 }
971 996
972 // TODO(bunnei): Verify behavior when this is not set
973 ASSERT(regs.stencil_two_side_enable);
974
975 state.stencil.front.test_func = MaxwellToGL::ComparisonOp(regs.stencil_front_func_func); 997 state.stencil.front.test_func = MaxwellToGL::ComparisonOp(regs.stencil_front_func_func);
976 state.stencil.front.test_ref = regs.stencil_front_func_ref; 998 state.stencil.front.test_ref = regs.stencil_front_func_ref;
977 state.stencil.front.test_mask = regs.stencil_front_func_mask; 999 state.stencil.front.test_mask = regs.stencil_front_func_mask;
@@ -979,14 +1001,23 @@ void RasterizerOpenGL::SyncStencilTestState() {
979 state.stencil.front.action_depth_fail = MaxwellToGL::StencilOp(regs.stencil_front_op_zfail); 1001 state.stencil.front.action_depth_fail = MaxwellToGL::StencilOp(regs.stencil_front_op_zfail);
980 state.stencil.front.action_depth_pass = MaxwellToGL::StencilOp(regs.stencil_front_op_zpass); 1002 state.stencil.front.action_depth_pass = MaxwellToGL::StencilOp(regs.stencil_front_op_zpass);
981 state.stencil.front.write_mask = regs.stencil_front_mask; 1003 state.stencil.front.write_mask = regs.stencil_front_mask;
982 1004 if (regs.stencil_two_side_enable) {
983 state.stencil.back.test_func = MaxwellToGL::ComparisonOp(regs.stencil_back_func_func); 1005 state.stencil.back.test_func = MaxwellToGL::ComparisonOp(regs.stencil_back_func_func);
984 state.stencil.back.test_ref = regs.stencil_back_func_ref; 1006 state.stencil.back.test_ref = regs.stencil_back_func_ref;
985 state.stencil.back.test_mask = regs.stencil_back_func_mask; 1007 state.stencil.back.test_mask = regs.stencil_back_func_mask;
986 state.stencil.back.action_stencil_fail = MaxwellToGL::StencilOp(regs.stencil_back_op_fail); 1008 state.stencil.back.action_stencil_fail = MaxwellToGL::StencilOp(regs.stencil_back_op_fail);
987 state.stencil.back.action_depth_fail = MaxwellToGL::StencilOp(regs.stencil_back_op_zfail); 1009 state.stencil.back.action_depth_fail = MaxwellToGL::StencilOp(regs.stencil_back_op_zfail);
988 state.stencil.back.action_depth_pass = MaxwellToGL::StencilOp(regs.stencil_back_op_zpass); 1010 state.stencil.back.action_depth_pass = MaxwellToGL::StencilOp(regs.stencil_back_op_zpass);
989 state.stencil.back.write_mask = regs.stencil_back_mask; 1011 state.stencil.back.write_mask = regs.stencil_back_mask;
1012 } else {
1013 state.stencil.back.test_func = GL_ALWAYS;
1014 state.stencil.back.test_ref = 0;
1015 state.stencil.back.test_mask = 0xFFFFFFFF;
1016 state.stencil.back.write_mask = 0xFFFFFFFF;
1017 state.stencil.back.action_stencil_fail = GL_KEEP;
1018 state.stencil.back.action_depth_fail = GL_KEEP;
1019 state.stencil.back.action_depth_pass = GL_KEEP;
1020 }
990} 1021}
991 1022
992void RasterizerOpenGL::SyncColorMask() { 1023void RasterizerOpenGL::SyncColorMask() {
@@ -1098,9 +1129,8 @@ void RasterizerOpenGL::CheckAlphaTests() {
1098 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 1129 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
1099 1130
1100 if (regs.alpha_test_enabled != 0 && regs.rt_control.count > 1) { 1131 if (regs.alpha_test_enabled != 0 && regs.rt_control.count > 1) {
1101 LOG_CRITICAL( 1132 LOG_CRITICAL(Render_OpenGL, "Alpha Testing is enabled with Multiple Render Targets, "
1102 Render_OpenGL, 1133 "this behavior is undefined.");
1103 "Alpha Testing is enabled with Multiple Render Targets, this behavior is undefined.");
1104 UNREACHABLE(); 1134 UNREACHABLE();
1105 } 1135 }
1106} 1136}
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 60e783803..8ef0f6c12 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -88,7 +88,7 @@ private:
88 /// SamplerInfo struct. 88 /// SamplerInfo struct.
89 void Create(); 89 void Create();
90 /// Syncs the sampler object with the config, updating any necessary state. 90 /// Syncs the sampler object with the config, updating any necessary state.
91 void SyncWithConfig(const Tegra::Texture::TSCEntry& config); 91 void SyncWithConfig(const Tegra::Texture::FullTextureInfo& info);
92 92
93 private: 93 private:
94 Tegra::Texture::TextureFilter mag_filter; 94 Tegra::Texture::TextureFilter mag_filter;
@@ -109,8 +109,8 @@ private:
109 * @param preserve_contents If true, tries to preserve data from a previously used framebuffer. 109 * @param preserve_contents If true, tries to preserve data from a previously used framebuffer.
110 * @param single_color_target Specifies if a single color buffer target should be used. 110 * @param single_color_target Specifies if a single color buffer target should be used.
111 */ 111 */
112 void ConfigureFramebuffers(bool use_color_fb = true, bool using_depth_fb = true, 112 void ConfigureFramebuffers(OpenGLState& current_state, bool use_color_fb = true,
113 bool preserve_contents = true, 113 bool using_depth_fb = true, bool preserve_contents = true,
114 std::optional<std::size_t> single_color_target = {}); 114 std::optional<std::size_t> single_color_target = {});
115 115
116 /* 116 /*
@@ -134,7 +134,7 @@ private:
134 GLenum primitive_mode, u32 current_unit); 134 GLenum primitive_mode, u32 current_unit);
135 135
136 /// Syncs the viewport and depth range to match the guest state 136 /// Syncs the viewport and depth range to match the guest state
137 void SyncViewport(); 137 void SyncViewport(OpenGLState& current_state);
138 138
139 /// Syncs the clip enabled status to match the guest state 139 /// Syncs the clip enabled status to match the guest state
140 void SyncClipEnabled(); 140 void SyncClipEnabled();
@@ -207,7 +207,8 @@ private:
207 207
208 std::size_t CalculateIndexBufferSize() const; 208 std::size_t CalculateIndexBufferSize() const;
209 209
210 void SetupVertexArrays(); 210 void SetupVertexFormat();
211 void SetupVertexBuffer();
211 212
212 DrawParameters SetupDraw(); 213 DrawParameters SetupDraw();
213 214
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 49d63e6f3..24cd88d06 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -15,6 +15,7 @@
15#include "core/memory.h" 15#include "core/memory.h"
16#include "core/settings.h" 16#include "core/settings.h"
17#include "video_core/engines/maxwell_3d.h" 17#include "video_core/engines/maxwell_3d.h"
18#include "video_core/renderer_opengl/gl_rasterizer.h"
18#include "video_core/renderer_opengl/gl_rasterizer_cache.h" 19#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
19#include "video_core/renderer_opengl/gl_state.h" 20#include "video_core/renderer_opengl/gl_state.h"
20#include "video_core/renderer_opengl/utils.h" 21#include "video_core/renderer_opengl/utils.h"
@@ -313,6 +314,8 @@ static constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex
313 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X4_SRGB 314 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X4_SRGB
314 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X5 315 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X5
315 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X5_SRGB 316 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X5_SRGB
317 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_10X8
318 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_10X8_SRGB
316 319
317 // Depth formats 320 // Depth formats
318 {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, ComponentType::Float, false}, // Z32F 321 {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, ComponentType::Float, false}, // Z32F
@@ -455,6 +458,8 @@ static constexpr GLConversionArray morton_to_gl_fns = {
455 MortonCopy<true, PixelFormat::ASTC_2D_5X4_SRGB>, 458 MortonCopy<true, PixelFormat::ASTC_2D_5X4_SRGB>,
456 MortonCopy<true, PixelFormat::ASTC_2D_5X5>, 459 MortonCopy<true, PixelFormat::ASTC_2D_5X5>,
457 MortonCopy<true, PixelFormat::ASTC_2D_5X5_SRGB>, 460 MortonCopy<true, PixelFormat::ASTC_2D_5X5_SRGB>,
461 MortonCopy<true, PixelFormat::ASTC_2D_10X8>,
462 MortonCopy<true, PixelFormat::ASTC_2D_10X8_SRGB>,
458 MortonCopy<true, PixelFormat::Z32F>, 463 MortonCopy<true, PixelFormat::Z32F>,
459 MortonCopy<true, PixelFormat::Z16>, 464 MortonCopy<true, PixelFormat::Z16>,
460 MortonCopy<true, PixelFormat::Z24S8>, 465 MortonCopy<true, PixelFormat::Z24S8>,
@@ -525,6 +530,8 @@ static constexpr GLConversionArray gl_to_morton_fns = {
525 nullptr, 530 nullptr,
526 nullptr, 531 nullptr,
527 nullptr, 532 nullptr,
533 nullptr,
534 nullptr,
528 MortonCopy<false, PixelFormat::Z32F>, 535 MortonCopy<false, PixelFormat::Z32F>,
529 MortonCopy<false, PixelFormat::Z16>, 536 MortonCopy<false, PixelFormat::Z16>,
530 MortonCopy<false, PixelFormat::Z24S8>, 537 MortonCopy<false, PixelFormat::Z24S8>,
@@ -579,7 +586,7 @@ static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface,
579 state.draw.draw_framebuffer = draw_fb_handle; 586 state.draw.draw_framebuffer = draw_fb_handle;
580 // Set sRGB enabled if the destination surfaces need it 587 // Set sRGB enabled if the destination surfaces need it
581 state.framebuffer_srgb.enabled = dst_params.srgb_conversion; 588 state.framebuffer_srgb.enabled = dst_params.srgb_conversion;
582 state.Apply(); 589 state.ApplyFramebufferState();
583 590
584 u32 buffers{}; 591 u32 buffers{};
585 592
@@ -931,7 +938,9 @@ static void ConvertFormatAsNeeded_LoadGLBuffer(std::vector<u8>& data, PixelForma
931 case PixelFormat::ASTC_2D_8X8_SRGB: 938 case PixelFormat::ASTC_2D_8X8_SRGB:
932 case PixelFormat::ASTC_2D_8X5_SRGB: 939 case PixelFormat::ASTC_2D_8X5_SRGB:
933 case PixelFormat::ASTC_2D_5X4_SRGB: 940 case PixelFormat::ASTC_2D_5X4_SRGB:
934 case PixelFormat::ASTC_2D_5X5_SRGB: { 941 case PixelFormat::ASTC_2D_5X5_SRGB:
942 case PixelFormat::ASTC_2D_10X8:
943 case PixelFormat::ASTC_2D_10X8_SRGB: {
935 // Convert ASTC pixel formats to RGBA8, as most desktop GPUs do not support ASTC. 944 // Convert ASTC pixel formats to RGBA8, as most desktop GPUs do not support ASTC.
936 u32 block_width{}; 945 u32 block_width{};
937 u32 block_height{}; 946 u32 block_height{};
@@ -966,7 +975,11 @@ static void ConvertFormatAsNeeded_FlushGLBuffer(std::vector<u8>& data, PixelForm
966 case PixelFormat::ASTC_2D_4X4: 975 case PixelFormat::ASTC_2D_4X4:
967 case PixelFormat::ASTC_2D_8X8: 976 case PixelFormat::ASTC_2D_8X8:
968 case PixelFormat::ASTC_2D_4X4_SRGB: 977 case PixelFormat::ASTC_2D_4X4_SRGB:
969 case PixelFormat::ASTC_2D_8X8_SRGB: { 978 case PixelFormat::ASTC_2D_8X8_SRGB:
979 case PixelFormat::ASTC_2D_5X5:
980 case PixelFormat::ASTC_2D_5X5_SRGB:
981 case PixelFormat::ASTC_2D_10X8:
982 case PixelFormat::ASTC_2D_10X8_SRGB: {
970 LOG_CRITICAL(HW_GPU, "Conversion of format {} after texture flushing is not implemented", 983 LOG_CRITICAL(HW_GPU, "Conversion of format {} after texture flushing is not implemented",
971 static_cast<u32>(pixel_format)); 984 static_cast<u32>(pixel_format));
972 UNREACHABLE(); 985 UNREACHABLE();
@@ -1172,7 +1185,8 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle
1172 UploadGLMipmapTexture(i, read_fb_handle, draw_fb_handle); 1185 UploadGLMipmapTexture(i, read_fb_handle, draw_fb_handle);
1173} 1186}
1174 1187
1175RasterizerCacheOpenGL::RasterizerCacheOpenGL() { 1188RasterizerCacheOpenGL::RasterizerCacheOpenGL(RasterizerOpenGL& rasterizer)
1189 : RasterizerCache{rasterizer} {
1176 read_framebuffer.Create(); 1190 read_framebuffer.Create();
1177 draw_framebuffer.Create(); 1191 draw_framebuffer.Create();
1178 copy_pbo.Create(); 1192 copy_pbo.Create();
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index c0b6bc4e6..494f6b903 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -264,6 +264,8 @@ struct hash<SurfaceReserveKey> {
264 264
265namespace OpenGL { 265namespace OpenGL {
266 266
267class RasterizerOpenGL;
268
267class CachedSurface final : public RasterizerCacheObject { 269class CachedSurface final : public RasterizerCacheObject {
268public: 270public:
269 CachedSurface(const SurfaceParams& params); 271 CachedSurface(const SurfaceParams& params);
@@ -311,7 +313,7 @@ private:
311 313
312class RasterizerCacheOpenGL final : public RasterizerCache<Surface> { 314class RasterizerCacheOpenGL final : public RasterizerCache<Surface> {
313public: 315public:
314 RasterizerCacheOpenGL(); 316 explicit RasterizerCacheOpenGL(RasterizerOpenGL& rasterizer);
315 317
316 /// Get a surface based on the texture configuration 318 /// Get a surface based on the texture configuration
317 Surface GetTextureSurface(const Tegra::Texture::FullTextureInfo& config, 319 Surface GetTextureSurface(const Tegra::Texture::FullTextureInfo& config,
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index 9522fd344..a85a7c0c5 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -6,10 +6,10 @@
6#include "core/core.h" 6#include "core/core.h"
7#include "core/memory.h" 7#include "core/memory.h"
8#include "video_core/engines/maxwell_3d.h" 8#include "video_core/engines/maxwell_3d.h"
9#include "video_core/renderer_opengl/gl_rasterizer.h"
9#include "video_core/renderer_opengl/gl_shader_cache.h" 10#include "video_core/renderer_opengl/gl_shader_cache.h"
10#include "video_core/renderer_opengl/gl_shader_manager.h" 11#include "video_core/renderer_opengl/gl_shader_manager.h"
11#include "video_core/renderer_opengl/utils.h" 12#include "video_core/renderer_opengl/utils.h"
12#include "video_core/utils.h"
13 13
14namespace OpenGL { 14namespace OpenGL {
15 15
@@ -121,12 +121,16 @@ GLint CachedShader::GetUniformLocation(const GLShader::SamplerEntry& sampler) {
121} 121}
122 122
123GLuint CachedShader::LazyGeometryProgram(OGLProgram& target_program, 123GLuint CachedShader::LazyGeometryProgram(OGLProgram& target_program,
124 const std::string& glsl_topology, 124 const std::string& glsl_topology, u32 max_vertices,
125 const std::string& debug_name) { 125 const std::string& debug_name) {
126 if (target_program.handle != 0) { 126 if (target_program.handle != 0) {
127 return target_program.handle; 127 return target_program.handle;
128 } 128 }
129 const std::string source{geometry_programs.code + "layout (" + glsl_topology + ") in;\n"}; 129 std::string source = "#version 430 core\n";
130 source += "layout (" + glsl_topology + ") in;\n";
131 source += "#define MAX_VERTEX_INPUT " + std::to_string(max_vertices) + '\n';
132 source += geometry_programs.code;
133
130 OGLShader shader; 134 OGLShader shader;
131 shader.Create(source.c_str(), GL_GEOMETRY_SHADER); 135 shader.Create(source.c_str(), GL_GEOMETRY_SHADER);
132 target_program.Create(true, shader.handle); 136 target_program.Create(true, shader.handle);
@@ -135,6 +139,8 @@ GLuint CachedShader::LazyGeometryProgram(OGLProgram& target_program,
135 return target_program.handle; 139 return target_program.handle;
136}; 140};
137 141
142ShaderCacheOpenGL::ShaderCacheOpenGL(RasterizerOpenGL& rasterizer) : RasterizerCache{rasterizer} {}
143
138Shader ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) { 144Shader ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) {
139 const VAddr program_addr{GetShaderAddress(program)}; 145 const VAddr program_addr{GetShaderAddress(program)};
140 146
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h
index a210f1731..ffbf21831 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.h
+++ b/src/video_core/renderer_opengl/gl_shader_cache.h
@@ -16,6 +16,8 @@
16namespace OpenGL { 16namespace OpenGL {
17 17
18class CachedShader; 18class CachedShader;
19class RasterizerOpenGL;
20
19using Shader = std::shared_ptr<CachedShader>; 21using Shader = std::shared_ptr<CachedShader>;
20using Maxwell = Tegra::Engines::Maxwell3D::Regs; 22using Maxwell = Tegra::Engines::Maxwell3D::Regs;
21 23
@@ -46,22 +48,23 @@ public:
46 } 48 }
47 switch (primitive_mode) { 49 switch (primitive_mode) {
48 case GL_POINTS: 50 case GL_POINTS:
49 return LazyGeometryProgram(geometry_programs.points, "points", "ShaderPoints"); 51 return LazyGeometryProgram(geometry_programs.points, "points", 1, "ShaderPoints");
50 case GL_LINES: 52 case GL_LINES:
51 case GL_LINE_STRIP: 53 case GL_LINE_STRIP:
52 return LazyGeometryProgram(geometry_programs.lines, "lines", "ShaderLines"); 54 return LazyGeometryProgram(geometry_programs.lines, "lines", 2, "ShaderLines");
53 case GL_LINES_ADJACENCY: 55 case GL_LINES_ADJACENCY:
54 case GL_LINE_STRIP_ADJACENCY: 56 case GL_LINE_STRIP_ADJACENCY:
55 return LazyGeometryProgram(geometry_programs.lines_adjacency, "lines_adjacency", 57 return LazyGeometryProgram(geometry_programs.lines_adjacency, "lines_adjacency", 4,
56 "ShaderLinesAdjacency"); 58 "ShaderLinesAdjacency");
57 case GL_TRIANGLES: 59 case GL_TRIANGLES:
58 case GL_TRIANGLE_STRIP: 60 case GL_TRIANGLE_STRIP:
59 case GL_TRIANGLE_FAN: 61 case GL_TRIANGLE_FAN:
60 return LazyGeometryProgram(geometry_programs.triangles, "triangles", "ShaderTriangles"); 62 return LazyGeometryProgram(geometry_programs.triangles, "triangles", 3,
63 "ShaderTriangles");
61 case GL_TRIANGLES_ADJACENCY: 64 case GL_TRIANGLES_ADJACENCY:
62 case GL_TRIANGLE_STRIP_ADJACENCY: 65 case GL_TRIANGLE_STRIP_ADJACENCY:
63 return LazyGeometryProgram(geometry_programs.triangles_adjacency, "triangles_adjacency", 66 return LazyGeometryProgram(geometry_programs.triangles_adjacency, "triangles_adjacency",
64 "ShaderLines"); 67 6, "ShaderTrianglesAdjacency");
65 default: 68 default:
66 UNREACHABLE_MSG("Unknown primitive mode."); 69 UNREACHABLE_MSG("Unknown primitive mode.");
67 } 70 }
@@ -76,7 +79,7 @@ public:
76private: 79private:
77 /// Generates a geometry shader or returns one that already exists. 80 /// Generates a geometry shader or returns one that already exists.
78 GLuint LazyGeometryProgram(OGLProgram& target_program, const std::string& glsl_topology, 81 GLuint LazyGeometryProgram(OGLProgram& target_program, const std::string& glsl_topology,
79 const std::string& debug_name); 82 u32 max_vertices, const std::string& debug_name);
80 83
81 VAddr addr; 84 VAddr addr;
82 Maxwell::ShaderProgram program_type; 85 Maxwell::ShaderProgram program_type;
@@ -104,6 +107,8 @@ private:
104 107
105class ShaderCacheOpenGL final : public RasterizerCache<Shader> { 108class ShaderCacheOpenGL final : public RasterizerCache<Shader> {
106public: 109public:
110 explicit ShaderCacheOpenGL(RasterizerOpenGL& rasterizer);
111
107 /// Gets the current specified shader stage program 112 /// Gets the current specified shader stage program
108 Shader GetStageProgram(Maxwell::ShaderProgram program); 113 Shader GetStageProgram(Maxwell::ShaderProgram program);
109}; 114};
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 09b003c59..5fde22ad4 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -494,10 +494,10 @@ public:
494 // instruction for now. 494 // instruction for now.
495 if (stage == Maxwell3D::Regs::ShaderStage::Geometry) { 495 if (stage == Maxwell3D::Regs::ShaderStage::Geometry) {
496 // TODO(Rodrigo): nouveau sets some attributes after setting emitting a geometry 496 // TODO(Rodrigo): nouveau sets some attributes after setting emitting a geometry
497 // shader. These instructions use a dirty register as buffer index. To avoid some 497 // shader. These instructions use a dirty register as buffer index, to avoid some
498 // drivers from complaining for the out of boundary writes, guard them. 498 // drivers from complaining about out of boundary writes, guard them.
499 const std::string buf_index{"min(" + GetRegisterAsInteger(buf_reg) + ", " + 499 const std::string buf_index{"((" + GetRegisterAsInteger(buf_reg) + ") % " +
500 std::to_string(MAX_GEOMETRY_BUFFERS - 1) + ')'}; 500 std::to_string(MAX_GEOMETRY_BUFFERS) + ')'};
501 shader.AddLine("amem[" + buf_index + "][" + 501 shader.AddLine("amem[" + buf_index + "][" +
502 std::to_string(static_cast<u32>(attribute)) + ']' + 502 std::to_string(static_cast<u32>(attribute)) + ']' +
503 GetSwizzle(elem) + " = " + src + ';'); 503 GetSwizzle(elem) + " = " + src + ';');
@@ -811,7 +811,11 @@ private:
811 std::optional<Register> vertex = {}) { 811 std::optional<Register> vertex = {}) {
812 auto GeometryPass = [&](const std::string& name) { 812 auto GeometryPass = [&](const std::string& name) {
813 if (stage == Maxwell3D::Regs::ShaderStage::Geometry && vertex) { 813 if (stage == Maxwell3D::Regs::ShaderStage::Geometry && vertex) {
814 return "gs_" + name + '[' + GetRegisterAsInteger(*vertex, 0, false) + ']'; 814 // TODO(Rodrigo): Guard geometry inputs against out of bound reads. Some games set
815 // an 0x80000000 index for those and the shader fails to build. Find out why this
816 // happens and what's its intent.
817 return "gs_" + name + '[' + GetRegisterAsInteger(*vertex, 0, false) +
818 " % MAX_VERTEX_INPUT]";
815 } 819 }
816 return name; 820 return name;
817 }; 821 };
@@ -2742,12 +2746,12 @@ private:
2742 } 2746 }
2743 case 3: { 2747 case 3: {
2744 if (is_array) { 2748 if (is_array) {
2745 UNIMPLEMENTED_MSG("3-coordinate arrays not fully implemented"); 2749 const std::string index = regs.GetRegisterAsInteger(instr.gpr8);
2746 const std::string x = regs.GetRegisterAsFloat(instr.gpr8); 2750 const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2747 const std::string y = regs.GetRegisterAsFloat(instr.gpr20); 2751 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 2);
2748 coord = "vec2 coords = vec2(" + x + ", " + y + ");"; 2752 const std::string z = regs.GetRegisterAsFloat(instr.gpr20);
2749 texture_type = Tegra::Shader::TextureType::Texture2D; 2753 coord =
2750 is_array = false; 2754 "vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + index + ");";
2751 } else { 2755 } else {
2752 const std::string x = regs.GetRegisterAsFloat(instr.gpr8); 2756 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
2753 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); 2757 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
@@ -2777,7 +2781,11 @@ private:
2777 break; 2781 break;
2778 } 2782 }
2779 case Tegra::Shader::TextureProcessMode::LZ: { 2783 case Tegra::Shader::TextureProcessMode::LZ: {
2780 texture = "textureLod(" + sampler + ", coords, 0.0)"; 2784 if (depth_compare && is_array) {
2785 texture = "texture(" + sampler + ", coords)";
2786 } else {
2787 texture = "textureLod(" + sampler + ", coords, 0.0)";
2788 }
2781 break; 2789 break;
2782 } 2790 }
2783 case Tegra::Shader::TextureProcessMode::LL: { 2791 case Tegra::Shader::TextureProcessMode::LL: {
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index 9d17edd63..eea090e52 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -82,8 +82,8 @@ void main() {
82} 82}
83 83
84ProgramResult GenerateGeometryShader(const ShaderSetup& setup) { 84ProgramResult GenerateGeometryShader(const ShaderSetup& setup) {
85 std::string out = "#version 430 core\n"; 85 // Version is intentionally skipped in shader generation, it's added by the lazy compilation.
86 out += "#extension GL_ARB_separate_shader_objects : enable\n\n"; 86 std::string out = "#extension GL_ARB_separate_shader_objects : enable\n\n";
87 out += Decompiler::GetCommonDeclarations(); 87 out += Decompiler::GetCommonDeclarations();
88 out += "bool exec_geometry();\n"; 88 out += "bool exec_geometry();\n";
89 89
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index 9517285e5..2635f2b0c 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -427,7 +427,7 @@ void OpenGLState::ApplySamplers() const {
427 } 427 }
428} 428}
429 429
430void OpenGLState::Apply() const { 430void OpenGLState::ApplyFramebufferState() const {
431 // Framebuffer 431 // Framebuffer
432 if (draw.read_framebuffer != cur_state.draw.read_framebuffer) { 432 if (draw.read_framebuffer != cur_state.draw.read_framebuffer) {
433 glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer); 433 glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer);
@@ -435,7 +435,9 @@ void OpenGLState::Apply() const {
435 if (draw.draw_framebuffer != cur_state.draw.draw_framebuffer) { 435 if (draw.draw_framebuffer != cur_state.draw.draw_framebuffer) {
436 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, draw.draw_framebuffer); 436 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, draw.draw_framebuffer);
437 } 437 }
438}
438 439
440void OpenGLState::ApplyVertexBufferState() const {
439 // Vertex array 441 // Vertex array
440 if (draw.vertex_array != cur_state.draw.vertex_array) { 442 if (draw.vertex_array != cur_state.draw.vertex_array) {
441 glBindVertexArray(draw.vertex_array); 443 glBindVertexArray(draw.vertex_array);
@@ -445,7 +447,11 @@ void OpenGLState::Apply() const {
445 if (draw.vertex_buffer != cur_state.draw.vertex_buffer) { 447 if (draw.vertex_buffer != cur_state.draw.vertex_buffer) {
446 glBindBuffer(GL_ARRAY_BUFFER, draw.vertex_buffer); 448 glBindBuffer(GL_ARRAY_BUFFER, draw.vertex_buffer);
447 } 449 }
450}
448 451
452void OpenGLState::Apply() const {
453 ApplyFramebufferState();
454 ApplyVertexBufferState();
449 // Uniform buffer 455 // Uniform buffer
450 if (draw.uniform_buffer != cur_state.draw.uniform_buffer) { 456 if (draw.uniform_buffer != cur_state.draw.uniform_buffer) {
451 glBindBuffer(GL_UNIFORM_BUFFER, draw.uniform_buffer); 457 glBindBuffer(GL_UNIFORM_BUFFER, draw.uniform_buffer);
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index b8cf1f637..eacca0b9c 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -181,6 +181,10 @@ public:
181 } 181 }
182 /// Apply this state as the current OpenGL state 182 /// Apply this state as the current OpenGL state
183 void Apply() const; 183 void Apply() const;
184 /// Apply only the state afecting the framebuffer
185 void ApplyFramebufferState() const;
186 /// Apply only the state afecting the vertex buffer
187 void ApplyVertexBufferState() const;
184 /// Set the initial OpenGL state 188 /// Set the initial OpenGL state
185 static void ApplyDefaultState(); 189 static void ApplyDefaultState();
186 /// Resets any references to the given resource 190 /// Resets any references to the given resource
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h
index 87d511c38..3ce2cc6d2 100644
--- a/src/video_core/renderer_opengl/maxwell_to_gl.h
+++ b/src/video_core/renderer_opengl/maxwell_to_gl.h
@@ -159,10 +159,8 @@ inline GLenum TextureFilterMode(Tegra::Texture::TextureFilter filter_mode,
159 } 159 }
160 } 160 }
161 } 161 }
162 LOG_CRITICAL(Render_OpenGL, "Unimplemented texture filter mode={}", 162 LOG_ERROR(Render_OpenGL, "Unimplemented texture filter mode={}", static_cast<u32>(filter_mode));
163 static_cast<u32>(filter_mode)); 163 return GL_LINEAR;
164 UNREACHABLE();
165 return {};
166} 164}
167 165
168inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) { 166inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) {
@@ -183,9 +181,8 @@ inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) {
183 case Tegra::Texture::WrapMode::MirrorOnceClampToEdge: 181 case Tegra::Texture::WrapMode::MirrorOnceClampToEdge:
184 return GL_MIRROR_CLAMP_TO_EDGE; 182 return GL_MIRROR_CLAMP_TO_EDGE;
185 } 183 }
186 LOG_CRITICAL(Render_OpenGL, "Unimplemented texture wrap mode={}", static_cast<u32>(wrap_mode)); 184 LOG_ERROR(Render_OpenGL, "Unimplemented texture wrap mode={}", static_cast<u32>(wrap_mode));
187 UNREACHABLE(); 185 return GL_REPEAT;
188 return {};
189} 186}
190 187
191inline GLenum DepthCompareFunc(Tegra::Texture::DepthCompareFunc func) { 188inline GLenum DepthCompareFunc(Tegra::Texture::DepthCompareFunc func) {
@@ -207,10 +204,9 @@ inline GLenum DepthCompareFunc(Tegra::Texture::DepthCompareFunc func) {
207 case Tegra::Texture::DepthCompareFunc::Always: 204 case Tegra::Texture::DepthCompareFunc::Always:
208 return GL_ALWAYS; 205 return GL_ALWAYS;
209 } 206 }
210 LOG_CRITICAL(Render_OpenGL, "Unimplemented texture depth compare function ={}", 207 LOG_ERROR(Render_OpenGL, "Unimplemented texture depth compare function ={}",
211 static_cast<u32>(func)); 208 static_cast<u32>(func));
212 UNREACHABLE(); 209 return GL_GREATER;
213 return {};
214} 210}
215 211
216inline GLenum BlendEquation(Maxwell::Blend::Equation equation) { 212inline GLenum BlendEquation(Maxwell::Blend::Equation equation) {
@@ -226,9 +222,8 @@ inline GLenum BlendEquation(Maxwell::Blend::Equation equation) {
226 case Maxwell::Blend::Equation::Max: 222 case Maxwell::Blend::Equation::Max:
227 return GL_MAX; 223 return GL_MAX;
228 } 224 }
229 LOG_CRITICAL(Render_OpenGL, "Unimplemented blend equation={}", static_cast<u32>(equation)); 225 LOG_ERROR(Render_OpenGL, "Unimplemented blend equation={}", static_cast<u32>(equation));
230 UNREACHABLE(); 226 return GL_FUNC_ADD;
231 return {};
232} 227}
233 228
234inline GLenum BlendFunc(Maxwell::Blend::Factor factor) { 229inline GLenum BlendFunc(Maxwell::Blend::Factor factor) {
@@ -291,9 +286,8 @@ inline GLenum BlendFunc(Maxwell::Blend::Factor factor) {
291 case Maxwell::Blend::Factor::OneMinusConstantAlphaGL: 286 case Maxwell::Blend::Factor::OneMinusConstantAlphaGL:
292 return GL_ONE_MINUS_CONSTANT_ALPHA; 287 return GL_ONE_MINUS_CONSTANT_ALPHA;
293 } 288 }
294 LOG_CRITICAL(Render_OpenGL, "Unimplemented blend factor={}", static_cast<u32>(factor)); 289 LOG_ERROR(Render_OpenGL, "Unimplemented blend factor={}", static_cast<u32>(factor));
295 UNREACHABLE(); 290 return GL_ZERO;
296 return {};
297} 291}
298 292
299inline GLenum SwizzleSource(Tegra::Texture::SwizzleSource source) { 293inline GLenum SwizzleSource(Tegra::Texture::SwizzleSource source) {
@@ -312,9 +306,8 @@ inline GLenum SwizzleSource(Tegra::Texture::SwizzleSource source) {
312 case Tegra::Texture::SwizzleSource::OneFloat: 306 case Tegra::Texture::SwizzleSource::OneFloat:
313 return GL_ONE; 307 return GL_ONE;
314 } 308 }
315 LOG_CRITICAL(Render_OpenGL, "Unimplemented swizzle source={}", static_cast<u32>(source)); 309 LOG_ERROR(Render_OpenGL, "Unimplemented swizzle source={}", static_cast<u32>(source));
316 UNREACHABLE(); 310 return GL_ZERO;
317 return {};
318} 311}
319 312
320inline GLenum ComparisonOp(Maxwell::ComparisonOp comparison) { 313inline GLenum ComparisonOp(Maxwell::ComparisonOp comparison) {
@@ -344,33 +337,39 @@ inline GLenum ComparisonOp(Maxwell::ComparisonOp comparison) {
344 case Maxwell::ComparisonOp::AlwaysOld: 337 case Maxwell::ComparisonOp::AlwaysOld:
345 return GL_ALWAYS; 338 return GL_ALWAYS;
346 } 339 }
347 LOG_CRITICAL(Render_OpenGL, "Unimplemented comparison op={}", static_cast<u32>(comparison)); 340 LOG_ERROR(Render_OpenGL, "Unimplemented comparison op={}", static_cast<u32>(comparison));
348 UNREACHABLE(); 341 return GL_ALWAYS;
349 return {};
350} 342}
351 343
352inline GLenum StencilOp(Maxwell::StencilOp stencil) { 344inline GLenum StencilOp(Maxwell::StencilOp stencil) {
353 switch (stencil) { 345 switch (stencil) {
354 case Maxwell::StencilOp::Keep: 346 case Maxwell::StencilOp::Keep:
347 case Maxwell::StencilOp::KeepOGL:
355 return GL_KEEP; 348 return GL_KEEP;
356 case Maxwell::StencilOp::Zero: 349 case Maxwell::StencilOp::Zero:
350 case Maxwell::StencilOp::ZeroOGL:
357 return GL_ZERO; 351 return GL_ZERO;
358 case Maxwell::StencilOp::Replace: 352 case Maxwell::StencilOp::Replace:
353 case Maxwell::StencilOp::ReplaceOGL:
359 return GL_REPLACE; 354 return GL_REPLACE;
360 case Maxwell::StencilOp::Incr: 355 case Maxwell::StencilOp::Incr:
356 case Maxwell::StencilOp::IncrOGL:
361 return GL_INCR; 357 return GL_INCR;
362 case Maxwell::StencilOp::Decr: 358 case Maxwell::StencilOp::Decr:
359 case Maxwell::StencilOp::DecrOGL:
363 return GL_DECR; 360 return GL_DECR;
364 case Maxwell::StencilOp::Invert: 361 case Maxwell::StencilOp::Invert:
362 case Maxwell::StencilOp::InvertOGL:
365 return GL_INVERT; 363 return GL_INVERT;
366 case Maxwell::StencilOp::IncrWrap: 364 case Maxwell::StencilOp::IncrWrap:
365 case Maxwell::StencilOp::IncrWrapOGL:
367 return GL_INCR_WRAP; 366 return GL_INCR_WRAP;
368 case Maxwell::StencilOp::DecrWrap: 367 case Maxwell::StencilOp::DecrWrap:
368 case Maxwell::StencilOp::DecrWrapOGL:
369 return GL_DECR_WRAP; 369 return GL_DECR_WRAP;
370 } 370 }
371 LOG_CRITICAL(Render_OpenGL, "Unimplemented stencil op={}", static_cast<u32>(stencil)); 371 LOG_ERROR(Render_OpenGL, "Unimplemented stencil op={}", static_cast<u32>(stencil));
372 UNREACHABLE(); 372 return GL_KEEP;
373 return {};
374} 373}
375 374
376inline GLenum FrontFace(Maxwell::Cull::FrontFace front_face) { 375inline GLenum FrontFace(Maxwell::Cull::FrontFace front_face) {
@@ -380,9 +379,8 @@ inline GLenum FrontFace(Maxwell::Cull::FrontFace front_face) {
380 case Maxwell::Cull::FrontFace::CounterClockWise: 379 case Maxwell::Cull::FrontFace::CounterClockWise:
381 return GL_CCW; 380 return GL_CCW;
382 } 381 }
383 LOG_CRITICAL(Render_OpenGL, "Unimplemented front face cull={}", static_cast<u32>(front_face)); 382 LOG_ERROR(Render_OpenGL, "Unimplemented front face cull={}", static_cast<u32>(front_face));
384 UNREACHABLE(); 383 return GL_CCW;
385 return {};
386} 384}
387 385
388inline GLenum CullFace(Maxwell::Cull::CullFace cull_face) { 386inline GLenum CullFace(Maxwell::Cull::CullFace cull_face) {
@@ -394,9 +392,8 @@ inline GLenum CullFace(Maxwell::Cull::CullFace cull_face) {
394 case Maxwell::Cull::CullFace::FrontAndBack: 392 case Maxwell::Cull::CullFace::FrontAndBack:
395 return GL_FRONT_AND_BACK; 393 return GL_FRONT_AND_BACK;
396 } 394 }
397 LOG_CRITICAL(Render_OpenGL, "Unimplemented cull face={}", static_cast<u32>(cull_face)); 395 LOG_ERROR(Render_OpenGL, "Unimplemented cull face={}", static_cast<u32>(cull_face));
398 UNREACHABLE(); 396 return GL_BACK;
399 return {};
400} 397}
401 398
402inline GLenum LogicOp(Maxwell::LogicOperation operation) { 399inline GLenum LogicOp(Maxwell::LogicOperation operation) {
@@ -434,9 +431,8 @@ inline GLenum LogicOp(Maxwell::LogicOperation operation) {
434 case Maxwell::LogicOperation::Set: 431 case Maxwell::LogicOperation::Set:
435 return GL_SET; 432 return GL_SET;
436 } 433 }
437 LOG_CRITICAL(Render_OpenGL, "Unimplemented logic operation={}", static_cast<u32>(operation)); 434 LOG_ERROR(Render_OpenGL, "Unimplemented logic operation={}", static_cast<u32>(operation));
438 UNREACHABLE(); 435 return GL_COPY;
439 return {};
440} 436}
441 437
442} // namespace MaxwellToGL 438} // namespace MaxwellToGL
diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp
index 051ad3964..9582dd2ca 100644
--- a/src/video_core/surface.cpp
+++ b/src/video_core/surface.cpp
@@ -306,6 +306,8 @@ PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format,
306 return is_srgb ? PixelFormat::ASTC_2D_8X8_SRGB : PixelFormat::ASTC_2D_8X8; 306 return is_srgb ? PixelFormat::ASTC_2D_8X8_SRGB : PixelFormat::ASTC_2D_8X8;
307 case Tegra::Texture::TextureFormat::ASTC_2D_8X5: 307 case Tegra::Texture::TextureFormat::ASTC_2D_8X5:
308 return is_srgb ? PixelFormat::ASTC_2D_8X5_SRGB : PixelFormat::ASTC_2D_8X5; 308 return is_srgb ? PixelFormat::ASTC_2D_8X5_SRGB : PixelFormat::ASTC_2D_8X5;
309 case Tegra::Texture::TextureFormat::ASTC_2D_10X8:
310 return is_srgb ? PixelFormat::ASTC_2D_10X8_SRGB : PixelFormat::ASTC_2D_10X8;
309 case Tegra::Texture::TextureFormat::R16_G16: 311 case Tegra::Texture::TextureFormat::R16_G16:
310 switch (component_type) { 312 switch (component_type) {
311 case Tegra::Texture::ComponentType::FLOAT: 313 case Tegra::Texture::ComponentType::FLOAT:
@@ -453,6 +455,8 @@ bool IsPixelFormatASTC(PixelFormat format) {
453 case PixelFormat::ASTC_2D_5X5_SRGB: 455 case PixelFormat::ASTC_2D_5X5_SRGB:
454 case PixelFormat::ASTC_2D_8X8_SRGB: 456 case PixelFormat::ASTC_2D_8X8_SRGB:
455 case PixelFormat::ASTC_2D_8X5_SRGB: 457 case PixelFormat::ASTC_2D_8X5_SRGB:
458 case PixelFormat::ASTC_2D_10X8:
459 case PixelFormat::ASTC_2D_10X8_SRGB:
456 return true; 460 return true;
457 default: 461 default:
458 return false; 462 return false;
diff --git a/src/video_core/surface.h b/src/video_core/surface.h
index dfdb8d122..0dd3eb2e4 100644
--- a/src/video_core/surface.h
+++ b/src/video_core/surface.h
@@ -74,19 +74,21 @@ enum class PixelFormat {
74 ASTC_2D_5X4_SRGB = 56, 74 ASTC_2D_5X4_SRGB = 56,
75 ASTC_2D_5X5 = 57, 75 ASTC_2D_5X5 = 57,
76 ASTC_2D_5X5_SRGB = 58, 76 ASTC_2D_5X5_SRGB = 58,
77 ASTC_2D_10X8 = 59,
78 ASTC_2D_10X8_SRGB = 60,
77 79
78 MaxColorFormat, 80 MaxColorFormat,
79 81
80 // Depth formats 82 // Depth formats
81 Z32F = 59, 83 Z32F = 61,
82 Z16 = 60, 84 Z16 = 62,
83 85
84 MaxDepthFormat, 86 MaxDepthFormat,
85 87
86 // DepthStencil formats 88 // DepthStencil formats
87 Z24S8 = 61, 89 Z24S8 = 63,
88 S8Z24 = 62, 90 S8Z24 = 64,
89 Z32FS8 = 63, 91 Z32FS8 = 65,
90 92
91 MaxDepthStencilFormat, 93 MaxDepthStencilFormat,
92 94
@@ -193,6 +195,8 @@ static constexpr u32 GetCompressionFactor(PixelFormat format) {
193 4, // ASTC_2D_5X4_SRGB 195 4, // ASTC_2D_5X4_SRGB
194 4, // ASTC_2D_5X5 196 4, // ASTC_2D_5X5
195 4, // ASTC_2D_5X5_SRGB 197 4, // ASTC_2D_5X5_SRGB
198 4, // ASTC_2D_10X8
199 4, // ASTC_2D_10X8_SRGB
196 1, // Z32F 200 1, // Z32F
197 1, // Z16 201 1, // Z16
198 1, // Z24S8 202 1, // Z24S8
@@ -208,70 +212,72 @@ static constexpr u32 GetDefaultBlockWidth(PixelFormat format) {
208 if (format == PixelFormat::Invalid) 212 if (format == PixelFormat::Invalid)
209 return 0; 213 return 0;
210 constexpr std::array<u32, MaxPixelFormat> block_width_table = {{ 214 constexpr std::array<u32, MaxPixelFormat> block_width_table = {{
211 1, // ABGR8U 215 1, // ABGR8U
212 1, // ABGR8S 216 1, // ABGR8S
213 1, // ABGR8UI 217 1, // ABGR8UI
214 1, // B5G6R5U 218 1, // B5G6R5U
215 1, // A2B10G10R10U 219 1, // A2B10G10R10U
216 1, // A1B5G5R5U 220 1, // A1B5G5R5U
217 1, // R8U 221 1, // R8U
218 1, // R8UI 222 1, // R8UI
219 1, // RGBA16F 223 1, // RGBA16F
220 1, // RGBA16U 224 1, // RGBA16U
221 1, // RGBA16UI 225 1, // RGBA16UI
222 1, // R11FG11FB10F 226 1, // R11FG11FB10F
223 1, // RGBA32UI 227 1, // RGBA32UI
224 4, // DXT1 228 4, // DXT1
225 4, // DXT23 229 4, // DXT23
226 4, // DXT45 230 4, // DXT45
227 4, // DXN1 231 4, // DXN1
228 4, // DXN2UNORM 232 4, // DXN2UNORM
229 4, // DXN2SNORM 233 4, // DXN2SNORM
230 4, // BC7U 234 4, // BC7U
231 4, // BC6H_UF16 235 4, // BC6H_UF16
232 4, // BC6H_SF16 236 4, // BC6H_SF16
233 4, // ASTC_2D_4X4 237 4, // ASTC_2D_4X4
234 1, // G8R8U 238 1, // G8R8U
235 1, // G8R8S 239 1, // G8R8S
236 1, // BGRA8 240 1, // BGRA8
237 1, // RGBA32F 241 1, // RGBA32F
238 1, // RG32F 242 1, // RG32F
239 1, // R32F 243 1, // R32F
240 1, // R16F 244 1, // R16F
241 1, // R16U 245 1, // R16U
242 1, // R16S 246 1, // R16S
243 1, // R16UI 247 1, // R16UI
244 1, // R16I 248 1, // R16I
245 1, // RG16 249 1, // RG16
246 1, // RG16F 250 1, // RG16F
247 1, // RG16UI 251 1, // RG16UI
248 1, // RG16I 252 1, // RG16I
249 1, // RG16S 253 1, // RG16S
250 1, // RGB32F 254 1, // RGB32F
251 1, // RGBA8_SRGB 255 1, // RGBA8_SRGB
252 1, // RG8U 256 1, // RG8U
253 1, // RG8S 257 1, // RG8S
254 1, // RG32UI 258 1, // RG32UI
255 1, // R32UI 259 1, // R32UI
256 8, // ASTC_2D_8X8 260 8, // ASTC_2D_8X8
257 8, // ASTC_2D_8X5 261 8, // ASTC_2D_8X5
258 5, // ASTC_2D_5X4 262 5, // ASTC_2D_5X4
259 1, // BGRA8_SRGB 263 1, // BGRA8_SRGB
260 4, // DXT1_SRGB 264 4, // DXT1_SRGB
261 4, // DXT23_SRGB 265 4, // DXT23_SRGB
262 4, // DXT45_SRGB 266 4, // DXT45_SRGB
263 4, // BC7U_SRGB 267 4, // BC7U_SRGB
264 4, // ASTC_2D_4X4_SRGB 268 4, // ASTC_2D_4X4_SRGB
265 8, // ASTC_2D_8X8_SRGB 269 8, // ASTC_2D_8X8_SRGB
266 8, // ASTC_2D_8X5_SRGB 270 8, // ASTC_2D_8X5_SRGB
267 5, // ASTC_2D_5X4_SRGB 271 5, // ASTC_2D_5X4_SRGB
268 5, // ASTC_2D_5X5 272 5, // ASTC_2D_5X5
269 5, // ASTC_2D_5X5_SRGB 273 5, // ASTC_2D_5X5_SRGB
270 1, // Z32F 274 10, // ASTC_2D_10X8
271 1, // Z16 275 10, // ASTC_2D_10X8_SRGB
272 1, // Z24S8 276 1, // Z32F
273 1, // S8Z24 277 1, // Z16
274 1, // Z32FS8 278 1, // Z24S8
279 1, // S8Z24
280 1, // Z32FS8
275 }}; 281 }};
276 ASSERT(static_cast<std::size_t>(format) < block_width_table.size()); 282 ASSERT(static_cast<std::size_t>(format) < block_width_table.size());
277 return block_width_table[static_cast<std::size_t>(format)]; 283 return block_width_table[static_cast<std::size_t>(format)];
@@ -341,6 +347,8 @@ static constexpr u32 GetDefaultBlockHeight(PixelFormat format) {
341 4, // ASTC_2D_5X4_SRGB 347 4, // ASTC_2D_5X4_SRGB
342 5, // ASTC_2D_5X5 348 5, // ASTC_2D_5X5
343 5, // ASTC_2D_5X5_SRGB 349 5, // ASTC_2D_5X5_SRGB
350 8, // ASTC_2D_10X8
351 8, // ASTC_2D_10X8_SRGB
344 1, // Z32F 352 1, // Z32F
345 1, // Z16 353 1, // Z16
346 1, // Z24S8 354 1, // Z24S8
@@ -416,6 +424,8 @@ static constexpr u32 GetFormatBpp(PixelFormat format) {
416 128, // ASTC_2D_5X4_SRGB 424 128, // ASTC_2D_5X4_SRGB
417 128, // ASTC_2D_5X5 425 128, // ASTC_2D_5X5
418 128, // ASTC_2D_5X5_SRGB 426 128, // ASTC_2D_5X5_SRGB
427 128, // ASTC_2D_10X8
428 128, // ASTC_2D_10X8_SRGB
419 32, // Z32F 429 32, // Z32F
420 16, // Z16 430 16, // Z16
421 32, // Z24S8 431 32, // Z24S8
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp
index 3066abf61..a9d134d14 100644
--- a/src/video_core/textures/decoders.cpp
+++ b/src/video_core/textures/decoders.cpp
@@ -202,6 +202,8 @@ u32 BytesPerPixel(TextureFormat format) {
202 case TextureFormat::ASTC_2D_5X4: 202 case TextureFormat::ASTC_2D_5X4:
203 case TextureFormat::ASTC_2D_8X8: 203 case TextureFormat::ASTC_2D_8X8:
204 case TextureFormat::ASTC_2D_8X5: 204 case TextureFormat::ASTC_2D_8X5:
205 case TextureFormat::ASTC_2D_10X8:
206 case TextureFormat::ASTC_2D_5X5:
205 case TextureFormat::A8R8G8B8: 207 case TextureFormat::A8R8G8B8:
206 case TextureFormat::A2B10G10R10: 208 case TextureFormat::A2B10G10R10:
207 case TextureFormat::BF10GF11RF11: 209 case TextureFormat::BF10GF11RF11:
@@ -294,6 +296,8 @@ std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat
294 case TextureFormat::BC6H_SF16: 296 case TextureFormat::BC6H_SF16:
295 case TextureFormat::ASTC_2D_4X4: 297 case TextureFormat::ASTC_2D_4X4:
296 case TextureFormat::ASTC_2D_8X8: 298 case TextureFormat::ASTC_2D_8X8:
299 case TextureFormat::ASTC_2D_5X5:
300 case TextureFormat::ASTC_2D_10X8:
297 case TextureFormat::A8R8G8B8: 301 case TextureFormat::A8R8G8B8:
298 case TextureFormat::A2B10G10R10: 302 case TextureFormat::A2B10G10R10:
299 case TextureFormat::A1B5G5R5: 303 case TextureFormat::A1B5G5R5:
diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h
index d12d2ecb8..e199d019a 100644
--- a/src/video_core/textures/texture.h
+++ b/src/video_core/textures/texture.h
@@ -168,20 +168,29 @@ struct TICEntry {
168 168
169 // High 16 bits of the pitch value 169 // High 16 bits of the pitch value
170 BitField<0, 16, u32> pitch_high; 170 BitField<0, 16, u32> pitch_high;
171 171 BitField<26, 1, u32> use_header_opt_control;
172 BitField<27, 1, u32> depth_texture;
172 BitField<28, 4, u32> max_mip_level; 173 BitField<28, 4, u32> max_mip_level;
173 }; 174 };
174 union { 175 union {
175 BitField<0, 16, u32> width_minus_1; 176 BitField<0, 16, u32> width_minus_1;
176 BitField<22, 1, u32> srgb_conversion; 177 BitField<22, 1, u32> srgb_conversion;
177 BitField<23, 4, TextureType> texture_type; 178 BitField<23, 4, TextureType> texture_type;
179 BitField<29, 3, u32> border_size;
178 }; 180 };
179 union { 181 union {
180 BitField<0, 16, u32> height_minus_1; 182 BitField<0, 16, u32> height_minus_1;
181 BitField<16, 15, u32> depth_minus_1; 183 BitField<16, 15, u32> depth_minus_1;
182 }; 184 };
185 union {
186 BitField<6, 13, u32> mip_lod_bias;
187 BitField<27, 3, u32> max_anisotropy;
188 };
183 189
184 INSERT_PADDING_BYTES(8); 190 union {
191 BitField<0, 4, u32> res_min_mip_level;
192 BitField<4, 4, u32> res_max_mip_level;
193 };
185 194
186 GPUVAddr Address() const { 195 GPUVAddr Address() const {
187 return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | address_low); 196 return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | address_low);
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index 537d6e576..b322258a0 100644
--- a/src/yuzu/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
@@ -3,6 +3,10 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/core.h" 5#include "core/core.h"
6#include "core/hle/service/am/am.h"
7#include "core/hle/service/am/applet_ae.h"
8#include "core/hle/service/am/applet_oe.h"
9#include "core/hle/service/sm/sm.h"
6#include "core/settings.h" 10#include "core/settings.h"
7#include "ui_configure_general.h" 11#include "ui_configure_general.h"
8#include "yuzu/configuration/configure_general.h" 12#include "yuzu/configuration/configure_general.h"
@@ -20,7 +24,6 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent)
20 this->setConfiguration(); 24 this->setConfiguration();
21 25
22 ui->use_cpu_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn()); 26 ui->use_cpu_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn());
23 ui->use_docked_mode->setEnabled(!Core::System::GetInstance().IsPoweredOn());
24} 27}
25 28
26ConfigureGeneral::~ConfigureGeneral() = default; 29ConfigureGeneral::~ConfigureGeneral() = default;
@@ -38,6 +41,30 @@ void ConfigureGeneral::PopulateHotkeyList(const HotkeyRegistry& registry) {
38 ui->widget->Populate(registry); 41 ui->widget->Populate(registry);
39} 42}
40 43
44void ConfigureGeneral::OnDockedModeChanged(bool last_state, bool new_state) {
45 if (last_state == new_state) {
46 return;
47 }
48
49 Core::System& system{Core::System::GetInstance()};
50 Service::SM::ServiceManager& sm = system.ServiceManager();
51
52 // Message queue is shared between these services, we just need to signal an operation
53 // change to one and it will handle both automatically
54 auto applet_oe = sm.GetService<Service::AM::AppletOE>("appletOE");
55 auto applet_ae = sm.GetService<Service::AM::AppletAE>("appletAE");
56 bool has_signalled = false;
57
58 if (applet_oe != nullptr) {
59 applet_oe->GetMessageQueue()->OperationModeChanged();
60 has_signalled = true;
61 }
62
63 if (applet_ae != nullptr && !has_signalled) {
64 applet_ae->GetMessageQueue()->OperationModeChanged();
65 }
66}
67
41void ConfigureGeneral::applyConfiguration() { 68void ConfigureGeneral::applyConfiguration() {
42 UISettings::values.gamedir_deepscan = ui->toggle_deepscan->isChecked(); 69 UISettings::values.gamedir_deepscan = ui->toggle_deepscan->isChecked();
43 UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked(); 70 UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
@@ -45,6 +72,9 @@ void ConfigureGeneral::applyConfiguration() {
45 ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString(); 72 ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString();
46 73
47 Settings::values.use_cpu_jit = ui->use_cpu_jit->isChecked(); 74 Settings::values.use_cpu_jit = ui->use_cpu_jit->isChecked();
75 const bool pre_docked_mode = Settings::values.use_docked_mode;
48 Settings::values.use_docked_mode = ui->use_docked_mode->isChecked(); 76 Settings::values.use_docked_mode = ui->use_docked_mode->isChecked();
77 OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode);
78
49 Settings::values.enable_nfc = ui->enable_nfc->isChecked(); 79 Settings::values.enable_nfc = ui->enable_nfc->isChecked();
50} 80}
diff --git a/src/yuzu/configuration/configure_general.h b/src/yuzu/configuration/configure_general.h
index 4770034cc..2210d48da 100644
--- a/src/yuzu/configuration/configure_general.h
+++ b/src/yuzu/configuration/configure_general.h
@@ -25,6 +25,7 @@ public:
25 25
26private: 26private:
27 void setConfiguration(); 27 void setConfiguration();
28 void OnDockedModeChanged(bool last_state, bool new_state);
28 29
29 std::unique_ptr<Ui::ConfigureGeneral> ui; 30 std::unique_ptr<Ui::ConfigureGeneral> ui;
30}; 31};
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp
index b4b4a4a56..4803d43bb 100644
--- a/src/yuzu/configuration/configure_system.cpp
+++ b/src/yuzu/configuration/configure_system.cpp
@@ -240,7 +240,7 @@ void ConfigureSystem::RefreshConsoleID() {
240 240
241void ConfigureSystem::SelectUser(const QModelIndex& index) { 241void ConfigureSystem::SelectUser(const QModelIndex& index) {
242 Settings::values.current_user = 242 Settings::values.current_user =
243 std::clamp<std::size_t>(index.row(), 0, profile_manager->GetUserCount() - 1); 243 std::clamp<s32>(index.row(), 0, static_cast<s32>(profile_manager->GetUserCount() - 1));
244 244
245 UpdateCurrentUser(); 245 UpdateCurrentUser();
246 246
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 74a44be37..131ad19de 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -933,7 +933,8 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
933 const auto full = res == "Full"; 933 const auto full = res == "Full";
934 const auto entry_size = CalculateRomFSEntrySize(extracted, full); 934 const auto entry_size = CalculateRomFSEntrySize(extracted, full);
935 935
936 QProgressDialog progress(tr("Extracting RomFS..."), tr("Cancel"), 0, entry_size, this); 936 QProgressDialog progress(tr("Extracting RomFS..."), tr("Cancel"), 0,
937 static_cast<s32>(entry_size), this);
937 progress.setWindowModality(Qt::WindowModal); 938 progress.setWindowModality(Qt::WindowModal);
938 progress.setMinimumDuration(100); 939 progress.setMinimumDuration(100);
939 940
@@ -1621,7 +1622,7 @@ void GMainWindow::closeEvent(QCloseEvent* event) {
1621 return; 1622 return;
1622 } 1623 }
1623 1624
1624 if (ui.action_Fullscreen->isChecked()) { 1625 if (!ui.action_Fullscreen->isChecked()) {
1625 UISettings::values.geometry = saveGeometry(); 1626 UISettings::values.geometry = saveGeometry();
1626 UISettings::values.renderwindow_geometry = render_window->saveGeometry(); 1627 UISettings::values.renderwindow_geometry = render_window->saveGeometry();
1627 } 1628 }