diff options
Diffstat (limited to 'src')
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 { | |||
| 26 | constexpr u64 SINGLE_BYTE_MODULUS = 0x100; | 26 | constexpr u64 SINGLE_BYTE_MODULUS = 0x100; |
| 27 | constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000; | 27 | constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000; |
| 28 | 28 | ||
| 29 | constexpr 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 | |||
| 29 | struct NSOBuildHeader { | 34 | struct 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; | |||
| 71 | constexpr u32 UC_ARM64_REG_Q0 = 34; | 71 | constexpr u32 UC_ARM64_REG_Q0 = 34; |
| 72 | constexpr u32 FPCR_REGISTER = 66; | 72 | constexpr u32 FPCR_REGISTER = 66; |
| 73 | 73 | ||
| 74 | // TODO/WiP - Used while working on support for FPU | ||
| 75 | constexpr u32 TODO_DUMMY_REG_997 = 997; | ||
| 76 | constexpr 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 | ||
| 259 | static 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 | |||
| 275 | static 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 | */ | ||
| 443 | static 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. |
| 413 | static u8 ReadByte() { | 460 | static 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) { | |||
| 967 | static void Step() { | 1014 | static 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 | ||
| 1323 | void SendTrap(Kernel::Thread* thread, int trap) { | 1370 | void 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 | ||
| 344 | void ClearUnionContents() { | ||
| 345 | registered_cache_union = nullptr; | ||
| 346 | } | ||
| 347 | |||
| 344 | FileSys::RegisteredCache* GetSystemNANDContents() { | 348 | FileSys::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) | |||
| 49 | ResultVal<FileSys::VirtualDir> OpenSDMC(); | 49 | ResultVal<FileSys::VirtualDir> OpenSDMC(); |
| 50 | 50 | ||
| 51 | std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents(); | 51 | std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents(); |
| 52 | void ClearUnionContents(); | ||
| 52 | 53 | ||
| 53 | FileSys::RegisteredCache* GetSystemNANDContents(); | 54 | FileSys::RegisteredCache* GetSystemNANDContents(); |
| 54 | FileSys::RegisteredCache* GetUserNANDContents(); | 55 | FileSys::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 | ||
| 66 | ResultCode 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 | |||
| 66 | ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> ServiceManager::GetServicePort( | 77 | ResultVal<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 | ||
| 141 | void 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 | |||
| 168 | void 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 | |||
| 130 | SM::SM(std::shared_ptr<ServiceManager> service_manager) | 180 | SM::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: | |||
| 35 | private: | 35 | private: |
| 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); | |||
| 1134 | ASSERT_REG_POSITION(color_mask_common, 0x3E4); | 1143 | ASSERT_REG_POSITION(color_mask_common, 0x3E4); |
| 1135 | ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB); | 1144 | ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB); |
| 1136 | ASSERT_REG_POSITION(zeta, 0x3F8); | 1145 | ASSERT_REG_POSITION(zeta, 0x3F8); |
| 1146 | ASSERT_REG_POSITION(clear_flags, 0x43E); | ||
| 1137 | ASSERT_REG_POSITION(vertex_attrib_format, 0x458); | 1147 | ASSERT_REG_POSITION(vertex_attrib_format, 0x458); |
| 1138 | ASSERT_REG_POSITION(rt_control, 0x487); | 1148 | ASSERT_REG_POSITION(rt_control, 0x487); |
| 1139 | ASSERT_REG_POSITION(zeta_width, 0x48a); | 1149 | ASSERT_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 | ||
| 265 | enum class ControlCode : u64 { | 265 | enum 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 | ||
| 1123 | void RasterizerOpenGL::SyncScissorTest() { | 1150 | void 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); | |||
| 34 | constexpr u32 MAX_GEOMETRY_BUFFERS = 6; | 34 | constexpr u32 MAX_GEOMETRY_BUFFERS = 6; |
| 35 | constexpr u32 MAX_ATTRIBUTES = 0x100; // Size in vec4s, this value is untested | 35 | constexpr u32 MAX_ATTRIBUTES = 0x100; // Size in vec4s, this value is untested |
| 36 | 36 | ||
| 37 | static const char* INTERNAL_FLAG_NAMES[] = {"zero_flag", "sign_flag", "carry_flag", | ||
| 38 | "overflow_flag"}; | ||
| 39 | |||
| 40 | enum class InternalFlag : u64 { | ||
| 41 | ZeroFlag = 0, | ||
| 42 | SignFlag = 1, | ||
| 43 | CarryFlag = 2, | ||
| 44 | OverflowFlag = 3, | ||
| 45 | Amount | ||
| 46 | }; | ||
| 47 | |||
| 37 | class DecompileFail : public std::runtime_error { | 48 | class DecompileFail : public std::runtime_error { |
| 38 | public: | 49 | public: |
| 39 | using std::runtime_error::runtime_error; | 50 | using std::runtime_error::runtime_error; |
| @@ -84,7 +95,8 @@ struct Subroutine { | |||
| 84 | class ControlFlowAnalyzer { | 95 | class ControlFlowAnalyzer { |
| 85 | public: | 96 | public: |
| 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 | |||
| 99 | private: | 115 | private: |
| 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 | ||
| 260 | enum 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: | |||
| 939 | class GLSLGenerator { | 954 | class GLSLGenerator { |
| 940 | public: | 955 | public: |
| 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 | ||
| 960 | private: | 976 | private: |
| @@ -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: | |||
| 163 | struct ShaderEntries { | 163 | struct 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 | ||
| 168 | using ProgramResult = std::pair<std::string, ShaderEntries>; | 169 | using 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 | ||
| 237 | void 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 | ||
| 237 | void OpenGLState::ApplyViewport() const { | 259 | void 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 | ||
| 210 | private: | 211 | private: |
| 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 | ||
| 97 | QtSoftwareKeyboardDialog::~QtSoftwareKeyboardDialog() = default; | 97 | QtSoftwareKeyboardDialog::~QtSoftwareKeyboardDialog() = default; |
| 98 | 98 | ||
| 99 | void QtSoftwareKeyboardDialog::Submit() { | 99 | void 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 | ||
| 105 | void QtSoftwareKeyboardDialog::Reject() { | 105 | void QtSoftwareKeyboardDialog::reject() { |
| 106 | ok = false; | 106 | ok = false; |
| 107 | text.clear(); | 107 | text.clear(); |
| 108 | accept(); | 108 | QDialog::reject(); |
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | std::u16string QtSoftwareKeyboardDialog::GetText() const { | 111 | std::u16string QtSoftwareKeyboardDialog::GetText() const { |
| @@ -129,13 +129,13 @@ QtSoftwareKeyboard::~QtSoftwareKeyboard() = default; | |||
| 129 | 129 | ||
| 130 | void QtSoftwareKeyboard::RequestText(std::function<void(std::optional<std::u16string>)> out, | 130 | void 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 | ||
| 136 | void QtSoftwareKeyboard::SendTextCheckDialog(std::u16string error_message, | 136 | void 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 | ||
| 73 | public slots: | 73 | private: |
| 74 | void MainWindowFinishedText(std::optional<std::u16string> text); | 74 | void MainWindowFinishedText(std::optional<std::u16string> text); |
| 75 | void MainWindowFinishedCheckDialog(); | 75 | void MainWindowFinishedCheckDialog(); |
| 76 | 76 | ||
| 77 | private: | ||
| 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) { | |||
| 518 | QStringList GMainWindow::GetUnsupportedGLExtensions() { | 518 | QStringList 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. |
| 207 | use_gdbstub=false | 207 | use_gdbstub=false |
| 208 | gdbstub_port=24689 | 208 | gdbstub_port=24689 |
| 209 | # Determines whether or not yuzu will dump the ExeFS of all games it attempts to load while loading them | ||
| 210 | dump_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 |
| 210 | dump_nso=false | 212 | dump_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() { | |||
| 111 | bool EmuWindow_SDL2::SupportsRequiredGLExtensions() { | 111 | bool 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); |