summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt3
-rw-r--r--src/core/hle/kernel/errors.h8
-rw-r--r--src/core/hle/kernel/svc.cpp14
-rw-r--r--src/core/hle/kernel/svc_wrap.h4
-rw-r--r--src/core/hle/kernel/thread.cpp4
-rw-r--r--src/core/hle/service/audio/audio.cpp1
-rw-r--r--src/core/hle/service/audio/audio.h4
-rw-r--r--src/core/hle/service/audio/audout_u.cpp17
-rw-r--r--src/core/hle/service/audio/audout_u.h17
-rw-r--r--src/core/hle/service/audio/audren_u.cpp6
-rw-r--r--src/core/hle/service/audio/audren_u.h1
-rw-r--r--src/core/hle/service/audio/hwopus.cpp5
-rw-r--r--src/core/hle/service/prepo/prepo.cpp63
-rw-r--r--src/core/hle/service/prepo/prepo.h16
-rw-r--r--src/video_core/engines/shader_bytecode.h74
-rw-r--r--src/video_core/renderer_base.cpp1
-rw-r--r--src/video_core/renderer_base.h1
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp41
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h8
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp125
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp6
-rw-r--r--src/yuzu/configuration/configure_graphics.cpp16
-rw-r--r--src/yuzu/configuration/configure_graphics.h1
-rw-r--r--src/yuzu/configuration/configure_graphics.ui21
-rw-r--r--src/yuzu/game_list.cpp8
-rw-r--r--src/yuzu/main.cpp2
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp2
27 files changed, 367 insertions, 102 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0f32ecfba..500d099fc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -431,6 +431,9 @@ enable_testing()
431add_subdirectory(externals) 431add_subdirectory(externals)
432add_subdirectory(src) 432add_subdirectory(src)
433 433
434# Set yuzu project as default StartUp Project in Visual Studio
435set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT yuzu)
436
434 437
435# Installation instructions 438# Installation instructions
436# ========================= 439# =========================
diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h
index 4054d5db6..ad39c8271 100644
--- a/src/core/hle/kernel/errors.h
+++ b/src/core/hle/kernel/errors.h
@@ -21,6 +21,7 @@ enum {
21 HandleTableFull = 105, 21 HandleTableFull = 105,
22 InvalidMemoryState = 106, 22 InvalidMemoryState = 106,
23 InvalidMemoryPermissions = 108, 23 InvalidMemoryPermissions = 108,
24 InvalidThreadPriority = 112,
24 InvalidProcessorId = 113, 25 InvalidProcessorId = 113,
25 InvalidHandle = 114, 26 InvalidHandle = 114,
26 InvalidCombination = 116, 27 InvalidCombination = 116,
@@ -36,7 +37,7 @@ enum {
36// WARNING: The kernel is quite inconsistent in it's usage of errors code. Make sure to always 37// WARNING: The kernel is quite inconsistent in it's usage of errors code. Make sure to always
37// double check that the code matches before re-using the constant. 38// double check that the code matches before re-using the constant.
38 39
39// TODO(bunnei): Replace these with correct errors for Switch OS 40// TODO(bunnei): Replace -1 with correct errors for Switch OS
40constexpr ResultCode ERR_HANDLE_TABLE_FULL(ErrorModule::Kernel, ErrCodes::HandleTableFull); 41constexpr ResultCode ERR_HANDLE_TABLE_FULL(ErrorModule::Kernel, ErrCodes::HandleTableFull);
41constexpr ResultCode ERR_SESSION_CLOSED_BY_REMOTE(-1); 42constexpr ResultCode ERR_SESSION_CLOSED_BY_REMOTE(-1);
42constexpr ResultCode ERR_PORT_NAME_TOO_LONG(ErrorModule::Kernel, ErrCodes::TooLarge); 43constexpr ResultCode ERR_PORT_NAME_TOO_LONG(ErrorModule::Kernel, ErrCodes::TooLarge);
@@ -53,15 +54,16 @@ constexpr ResultCode ERR_INVALID_ADDRESS_STATE(ErrorModule::Kernel, ErrCodes::In
53constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS(ErrorModule::Kernel, 54constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS(ErrorModule::Kernel,
54 ErrCodes::InvalidMemoryPermissions); 55 ErrCodes::InvalidMemoryPermissions);
55constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle); 56constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle);
57constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId);
56constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState); 58constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState);
59constexpr ResultCode ERR_INVALID_THREAD_PRIORITY(ErrorModule::Kernel,
60 ErrCodes::InvalidThreadPriority);
57constexpr ResultCode ERR_INVALID_POINTER(-1); 61constexpr ResultCode ERR_INVALID_POINTER(-1);
58constexpr ResultCode ERR_INVALID_OBJECT_ADDR(-1); 62constexpr ResultCode ERR_INVALID_OBJECT_ADDR(-1);
59constexpr ResultCode ERR_NOT_AUTHORIZED(-1); 63constexpr ResultCode ERR_NOT_AUTHORIZED(-1);
60/// Alternate code returned instead of ERR_INVALID_HANDLE in some code paths. 64/// Alternate code returned instead of ERR_INVALID_HANDLE in some code paths.
61constexpr ResultCode ERR_INVALID_HANDLE_OS(-1); 65constexpr ResultCode ERR_INVALID_HANDLE_OS(-1);
62constexpr ResultCode ERR_NOT_FOUND(-1); 66constexpr ResultCode ERR_NOT_FOUND(-1);
63constexpr ResultCode ERR_OUT_OF_RANGE(-1);
64constexpr ResultCode ERR_OUT_OF_RANGE_KERNEL(-1);
65constexpr ResultCode RESULT_TIMEOUT(ErrorModule::Kernel, ErrCodes::Timeout); 67constexpr ResultCode RESULT_TIMEOUT(ErrorModule::Kernel, ErrCodes::Timeout);
66/// Returned when Accept() is called on a port with no sessions to be accepted. 68/// Returned when Accept() is called on a port with no sessions to be accepted.
67constexpr ResultCode ERR_NO_PENDING_SESSIONS(-1); 69constexpr ResultCode ERR_NO_PENDING_SESSIONS(-1);
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 1c9373ed8..f500fd2e7 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -273,7 +273,11 @@ static void Break(u64 reason, u64 info1, u64 info2) {
273} 273}
274 274
275/// Used to output a message on a debug hardware unit - does nothing on a retail unit 275/// Used to output a message on a debug hardware unit - does nothing on a retail unit
276static void OutputDebugString(VAddr address, s32 len) { 276static void OutputDebugString(VAddr address, u64 len) {
277 if (len == 0) {
278 return;
279 }
280
277 std::string str(len, '\0'); 281 std::string str(len, '\0');
278 Memory::ReadBlock(address, str.data(), str.size()); 282 Memory::ReadBlock(address, str.data(), str.size());
279 LOG_DEBUG(Debug_Emulated, "{}", str); 283 LOG_DEBUG(Debug_Emulated, "{}", str);
@@ -378,7 +382,7 @@ static ResultCode GetThreadPriority(u32* priority, Handle handle) {
378/// Sets the priority for the specified thread 382/// Sets the priority for the specified thread
379static ResultCode SetThreadPriority(Handle handle, u32 priority) { 383static ResultCode SetThreadPriority(Handle handle, u32 priority) {
380 if (priority > THREADPRIO_LOWEST) { 384 if (priority > THREADPRIO_LOWEST) {
381 return ERR_OUT_OF_RANGE; 385 return ERR_INVALID_THREAD_PRIORITY;
382 } 386 }
383 387
384 auto& kernel = Core::System::GetInstance().Kernel(); 388 auto& kernel = Core::System::GetInstance().Kernel();
@@ -523,7 +527,7 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
523 std::string name = fmt::format("unknown-{:X}", entry_point); 527 std::string name = fmt::format("unknown-{:X}", entry_point);
524 528
525 if (priority > THREADPRIO_LOWEST) { 529 if (priority > THREADPRIO_LOWEST) {
526 return ERR_OUT_OF_RANGE; 530 return ERR_INVALID_THREAD_PRIORITY;
527 } 531 }
528 532
529 SharedPtr<ResourceLimit>& resource_limit = Core::CurrentProcess()->resource_limit; 533 SharedPtr<ResourceLimit>& resource_limit = Core::CurrentProcess()->resource_limit;
@@ -544,8 +548,8 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
544 case THREADPROCESSORID_3: 548 case THREADPROCESSORID_3:
545 break; 549 break;
546 default: 550 default:
547 ASSERT_MSG(false, "Unsupported thread processor ID: {}", processor_id); 551 LOG_ERROR(Kernel_SVC, "Invalid thread processor ID: {}", processor_id);
548 break; 552 return ERR_INVALID_PROCESSOR_ID;
549 } 553 }
550 554
551 auto& kernel = Core::System::GetInstance().Kernel(); 555 auto& kernel = Core::System::GetInstance().Kernel();
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h
index 79c3fe31b..1eda5f879 100644
--- a/src/core/hle/kernel/svc_wrap.h
+++ b/src/core/hle/kernel/svc_wrap.h
@@ -222,9 +222,9 @@ void SvcWrap() {
222 func((s64)PARAM(0)); 222 func((s64)PARAM(0));
223} 223}
224 224
225template <void func(u64, s32 len)> 225template <void func(u64, u64 len)>
226void SvcWrap() { 226void SvcWrap() {
227 func(PARAM(0), (s32)(PARAM(1) & 0xFFFFFFFF)); 227 func(PARAM(0), PARAM(1));
228} 228}
229 229
230template <void func(u64, u64, u64)> 230template <void func(u64, u64, u64)>
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 3d10d9af2..3f12a84dc 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -227,12 +227,12 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name
227 // Check if priority is in ranged. Lowest priority -> highest priority id. 227 // Check if priority is in ranged. Lowest priority -> highest priority id.
228 if (priority > THREADPRIO_LOWEST) { 228 if (priority > THREADPRIO_LOWEST) {
229 LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority); 229 LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority);
230 return ERR_OUT_OF_RANGE; 230 return ERR_INVALID_THREAD_PRIORITY;
231 } 231 }
232 232
233 if (processor_id > THREADPROCESSORID_MAX) { 233 if (processor_id > THREADPROCESSORID_MAX) {
234 LOG_ERROR(Kernel_SVC, "Invalid processor id: {}", processor_id); 234 LOG_ERROR(Kernel_SVC, "Invalid processor id: {}", processor_id);
235 return ERR_OUT_OF_RANGE_KERNEL; 235 return ERR_INVALID_PROCESSOR_ID;
236 } 236 }
237 237
238 // TODO(yuriks): Other checks, returning 0xD9001BEA 238 // TODO(yuriks): Other checks, returning 0xD9001BEA
diff --git a/src/core/hle/service/audio/audio.cpp b/src/core/hle/service/audio/audio.cpp
index 6b5e15633..128df7db5 100644
--- a/src/core/hle/service/audio/audio.cpp
+++ b/src/core/hle/service/audio/audio.cpp
@@ -15,6 +15,7 @@
15#include "core/hle/service/audio/audren_u.h" 15#include "core/hle/service/audio/audren_u.h"
16#include "core/hle/service/audio/codecctl.h" 16#include "core/hle/service/audio/codecctl.h"
17#include "core/hle/service/audio/hwopus.h" 17#include "core/hle/service/audio/hwopus.h"
18#include "core/hle/service/service.h"
18 19
19namespace Service::Audio { 20namespace Service::Audio {
20 21
diff --git a/src/core/hle/service/audio/audio.h b/src/core/hle/service/audio/audio.h
index 95e5691f7..f5bd3bf5f 100644
--- a/src/core/hle/service/audio/audio.h
+++ b/src/core/hle/service/audio/audio.h
@@ -4,7 +4,9 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/service/service.h" 7namespace Service::SM {
8class ServiceManager;
9}
8 10
9namespace Service::Audio { 11namespace Service::Audio {
10 12
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index 05100ca8f..80a002322 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -3,15 +3,20 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <array> 5#include <array>
6#include <cstring>
6#include <vector> 7#include <vector>
7 8
9#include "audio_core/audio_out.h"
8#include "audio_core/codec.h" 10#include "audio_core/codec.h"
11#include "common/common_funcs.h"
9#include "common/logging/log.h" 12#include "common/logging/log.h"
13#include "common/swap.h"
10#include "core/core.h" 14#include "core/core.h"
11#include "core/hle/ipc_helpers.h" 15#include "core/hle/ipc_helpers.h"
12#include "core/hle/kernel/event.h" 16#include "core/hle/kernel/event.h"
13#include "core/hle/kernel/hle_ipc.h" 17#include "core/hle/kernel/hle_ipc.h"
14#include "core/hle/service/audio/audout_u.h" 18#include "core/hle/service/audio/audout_u.h"
19#include "core/memory.h"
15 20
16namespace Service::Audio { 21namespace Service::Audio {
17 22
@@ -25,6 +30,18 @@ enum {
25constexpr std::array<char, 10> DefaultDevice{{"DeviceOut"}}; 30constexpr std::array<char, 10> DefaultDevice{{"DeviceOut"}};
26constexpr int DefaultSampleRate{48000}; 31constexpr int DefaultSampleRate{48000};
27 32
33struct AudoutParams {
34 s32_le sample_rate;
35 u16_le channel_count;
36 INSERT_PADDING_BYTES(2);
37};
38static_assert(sizeof(AudoutParams) == 0x8, "AudoutParams is an invalid size");
39
40enum class AudioState : u32 {
41 Started,
42 Stopped,
43};
44
28class IAudioOut final : public ServiceFramework<IAudioOut> { 45class IAudioOut final : public ServiceFramework<IAudioOut> {
29public: 46public:
30 IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core) 47 IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core)
diff --git a/src/core/hle/service/audio/audout_u.h b/src/core/hle/service/audio/audout_u.h
index aa52d3855..dcaf64708 100644
--- a/src/core/hle/service/audio/audout_u.h
+++ b/src/core/hle/service/audio/audout_u.h
@@ -4,27 +4,18 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "audio_core/audio_out.h"
8#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
9 8
9namespace AudioCore {
10class AudioOut;
11}
12
10namespace Kernel { 13namespace Kernel {
11class HLERequestContext; 14class HLERequestContext;
12} 15}
13 16
14namespace Service::Audio { 17namespace Service::Audio {
15 18
16struct AudoutParams {
17 s32_le sample_rate;
18 u16_le channel_count;
19 INSERT_PADDING_BYTES(2);
20};
21static_assert(sizeof(AudoutParams) == 0x8, "AudoutParams is an invalid size");
22
23enum class AudioState : u32 {
24 Started,
25 Stopped,
26};
27
28class IAudioOut; 19class IAudioOut;
29 20
30class AudOutU final : public ServiceFramework<AudOutU> { 21class AudOutU final : public ServiceFramework<AudOutU> {
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 3870bec65..e84c4fa2b 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -2,12 +2,14 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
5#include <array> 6#include <array>
7#include <memory>
6 8
9#include "audio_core/audio_renderer.h"
7#include "common/alignment.h" 10#include "common/alignment.h"
11#include "common/common_funcs.h"
8#include "common/logging/log.h" 12#include "common/logging/log.h"
9#include "core/core_timing.h"
10#include "core/core_timing_util.h"
11#include "core/hle/ipc_helpers.h" 13#include "core/hle/ipc_helpers.h"
12#include "core/hle/kernel/event.h" 14#include "core/hle/kernel/event.h"
13#include "core/hle/kernel/hle_ipc.h" 15#include "core/hle/kernel/hle_ipc.h"
diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h
index 85a995a2f..c6bc3a90a 100644
--- a/src/core/hle/service/audio/audren_u.h
+++ b/src/core/hle/service/audio/audren_u.h
@@ -4,7 +4,6 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "audio_core/audio_renderer.h"
8#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
9 8
10namespace Kernel { 9namespace Kernel {
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
index 341bfda42..668fef145 100644
--- a/src/core/hle/service/audio/hwopus.cpp
+++ b/src/core/hle/service/audio/hwopus.cpp
@@ -3,7 +3,12 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring> 5#include <cstring>
6#include <memory>
7#include <vector>
8
6#include <opus.h> 9#include <opus.h>
10
11#include "common/common_funcs.h"
7#include "common/logging/log.h" 12#include "common/logging/log.h"
8#include "core/hle/ipc_helpers.h" 13#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/hle_ipc.h" 14#include "core/hle/kernel/hle_ipc.h"
diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp
index 3c43b8d8c..6a9eccfb5 100644
--- a/src/core/hle/service/prepo/prepo.cpp
+++ b/src/core/hle/service/prepo/prepo.cpp
@@ -1,36 +1,47 @@
1#include <cinttypes> 1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
2#include "common/logging/log.h" 5#include "common/logging/log.h"
3#include "core/hle/ipc_helpers.h" 6#include "core/hle/ipc_helpers.h"
4#include "core/hle/kernel/event.h"
5#include "core/hle/service/prepo/prepo.h" 7#include "core/hle/service/prepo/prepo.h"
8#include "core/hle/service/service.h"
6 9
7namespace Service::PlayReport { 10namespace Service::PlayReport {
8PlayReport::PlayReport(const char* name) : ServiceFramework(name) {
9 static const FunctionInfo functions[] = {
10 {10100, nullptr, "SaveReport"},
11 {10101, &PlayReport::SaveReportWithUser, "SaveReportWithUser"},
12 {10200, nullptr, "RequestImmediateTransmission"},
13 {10300, nullptr, "GetTransmissionStatus"},
14 {20100, nullptr, "SaveSystemReport"},
15 {20200, nullptr, "SetOperationMode"},
16 {20101, nullptr, "SaveSystemReportWithUser"},
17 {30100, nullptr, "ClearStorage"},
18 {40100, nullptr, "IsUserAgreementCheckEnabled"},
19 {40101, nullptr, "SetUserAgreementCheckEnabled"},
20 {90100, nullptr, "GetStorageUsage"},
21 {90200, nullptr, "GetStatistics"},
22 {90201, nullptr, "GetThroughputHistory"},
23 {90300, nullptr, "GetLastUploadError"},
24 };
25 RegisterHandlers(functions);
26};
27 11
28void PlayReport::SaveReportWithUser(Kernel::HLERequestContext& ctx) { 12class PlayReport final : public ServiceFramework<PlayReport> {
29 // TODO(ogniK): Do we want to add play report? 13public:
30 LOG_WARNING(Service_PREPO, "(STUBBED) called"); 14 explicit PlayReport(const char* name) : ServiceFramework{name} {
15 // clang-format off
16 static const FunctionInfo functions[] = {
17 {10100, nullptr, "SaveReport"},
18 {10101, &PlayReport::SaveReportWithUser, "SaveReportWithUser"},
19 {10200, nullptr, "RequestImmediateTransmission"},
20 {10300, nullptr, "GetTransmissionStatus"},
21 {20100, nullptr, "SaveSystemReport"},
22 {20200, nullptr, "SetOperationMode"},
23 {20101, nullptr, "SaveSystemReportWithUser"},
24 {30100, nullptr, "ClearStorage"},
25 {40100, nullptr, "IsUserAgreementCheckEnabled"},
26 {40101, nullptr, "SetUserAgreementCheckEnabled"},
27 {90100, nullptr, "GetStorageUsage"},
28 {90200, nullptr, "GetStatistics"},
29 {90201, nullptr, "GetThroughputHistory"},
30 {90300, nullptr, "GetLastUploadError"},
31 };
32 // clang-format on
33
34 RegisterHandlers(functions);
35 }
36
37private:
38 void SaveReportWithUser(Kernel::HLERequestContext& ctx) {
39 // TODO(ogniK): Do we want to add play report?
40 LOG_WARNING(Service_PREPO, "(STUBBED) called");
31 41
32 IPC::ResponseBuilder rb{ctx, 2}; 42 IPC::ResponseBuilder rb{ctx, 2};
33 rb.Push(RESULT_SUCCESS); 43 rb.Push(RESULT_SUCCESS);
44 }
34}; 45};
35 46
36void InstallInterfaces(SM::ServiceManager& service_manager) { 47void InstallInterfaces(SM::ServiceManager& service_manager) {
diff --git a/src/core/hle/service/prepo/prepo.h b/src/core/hle/service/prepo/prepo.h
index f5a6aba6d..0e7b01331 100644
--- a/src/core/hle/service/prepo/prepo.h
+++ b/src/core/hle/service/prepo/prepo.h
@@ -4,22 +4,12 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory> 7namespace Service::SM {
8#include <string> 8class ServiceManager;
9#include "core/hle/kernel/event.h" 9}
10#include "core/hle/service/service.h"
11 10
12namespace Service::PlayReport { 11namespace Service::PlayReport {
13 12
14class PlayReport final : public ServiceFramework<PlayReport> {
15public:
16 explicit PlayReport(const char* name);
17 ~PlayReport() = default;
18
19private:
20 void SaveReportWithUser(Kernel::HLERequestContext& ctx);
21};
22
23void InstallInterfaces(SM::ServiceManager& service_manager); 13void InstallInterfaces(SM::ServiceManager& service_manager);
24 14
25} // namespace Service::PlayReport 15} // namespace Service::PlayReport
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 9176a8dbc..58f2904ce 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -254,6 +254,15 @@ enum class TextureQueryType : u64 {
254 BorderColor = 22, 254 BorderColor = 22,
255}; 255};
256 256
257enum class TextureProcessMode : u64 {
258 None = 0,
259 LZ = 1, // Unknown, appears to be the same as none.
260 LB = 2, // Load Bias.
261 LL = 3, // Load LOD (LevelOfDetail)
262 LBA = 6, // Load Bias. The A is unknown, does not appear to differ with LB
263 LLA = 7 // Load LOD. The A is unknown, does not appear to differ with LL
264};
265
257enum class IpaInterpMode : u64 { Linear = 0, Perspective = 1, Flat = 2, Sc = 3 }; 266enum class IpaInterpMode : u64 { Linear = 0, Perspective = 1, Flat = 2, Sc = 3 };
258enum class IpaSampleMode : u64 { Default = 0, Centroid = 1, Offset = 2 }; 267enum class IpaSampleMode : u64 { Default = 0, Centroid = 1, Offset = 2 };
259 268
@@ -424,6 +433,45 @@ union Instruction {
424 } bfe; 433 } bfe;
425 434
426 union { 435 union {
436 BitField<48, 3, u64> pred48;
437
438 union {
439 BitField<20, 20, u64> entry_a;
440 BitField<39, 5, u64> entry_b;
441 BitField<45, 1, u64> neg;
442 BitField<46, 1, u64> uses_cc;
443 } imm;
444
445 union {
446 BitField<20, 14, u64> cb_index;
447 BitField<34, 5, u64> cb_offset;
448 BitField<56, 1, u64> neg;
449 BitField<57, 1, u64> uses_cc;
450 } hi;
451
452 union {
453 BitField<20, 14, u64> cb_index;
454 BitField<34, 5, u64> cb_offset;
455 BitField<39, 5, u64> entry_a;
456 BitField<45, 1, u64> neg;
457 BitField<46, 1, u64> uses_cc;
458 } rz;
459
460 union {
461 BitField<39, 5, u64> entry_a;
462 BitField<45, 1, u64> neg;
463 BitField<46, 1, u64> uses_cc;
464 } r1;
465
466 union {
467 BitField<28, 8, u64> entry_a;
468 BitField<37, 1, u64> neg;
469 BitField<38, 1, u64> uses_cc;
470 } r2;
471
472 } lea;
473
474 union {
427 BitField<0, 5, FlowCondition> cond; 475 BitField<0, 5, FlowCondition> cond;
428 } flow; 476 } flow;
429 477
@@ -478,6 +526,18 @@ union Instruction {
478 } psetp; 526 } psetp;
479 527
480 union { 528 union {
529 BitField<12, 3, u64> pred12;
530 BitField<15, 1, u64> neg_pred12;
531 BitField<24, 2, PredOperation> cond;
532 BitField<29, 3, u64> pred29;
533 BitField<32, 1, u64> neg_pred29;
534 BitField<39, 3, u64> pred39;
535 BitField<42, 1, u64> neg_pred39;
536 BitField<44, 1, u64> bf;
537 BitField<45, 2, PredOperation> op;
538 } pset;
539
540 union {
481 BitField<39, 3, u64> pred39; 541 BitField<39, 3, u64> pred39;
482 BitField<42, 1, u64> neg_pred; 542 BitField<42, 1, u64> neg_pred;
483 BitField<43, 1, u64> neg_a; 543 BitField<43, 1, u64> neg_a;
@@ -522,6 +582,7 @@ union Instruction {
522 BitField<28, 1, u64> array; 582 BitField<28, 1, u64> array;
523 BitField<29, 2, TextureType> texture_type; 583 BitField<29, 2, TextureType> texture_type;
524 BitField<31, 4, u64> component_mask; 584 BitField<31, 4, u64> component_mask;
585 BitField<55, 3, TextureProcessMode> process_mode;
525 586
526 bool IsComponentEnabled(size_t component) const { 587 bool IsComponentEnabled(size_t component) const {
527 return ((1ull << component) & component_mask) != 0; 588 return ((1ull << component) & component_mask) != 0;
@@ -726,6 +787,11 @@ public:
726 ISCADD_C, // Scale and Add 787 ISCADD_C, // Scale and Add
727 ISCADD_R, 788 ISCADD_R,
728 ISCADD_IMM, 789 ISCADD_IMM,
790 LEA_R1,
791 LEA_R2,
792 LEA_RZ,
793 LEA_IMM,
794 LEA_HI,
729 POPC_C, 795 POPC_C,
730 POPC_R, 796 POPC_R,
731 POPC_IMM, 797 POPC_IMM,
@@ -784,6 +850,7 @@ public:
784 ISET_C, 850 ISET_C,
785 ISET_IMM, 851 ISET_IMM,
786 PSETP, 852 PSETP,
853 PSET,
787 XMAD_IMM, 854 XMAD_IMM,
788 XMAD_CR, 855 XMAD_CR,
789 XMAD_RC, 856 XMAD_RC,
@@ -807,6 +874,7 @@ public:
807 IntegerSet, 874 IntegerSet,
808 IntegerSetPredicate, 875 IntegerSetPredicate,
809 PredicateSetPredicate, 876 PredicateSetPredicate,
877 PredicateSetRegister,
810 Conversion, 878 Conversion,
811 Xmad, 879 Xmad,
812 Unknown, 880 Unknown,
@@ -958,6 +1026,11 @@ private:
958 INST("0100110010100---", Id::SEL_C, Type::ArithmeticInteger, "SEL_C"), 1026 INST("0100110010100---", Id::SEL_C, Type::ArithmeticInteger, "SEL_C"),
959 INST("0101110010100---", Id::SEL_R, Type::ArithmeticInteger, "SEL_R"), 1027 INST("0101110010100---", Id::SEL_R, Type::ArithmeticInteger, "SEL_R"),
960 INST("0011100-10100---", Id::SEL_IMM, Type::ArithmeticInteger, "SEL_IMM"), 1028 INST("0011100-10100---", Id::SEL_IMM, Type::ArithmeticInteger, "SEL_IMM"),
1029 INST("0101101111011---", Id::LEA_R2, Type::ArithmeticInteger, "LEA_R2"),
1030 INST("0101101111010---", Id::LEA_R1, Type::ArithmeticInteger, "LEA_R1"),
1031 INST("001101101101----", Id::LEA_IMM, Type::ArithmeticInteger, "LEA_IMM"),
1032 INST("010010111101----", Id::LEA_RZ, Type::ArithmeticInteger, "LEA_RZ"),
1033 INST("00011000--------", Id::LEA_HI, Type::ArithmeticInteger, "LEA_HI"),
961 INST("0101000010000---", Id::MUFU, Type::Arithmetic, "MUFU"), 1034 INST("0101000010000---", Id::MUFU, Type::Arithmetic, "MUFU"),
962 INST("0100110010010---", Id::RRO_C, Type::Arithmetic, "RRO_C"), 1035 INST("0100110010010---", Id::RRO_C, Type::Arithmetic, "RRO_C"),
963 INST("0101110010010---", Id::RRO_R, Type::Arithmetic, "RRO_R"), 1036 INST("0101110010010---", Id::RRO_R, Type::Arithmetic, "RRO_R"),
@@ -1012,6 +1085,7 @@ private:
1012 INST("010110110101----", Id::ISET_R, Type::IntegerSet, "ISET_R"), 1085 INST("010110110101----", Id::ISET_R, Type::IntegerSet, "ISET_R"),
1013 INST("010010110101----", Id::ISET_C, Type::IntegerSet, "ISET_C"), 1086 INST("010010110101----", Id::ISET_C, Type::IntegerSet, "ISET_C"),
1014 INST("0011011-0101----", Id::ISET_IMM, Type::IntegerSet, "ISET_IMM"), 1087 INST("0011011-0101----", Id::ISET_IMM, Type::IntegerSet, "ISET_IMM"),
1088 INST("0101000010001---", Id::PSET, Type::PredicateSetRegister, "PSET"),
1015 INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"), 1089 INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"),
1016 INST("0011011-00------", Id::XMAD_IMM, Type::Xmad, "XMAD_IMM"), 1090 INST("0011011-00------", Id::XMAD_IMM, Type::Xmad, "XMAD_IMM"),
1017 INST("0100111---------", Id::XMAD_CR, Type::Xmad, "XMAD_CR"), 1091 INST("0100111---------", Id::XMAD_CR, Type::Xmad, "XMAD_CR"),
diff --git a/src/video_core/renderer_base.cpp b/src/video_core/renderer_base.cpp
index be17a2b9c..0df3725c2 100644
--- a/src/video_core/renderer_base.cpp
+++ b/src/video_core/renderer_base.cpp
@@ -19,6 +19,7 @@ void RendererBase::RefreshBaseSettings() {
19 UpdateCurrentFramebufferLayout(); 19 UpdateCurrentFramebufferLayout();
20 20
21 renderer_settings.use_framelimiter = Settings::values.use_frame_limit; 21 renderer_settings.use_framelimiter = Settings::values.use_frame_limit;
22 renderer_settings.set_background_color = true;
22} 23}
23 24
24void RendererBase::UpdateCurrentFramebufferLayout() { 25void RendererBase::UpdateCurrentFramebufferLayout() {
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h
index 2a357f9d0..2cd0738ff 100644
--- a/src/video_core/renderer_base.h
+++ b/src/video_core/renderer_base.h
@@ -19,6 +19,7 @@ namespace VideoCore {
19 19
20struct RendererSettings { 20struct RendererSettings {
21 std::atomic_bool use_framelimiter{false}; 21 std::atomic_bool use_framelimiter{false};
22 std::atomic_bool set_background_color{false};
22}; 23};
23 24
24class RendererBase : NonCopyable { 25class RendererBase : NonCopyable {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 29d61eccd..fb56decc0 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -53,8 +53,6 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) {
53 params.width = Common::AlignUp(config.tic.Width(), GetCompressionFactor(params.pixel_format)); 53 params.width = Common::AlignUp(config.tic.Width(), GetCompressionFactor(params.pixel_format));
54 params.height = Common::AlignUp(config.tic.Height(), GetCompressionFactor(params.pixel_format)); 54 params.height = Common::AlignUp(config.tic.Height(), GetCompressionFactor(params.pixel_format));
55 params.unaligned_height = config.tic.Height(); 55 params.unaligned_height = config.tic.Height();
56 params.cache_width = Common::AlignUp(params.width, 8);
57 params.cache_height = Common::AlignUp(params.height, 8);
58 params.target = SurfaceTargetFromTextureType(config.tic.texture_type); 56 params.target = SurfaceTargetFromTextureType(config.tic.texture_type);
59 57
60 switch (params.target) { 58 switch (params.target) {
@@ -89,8 +87,6 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) {
89 params.width = config.width; 87 params.width = config.width;
90 params.height = config.height; 88 params.height = config.height;
91 params.unaligned_height = config.height; 89 params.unaligned_height = config.height;
92 params.cache_width = Common::AlignUp(params.width, 8);
93 params.cache_height = Common::AlignUp(params.height, 8);
94 params.target = SurfaceTarget::Texture2D; 90 params.target = SurfaceTarget::Texture2D;
95 params.depth = 1; 91 params.depth = 1;
96 params.size_in_bytes = params.SizeInBytes(); 92 params.size_in_bytes = params.SizeInBytes();
@@ -110,8 +106,6 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) {
110 params.width = zeta_width; 106 params.width = zeta_width;
111 params.height = zeta_height; 107 params.height = zeta_height;
112 params.unaligned_height = zeta_height; 108 params.unaligned_height = zeta_height;
113 params.cache_width = Common::AlignUp(params.width, 8);
114 params.cache_height = Common::AlignUp(params.height, 8);
115 params.target = SurfaceTarget::Texture2D; 109 params.target = SurfaceTarget::Texture2D;
116 params.depth = 1; 110 params.depth = 1;
117 params.size_in_bytes = params.SizeInBytes(); 111 params.size_in_bytes = params.SizeInBytes();
@@ -477,30 +471,27 @@ CachedSurface::CachedSurface(const SurfaceParams& params)
477 // Only pre-create the texture for non-compressed textures. 471 // Only pre-create the texture for non-compressed textures.
478 switch (params.target) { 472 switch (params.target) {
479 case SurfaceParams::SurfaceTarget::Texture1D: 473 case SurfaceParams::SurfaceTarget::Texture1D:
480 glTexImage1D(SurfaceTargetToGL(params.target), 0, format_tuple.internal_format, 474 glTexStorage1D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format,
481 rect.GetWidth(), 0, format_tuple.format, format_tuple.type, nullptr); 475 rect.GetWidth());
482 break; 476 break;
483 case SurfaceParams::SurfaceTarget::Texture2D: 477 case SurfaceParams::SurfaceTarget::Texture2D:
484 glTexImage2D(SurfaceTargetToGL(params.target), 0, format_tuple.internal_format, 478 glTexStorage2D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format,
485 rect.GetWidth(), rect.GetHeight(), 0, format_tuple.format, 479 rect.GetWidth(), rect.GetHeight());
486 format_tuple.type, nullptr);
487 break; 480 break;
488 case SurfaceParams::SurfaceTarget::Texture3D: 481 case SurfaceParams::SurfaceTarget::Texture3D:
489 case SurfaceParams::SurfaceTarget::Texture2DArray: 482 case SurfaceParams::SurfaceTarget::Texture2DArray:
490 glTexImage3D(SurfaceTargetToGL(params.target), 0, format_tuple.internal_format, 483 glTexStorage3D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format,
491 rect.GetWidth(), rect.GetHeight(), params.depth, 0, format_tuple.format, 484 rect.GetWidth(), rect.GetHeight(), params.depth);
492 format_tuple.type, nullptr);
493 break; 485 break;
494 default: 486 default:
495 LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", 487 LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
496 static_cast<u32>(params.target)); 488 static_cast<u32>(params.target));
497 UNREACHABLE(); 489 UNREACHABLE();
498 glTexImage2D(GL_TEXTURE_2D, 0, format_tuple.internal_format, rect.GetWidth(), 490 glTexStorage2D(GL_TEXTURE_2D, 1, format_tuple.internal_format, rect.GetWidth(),
499 rect.GetHeight(), 0, format_tuple.format, format_tuple.type, nullptr); 491 rect.GetHeight());
500 } 492 }
501 } 493 }
502 494
503 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MAX_LEVEL, 0);
504 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MIN_FILTER, GL_LINEAR); 495 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MIN_FILTER, GL_LINEAR);
505 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 496 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
506 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 497 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
@@ -817,16 +808,20 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
817 // Get a new surface with the new parameters, and blit the previous surface to it 808 // Get a new surface with the new parameters, and blit the previous surface to it
818 Surface new_surface{GetUncachedSurface(new_params)}; 809 Surface new_surface{GetUncachedSurface(new_params)};
819 810
820 // If format is unchanged, we can do a faster blit without reinterpreting pixel data 811 if (params.pixel_format == new_params.pixel_format ||
821 if (params.pixel_format == new_params.pixel_format) { 812 !Settings::values.use_accurate_framebuffers) {
813 // If the format is the same, just do a framebuffer blit. This is significantly faster than
814 // using PBOs. The is also likely less accurate, as textures will be converted rather than
815 // reinterpreted.
816
822 BlitTextures(surface->Texture().handle, params.GetRect(), new_surface->Texture().handle, 817 BlitTextures(surface->Texture().handle, params.GetRect(), new_surface->Texture().handle,
823 params.GetRect(), params.type, read_framebuffer.handle, 818 params.GetRect(), params.type, read_framebuffer.handle,
824 draw_framebuffer.handle); 819 draw_framebuffer.handle);
825 return new_surface; 820 } else {
826 } 821 // When use_accurate_framebuffers setting is enabled, perform a more accurate surface copy,
822 // where pixels are reinterpreted as a new format (without conversion). This code path uses
823 // OpenGL PBOs and is quite slow.
827 824
828 // When using accurate framebuffers, always copy old data to new surface, regardless of format
829 if (Settings::values.use_accurate_framebuffers) {
830 auto source_format = GetFormatTuple(params.pixel_format, params.component_type); 825 auto source_format = GetFormatTuple(params.pixel_format, params.component_type);
831 auto dest_format = GetFormatTuple(new_params.pixel_format, new_params.component_type); 826 auto dest_format = GetFormatTuple(new_params.pixel_format, new_params.component_type);
832 827
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index e660998d0..57ea8593b 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -680,8 +680,8 @@ struct SurfaceParams {
680 680
681 /// Checks if surfaces are compatible for caching 681 /// Checks if surfaces are compatible for caching
682 bool IsCompatibleSurface(const SurfaceParams& other) const { 682 bool IsCompatibleSurface(const SurfaceParams& other) const {
683 return std::tie(pixel_format, type, cache_width, cache_height) == 683 return std::tie(pixel_format, type, width, height) ==
684 std::tie(other.pixel_format, other.type, other.cache_width, other.cache_height); 684 std::tie(other.pixel_format, other.type, other.width, other.height);
685 } 685 }
686 686
687 VAddr addr; 687 VAddr addr;
@@ -696,10 +696,6 @@ struct SurfaceParams {
696 u32 unaligned_height; 696 u32 unaligned_height;
697 size_t size_in_bytes; 697 size_t size_in_bytes;
698 SurfaceTarget target; 698 SurfaceTarget target;
699
700 // Parameters used for caching only
701 u32 cache_width;
702 u32 cache_height;
703}; 699};
704 700
705}; // namespace OpenGL 701}; // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index e350113f1..2d56370c7 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -1505,6 +1505,73 @@ private:
1505 1, 1); 1505 1, 1);
1506 break; 1506 break;
1507 } 1507 }
1508 case OpCode::Id::LEA_R2:
1509 case OpCode::Id::LEA_R1:
1510 case OpCode::Id::LEA_IMM:
1511 case OpCode::Id::LEA_RZ:
1512 case OpCode::Id::LEA_HI: {
1513 std::string op_a;
1514 std::string op_b;
1515 std::string op_c;
1516
1517 switch (opcode->GetId()) {
1518 case OpCode::Id::LEA_R2: {
1519 op_a = regs.GetRegisterAsInteger(instr.gpr20);
1520 op_b = regs.GetRegisterAsInteger(instr.gpr39);
1521 op_c = std::to_string(instr.lea.r2.entry_a);
1522 break;
1523 }
1524
1525 case OpCode::Id::LEA_R1: {
1526 const bool neg = instr.lea.r1.neg != 0;
1527 op_a = regs.GetRegisterAsInteger(instr.gpr8);
1528 if (neg)
1529 op_a = "-(" + op_a + ')';
1530 op_b = regs.GetRegisterAsInteger(instr.gpr20);
1531 op_c = std::to_string(instr.lea.r1.entry_a);
1532 break;
1533 }
1534
1535 case OpCode::Id::LEA_IMM: {
1536 const bool neg = instr.lea.imm.neg != 0;
1537 op_b = regs.GetRegisterAsInteger(instr.gpr8);
1538 if (neg)
1539 op_b = "-(" + op_b + ')';
1540 op_a = std::to_string(instr.lea.imm.entry_a);
1541 op_c = std::to_string(instr.lea.imm.entry_b);
1542 break;
1543 }
1544
1545 case OpCode::Id::LEA_RZ: {
1546 const bool neg = instr.lea.rz.neg != 0;
1547 op_b = regs.GetRegisterAsInteger(instr.gpr8);
1548 if (neg)
1549 op_b = "-(" + op_b + ')';
1550 op_a = regs.GetUniform(instr.lea.rz.cb_index, instr.lea.rz.cb_offset,
1551 GLSLRegister::Type::Integer);
1552 op_c = std::to_string(instr.lea.rz.entry_a);
1553
1554 break;
1555 }
1556
1557 case OpCode::Id::LEA_HI:
1558 default: {
1559 op_b = regs.GetRegisterAsInteger(instr.gpr8);
1560 op_a = std::to_string(instr.lea.imm.entry_a);
1561 op_c = std::to_string(instr.lea.imm.entry_b);
1562 LOG_CRITICAL(HW_GPU, "Unhandled LEA subinstruction: {}", opcode->GetName());
1563 UNREACHABLE();
1564 }
1565 }
1566 if (instr.lea.pred48 != static_cast<u64>(Pred::UnusedIndex)) {
1567 LOG_ERROR(HW_GPU, "Unhandled LEA Predicate");
1568 UNREACHABLE();
1569 }
1570 const std::string value = '(' + op_a + " + (" + op_b + "*(1 << " + op_c + ")))";
1571 regs.SetRegisterToInteger(instr.gpr0, true, 0, value, 1, 1);
1572
1573 break;
1574 }
1508 default: { 1575 default: {
1509 LOG_CRITICAL(HW_GPU, "Unhandled ArithmeticInteger instruction: {}", 1576 LOG_CRITICAL(HW_GPU, "Unhandled ArithmeticInteger instruction: {}",
1510 opcode->GetName()); 1577 opcode->GetName());
@@ -1786,15 +1853,47 @@ private:
1786 coord = "vec2 coords = vec2(" + x + ", " + y + ");"; 1853 coord = "vec2 coords = vec2(" + x + ", " + y + ");";
1787 texture_type = Tegra::Shader::TextureType::Texture2D; 1854 texture_type = Tegra::Shader::TextureType::Texture2D;
1788 } 1855 }
1856 // TODO: make sure coordinates are always indexed to gpr8 and gpr20 is always bias
1857 // or lod.
1858 const std::string op_c = regs.GetRegisterAsFloat(instr.gpr20);
1789 1859
1790 const std::string sampler = GetSampler(instr.sampler, texture_type, false); 1860 const std::string sampler = GetSampler(instr.sampler, texture_type, false);
1791 // Add an extra scope and declare the texture coords inside to prevent 1861 // Add an extra scope and declare the texture coords inside to prevent
1792 // overwriting them in case they are used as outputs of the texs instruction. 1862 // overwriting them in case they are used as outputs of the texs instruction.
1863
1793 shader.AddLine("{"); 1864 shader.AddLine("{");
1794 ++shader.scope; 1865 ++shader.scope;
1795 shader.AddLine(coord); 1866 shader.AddLine(coord);
1796 const std::string texture = "texture(" + sampler + ", coords)"; 1867 std::string texture;
1797 1868
1869 switch (instr.tex.process_mode) {
1870 case Tegra::Shader::TextureProcessMode::None: {
1871 texture = "texture(" + sampler + ", coords)";
1872 break;
1873 }
1874 case Tegra::Shader::TextureProcessMode::LZ: {
1875 texture = "textureLod(" + sampler + ", coords, 0.0)";
1876 break;
1877 }
1878 case Tegra::Shader::TextureProcessMode::LB:
1879 case Tegra::Shader::TextureProcessMode::LBA: {
1880 // TODO: Figure if A suffix changes the equation at all.
1881 texture = "texture(" + sampler + ", coords, " + op_c + ')';
1882 break;
1883 }
1884 case Tegra::Shader::TextureProcessMode::LL:
1885 case Tegra::Shader::TextureProcessMode::LLA: {
1886 // TODO: Figure if A suffix changes the equation at all.
1887 texture = "textureLod(" + sampler + ", coords, " + op_c + ')';
1888 break;
1889 }
1890 default: {
1891 texture = "texture(" + sampler + ", coords)";
1892 LOG_CRITICAL(HW_GPU, "Unhandled texture process mode {}",
1893 static_cast<u32>(instr.tex.process_mode.Value()));
1894 UNREACHABLE();
1895 }
1896 }
1798 size_t dest_elem{}; 1897 size_t dest_elem{};
1799 for (size_t elem = 0; elem < 4; ++elem) { 1898 for (size_t elem = 0; elem < 4; ++elem) {
1800 if (!instr.tex.IsComponentEnabled(elem)) { 1899 if (!instr.tex.IsComponentEnabled(elem)) {
@@ -2087,6 +2186,30 @@ private:
2087 } 2186 }
2088 break; 2187 break;
2089 } 2188 }
2189 case OpCode::Type::PredicateSetRegister: {
2190 const std::string op_a =
2191 GetPredicateCondition(instr.pset.pred12, instr.pset.neg_pred12 != 0);
2192 const std::string op_b =
2193 GetPredicateCondition(instr.pset.pred29, instr.pset.neg_pred29 != 0);
2194
2195 const std::string second_pred =
2196 GetPredicateCondition(instr.pset.pred39, instr.pset.neg_pred39 != 0);
2197
2198 const std::string combiner = GetPredicateCombiner(instr.pset.op);
2199
2200 const std::string predicate =
2201 '(' + op_a + ") " + GetPredicateCombiner(instr.pset.cond) + " (" + op_b + ')';
2202 const std::string result = '(' + predicate + ") " + combiner + " (" + second_pred + ')';
2203 if (instr.pset.bf == 0) {
2204 const std::string value = '(' + result + ") ? 0xFFFFFFFF : 0";
2205 regs.SetRegisterToInteger(instr.gpr0, false, 0, value, 1, 1);
2206 } else {
2207 const std::string value = '(' + result + ") ? 1.0 : 0.0";
2208 regs.SetRegisterToFloat(instr.gpr0, 0, value, 1, 1);
2209 }
2210
2211 break;
2212 }
2090 case OpCode::Type::PredicateSetPredicate: { 2213 case OpCode::Type::PredicateSetPredicate: {
2091 const std::string op_a = 2214 const std::string op_a =
2092 GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0); 2215 GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0);
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index ccff3e342..96d916b07 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -369,6 +369,12 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x,
369 * Draws the emulated screens to the emulator window. 369 * Draws the emulated screens to the emulator window.
370 */ 370 */
371void RendererOpenGL::DrawScreen() { 371void RendererOpenGL::DrawScreen() {
372 if (renderer_settings.set_background_color) {
373 // Update background color before drawing
374 glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue,
375 0.0f);
376 }
377
372 const auto& layout = render_window.GetFramebufferLayout(); 378 const auto& layout = render_window.GetFramebufferLayout();
373 const auto& screen = layout.screen; 379 const auto& screen = layout.screen;
374 380
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp
index ee1287028..839d58f59 100644
--- a/src/yuzu/configuration/configure_graphics.cpp
+++ b/src/yuzu/configuration/configure_graphics.cpp
@@ -2,6 +2,7 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <QColorDialog>
5#include "core/core.h" 6#include "core/core.h"
6#include "core/settings.h" 7#include "core/settings.h"
7#include "ui_configure_graphics.h" 8#include "ui_configure_graphics.h"
@@ -16,6 +17,14 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent)
16 ui->frame_limit->setEnabled(Settings::values.use_frame_limit); 17 ui->frame_limit->setEnabled(Settings::values.use_frame_limit);
17 connect(ui->toggle_frame_limit, &QCheckBox::stateChanged, ui->frame_limit, 18 connect(ui->toggle_frame_limit, &QCheckBox::stateChanged, ui->frame_limit,
18 &QSpinBox::setEnabled); 19 &QSpinBox::setEnabled);
20 connect(ui->bg_button, &QPushButton::clicked, this, [this] {
21 const QColor new_bg_color = QColorDialog::getColor(bg_color);
22 if (!new_bg_color.isValid())
23 return;
24 bg_color = new_bg_color;
25 ui->bg_button->setStyleSheet(
26 QString("QPushButton { background-color: %1 }").arg(bg_color.name()));
27 });
19} 28}
20 29
21ConfigureGraphics::~ConfigureGraphics() = default; 30ConfigureGraphics::~ConfigureGraphics() = default;
@@ -65,6 +74,10 @@ void ConfigureGraphics::setConfiguration() {
65 ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit); 74 ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit);
66 ui->frame_limit->setValue(Settings::values.frame_limit); 75 ui->frame_limit->setValue(Settings::values.frame_limit);
67 ui->use_accurate_framebuffers->setChecked(Settings::values.use_accurate_framebuffers); 76 ui->use_accurate_framebuffers->setChecked(Settings::values.use_accurate_framebuffers);
77 bg_color = QColor::fromRgbF(Settings::values.bg_red, Settings::values.bg_green,
78 Settings::values.bg_blue);
79 ui->bg_button->setStyleSheet(
80 QString("QPushButton { background-color: %1 }").arg(bg_color.name()));
68} 81}
69 82
70void ConfigureGraphics::applyConfiguration() { 83void ConfigureGraphics::applyConfiguration() {
@@ -73,4 +86,7 @@ void ConfigureGraphics::applyConfiguration() {
73 Settings::values.use_frame_limit = ui->toggle_frame_limit->isChecked(); 86 Settings::values.use_frame_limit = ui->toggle_frame_limit->isChecked();
74 Settings::values.frame_limit = ui->frame_limit->value(); 87 Settings::values.frame_limit = ui->frame_limit->value();
75 Settings::values.use_accurate_framebuffers = ui->use_accurate_framebuffers->isChecked(); 88 Settings::values.use_accurate_framebuffers = ui->use_accurate_framebuffers->isChecked();
89 Settings::values.bg_red = static_cast<float>(bg_color.redF());
90 Settings::values.bg_green = static_cast<float>(bg_color.greenF());
91 Settings::values.bg_blue = static_cast<float>(bg_color.blueF());
76} 92}
diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h
index 5497a55f7..9bda26fd6 100644
--- a/src/yuzu/configuration/configure_graphics.h
+++ b/src/yuzu/configuration/configure_graphics.h
@@ -25,4 +25,5 @@ private:
25 25
26private: 26private:
27 std::unique_ptr<Ui::ConfigureGraphics> ui; 27 std::unique_ptr<Ui::ConfigureGraphics> ui;
28 QColor bg_color;
28}; 29};
diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui
index 3bc18c26e..8fc00af1b 100644
--- a/src/yuzu/configuration/configure_graphics.ui
+++ b/src/yuzu/configuration/configure_graphics.ui
@@ -96,6 +96,27 @@
96 </item> 96 </item>
97 </layout> 97 </layout>
98 </item> 98 </item>
99 <item>
100 <layout class="QHBoxLayout" name="horizontalLayout_6">
101 <item>
102 <widget class="QLabel" name="bg_label">
103 <property name="text">
104 <string>Background Color:</string>
105 </property>
106 </widget>
107 </item>
108 <item>
109 <widget class="QPushButton" name="bg_button">
110 <property name="maximumSize">
111 <size>
112 <width>40</width>
113 <height>16777215</height>
114 </size>
115 </property>
116 </widget>
117 </item>
118 </layout>
119 </item>
99 </layout> 120 </layout>
100 </widget> 121 </widget>
101 </item> 122 </item>
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index 8c6e16d47..3b3b551bb 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -366,7 +366,7 @@ void GameList::LoadCompatibilityList() {
366 QJsonDocument json = QJsonDocument::fromJson(string_content.toUtf8()); 366 QJsonDocument json = QJsonDocument::fromJson(string_content.toUtf8());
367 QJsonArray arr = json.array(); 367 QJsonArray arr = json.array();
368 368
369 for (const QJsonValue& value : arr) { 369 for (const QJsonValueRef& value : arr) {
370 QJsonObject game = value.toObject(); 370 QJsonObject game = value.toObject();
371 371
372 if (game.contains("compatibility") && game["compatibility"].isDouble()) { 372 if (game.contains("compatibility") && game["compatibility"].isDouble()) {
@@ -374,9 +374,9 @@ void GameList::LoadCompatibilityList() {
374 QString directory = game["directory"].toString(); 374 QString directory = game["directory"].toString();
375 QJsonArray ids = game["releases"].toArray(); 375 QJsonArray ids = game["releases"].toArray();
376 376
377 for (const QJsonValue& value : ids) { 377 for (const QJsonValueRef& id_ref : ids) {
378 QJsonObject object = value.toObject(); 378 QJsonObject id_object = id_ref.toObject();
379 QString id = object["id"].toString(); 379 QString id = id_object["id"].toString();
380 compatibility_list.emplace( 380 compatibility_list.emplace(
381 id.toUpper().toStdString(), 381 id.toUpper().toStdString(),
382 std::make_pair(QString::number(compatibility), directory)); 382 std::make_pair(QString::number(compatibility), directory));
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index e36914f14..05a4a55e8 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -447,6 +447,8 @@ QStringList GMainWindow::GetUnsupportedGLExtensions() {
447 unsupported_ext.append("ARB_texture_mirror_clamp_to_edge"); 447 unsupported_ext.append("ARB_texture_mirror_clamp_to_edge");
448 if (!GLAD_GL_ARB_base_instance) 448 if (!GLAD_GL_ARB_base_instance)
449 unsupported_ext.append("ARB_base_instance"); 449 unsupported_ext.append("ARB_base_instance");
450 if (!GLAD_GL_ARB_texture_storage)
451 unsupported_ext.append("ARB_texture_storage");
450 452
451 // Extensions required to support some texture formats. 453 // Extensions required to support some texture formats.
452 if (!GLAD_GL_EXT_texture_compression_s3tc) 454 if (!GLAD_GL_EXT_texture_compression_s3tc)
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
index 1c4717123..d213929bd 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
@@ -94,6 +94,8 @@ bool EmuWindow_SDL2::SupportsRequiredGLExtensions() {
94 unsupported_ext.push_back("ARB_texture_mirror_clamp_to_edge"); 94 unsupported_ext.push_back("ARB_texture_mirror_clamp_to_edge");
95 if (!GLAD_GL_ARB_base_instance) 95 if (!GLAD_GL_ARB_base_instance)
96 unsupported_ext.push_back("ARB_base_instance"); 96 unsupported_ext.push_back("ARB_base_instance");
97 if (!GLAD_GL_ARB_texture_storage)
98 unsupported_ext.push_back("ARB_texture_storage");
97 99
98 // Extensions required to support some texture formats. 100 // Extensions required to support some texture formats.
99 if (!GLAD_GL_EXT_texture_compression_s3tc) 101 if (!GLAD_GL_EXT_texture_compression_s3tc)