summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/file_sys/patch_manager.cpp49
-rw-r--r--src/core/gdbstub/gdbstub.cpp123
-rw-r--r--src/core/hle/service/am/am.cpp12
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp5
-rw-r--r--src/core/hle/service/filesystem/filesystem.h1
-rw-r--r--src/core/hle/service/sm/sm.cpp54
-rw-r--r--src/core/hle/service/sm/sm.h3
-rw-r--r--src/core/hle/service/vi/vi.cpp32
-rw-r--r--src/core/settings.h1
-rw-r--r--src/video_core/engines/maxwell_3d.h12
-rw-r--r--src/video_core/engines/shader_bytecode.h7
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp49
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h31
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp16
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp1
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.h3
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp171
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.h1
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp37
-rw-r--r--src/video_core/renderer_opengl/gl_state.h9
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp2
-rw-r--r--src/yuzu/applets/software_keyboard.cpp16
-rw-r--r--src/yuzu/applets/software_keyboard.h7
-rw-r--r--src/yuzu/bootmanager.cpp2
-rw-r--r--src/yuzu/configuration/config.cpp2
-rw-r--r--src/yuzu/configuration/configure_debug.cpp2
-rw-r--r--src/yuzu/configuration/configure_debug.ui10
-rw-r--r--src/yuzu/configuration/configure_graphics.ui94
-rw-r--r--src/yuzu/main.cpp18
-rw-r--r--src/yuzu_cmd/config.cpp1
-rw-r--r--src/yuzu_cmd/default_ini.h2
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp16
32 files changed, 518 insertions, 271 deletions
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index 8d062eb3e..e8df08724 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -26,6 +26,11 @@ namespace FileSys {
26constexpr u64 SINGLE_BYTE_MODULUS = 0x100; 26constexpr u64 SINGLE_BYTE_MODULUS = 0x100;
27constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000; 27constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000;
28 28
29constexpr std::array<const char*, 14> EXEFS_FILE_NAMES{
30 "main", "main.npdm", "rtld", "sdk", "subsdk0", "subsdk1", "subsdk2",
31 "subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7", "subsdk8", "subsdk9",
32};
33
29struct NSOBuildHeader { 34struct NSOBuildHeader {
30 u32_le magic; 35 u32_le magic;
31 INSERT_PADDING_BYTES(0x3C); 36 INSERT_PADDING_BYTES(0x3C);
@@ -57,6 +62,15 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
57 if (exefs == nullptr) 62 if (exefs == nullptr)
58 return exefs; 63 return exefs;
59 64
65 if (Settings::values.dump_exefs) {
66 LOG_INFO(Loader, "Dumping ExeFS for title_id={:016X}", title_id);
67 const auto dump_dir = Service::FileSystem::GetModificationDumpRoot(title_id);
68 if (dump_dir != nullptr) {
69 const auto exefs_dir = GetOrCreateDirectoryRelative(dump_dir, "/exefs");
70 VfsRawCopyD(exefs, exefs_dir);
71 }
72 }
73
60 const auto installed = Service::FileSystem::GetUnionContents(); 74 const auto installed = Service::FileSystem::GetUnionContents();
61 75
62 // Game Updates 76 // Game Updates
@@ -70,6 +84,30 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
70 exefs = update->GetExeFS(); 84 exefs = update->GetExeFS();
71 } 85 }
72 86
87 // LayeredExeFS
88 const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
89 if (load_dir != nullptr && load_dir->GetSize() > 0) {
90 auto patch_dirs = load_dir->GetSubdirectories();
91 std::sort(
92 patch_dirs.begin(), patch_dirs.end(),
93 [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
94
95 std::vector<VirtualDir> layers;
96 layers.reserve(patch_dirs.size() + 1);
97 for (const auto& subdir : patch_dirs) {
98 auto exefs_dir = subdir->GetSubdirectory("exefs");
99 if (exefs_dir != nullptr)
100 layers.push_back(std::move(exefs_dir));
101 }
102 layers.push_back(exefs);
103
104 auto layered = LayeredVfsDirectory::MakeLayeredDirectory(std::move(layers));
105 if (layered != nullptr) {
106 LOG_INFO(Loader, " ExeFS: LayeredExeFS patches applied successfully");
107 exefs = std::move(layered);
108 }
109 }
110
73 return exefs; 111 return exefs;
74} 112}
75 113
@@ -314,18 +352,25 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
314 if (IsDirValidAndNonEmpty(exefs_dir)) { 352 if (IsDirValidAndNonEmpty(exefs_dir)) {
315 bool ips = false; 353 bool ips = false;
316 bool ipswitch = false; 354 bool ipswitch = false;
355 bool layeredfs = false;
317 356
318 for (const auto& file : exefs_dir->GetFiles()) { 357 for (const auto& file : exefs_dir->GetFiles()) {
319 if (file->GetExtension() == "ips") 358 if (file->GetExtension() == "ips") {
320 ips = true; 359 ips = true;
321 else if (file->GetExtension() == "pchtxt") 360 } else if (file->GetExtension() == "pchtxt") {
322 ipswitch = true; 361 ipswitch = true;
362 } else if (std::find(EXEFS_FILE_NAMES.begin(), EXEFS_FILE_NAMES.end(),
363 file->GetName()) != EXEFS_FILE_NAMES.end()) {
364 layeredfs = true;
365 }
323 } 366 }
324 367
325 if (ips) 368 if (ips)
326 AppendCommaIfNotEmpty(types, "IPS"); 369 AppendCommaIfNotEmpty(types, "IPS");
327 if (ipswitch) 370 if (ipswitch)
328 AppendCommaIfNotEmpty(types, "IPSwitch"); 371 AppendCommaIfNotEmpty(types, "IPSwitch");
372 if (layeredfs)
373 AppendCommaIfNotEmpty(types, "LayeredExeFS");
329 } 374 }
330 if (IsDirValidAndNonEmpty(mod->GetSubdirectory("romfs"))) 375 if (IsDirValidAndNonEmpty(mod->GetSubdirectory("romfs")))
331 AppendCommaIfNotEmpty(types, "LayeredFS"); 376 AppendCommaIfNotEmpty(types, "LayeredFS");
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index bdcc889e0..687dea409 100644
--- a/src/core/gdbstub/gdbstub.cpp
+++ b/src/core/gdbstub/gdbstub.cpp
@@ -71,10 +71,6 @@ constexpr u32 PSTATE_REGISTER = 33;
71constexpr u32 UC_ARM64_REG_Q0 = 34; 71constexpr u32 UC_ARM64_REG_Q0 = 34;
72constexpr u32 FPCR_REGISTER = 66; 72constexpr u32 FPCR_REGISTER = 66;
73 73
74// TODO/WiP - Used while working on support for FPU
75constexpr u32 TODO_DUMMY_REG_997 = 997;
76constexpr u32 TODO_DUMMY_REG_998 = 998;
77
78// For sample XML files see the GDB source /gdb/features 74// For sample XML files see the GDB source /gdb/features
79// GDB also wants the l character at the start 75// GDB also wants the l character at the start
80// This XML defines what the registers are for this specific ARM device 76// This XML defines what the registers are for this specific ARM device
@@ -260,6 +256,36 @@ static void RegWrite(std::size_t id, u64 val, Kernel::Thread* thread = nullptr)
260 } 256 }
261} 257}
262 258
259static u128 FpuRead(std::size_t id, Kernel::Thread* thread = nullptr) {
260 if (!thread) {
261 return u128{0};
262 }
263
264 auto& thread_context = thread->GetContext();
265
266 if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
267 return thread_context.vector_registers[id - UC_ARM64_REG_Q0];
268 } else if (id == FPCR_REGISTER) {
269 return u128{thread_context.fpcr, 0};
270 } else {
271 return u128{0};
272 }
273}
274
275static void FpuWrite(std::size_t id, u128 val, Kernel::Thread* thread = nullptr) {
276 if (!thread) {
277 return;
278 }
279
280 auto& thread_context = thread->GetContext();
281
282 if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
283 thread_context.vector_registers[id - UC_ARM64_REG_Q0] = val;
284 } else if (id == FPCR_REGISTER) {
285 thread_context.fpcr = val[0];
286 }
287}
288
263/** 289/**
264 * Turns hex string character into the equivalent byte. 290 * Turns hex string character into the equivalent byte.
265 * 291 *
@@ -409,6 +435,27 @@ static u64 GdbHexToLong(const u8* src) {
409 return output; 435 return output;
410} 436}
411 437
438/**
439 * Convert a gdb-formatted hex string into a u128.
440 *
441 * @param src Pointer to hex string.
442 */
443static u128 GdbHexToU128(const u8* src) {
444 u128 output;
445
446 for (int i = 0; i < 16; i += 2) {
447 output[0] = (output[0] << 4) | HexCharToValue(src[15 - i - 1]);
448 output[0] = (output[0] << 4) | HexCharToValue(src[15 - i]);
449 }
450
451 for (int i = 0; i < 16; i += 2) {
452 output[1] = (output[1] << 4) | HexCharToValue(src[16 + 15 - i - 1]);
453 output[1] = (output[1] << 4) | HexCharToValue(src[16 + 15 - i]);
454 }
455
456 return output;
457}
458
412/// Read a byte from the gdb client. 459/// Read a byte from the gdb client.
413static u8 ReadByte() { 460static u8 ReadByte() {
414 u8 c; 461 u8 c;
@@ -599,8 +646,7 @@ static void HandleQuery() {
599 for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) { 646 for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) {
600 const auto& threads = Core::System::GetInstance().Scheduler(core).GetThreadList(); 647 const auto& threads = Core::System::GetInstance().Scheduler(core).GetThreadList();
601 for (const auto& thread : threads) { 648 for (const auto& thread : threads) {
602 val += fmt::format("{:x}", thread->GetThreadID()); 649 val += fmt::format("{:x},", thread->GetThreadID());
603 val += ",";
604 } 650 }
605 } 651 }
606 val.pop_back(); 652 val.pop_back();
@@ -791,11 +837,15 @@ static void ReadRegister() {
791 } else if (id == PSTATE_REGISTER) { 837 } else if (id == PSTATE_REGISTER) {
792 IntToGdbHex(reply, static_cast<u32>(RegRead(id, current_thread))); 838 IntToGdbHex(reply, static_cast<u32>(RegRead(id, current_thread)));
793 } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { 839 } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
794 LongToGdbHex(reply, RegRead(id, current_thread)); 840 u128 r = FpuRead(id, current_thread);
841 LongToGdbHex(reply, r[0]);
842 LongToGdbHex(reply + 16, r[1]);
795 } else if (id == FPCR_REGISTER) { 843 } else if (id == FPCR_REGISTER) {
796 LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_998, current_thread)); 844 u128 r = FpuRead(id, current_thread);
797 } else { 845 IntToGdbHex(reply, static_cast<u32>(r[0]));
798 LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_997, current_thread)); 846 } else if (id == FPCR_REGISTER + 1) {
847 u128 r = FpuRead(id, current_thread);
848 IntToGdbHex(reply, static_cast<u32>(r[0] >> 32));
799 } 849 }
800 850
801 SendReply(reinterpret_cast<char*>(reply)); 851 SendReply(reinterpret_cast<char*>(reply));
@@ -822,13 +872,18 @@ static void ReadRegisters() {
822 872
823 bufptr += 8; 873 bufptr += 8;
824 874
825 for (u32 reg = UC_ARM64_REG_Q0; reg <= UC_ARM64_REG_Q0 + 31; reg++) { 875 u128 r;
826 LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread)); 876
877 for (u32 reg = UC_ARM64_REG_Q0; reg < FPCR_REGISTER; reg++) {
878 r = FpuRead(reg, current_thread);
879 LongToGdbHex(bufptr + reg * 32, r[0]);
880 LongToGdbHex(bufptr + reg * 32 + 16, r[1]);
827 } 881 }
828 882
829 bufptr += 32 * 32; 883 bufptr += 32 * 32;
830 884
831 LongToGdbHex(bufptr, RegRead(TODO_DUMMY_REG_998, current_thread)); 885 r = FpuRead(FPCR_REGISTER, current_thread);
886 IntToGdbHex(bufptr, static_cast<u32>(r[0]));
832 887
833 bufptr += 8; 888 bufptr += 8;
834 889
@@ -853,14 +908,12 @@ static void WriteRegister() {
853 } else if (id == PSTATE_REGISTER) { 908 } else if (id == PSTATE_REGISTER) {
854 RegWrite(id, GdbHexToInt(buffer_ptr), current_thread); 909 RegWrite(id, GdbHexToInt(buffer_ptr), current_thread);
855 } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { 910 } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
856 RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); 911 FpuWrite(id, GdbHexToU128(buffer_ptr), current_thread);
857 } else if (id == FPCR_REGISTER) { 912 } else if (id == FPCR_REGISTER) {
858 RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr), current_thread); 913 } else if (id == FPCR_REGISTER + 1) {
859 } else {
860 RegWrite(TODO_DUMMY_REG_997, GdbHexToLong(buffer_ptr), current_thread);
861 } 914 }
862 915
863 // Update Unicorn context skipping scheduler, no running threads at this point 916 // Update ARM context, skipping scheduler - no running threads at this point
864 Core::System::GetInstance() 917 Core::System::GetInstance()
865 .ArmInterface(current_core) 918 .ArmInterface(current_core)
866 .LoadContext(current_thread->GetContext()); 919 .LoadContext(current_thread->GetContext());
@@ -885,13 +938,13 @@ static void WriteRegisters() {
885 } else if (reg >= UC_ARM64_REG_Q0 && reg < FPCR_REGISTER) { 938 } else if (reg >= UC_ARM64_REG_Q0 && reg < FPCR_REGISTER) {
886 RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); 939 RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread);
887 } else if (reg == FPCR_REGISTER) { 940 } else if (reg == FPCR_REGISTER) {
888 RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr + i * 16), current_thread); 941 RegWrite(FPCR_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread);
889 } else { 942 } else if (reg == FPCR_REGISTER + 1) {
890 UNIMPLEMENTED(); 943 RegWrite(FPCR_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread);
891 } 944 }
892 } 945 }
893 946
894 // Update Unicorn context skipping scheduler, no running threads at this point 947 // Update ARM context, skipping scheduler - no running threads at this point
895 Core::System::GetInstance() 948 Core::System::GetInstance()
896 .ArmInterface(current_core) 949 .ArmInterface(current_core)
897 .LoadContext(current_thread->GetContext()); 950 .LoadContext(current_thread->GetContext());
@@ -917,12 +970,6 @@ static void ReadMemory() {
917 SendReply("E01"); 970 SendReply("E01");
918 } 971 }
919 972
920 const auto& vm_manager = Core::CurrentProcess()->VMManager();
921 if (addr < vm_manager.GetCodeRegionBaseAddress() ||
922 addr >= vm_manager.GetMapRegionEndAddress()) {
923 return SendReply("E00");
924 }
925
926 if (!Memory::IsValidVirtualAddress(addr)) { 973 if (!Memory::IsValidVirtualAddress(addr)) {
927 return SendReply("E00"); 974 return SendReply("E00");
928 } 975 }
@@ -967,7 +1014,7 @@ void Break(bool is_memory_break) {
967static void Step() { 1014static void Step() {
968 if (command_length > 1) { 1015 if (command_length > 1) {
969 RegWrite(PC_REGISTER, GdbHexToLong(command_buffer + 1), current_thread); 1016 RegWrite(PC_REGISTER, GdbHexToLong(command_buffer + 1), current_thread);
970 // Update Unicorn context skipping scheduler, no running threads at this point 1017 // Update ARM context, skipping scheduler - no running threads at this point
971 Core::System::GetInstance() 1018 Core::System::GetInstance()
972 .ArmInterface(current_core) 1019 .ArmInterface(current_core)
973 .LoadContext(current_thread->GetContext()); 1020 .LoadContext(current_thread->GetContext());
@@ -1010,7 +1057,7 @@ static bool CommitBreakpoint(BreakpointType type, VAddr addr, u64 len) {
1010 breakpoint.addr = addr; 1057 breakpoint.addr = addr;
1011 breakpoint.len = len; 1058 breakpoint.len = len;
1012 Memory::ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size()); 1059 Memory::ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size());
1013 static constexpr std::array<u8, 4> btrap{{0x00, 0x7d, 0x20, 0xd4}}; 1060 static constexpr std::array<u8, 4> btrap{0x00, 0x7d, 0x20, 0xd4};
1014 Memory::WriteBlock(addr, btrap.data(), btrap.size()); 1061 Memory::WriteBlock(addr, btrap.data(), btrap.size());
1015 Core::System::GetInstance().InvalidateCpuInstructionCaches(); 1062 Core::System::GetInstance().InvalidateCpuInstructionCaches();
1016 p.insert({addr, breakpoint}); 1063 p.insert({addr, breakpoint});
@@ -1321,13 +1368,15 @@ void SetCpuStepFlag(bool is_step) {
1321} 1368}
1322 1369
1323void SendTrap(Kernel::Thread* thread, int trap) { 1370void SendTrap(Kernel::Thread* thread, int trap) {
1324 if (send_trap) { 1371 if (!send_trap) {
1325 if (!halt_loop || current_thread == thread) { 1372 return;
1326 current_thread = thread;
1327 SendSignal(thread, trap);
1328 }
1329 halt_loop = true;
1330 send_trap = false;
1331 } 1373 }
1374
1375 if (!halt_loop || current_thread == thread) {
1376 current_thread = thread;
1377 SendSignal(thread, trap);
1378 }
1379 halt_loop = true;
1380 send_trap = false;
1332} 1381}
1333}; // namespace GDBStub 1382}; // namespace GDBStub
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index f4127701f..4f17b52f9 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -483,11 +483,15 @@ void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext&
483 rb.Push(RESULT_SUCCESS); 483 rb.Push(RESULT_SUCCESS);
484 484
485 if (Settings::values.use_docked_mode) { 485 if (Settings::values.use_docked_mode) {
486 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth)); 486 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) *
487 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight)); 487 static_cast<u32>(Settings::values.resolution_factor));
488 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) *
489 static_cast<u32>(Settings::values.resolution_factor));
488 } else { 490 } else {
489 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth)); 491 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth) *
490 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight)); 492 static_cast<u32>(Settings::values.resolution_factor));
493 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight) *
494 static_cast<u32>(Settings::values.resolution_factor));
491 } 495 }
492 496
493 LOG_DEBUG(Service_AM, "called"); 497 LOG_DEBUG(Service_AM, "called");
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index 5d6294016..2aa77f68d 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -341,6 +341,10 @@ std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents() {
341 return registered_cache_union; 341 return registered_cache_union;
342} 342}
343 343
344void ClearUnionContents() {
345 registered_cache_union = nullptr;
346}
347
344FileSys::RegisteredCache* GetSystemNANDContents() { 348FileSys::RegisteredCache* GetSystemNANDContents() {
345 LOG_TRACE(Service_FS, "Opening System NAND Contents"); 349 LOG_TRACE(Service_FS, "Opening System NAND Contents");
346 350
@@ -391,6 +395,7 @@ void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
391 bis_factory = nullptr; 395 bis_factory = nullptr;
392 save_data_factory = nullptr; 396 save_data_factory = nullptr;
393 sdmc_factory = nullptr; 397 sdmc_factory = nullptr;
398 ClearUnionContents();
394 } 399 }
395 400
396 auto nand_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), 401 auto nand_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir),
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index ff9182e84..0a6cb6635 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -49,6 +49,7 @@ ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space)
49ResultVal<FileSys::VirtualDir> OpenSDMC(); 49ResultVal<FileSys::VirtualDir> OpenSDMC();
50 50
51std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents(); 51std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents();
52void ClearUnionContents();
52 53
53FileSys::RegisteredCache* GetSystemNANDContents(); 54FileSys::RegisteredCache* GetSystemNANDContents();
54FileSys::RegisteredCache* GetUserNANDContents(); 55FileSys::RegisteredCache* GetUserNANDContents();
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index 464e79d01..c1b2f33b9 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -63,6 +63,17 @@ ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> ServiceManager::RegisterService
63 return MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port)); 63 return MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port));
64} 64}
65 65
66ResultCode ServiceManager::UnregisterService(std::string name) {
67 CASCADE_CODE(ValidateServiceName(name));
68
69 const auto iter = registered_services.find(name);
70 if (iter == registered_services.end())
71 return ERR_SERVICE_NOT_REGISTERED;
72
73 registered_services.erase(iter);
74 return RESULT_SUCCESS;
75}
76
66ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> ServiceManager::GetServicePort( 77ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> ServiceManager::GetServicePort(
67 const std::string& name) { 78 const std::string& name) {
68 79
@@ -127,13 +138,52 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {
127 } 138 }
128} 139}
129 140
141void SM::RegisterService(Kernel::HLERequestContext& ctx) {
142 IPC::RequestParser rp{ctx};
143
144 const auto name_buf = rp.PopRaw<std::array<char, 8>>();
145 const auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
146
147 const std::string name(name_buf.begin(), end);
148
149 const auto unk_bool = static_cast<bool>(rp.PopRaw<u32>());
150 const auto session_count = rp.PopRaw<u32>();
151
152 LOG_DEBUG(Service_SM, "called with unk_bool={}", unk_bool);
153
154 auto handle = service_manager->RegisterService(name, session_count);
155 if (handle.Failed()) {
156 LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}",
157 handle.Code().raw);
158 IPC::ResponseBuilder rb{ctx, 2};
159 rb.Push(handle.Code());
160 return;
161 }
162
163 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
164 rb.Push(handle.Code());
165 rb.PushMoveObjects(std::move(handle).Unwrap());
166}
167
168void SM::UnregisterService(Kernel::HLERequestContext& ctx) {
169 IPC::RequestParser rp{ctx};
170
171 const auto name_buf = rp.PopRaw<std::array<char, 8>>();
172 const auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
173
174 const std::string name(name_buf.begin(), end);
175
176 IPC::ResponseBuilder rb{ctx, 2};
177 rb.Push(service_manager->UnregisterService(name));
178}
179
130SM::SM(std::shared_ptr<ServiceManager> service_manager) 180SM::SM(std::shared_ptr<ServiceManager> service_manager)
131 : ServiceFramework("sm:", 4), service_manager(std::move(service_manager)) { 181 : ServiceFramework("sm:", 4), service_manager(std::move(service_manager)) {
132 static const FunctionInfo functions[] = { 182 static const FunctionInfo functions[] = {
133 {0x00000000, &SM::Initialize, "Initialize"}, 183 {0x00000000, &SM::Initialize, "Initialize"},
134 {0x00000001, &SM::GetService, "GetService"}, 184 {0x00000001, &SM::GetService, "GetService"},
135 {0x00000002, nullptr, "RegisterService"}, 185 {0x00000002, &SM::RegisterService, "RegisterService"},
136 {0x00000003, nullptr, "UnregisterService"}, 186 {0x00000003, &SM::UnregisterService, "UnregisterService"},
137 }; 187 };
138 RegisterHandlers(functions); 188 RegisterHandlers(functions);
139} 189}
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index 4f8145dda..c4714b3e3 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -35,6 +35,8 @@ public:
35private: 35private:
36 void Initialize(Kernel::HLERequestContext& ctx); 36 void Initialize(Kernel::HLERequestContext& ctx);
37 void GetService(Kernel::HLERequestContext& ctx); 37 void GetService(Kernel::HLERequestContext& ctx);
38 void RegisterService(Kernel::HLERequestContext& ctx);
39 void UnregisterService(Kernel::HLERequestContext& ctx);
38 40
39 std::shared_ptr<ServiceManager> service_manager; 41 std::shared_ptr<ServiceManager> service_manager;
40}; 42};
@@ -48,6 +50,7 @@ public:
48 50
49 ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> RegisterService(std::string name, 51 ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> RegisterService(std::string name,
50 unsigned int max_sessions); 52 unsigned int max_sessions);
53 ResultCode UnregisterService(std::string name);
51 ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> GetServicePort(const std::string& name); 54 ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> GetServicePort(const std::string& name);
52 ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ConnectToService(const std::string& name); 55 ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ConnectToService(const std::string& name);
53 56
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index d25fdb1fe..a72416084 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -510,7 +510,11 @@ private:
510 510
511 if (transaction == TransactionId::Connect) { 511 if (transaction == TransactionId::Connect) {
512 IGBPConnectRequestParcel request{ctx.ReadBuffer()}; 512 IGBPConnectRequestParcel request{ctx.ReadBuffer()};
513 IGBPConnectResponseParcel response{1280, 720}; 513 IGBPConnectResponseParcel response{
514 static_cast<u32>(static_cast<u32>(DisplayResolution::UndockedWidth) *
515 Settings::values.resolution_factor),
516 static_cast<u32>(static_cast<u32>(DisplayResolution::UndockedHeight) *
517 Settings::values.resolution_factor)};
514 ctx.WriteBuffer(response.Serialize()); 518 ctx.WriteBuffer(response.Serialize());
515 } else if (transaction == TransactionId::SetPreallocatedBuffer) { 519 } else if (transaction == TransactionId::SetPreallocatedBuffer) {
516 IGBPSetPreallocatedBufferRequestParcel request{ctx.ReadBuffer()}; 520 IGBPSetPreallocatedBufferRequestParcel request{ctx.ReadBuffer()};
@@ -692,11 +696,15 @@ private:
692 rb.Push(RESULT_SUCCESS); 696 rb.Push(RESULT_SUCCESS);
693 697
694 if (Settings::values.use_docked_mode) { 698 if (Settings::values.use_docked_mode) {
695 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth)); 699 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) *
696 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight)); 700 static_cast<u32>(Settings::values.resolution_factor));
701 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) *
702 static_cast<u32>(Settings::values.resolution_factor));
697 } else { 703 } else {
698 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth)); 704 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth) *
699 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight)); 705 static_cast<u32>(Settings::values.resolution_factor));
706 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight) *
707 static_cast<u32>(Settings::values.resolution_factor));
700 } 708 }
701 709
702 rb.PushRaw<float>(60.0f); 710 rb.PushRaw<float>(60.0f);
@@ -901,11 +909,15 @@ private:
901 rb.Push(RESULT_SUCCESS); 909 rb.Push(RESULT_SUCCESS);
902 910
903 if (Settings::values.use_docked_mode) { 911 if (Settings::values.use_docked_mode) {
904 rb.Push(static_cast<u64>(DisplayResolution::DockedWidth)); 912 rb.Push(static_cast<u64>(DisplayResolution::DockedWidth) *
905 rb.Push(static_cast<u64>(DisplayResolution::DockedHeight)); 913 static_cast<u32>(Settings::values.resolution_factor));
914 rb.Push(static_cast<u64>(DisplayResolution::DockedHeight) *
915 static_cast<u32>(Settings::values.resolution_factor));
906 } else { 916 } else {
907 rb.Push(static_cast<u64>(DisplayResolution::UndockedWidth)); 917 rb.Push(static_cast<u64>(DisplayResolution::UndockedWidth) *
908 rb.Push(static_cast<u64>(DisplayResolution::UndockedHeight)); 918 static_cast<u32>(Settings::values.resolution_factor));
919 rb.Push(static_cast<u64>(DisplayResolution::UndockedHeight) *
920 static_cast<u32>(Settings::values.resolution_factor));
909 } 921 }
910 } 922 }
911 923
@@ -922,6 +934,8 @@ private:
922 void ListDisplays(Kernel::HLERequestContext& ctx) { 934 void ListDisplays(Kernel::HLERequestContext& ctx) {
923 IPC::RequestParser rp{ctx}; 935 IPC::RequestParser rp{ctx};
924 DisplayInfo display_info; 936 DisplayInfo display_info;
937 display_info.width *= static_cast<u64>(Settings::values.resolution_factor);
938 display_info.height *= static_cast<u64>(Settings::values.resolution_factor);
925 ctx.WriteBuffer(&display_info, sizeof(DisplayInfo)); 939 ctx.WriteBuffer(&display_info, sizeof(DisplayInfo));
926 IPC::ResponseBuilder rb{ctx, 4}; 940 IPC::ResponseBuilder rb{ctx, 4};
927 rb.Push(RESULT_SUCCESS); 941 rb.Push(RESULT_SUCCESS);
diff --git a/src/core/settings.h b/src/core/settings.h
index e63134f80..a0c5fd447 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -403,6 +403,7 @@ struct Values {
403 bool use_gdbstub; 403 bool use_gdbstub;
404 u16 gdbstub_port; 404 u16 gdbstub_port;
405 std::string program_args; 405 std::string program_args;
406 bool dump_exefs;
406 bool dump_nso; 407 bool dump_nso;
407 408
408 // WebService 409 // WebService
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index eff6abd55..4f137e693 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -631,7 +631,16 @@ public:
631 } 631 }
632 } zeta; 632 } zeta;
633 633
634 INSERT_PADDING_WORDS(0x5B); 634 INSERT_PADDING_WORDS(0x41);
635
636 union {
637 BitField<0, 4, u32> stencil;
638 BitField<4, 4, u32> unknown;
639 BitField<8, 4, u32> scissor;
640 BitField<12, 4, u32> viewport;
641 } clear_flags;
642
643 INSERT_PADDING_WORDS(0x19);
635 644
636 std::array<VertexAttribute, NumVertexAttributes> vertex_attrib_format; 645 std::array<VertexAttribute, NumVertexAttributes> vertex_attrib_format;
637 646
@@ -1134,6 +1143,7 @@ ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7);
1134ASSERT_REG_POSITION(color_mask_common, 0x3E4); 1143ASSERT_REG_POSITION(color_mask_common, 0x3E4);
1135ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB); 1144ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB);
1136ASSERT_REG_POSITION(zeta, 0x3F8); 1145ASSERT_REG_POSITION(zeta, 0x3F8);
1146ASSERT_REG_POSITION(clear_flags, 0x43E);
1137ASSERT_REG_POSITION(vertex_attrib_format, 0x458); 1147ASSERT_REG_POSITION(vertex_attrib_format, 0x458);
1138ASSERT_REG_POSITION(rt_control, 0x487); 1148ASSERT_REG_POSITION(rt_control, 0x487);
1139ASSERT_REG_POSITION(zeta_width, 0x48a); 1149ASSERT_REG_POSITION(zeta_width, 0x48a);
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index c5f502ce1..7e8449bc4 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -262,7 +262,7 @@ enum class FlowCondition : u64 {
262 Fcsm_Tr = 0x1C, // TODO(bunnei): What is this used for? 262 Fcsm_Tr = 0x1C, // TODO(bunnei): What is this used for?
263}; 263};
264 264
265enum class ControlCode : u64 { 265enum class ConditionCode : u64 {
266 F = 0, 266 F = 0,
267 LT = 1, 267 LT = 1,
268 EQ = 2, 268 EQ = 2,
@@ -570,7 +570,6 @@ union Instruction {
570 BitField<39, 2, u64> tab5cb8_2; 570 BitField<39, 2, u64> tab5cb8_2;
571 BitField<41, 3, u64> tab5c68_1; 571 BitField<41, 3, u64> tab5c68_1;
572 BitField<44, 2, u64> tab5c68_0; 572 BitField<44, 2, u64> tab5c68_0;
573 BitField<47, 1, u64> cc;
574 BitField<48, 1, u64> negate_b; 573 BitField<48, 1, u64> negate_b;
575 } fmul; 574 } fmul;
576 575
@@ -832,7 +831,7 @@ union Instruction {
832 union { 831 union {
833 BitField<0, 3, u64> pred0; 832 BitField<0, 3, u64> pred0;
834 BitField<3, 3, u64> pred3; 833 BitField<3, 3, u64> pred3;
835 BitField<8, 5, ControlCode> cc; // flag in cc 834 BitField<8, 5, ConditionCode> cc; // flag in cc
836 BitField<39, 3, u64> pred39; 835 BitField<39, 3, u64> pred39;
837 BitField<42, 1, u64> neg_pred39; 836 BitField<42, 1, u64> neg_pred39;
838 BitField<45, 4, PredOperation> op; // op with pred39 837 BitField<45, 4, PredOperation> op; // op with pred39
@@ -1236,7 +1235,7 @@ union Instruction {
1236 BitField<60, 1, u64> is_b_gpr; 1235 BitField<60, 1, u64> is_b_gpr;
1237 BitField<59, 1, u64> is_c_gpr; 1236 BitField<59, 1, u64> is_c_gpr;
1238 BitField<20, 24, s64> smem_imm; 1237 BitField<20, 24, s64> smem_imm;
1239 BitField<0, 5, ControlCode> flow_control_code; 1238 BitField<0, 5, ConditionCode> flow_condition_code;
1240 1239
1241 Attribute attribute; 1240 Attribute attribute;
1242 Sampler sampler; 1241 Sampler sampler;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index ae6aaee4c..630a58e49 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -98,14 +98,9 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo
98 has_ARB_direct_state_access = true; 98 has_ARB_direct_state_access = true;
99 } else if (extension == "GL_ARB_multi_bind") { 99 } else if (extension == "GL_ARB_multi_bind") {
100 has_ARB_multi_bind = true; 100 has_ARB_multi_bind = true;
101 } else if (extension == "GL_ARB_separate_shader_objects") {
102 has_ARB_separate_shader_objects = true;
103 } else if (extension == "GL_ARB_vertex_attrib_binding") {
104 has_ARB_vertex_attrib_binding = true;
105 } 101 }
106 } 102 }
107 103
108 ASSERT_MSG(has_ARB_separate_shader_objects, "has_ARB_separate_shader_objects is unsupported");
109 OpenGLState::ApplyDefaultState(); 104 OpenGLState::ApplyDefaultState();
110 105
111 // Create render framebuffer 106 // Create render framebuffer
@@ -542,6 +537,30 @@ void RasterizerOpenGL::Clear() {
542 ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!"); 537 ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!");
543 use_stencil = true; 538 use_stencil = true;
544 clear_state.stencil.test_enabled = true; 539 clear_state.stencil.test_enabled = true;
540 if (regs.clear_flags.stencil) {
541 // Stencil affects the clear so fill it with the used masks
542 clear_state.stencil.front.test_func = GL_ALWAYS;
543 clear_state.stencil.front.test_mask = regs.stencil_front_func_mask;
544 clear_state.stencil.front.action_stencil_fail = GL_KEEP;
545 clear_state.stencil.front.action_depth_fail = GL_KEEP;
546 clear_state.stencil.front.action_depth_pass = GL_KEEP;
547 clear_state.stencil.front.write_mask = regs.stencil_front_mask;
548 if (regs.stencil_two_side_enable) {
549 clear_state.stencil.back.test_func = GL_ALWAYS;
550 clear_state.stencil.back.test_mask = regs.stencil_back_func_mask;
551 clear_state.stencil.back.action_stencil_fail = GL_KEEP;
552 clear_state.stencil.back.action_depth_fail = GL_KEEP;
553 clear_state.stencil.back.action_depth_pass = GL_KEEP;
554 clear_state.stencil.back.write_mask = regs.stencil_back_mask;
555 } else {
556 clear_state.stencil.back.test_func = GL_ALWAYS;
557 clear_state.stencil.back.test_mask = 0xFFFFFFFF;
558 clear_state.stencil.back.write_mask = 0xFFFFFFFF;
559 clear_state.stencil.back.action_stencil_fail = GL_KEEP;
560 clear_state.stencil.back.action_depth_fail = GL_KEEP;
561 clear_state.stencil.back.action_depth_pass = GL_KEEP;
562 }
563 }
545 } 564 }
546 565
547 if (!use_color && !use_depth && !use_stencil) { 566 if (!use_color && !use_depth && !use_stencil) {
@@ -553,6 +572,14 @@ void RasterizerOpenGL::Clear() {
553 572
554 ConfigureFramebuffers(clear_state, use_color, use_depth || use_stencil, false, 573 ConfigureFramebuffers(clear_state, use_color, use_depth || use_stencil, false,
555 regs.clear_buffers.RT.Value()); 574 regs.clear_buffers.RT.Value());
575 if (regs.clear_flags.scissor) {
576 SyncScissorTest(clear_state);
577 }
578
579 if (regs.clear_flags.viewport) {
580 clear_state.EmulateViewportWithScissor();
581 }
582
556 clear_state.Apply(); 583 clear_state.Apply();
557 584
558 if (use_color) { 585 if (use_color) {
@@ -588,7 +615,7 @@ void RasterizerOpenGL::DrawArrays() {
588 SyncLogicOpState(); 615 SyncLogicOpState();
589 SyncCullMode(); 616 SyncCullMode();
590 SyncPrimitiveRestart(); 617 SyncPrimitiveRestart();
591 SyncScissorTest(); 618 SyncScissorTest(state);
592 // Alpha Testing is synced on shaders. 619 // Alpha Testing is synced on shaders.
593 SyncTransformFeedback(); 620 SyncTransformFeedback();
594 SyncPointState(); 621 SyncPointState();
@@ -815,7 +842,7 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr
815 } 842 }
816 const u32 bias = config.mip_lod_bias.Value(); 843 const u32 bias = config.mip_lod_bias.Value();
817 // Sign extend the 13-bit value. 844 // Sign extend the 13-bit value.
818 const u32 mask = 1U << (13 - 1); 845 constexpr u32 mask = 1U << (13 - 1);
819 const float bias_lod = static_cast<s32>((bias ^ mask) - mask) / 256.f; 846 const float bias_lod = static_cast<s32>((bias ^ mask) - mask) / 256.f;
820 if (lod_bias != bias_lod) { 847 if (lod_bias != bias_lod) {
821 lod_bias = bias_lod; 848 lod_bias = bias_lod;
@@ -947,8 +974,8 @@ void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) {
947 auto& viewport = current_state.viewports[i]; 974 auto& viewport = current_state.viewports[i];
948 viewport.x = viewport_rect.left; 975 viewport.x = viewport_rect.left;
949 viewport.y = viewport_rect.bottom; 976 viewport.y = viewport_rect.bottom;
950 viewport.width = static_cast<GLfloat>(viewport_rect.GetWidth()); 977 viewport.width = viewport_rect.GetWidth();
951 viewport.height = static_cast<GLfloat>(viewport_rect.GetHeight()); 978 viewport.height = viewport_rect.GetHeight();
952 viewport.depth_range_far = regs.viewports[i].depth_range_far; 979 viewport.depth_range_far = regs.viewports[i].depth_range_far;
953 viewport.depth_range_near = regs.viewports[i].depth_range_near; 980 viewport.depth_range_near = regs.viewports[i].depth_range_near;
954 } 981 }
@@ -1120,11 +1147,11 @@ void RasterizerOpenGL::SyncLogicOpState() {
1120 state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation); 1147 state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation);
1121} 1148}
1122 1149
1123void RasterizerOpenGL::SyncScissorTest() { 1150void RasterizerOpenGL::SyncScissorTest(OpenGLState& current_state) {
1124 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 1151 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
1125 for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) { 1152 for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) {
1126 const auto& src = regs.scissor_test[i]; 1153 const auto& src = regs.scissor_test[i];
1127 auto& dst = state.viewports[i].scissor; 1154 auto& dst = current_state.viewports[i].scissor;
1128 dst.enabled = (src.enable != 0); 1155 dst.enabled = (src.enable != 0);
1129 if (dst.enabled == 0) { 1156 if (dst.enabled == 0) {
1130 return; 1157 return;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 6e78ab4cd..f4354289c 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -91,19 +91,20 @@ private:
91 void SyncWithConfig(const Tegra::Texture::TSCEntry& info); 91 void SyncWithConfig(const Tegra::Texture::TSCEntry& info);
92 92
93 private: 93 private:
94 Tegra::Texture::TextureFilter mag_filter; 94 Tegra::Texture::TextureFilter mag_filter = Tegra::Texture::TextureFilter::Nearest;
95 Tegra::Texture::TextureFilter min_filter; 95 Tegra::Texture::TextureFilter min_filter = Tegra::Texture::TextureFilter::Nearest;
96 Tegra::Texture::TextureMipmapFilter mip_filter; 96 Tegra::Texture::TextureMipmapFilter mip_filter = Tegra::Texture::TextureMipmapFilter::None;
97 Tegra::Texture::WrapMode wrap_u; 97 Tegra::Texture::WrapMode wrap_u = Tegra::Texture::WrapMode::ClampToEdge;
98 Tegra::Texture::WrapMode wrap_v; 98 Tegra::Texture::WrapMode wrap_v = Tegra::Texture::WrapMode::ClampToEdge;
99 Tegra::Texture::WrapMode wrap_p; 99 Tegra::Texture::WrapMode wrap_p = Tegra::Texture::WrapMode::ClampToEdge;
100 bool uses_depth_compare; 100 bool uses_depth_compare = false;
101 Tegra::Texture::DepthCompareFunc depth_compare_func; 101 Tegra::Texture::DepthCompareFunc depth_compare_func =
102 GLvec4 border_color; 102 Tegra::Texture::DepthCompareFunc::Always;
103 float min_lod; 103 GLvec4 border_color = {};
104 float max_lod; 104 float min_lod = 0.0f;
105 float lod_bias; 105 float max_lod = 16.0f;
106 float max_anisotropic; 106 float lod_bias = 0.0f;
107 float max_anisotropic = 1.0f;
107 }; 108 };
108 109
109 /** 110 /**
@@ -171,7 +172,7 @@ private:
171 void SyncMultiSampleState(); 172 void SyncMultiSampleState();
172 173
173 /// Syncs the scissor test state to match the guest state 174 /// Syncs the scissor test state to match the guest state
174 void SyncScissorTest(); 175 void SyncScissorTest(OpenGLState& current_state);
175 176
176 /// Syncs the transform feedback state to match the guest state 177 /// Syncs the transform feedback state to match the guest state
177 void SyncTransformFeedback(); 178 void SyncTransformFeedback();
@@ -187,8 +188,6 @@ private:
187 188
188 bool has_ARB_direct_state_access = false; 189 bool has_ARB_direct_state_access = false;
189 bool has_ARB_multi_bind = false; 190 bool has_ARB_multi_bind = false;
190 bool has_ARB_separate_shader_objects = false;
191 bool has_ARB_vertex_attrib_binding = false;
192 191
193 OpenGLState state; 192 OpenGLState state;
194 193
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index b994e89dd..4f434fc31 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -265,11 +265,11 @@ static constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex
265 {GL_COMPRESSED_RG_RGTC2, GL_RG, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, 265 {GL_COMPRESSED_RG_RGTC2, GL_RG, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
266 true}, // DXN2UNORM 266 true}, // DXN2UNORM
267 {GL_COMPRESSED_SIGNED_RG_RGTC2, GL_RG, GL_INT, ComponentType::SNorm, true}, // DXN2SNORM 267 {GL_COMPRESSED_SIGNED_RG_RGTC2, GL_RG, GL_INT, ComponentType::SNorm, true}, // DXN2SNORM
268 {GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, 268 {GL_COMPRESSED_RGBA_BPTC_UNORM, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
269 true}, // BC7U 269 true}, // BC7U
270 {GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, 270 {GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::Float,
271 ComponentType::Float, true}, // BC6H_UF16 271 true}, // BC6H_UF16
272 {GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::Float, 272 {GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::Float,
273 true}, // BC6H_SF16 273 true}, // BC6H_SF16
274 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4 274 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4
275 {GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // G8R8U 275 {GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // G8R8U
@@ -306,8 +306,8 @@ static constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex
306 true}, // DXT23_SRGB 306 true}, // DXT23_SRGB
307 {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, 307 {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
308 true}, // DXT45_SRGB 308 true}, // DXT45_SRGB
309 {GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, 309 {GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
310 ComponentType::UNorm, true}, // BC7U_SRGB 310 true}, // BC7U_SRGB
311 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4_SRGB 311 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4_SRGB
312 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X8_SRGB 312 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X8_SRGB
313 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X5_SRGB 313 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X5_SRGB
@@ -346,7 +346,7 @@ static GLenum SurfaceTargetToGL(SurfaceTarget target) {
346 case SurfaceTarget::TextureCubemap: 346 case SurfaceTarget::TextureCubemap:
347 return GL_TEXTURE_CUBE_MAP; 347 return GL_TEXTURE_CUBE_MAP;
348 case SurfaceTarget::TextureCubeArray: 348 case SurfaceTarget::TextureCubeArray:
349 return GL_TEXTURE_CUBE_MAP_ARRAY_ARB; 349 return GL_TEXTURE_CUBE_MAP_ARRAY;
350 } 350 }
351 LOG_CRITICAL(Render_OpenGL, "Unimplemented texture target={}", static_cast<u32>(target)); 351 LOG_CRITICAL(Render_OpenGL, "Unimplemented texture target={}", static_cast<u32>(target));
352 UNREACHABLE(); 352 UNREACHABLE();
@@ -726,7 +726,7 @@ static void CopySurface(const Surface& src_surface, const Surface& dst_surface,
726 const std::size_t buffer_size = std::max(src_params.size_in_bytes, dst_params.size_in_bytes); 726 const std::size_t buffer_size = std::max(src_params.size_in_bytes, dst_params.size_in_bytes);
727 727
728 glBindBuffer(GL_PIXEL_PACK_BUFFER, copy_pbo_handle); 728 glBindBuffer(GL_PIXEL_PACK_BUFFER, copy_pbo_handle);
729 glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB); 729 glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW);
730 if (source_format.compressed) { 730 if (source_format.compressed) {
731 glGetCompressedTextureImage(src_surface->Texture().handle, src_attachment, 731 glGetCompressedTextureImage(src_surface->Texture().handle, src_attachment,
732 static_cast<GLsizei>(src_params.size_in_bytes), nullptr); 732 static_cast<GLsizei>(src_params.size_in_bytes), nullptr);
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index a85a7c0c5..038b25c75 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -84,6 +84,7 @@ CachedShader::CachedShader(VAddr addr, Maxwell::ShaderProgram program_type)
84 } 84 }
85 85
86 entries = program_result.second; 86 entries = program_result.second;
87 shader_length = entries.shader_length;
87 88
88 if (program_type != Maxwell::ShaderProgram::Geometry) { 89 if (program_type != Maxwell::ShaderProgram::Geometry) {
89 OGLShader shader; 90 OGLShader shader;
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h
index ffbf21831..08f470de3 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.h
+++ b/src/video_core/renderer_opengl/gl_shader_cache.h
@@ -30,7 +30,7 @@ public:
30 } 30 }
31 31
32 std::size_t GetSizeInBytes() const override { 32 std::size_t GetSizeInBytes() const override {
33 return GLShader::MAX_PROGRAM_CODE_LENGTH * sizeof(u64); 33 return shader_length;
34 } 34 }
35 35
36 // We do not have to flush this cache as things in it are never modified by us. 36 // We do not have to flush this cache as things in it are never modified by us.
@@ -82,6 +82,7 @@ private:
82 u32 max_vertices, const std::string& debug_name); 82 u32 max_vertices, const std::string& debug_name);
83 83
84 VAddr addr; 84 VAddr addr;
85 std::size_t shader_length;
85 Maxwell::ShaderProgram program_type; 86 Maxwell::ShaderProgram program_type;
86 GLShader::ShaderSetup setup; 87 GLShader::ShaderSetup setup;
87 GLShader::ShaderEntries entries; 88 GLShader::ShaderEntries entries;
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index ba80e5832..97b9028c5 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -34,6 +34,17 @@ constexpr u32 PROGRAM_HEADER_SIZE = sizeof(Tegra::Shader::Header);
34constexpr u32 MAX_GEOMETRY_BUFFERS = 6; 34constexpr u32 MAX_GEOMETRY_BUFFERS = 6;
35constexpr u32 MAX_ATTRIBUTES = 0x100; // Size in vec4s, this value is untested 35constexpr u32 MAX_ATTRIBUTES = 0x100; // Size in vec4s, this value is untested
36 36
37static const char* INTERNAL_FLAG_NAMES[] = {"zero_flag", "sign_flag", "carry_flag",
38 "overflow_flag"};
39
40enum class InternalFlag : u64 {
41 ZeroFlag = 0,
42 SignFlag = 1,
43 CarryFlag = 2,
44 OverflowFlag = 3,
45 Amount
46};
47
37class DecompileFail : public std::runtime_error { 48class DecompileFail : public std::runtime_error {
38public: 49public:
39 using std::runtime_error::runtime_error; 50 using std::runtime_error::runtime_error;
@@ -84,7 +95,8 @@ struct Subroutine {
84class ControlFlowAnalyzer { 95class ControlFlowAnalyzer {
85public: 96public:
86 ControlFlowAnalyzer(const ProgramCode& program_code, u32 main_offset, const std::string& suffix) 97 ControlFlowAnalyzer(const ProgramCode& program_code, u32 main_offset, const std::string& suffix)
87 : program_code(program_code) { 98 : program_code(program_code), shader_coverage_begin(main_offset),
99 shader_coverage_end(main_offset + 1) {
88 100
89 // Recursively finds all subroutines. 101 // Recursively finds all subroutines.
90 const Subroutine& program_main = AddSubroutine(main_offset, PROGRAM_END, suffix); 102 const Subroutine& program_main = AddSubroutine(main_offset, PROGRAM_END, suffix);
@@ -96,10 +108,16 @@ public:
96 return std::move(subroutines); 108 return std::move(subroutines);
97 } 109 }
98 110
111 std::size_t GetShaderLength() const {
112 return shader_coverage_end * sizeof(u64);
113 }
114
99private: 115private:
100 const ProgramCode& program_code; 116 const ProgramCode& program_code;
101 std::set<Subroutine> subroutines; 117 std::set<Subroutine> subroutines;
102 std::map<std::pair<u32, u32>, ExitMethod> exit_method_map; 118 std::map<std::pair<u32, u32>, ExitMethod> exit_method_map;
119 u32 shader_coverage_begin;
120 u32 shader_coverage_end;
103 121
104 /// Adds and analyzes a new subroutine if it is not added yet. 122 /// Adds and analyzes a new subroutine if it is not added yet.
105 const Subroutine& AddSubroutine(u32 begin, u32 end, const std::string& suffix) { 123 const Subroutine& AddSubroutine(u32 begin, u32 end, const std::string& suffix) {
@@ -141,6 +159,9 @@ private:
141 return exit_method; 159 return exit_method;
142 160
143 for (u32 offset = begin; offset != end && offset != PROGRAM_END; ++offset) { 161 for (u32 offset = begin; offset != end && offset != PROGRAM_END; ++offset) {
162 shader_coverage_begin = std::min(shader_coverage_begin, offset);
163 shader_coverage_end = std::max(shader_coverage_end, offset + 1);
164
144 const Instruction instr = {program_code[offset]}; 165 const Instruction instr = {program_code[offset]};
145 if (const auto opcode = OpCode::Decode(instr)) { 166 if (const auto opcode = OpCode::Decode(instr)) {
146 switch (opcode->get().GetId()) { 167 switch (opcode->get().GetId()) {
@@ -257,14 +278,6 @@ private:
257 const std::string& suffix; 278 const std::string& suffix;
258}; 279};
259 280
260enum class InternalFlag : u64 {
261 ZeroFlag = 0,
262 CarryFlag = 1,
263 OverflowFlag = 2,
264 NaNFlag = 3,
265 Amount
266};
267
268/** 281/**
269 * Used to manage shader registers that are emulated with GLSL. This class keeps track of the state 282 * Used to manage shader registers that are emulated with GLSL. This class keeps track of the state
270 * of all registers (e.g. whether they are currently being used as Floats or Integers), and 283 * of all registers (e.g. whether they are currently being used as Floats or Integers), and
@@ -371,7 +384,7 @@ public:
371 if (sets_cc) { 384 if (sets_cc) {
372 const std::string zero_condition = "( " + ConvertIntegerSize(value, size) + " == 0 )"; 385 const std::string zero_condition = "( " + ConvertIntegerSize(value, size) + " == 0 )";
373 SetInternalFlag(InternalFlag::ZeroFlag, zero_condition); 386 SetInternalFlag(InternalFlag::ZeroFlag, zero_condition);
374 LOG_WARNING(HW_GPU, "Control Codes Imcomplete."); 387 LOG_WARNING(HW_GPU, "Condition codes implementation is incomplete.");
375 } 388 }
376 } 389 }
377 390
@@ -454,23 +467,25 @@ public:
454 shader.AddLine("lmem[" + index + "] = " + func + '(' + value + ");"); 467 shader.AddLine("lmem[" + index + "] = " + func + '(' + value + ");");
455 } 468 }
456 469
457 std::string GetControlCode(const Tegra::Shader::ControlCode cc) const { 470 std::string GetConditionCode(const Tegra::Shader::ConditionCode cc) const {
458 switch (cc) { 471 switch (cc) {
459 case Tegra::Shader::ControlCode::NEU: 472 case Tegra::Shader::ConditionCode::NEU:
460 return "!(" + GetInternalFlag(InternalFlag::ZeroFlag) + ')'; 473 return "!(" + GetInternalFlag(InternalFlag::ZeroFlag) + ')';
461 default: 474 default:
462 UNIMPLEMENTED_MSG("Unimplemented Control Code: {}", static_cast<u32>(cc)); 475 UNIMPLEMENTED_MSG("Unimplemented condition code: {}", static_cast<u32>(cc));
463 return "false"; 476 return "false";
464 } 477 }
465 } 478 }
466 479
467 std::string GetInternalFlag(const InternalFlag ii) const { 480 std::string GetInternalFlag(const InternalFlag flag) const {
468 const u32 code = static_cast<u32>(ii); 481 const auto index = static_cast<u32>(flag);
469 return "internalFlag_" + std::to_string(code) + suffix; 482 ASSERT(index < static_cast<u32>(InternalFlag::Amount));
483
484 return std::string(INTERNAL_FLAG_NAMES[index]) + '_' + suffix;
470 } 485 }
471 486
472 void SetInternalFlag(const InternalFlag ii, const std::string& value) const { 487 void SetInternalFlag(const InternalFlag flag, const std::string& value) const {
473 shader.AddLine(GetInternalFlag(ii) + " = " + value + ';'); 488 shader.AddLine(GetInternalFlag(flag) + " = " + value + ';');
474 } 489 }
475 490
476 /** 491 /**
@@ -621,8 +636,8 @@ private:
621 636
622 /// Generates declarations for internal flags. 637 /// Generates declarations for internal flags.
623 void GenerateInternalFlags() { 638 void GenerateInternalFlags() {
624 for (u32 ii = 0; ii < static_cast<u64>(InternalFlag::Amount); ii++) { 639 for (u32 flag = 0; flag < static_cast<u32>(InternalFlag::Amount); flag++) {
625 const InternalFlag code = static_cast<InternalFlag>(ii); 640 const InternalFlag code = static_cast<InternalFlag>(flag);
626 declarations.AddLine("bool " + GetInternalFlag(code) + " = false;"); 641 declarations.AddLine("bool " + GetInternalFlag(code) + " = false;");
627 } 642 }
628 declarations.AddNewLine(); 643 declarations.AddNewLine();
@@ -939,9 +954,10 @@ private:
939class GLSLGenerator { 954class GLSLGenerator {
940public: 955public:
941 GLSLGenerator(const std::set<Subroutine>& subroutines, const ProgramCode& program_code, 956 GLSLGenerator(const std::set<Subroutine>& subroutines, const ProgramCode& program_code,
942 u32 main_offset, Maxwell3D::Regs::ShaderStage stage, const std::string& suffix) 957 u32 main_offset, Maxwell3D::Regs::ShaderStage stage, const std::string& suffix,
958 std::size_t shader_length)
943 : subroutines(subroutines), program_code(program_code), main_offset(main_offset), 959 : subroutines(subroutines), program_code(program_code), main_offset(main_offset),
944 stage(stage), suffix(suffix) { 960 stage(stage), suffix(suffix), shader_length(shader_length) {
945 std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header)); 961 std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header));
946 local_memory_size = header.GetLocalMemorySize(); 962 local_memory_size = header.GetLocalMemorySize();
947 regs.SetLocalMemory(local_memory_size); 963 regs.SetLocalMemory(local_memory_size);
@@ -954,7 +970,7 @@ public:
954 970
955 /// Returns entries in the shader that are useful for external functions 971 /// Returns entries in the shader that are useful for external functions
956 ShaderEntries GetEntries() const { 972 ShaderEntries GetEntries() const {
957 return {regs.GetConstBuffersDeclarations(), regs.GetSamplers()}; 973 return {regs.GetConstBuffersDeclarations(), regs.GetSamplers(), shader_length};
958 } 974 }
959 975
960private: 976private:
@@ -1505,9 +1521,8 @@ private:
1505 instr.fmul.tab5c68_0 != 1, "FMUL tab5cb8_0({}) is not implemented", 1521 instr.fmul.tab5c68_0 != 1, "FMUL tab5cb8_0({}) is not implemented",
1506 instr.fmul.tab5c68_0 1522 instr.fmul.tab5c68_0
1507 .Value()); // SMO typical sends 1 here which seems to be the default 1523 .Value()); // SMO typical sends 1 here which seems to be the default
1508 UNIMPLEMENTED_IF_MSG(instr.fmul.cc != 0, "FMUL cc is not implemented");
1509 UNIMPLEMENTED_IF_MSG(instr.generates_cc, 1524 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
1510 "FMUL Generates an unhandled Control Code"); 1525 "Condition codes generation in FMUL is not implemented");
1511 1526
1512 op_b = GetOperandAbsNeg(op_b, false, instr.fmul.negate_b); 1527 op_b = GetOperandAbsNeg(op_b, false, instr.fmul.negate_b);
1513 1528
@@ -1519,7 +1534,7 @@ private:
1519 case OpCode::Id::FADD_R: 1534 case OpCode::Id::FADD_R:
1520 case OpCode::Id::FADD_IMM: { 1535 case OpCode::Id::FADD_IMM: {
1521 UNIMPLEMENTED_IF_MSG(instr.generates_cc, 1536 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
1522 "FADD Generates an unhandled Control Code"); 1537 "Condition codes generation in FADD is not implemented");
1523 1538
1524 op_a = GetOperandAbsNeg(op_a, instr.alu.abs_a, instr.alu.negate_a); 1539 op_a = GetOperandAbsNeg(op_a, instr.alu.abs_a, instr.alu.negate_a);
1525 op_b = GetOperandAbsNeg(op_b, instr.alu.abs_b, instr.alu.negate_b); 1540 op_b = GetOperandAbsNeg(op_b, instr.alu.abs_b, instr.alu.negate_b);
@@ -1569,7 +1584,7 @@ private:
1569 case OpCode::Id::FMNMX_R: 1584 case OpCode::Id::FMNMX_R:
1570 case OpCode::Id::FMNMX_IMM: { 1585 case OpCode::Id::FMNMX_IMM: {
1571 UNIMPLEMENTED_IF_MSG(instr.generates_cc, 1586 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
1572 "FMNMX Generates an unhandled Control Code"); 1587 "Condition codes generation in FMNMX is not implemented");
1573 1588
1574 op_a = GetOperandAbsNeg(op_a, instr.alu.abs_a, instr.alu.negate_a); 1589 op_a = GetOperandAbsNeg(op_a, instr.alu.abs_a, instr.alu.negate_a);
1575 op_b = GetOperandAbsNeg(op_b, instr.alu.abs_b, instr.alu.negate_b); 1590 op_b = GetOperandAbsNeg(op_b, instr.alu.abs_b, instr.alu.negate_b);
@@ -1606,7 +1621,7 @@ private:
1606 } 1621 }
1607 case OpCode::Id::FMUL32_IMM: { 1622 case OpCode::Id::FMUL32_IMM: {
1608 UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc, 1623 UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc,
1609 "FMUL32 Generates an unhandled Control Code"); 1624 "Condition codes generation in FMUL32 is not implemented");
1610 1625
1611 regs.SetRegisterToFloat(instr.gpr0, 0, 1626 regs.SetRegisterToFloat(instr.gpr0, 0,
1612 regs.GetRegisterAsFloat(instr.gpr8) + " * " + 1627 regs.GetRegisterAsFloat(instr.gpr8) + " * " +
@@ -1616,7 +1631,7 @@ private:
1616 } 1631 }
1617 case OpCode::Id::FADD32I: { 1632 case OpCode::Id::FADD32I: {
1618 UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc, 1633 UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc,
1619 "FADD32 Generates an unhandled Control Code"); 1634 "Condition codes generation in FADD32I is not implemented");
1620 1635
1621 std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); 1636 std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
1622 std::string op_b = GetImmediate32(instr); 1637 std::string op_b = GetImmediate32(instr);
@@ -1651,7 +1666,8 @@ private:
1651 1666
1652 switch (opcode->get().GetId()) { 1667 switch (opcode->get().GetId()) {
1653 case OpCode::Id::BFE_IMM: { 1668 case OpCode::Id::BFE_IMM: {
1654 UNIMPLEMENTED_IF_MSG(instr.generates_cc, "BFE Generates an unhandled Control Code"); 1669 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
1670 "Condition codes generation in BFE is not implemented");
1655 1671
1656 std::string inner_shift = 1672 std::string inner_shift =
1657 '(' + op_a + " << " + std::to_string(instr.bfe.GetLeftShiftValue()) + ')'; 1673 '(' + op_a + " << " + std::to_string(instr.bfe.GetLeftShiftValue()) + ')';
@@ -1688,7 +1704,8 @@ private:
1688 case OpCode::Id::SHR_C: 1704 case OpCode::Id::SHR_C:
1689 case OpCode::Id::SHR_R: 1705 case OpCode::Id::SHR_R:
1690 case OpCode::Id::SHR_IMM: { 1706 case OpCode::Id::SHR_IMM: {
1691 UNIMPLEMENTED_IF_MSG(instr.generates_cc, "SHR Generates an unhandled Control Code"); 1707 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
1708 "Condition codes generation in SHR is not implemented");
1692 1709
1693 if (!instr.shift.is_signed) { 1710 if (!instr.shift.is_signed) {
1694 // Logical shift right 1711 // Logical shift right
@@ -1703,8 +1720,8 @@ private:
1703 case OpCode::Id::SHL_C: 1720 case OpCode::Id::SHL_C:
1704 case OpCode::Id::SHL_R: 1721 case OpCode::Id::SHL_R:
1705 case OpCode::Id::SHL_IMM: 1722 case OpCode::Id::SHL_IMM:
1706 UNIMPLEMENTED_IF_MSG(instr.generates_cc, "SHL Generates an unhandled Control Code"); 1723 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
1707 1724 "Condition codes generation in SHL is not implemented");
1708 regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " << " + op_b, 1, 1); 1725 regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " << " + op_b, 1, 1);
1709 break; 1726 break;
1710 default: { 1727 default: {
@@ -1720,7 +1737,7 @@ private:
1720 switch (opcode->get().GetId()) { 1737 switch (opcode->get().GetId()) {
1721 case OpCode::Id::IADD32I: 1738 case OpCode::Id::IADD32I:
1722 UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc, 1739 UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc,
1723 "IADD32 Generates an unhandled Control Code"); 1740 "Condition codes generation in IADD32I is not implemented");
1724 1741
1725 if (instr.iadd32i.negate_a) 1742 if (instr.iadd32i.negate_a)
1726 op_a = "-(" + op_a + ')'; 1743 op_a = "-(" + op_a + ')';
@@ -1730,7 +1747,7 @@ private:
1730 break; 1747 break;
1731 case OpCode::Id::LOP32I: { 1748 case OpCode::Id::LOP32I: {
1732 UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc, 1749 UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc,
1733 "LOP32I Generates an unhandled Control Code"); 1750 "Condition codes generation in LOP32I is not implemented");
1734 1751
1735 if (instr.alu.lop32i.invert_a) 1752 if (instr.alu.lop32i.invert_a)
1736 op_a = "~(" + op_a + ')'; 1753 op_a = "~(" + op_a + ')';
@@ -1769,7 +1786,7 @@ private:
1769 case OpCode::Id::IADD_R: 1786 case OpCode::Id::IADD_R:
1770 case OpCode::Id::IADD_IMM: { 1787 case OpCode::Id::IADD_IMM: {
1771 UNIMPLEMENTED_IF_MSG(instr.generates_cc, 1788 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
1772 "IADD Generates an unhandled Control Code"); 1789 "Condition codes generation in IADD is not implemented");
1773 1790
1774 if (instr.alu_integer.negate_a) 1791 if (instr.alu_integer.negate_a)
1775 op_a = "-(" + op_a + ')'; 1792 op_a = "-(" + op_a + ')';
@@ -1785,7 +1802,7 @@ private:
1785 case OpCode::Id::IADD3_R: 1802 case OpCode::Id::IADD3_R:
1786 case OpCode::Id::IADD3_IMM: { 1803 case OpCode::Id::IADD3_IMM: {
1787 UNIMPLEMENTED_IF_MSG(instr.generates_cc, 1804 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
1788 "IADD3 Generates an unhandled Control Code"); 1805 "Condition codes generation in IADD3 is not implemented");
1789 1806
1790 std::string op_c = regs.GetRegisterAsInteger(instr.gpr39); 1807 std::string op_c = regs.GetRegisterAsInteger(instr.gpr39);
1791 1808
@@ -1848,7 +1865,7 @@ private:
1848 case OpCode::Id::ISCADD_R: 1865 case OpCode::Id::ISCADD_R:
1849 case OpCode::Id::ISCADD_IMM: { 1866 case OpCode::Id::ISCADD_IMM: {
1850 UNIMPLEMENTED_IF_MSG(instr.generates_cc, 1867 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
1851 "ISCADD Generates an unhandled Control Code"); 1868 "Condition codes generation in ISCADD is not implemented");
1852 1869
1853 if (instr.alu_integer.negate_a) 1870 if (instr.alu_integer.negate_a)
1854 op_a = "-(" + op_a + ')'; 1871 op_a = "-(" + op_a + ')';
@@ -1883,7 +1900,8 @@ private:
1883 case OpCode::Id::LOP_C: 1900 case OpCode::Id::LOP_C:
1884 case OpCode::Id::LOP_R: 1901 case OpCode::Id::LOP_R:
1885 case OpCode::Id::LOP_IMM: { 1902 case OpCode::Id::LOP_IMM: {
1886 UNIMPLEMENTED_IF_MSG(instr.generates_cc, "LOP Generates an unhandled Control Code"); 1903 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
1904 "Condition codes generation in LOP is not implemented");
1887 1905
1888 if (instr.alu.lop.invert_a) 1906 if (instr.alu.lop.invert_a)
1889 op_a = "~(" + op_a + ')'; 1907 op_a = "~(" + op_a + ')';
@@ -1899,7 +1917,7 @@ private:
1899 case OpCode::Id::LOP3_R: 1917 case OpCode::Id::LOP3_R:
1900 case OpCode::Id::LOP3_IMM: { 1918 case OpCode::Id::LOP3_IMM: {
1901 UNIMPLEMENTED_IF_MSG(instr.generates_cc, 1919 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
1902 "LOP3 Generates an unhandled Control Code"); 1920 "Condition codes generation in LOP3 is not implemented");
1903 1921
1904 const std::string op_c = regs.GetRegisterAsInteger(instr.gpr39); 1922 const std::string op_c = regs.GetRegisterAsInteger(instr.gpr39);
1905 std::string lut; 1923 std::string lut;
@@ -1918,7 +1936,7 @@ private:
1918 case OpCode::Id::IMNMX_IMM: { 1936 case OpCode::Id::IMNMX_IMM: {
1919 UNIMPLEMENTED_IF(instr.imnmx.exchange != Tegra::Shader::IMinMaxExchange::None); 1937 UNIMPLEMENTED_IF(instr.imnmx.exchange != Tegra::Shader::IMinMaxExchange::None);
1920 UNIMPLEMENTED_IF_MSG(instr.generates_cc, 1938 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
1921 "IMNMX Generates an unhandled Control Code"); 1939 "Condition codes generation in IMNMX is not implemented");
1922 1940
1923 const std::string condition = 1941 const std::string condition =
1924 GetPredicateCondition(instr.imnmx.pred, instr.imnmx.negate_pred != 0); 1942 GetPredicateCondition(instr.imnmx.pred, instr.imnmx.negate_pred != 0);
@@ -2091,7 +2109,8 @@ private:
2091 instr.ffma.tab5980_0.Value()); // Seems to be 1 by default based on SMO 2109 instr.ffma.tab5980_0.Value()); // Seems to be 1 by default based on SMO
2092 UNIMPLEMENTED_IF_MSG(instr.ffma.tab5980_1 != 0, "FFMA tab5980_1({}) not implemented", 2110 UNIMPLEMENTED_IF_MSG(instr.ffma.tab5980_1 != 0, "FFMA tab5980_1({}) not implemented",
2093 instr.ffma.tab5980_1.Value()); 2111 instr.ffma.tab5980_1.Value());
2094 UNIMPLEMENTED_IF_MSG(instr.generates_cc, "FFMA Generates an unhandled Control Code"); 2112 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
2113 "Condition codes generation in FFMA is not implemented");
2095 2114
2096 switch (opcode->get().GetId()) { 2115 switch (opcode->get().GetId()) {
2097 case OpCode::Id::FFMA_CR: { 2116 case OpCode::Id::FFMA_CR: {
@@ -2201,7 +2220,8 @@ private:
2201 case OpCode::Id::I2F_C: { 2220 case OpCode::Id::I2F_C: {
2202 UNIMPLEMENTED_IF(instr.conversion.dest_size != Register::Size::Word); 2221 UNIMPLEMENTED_IF(instr.conversion.dest_size != Register::Size::Word);
2203 UNIMPLEMENTED_IF(instr.conversion.selector); 2222 UNIMPLEMENTED_IF(instr.conversion.selector);
2204 UNIMPLEMENTED_IF_MSG(instr.generates_cc, "I2F Generates an unhandled Control Code"); 2223 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
2224 "Condition codes generation in I2F is not implemented");
2205 2225
2206 std::string op_a{}; 2226 std::string op_a{};
2207 2227
@@ -2231,7 +2251,8 @@ private:
2231 case OpCode::Id::F2F_R: { 2251 case OpCode::Id::F2F_R: {
2232 UNIMPLEMENTED_IF(instr.conversion.dest_size != Register::Size::Word); 2252 UNIMPLEMENTED_IF(instr.conversion.dest_size != Register::Size::Word);
2233 UNIMPLEMENTED_IF(instr.conversion.src_size != Register::Size::Word); 2253 UNIMPLEMENTED_IF(instr.conversion.src_size != Register::Size::Word);
2234 UNIMPLEMENTED_IF_MSG(instr.generates_cc, "F2F Generates an unhandled Control Code"); 2254 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
2255 "Condition codes generation in F2F is not implemented");
2235 std::string op_a = regs.GetRegisterAsFloat(instr.gpr20); 2256 std::string op_a = regs.GetRegisterAsFloat(instr.gpr20);
2236 2257
2237 if (instr.conversion.abs_a) { 2258 if (instr.conversion.abs_a) {
@@ -2269,7 +2290,8 @@ private:
2269 case OpCode::Id::F2I_R: 2290 case OpCode::Id::F2I_R:
2270 case OpCode::Id::F2I_C: { 2291 case OpCode::Id::F2I_C: {
2271 UNIMPLEMENTED_IF(instr.conversion.src_size != Register::Size::Word); 2292 UNIMPLEMENTED_IF(instr.conversion.src_size != Register::Size::Word);
2272 UNIMPLEMENTED_IF_MSG(instr.generates_cc, "F2I Generates an unhandled Control Code"); 2293 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
2294 "Condition codes generation in F2I is not implemented");
2273 std::string op_a{}; 2295 std::string op_a{};
2274 2296
2275 if (instr.is_b_gpr) { 2297 if (instr.is_b_gpr) {
@@ -3118,7 +3140,8 @@ private:
3118 break; 3140 break;
3119 } 3141 }
3120 case OpCode::Type::PredicateSetRegister: { 3142 case OpCode::Type::PredicateSetRegister: {
3121 UNIMPLEMENTED_IF_MSG(instr.generates_cc, "PSET Generates an unhandled Control Code"); 3143 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
3144 "Condition codes generation in PSET is not implemented");
3122 3145
3123 const std::string op_a = 3146 const std::string op_a =
3124 GetPredicateCondition(instr.pset.pred12, instr.pset.neg_pred12 != 0); 3147 GetPredicateCondition(instr.pset.pred12, instr.pset.neg_pred12 != 0);
@@ -3177,14 +3200,14 @@ private:
3177 const std::string pred = 3200 const std::string pred =
3178 GetPredicateCondition(instr.csetp.pred39, instr.csetp.neg_pred39 != 0); 3201 GetPredicateCondition(instr.csetp.pred39, instr.csetp.neg_pred39 != 0);
3179 const std::string combiner = GetPredicateCombiner(instr.csetp.op); 3202 const std::string combiner = GetPredicateCombiner(instr.csetp.op);
3180 const std::string control_code = regs.GetControlCode(instr.csetp.cc); 3203 const std::string condition_code = regs.GetConditionCode(instr.csetp.cc);
3181 if (instr.csetp.pred3 != static_cast<u64>(Pred::UnusedIndex)) { 3204 if (instr.csetp.pred3 != static_cast<u64>(Pred::UnusedIndex)) {
3182 SetPredicate(instr.csetp.pred3, 3205 SetPredicate(instr.csetp.pred3,
3183 '(' + control_code + ") " + combiner + " (" + pred + ')'); 3206 '(' + condition_code + ") " + combiner + " (" + pred + ')');
3184 } 3207 }
3185 if (instr.csetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) { 3208 if (instr.csetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) {
3186 SetPredicate(instr.csetp.pred0, 3209 SetPredicate(instr.csetp.pred0,
3187 "!(" + control_code + ") " + combiner + " (" + pred + ')'); 3210 "!(" + condition_code + ") " + combiner + " (" + pred + ')');
3188 } 3211 }
3189 break; 3212 break;
3190 } 3213 }
@@ -3315,7 +3338,8 @@ private:
3315 case OpCode::Type::Xmad: { 3338 case OpCode::Type::Xmad: {
3316 UNIMPLEMENTED_IF(instr.xmad.sign_a); 3339 UNIMPLEMENTED_IF(instr.xmad.sign_a);
3317 UNIMPLEMENTED_IF(instr.xmad.sign_b); 3340 UNIMPLEMENTED_IF(instr.xmad.sign_b);
3318 UNIMPLEMENTED_IF_MSG(instr.generates_cc, "XMAD Generates an unhandled Control Code"); 3341 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
3342 "Condition codes generation in XMAD is not implemented");
3319 3343
3320 std::string op_a{regs.GetRegisterAsInteger(instr.gpr8, 0, instr.xmad.sign_a)}; 3344 std::string op_a{regs.GetRegisterAsInteger(instr.gpr8, 0, instr.xmad.sign_a)};
3321 std::string op_b; 3345 std::string op_b;
@@ -3407,9 +3431,9 @@ private:
3407 default: { 3431 default: {
3408 switch (opcode->get().GetId()) { 3432 switch (opcode->get().GetId()) {
3409 case OpCode::Id::EXIT: { 3433 case OpCode::Id::EXIT: {
3410 const Tegra::Shader::ControlCode cc = instr.flow_control_code; 3434 const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
3411 UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ControlCode::T, 3435 UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T,
3412 "EXIT Control Code used: {}", static_cast<u32>(cc)); 3436 "EXIT condition code used: {}", static_cast<u32>(cc));
3413 3437
3414 if (stage == Maxwell3D::Regs::ShaderStage::Fragment) { 3438 if (stage == Maxwell3D::Regs::ShaderStage::Fragment) {
3415 EmitFragmentOutputsWrite(); 3439 EmitFragmentOutputsWrite();
@@ -3441,9 +3465,9 @@ private:
3441 case OpCode::Id::KIL: { 3465 case OpCode::Id::KIL: {
3442 UNIMPLEMENTED_IF(instr.flow.cond != Tegra::Shader::FlowCondition::Always); 3466 UNIMPLEMENTED_IF(instr.flow.cond != Tegra::Shader::FlowCondition::Always);
3443 3467
3444 const Tegra::Shader::ControlCode cc = instr.flow_control_code; 3468 const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
3445 UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ControlCode::T, 3469 UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T,
3446 "KIL Control Code used: {}", static_cast<u32>(cc)); 3470 "KIL condition code used: {}", static_cast<u32>(cc));
3447 3471
3448 // Enclose "discard" in a conditional, so that GLSL compilation does not complain 3472 // Enclose "discard" in a conditional, so that GLSL compilation does not complain
3449 // about unexecuted instructions that may follow this. 3473 // about unexecuted instructions that may follow this.
@@ -3505,9 +3529,9 @@ private:
3505 UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0, 3529 UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0,
3506 "BRA with constant buffers are not implemented"); 3530 "BRA with constant buffers are not implemented");
3507 3531
3508 const Tegra::Shader::ControlCode cc = instr.flow_control_code; 3532 const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
3509 UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ControlCode::T, 3533 UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T,
3510 "BRA Control Code used: {}", static_cast<u32>(cc)); 3534 "BRA condition code used: {}", static_cast<u32>(cc));
3511 3535
3512 const u32 target = offset + instr.bra.GetBranchTarget(); 3536 const u32 target = offset + instr.bra.GetBranchTarget();
3513 shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }"); 3537 shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }");
@@ -3550,9 +3574,9 @@ private:
3550 break; 3574 break;
3551 } 3575 }
3552 case OpCode::Id::SYNC: { 3576 case OpCode::Id::SYNC: {
3553 const Tegra::Shader::ControlCode cc = instr.flow_control_code; 3577 const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
3554 UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ControlCode::T, 3578 UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T,
3555 "SYNC Control Code used: {}", static_cast<u32>(cc)); 3579 "SYNC condition code used: {}", static_cast<u32>(cc));
3556 3580
3557 // The SYNC opcode jumps to the address previously set by the SSY opcode 3581 // The SYNC opcode jumps to the address previously set by the SSY opcode
3558 EmitPopFromFlowStack(); 3582 EmitPopFromFlowStack();
@@ -3560,10 +3584,10 @@ private:
3560 } 3584 }
3561 case OpCode::Id::BRK: { 3585 case OpCode::Id::BRK: {
3562 // The BRK opcode jumps to the address previously set by the PBK opcode 3586 // The BRK opcode jumps to the address previously set by the PBK opcode
3563 const Tegra::Shader::ControlCode cc = instr.flow_control_code; 3587 const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
3564 if (cc != Tegra::Shader::ControlCode::T) { 3588 UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T,
3565 UNIMPLEMENTED_MSG("BRK Control Code used: {}", static_cast<u32>(cc)); 3589 "BRK condition code used: {}", static_cast<u32>(cc));
3566 } 3590
3567 EmitPopFromFlowStack(); 3591 EmitPopFromFlowStack();
3568 break; 3592 break;
3569 } 3593 }
@@ -3574,6 +3598,9 @@ private:
3574 break; 3598 break;
3575 } 3599 }
3576 case OpCode::Id::VMAD: { 3600 case OpCode::Id::VMAD: {
3601 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
3602 "Condition codes generation in VMAD is not implemented");
3603
3577 const bool result_signed = instr.video.signed_a == 1 || instr.video.signed_b == 1; 3604 const bool result_signed = instr.video.signed_a == 1 || instr.video.signed_b == 1;
3578 const std::string op_a = GetVideoOperandA(instr); 3605 const std::string op_a = GetVideoOperandA(instr);
3579 const std::string op_b = GetVideoOperandB(instr); 3606 const std::string op_b = GetVideoOperandB(instr);
@@ -3593,10 +3620,6 @@ private:
3593 regs.SetRegisterToInteger(instr.gpr0, result_signed, 1, result, 1, 1, 3620 regs.SetRegisterToInteger(instr.gpr0, result_signed, 1, result, 1, 1,
3594 instr.vmad.saturate == 1, 0, Register::Size::Word, 3621 instr.vmad.saturate == 1, 0, Register::Size::Word,
3595 instr.vmad.cc); 3622 instr.vmad.cc);
3596 if (instr.generates_cc) {
3597 UNIMPLEMENTED_MSG("VMAD Generates an unhandled Control Code");
3598 }
3599
3600 break; 3623 break;
3601 } 3624 }
3602 case OpCode::Id::VSETP: { 3625 case OpCode::Id::VSETP: {
@@ -3748,6 +3771,7 @@ private:
3748 Maxwell3D::Regs::ShaderStage stage; 3771 Maxwell3D::Regs::ShaderStage stage;
3749 const std::string& suffix; 3772 const std::string& suffix;
3750 u64 local_memory_size; 3773 u64 local_memory_size;
3774 std::size_t shader_length;
3751 3775
3752 ShaderWriter shader; 3776 ShaderWriter shader;
3753 ShaderWriter declarations; 3777 ShaderWriter declarations;
@@ -3766,9 +3790,10 @@ std::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u
3766 Maxwell3D::Regs::ShaderStage stage, 3790 Maxwell3D::Regs::ShaderStage stage,
3767 const std::string& suffix) { 3791 const std::string& suffix) {
3768 try { 3792 try {
3769 const auto subroutines = 3793 ControlFlowAnalyzer analyzer(program_code, main_offset, suffix);
3770 ControlFlowAnalyzer(program_code, main_offset, suffix).GetSubroutines(); 3794 const auto subroutines = analyzer.GetSubroutines();
3771 GLSLGenerator generator(subroutines, program_code, main_offset, stage, suffix); 3795 GLSLGenerator generator(subroutines, program_code, main_offset, stage, suffix,
3796 analyzer.GetShaderLength());
3772 return ProgramResult{generator.GetShaderCode(), generator.GetEntries()}; 3797 return ProgramResult{generator.GetShaderCode(), generator.GetEntries()};
3773 } catch (const DecompileFail& exception) { 3798 } catch (const DecompileFail& exception) {
3774 LOG_ERROR(HW_GPU, "Shader decompilation failed: {}", exception.what()); 3799 LOG_ERROR(HW_GPU, "Shader decompilation failed: {}", exception.what());
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h
index 520b9d4e3..b425d98ae 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.h
+++ b/src/video_core/renderer_opengl/gl_shader_gen.h
@@ -163,6 +163,7 @@ private:
163struct ShaderEntries { 163struct ShaderEntries {
164 std::vector<ConstBufferEntry> const_buffer_entries; 164 std::vector<ConstBufferEntry> const_buffer_entries;
165 std::vector<SamplerEntry> texture_samplers; 165 std::vector<SamplerEntry> texture_samplers;
166 std::size_t shader_length;
166}; 167};
167 168
168using ProgramResult = std::pair<std::string, ShaderEntries>; 169using ProgramResult = std::pair<std::string, ShaderEntries>;
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index d9910c6e8..934f4db78 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -233,6 +233,28 @@ void OpenGLState::ApplyStencilTest() const {
233 config_stencil(GL_BACK, stencil.back, cur_state.stencil.back); 233 config_stencil(GL_BACK, stencil.back, cur_state.stencil.back);
234 } 234 }
235} 235}
236// Viewport does not affects glClearBuffer so emulate viewport using scissor test
237void OpenGLState::EmulateViewportWithScissor() {
238 auto& current = viewports[0];
239 if (current.scissor.enabled) {
240 const GLint left = std::max(current.x, current.scissor.x);
241 const GLint right =
242 std::max(current.x + current.width, current.scissor.x + current.scissor.width);
243 const GLint bottom = std::max(current.y, current.scissor.y);
244 const GLint top =
245 std::max(current.y + current.height, current.scissor.y + current.scissor.height);
246 current.scissor.x = std::max(left, 0);
247 current.scissor.y = std::max(bottom, 0);
248 current.scissor.width = std::max(right - left, 0);
249 current.scissor.height = std::max(top - bottom, 0);
250 } else {
251 current.scissor.enabled = true;
252 current.scissor.x = current.x;
253 current.scissor.y = current.y;
254 current.scissor.width = current.width;
255 current.scissor.height = current.height;
256 }
257}
236 258
237void OpenGLState::ApplyViewport() const { 259void OpenGLState::ApplyViewport() const {
238 if (GLAD_GL_ARB_viewport_array && geometry_shaders.enabled) { 260 if (GLAD_GL_ARB_viewport_array && geometry_shaders.enabled) {
@@ -242,7 +264,9 @@ void OpenGLState::ApplyViewport() const {
242 const auto& updated = viewports[i]; 264 const auto& updated = viewports[i];
243 if (updated.x != current.x || updated.y != current.y || 265 if (updated.x != current.x || updated.y != current.y ||
244 updated.width != current.width || updated.height != current.height) { 266 updated.width != current.width || updated.height != current.height) {
245 glViewportIndexedf(i, updated.x, updated.y, updated.width, updated.height); 267 glViewportIndexedf(
268 i, static_cast<GLfloat>(updated.x), static_cast<GLfloat>(updated.y),
269 static_cast<GLfloat>(updated.width), static_cast<GLfloat>(updated.height));
246 } 270 }
247 if (updated.depth_range_near != current.depth_range_near || 271 if (updated.depth_range_near != current.depth_range_near ||
248 updated.depth_range_far != current.depth_range_far) { 272 updated.depth_range_far != current.depth_range_far) {
@@ -270,8 +294,7 @@ void OpenGLState::ApplyViewport() const {
270 const auto& updated = viewports[0]; 294 const auto& updated = viewports[0];
271 if (updated.x != current.x || updated.y != current.y || updated.width != current.width || 295 if (updated.x != current.x || updated.y != current.y || updated.width != current.width ||
272 updated.height != current.height) { 296 updated.height != current.height) {
273 glViewport(static_cast<GLint>(updated.x), static_cast<GLint>(updated.y), 297 glViewport(updated.x, updated.y, updated.width, updated.height);
274 static_cast<GLsizei>(updated.width), static_cast<GLsizei>(updated.height));
275 } 298 }
276 if (updated.depth_range_near != current.depth_range_near || 299 if (updated.depth_range_near != current.depth_range_near ||
277 updated.depth_range_far != current.depth_range_far) { 300 updated.depth_range_far != current.depth_range_far) {
@@ -339,14 +362,14 @@ void OpenGLState::ApplyTargetBlending(std::size_t target, bool force) const {
339 if (blend_changed || updated.src_rgb_func != current.src_rgb_func || 362 if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
340 updated.dst_rgb_func != current.dst_rgb_func || updated.src_a_func != current.src_a_func || 363 updated.dst_rgb_func != current.dst_rgb_func || updated.src_a_func != current.src_a_func ||
341 updated.dst_a_func != current.dst_a_func) { 364 updated.dst_a_func != current.dst_a_func) {
342 glBlendFuncSeparateiARB(static_cast<GLuint>(target), updated.src_rgb_func, 365 glBlendFuncSeparatei(static_cast<GLuint>(target), updated.src_rgb_func,
343 updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func); 366 updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func);
344 } 367 }
345 368
346 if (blend_changed || updated.rgb_equation != current.rgb_equation || 369 if (blend_changed || updated.rgb_equation != current.rgb_equation ||
347 updated.a_equation != current.a_equation) { 370 updated.a_equation != current.a_equation) {
348 glBlendEquationSeparateiARB(static_cast<GLuint>(target), updated.rgb_equation, 371 glBlendEquationSeparatei(static_cast<GLuint>(target), updated.rgb_equation,
349 updated.a_equation); 372 updated.a_equation);
350 } 373 }
351} 374}
352 375
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index bdc743b0f..032fc43f0 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -156,10 +156,10 @@ public:
156 } draw; 156 } draw;
157 157
158 struct viewport { 158 struct viewport {
159 GLfloat x; 159 GLint x;
160 GLfloat y; 160 GLint y;
161 GLfloat width; 161 GLint width;
162 GLfloat height; 162 GLint height;
163 GLfloat depth_range_near; // GL_DEPTH_RANGE 163 GLfloat depth_range_near; // GL_DEPTH_RANGE
164 GLfloat depth_range_far; // GL_DEPTH_RANGE 164 GLfloat depth_range_far; // GL_DEPTH_RANGE
165 struct { 165 struct {
@@ -206,6 +206,7 @@ public:
206 OpenGLState& ResetBuffer(GLuint handle); 206 OpenGLState& ResetBuffer(GLuint handle);
207 OpenGLState& ResetVertexArray(GLuint handle); 207 OpenGLState& ResetVertexArray(GLuint handle);
208 OpenGLState& ResetFramebuffer(GLuint handle); 208 OpenGLState& ResetFramebuffer(GLuint handle);
209 void EmulateViewportWithScissor();
209 210
210private: 211private:
211 static OpenGLState cur_state; 212 static OpenGLState cur_state;
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 27b5b8960..1492e063a 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -490,7 +490,7 @@ bool RendererOpenGL::Init() {
490 Core::Telemetry().AddField(Telemetry::FieldType::UserSystem, "GPU_Model", gpu_model); 490 Core::Telemetry().AddField(Telemetry::FieldType::UserSystem, "GPU_Model", gpu_model);
491 Core::Telemetry().AddField(Telemetry::FieldType::UserSystem, "GPU_OpenGL_Version", gl_version); 491 Core::Telemetry().AddField(Telemetry::FieldType::UserSystem, "GPU_OpenGL_Version", gl_version);
492 492
493 if (!GLAD_GL_VERSION_3_3) { 493 if (!GLAD_GL_VERSION_4_3) {
494 return false; 494 return false;
495 } 495 }
496 496
diff --git a/src/yuzu/applets/software_keyboard.cpp b/src/yuzu/applets/software_keyboard.cpp
index efefb1f99..8a26fdff1 100644
--- a/src/yuzu/applets/software_keyboard.cpp
+++ b/src/yuzu/applets/software_keyboard.cpp
@@ -82,8 +82,8 @@ QtSoftwareKeyboardDialog::QtSoftwareKeyboardDialog(
82 : QString::fromStdU16String(parameters.submit_text), 82 : QString::fromStdU16String(parameters.submit_text),
83 QDialogButtonBox::AcceptRole); 83 QDialogButtonBox::AcceptRole);
84 84
85 connect(buttons, &QDialogButtonBox::accepted, this, &QtSoftwareKeyboardDialog::Submit); 85 connect(buttons, &QDialogButtonBox::accepted, this, &QtSoftwareKeyboardDialog::accept);
86 connect(buttons, &QDialogButtonBox::rejected, this, &QtSoftwareKeyboardDialog::Reject); 86 connect(buttons, &QDialogButtonBox::rejected, this, &QtSoftwareKeyboardDialog::reject);
87 layout->addWidget(header_label); 87 layout->addWidget(header_label);
88 layout->addWidget(sub_label); 88 layout->addWidget(sub_label);
89 layout->addWidget(guide_label); 89 layout->addWidget(guide_label);
@@ -96,16 +96,16 @@ QtSoftwareKeyboardDialog::QtSoftwareKeyboardDialog(
96 96
97QtSoftwareKeyboardDialog::~QtSoftwareKeyboardDialog() = default; 97QtSoftwareKeyboardDialog::~QtSoftwareKeyboardDialog() = default;
98 98
99void QtSoftwareKeyboardDialog::Submit() { 99void QtSoftwareKeyboardDialog::accept() {
100 ok = true; 100 ok = true;
101 text = line_edit->text().toStdU16String(); 101 text = line_edit->text().toStdU16String();
102 accept(); 102 QDialog::accept();
103} 103}
104 104
105void QtSoftwareKeyboardDialog::Reject() { 105void QtSoftwareKeyboardDialog::reject() {
106 ok = false; 106 ok = false;
107 text.clear(); 107 text.clear();
108 accept(); 108 QDialog::reject();
109} 109}
110 110
111std::u16string QtSoftwareKeyboardDialog::GetText() const { 111std::u16string QtSoftwareKeyboardDialog::GetText() const {
@@ -129,13 +129,13 @@ QtSoftwareKeyboard::~QtSoftwareKeyboard() = default;
129 129
130void QtSoftwareKeyboard::RequestText(std::function<void(std::optional<std::u16string>)> out, 130void QtSoftwareKeyboard::RequestText(std::function<void(std::optional<std::u16string>)> out,
131 Core::Frontend::SoftwareKeyboardParameters parameters) const { 131 Core::Frontend::SoftwareKeyboardParameters parameters) const {
132 text_output = out; 132 text_output = std::move(out);
133 emit MainWindowGetText(parameters); 133 emit MainWindowGetText(parameters);
134} 134}
135 135
136void QtSoftwareKeyboard::SendTextCheckDialog(std::u16string error_message, 136void QtSoftwareKeyboard::SendTextCheckDialog(std::u16string error_message,
137 std::function<void()> finished_check) const { 137 std::function<void()> finished_check) const {
138 this->finished_check = finished_check; 138 this->finished_check = std::move(finished_check);
139 emit MainWindowTextCheckDialog(error_message); 139 emit MainWindowTextCheckDialog(error_message);
140} 140}
141 141
diff --git a/src/yuzu/applets/software_keyboard.h b/src/yuzu/applets/software_keyboard.h
index 73f56714f..c63720ba4 100644
--- a/src/yuzu/applets/software_keyboard.h
+++ b/src/yuzu/applets/software_keyboard.h
@@ -33,8 +33,8 @@ public:
33 Core::Frontend::SoftwareKeyboardParameters parameters); 33 Core::Frontend::SoftwareKeyboardParameters parameters);
34 ~QtSoftwareKeyboardDialog() override; 34 ~QtSoftwareKeyboardDialog() override;
35 35
36 void Submit(); 36 void accept() override;
37 void Reject(); 37 void reject() override;
38 38
39 std::u16string GetText() const; 39 std::u16string GetText() const;
40 bool GetStatus() const; 40 bool GetStatus() const;
@@ -70,11 +70,10 @@ signals:
70 void MainWindowGetText(Core::Frontend::SoftwareKeyboardParameters parameters) const; 70 void MainWindowGetText(Core::Frontend::SoftwareKeyboardParameters parameters) const;
71 void MainWindowTextCheckDialog(std::u16string error_message) const; 71 void MainWindowTextCheckDialog(std::u16string error_message) const;
72 72
73public slots: 73private:
74 void MainWindowFinishedText(std::optional<std::u16string> text); 74 void MainWindowFinishedText(std::optional<std::u16string> text);
75 void MainWindowFinishedCheckDialog(); 75 void MainWindowFinishedCheckDialog();
76 76
77private:
78 mutable std::function<void(std::optional<std::u16string>)> text_output; 77 mutable std::function<void(std::optional<std::u16string>)> text_output;
79 mutable std::function<void()> finished_check; 78 mutable std::function<void()> finished_check;
80}; 79};
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index 39eef8858..384e17921 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -310,7 +310,7 @@ void GRenderWindow::InitRenderTarget() {
310 // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground, 310 // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground,
311 // WA_DontShowOnScreen, WA_DeleteOnClose 311 // WA_DontShowOnScreen, WA_DeleteOnClose
312 QGLFormat fmt; 312 QGLFormat fmt;
313 fmt.setVersion(3, 3); 313 fmt.setVersion(4, 3);
314 fmt.setProfile(QGLFormat::CoreProfile); 314 fmt.setProfile(QGLFormat::CoreProfile);
315 fmt.setSwapInterval(false); 315 fmt.setSwapInterval(false);
316 316
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index e24ed5f2b..83ebbd1fe 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -432,6 +432,7 @@ void Config::ReadValues() {
432 Settings::values.use_gdbstub = qt_config->value("use_gdbstub", false).toBool(); 432 Settings::values.use_gdbstub = qt_config->value("use_gdbstub", false).toBool();
433 Settings::values.gdbstub_port = qt_config->value("gdbstub_port", 24689).toInt(); 433 Settings::values.gdbstub_port = qt_config->value("gdbstub_port", 24689).toInt();
434 Settings::values.program_args = qt_config->value("program_args", "").toString().toStdString(); 434 Settings::values.program_args = qt_config->value("program_args", "").toString().toStdString();
435 Settings::values.dump_exefs = qt_config->value("dump_exefs", false).toBool();
435 Settings::values.dump_nso = qt_config->value("dump_nso", false).toBool(); 436 Settings::values.dump_nso = qt_config->value("dump_nso", false).toBool();
436 qt_config->endGroup(); 437 qt_config->endGroup();
437 438
@@ -638,6 +639,7 @@ void Config::SaveValues() {
638 qt_config->setValue("use_gdbstub", Settings::values.use_gdbstub); 639 qt_config->setValue("use_gdbstub", Settings::values.use_gdbstub);
639 qt_config->setValue("gdbstub_port", Settings::values.gdbstub_port); 640 qt_config->setValue("gdbstub_port", Settings::values.gdbstub_port);
640 qt_config->setValue("program_args", QString::fromStdString(Settings::values.program_args)); 641 qt_config->setValue("program_args", QString::fromStdString(Settings::values.program_args));
642 qt_config->setValue("dump_exefs", Settings::values.dump_exefs);
641 qt_config->setValue("dump_nso", Settings::values.dump_nso); 643 qt_config->setValue("dump_nso", Settings::values.dump_nso);
642 qt_config->endGroup(); 644 qt_config->endGroup();
643 645
diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp
index fd5876b41..aa7de7b54 100644
--- a/src/yuzu/configuration/configure_debug.cpp
+++ b/src/yuzu/configuration/configure_debug.cpp
@@ -34,6 +34,7 @@ void ConfigureDebug::setConfiguration() {
34 ui->toggle_console->setChecked(UISettings::values.show_console); 34 ui->toggle_console->setChecked(UISettings::values.show_console);
35 ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter)); 35 ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter));
36 ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args)); 36 ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args));
37 ui->dump_exefs->setChecked(Settings::values.dump_exefs);
37 ui->dump_decompressed_nso->setChecked(Settings::values.dump_nso); 38 ui->dump_decompressed_nso->setChecked(Settings::values.dump_nso);
38} 39}
39 40
@@ -43,6 +44,7 @@ void ConfigureDebug::applyConfiguration() {
43 UISettings::values.show_console = ui->toggle_console->isChecked(); 44 UISettings::values.show_console = ui->toggle_console->isChecked();
44 Settings::values.log_filter = ui->log_filter_edit->text().toStdString(); 45 Settings::values.log_filter = ui->log_filter_edit->text().toStdString();
45 Settings::values.program_args = ui->homebrew_args_edit->text().toStdString(); 46 Settings::values.program_args = ui->homebrew_args_edit->text().toStdString();
47 Settings::values.dump_exefs = ui->dump_exefs->isChecked();
46 Settings::values.dump_nso = ui->dump_decompressed_nso->isChecked(); 48 Settings::values.dump_nso = ui->dump_decompressed_nso->isChecked();
47 Debugger::ToggleConsole(); 49 Debugger::ToggleConsole();
48 Log::Filter filter; 50 Log::Filter filter;
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui
index 9c5b702f8..758a92335 100644
--- a/src/yuzu/configuration/configure_debug.ui
+++ b/src/yuzu/configuration/configure_debug.ui
@@ -145,6 +145,16 @@
145 </property> 145 </property>
146 </widget> 146 </widget>
147 </item> 147 </item>
148 <item>
149 <widget class="QCheckBox" name="dump_exefs">
150 <property name="whatsThis">
151 <string>When checked, any game that yuzu loads will have its ExeFS dumped to the yuzu/dump directory.</string>
152 </property>
153 <property name="text">
154 <string>Dump ExeFS</string>
155 </property>
156 </widget>
157 </item>
148 </layout> 158 </layout>
149 </widget> 159 </widget>
150 </item> 160 </item>
diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui
index 91fcad994..e278cdd05 100644
--- a/src/yuzu/configuration/configure_graphics.ui
+++ b/src/yuzu/configuration/configure_graphics.ui
@@ -23,31 +23,31 @@
23 </property> 23 </property>
24 <layout class="QVBoxLayout" name="verticalLayout_2"> 24 <layout class="QVBoxLayout" name="verticalLayout_2">
25 <item> 25 <item>
26 <layout class="QHBoxLayout" name="horizontalLayout_2"> 26 <layout class="QHBoxLayout" name="horizontalLayout_2">
27 <item> 27 <item>
28 <widget class="QCheckBox" name="toggle_frame_limit"> 28 <widget class="QCheckBox" name="toggle_frame_limit">
29 <property name="text"> 29 <property name="text">
30 <string>Limit Speed Percent</string> 30 <string>Limit Speed Percent</string>
31 </property> 31 </property>
32 </widget> 32 </widget>
33 </item> 33 </item>
34 <item> 34 <item>
35 <widget class="QSpinBox" name="frame_limit"> 35 <widget class="QSpinBox" name="frame_limit">
36 <property name="suffix"> 36 <property name="suffix">
37 <string>%</string> 37 <string>%</string>
38 </property> 38 </property>
39 <property name="minimum"> 39 <property name="minimum">
40 <number>1</number> 40 <number>1</number>
41 </property> 41 </property>
42 <property name="maximum"> 42 <property name="maximum">
43 <number>9999</number> 43 <number>9999</number>
44 </property> 44 </property>
45 <property name="value"> 45 <property name="value">
46 <number>100</number> 46 <number>100</number>
47 </property> 47 </property>
48 </widget> 48 </widget>
49 </item> 49 </item>
50 </layout> 50 </layout>
51 </item> 51 </item>
52 <item> 52 <item>
53 <widget class="QCheckBox" name="use_accurate_gpu_emulation"> 53 <widget class="QCheckBox" name="use_accurate_gpu_emulation">
@@ -61,7 +61,7 @@
61 <item> 61 <item>
62 <widget class="QLabel" name="label"> 62 <widget class="QLabel" name="label">
63 <property name="text"> 63 <property name="text">
64 <string>Internal Resolution:(Currently does nothing.)</string> 64 <string>Internal Resolution</string>
65 </property> 65 </property>
66 </widget> 66 </widget>
67 </item> 67 </item>
@@ -96,27 +96,27 @@
96 </item> 96 </item>
97 </layout> 97 </layout>
98 </item> 98 </item>
99 <item> 99 <item>
100 <layout class="QHBoxLayout" name="horizontalLayout_6"> 100 <layout class="QHBoxLayout" name="horizontalLayout_6">
101 <item> 101 <item>
102 <widget class="QLabel" name="bg_label"> 102 <widget class="QLabel" name="bg_label">
103 <property name="text"> 103 <property name="text">
104 <string>Background Color:</string> 104 <string>Background Color:</string>
105 </property> 105 </property>
106 </widget> 106 </widget>
107 </item> 107 </item>
108 <item> 108 <item>
109 <widget class="QPushButton" name="bg_button"> 109 <widget class="QPushButton" name="bg_button">
110 <property name="maximumSize"> 110 <property name="maximumSize">
111 <size> 111 <size>
112 <width>40</width> 112 <width>40</width>
113 <height>16777215</height> 113 <height>16777215</height>
114 </size> 114 </size>
115 </property> 115 </property>
116 </widget> 116 </widget>
117 </item> 117 </item>
118 </layout> 118 </layout>
119 </item> 119 </item>
120 </layout> 120 </layout>
121 </widget> 121 </widget>
122 </item> 122 </item>
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 9e13bbf7c..9c6d150a5 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -518,32 +518,18 @@ void GMainWindow::OnDisplayTitleBars(bool show) {
518QStringList GMainWindow::GetUnsupportedGLExtensions() { 518QStringList GMainWindow::GetUnsupportedGLExtensions() {
519 QStringList unsupported_ext; 519 QStringList unsupported_ext;
520 520
521 if (!GLAD_GL_ARB_program_interface_query)
522 unsupported_ext.append("ARB_program_interface_query");
523 if (!GLAD_GL_ARB_separate_shader_objects)
524 unsupported_ext.append("ARB_separate_shader_objects");
525 if (!GLAD_GL_ARB_vertex_attrib_binding)
526 unsupported_ext.append("ARB_vertex_attrib_binding");
527 if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev) 521 if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev)
528 unsupported_ext.append("ARB_vertex_type_10f_11f_11f_rev"); 522 unsupported_ext.append("ARB_vertex_type_10f_11f_11f_rev");
529 if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge) 523 if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge)
530 unsupported_ext.append("ARB_texture_mirror_clamp_to_edge"); 524 unsupported_ext.append("ARB_texture_mirror_clamp_to_edge");
531 if (!GLAD_GL_ARB_base_instance)
532 unsupported_ext.append("ARB_base_instance");
533 if (!GLAD_GL_ARB_texture_storage)
534 unsupported_ext.append("ARB_texture_storage");
535 if (!GLAD_GL_ARB_multi_bind) 525 if (!GLAD_GL_ARB_multi_bind)
536 unsupported_ext.append("ARB_multi_bind"); 526 unsupported_ext.append("ARB_multi_bind");
537 if (!GLAD_GL_ARB_copy_image)
538 unsupported_ext.append("ARB_copy_image");
539 527
540 // Extensions required to support some texture formats. 528 // Extensions required to support some texture formats.
541 if (!GLAD_GL_EXT_texture_compression_s3tc) 529 if (!GLAD_GL_EXT_texture_compression_s3tc)
542 unsupported_ext.append("EXT_texture_compression_s3tc"); 530 unsupported_ext.append("EXT_texture_compression_s3tc");
543 if (!GLAD_GL_ARB_texture_compression_rgtc) 531 if (!GLAD_GL_ARB_texture_compression_rgtc)
544 unsupported_ext.append("ARB_texture_compression_rgtc"); 532 unsupported_ext.append("ARB_texture_compression_rgtc");
545 if (!GLAD_GL_ARB_texture_compression_bptc)
546 unsupported_ext.append("ARB_texture_compression_bptc");
547 if (!GLAD_GL_ARB_depth_buffer_float) 533 if (!GLAD_GL_ARB_depth_buffer_float)
548 unsupported_ext.append("ARB_depth_buffer_float"); 534 unsupported_ext.append("ARB_depth_buffer_float");
549 535
@@ -562,8 +548,8 @@ bool GMainWindow::LoadROM(const QString& filename) {
562 render_window->MakeCurrent(); 548 render_window->MakeCurrent();
563 549
564 if (!gladLoadGL()) { 550 if (!gladLoadGL()) {
565 QMessageBox::critical(this, tr("Error while initializing OpenGL 3.3 Core!"), 551 QMessageBox::critical(this, tr("Error while initializing OpenGL 4.3 Core!"),
566 tr("Your GPU may not support OpenGL 3.3, or you do not " 552 tr("Your GPU may not support OpenGL 4.3, or you do not "
567 "have the latest graphics driver.")); 553 "have the latest graphics driver."));
568 return false; 554 return false;
569 } 555 }
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index c66353a65..097c1fbe3 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -366,6 +366,7 @@ void Config::ReadValues() {
366 Settings::values.gdbstub_port = 366 Settings::values.gdbstub_port =
367 static_cast<u16>(sdl2_config->GetInteger("Debugging", "gdbstub_port", 24689)); 367 static_cast<u16>(sdl2_config->GetInteger("Debugging", "gdbstub_port", 24689));
368 Settings::values.program_args = sdl2_config->Get("Debugging", "program_args", ""); 368 Settings::values.program_args = sdl2_config->Get("Debugging", "program_args", "");
369 Settings::values.dump_exefs = sdl2_config->GetBoolean("Debugging", "dump_exefs", false);
369 Settings::values.dump_nso = sdl2_config->GetBoolean("Debugging", "dump_nso", false); 370 Settings::values.dump_nso = sdl2_config->GetBoolean("Debugging", "dump_nso", false);
370 371
371 // Web Service 372 // Web Service
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index ecf625e7b..d73669f36 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -206,6 +206,8 @@ log_filter = *:Trace
206# Port for listening to GDB connections. 206# Port for listening to GDB connections.
207use_gdbstub=false 207use_gdbstub=false
208gdbstub_port=24689 208gdbstub_port=24689
209# Determines whether or not yuzu will dump the ExeFS of all games it attempts to load while loading them
210dump_exefs=false
209# Determines whether or not yuzu will dump all NSOs it attempts to load while loading them 211# Determines whether or not yuzu will dump all NSOs it attempts to load while loading them
210dump_nso=false 212dump_nso=false
211 213
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
index a9ad92a80..2d6f8cced 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
@@ -111,32 +111,18 @@ void EmuWindow_SDL2::Fullscreen() {
111bool EmuWindow_SDL2::SupportsRequiredGLExtensions() { 111bool EmuWindow_SDL2::SupportsRequiredGLExtensions() {
112 std::vector<std::string> unsupported_ext; 112 std::vector<std::string> unsupported_ext;
113 113
114 if (!GLAD_GL_ARB_program_interface_query)
115 unsupported_ext.push_back("ARB_program_interface_query");
116 if (!GLAD_GL_ARB_separate_shader_objects)
117 unsupported_ext.push_back("ARB_separate_shader_objects");
118 if (!GLAD_GL_ARB_vertex_attrib_binding)
119 unsupported_ext.push_back("ARB_vertex_attrib_binding");
120 if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev) 114 if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev)
121 unsupported_ext.push_back("ARB_vertex_type_10f_11f_11f_rev"); 115 unsupported_ext.push_back("ARB_vertex_type_10f_11f_11f_rev");
122 if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge) 116 if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge)
123 unsupported_ext.push_back("ARB_texture_mirror_clamp_to_edge"); 117 unsupported_ext.push_back("ARB_texture_mirror_clamp_to_edge");
124 if (!GLAD_GL_ARB_base_instance)
125 unsupported_ext.push_back("ARB_base_instance");
126 if (!GLAD_GL_ARB_texture_storage)
127 unsupported_ext.push_back("ARB_texture_storage");
128 if (!GLAD_GL_ARB_multi_bind) 118 if (!GLAD_GL_ARB_multi_bind)
129 unsupported_ext.push_back("ARB_multi_bind"); 119 unsupported_ext.push_back("ARB_multi_bind");
130 if (!GLAD_GL_ARB_copy_image)
131 unsupported_ext.push_back("ARB_copy_image");
132 120
133 // Extensions required to support some texture formats. 121 // Extensions required to support some texture formats.
134 if (!GLAD_GL_EXT_texture_compression_s3tc) 122 if (!GLAD_GL_EXT_texture_compression_s3tc)
135 unsupported_ext.push_back("EXT_texture_compression_s3tc"); 123 unsupported_ext.push_back("EXT_texture_compression_s3tc");
136 if (!GLAD_GL_ARB_texture_compression_rgtc) 124 if (!GLAD_GL_ARB_texture_compression_rgtc)
137 unsupported_ext.push_back("ARB_texture_compression_rgtc"); 125 unsupported_ext.push_back("ARB_texture_compression_rgtc");
138 if (!GLAD_GL_ARB_texture_compression_bptc)
139 unsupported_ext.push_back("ARB_texture_compression_bptc");
140 if (!GLAD_GL_ARB_depth_buffer_float) 126 if (!GLAD_GL_ARB_depth_buffer_float)
141 unsupported_ext.push_back("ARB_depth_buffer_float"); 127 unsupported_ext.push_back("ARB_depth_buffer_float");
142 128
@@ -157,7 +143,7 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) {
157 exit(1); 143 exit(1);
158 } 144 }
159 145
160 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); 146 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
161 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); 147 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
162 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); 148 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
163 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); 149 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);