summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/audio_core/stream.cpp4
-rw-r--r--src/core/hle/kernel/svc.cpp28
-rw-r--r--src/core/hle/service/acc/acc.cpp22
-rw-r--r--src/core/hle/service/acc/acc.h1
-rw-r--r--src/core/hle/service/acc/acc_su.cpp2
-rw-r--r--src/core/hle/service/acc/acc_u0.cpp2
-rw-r--r--src/core/hle/service/acc/acc_u1.cpp2
-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/hle/service/hid/controllers/npad.cpp2
-rw-r--r--src/video_core/CMakeLists.txt1
-rw-r--r--src/video_core/engines/maxwell_3d.cpp16
-rw-r--r--src/video_core/engines/maxwell_3d.h37
-rw-r--r--src/video_core/memory_manager.cpp75
-rw-r--r--src/video_core/memory_manager.h8
-rw-r--r--src/video_core/rasterizer_cache.cpp7
-rw-r--r--src/video_core/rasterizer_cache.h2
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp118
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h8
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp8
-rw-r--r--src/video_core/renderer_opengl/gl_resource_manager.cpp40
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp252
-rw-r--r--src/video_core/renderer_opengl/gl_state.h60
-rw-r--r--src/video_core/renderer_opengl/gl_stream_buffer.cpp5
-rw-r--r--src/yuzu/configuration/configure_general.cpp32
-rw-r--r--src/yuzu/configuration/configure_general.h1
30 files changed, 677 insertions, 229 deletions
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp
index 742a5e0a0..f35628e45 100644
--- a/src/audio_core/stream.cpp
+++ b/src/audio_core/stream.cpp
@@ -11,7 +11,6 @@
11#include "audio_core/stream.h" 11#include "audio_core/stream.h"
12#include "common/assert.h" 12#include "common/assert.h"
13#include "common/logging/log.h" 13#include "common/logging/log.h"
14#include "common/microprofile.h"
15#include "core/core_timing.h" 14#include "core/core_timing.h"
16#include "core/core_timing_util.h" 15#include "core/core_timing_util.h"
17#include "core/settings.h" 16#include "core/settings.h"
@@ -104,10 +103,7 @@ void Stream::PlayNextBuffer() {
104 CoreTiming::ScheduleEventThreadsafe(GetBufferReleaseCycles(*active_buffer), release_event, {}); 103 CoreTiming::ScheduleEventThreadsafe(GetBufferReleaseCycles(*active_buffer), release_event, {});
105} 104}
106 105
107MICROPROFILE_DEFINE(AudioOutput, "Audio", "ReleaseActiveBuffer", MP_RGB(100, 100, 255));
108
109void Stream::ReleaseActiveBuffer() { 106void Stream::ReleaseActiveBuffer() {
110 MICROPROFILE_SCOPE(AudioOutput);
111 ASSERT(active_buffer); 107 ASSERT(active_buffer);
112 released_buffers.push(std::move(active_buffer)); 108 released_buffers.push(std::move(active_buffer));
113 release_callback(); 109 release_callback();
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index c7c579aaf..7e8e87c33 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -395,16 +395,42 @@ struct BreakReason {
395/// Break program execution 395/// Break program execution
396static void Break(u32 reason, u64 info1, u64 info2) { 396static void Break(u32 reason, u64 info1, u64 info2) {
397 BreakReason break_reason{reason}; 397 BreakReason break_reason{reason};
398 bool has_dumped_buffer{};
398 399
400 const auto handle_debug_buffer = [&](VAddr addr, u64 sz) {
401 if (sz == 0 || addr == 0 || has_dumped_buffer) {
402 return;
403 }
404
405 // This typically is an error code so we're going to assume this is the case
406 if (sz == sizeof(u32)) {
407 LOG_CRITICAL(Debug_Emulated, "debug_buffer_err_code={:X}", Memory::Read32(addr));
408 } else {
409 // We don't know what's in here so we'll hexdump it
410 std::vector<u8> debug_buffer(sz);
411 Memory::ReadBlock(addr, debug_buffer.data(), sz);
412 std::string hexdump;
413 for (std::size_t i = 0; i < debug_buffer.size(); i++) {
414 hexdump += fmt::format("{:02X} ", debug_buffer[i]);
415 if (i != 0 && i % 16 == 0) {
416 hexdump += '\n';
417 }
418 }
419 LOG_CRITICAL(Debug_Emulated, "debug_buffer=\n{}", hexdump);
420 }
421 has_dumped_buffer = true;
422 };
399 switch (break_reason.break_type) { 423 switch (break_reason.break_type) {
400 case BreakType::Panic: 424 case BreakType::Panic:
401 LOG_CRITICAL(Debug_Emulated, "Signalling debugger, PANIC! info1=0x{:016X}, info2=0x{:016X}", 425 LOG_CRITICAL(Debug_Emulated, "Signalling debugger, PANIC! info1=0x{:016X}, info2=0x{:016X}",
402 info1, info2); 426 info1, info2);
427 handle_debug_buffer(info1, info2);
403 break; 428 break;
404 case BreakType::AssertionFailed: 429 case BreakType::AssertionFailed:
405 LOG_CRITICAL(Debug_Emulated, 430 LOG_CRITICAL(Debug_Emulated,
406 "Signalling debugger, Assertion failed! info1=0x{:016X}, info2=0x{:016X}", 431 "Signalling debugger, Assertion failed! info1=0x{:016X}, info2=0x{:016X}",
407 info1, info2); 432 info1, info2);
433 handle_debug_buffer(info1, info2);
408 break; 434 break;
409 case BreakType::PreNROLoad: 435 case BreakType::PreNROLoad:
410 LOG_WARNING( 436 LOG_WARNING(
@@ -433,6 +459,7 @@ static void Break(u32 reason, u64 info1, u64 info2) {
433 Debug_Emulated, 459 Debug_Emulated,
434 "Signalling debugger, Unknown break reason {}, info1=0x{:016X}, info2=0x{:016X}", 460 "Signalling debugger, Unknown break reason {}, info1=0x{:016X}, info2=0x{:016X}",
435 static_cast<u32>(break_reason.break_type.Value()), info1, info2); 461 static_cast<u32>(break_reason.break_type.Value()), info1, info2);
462 handle_debug_buffer(info1, info2);
436 break; 463 break;
437 } 464 }
438 465
@@ -441,6 +468,7 @@ static void Break(u32 reason, u64 info1, u64 info2) {
441 Debug_Emulated, 468 Debug_Emulated,
442 "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}", 469 "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}",
443 reason, info1, info2); 470 reason, info1, info2);
471 handle_debug_buffer(info1, info2);
444 ASSERT(false); 472 ASSERT(false);
445 473
446 Core::CurrentProcess()->PrepareForTermination(); 474 Core::CurrentProcess()->PrepareForTermination();
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index c6437a671..8318eff5f 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -242,6 +242,28 @@ void Module::Interface::GetBaasAccountManagerForApplication(Kernel::HLERequestCo
242 LOG_DEBUG(Service_ACC, "called"); 242 LOG_DEBUG(Service_ACC, "called");
243} 243}
244 244
245void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) {
246 LOG_DEBUG(Service_ACC, "called");
247 // A u8 is passed into this function which we can safely ignore. It's to determine if we have
248 // access to use the network or not by the looks of it
249 IPC::ResponseBuilder rb{ctx, 6};
250 if (profile_manager->GetUserCount() != 1) {
251 rb.Push(RESULT_SUCCESS);
252 rb.PushRaw<u128>(INVALID_UUID);
253 return;
254 }
255 auto user_list = profile_manager->GetAllUsers();
256 if (user_list.empty()) {
257 rb.Push(ResultCode(-1)); // TODO(ogniK): Find the correct error code
258 rb.PushRaw<u128>(INVALID_UUID);
259 return;
260 }
261
262 // Select the first user we have
263 rb.Push(RESULT_SUCCESS);
264 rb.PushRaw<u128>(profile_manager->GetUser(0)->uuid);
265}
266
245Module::Interface::Interface(std::shared_ptr<Module> module, 267Module::Interface::Interface(std::shared_ptr<Module> module,
246 std::shared_ptr<ProfileManager> profile_manager, const char* name) 268 std::shared_ptr<ProfileManager> profile_manager, const char* name)
247 : ServiceFramework(name), module(std::move(module)), 269 : ServiceFramework(name), module(std::move(module)),
diff --git a/src/core/hle/service/acc/acc.h b/src/core/hle/service/acc/acc.h
index c7ed74351..89b2104fa 100644
--- a/src/core/hle/service/acc/acc.h
+++ b/src/core/hle/service/acc/acc.h
@@ -27,6 +27,7 @@ public:
27 void InitializeApplicationInfo(Kernel::HLERequestContext& ctx); 27 void InitializeApplicationInfo(Kernel::HLERequestContext& ctx);
28 void GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx); 28 void GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx);
29 void IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx); 29 void IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx);
30 void TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx);
30 31
31 protected: 32 protected:
32 std::shared_ptr<Module> module; 33 std::shared_ptr<Module> module;
diff --git a/src/core/hle/service/acc/acc_su.cpp b/src/core/hle/service/acc/acc_su.cpp
index ad455c3a7..5e2030355 100644
--- a/src/core/hle/service/acc/acc_su.cpp
+++ b/src/core/hle/service/acc/acc_su.cpp
@@ -17,7 +17,7 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
17 {5, &ACC_SU::GetProfile, "GetProfile"}, 17 {5, &ACC_SU::GetProfile, "GetProfile"},
18 {6, nullptr, "GetProfileDigest"}, 18 {6, nullptr, "GetProfileDigest"},
19 {50, &ACC_SU::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"}, 19 {50, &ACC_SU::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"},
20 {51, nullptr, "TrySelectUserWithoutInteraction"}, 20 {51, &ACC_SU::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"},
21 {60, nullptr, "ListOpenContextStoredUsers"}, 21 {60, nullptr, "ListOpenContextStoredUsers"},
22 {100, nullptr, "GetUserRegistrationNotifier"}, 22 {100, nullptr, "GetUserRegistrationNotifier"},
23 {101, nullptr, "GetUserStateChangeNotifier"}, 23 {101, nullptr, "GetUserStateChangeNotifier"},
diff --git a/src/core/hle/service/acc/acc_u0.cpp b/src/core/hle/service/acc/acc_u0.cpp
index 72d4adf35..a4d705b45 100644
--- a/src/core/hle/service/acc/acc_u0.cpp
+++ b/src/core/hle/service/acc/acc_u0.cpp
@@ -17,7 +17,7 @@ ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
17 {5, &ACC_U0::GetProfile, "GetProfile"}, 17 {5, &ACC_U0::GetProfile, "GetProfile"},
18 {6, nullptr, "GetProfileDigest"}, 18 {6, nullptr, "GetProfileDigest"},
19 {50, &ACC_U0::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"}, 19 {50, &ACC_U0::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"},
20 {51, nullptr, "TrySelectUserWithoutInteraction"}, 20 {51, &ACC_U0::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"},
21 {60, nullptr, "ListOpenContextStoredUsers"}, 21 {60, nullptr, "ListOpenContextStoredUsers"},
22 {100, &ACC_U0::InitializeApplicationInfo, "InitializeApplicationInfo"}, 22 {100, &ACC_U0::InitializeApplicationInfo, "InitializeApplicationInfo"},
23 {101, &ACC_U0::GetBaasAccountManagerForApplication, "GetBaasAccountManagerForApplication"}, 23 {101, &ACC_U0::GetBaasAccountManagerForApplication, "GetBaasAccountManagerForApplication"},
diff --git a/src/core/hle/service/acc/acc_u1.cpp b/src/core/hle/service/acc/acc_u1.cpp
index d480f08e5..8fffc93b5 100644
--- a/src/core/hle/service/acc/acc_u1.cpp
+++ b/src/core/hle/service/acc/acc_u1.cpp
@@ -17,7 +17,7 @@ ACC_U1::ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
17 {5, &ACC_U1::GetProfile, "GetProfile"}, 17 {5, &ACC_U1::GetProfile, "GetProfile"},
18 {6, nullptr, "GetProfileDigest"}, 18 {6, nullptr, "GetProfileDigest"},
19 {50, &ACC_U1::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"}, 19 {50, &ACC_U1::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"},
20 {51, nullptr, "TrySelectUserWithoutInteraction"}, 20 {51, &ACC_U1::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"},
21 {60, nullptr, "ListOpenContextStoredUsers"}, 21 {60, nullptr, "ListOpenContextStoredUsers"},
22 {100, nullptr, "GetUserRegistrationNotifier"}, 22 {100, nullptr, "GetUserRegistrationNotifier"},
23 {101, nullptr, "GetUserStateChangeNotifier"}, 23 {101, nullptr, "GetUserStateChangeNotifier"},
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/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 1ef789bd0..ff9b64be4 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -392,8 +392,10 @@ std::size_t Controller_NPad::GetSupportedNPadIdTypesSize() const {
392} 392}
393 393
394void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) { 394void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) {
395 styleset_changed_event->Signal();
395 hold_type = joy_hold_type; 396 hold_type = joy_hold_type;
396} 397}
398
397Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const { 399Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const {
398 return hold_type; 400 return hold_type;
399} 401}
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 41e554998..5ae836aca 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -37,6 +37,22 @@ void Maxwell3D::InitializeRegisterDefaults() {
37 regs.viewport[viewport].depth_range_near = 0.0f; 37 regs.viewport[viewport].depth_range_near = 0.0f;
38 regs.viewport[viewport].depth_range_far = 1.0f; 38 regs.viewport[viewport].depth_range_far = 1.0f;
39 } 39 }
40 // Doom and Bomberman seems to use the uninitialized registers and just enable blend
41 // so initialize blend registers with sane values
42 regs.blend.equation_rgb = Regs::Blend::Equation::Add;
43 regs.blend.factor_source_rgb = Regs::Blend::Factor::One;
44 regs.blend.factor_dest_rgb = Regs::Blend::Factor::Zero;
45 regs.blend.equation_a = Regs::Blend::Equation::Add;
46 regs.blend.factor_source_a = Regs::Blend::Factor::One;
47 regs.blend.factor_dest_a = Regs::Blend::Factor::Zero;
48 for (std::size_t blend_index = 0; blend_index < Regs::NumRenderTargets; blend_index++) {
49 regs.independent_blend[blend_index].equation_rgb = Regs::Blend::Equation::Add;
50 regs.independent_blend[blend_index].factor_source_rgb = Regs::Blend::Factor::One;
51 regs.independent_blend[blend_index].factor_dest_rgb = Regs::Blend::Factor::Zero;
52 regs.independent_blend[blend_index].equation_a = Regs::Blend::Equation::Add;
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;
55 }
40} 56}
41 57
42void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) { 58void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) {
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index f2052b4c7..557795d0f 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -462,6 +462,16 @@ public:
462 } 462 }
463 }; 463 };
464 464
465 struct ColorMask {
466 union {
467 u32 raw;
468 BitField<0, 4, u32> R;
469 BitField<4, 4, u32> G;
470 BitField<8, 4, u32> B;
471 BitField<12, 4, u32> A;
472 };
473 };
474
465 bool IsShaderConfigEnabled(std::size_t index) const { 475 bool IsShaderConfigEnabled(std::size_t index) const {
466 // The VertexB is always enabled. 476 // The VertexB is always enabled.
467 if (index == static_cast<std::size_t>(Regs::ShaderProgram::VertexB)) { 477 if (index == static_cast<std::size_t>(Regs::ShaderProgram::VertexB)) {
@@ -571,7 +581,11 @@ public:
571 u32 stencil_back_mask; 581 u32 stencil_back_mask;
572 u32 stencil_back_func_mask; 582 u32 stencil_back_func_mask;
573 583
574 INSERT_PADDING_WORDS(0x13); 584 INSERT_PADDING_WORDS(0xC);
585
586 u32 color_mask_common;
587
588 INSERT_PADDING_WORDS(0x6);
575 589
576 u32 rt_separate_frag_data; 590 u32 rt_separate_frag_data;
577 591
@@ -646,8 +660,14 @@ public:
646 ComparisonOp depth_test_func; 660 ComparisonOp depth_test_func;
647 float alpha_test_ref; 661 float alpha_test_ref;
648 ComparisonOp alpha_test_func; 662 ComparisonOp alpha_test_func;
649 663 u32 draw_tfb_stride;
650 INSERT_PADDING_WORDS(0x9); 664 struct {
665 float r;
666 float g;
667 float b;
668 float a;
669 } blend_color;
670 INSERT_PADDING_WORDS(0x4);
651 671
652 struct { 672 struct {
653 u32 separate_alpha; 673 u32 separate_alpha;
@@ -841,8 +861,9 @@ public:
841 BitField<6, 4, u32> RT; 861 BitField<6, 4, u32> RT;
842 BitField<10, 11, u32> layer; 862 BitField<10, 11, u32> layer;
843 } clear_buffers; 863 } clear_buffers;
844 864 INSERT_PADDING_WORDS(0xB);
845 INSERT_PADDING_WORDS(0x4B); 865 std::array<ColorMask, NumRenderTargets> color_mask;
866 INSERT_PADDING_WORDS(0x38);
846 867
847 struct { 868 struct {
848 u32 query_address_high; 869 u32 query_address_high;
@@ -1081,6 +1102,7 @@ ASSERT_REG_POSITION(scissor_test, 0x380);
1081ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5); 1102ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5);
1082ASSERT_REG_POSITION(stencil_back_mask, 0x3D6); 1103ASSERT_REG_POSITION(stencil_back_mask, 0x3D6);
1083ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7); 1104ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7);
1105ASSERT_REG_POSITION(color_mask_common, 0x3E4);
1084ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB); 1106ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB);
1085ASSERT_REG_POSITION(zeta, 0x3F8); 1107ASSERT_REG_POSITION(zeta, 0x3F8);
1086ASSERT_REG_POSITION(vertex_attrib_format, 0x458); 1108ASSERT_REG_POSITION(vertex_attrib_format, 0x458);
@@ -1093,6 +1115,10 @@ ASSERT_REG_POSITION(depth_write_enabled, 0x4BA);
1093ASSERT_REG_POSITION(alpha_test_enabled, 0x4BB); 1115ASSERT_REG_POSITION(alpha_test_enabled, 0x4BB);
1094ASSERT_REG_POSITION(d3d_cull_mode, 0x4C2); 1116ASSERT_REG_POSITION(d3d_cull_mode, 0x4C2);
1095ASSERT_REG_POSITION(depth_test_func, 0x4C3); 1117ASSERT_REG_POSITION(depth_test_func, 0x4C3);
1118ASSERT_REG_POSITION(alpha_test_ref, 0x4C4);
1119ASSERT_REG_POSITION(alpha_test_func, 0x4C5);
1120ASSERT_REG_POSITION(draw_tfb_stride, 0x4C6);
1121ASSERT_REG_POSITION(blend_color, 0x4C7);
1096ASSERT_REG_POSITION(blend, 0x4CF); 1122ASSERT_REG_POSITION(blend, 0x4CF);
1097ASSERT_REG_POSITION(stencil_enable, 0x4E0); 1123ASSERT_REG_POSITION(stencil_enable, 0x4E0);
1098ASSERT_REG_POSITION(stencil_front_op_fail, 0x4E1); 1124ASSERT_REG_POSITION(stencil_front_op_fail, 0x4E1);
@@ -1123,6 +1149,7 @@ ASSERT_REG_POSITION(instanced_arrays, 0x620);
1123ASSERT_REG_POSITION(cull, 0x646); 1149ASSERT_REG_POSITION(cull, 0x646);
1124ASSERT_REG_POSITION(logic_op, 0x671); 1150ASSERT_REG_POSITION(logic_op, 0x671);
1125ASSERT_REG_POSITION(clear_buffers, 0x674); 1151ASSERT_REG_POSITION(clear_buffers, 0x674);
1152ASSERT_REG_POSITION(color_mask, 0x680);
1126ASSERT_REG_POSITION(query, 0x6C0); 1153ASSERT_REG_POSITION(query, 0x6C0);
1127ASSERT_REG_POSITION(vertex_array[0], 0x700); 1154ASSERT_REG_POSITION(vertex_array[0], 0x700);
1128ASSERT_REG_POSITION(independent_blend, 0x780); 1155ASSERT_REG_POSITION(independent_blend, 0x780);
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp
index 90a8e825d..77a20bb84 100644
--- a/src/video_core/memory_manager.cpp
+++ b/src/video_core/memory_manager.cpp
@@ -4,18 +4,21 @@
4 4
5#include "common/alignment.h" 5#include "common/alignment.h"
6#include "common/assert.h" 6#include "common/assert.h"
7#include "common/logging/log.h"
7#include "video_core/memory_manager.h" 8#include "video_core/memory_manager.h"
8 9
9namespace Tegra { 10namespace Tegra {
10 11
11GPUVAddr MemoryManager::AllocateSpace(u64 size, u64 align) { 12GPUVAddr MemoryManager::AllocateSpace(u64 size, u64 align) {
12 std::optional<GPUVAddr> gpu_addr = FindFreeBlock(size, align); 13 const std::optional<GPUVAddr> gpu_addr{FindFreeBlock(0, size, align, PageStatus::Unmapped)};
13 ASSERT(gpu_addr);
14 14
15 for (u64 offset = 0; offset < size; offset += PAGE_SIZE) { 15 ASSERT_MSG(gpu_addr, "unable to find available GPU memory");
16 VAddr& slot = PageSlot(*gpu_addr + offset); 16
17 for (u64 offset{}; offset < size; offset += PAGE_SIZE) {
18 VAddr& slot{PageSlot(*gpu_addr + offset)};
17 19
18 ASSERT(slot == static_cast<u64>(PageStatus::Unmapped)); 20 ASSERT(slot == static_cast<u64>(PageStatus::Unmapped));
21
19 slot = static_cast<u64>(PageStatus::Allocated); 22 slot = static_cast<u64>(PageStatus::Allocated);
20 } 23 }
21 24
@@ -23,10 +26,11 @@ GPUVAddr MemoryManager::AllocateSpace(u64 size, u64 align) {
23} 26}
24 27
25GPUVAddr MemoryManager::AllocateSpace(GPUVAddr gpu_addr, u64 size, u64 align) { 28GPUVAddr MemoryManager::AllocateSpace(GPUVAddr gpu_addr, u64 size, u64 align) {
26 for (u64 offset = 0; offset < size; offset += PAGE_SIZE) { 29 for (u64 offset{}; offset < size; offset += PAGE_SIZE) {
27 VAddr& slot = PageSlot(gpu_addr + offset); 30 VAddr& slot{PageSlot(gpu_addr + offset)};
28 31
29 ASSERT(slot == static_cast<u64>(PageStatus::Unmapped)); 32 ASSERT(slot == static_cast<u64>(PageStatus::Unmapped));
33
30 slot = static_cast<u64>(PageStatus::Allocated); 34 slot = static_cast<u64>(PageStatus::Allocated);
31 } 35 }
32 36
@@ -34,17 +38,19 @@ GPUVAddr MemoryManager::AllocateSpace(GPUVAddr gpu_addr, u64 size, u64 align) {
34} 38}
35 39
36GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, u64 size) { 40GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, u64 size) {
37 std::optional<GPUVAddr> gpu_addr = FindFreeBlock(size, PAGE_SIZE); 41 const std::optional<GPUVAddr> gpu_addr{FindFreeBlock(0, size, PAGE_SIZE, PageStatus::Unmapped)};
38 ASSERT(gpu_addr); 42
43 ASSERT_MSG(gpu_addr, "unable to find available GPU memory");
39 44
40 for (u64 offset = 0; offset < size; offset += PAGE_SIZE) { 45 for (u64 offset{}; offset < size; offset += PAGE_SIZE) {
41 VAddr& slot = PageSlot(*gpu_addr + offset); 46 VAddr& slot{PageSlot(*gpu_addr + offset)};
42 47
43 ASSERT(slot == static_cast<u64>(PageStatus::Unmapped)); 48 ASSERT(slot == static_cast<u64>(PageStatus::Unmapped));
49
44 slot = cpu_addr + offset; 50 slot = cpu_addr + offset;
45 } 51 }
46 52
47 MappedRegion region{cpu_addr, *gpu_addr, size}; 53 const MappedRegion region{cpu_addr, *gpu_addr, size};
48 mapped_regions.push_back(region); 54 mapped_regions.push_back(region);
49 55
50 return *gpu_addr; 56 return *gpu_addr;
@@ -53,14 +59,31 @@ GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, u64 size) {
53GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size) { 59GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size) {
54 ASSERT((gpu_addr & PAGE_MASK) == 0); 60 ASSERT((gpu_addr & PAGE_MASK) == 0);
55 61
56 for (u64 offset = 0; offset < size; offset += PAGE_SIZE) { 62 if (PageSlot(gpu_addr) != static_cast<u64>(PageStatus::Allocated)) {
57 VAddr& slot = PageSlot(gpu_addr + offset); 63 // Page has been already mapped. In this case, we must find a new area of memory to use that
64 // is different than the specified one. Super Mario Odyssey hits this scenario when changing
65 // areas, but we do not want to overwrite the old pages.
66 // TODO(bunnei): We need to write a hardware test to confirm this behavior.
67
68 LOG_ERROR(HW_GPU, "attempting to map addr 0x{:016X}, which is not available!", gpu_addr);
69
70 const std::optional<GPUVAddr> new_gpu_addr{
71 FindFreeBlock(gpu_addr, size, PAGE_SIZE, PageStatus::Allocated)};
72
73 ASSERT_MSG(new_gpu_addr, "unable to find available GPU memory");
74
75 gpu_addr = *new_gpu_addr;
76 }
77
78 for (u64 offset{}; offset < size; offset += PAGE_SIZE) {
79 VAddr& slot{PageSlot(gpu_addr + offset)};
58 80
59 ASSERT(slot == static_cast<u64>(PageStatus::Allocated)); 81 ASSERT(slot == static_cast<u64>(PageStatus::Allocated));
82
60 slot = cpu_addr + offset; 83 slot = cpu_addr + offset;
61 } 84 }
62 85
63 MappedRegion region{cpu_addr, gpu_addr, size}; 86 const MappedRegion region{cpu_addr, gpu_addr, size};
64 mapped_regions.push_back(region); 87 mapped_regions.push_back(region);
65 88
66 return gpu_addr; 89 return gpu_addr;
@@ -69,11 +92,12 @@ GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size)
69GPUVAddr MemoryManager::UnmapBuffer(GPUVAddr gpu_addr, u64 size) { 92GPUVAddr MemoryManager::UnmapBuffer(GPUVAddr gpu_addr, u64 size) {
70 ASSERT((gpu_addr & PAGE_MASK) == 0); 93 ASSERT((gpu_addr & PAGE_MASK) == 0);
71 94
72 for (u64 offset = 0; offset < size; offset += PAGE_SIZE) { 95 for (u64 offset{}; offset < size; offset += PAGE_SIZE) {
73 VAddr& slot = PageSlot(gpu_addr + offset); 96 VAddr& slot{PageSlot(gpu_addr + offset)};
74 97
75 ASSERT(slot != static_cast<u64>(PageStatus::Allocated) && 98 ASSERT(slot != static_cast<u64>(PageStatus::Allocated) &&
76 slot != static_cast<u64>(PageStatus::Unmapped)); 99 slot != static_cast<u64>(PageStatus::Unmapped));
100
77 slot = static_cast<u64>(PageStatus::Unmapped); 101 slot = static_cast<u64>(PageStatus::Unmapped);
78 } 102 }
79 103
@@ -97,13 +121,14 @@ GPUVAddr MemoryManager::GetRegionEnd(GPUVAddr region_start) const {
97 return {}; 121 return {};
98} 122}
99 123
100std::optional<GPUVAddr> MemoryManager::FindFreeBlock(u64 size, u64 align) { 124std::optional<GPUVAddr> MemoryManager::FindFreeBlock(GPUVAddr region_start, u64 size, u64 align,
101 GPUVAddr gpu_addr = 0; 125 PageStatus status) {
102 u64 free_space = 0; 126 GPUVAddr gpu_addr{region_start};
127 u64 free_space{};
103 align = (align + PAGE_MASK) & ~PAGE_MASK; 128 align = (align + PAGE_MASK) & ~PAGE_MASK;
104 129
105 while (gpu_addr + free_space < MAX_ADDRESS) { 130 while (gpu_addr + free_space < MAX_ADDRESS) {
106 if (!IsPageMapped(gpu_addr + free_space)) { 131 if (PageSlot(gpu_addr + free_space) == static_cast<u64>(status)) {
107 free_space += PAGE_SIZE; 132 free_space += PAGE_SIZE;
108 if (free_space >= size) { 133 if (free_space >= size) {
109 return gpu_addr; 134 return gpu_addr;
@@ -119,7 +144,7 @@ std::optional<GPUVAddr> MemoryManager::FindFreeBlock(u64 size, u64 align) {
119} 144}
120 145
121std::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr gpu_addr) { 146std::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr gpu_addr) {
122 VAddr base_addr = PageSlot(gpu_addr); 147 const VAddr base_addr{PageSlot(gpu_addr)};
123 148
124 if (base_addr == static_cast<u64>(PageStatus::Allocated) || 149 if (base_addr == static_cast<u64>(PageStatus::Allocated) ||
125 base_addr == static_cast<u64>(PageStatus::Unmapped)) { 150 base_addr == static_cast<u64>(PageStatus::Unmapped)) {
@@ -133,19 +158,15 @@ std::vector<GPUVAddr> MemoryManager::CpuToGpuAddress(VAddr cpu_addr) const {
133 std::vector<GPUVAddr> results; 158 std::vector<GPUVAddr> results;
134 for (const auto& region : mapped_regions) { 159 for (const auto& region : mapped_regions) {
135 if (cpu_addr >= region.cpu_addr && cpu_addr < (region.cpu_addr + region.size)) { 160 if (cpu_addr >= region.cpu_addr && cpu_addr < (region.cpu_addr + region.size)) {
136 u64 offset = cpu_addr - region.cpu_addr; 161 const u64 offset{cpu_addr - region.cpu_addr};
137 results.push_back(region.gpu_addr + offset); 162 results.push_back(region.gpu_addr + offset);
138 } 163 }
139 } 164 }
140 return results; 165 return results;
141} 166}
142 167
143bool MemoryManager::IsPageMapped(GPUVAddr gpu_addr) {
144 return PageSlot(gpu_addr) != static_cast<u64>(PageStatus::Unmapped);
145}
146
147VAddr& MemoryManager::PageSlot(GPUVAddr gpu_addr) { 168VAddr& MemoryManager::PageSlot(GPUVAddr gpu_addr) {
148 auto& block = page_table[(gpu_addr >> (PAGE_BITS + PAGE_TABLE_BITS)) & PAGE_TABLE_MASK]; 169 auto& block{page_table[(gpu_addr >> (PAGE_BITS + PAGE_TABLE_BITS)) & PAGE_TABLE_MASK]};
149 if (!block) { 170 if (!block) {
150 block = std::make_unique<PageBlock>(); 171 block = std::make_unique<PageBlock>();
151 block->fill(static_cast<VAddr>(PageStatus::Unmapped)); 172 block->fill(static_cast<VAddr>(PageStatus::Unmapped));
diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h
index b1255fd56..4eb338aa2 100644
--- a/src/video_core/memory_manager.h
+++ b/src/video_core/memory_manager.h
@@ -34,15 +34,15 @@ public:
34 static constexpr u64 PAGE_MASK = PAGE_SIZE - 1; 34 static constexpr u64 PAGE_MASK = PAGE_SIZE - 1;
35 35
36private: 36private:
37 std::optional<GPUVAddr> FindFreeBlock(u64 size, u64 align = 1);
38 bool IsPageMapped(GPUVAddr gpu_addr);
39 VAddr& PageSlot(GPUVAddr gpu_addr);
40
41 enum class PageStatus : u64 { 37 enum class PageStatus : u64 {
42 Unmapped = 0xFFFFFFFFFFFFFFFFULL, 38 Unmapped = 0xFFFFFFFFFFFFFFFFULL,
43 Allocated = 0xFFFFFFFFFFFFFFFEULL, 39 Allocated = 0xFFFFFFFFFFFFFFFEULL,
44 }; 40 };
45 41
42 std::optional<GPUVAddr> FindFreeBlock(GPUVAddr region_start, u64 size, u64 align,
43 PageStatus status);
44 VAddr& PageSlot(GPUVAddr gpu_addr);
45
46 static constexpr u64 MAX_ADDRESS{0x10000000000ULL}; 46 static constexpr u64 MAX_ADDRESS{0x10000000000ULL};
47 static constexpr u64 PAGE_TABLE_BITS{10}; 47 static constexpr u64 PAGE_TABLE_BITS{10};
48 static constexpr u64 PAGE_TABLE_SIZE{1 << PAGE_TABLE_BITS}; 48 static constexpr u64 PAGE_TABLE_SIZE{1 << PAGE_TABLE_BITS};
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..d999c92fa 100644
--- a/src/video_core/rasterizer_cache.h
+++ b/src/video_core/rasterizer_cache.h
@@ -17,6 +17,8 @@
17 17
18class RasterizerCacheObject { 18class RasterizerCacheObject {
19public: 19public:
20 virtual ~RasterizerCacheObject();
21
20 /// Gets the address of the shader in guest memory, required for cache management 22 /// Gets the address of the shader in guest memory, required for cache management
21 virtual VAddr GetAddr() const = 0; 23 virtual VAddr GetAddr() const = 0;
22 24
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 6ae2adfab..1bdd4c054 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -525,10 +525,10 @@ void RasterizerOpenGL::Clear() {
525 525
526 OpenGLState clear_state; 526 OpenGLState clear_state;
527 clear_state.draw.draw_framebuffer = framebuffer.handle; 527 clear_state.draw.draw_framebuffer = framebuffer.handle;
528 clear_state.color_mask.red_enabled = regs.clear_buffers.R ? GL_TRUE : GL_FALSE; 528 clear_state.color_mask[0].red_enabled = regs.clear_buffers.R ? GL_TRUE : GL_FALSE;
529 clear_state.color_mask.green_enabled = regs.clear_buffers.G ? 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.blue_enabled = regs.clear_buffers.B ? 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.alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE; 531 clear_state.color_mask[0].alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE;
532 532
533 if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B || 533 if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B ||
534 regs.clear_buffers.A) { 534 regs.clear_buffers.A) {
@@ -587,14 +587,13 @@ void RasterizerOpenGL::DrawArrays() {
587 ScopeAcquireGLContext acquire_context{emu_window}; 587 ScopeAcquireGLContext acquire_context{emu_window};
588 588
589 ConfigureFramebuffers(); 589 ConfigureFramebuffers();
590 590 SyncColorMask();
591 SyncDepthTestState(); 591 SyncDepthTestState();
592 SyncStencilTestState(); 592 SyncStencilTestState();
593 SyncBlendState(); 593 SyncBlendState();
594 SyncLogicOpState(); 594 SyncLogicOpState();
595 SyncCullMode(); 595 SyncCullMode();
596 SyncPrimitiveRestart(); 596 SyncPrimitiveRestart();
597 SyncDepthRange();
598 SyncScissorTest(); 597 SyncScissorTest();
599 // Alpha Testing is synced on shaders. 598 // Alpha Testing is synced on shaders.
600 SyncTransformFeedback(); 599 SyncTransformFeedback();
@@ -914,12 +913,16 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader,
914 913
915void RasterizerOpenGL::SyncViewport() { 914void RasterizerOpenGL::SyncViewport() {
916 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 915 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
917 const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()}; 916 for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
918 917 const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()};
919 state.viewport.x = viewport_rect.left; 918 auto& viewport = state.viewports[i];
920 state.viewport.y = viewport_rect.bottom; 919 viewport.x = viewport_rect.left;
921 state.viewport.width = static_cast<GLsizei>(viewport_rect.GetWidth()); 920 viewport.y = viewport_rect.bottom;
922 state.viewport.height = static_cast<GLsizei>(viewport_rect.GetHeight()); 921 viewport.width = static_cast<GLsizei>(viewport_rect.GetWidth());
922 viewport.height = static_cast<GLsizei>(viewport_rect.GetHeight());
923 viewport.depth_range_far = regs.viewport[i].depth_range_far;
924 viewport.depth_range_near = regs.viewport[i].depth_range_near;
925 }
923} 926}
924 927
925void RasterizerOpenGL::SyncClipEnabled() { 928void RasterizerOpenGL::SyncClipEnabled() {
@@ -961,13 +964,6 @@ void RasterizerOpenGL::SyncPrimitiveRestart() {
961 state.primitive_restart.index = regs.primitive_restart.index; 964 state.primitive_restart.index = regs.primitive_restart.index;
962} 965}
963 966
964void RasterizerOpenGL::SyncDepthRange() {
965 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
966
967 state.depth.depth_range_near = regs.viewport->depth_range_near;
968 state.depth.depth_range_far = regs.viewport->depth_range_far;
969}
970
971void RasterizerOpenGL::SyncDepthTestState() { 967void RasterizerOpenGL::SyncDepthTestState() {
972 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 968 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
973 969
@@ -1008,26 +1004,60 @@ void RasterizerOpenGL::SyncStencilTestState() {
1008 state.stencil.back.write_mask = regs.stencil_back_mask; 1004 state.stencil.back.write_mask = regs.stencil_back_mask;
1009} 1005}
1010 1006
1011void RasterizerOpenGL::SyncBlendState() { 1007void RasterizerOpenGL::SyncColorMask() {
1012 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 1008 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
1009 for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
1010 const auto& source = regs.color_mask[regs.color_mask_common ? 0 : i];
1011 auto& dest = state.color_mask[i];
1012 dest.red_enabled = (source.R == 0) ? GL_FALSE : GL_TRUE;
1013 dest.green_enabled = (source.G == 0) ? GL_FALSE : GL_TRUE;
1014 dest.blue_enabled = (source.B == 0) ? GL_FALSE : GL_TRUE;
1015 dest.alpha_enabled = (source.A == 0) ? GL_FALSE : GL_TRUE;
1016 }
1017}
1013 1018
1014 // TODO(Subv): Support more than just render target 0. 1019void RasterizerOpenGL::SyncBlendState() {
1015 state.blend.enabled = regs.blend.enable[0] != 0; 1020 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
1016 1021
1017 if (!state.blend.enabled) 1022 state.blend_color.red = regs.blend_color.r;
1023 state.blend_color.green = regs.blend_color.g;
1024 state.blend_color.blue = regs.blend_color.b;
1025 state.blend_color.alpha = regs.blend_color.a;
1026
1027 state.independant_blend.enabled = regs.independent_blend_enable;
1028 if (!state.independant_blend.enabled) {
1029 auto& blend = state.blend[0];
1030 blend.enabled = regs.blend.enable[0] != 0;
1031 blend.separate_alpha = regs.blend.separate_alpha;
1032 blend.rgb_equation = MaxwellToGL::BlendEquation(regs.blend.equation_rgb);
1033 blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_rgb);
1034 blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.blend.factor_dest_rgb);
1035 if (blend.separate_alpha) {
1036 blend.a_equation = MaxwellToGL::BlendEquation(regs.blend.equation_a);
1037 blend.src_a_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_a);
1038 blend.dst_a_func = MaxwellToGL::BlendFunc(regs.blend.factor_dest_a);
1039 }
1040 for (size_t i = 1; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
1041 state.blend[i].enabled = false;
1042 }
1018 return; 1043 return;
1044 }
1019 1045
1020 ASSERT_MSG(regs.logic_op.enable == 0, 1046 for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
1021 "Blending and logic op can't be enabled at the same time."); 1047 auto& blend = state.blend[i];
1022 1048 blend.enabled = regs.blend.enable[i] != 0;
1023 ASSERT_MSG(regs.independent_blend_enable == 1, "Only independent blending is implemented"); 1049 if (!blend.enabled)
1024 ASSERT_MSG(!regs.independent_blend[0].separate_alpha, "Unimplemented"); 1050 continue;
1025 state.blend.rgb_equation = MaxwellToGL::BlendEquation(regs.independent_blend[0].equation_rgb); 1051 blend.separate_alpha = regs.independent_blend[i].separate_alpha;
1026 state.blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_source_rgb); 1052 blend.rgb_equation = MaxwellToGL::BlendEquation(regs.independent_blend[i].equation_rgb);
1027 state.blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_dest_rgb); 1053 blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_source_rgb);
1028 state.blend.a_equation = MaxwellToGL::BlendEquation(regs.independent_blend[0].equation_a); 1054 blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_dest_rgb);
1029 state.blend.src_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_source_a); 1055 if (blend.separate_alpha) {
1030 state.blend.dst_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_dest_a); 1056 blend.a_equation = MaxwellToGL::BlendEquation(regs.independent_blend[i].equation_a);
1057 blend.src_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_source_a);
1058 blend.dst_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_dest_a);
1059 }
1060 }
1031} 1061}
1032 1062
1033void RasterizerOpenGL::SyncLogicOpState() { 1063void RasterizerOpenGL::SyncLogicOpState() {
@@ -1046,19 +1076,19 @@ void RasterizerOpenGL::SyncLogicOpState() {
1046} 1076}
1047 1077
1048void RasterizerOpenGL::SyncScissorTest() { 1078void RasterizerOpenGL::SyncScissorTest() {
1079 // TODO: what is the correct behavior here, a single scissor for all targets
1080 // or scissor disabled for the rest of the targets?
1049 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 1081 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
1050
1051 state.scissor.enabled = (regs.scissor_test.enable != 0); 1082 state.scissor.enabled = (regs.scissor_test.enable != 0);
1052 // TODO(Blinkhawk): Figure if the hardware supports scissor testing per viewport and how it's 1083 if (regs.scissor_test.enable == 0) {
1053 // implemented. 1084 return;
1054 if (regs.scissor_test.enable != 0) {
1055 const u32 width = regs.scissor_test.max_x - regs.scissor_test.min_x;
1056 const u32 height = regs.scissor_test.max_y - regs.scissor_test.min_y;
1057 state.scissor.x = regs.scissor_test.min_x;
1058 state.scissor.y = regs.scissor_test.min_y;
1059 state.scissor.width = width;
1060 state.scissor.height = height;
1061 } 1085 }
1086 const u32 width = regs.scissor_test.max_x - regs.scissor_test.min_x;
1087 const u32 height = regs.scissor_test.max_y - regs.scissor_test.min_y;
1088 state.scissor.x = regs.scissor_test.min_x;
1089 state.scissor.y = regs.scissor_test.min_y;
1090 state.scissor.width = width;
1091 state.scissor.height = height;
1062} 1092}
1063 1093
1064void RasterizerOpenGL::SyncTransformFeedback() { 1094void RasterizerOpenGL::SyncTransformFeedback() {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 0fab3eb28..5eee5f088 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -133,7 +133,7 @@ private:
133 u32 SetupTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, Shader& shader, 133 u32 SetupTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, Shader& shader,
134 GLenum primitive_mode, u32 current_unit); 134 GLenum primitive_mode, u32 current_unit);
135 135
136 /// Syncs the viewport to match the guest state 136 /// Syncs the viewport and depth range to match the guest state
137 void SyncViewport(); 137 void SyncViewport();
138 138
139 /// Syncs the clip enabled status to match the guest state 139 /// Syncs the clip enabled status to match the guest state
@@ -148,9 +148,6 @@ private:
148 /// Syncs the primitve restart to match the guest state 148 /// Syncs the primitve restart to match the guest state
149 void SyncPrimitiveRestart(); 149 void SyncPrimitiveRestart();
150 150
151 /// Syncs the depth range to match the guest state
152 void SyncDepthRange();
153
154 /// Syncs the depth test state to match the guest state 151 /// Syncs the depth test state to match the guest state
155 void SyncDepthTestState(); 152 void SyncDepthTestState();
156 153
@@ -172,6 +169,9 @@ private:
172 /// Syncs the point state to match the guest state 169 /// Syncs the point state to match the guest state
173 void SyncPointState(); 170 void SyncPointState();
174 171
172 /// Syncs Color Mask
173 void SyncColorMask();
174
175 /// Check asserts for alpha testing. 175 /// Check asserts for alpha testing.
176 void CheckAlphaTests(); 176 void CheckAlphaTests();
177 177
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 7d970efa0..49d63e6f3 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -562,9 +562,11 @@ void SwizzleFunc(const GLConversionArray& functions, const SurfaceParams& params
562 } 562 }
563} 563}
564 564
565MICROPROFILE_DEFINE(OpenGL_BlitSurface, "OpenGL", "BlitSurface", MP_RGB(128, 192, 64));
565static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface, 566static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface,
566 GLuint read_fb_handle, GLuint draw_fb_handle, GLenum src_attachment = 0, 567 GLuint read_fb_handle, GLuint draw_fb_handle, GLenum src_attachment = 0,
567 GLenum dst_attachment = 0, std::size_t cubemap_face = 0) { 568 GLenum dst_attachment = 0, std::size_t cubemap_face = 0) {
569 MICROPROFILE_SCOPE(OpenGL_BlitSurface);
568 570
569 const auto& src_params{src_surface->GetSurfaceParams()}; 571 const auto& src_params{src_surface->GetSurfaceParams()};
570 const auto& dst_params{dst_surface->GetSurfaceParams()}; 572 const auto& dst_params{dst_surface->GetSurfaceParams()};
@@ -704,9 +706,11 @@ static void FastCopySurface(const Surface& src_surface, const Surface& dst_surfa
704 0, 0, width, height, 1); 706 0, 0, width, height, 1);
705} 707}
706 708
709MICROPROFILE_DEFINE(OpenGL_CopySurface, "OpenGL", "CopySurface", MP_RGB(128, 192, 64));
707static void CopySurface(const Surface& src_surface, const Surface& dst_surface, 710static void CopySurface(const Surface& src_surface, const Surface& dst_surface,
708 GLuint copy_pbo_handle, GLenum src_attachment = 0, 711 GLuint copy_pbo_handle, GLenum src_attachment = 0,
709 GLenum dst_attachment = 0, std::size_t cubemap_face = 0) { 712 GLenum dst_attachment = 0, std::size_t cubemap_face = 0) {
713 MICROPROFILE_SCOPE(OpenGL_CopySurface);
710 ASSERT_MSG(dst_attachment == 0, "Unimplemented"); 714 ASSERT_MSG(dst_attachment == 0, "Unimplemented");
711 715
712 const auto& src_params{src_surface->GetSurfaceParams()}; 716 const auto& src_params{src_surface->GetSurfaceParams()};
@@ -975,7 +979,7 @@ static void ConvertFormatAsNeeded_FlushGLBuffer(std::vector<u8>& data, PixelForm
975 } 979 }
976} 980}
977 981
978MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192)); 982MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 192, 64));
979void CachedSurface::LoadGLBuffer() { 983void CachedSurface::LoadGLBuffer() {
980 MICROPROFILE_SCOPE(OpenGL_SurfaceLoad); 984 MICROPROFILE_SCOPE(OpenGL_SurfaceLoad);
981 gl_buffer.resize(params.max_mip_level); 985 gl_buffer.resize(params.max_mip_level);
@@ -1157,7 +1161,7 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
1157 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 1161 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1158} 1162}
1159 1163
1160MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192)); 1164MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 192, 64));
1161void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle) { 1165void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle) {
1162 if (params.type == SurfaceType::Fill) 1166 if (params.type == SurfaceType::Fill)
1163 return; 1167 return;
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.cpp b/src/video_core/renderer_opengl/gl_resource_manager.cpp
index c10863337..c17d5ac00 100644
--- a/src/video_core/renderer_opengl/gl_resource_manager.cpp
+++ b/src/video_core/renderer_opengl/gl_resource_manager.cpp
@@ -5,21 +5,29 @@
5#include <utility> 5#include <utility>
6#include <glad/glad.h> 6#include <glad/glad.h>
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "common/microprofile.h"
8#include "video_core/renderer_opengl/gl_resource_manager.h" 9#include "video_core/renderer_opengl/gl_resource_manager.h"
9#include "video_core/renderer_opengl/gl_shader_util.h" 10#include "video_core/renderer_opengl/gl_shader_util.h"
10#include "video_core/renderer_opengl/gl_state.h" 11#include "video_core/renderer_opengl/gl_state.h"
11 12
13MICROPROFILE_DEFINE(OpenGL_ResourceCreation, "OpenGL", "Resource Creation", MP_RGB(128, 128, 192));
14MICROPROFILE_DEFINE(OpenGL_ResourceDeletion, "OpenGL", "Resource Deletion", MP_RGB(128, 128, 192));
15
12namespace OpenGL { 16namespace OpenGL {
13 17
14void OGLTexture::Create() { 18void OGLTexture::Create() {
15 if (handle != 0) 19 if (handle != 0)
16 return; 20 return;
21
22 MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
17 glGenTextures(1, &handle); 23 glGenTextures(1, &handle);
18} 24}
19 25
20void OGLTexture::Release() { 26void OGLTexture::Release() {
21 if (handle == 0) 27 if (handle == 0)
22 return; 28 return;
29
30 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
23 glDeleteTextures(1, &handle); 31 glDeleteTextures(1, &handle);
24 OpenGLState::GetCurState().UnbindTexture(handle).Apply(); 32 OpenGLState::GetCurState().UnbindTexture(handle).Apply();
25 handle = 0; 33 handle = 0;
@@ -28,12 +36,16 @@ void OGLTexture::Release() {
28void OGLSampler::Create() { 36void OGLSampler::Create() {
29 if (handle != 0) 37 if (handle != 0)
30 return; 38 return;
39
40 MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
31 glGenSamplers(1, &handle); 41 glGenSamplers(1, &handle);
32} 42}
33 43
34void OGLSampler::Release() { 44void OGLSampler::Release() {
35 if (handle == 0) 45 if (handle == 0)
36 return; 46 return;
47
48 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
37 glDeleteSamplers(1, &handle); 49 glDeleteSamplers(1, &handle);
38 OpenGLState::GetCurState().ResetSampler(handle).Apply(); 50 OpenGLState::GetCurState().ResetSampler(handle).Apply();
39 handle = 0; 51 handle = 0;
@@ -44,12 +56,16 @@ void OGLShader::Create(const char* source, GLenum type) {
44 return; 56 return;
45 if (source == nullptr) 57 if (source == nullptr)
46 return; 58 return;
59
60 MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
47 handle = GLShader::LoadShader(source, type); 61 handle = GLShader::LoadShader(source, type);
48} 62}
49 63
50void OGLShader::Release() { 64void OGLShader::Release() {
51 if (handle == 0) 65 if (handle == 0)
52 return; 66 return;
67
68 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
53 glDeleteShader(handle); 69 glDeleteShader(handle);
54 handle = 0; 70 handle = 0;
55} 71}
@@ -63,12 +79,16 @@ void OGLProgram::CreateFromSource(const char* vert_shader, const char* geo_shade
63 geo.Create(geo_shader, GL_GEOMETRY_SHADER); 79 geo.Create(geo_shader, GL_GEOMETRY_SHADER);
64 if (frag_shader) 80 if (frag_shader)
65 frag.Create(frag_shader, GL_FRAGMENT_SHADER); 81 frag.Create(frag_shader, GL_FRAGMENT_SHADER);
82
83 MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
66 Create(separable_program, vert.handle, geo.handle, frag.handle); 84 Create(separable_program, vert.handle, geo.handle, frag.handle);
67} 85}
68 86
69void OGLProgram::Release() { 87void OGLProgram::Release() {
70 if (handle == 0) 88 if (handle == 0)
71 return; 89 return;
90
91 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
72 glDeleteProgram(handle); 92 glDeleteProgram(handle);
73 OpenGLState::GetCurState().ResetProgram(handle).Apply(); 93 OpenGLState::GetCurState().ResetProgram(handle).Apply();
74 handle = 0; 94 handle = 0;
@@ -77,12 +97,16 @@ void OGLProgram::Release() {
77void OGLPipeline::Create() { 97void OGLPipeline::Create() {
78 if (handle != 0) 98 if (handle != 0)
79 return; 99 return;
100
101 MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
80 glGenProgramPipelines(1, &handle); 102 glGenProgramPipelines(1, &handle);
81} 103}
82 104
83void OGLPipeline::Release() { 105void OGLPipeline::Release() {
84 if (handle == 0) 106 if (handle == 0)
85 return; 107 return;
108
109 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
86 glDeleteProgramPipelines(1, &handle); 110 glDeleteProgramPipelines(1, &handle);
87 OpenGLState::GetCurState().ResetPipeline(handle).Apply(); 111 OpenGLState::GetCurState().ResetPipeline(handle).Apply();
88 handle = 0; 112 handle = 0;
@@ -91,12 +115,16 @@ void OGLPipeline::Release() {
91void OGLBuffer::Create() { 115void OGLBuffer::Create() {
92 if (handle != 0) 116 if (handle != 0)
93 return; 117 return;
118
119 MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
94 glGenBuffers(1, &handle); 120 glGenBuffers(1, &handle);
95} 121}
96 122
97void OGLBuffer::Release() { 123void OGLBuffer::Release() {
98 if (handle == 0) 124 if (handle == 0)
99 return; 125 return;
126
127 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
100 glDeleteBuffers(1, &handle); 128 glDeleteBuffers(1, &handle);
101 OpenGLState::GetCurState().ResetBuffer(handle).Apply(); 129 OpenGLState::GetCurState().ResetBuffer(handle).Apply();
102 handle = 0; 130 handle = 0;
@@ -105,12 +133,16 @@ void OGLBuffer::Release() {
105void OGLSync::Create() { 133void OGLSync::Create() {
106 if (handle != 0) 134 if (handle != 0)
107 return; 135 return;
136
137 // Don't profile here, this one is expected to happen ingame.
108 handle = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); 138 handle = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
109} 139}
110 140
111void OGLSync::Release() { 141void OGLSync::Release() {
112 if (handle == 0) 142 if (handle == 0)
113 return; 143 return;
144
145 // Don't profile here, this one is expected to happen ingame.
114 glDeleteSync(handle); 146 glDeleteSync(handle);
115 handle = 0; 147 handle = 0;
116} 148}
@@ -118,12 +150,16 @@ void OGLSync::Release() {
118void OGLVertexArray::Create() { 150void OGLVertexArray::Create() {
119 if (handle != 0) 151 if (handle != 0)
120 return; 152 return;
153
154 MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
121 glGenVertexArrays(1, &handle); 155 glGenVertexArrays(1, &handle);
122} 156}
123 157
124void OGLVertexArray::Release() { 158void OGLVertexArray::Release() {
125 if (handle == 0) 159 if (handle == 0)
126 return; 160 return;
161
162 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
127 glDeleteVertexArrays(1, &handle); 163 glDeleteVertexArrays(1, &handle);
128 OpenGLState::GetCurState().ResetVertexArray(handle).Apply(); 164 OpenGLState::GetCurState().ResetVertexArray(handle).Apply();
129 handle = 0; 165 handle = 0;
@@ -132,12 +168,16 @@ void OGLVertexArray::Release() {
132void OGLFramebuffer::Create() { 168void OGLFramebuffer::Create() {
133 if (handle != 0) 169 if (handle != 0)
134 return; 170 return;
171
172 MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
135 glGenFramebuffers(1, &handle); 173 glGenFramebuffers(1, &handle);
136} 174}
137 175
138void OGLFramebuffer::Release() { 176void OGLFramebuffer::Release() {
139 if (handle == 0) 177 if (handle == 0)
140 return; 178 return;
179
180 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
141 glDeleteFramebuffers(1, &handle); 181 glDeleteFramebuffers(1, &handle);
142 OpenGLState::GetCurState().ResetFramebuffer(handle).Apply(); 182 OpenGLState::GetCurState().ResetFramebuffer(handle).Apply();
143 handle = 0; 183 handle = 0;
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index b6b426f34..9517285e5 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -22,17 +22,15 @@ OpenGLState::OpenGLState() {
22 depth.test_enabled = false; 22 depth.test_enabled = false;
23 depth.test_func = GL_LESS; 23 depth.test_func = GL_LESS;
24 depth.write_mask = GL_TRUE; 24 depth.write_mask = GL_TRUE;
25 depth.depth_range_near = 0.0f;
26 depth.depth_range_far = 1.0f;
27 25
28 primitive_restart.enabled = false; 26 primitive_restart.enabled = false;
29 primitive_restart.index = 0; 27 primitive_restart.index = 0;
30 28 for (auto& item : color_mask) {
31 color_mask.red_enabled = GL_TRUE; 29 item.red_enabled = GL_TRUE;
32 color_mask.green_enabled = GL_TRUE; 30 item.green_enabled = GL_TRUE;
33 color_mask.blue_enabled = GL_TRUE; 31 item.blue_enabled = GL_TRUE;
34 color_mask.alpha_enabled = GL_TRUE; 32 item.alpha_enabled = GL_TRUE;
35 33 }
36 stencil.test_enabled = false; 34 stencil.test_enabled = false;
37 auto reset_stencil = [](auto& config) { 35 auto reset_stencil = [](auto& config) {
38 config.test_func = GL_ALWAYS; 36 config.test_func = GL_ALWAYS;
@@ -45,19 +43,33 @@ OpenGLState::OpenGLState() {
45 }; 43 };
46 reset_stencil(stencil.front); 44 reset_stencil(stencil.front);
47 reset_stencil(stencil.back); 45 reset_stencil(stencil.back);
48 46 for (auto& item : viewports) {
49 blend.enabled = true; 47 item.x = 0;
50 blend.rgb_equation = GL_FUNC_ADD; 48 item.y = 0;
51 blend.a_equation = GL_FUNC_ADD; 49 item.width = 0;
52 blend.src_rgb_func = GL_ONE; 50 item.height = 0;
53 blend.dst_rgb_func = GL_ZERO; 51 item.depth_range_near = 0.0f;
54 blend.src_a_func = GL_ONE; 52 item.depth_range_far = 1.0f;
55 blend.dst_a_func = GL_ZERO; 53 }
56 blend.color.red = 0.0f; 54 scissor.enabled = false;
57 blend.color.green = 0.0f; 55 scissor.x = 0;
58 blend.color.blue = 0.0f; 56 scissor.y = 0;
59 blend.color.alpha = 0.0f; 57 scissor.width = 0;
60 58 scissor.height = 0;
59 for (auto& item : blend) {
60 item.enabled = true;
61 item.rgb_equation = GL_FUNC_ADD;
62 item.a_equation = GL_FUNC_ADD;
63 item.src_rgb_func = GL_ONE;
64 item.dst_rgb_func = GL_ZERO;
65 item.src_a_func = GL_ONE;
66 item.dst_a_func = GL_ZERO;
67 }
68 independant_blend.enabled = false;
69 blend_color.red = 0.0f;
70 blend_color.green = 0.0f;
71 blend_color.blue = 0.0f;
72 blend_color.alpha = 0.0f;
61 logic_op.enabled = false; 73 logic_op.enabled = false;
62 logic_op.operation = GL_COPY; 74 logic_op.operation = GL_COPY;
63 75
@@ -73,17 +85,6 @@ OpenGLState::OpenGLState() {
73 draw.shader_program = 0; 85 draw.shader_program = 0;
74 draw.program_pipeline = 0; 86 draw.program_pipeline = 0;
75 87
76 scissor.enabled = false;
77 scissor.x = 0;
78 scissor.y = 0;
79 scissor.width = 0;
80 scissor.height = 0;
81
82 viewport.x = 0;
83 viewport.y = 0;
84 viewport.width = 0;
85 viewport.height = 0;
86
87 clip_distance = {}; 88 clip_distance = {};
88 89
89 point.size = 1; 90 point.size = 1;
@@ -134,6 +135,32 @@ void OpenGLState::ApplyCulling() const {
134 } 135 }
135} 136}
136 137
138void OpenGLState::ApplyColorMask() const {
139 if (GLAD_GL_ARB_viewport_array) {
140 for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
141 const auto& updated = color_mask[i];
142 const auto& current = cur_state.color_mask[i];
143 if (updated.red_enabled != current.red_enabled ||
144 updated.green_enabled != current.green_enabled ||
145 updated.blue_enabled != current.blue_enabled ||
146 updated.alpha_enabled != current.alpha_enabled) {
147 glColorMaski(static_cast<GLuint>(i), updated.red_enabled, updated.green_enabled,
148 updated.blue_enabled, updated.alpha_enabled);
149 }
150 }
151 } else {
152 const auto& updated = color_mask[0];
153 const auto& current = cur_state.color_mask[0];
154 if (updated.red_enabled != current.red_enabled ||
155 updated.green_enabled != current.green_enabled ||
156 updated.blue_enabled != current.blue_enabled ||
157 updated.alpha_enabled != current.alpha_enabled) {
158 glColorMask(updated.red_enabled, updated.green_enabled, updated.blue_enabled,
159 updated.alpha_enabled);
160 }
161 }
162}
163
137void OpenGLState::ApplyDepth() const { 164void OpenGLState::ApplyDepth() const {
138 // Depth test 165 // Depth test
139 const bool depth_test_changed = depth.test_enabled != cur_state.depth.test_enabled; 166 const bool depth_test_changed = depth.test_enabled != cur_state.depth.test_enabled;
@@ -152,11 +179,6 @@ void OpenGLState::ApplyDepth() const {
152 if (depth.write_mask != cur_state.depth.write_mask) { 179 if (depth.write_mask != cur_state.depth.write_mask) {
153 glDepthMask(depth.write_mask); 180 glDepthMask(depth.write_mask);
154 } 181 }
155 // Depth range
156 if (depth.depth_range_near != cur_state.depth.depth_range_near ||
157 depth.depth_range_far != cur_state.depth.depth_range_far) {
158 glDepthRange(depth.depth_range_near, depth.depth_range_far);
159 }
160} 182}
161 183
162void OpenGLState::ApplyPrimitiveRestart() const { 184void OpenGLState::ApplyPrimitiveRestart() const {
@@ -208,7 +230,7 @@ void OpenGLState::ApplyStencilTest() const {
208 } 230 }
209} 231}
210 232
211void OpenGLState::ApplyScissorTest() const { 233void OpenGLState::ApplyScissor() const {
212 const bool scissor_changed = scissor.enabled != cur_state.scissor.enabled; 234 const bool scissor_changed = scissor.enabled != cur_state.scissor.enabled;
213 if (scissor_changed) { 235 if (scissor_changed) {
214 if (scissor.enabled) { 236 if (scissor.enabled) {
@@ -217,51 +239,141 @@ void OpenGLState::ApplyScissorTest() const {
217 glDisable(GL_SCISSOR_TEST); 239 glDisable(GL_SCISSOR_TEST);
218 } 240 }
219 } 241 }
220 if (scissor_changed || scissor_changed || scissor.x != cur_state.scissor.x || 242 if (scissor.enabled &&
221 scissor.y != cur_state.scissor.y || scissor.width != cur_state.scissor.width || 243 (scissor_changed || scissor.x != cur_state.scissor.x || scissor.y != cur_state.scissor.y ||
222 scissor.height != cur_state.scissor.height) { 244 scissor.width != cur_state.scissor.width || scissor.height != cur_state.scissor.height)) {
223 glScissor(scissor.x, scissor.y, scissor.width, scissor.height); 245 glScissor(scissor.x, scissor.y, scissor.width, scissor.height);
224 } 246 }
225} 247}
226 248
227void OpenGLState::ApplyBlending() const { 249void OpenGLState::ApplyViewport() const {
228 const bool blend_changed = blend.enabled != cur_state.blend.enabled; 250 if (GLAD_GL_ARB_viewport_array) {
251 for (GLuint i = 0;
252 i < static_cast<GLuint>(Tegra::Engines::Maxwell3D::Regs::NumRenderTargets); i++) {
253 const auto& current = cur_state.viewports[i];
254 const auto& updated = viewports[i];
255 if (updated.x != current.x || updated.y != current.y ||
256 updated.width != current.width || updated.height != current.height) {
257 glViewportIndexedf(i, updated.x, updated.y, updated.width, updated.height);
258 }
259 if (updated.depth_range_near != current.depth_range_near ||
260 updated.depth_range_far != current.depth_range_far) {
261 glDepthRangeIndexed(i, updated.depth_range_near, updated.depth_range_far);
262 }
263 }
264 } else {
265 const auto& current = cur_state.viewports[0];
266 const auto& updated = viewports[0];
267 if (updated.x != current.x || updated.y != current.y || updated.width != current.width ||
268 updated.height != current.height) {
269 glViewport(updated.x, updated.y, updated.width, updated.height);
270 }
271 if (updated.depth_range_near != current.depth_range_near ||
272 updated.depth_range_far != current.depth_range_far) {
273 glDepthRange(updated.depth_range_near, updated.depth_range_far);
274 }
275 }
276}
277
278void OpenGLState::ApplyGlobalBlending() const {
279 const Blend& current = cur_state.blend[0];
280 const Blend& updated = blend[0];
281 const bool blend_changed = updated.enabled != current.enabled;
229 if (blend_changed) { 282 if (blend_changed) {
230 if (blend.enabled) { 283 if (updated.enabled) {
231 ASSERT(!logic_op.enabled);
232 glEnable(GL_BLEND); 284 glEnable(GL_BLEND);
233 } else { 285 } else {
234 glDisable(GL_BLEND); 286 glDisable(GL_BLEND);
235 } 287 }
236 } 288 }
237 if (blend.enabled) { 289 if (!updated.enabled) {
238 if (blend_changed || blend.color.red != cur_state.blend.color.red || 290 return;
239 blend.color.green != cur_state.blend.color.green || 291 }
240 blend.color.blue != cur_state.blend.color.blue || 292 if (updated.separate_alpha) {
241 blend.color.alpha != cur_state.blend.color.alpha) { 293 if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
242 glBlendColor(blend.color.red, blend.color.green, blend.color.blue, blend.color.alpha); 294 updated.dst_rgb_func != current.dst_rgb_func ||
295 updated.src_a_func != current.src_a_func || updated.dst_a_func != current.dst_a_func) {
296 glBlendFuncSeparate(updated.src_rgb_func, updated.dst_rgb_func, updated.src_a_func,
297 updated.dst_a_func);
243 } 298 }
244 299
245 if (blend_changed || blend.src_rgb_func != cur_state.blend.src_rgb_func || 300 if (blend_changed || updated.rgb_equation != current.rgb_equation ||
246 blend.dst_rgb_func != cur_state.blend.dst_rgb_func || 301 updated.a_equation != current.a_equation) {
247 blend.src_a_func != cur_state.blend.src_a_func || 302 glBlendEquationSeparate(updated.rgb_equation, updated.a_equation);
248 blend.dst_a_func != cur_state.blend.dst_a_func) { 303 }
249 glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func, 304 } else {
250 blend.dst_a_func); 305 if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
306 updated.dst_rgb_func != current.dst_rgb_func) {
307 glBlendFunc(updated.src_rgb_func, updated.dst_rgb_func);
251 } 308 }
252 309
253 if (blend_changed || blend.rgb_equation != cur_state.blend.rgb_equation || 310 if (blend_changed || updated.rgb_equation != current.rgb_equation) {
254 blend.a_equation != cur_state.blend.a_equation) { 311 glBlendEquation(updated.rgb_equation);
255 glBlendEquationSeparate(blend.rgb_equation, blend.a_equation);
256 } 312 }
257 } 313 }
258} 314}
259 315
316void OpenGLState::ApplyTargetBlending(int target, bool force) const {
317 const Blend& updated = blend[target];
318 const Blend& current = cur_state.blend[target];
319 const bool blend_changed = updated.enabled != current.enabled || force;
320 if (blend_changed) {
321 if (updated.enabled) {
322 glEnablei(GL_BLEND, static_cast<GLuint>(target));
323 } else {
324 glDisablei(GL_BLEND, static_cast<GLuint>(target));
325 }
326 }
327 if (!updated.enabled) {
328 return;
329 }
330 if (updated.separate_alpha) {
331 if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
332 updated.dst_rgb_func != current.dst_rgb_func ||
333 updated.src_a_func != current.src_a_func || updated.dst_a_func != current.dst_a_func) {
334 glBlendFuncSeparateiARB(static_cast<GLuint>(target), updated.src_rgb_func,
335 updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func);
336 }
337
338 if (blend_changed || updated.rgb_equation != current.rgb_equation ||
339 updated.a_equation != current.a_equation) {
340 glBlendEquationSeparateiARB(static_cast<GLuint>(target), updated.rgb_equation,
341 updated.a_equation);
342 }
343 } else {
344 if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
345 updated.dst_rgb_func != current.dst_rgb_func) {
346 glBlendFunciARB(static_cast<GLuint>(target), updated.src_rgb_func,
347 updated.dst_rgb_func);
348 }
349
350 if (blend_changed || updated.rgb_equation != current.rgb_equation) {
351 glBlendEquationiARB(static_cast<GLuint>(target), updated.rgb_equation);
352 }
353 }
354}
355
356void OpenGLState::ApplyBlending() const {
357 if (independant_blend.enabled) {
358 for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
359 ApplyTargetBlending(i,
360 independant_blend.enabled != cur_state.independant_blend.enabled);
361 }
362 } else {
363 ApplyGlobalBlending();
364 }
365 if (blend_color.red != cur_state.blend_color.red ||
366 blend_color.green != cur_state.blend_color.green ||
367 blend_color.blue != cur_state.blend_color.blue ||
368 blend_color.alpha != cur_state.blend_color.alpha) {
369 glBlendColor(blend_color.red, blend_color.green, blend_color.blue, blend_color.alpha);
370 }
371}
372
260void OpenGLState::ApplyLogicOp() const { 373void OpenGLState::ApplyLogicOp() const {
261 const bool logic_op_changed = logic_op.enabled != cur_state.logic_op.enabled; 374 const bool logic_op_changed = logic_op.enabled != cur_state.logic_op.enabled;
262 if (logic_op_changed) { 375 if (logic_op_changed) {
263 if (logic_op.enabled) { 376 if (logic_op.enabled) {
264 ASSERT(!blend.enabled);
265 glEnable(GL_COLOR_LOGIC_OP); 377 glEnable(GL_COLOR_LOGIC_OP);
266 } else { 378 } else {
267 glDisable(GL_COLOR_LOGIC_OP); 379 glDisable(GL_COLOR_LOGIC_OP);
@@ -348,12 +460,6 @@ void OpenGLState::Apply() const {
348 if (draw.program_pipeline != cur_state.draw.program_pipeline) { 460 if (draw.program_pipeline != cur_state.draw.program_pipeline) {
349 glBindProgramPipeline(draw.program_pipeline); 461 glBindProgramPipeline(draw.program_pipeline);
350 } 462 }
351 // Viewport
352 if (viewport.x != cur_state.viewport.x || viewport.y != cur_state.viewport.y ||
353 viewport.width != cur_state.viewport.width ||
354 viewport.height != cur_state.viewport.height) {
355 glViewport(viewport.x, viewport.y, viewport.width, viewport.height);
356 }
357 // Clip distance 463 // Clip distance
358 for (std::size_t i = 0; i < clip_distance.size(); ++i) { 464 for (std::size_t i = 0; i < clip_distance.size(); ++i) {
359 if (clip_distance[i] != cur_state.clip_distance[i]) { 465 if (clip_distance[i] != cur_state.clip_distance[i]) {
@@ -364,19 +470,13 @@ void OpenGLState::Apply() const {
364 } 470 }
365 } 471 }
366 } 472 }
367 // Color mask
368 if (color_mask.red_enabled != cur_state.color_mask.red_enabled ||
369 color_mask.green_enabled != cur_state.color_mask.green_enabled ||
370 color_mask.blue_enabled != cur_state.color_mask.blue_enabled ||
371 color_mask.alpha_enabled != cur_state.color_mask.alpha_enabled) {
372 glColorMask(color_mask.red_enabled, color_mask.green_enabled, color_mask.blue_enabled,
373 color_mask.alpha_enabled);
374 }
375 // Point 473 // Point
376 if (point.size != cur_state.point.size) { 474 if (point.size != cur_state.point.size) {
377 glPointSize(point.size); 475 glPointSize(point.size);
378 } 476 }
379 ApplyScissorTest(); 477 ApplyColorMask();
478 ApplyViewport();
479 ApplyScissor();
380 ApplyStencilTest(); 480 ApplyStencilTest();
381 ApplySRgb(); 481 ApplySRgb();
382 ApplyCulling(); 482 ApplyCulling();
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index fe648aff6..b8cf1f637 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -46,11 +46,9 @@ public:
46 } cull; 46 } cull;
47 47
48 struct { 48 struct {
49 bool test_enabled; // GL_DEPTH_TEST 49 bool test_enabled; // GL_DEPTH_TEST
50 GLenum test_func; // GL_DEPTH_FUNC 50 GLenum test_func; // GL_DEPTH_FUNC
51 GLboolean write_mask; // GL_DEPTH_WRITEMASK 51 GLboolean write_mask; // GL_DEPTH_WRITEMASK
52 GLfloat depth_range_near; // GL_DEPTH_RANGE
53 GLfloat depth_range_far; // GL_DEPTH_RANGE
54 } depth; 52 } depth;
55 53
56 struct { 54 struct {
@@ -58,13 +56,14 @@ public:
58 GLuint index; 56 GLuint index;
59 } primitive_restart; // GL_PRIMITIVE_RESTART 57 } primitive_restart; // GL_PRIMITIVE_RESTART
60 58
61 struct { 59 struct ColorMask {
62 GLboolean red_enabled; 60 GLboolean red_enabled;
63 GLboolean green_enabled; 61 GLboolean green_enabled;
64 GLboolean blue_enabled; 62 GLboolean blue_enabled;
65 GLboolean alpha_enabled; 63 GLboolean alpha_enabled;
66 } color_mask; // GL_COLOR_WRITEMASK 64 };
67 65 std::array<ColorMask, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets>
66 color_mask; // GL_COLOR_WRITEMASK
68 struct { 67 struct {
69 bool test_enabled; // GL_STENCIL_TEST 68 bool test_enabled; // GL_STENCIL_TEST
70 struct { 69 struct {
@@ -78,22 +77,28 @@ public:
78 } front, back; 77 } front, back;
79 } stencil; 78 } stencil;
80 79
81 struct { 80 struct Blend {
82 bool enabled; // GL_BLEND 81 bool enabled; // GL_BLEND
82 bool separate_alpha; // Independent blend enabled
83 GLenum rgb_equation; // GL_BLEND_EQUATION_RGB 83 GLenum rgb_equation; // GL_BLEND_EQUATION_RGB
84 GLenum a_equation; // GL_BLEND_EQUATION_ALPHA 84 GLenum a_equation; // GL_BLEND_EQUATION_ALPHA
85 GLenum src_rgb_func; // GL_BLEND_SRC_RGB 85 GLenum src_rgb_func; // GL_BLEND_SRC_RGB
86 GLenum dst_rgb_func; // GL_BLEND_DST_RGB 86 GLenum dst_rgb_func; // GL_BLEND_DST_RGB
87 GLenum src_a_func; // GL_BLEND_SRC_ALPHA 87 GLenum src_a_func; // GL_BLEND_SRC_ALPHA
88 GLenum dst_a_func; // GL_BLEND_DST_ALPHA 88 GLenum dst_a_func; // GL_BLEND_DST_ALPHA
89 };
90 std::array<Blend, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> blend;
89 91
90 struct { 92 struct {
91 GLclampf red; 93 bool enabled;
92 GLclampf green; 94 } independant_blend;
93 GLclampf blue; 95
94 GLclampf alpha; 96 struct {
95 } color; // GL_BLEND_COLOR 97 GLclampf red;
96 } blend; 98 GLclampf green;
99 GLclampf blue;
100 GLclampf alpha;
101 } blend_color; // GL_BLEND_COLOR
97 102
98 struct { 103 struct {
99 bool enabled; // GL_LOGIC_OP_MODE 104 bool enabled; // GL_LOGIC_OP_MODE
@@ -138,6 +143,16 @@ public:
138 GLuint program_pipeline; // GL_PROGRAM_PIPELINE_BINDING 143 GLuint program_pipeline; // GL_PROGRAM_PIPELINE_BINDING
139 } draw; 144 } draw;
140 145
146 struct viewport {
147 GLfloat x;
148 GLfloat y;
149 GLfloat width;
150 GLfloat height;
151 GLfloat depth_range_near; // GL_DEPTH_RANGE
152 GLfloat depth_range_far; // GL_DEPTH_RANGE
153 };
154 std::array<viewport, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> viewports;
155
141 struct { 156 struct {
142 bool enabled; // GL_SCISSOR_TEST 157 bool enabled; // GL_SCISSOR_TEST
143 GLint x; 158 GLint x;
@@ -147,13 +162,6 @@ public:
147 } scissor; 162 } scissor;
148 163
149 struct { 164 struct {
150 GLint x;
151 GLint y;
152 GLsizei width;
153 GLsizei height;
154 } viewport;
155
156 struct {
157 float size; // GL_POINT_SIZE 165 float size; // GL_POINT_SIZE
158 } point; 166 } point;
159 167
@@ -191,14 +199,18 @@ private:
191 static bool s_rgb_used; 199 static bool s_rgb_used;
192 void ApplySRgb() const; 200 void ApplySRgb() const;
193 void ApplyCulling() const; 201 void ApplyCulling() const;
202 void ApplyColorMask() const;
194 void ApplyDepth() const; 203 void ApplyDepth() const;
195 void ApplyPrimitiveRestart() const; 204 void ApplyPrimitiveRestart() const;
196 void ApplyStencilTest() const; 205 void ApplyStencilTest() const;
197 void ApplyScissorTest() const; 206 void ApplyViewport() const;
207 void ApplyTargetBlending(int target, bool force) const;
208 void ApplyGlobalBlending() const;
198 void ApplyBlending() const; 209 void ApplyBlending() const;
199 void ApplyLogicOp() const; 210 void ApplyLogicOp() const;
200 void ApplyTextures() const; 211 void ApplyTextures() const;
201 void ApplySamplers() const; 212 void ApplySamplers() const;
213 void ApplyScissor() const;
202}; 214};
203 215
204} // namespace OpenGL 216} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_stream_buffer.cpp b/src/video_core/renderer_opengl/gl_stream_buffer.cpp
index e409228cc..b97b895a4 100644
--- a/src/video_core/renderer_opengl/gl_stream_buffer.cpp
+++ b/src/video_core/renderer_opengl/gl_stream_buffer.cpp
@@ -6,9 +6,13 @@
6#include <vector> 6#include <vector>
7#include "common/alignment.h" 7#include "common/alignment.h"
8#include "common/assert.h" 8#include "common/assert.h"
9#include "common/microprofile.h"
9#include "video_core/renderer_opengl/gl_state.h" 10#include "video_core/renderer_opengl/gl_state.h"
10#include "video_core/renderer_opengl/gl_stream_buffer.h" 11#include "video_core/renderer_opengl/gl_stream_buffer.h"
11 12
13MICROPROFILE_DEFINE(OpenGL_StreamBuffer, "OpenGL", "Stream Buffer Orphaning",
14 MP_RGB(128, 128, 192));
15
12namespace OpenGL { 16namespace OpenGL {
13 17
14OGLStreamBuffer::OGLStreamBuffer(GLenum target, GLsizeiptr size, bool prefer_coherent) 18OGLStreamBuffer::OGLStreamBuffer(GLenum target, GLsizeiptr size, bool prefer_coherent)
@@ -75,6 +79,7 @@ std::tuple<u8*, GLintptr, bool> OGLStreamBuffer::Map(GLsizeiptr size, GLintptr a
75 } 79 }
76 80
77 if (invalidate || !persistent) { 81 if (invalidate || !persistent) {
82 MICROPROFILE_SCOPE(OpenGL_StreamBuffer);
78 GLbitfield flags = GL_MAP_WRITE_BIT | (persistent ? GL_MAP_PERSISTENT_BIT : 0) | 83 GLbitfield flags = GL_MAP_WRITE_BIT | (persistent ? GL_MAP_PERSISTENT_BIT : 0) |
79 (coherent ? GL_MAP_COHERENT_BIT : GL_MAP_FLUSH_EXPLICIT_BIT) | 84 (coherent ? GL_MAP_COHERENT_BIT : GL_MAP_FLUSH_EXPLICIT_BIT) |
80 (invalidate ? GL_MAP_INVALIDATE_BUFFER_BIT : GL_MAP_UNSYNCHRONIZED_BIT); 85 (invalidate ? GL_MAP_INVALIDATE_BUFFER_BIT : GL_MAP_UNSYNCHRONIZED_BIT);
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};