diff options
Diffstat (limited to 'src')
41 files changed, 217 insertions, 501 deletions
diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp index 54556e0f9..caefc09f4 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp | |||
| @@ -34,7 +34,7 @@ std::optional<Callback> DynarmicCP15::CompileInternalOperation(bool two, unsigne | |||
| 34 | CoprocReg CRm, unsigned opc2) { | 34 | CoprocReg CRm, unsigned opc2) { |
| 35 | LOG_CRITICAL(Core_ARM, "CP15: cdp{} p15, {}, {}, {}, {}, {}", two ? "2" : "", opc1, CRd, CRn, | 35 | LOG_CRITICAL(Core_ARM, "CP15: cdp{} p15, {}, {}, {}, {}, {}", two ? "2" : "", opc1, CRd, CRn, |
| 36 | CRm, opc2); | 36 | CRm, opc2); |
| 37 | return {}; | 37 | return std::nullopt; |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | CallbackOrAccessOneWord DynarmicCP15::CompileSendOneWord(bool two, unsigned opc1, CoprocReg CRn, | 40 | CallbackOrAccessOneWord DynarmicCP15::CompileSendOneWord(bool two, unsigned opc1, CoprocReg CRn, |
| @@ -115,7 +115,7 @@ std::optional<Callback> DynarmicCP15::CompileLoadWords(bool two, bool long_trans | |||
| 115 | LOG_CRITICAL(Core_ARM, "CP15: mrrc{}{} p15, {}, [...]", two ? "2" : "", | 115 | LOG_CRITICAL(Core_ARM, "CP15: mrrc{}{} p15, {}, [...]", two ? "2" : "", |
| 116 | long_transfer ? "l" : "", CRd); | 116 | long_transfer ? "l" : "", CRd); |
| 117 | } | 117 | } |
| 118 | return {}; | 118 | return std::nullopt; |
| 119 | } | 119 | } |
| 120 | 120 | ||
| 121 | std::optional<Callback> DynarmicCP15::CompileStoreWords(bool two, bool long_transfer, CoprocReg CRd, | 121 | std::optional<Callback> DynarmicCP15::CompileStoreWords(bool two, bool long_transfer, CoprocReg CRd, |
| @@ -127,7 +127,7 @@ std::optional<Callback> DynarmicCP15::CompileStoreWords(bool two, bool long_tran | |||
| 127 | LOG_CRITICAL(Core_ARM, "CP15: mrrc{}{} p15, {}, [...]", two ? "2" : "", | 127 | LOG_CRITICAL(Core_ARM, "CP15: mrrc{}{} p15, {}, [...]", two ? "2" : "", |
| 128 | long_transfer ? "l" : "", CRd); | 128 | long_transfer ? "l" : "", CRd); |
| 129 | } | 129 | } |
| 130 | return {}; | 130 | return std::nullopt; |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | } // namespace Core | 133 | } // namespace Core |
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp index 426fb6bb5..76af47ff9 100644 --- a/src/core/file_sys/content_archive.cpp +++ b/src/core/file_sys/content_archive.cpp | |||
| @@ -323,7 +323,7 @@ bool NCA::ReadRomFSSection(const NCASectionHeader& section, const NCASectionTabl | |||
| 323 | subsection_buckets.back().entries.push_back({section.bktr.relocation.offset, {0}, ctr_low}); | 323 | subsection_buckets.back().entries.push_back({section.bktr.relocation.offset, {0}, ctr_low}); |
| 324 | subsection_buckets.back().entries.push_back({size, {0}, 0}); | 324 | subsection_buckets.back().entries.push_back({size, {0}, 0}); |
| 325 | 325 | ||
| 326 | std::optional<Core::Crypto::Key128> key = {}; | 326 | std::optional<Core::Crypto::Key128> key; |
| 327 | if (encrypted) { | 327 | if (encrypted) { |
| 328 | if (has_rights_id) { | 328 | if (has_rights_id) { |
| 329 | status = Loader::ResultStatus::Success; | 329 | status = Loader::ResultStatus::Success; |
| @@ -442,18 +442,18 @@ std::optional<Core::Crypto::Key128> NCA::GetTitlekey() { | |||
| 442 | memcpy(rights_id.data(), header.rights_id.data(), 16); | 442 | memcpy(rights_id.data(), header.rights_id.data(), 16); |
| 443 | if (rights_id == u128{}) { | 443 | if (rights_id == u128{}) { |
| 444 | status = Loader::ResultStatus::ErrorInvalidRightsID; | 444 | status = Loader::ResultStatus::ErrorInvalidRightsID; |
| 445 | return {}; | 445 | return std::nullopt; |
| 446 | } | 446 | } |
| 447 | 447 | ||
| 448 | auto titlekey = keys.GetKey(Core::Crypto::S128KeyType::Titlekey, rights_id[1], rights_id[0]); | 448 | auto titlekey = keys.GetKey(Core::Crypto::S128KeyType::Titlekey, rights_id[1], rights_id[0]); |
| 449 | if (titlekey == Core::Crypto::Key128{}) { | 449 | if (titlekey == Core::Crypto::Key128{}) { |
| 450 | status = Loader::ResultStatus::ErrorMissingTitlekey; | 450 | status = Loader::ResultStatus::ErrorMissingTitlekey; |
| 451 | return {}; | 451 | return std::nullopt; |
| 452 | } | 452 | } |
| 453 | 453 | ||
| 454 | if (!keys.HasKey(Core::Crypto::S128KeyType::Titlekek, master_key_id)) { | 454 | if (!keys.HasKey(Core::Crypto::S128KeyType::Titlekek, master_key_id)) { |
| 455 | status = Loader::ResultStatus::ErrorMissingTitlekek; | 455 | status = Loader::ResultStatus::ErrorMissingTitlekek; |
| 456 | return {}; | 456 | return std::nullopt; |
| 457 | } | 457 | } |
| 458 | 458 | ||
| 459 | Core::Crypto::AESCipher<Core::Crypto::Key128> cipher( | 459 | Core::Crypto::AESCipher<Core::Crypto::Key128> cipher( |
| @@ -477,7 +477,7 @@ VirtualFile NCA::Decrypt(const NCASectionHeader& s_header, VirtualFile in, u64 s | |||
| 477 | case NCASectionCryptoType::BKTR: | 477 | case NCASectionCryptoType::BKTR: |
| 478 | LOG_TRACE(Crypto, "called with mode=CTR, starting_offset={:016X}", starting_offset); | 478 | LOG_TRACE(Crypto, "called with mode=CTR, starting_offset={:016X}", starting_offset); |
| 479 | { | 479 | { |
| 480 | std::optional<Core::Crypto::Key128> key = {}; | 480 | std::optional<Core::Crypto::Key128> key; |
| 481 | if (has_rights_id) { | 481 | if (has_rights_id) { |
| 482 | status = Loader::ResultStatus::Success; | 482 | status = Loader::ResultStatus::Success; |
| 483 | key = GetTitlekey(); | 483 | key = GetTitlekey(); |
diff --git a/src/core/file_sys/ips_layer.cpp b/src/core/file_sys/ips_layer.cpp index a08a70efd..dd779310f 100644 --- a/src/core/file_sys/ips_layer.cpp +++ b/src/core/file_sys/ips_layer.cpp | |||
| @@ -245,9 +245,11 @@ void IPSwitchCompiler::Parse() { | |||
| 245 | 245 | ||
| 246 | // Read rest of patch | 246 | // Read rest of patch |
| 247 | while (true) { | 247 | while (true) { |
| 248 | if (i + 1 >= lines.size()) | 248 | if (i + 1 >= lines.size()) { |
| 249 | break; | 249 | break; |
| 250 | const auto patch_line = lines[++i]; | 250 | } |
| 251 | |||
| 252 | const auto& patch_line = lines[++i]; | ||
| 251 | 253 | ||
| 252 | // Start of new patch | 254 | // Start of new patch |
| 253 | if (StartsWith(patch_line, "@enabled") || StartsWith(patch_line, "@disabled")) { | 255 | if (StartsWith(patch_line, "@enabled") || StartsWith(patch_line, "@disabled")) { |
diff --git a/src/core/file_sys/submission_package.cpp b/src/core/file_sys/submission_package.cpp index b9ce93b7c..aab957bf2 100644 --- a/src/core/file_sys/submission_package.cpp +++ b/src/core/file_sys/submission_package.cpp | |||
| @@ -267,9 +267,9 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) { | |||
| 267 | } | 267 | } |
| 268 | 268 | ||
| 269 | const CNMT cnmt(inner_file); | 269 | const CNMT cnmt(inner_file); |
| 270 | auto& ncas_title = ncas[cnmt.GetTitleID()]; | ||
| 271 | 270 | ||
| 272 | ncas_title[{cnmt.GetType(), ContentRecordType::Meta}] = nca; | 271 | ncas[cnmt.GetTitleID()][{cnmt.GetType(), ContentRecordType::Meta}] = nca; |
| 272 | |||
| 273 | for (const auto& rec : cnmt.GetContentRecords()) { | 273 | for (const auto& rec : cnmt.GetContentRecords()) { |
| 274 | const auto id_string = Common::HexToString(rec.nca_id, false); | 274 | const auto id_string = Common::HexToString(rec.nca_id, false); |
| 275 | auto next_file = pfs->GetFile(fmt::format("{}.nca", id_string)); | 275 | auto next_file = pfs->GetFile(fmt::format("{}.nca", id_string)); |
| @@ -287,12 +287,12 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) { | |||
| 287 | 287 | ||
| 288 | auto next_nca = std::make_shared<NCA>(std::move(next_file), nullptr, 0); | 288 | auto next_nca = std::make_shared<NCA>(std::move(next_file), nullptr, 0); |
| 289 | if (next_nca->GetType() == NCAContentType::Program) { | 289 | if (next_nca->GetType() == NCAContentType::Program) { |
| 290 | program_status[cnmt.GetTitleID()] = next_nca->GetStatus(); | 290 | program_status[next_nca->GetTitleId()] = next_nca->GetStatus(); |
| 291 | } | 291 | } |
| 292 | if (next_nca->GetStatus() == Loader::ResultStatus::Success || | 292 | if (next_nca->GetStatus() == Loader::ResultStatus::Success || |
| 293 | (next_nca->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS && | 293 | (next_nca->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS && |
| 294 | (cnmt.GetTitleID() & 0x800) != 0)) { | 294 | (next_nca->GetTitleId() & 0x800) != 0)) { |
| 295 | ncas_title[{cnmt.GetType(), rec.type}] = std::move(next_nca); | 295 | ncas[next_nca->GetTitleId()][{cnmt.GetType(), rec.type}] = std::move(next_nca); |
| 296 | } | 296 | } |
| 297 | } | 297 | } |
| 298 | 298 | ||
diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp index a4c3f67c4..b2f026b6d 100644 --- a/src/core/file_sys/vfs.cpp +++ b/src/core/file_sys/vfs.cpp | |||
| @@ -169,11 +169,12 @@ VfsDirectory::~VfsDirectory() = default; | |||
| 169 | 169 | ||
| 170 | std::optional<u8> VfsFile::ReadByte(std::size_t offset) const { | 170 | std::optional<u8> VfsFile::ReadByte(std::size_t offset) const { |
| 171 | u8 out{}; | 171 | u8 out{}; |
| 172 | std::size_t size = Read(&out, 1, offset); | 172 | const std::size_t size = Read(&out, sizeof(u8), offset); |
| 173 | if (size == 1) | 173 | if (size == 1) { |
| 174 | return out; | 174 | return out; |
| 175 | } | ||
| 175 | 176 | ||
| 176 | return {}; | 177 | return std::nullopt; |
| 177 | } | 178 | } |
| 178 | 179 | ||
| 179 | std::vector<u8> VfsFile::ReadBytes(std::size_t size, std::size_t offset) const { | 180 | std::vector<u8> VfsFile::ReadBytes(std::size_t size, std::size_t offset) const { |
diff --git a/src/core/file_sys/vfs_offset.cpp b/src/core/file_sys/vfs_offset.cpp index c96f88488..7714d3de5 100644 --- a/src/core/file_sys/vfs_offset.cpp +++ b/src/core/file_sys/vfs_offset.cpp | |||
| @@ -58,10 +58,11 @@ std::size_t OffsetVfsFile::Write(const u8* data, std::size_t length, std::size_t | |||
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | std::optional<u8> OffsetVfsFile::ReadByte(std::size_t r_offset) const { | 60 | std::optional<u8> OffsetVfsFile::ReadByte(std::size_t r_offset) const { |
| 61 | if (r_offset < size) | 61 | if (r_offset >= size) { |
| 62 | return file->ReadByte(offset + r_offset); | 62 | return std::nullopt; |
| 63 | } | ||
| 63 | 64 | ||
| 64 | return {}; | 65 | return file->ReadByte(offset + r_offset); |
| 65 | } | 66 | } |
| 66 | 67 | ||
| 67 | std::vector<u8> OffsetVfsFile::ReadBytes(std::size_t r_size, std::size_t r_offset) const { | 68 | std::vector<u8> OffsetVfsFile::ReadBytes(std::size_t r_size, std::size_t r_offset) const { |
diff --git a/src/core/file_sys/vfs_static.h b/src/core/file_sys/vfs_static.h index 9f5a90b1b..8b27c30fa 100644 --- a/src/core/file_sys/vfs_static.h +++ b/src/core/file_sys/vfs_static.h | |||
| @@ -54,9 +54,11 @@ public: | |||
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | std::optional<u8> ReadByte(std::size_t offset) const override { | 56 | std::optional<u8> ReadByte(std::size_t offset) const override { |
| 57 | if (offset < size) | 57 | if (offset >= size) { |
| 58 | return value; | 58 | return std::nullopt; |
| 59 | return {}; | 59 | } |
| 60 | |||
| 61 | return value; | ||
| 60 | } | 62 | } |
| 61 | 63 | ||
| 62 | std::vector<u8> ReadBytes(std::size_t length, std::size_t offset) const override { | 64 | std::vector<u8> ReadBytes(std::size_t length, std::size_t offset) const override { |
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index b65d59373..620386cd1 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp | |||
| @@ -593,6 +593,14 @@ Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const { | |||
| 593 | return hold_type; | 593 | return hold_type; |
| 594 | } | 594 | } |
| 595 | 595 | ||
| 596 | void Controller_NPad::SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode) { | ||
| 597 | handheld_activation_mode = activation_mode; | ||
| 598 | } | ||
| 599 | |||
| 600 | Controller_NPad::NpadHandheldActivationMode Controller_NPad::GetNpadHandheldActivationMode() const { | ||
| 601 | return handheld_activation_mode; | ||
| 602 | } | ||
| 603 | |||
| 596 | void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) { | 604 | void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) { |
| 597 | const std::size_t npad_index = NPadIdToIndex(npad_id); | 605 | const std::size_t npad_index = NPadIdToIndex(npad_id); |
| 598 | ASSERT(npad_index < shared_memory_entries.size()); | 606 | ASSERT(npad_index < shared_memory_entries.size()); |
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 78e7c320b..654d97c3f 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h | |||
| @@ -74,6 +74,12 @@ public: | |||
| 74 | Single = 1, | 74 | Single = 1, |
| 75 | }; | 75 | }; |
| 76 | 76 | ||
| 77 | enum class NpadHandheldActivationMode : u64 { | ||
| 78 | Dual = 0, | ||
| 79 | Single = 1, | ||
| 80 | None = 2, | ||
| 81 | }; | ||
| 82 | |||
| 77 | enum class NPadControllerType { | 83 | enum class NPadControllerType { |
| 78 | None, | 84 | None, |
| 79 | ProController, | 85 | ProController, |
| @@ -110,6 +116,9 @@ public: | |||
| 110 | void SetHoldType(NpadHoldType joy_hold_type); | 116 | void SetHoldType(NpadHoldType joy_hold_type); |
| 111 | NpadHoldType GetHoldType() const; | 117 | NpadHoldType GetHoldType() const; |
| 112 | 118 | ||
| 119 | void SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode); | ||
| 120 | NpadHandheldActivationMode GetNpadHandheldActivationMode() const; | ||
| 121 | |||
| 113 | void SetNpadMode(u32 npad_id, NPadAssignments assignment_mode); | 122 | void SetNpadMode(u32 npad_id, NPadAssignments assignment_mode); |
| 114 | 123 | ||
| 115 | void VibrateController(const std::vector<u32>& controller_ids, | 124 | void VibrateController(const std::vector<u32>& controller_ids, |
| @@ -369,6 +378,7 @@ private: | |||
| 369 | MotionArray motions; | 378 | MotionArray motions; |
| 370 | std::vector<u32> supported_npad_id_types{}; | 379 | std::vector<u32> supported_npad_id_types{}; |
| 371 | NpadHoldType hold_type{NpadHoldType::Vertical}; | 380 | NpadHoldType hold_type{NpadHoldType::Vertical}; |
| 381 | NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual}; | ||
| 372 | // Each controller should have their own styleset changed event | 382 | // Each controller should have their own styleset changed event |
| 373 | std::array<Kernel::EventPair, 10> styleset_changed_events; | 383 | std::array<Kernel::EventPair, 10> styleset_changed_events; |
| 374 | Vibration last_processed_vibration{}; | 384 | Vibration last_processed_vibration{}; |
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 302a25540..395e83b3f 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -40,7 +40,7 @@ namespace Service::HID { | |||
| 40 | // Updating period for each HID device. | 40 | // Updating period for each HID device. |
| 41 | // HID is polled every 15ms, this value was derived from | 41 | // HID is polled every 15ms, this value was derived from |
| 42 | // https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering#joy-con-status-data-packet | 42 | // https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering#joy-con-status-data-packet |
| 43 | constexpr auto pad_update_ns = std::chrono::nanoseconds{15 * 1000 * 1000}; // (15ms, 66.6Hz) | 43 | constexpr auto pad_update_ns = std::chrono::nanoseconds{1000 * 1000}; // (1ms, 1000Hz) |
| 44 | constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; | 44 | constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; |
| 45 | 45 | ||
| 46 | IAppletResource::IAppletResource(Core::System& system) | 46 | IAppletResource::IAppletResource(Core::System& system) |
| @@ -739,8 +739,11 @@ void Hid::SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { | |||
| 739 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 739 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 740 | const auto mode{rp.Pop<u64>()}; | 740 | const auto mode{rp.Pop<u64>()}; |
| 741 | 741 | ||
| 742 | LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, mode={}", | 742 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, mode={}", applet_resource_user_id, |
| 743 | applet_resource_user_id, mode); | 743 | mode); |
| 744 | |||
| 745 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | ||
| 746 | .SetNpadHandheldActivationMode(Controller_NPad::NpadHandheldActivationMode{mode}); | ||
| 744 | 747 | ||
| 745 | IPC::ResponseBuilder rb{ctx, 2}; | 748 | IPC::ResponseBuilder rb{ctx, 2}; |
| 746 | rb.Push(RESULT_SUCCESS); | 749 | rb.Push(RESULT_SUCCESS); |
| @@ -750,11 +753,13 @@ void Hid::GetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { | |||
| 750 | IPC::RequestParser rp{ctx}; | 753 | IPC::RequestParser rp{ctx}; |
| 751 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 754 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 752 | 755 | ||
| 753 | LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", | 756 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); |
| 754 | applet_resource_user_id); | ||
| 755 | 757 | ||
| 756 | IPC::ResponseBuilder rb{ctx, 2}; | 758 | IPC::ResponseBuilder rb{ctx, 4}; |
| 757 | rb.Push(RESULT_SUCCESS); | 759 | rb.Push(RESULT_SUCCESS); |
| 760 | rb.Push<u64>( | ||
| 761 | static_cast<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad) | ||
| 762 | .GetNpadHandheldActivationMode())); | ||
| 758 | } | 763 | } |
| 759 | 764 | ||
| 760 | void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) { | 765 | void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) { |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index d4ba88147..39bd2a45b 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp | |||
| @@ -265,7 +265,7 @@ std::optional<nvhost_as_gpu::BufferMap> nvhost_as_gpu::FindBufferMap(GPUVAddr gp | |||
| 265 | } | 265 | } |
| 266 | } | 266 | } |
| 267 | 267 | ||
| 268 | return {}; | 268 | return std::nullopt; |
| 269 | } | 269 | } |
| 270 | 270 | ||
| 271 | void nvhost_as_gpu::AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, | 271 | void nvhost_as_gpu::AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, |
| @@ -286,7 +286,7 @@ std::optional<std::size_t> nvhost_as_gpu::RemoveBufferMap(GPUVAddr gpu_addr) { | |||
| 286 | return size; | 286 | return size; |
| 287 | } | 287 | } |
| 288 | 288 | ||
| 289 | return {}; | 289 | return std::nullopt; |
| 290 | } | 290 | } |
| 291 | 291 | ||
| 292 | } // namespace Service::Nvidia::Devices | 292 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index d7a1bef91..7706a5590 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h | |||
| @@ -54,7 +54,7 @@ struct EventInterface { | |||
| 54 | } | 54 | } |
| 55 | mask = mask >> 1; | 55 | mask = mask >> 1; |
| 56 | } | 56 | } |
| 57 | return {}; | 57 | return std::nullopt; |
| 58 | } | 58 | } |
| 59 | void SetEventStatus(const u32 event_id, EventState new_status) { | 59 | void SetEventStatus(const u32 event_id, EventState new_status) { |
| 60 | EventState old_status = status[event_id]; | 60 | EventState old_status = status[event_id]; |
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index f644a460d..c64673dba 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp | |||
| @@ -114,7 +114,7 @@ std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) { | |||
| 114 | [&](const VI::Display& display) { return display.GetName() == name; }); | 114 | [&](const VI::Display& display) { return display.GetName() == name; }); |
| 115 | 115 | ||
| 116 | if (itr == displays.end()) { | 116 | if (itr == displays.end()) { |
| 117 | return {}; | 117 | return std::nullopt; |
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | return itr->GetID(); | 120 | return itr->GetID(); |
| @@ -124,7 +124,7 @@ std::optional<u64> NVFlinger::CreateLayer(u64 display_id) { | |||
| 124 | auto* const display = FindDisplay(display_id); | 124 | auto* const display = FindDisplay(display_id); |
| 125 | 125 | ||
| 126 | if (display == nullptr) { | 126 | if (display == nullptr) { |
| 127 | return {}; | 127 | return std::nullopt; |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | const u64 layer_id = next_layer_id++; | 130 | const u64 layer_id = next_layer_id++; |
| @@ -144,7 +144,7 @@ std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) co | |||
| 144 | const auto* const layer = FindLayer(display_id, layer_id); | 144 | const auto* const layer = FindLayer(display_id, layer_id); |
| 145 | 145 | ||
| 146 | if (layer == nullptr) { | 146 | if (layer == nullptr) { |
| 147 | return {}; | 147 | return std::nullopt; |
| 148 | } | 148 | } |
| 149 | 149 | ||
| 150 | return layer->GetBufferQueue().GetId(); | 150 | return layer->GetBufferQueue().GetId(); |
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp index 7b9dd42d8..a74be9370 100644 --- a/src/core/hle/service/sockets/bsd.cpp +++ b/src/core/hle/service/sockets/bsd.cpp | |||
| @@ -497,7 +497,7 @@ std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::vector<u | |||
| 497 | return {0, Errno::SUCCESS}; | 497 | return {0, Errno::SUCCESS}; |
| 498 | } | 498 | } |
| 499 | 499 | ||
| 500 | std::optional<FileDescriptor>& descriptor = file_descriptors[pollfd.fd]; | 500 | const std::optional<FileDescriptor>& descriptor = file_descriptors[pollfd.fd]; |
| 501 | if (!descriptor) { | 501 | if (!descriptor) { |
| 502 | LOG_ERROR(Service, "File descriptor handle={} is not allocated", pollfd.fd); | 502 | LOG_ERROR(Service, "File descriptor handle={} is not allocated", pollfd.fd); |
| 503 | pollfd.revents = POLL_NVAL; | 503 | pollfd.revents = POLL_NVAL; |
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 60373cc5f..1e70f6e11 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp | |||
| @@ -76,16 +76,16 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, Core::S | |||
| 76 | bool should_pass_arguments, bool load_into_process, | 76 | bool should_pass_arguments, bool load_into_process, |
| 77 | std::optional<FileSys::PatchManager> pm) { | 77 | std::optional<FileSys::PatchManager> pm) { |
| 78 | if (file.GetSize() < sizeof(NSOHeader)) { | 78 | if (file.GetSize() < sizeof(NSOHeader)) { |
| 79 | return {}; | 79 | return std::nullopt; |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | NSOHeader nso_header{}; | 82 | NSOHeader nso_header{}; |
| 83 | if (sizeof(NSOHeader) != file.ReadObject(&nso_header)) { | 83 | if (sizeof(NSOHeader) != file.ReadObject(&nso_header)) { |
| 84 | return {}; | 84 | return std::nullopt; |
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | if (nso_header.magic != Common::MakeMagic('N', 'S', 'O', '0')) { | 87 | if (nso_header.magic != Common::MakeMagic('N', 'S', 'O', '0')) { |
| 88 | return {}; | 88 | return std::nullopt; |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | // Build program image | 91 | // Build program image |
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 86d17c6cb..c3f4829d7 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp | |||
| @@ -567,7 +567,7 @@ struct Memory::Impl { | |||
| 567 | * @param page_table The page table to use to perform the mapping. | 567 | * @param page_table The page table to use to perform the mapping. |
| 568 | * @param base The base address to begin mapping at. | 568 | * @param base The base address to begin mapping at. |
| 569 | * @param size The total size of the range in bytes. | 569 | * @param size The total size of the range in bytes. |
| 570 | * @param memory The memory to map. | 570 | * @param target The target address to begin mapping from. |
| 571 | * @param type The page type to map the memory as. | 571 | * @param type The page type to map the memory as. |
| 572 | */ | 572 | */ |
| 573 | void MapPages(Common::PageTable& page_table, VAddr base, u64 size, PAddr target, | 573 | void MapPages(Common::PageTable& page_table, VAddr base, u64 size, PAddr target, |
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 33854445f..57ebc785f 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -597,7 +597,7 @@ std::optional<u64> Maxwell3D::GetQueryResult() { | |||
| 597 | // Deferred. | 597 | // Deferred. |
| 598 | rasterizer->Query(regs.query.QueryAddress(), VideoCore::QueryType::SamplesPassed, | 598 | rasterizer->Query(regs.query.QueryAddress(), VideoCore::QueryType::SamplesPassed, |
| 599 | system.GPU().GetTicks()); | 599 | system.GPU().GetTicks()); |
| 600 | return {}; | 600 | return std::nullopt; |
| 601 | default: | 601 | default: |
| 602 | LOG_DEBUG(HW_GPU, "Unimplemented query select type {}", | 602 | LOG_DEBUG(HW_GPU, "Unimplemented query select type {}", |
| 603 | static_cast<u32>(regs.query.query_get.select.Value())); | 603 | static_cast<u32>(regs.query.query_get.select.Value())); |
diff --git a/src/video_core/macro/macro.cpp b/src/video_core/macro/macro.cpp index a50e7b4e0..cd21a2112 100644 --- a/src/video_core/macro/macro.cpp +++ b/src/video_core/macro/macro.cpp | |||
| @@ -36,7 +36,7 @@ void MacroEngine::Execute(Engines::Maxwell3D& maxwell3d, u32 method, | |||
| 36 | } | 36 | } |
| 37 | } else { | 37 | } else { |
| 38 | // Macro not compiled, check if it's uploaded and if so, compile it | 38 | // Macro not compiled, check if it's uploaded and if so, compile it |
| 39 | std::optional<u32> mid_method = std::nullopt; | 39 | std::optional<u32> mid_method; |
| 40 | const auto macro_code = uploaded_macro_code.find(method); | 40 | const auto macro_code = uploaded_macro_code.find(method); |
| 41 | if (macro_code == uploaded_macro_code.end()) { | 41 | if (macro_code == uploaded_macro_code.end()) { |
| 42 | for (const auto& [method_base, code] : uploaded_macro_code) { | 42 | for (const auto& [method_base, code] : uploaded_macro_code) { |
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp index 16b2aaa27..02cf53d15 100644 --- a/src/video_core/memory_manager.cpp +++ b/src/video_core/memory_manager.cpp | |||
| @@ -58,7 +58,7 @@ void MemoryManager::Unmap(GPUVAddr gpu_addr, std::size_t size) { | |||
| 58 | std::optional<GPUVAddr> MemoryManager::AllocateFixed(GPUVAddr gpu_addr, std::size_t size) { | 58 | std::optional<GPUVAddr> MemoryManager::AllocateFixed(GPUVAddr gpu_addr, std::size_t size) { |
| 59 | for (u64 offset{}; offset < size; offset += page_size) { | 59 | for (u64 offset{}; offset < size; offset += page_size) { |
| 60 | if (!GetPageEntry(gpu_addr + offset).IsUnmapped()) { | 60 | if (!GetPageEntry(gpu_addr + offset).IsUnmapped()) { |
| 61 | return {}; | 61 | return std::nullopt; |
| 62 | } | 62 | } |
| 63 | } | 63 | } |
| 64 | 64 | ||
| @@ -135,13 +135,13 @@ std::optional<GPUVAddr> MemoryManager::FindFreeRange(std::size_t size, std::size | |||
| 135 | } | 135 | } |
| 136 | } | 136 | } |
| 137 | 137 | ||
| 138 | return {}; | 138 | return std::nullopt; |
| 139 | } | 139 | } |
| 140 | 140 | ||
| 141 | std::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr gpu_addr) const { | 141 | std::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr gpu_addr) const { |
| 142 | const auto page_entry{GetPageEntry(gpu_addr)}; | 142 | const auto page_entry{GetPageEntry(gpu_addr)}; |
| 143 | if (!page_entry.IsValid()) { | 143 | if (!page_entry.IsValid()) { |
| 144 | return {}; | 144 | return std::nullopt; |
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | return page_entry.ToAddress() + (gpu_addr & page_mask); | 147 | return page_entry.ToAddress() + (gpu_addr & page_mask); |
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h index 649074acd..5c650808b 100644 --- a/src/video_core/renderer_base.h +++ b/src/video_core/renderer_base.h | |||
| @@ -46,11 +46,6 @@ public: | |||
| 46 | /// Finalize rendering the guest frame and draw into the presentation texture | 46 | /// Finalize rendering the guest frame and draw into the presentation texture |
| 47 | virtual void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) = 0; | 47 | virtual void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) = 0; |
| 48 | 48 | ||
| 49 | /// Draws the latest frame to the window waiting timeout_ms for a frame to arrive (Renderer | ||
| 50 | /// specific implementation) | ||
| 51 | /// Returns true if a frame was drawn | ||
| 52 | virtual bool TryPresent(int timeout_ms) = 0; | ||
| 53 | |||
| 54 | // Getter/setter functions: | 49 | // Getter/setter functions: |
| 55 | // ------------------------ | 50 | // ------------------------ |
| 56 | 51 | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index ce3a65122..bbb8fb095 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -813,7 +813,7 @@ private: | |||
| 813 | const u8 location = static_cast<u8>(static_cast<u32>(index) * 4 + element); | 813 | const u8 location = static_cast<u8>(static_cast<u32>(index) * 4 + element); |
| 814 | const auto it = transform_feedback.find(location); | 814 | const auto it = transform_feedback.find(location); |
| 815 | if (it == transform_feedback.end()) { | 815 | if (it == transform_feedback.end()) { |
| 816 | return {}; | 816 | return std::nullopt; |
| 817 | } | 817 | } |
| 818 | return it->second.components; | 818 | return it->second.components; |
| 819 | } | 819 | } |
| @@ -1295,21 +1295,21 @@ private: | |||
| 1295 | switch (element) { | 1295 | switch (element) { |
| 1296 | case 0: | 1296 | case 0: |
| 1297 | UNIMPLEMENTED(); | 1297 | UNIMPLEMENTED(); |
| 1298 | return {}; | 1298 | return std::nullopt; |
| 1299 | case 1: | 1299 | case 1: |
| 1300 | if (stage == ShaderType::Vertex && !device.HasVertexViewportLayer()) { | 1300 | if (stage == ShaderType::Vertex && !device.HasVertexViewportLayer()) { |
| 1301 | return {}; | 1301 | return std::nullopt; |
| 1302 | } | 1302 | } |
| 1303 | return {{"gl_Layer", Type::Int}}; | 1303 | return {{"gl_Layer", Type::Int}}; |
| 1304 | case 2: | 1304 | case 2: |
| 1305 | if (stage == ShaderType::Vertex && !device.HasVertexViewportLayer()) { | 1305 | if (stage == ShaderType::Vertex && !device.HasVertexViewportLayer()) { |
| 1306 | return {}; | 1306 | return std::nullopt; |
| 1307 | } | 1307 | } |
| 1308 | return {{"gl_ViewportIndex", Type::Int}}; | 1308 | return {{"gl_ViewportIndex", Type::Int}}; |
| 1309 | case 3: | 1309 | case 3: |
| 1310 | return {{"gl_PointSize", Type::Float}}; | 1310 | return {{"gl_PointSize", Type::Float}}; |
| 1311 | } | 1311 | } |
| 1312 | return {}; | 1312 | return std::nullopt; |
| 1313 | case Attribute::Index::FrontColor: | 1313 | case Attribute::Index::FrontColor: |
| 1314 | return {{"gl_FrontColor"s + GetSwizzle(element), Type::Float}}; | 1314 | return {{"gl_FrontColor"s + GetSwizzle(element), Type::Float}}; |
| 1315 | case Attribute::Index::FrontSecondaryColor: | 1315 | case Attribute::Index::FrontSecondaryColor: |
| @@ -1332,7 +1332,7 @@ private: | |||
| 1332 | Type::Float}}; | 1332 | Type::Float}}; |
| 1333 | } | 1333 | } |
| 1334 | UNIMPLEMENTED_MSG("Unhandled output attribute: {}", static_cast<u32>(attribute)); | 1334 | UNIMPLEMENTED_MSG("Unhandled output attribute: {}", static_cast<u32>(attribute)); |
| 1335 | return {}; | 1335 | return std::nullopt; |
| 1336 | } | 1336 | } |
| 1337 | } | 1337 | } |
| 1338 | 1338 | ||
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index a4c5b8f74..2ccca1993 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -32,20 +32,6 @@ namespace OpenGL { | |||
| 32 | 32 | ||
| 33 | namespace { | 33 | namespace { |
| 34 | 34 | ||
| 35 | constexpr std::size_t SWAP_CHAIN_SIZE = 3; | ||
| 36 | |||
| 37 | struct Frame { | ||
| 38 | u32 width{}; /// Width of the frame (to detect resize) | ||
| 39 | u32 height{}; /// Height of the frame | ||
| 40 | bool color_reloaded{}; /// Texture attachment was recreated (ie: resized) | ||
| 41 | OpenGL::OGLRenderbuffer color{}; /// Buffer shared between the render/present FBO | ||
| 42 | OpenGL::OGLFramebuffer render{}; /// FBO created on the render thread | ||
| 43 | OpenGL::OGLFramebuffer present{}; /// FBO created on the present thread | ||
| 44 | GLsync render_fence{}; /// Fence created on the render thread | ||
| 45 | GLsync present_fence{}; /// Fence created on the presentation thread | ||
| 46 | bool is_srgb{}; /// Framebuffer is sRGB or RGB | ||
| 47 | }; | ||
| 48 | |||
| 49 | constexpr GLint PositionLocation = 0; | 35 | constexpr GLint PositionLocation = 0; |
| 50 | constexpr GLint TexCoordLocation = 1; | 36 | constexpr GLint TexCoordLocation = 1; |
| 51 | constexpr GLint ModelViewMatrixLocation = 0; | 37 | constexpr GLint ModelViewMatrixLocation = 0; |
| @@ -58,24 +44,6 @@ struct ScreenRectVertex { | |||
| 58 | std::array<GLfloat, 2> tex_coord; | 44 | std::array<GLfloat, 2> tex_coord; |
| 59 | }; | 45 | }; |
| 60 | 46 | ||
| 61 | /// Returns true if any debug tool is attached | ||
| 62 | bool HasDebugTool() { | ||
| 63 | const bool nsight = std::getenv("NVTX_INJECTION64_PATH") || std::getenv("NSIGHT_LAUNCHED"); | ||
| 64 | if (nsight) { | ||
| 65 | return true; | ||
| 66 | } | ||
| 67 | |||
| 68 | GLint num_extensions; | ||
| 69 | glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions); | ||
| 70 | for (GLuint index = 0; index < static_cast<GLuint>(num_extensions); ++index) { | ||
| 71 | const auto name = reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, index)); | ||
| 72 | if (!std::strcmp(name, "GL_EXT_debug_tool")) { | ||
| 73 | return true; | ||
| 74 | } | ||
| 75 | } | ||
| 76 | return false; | ||
| 77 | } | ||
| 78 | |||
| 79 | /** | 47 | /** |
| 80 | * Defines a 1:1 pixel ortographic projection matrix with (0,0) on the top-left | 48 | * Defines a 1:1 pixel ortographic projection matrix with (0,0) on the top-left |
| 81 | * corner and (width, height) on the lower-bottom. | 49 | * corner and (width, height) on the lower-bottom. |
| @@ -159,135 +127,15 @@ void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum severit | |||
| 159 | 127 | ||
| 160 | } // Anonymous namespace | 128 | } // Anonymous namespace |
| 161 | 129 | ||
| 162 | /** | ||
| 163 | * For smooth Vsync rendering, we want to always present the latest frame that the core generates, | ||
| 164 | * but also make sure that rendering happens at the pace that the frontend dictates. This is a | ||
| 165 | * helper class that the renderer uses to sync frames between the render thread and the presentation | ||
| 166 | * thread | ||
| 167 | */ | ||
| 168 | class FrameMailbox { | ||
| 169 | public: | ||
| 170 | std::mutex swap_chain_lock; | ||
| 171 | std::condition_variable present_cv; | ||
| 172 | std::array<Frame, SWAP_CHAIN_SIZE> swap_chain{}; | ||
| 173 | std::queue<Frame*> free_queue; | ||
| 174 | std::deque<Frame*> present_queue; | ||
| 175 | Frame* previous_frame{}; | ||
| 176 | |||
| 177 | FrameMailbox() { | ||
| 178 | for (auto& frame : swap_chain) { | ||
| 179 | free_queue.push(&frame); | ||
| 180 | } | ||
| 181 | } | ||
| 182 | |||
| 183 | ~FrameMailbox() { | ||
| 184 | // lock the mutex and clear out the present and free_queues and notify any people who are | ||
| 185 | // blocked to prevent deadlock on shutdown | ||
| 186 | std::scoped_lock lock{swap_chain_lock}; | ||
| 187 | std::queue<Frame*>().swap(free_queue); | ||
| 188 | present_queue.clear(); | ||
| 189 | present_cv.notify_all(); | ||
| 190 | } | ||
| 191 | |||
| 192 | void ReloadPresentFrame(Frame* frame, u32 height, u32 width) { | ||
| 193 | frame->present.Release(); | ||
| 194 | frame->present.Create(); | ||
| 195 | GLint previous_draw_fbo{}; | ||
| 196 | glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &previous_draw_fbo); | ||
| 197 | glBindFramebuffer(GL_FRAMEBUFFER, frame->present.handle); | ||
| 198 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, | ||
| 199 | frame->color.handle); | ||
| 200 | if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { | ||
| 201 | LOG_CRITICAL(Render_OpenGL, "Failed to recreate present FBO!"); | ||
| 202 | } | ||
| 203 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, previous_draw_fbo); | ||
| 204 | frame->color_reloaded = false; | ||
| 205 | } | ||
| 206 | |||
| 207 | void ReloadRenderFrame(Frame* frame, u32 width, u32 height) { | ||
| 208 | // Recreate the color texture attachment | ||
| 209 | frame->color.Release(); | ||
| 210 | frame->color.Create(); | ||
| 211 | const GLenum internal_format = frame->is_srgb ? GL_SRGB8 : GL_RGB8; | ||
| 212 | glNamedRenderbufferStorage(frame->color.handle, internal_format, width, height); | ||
| 213 | |||
| 214 | // Recreate the FBO for the render target | ||
| 215 | frame->render.Release(); | ||
| 216 | frame->render.Create(); | ||
| 217 | glBindFramebuffer(GL_FRAMEBUFFER, frame->render.handle); | ||
| 218 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, | ||
| 219 | frame->color.handle); | ||
| 220 | if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { | ||
| 221 | LOG_CRITICAL(Render_OpenGL, "Failed to recreate render FBO!"); | ||
| 222 | } | ||
| 223 | |||
| 224 | frame->width = width; | ||
| 225 | frame->height = height; | ||
| 226 | frame->color_reloaded = true; | ||
| 227 | } | ||
| 228 | |||
| 229 | Frame* GetRenderFrame() { | ||
| 230 | std::unique_lock lock{swap_chain_lock}; | ||
| 231 | |||
| 232 | // If theres no free frames, we will reuse the oldest render frame | ||
| 233 | if (free_queue.empty()) { | ||
| 234 | auto frame = present_queue.back(); | ||
| 235 | present_queue.pop_back(); | ||
| 236 | return frame; | ||
| 237 | } | ||
| 238 | |||
| 239 | Frame* frame = free_queue.front(); | ||
| 240 | free_queue.pop(); | ||
| 241 | return frame; | ||
| 242 | } | ||
| 243 | |||
| 244 | void ReleaseRenderFrame(Frame* frame) { | ||
| 245 | std::unique_lock lock{swap_chain_lock}; | ||
| 246 | present_queue.push_front(frame); | ||
| 247 | present_cv.notify_one(); | ||
| 248 | } | ||
| 249 | |||
| 250 | Frame* TryGetPresentFrame(int timeout_ms) { | ||
| 251 | std::unique_lock lock{swap_chain_lock}; | ||
| 252 | // wait for new entries in the present_queue | ||
| 253 | present_cv.wait_for(lock, std::chrono::milliseconds(timeout_ms), | ||
| 254 | [&] { return !present_queue.empty(); }); | ||
| 255 | if (present_queue.empty()) { | ||
| 256 | // timed out waiting for a frame to draw so return the previous frame | ||
| 257 | return previous_frame; | ||
| 258 | } | ||
| 259 | |||
| 260 | // free the previous frame and add it back to the free queue | ||
| 261 | if (previous_frame) { | ||
| 262 | free_queue.push(previous_frame); | ||
| 263 | } | ||
| 264 | |||
| 265 | // the newest entries are pushed to the front of the queue | ||
| 266 | Frame* frame = present_queue.front(); | ||
| 267 | present_queue.pop_front(); | ||
| 268 | // remove all old entries from the present queue and move them back to the free_queue | ||
| 269 | for (auto f : present_queue) { | ||
| 270 | free_queue.push(f); | ||
| 271 | } | ||
| 272 | present_queue.clear(); | ||
| 273 | previous_frame = frame; | ||
| 274 | return frame; | ||
| 275 | } | ||
| 276 | }; | ||
| 277 | |||
| 278 | RendererOpenGL::RendererOpenGL(Core::TelemetrySession& telemetry_session_, | 130 | RendererOpenGL::RendererOpenGL(Core::TelemetrySession& telemetry_session_, |
| 279 | Core::Frontend::EmuWindow& emu_window_, | 131 | Core::Frontend::EmuWindow& emu_window_, |
| 280 | Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_, | 132 | Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_, |
| 281 | std::unique_ptr<Core::Frontend::GraphicsContext> context) | 133 | std::unique_ptr<Core::Frontend::GraphicsContext> context) |
| 282 | : RendererBase{emu_window_, std::move(context)}, telemetry_session{telemetry_session_}, | 134 | : RendererBase{emu_window_, std::move(context)}, telemetry_session{telemetry_session_}, |
| 283 | emu_window{emu_window_}, cpu_memory{cpu_memory_}, gpu{gpu_}, program_manager{device}, | 135 | emu_window{emu_window_}, cpu_memory{cpu_memory_}, gpu{gpu_}, program_manager{device} {} |
| 284 | has_debug_tool{HasDebugTool()} {} | ||
| 285 | 136 | ||
| 286 | RendererOpenGL::~RendererOpenGL() = default; | 137 | RendererOpenGL::~RendererOpenGL() = default; |
| 287 | 138 | ||
| 288 | MICROPROFILE_DEFINE(OpenGL_RenderFrame, "OpenGL", "Render Frame", MP_RGB(128, 128, 64)); | ||
| 289 | MICROPROFILE_DEFINE(OpenGL_WaitPresent, "OpenGL", "Wait For Present", MP_RGB(128, 128, 128)); | ||
| 290 | |||
| 291 | void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | 139 | void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { |
| 292 | if (!framebuffer) { | 140 | if (!framebuffer) { |
| 293 | return; | 141 | return; |
| @@ -296,79 +144,34 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | |||
| 296 | PrepareRendertarget(framebuffer); | 144 | PrepareRendertarget(framebuffer); |
| 297 | RenderScreenshot(); | 145 | RenderScreenshot(); |
| 298 | 146 | ||
| 299 | Frame* frame; | 147 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); |
| 300 | { | 148 | DrawScreen(emu_window.GetFramebufferLayout()); |
| 301 | MICROPROFILE_SCOPE(OpenGL_WaitPresent); | ||
| 302 | |||
| 303 | frame = frame_mailbox->GetRenderFrame(); | ||
| 304 | |||
| 305 | // Clean up sync objects before drawing | ||
| 306 | |||
| 307 | // INTEL driver workaround. We can't delete the previous render sync object until we are | ||
| 308 | // sure that the presentation is done | ||
| 309 | if (frame->present_fence) { | ||
| 310 | glClientWaitSync(frame->present_fence, 0, GL_TIMEOUT_IGNORED); | ||
| 311 | } | ||
| 312 | |||
| 313 | // delete the draw fence if the frame wasn't presented | ||
| 314 | if (frame->render_fence) { | ||
| 315 | glDeleteSync(frame->render_fence); | ||
| 316 | frame->render_fence = 0; | ||
| 317 | } | ||
| 318 | |||
| 319 | // wait for the presentation to be done | ||
| 320 | if (frame->present_fence) { | ||
| 321 | glWaitSync(frame->present_fence, 0, GL_TIMEOUT_IGNORED); | ||
| 322 | glDeleteSync(frame->present_fence); | ||
| 323 | frame->present_fence = 0; | ||
| 324 | } | ||
| 325 | } | ||
| 326 | 149 | ||
| 327 | { | 150 | ++m_current_frame; |
| 328 | MICROPROFILE_SCOPE(OpenGL_RenderFrame); | ||
| 329 | const auto& layout = render_window.GetFramebufferLayout(); | ||
| 330 | 151 | ||
| 331 | // Recreate the frame if the size of the window has changed | 152 | rasterizer->TickFrame(); |
| 332 | if (layout.width != frame->width || layout.height != frame->height || | ||
| 333 | screen_info.display_srgb != frame->is_srgb) { | ||
| 334 | LOG_DEBUG(Render_OpenGL, "Reloading render frame"); | ||
| 335 | frame->is_srgb = screen_info.display_srgb; | ||
| 336 | frame_mailbox->ReloadRenderFrame(frame, layout.width, layout.height); | ||
| 337 | } | ||
| 338 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frame->render.handle); | ||
| 339 | DrawScreen(layout); | ||
| 340 | // Create a fence for the frontend to wait on and swap this frame to OffTex | ||
| 341 | frame->render_fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); | ||
| 342 | glFlush(); | ||
| 343 | frame_mailbox->ReleaseRenderFrame(frame); | ||
| 344 | m_current_frame++; | ||
| 345 | rasterizer->TickFrame(); | ||
| 346 | } | ||
| 347 | 153 | ||
| 348 | render_window.PollEvents(); | 154 | render_window.PollEvents(); |
| 349 | if (has_debug_tool) { | 155 | context->SwapBuffers(); |
| 350 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); | ||
| 351 | Present(0); | ||
| 352 | context->SwapBuffers(); | ||
| 353 | } | ||
| 354 | } | 156 | } |
| 355 | 157 | ||
| 356 | void RendererOpenGL::PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer) { | 158 | void RendererOpenGL::PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer) { |
| 357 | if (framebuffer) { | 159 | if (!framebuffer) { |
| 358 | // If framebuffer is provided, reload it from memory to a texture | 160 | return; |
| 359 | if (screen_info.texture.width != static_cast<GLsizei>(framebuffer->width) || | 161 | } |
| 360 | screen_info.texture.height != static_cast<GLsizei>(framebuffer->height) || | 162 | // If framebuffer is provided, reload it from memory to a texture |
| 361 | screen_info.texture.pixel_format != framebuffer->pixel_format || | 163 | if (screen_info.texture.width != static_cast<GLsizei>(framebuffer->width) || |
| 362 | gl_framebuffer_data.empty()) { | 164 | screen_info.texture.height != static_cast<GLsizei>(framebuffer->height) || |
| 363 | // Reallocate texture if the framebuffer size has changed. | 165 | screen_info.texture.pixel_format != framebuffer->pixel_format || |
| 364 | // This is expected to not happen very often and hence should not be a | 166 | gl_framebuffer_data.empty()) { |
| 365 | // performance problem. | 167 | // Reallocate texture if the framebuffer size has changed. |
| 366 | ConfigureFramebufferTexture(screen_info.texture, *framebuffer); | 168 | // This is expected to not happen very often and hence should not be a |
| 367 | } | 169 | // performance problem. |
| 368 | 170 | ConfigureFramebufferTexture(screen_info.texture, *framebuffer); | |
| 369 | // Load the framebuffer from memory, draw it to the screen, and swap buffers | ||
| 370 | LoadFBToScreenInfo(*framebuffer); | ||
| 371 | } | 171 | } |
| 172 | |||
| 173 | // Load the framebuffer from memory, draw it to the screen, and swap buffers | ||
| 174 | LoadFBToScreenInfo(*framebuffer); | ||
| 372 | } | 175 | } |
| 373 | 176 | ||
| 374 | void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer) { | 177 | void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer) { |
| @@ -418,8 +221,6 @@ void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color | |||
| 418 | } | 221 | } |
| 419 | 222 | ||
| 420 | void RendererOpenGL::InitOpenGLObjects() { | 223 | void RendererOpenGL::InitOpenGLObjects() { |
| 421 | frame_mailbox = std::make_unique<FrameMailbox>(); | ||
| 422 | |||
| 423 | glClearColor(Settings::values.bg_red.GetValue(), Settings::values.bg_green.GetValue(), | 224 | glClearColor(Settings::values.bg_red.GetValue(), Settings::values.bg_green.GetValue(), |
| 424 | Settings::values.bg_blue.GetValue(), 0.0f); | 225 | Settings::values.bg_blue.GetValue(), 0.0f); |
| 425 | 226 | ||
| @@ -647,51 +448,6 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | |||
| 647 | program_manager.RestoreGuestPipeline(); | 448 | program_manager.RestoreGuestPipeline(); |
| 648 | } | 449 | } |
| 649 | 450 | ||
| 650 | bool RendererOpenGL::TryPresent(int timeout_ms) { | ||
| 651 | if (has_debug_tool) { | ||
| 652 | LOG_DEBUG(Render_OpenGL, | ||
| 653 | "Skipping presentation because we are presenting on the main context"); | ||
| 654 | return false; | ||
| 655 | } | ||
| 656 | return Present(timeout_ms); | ||
| 657 | } | ||
| 658 | |||
| 659 | bool RendererOpenGL::Present(int timeout_ms) { | ||
| 660 | const auto& layout = render_window.GetFramebufferLayout(); | ||
| 661 | auto frame = frame_mailbox->TryGetPresentFrame(timeout_ms); | ||
| 662 | if (!frame) { | ||
| 663 | LOG_DEBUG(Render_OpenGL, "TryGetPresentFrame returned no frame to present"); | ||
| 664 | return false; | ||
| 665 | } | ||
| 666 | |||
| 667 | // Clearing before a full overwrite of a fbo can signal to drivers that they can avoid a | ||
| 668 | // readback since we won't be doing any blending | ||
| 669 | glClear(GL_COLOR_BUFFER_BIT); | ||
| 670 | |||
| 671 | // Recreate the presentation FBO if the color attachment was changed | ||
| 672 | if (frame->color_reloaded) { | ||
| 673 | LOG_DEBUG(Render_OpenGL, "Reloading present frame"); | ||
| 674 | frame_mailbox->ReloadPresentFrame(frame, layout.width, layout.height); | ||
| 675 | } | ||
| 676 | glWaitSync(frame->render_fence, 0, GL_TIMEOUT_IGNORED); | ||
| 677 | // INTEL workaround. | ||
| 678 | // Normally we could just delete the draw fence here, but due to driver bugs, we can just delete | ||
| 679 | // it on the emulation thread without too much penalty | ||
| 680 | // glDeleteSync(frame.render_sync); | ||
| 681 | // frame.render_sync = 0; | ||
| 682 | |||
| 683 | glBindFramebuffer(GL_READ_FRAMEBUFFER, frame->present.handle); | ||
| 684 | glBlitFramebuffer(0, 0, frame->width, frame->height, 0, 0, layout.width, layout.height, | ||
| 685 | GL_COLOR_BUFFER_BIT, GL_LINEAR); | ||
| 686 | |||
| 687 | // Insert fence for the main thread to block on | ||
| 688 | frame->present_fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); | ||
| 689 | glFlush(); | ||
| 690 | |||
| 691 | glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); | ||
| 692 | return true; | ||
| 693 | } | ||
| 694 | |||
| 695 | void RendererOpenGL::RenderScreenshot() { | 451 | void RendererOpenGL::RenderScreenshot() { |
| 696 | if (!renderer_settings.screenshot_requested) { | 452 | if (!renderer_settings.screenshot_requested) { |
| 697 | return; | 453 | return; |
| @@ -706,7 +462,7 @@ void RendererOpenGL::RenderScreenshot() { | |||
| 706 | screenshot_framebuffer.Create(); | 462 | screenshot_framebuffer.Create(); |
| 707 | glBindFramebuffer(GL_FRAMEBUFFER, screenshot_framebuffer.handle); | 463 | glBindFramebuffer(GL_FRAMEBUFFER, screenshot_framebuffer.handle); |
| 708 | 464 | ||
| 709 | Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout}; | 465 | const Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout}; |
| 710 | 466 | ||
| 711 | GLuint renderbuffer; | 467 | GLuint renderbuffer; |
| 712 | glGenRenderbuffers(1, &renderbuffer); | 468 | glGenRenderbuffers(1, &renderbuffer); |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index 5329577fb..9ef181f95 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h | |||
| @@ -55,14 +55,6 @@ struct ScreenInfo { | |||
| 55 | TextureInfo texture; | 55 | TextureInfo texture; |
| 56 | }; | 56 | }; |
| 57 | 57 | ||
| 58 | struct PresentationTexture { | ||
| 59 | u32 width = 0; | ||
| 60 | u32 height = 0; | ||
| 61 | OGLTexture texture; | ||
| 62 | }; | ||
| 63 | |||
| 64 | class FrameMailbox; | ||
| 65 | |||
| 66 | class RendererOpenGL final : public VideoCore::RendererBase { | 58 | class RendererOpenGL final : public VideoCore::RendererBase { |
| 67 | public: | 59 | public: |
| 68 | explicit RendererOpenGL(Core::TelemetrySession& telemetry_session, | 60 | explicit RendererOpenGL(Core::TelemetrySession& telemetry_session, |
| @@ -74,7 +66,6 @@ public: | |||
| 74 | bool Init() override; | 66 | bool Init() override; |
| 75 | void ShutDown() override; | 67 | void ShutDown() override; |
| 76 | void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override; | 68 | void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override; |
| 77 | bool TryPresent(int timeout_ms) override; | ||
| 78 | 69 | ||
| 79 | private: | 70 | private: |
| 80 | /// Initializes the OpenGL state and creates persistent objects. | 71 | /// Initializes the OpenGL state and creates persistent objects. |
| @@ -102,8 +93,6 @@ private: | |||
| 102 | 93 | ||
| 103 | void PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer); | 94 | void PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer); |
| 104 | 95 | ||
| 105 | bool Present(int timeout_ms); | ||
| 106 | |||
| 107 | Core::TelemetrySession& telemetry_session; | 96 | Core::TelemetrySession& telemetry_session; |
| 108 | Core::Frontend::EmuWindow& emu_window; | 97 | Core::Frontend::EmuWindow& emu_window; |
| 109 | Core::Memory::Memory& cpu_memory; | 98 | Core::Memory::Memory& cpu_memory; |
| @@ -134,11 +123,6 @@ private: | |||
| 134 | /// Used for transforming the framebuffer orientation | 123 | /// Used for transforming the framebuffer orientation |
| 135 | Tegra::FramebufferConfig::TransformFlags framebuffer_transform_flags{}; | 124 | Tegra::FramebufferConfig::TransformFlags framebuffer_transform_flags{}; |
| 136 | Common::Rectangle<int> framebuffer_crop_rect; | 125 | Common::Rectangle<int> framebuffer_crop_rect; |
| 137 | |||
| 138 | /// Frame presentation mailbox | ||
| 139 | std::unique_ptr<FrameMailbox> frame_mailbox; | ||
| 140 | |||
| 141 | bool has_debug_tool = false; | ||
| 142 | }; | 126 | }; |
| 143 | 127 | ||
| 144 | } // namespace OpenGL | 128 | } // namespace OpenGL |
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 0e4583986..d38e797a4 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp | |||
| @@ -283,11 +283,6 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | |||
| 283 | render_window.PollEvents(); | 283 | render_window.PollEvents(); |
| 284 | } | 284 | } |
| 285 | 285 | ||
| 286 | bool RendererVulkan::TryPresent(int /*timeout_ms*/) { | ||
| 287 | // TODO (bunnei): ImplementMe | ||
| 288 | return true; | ||
| 289 | } | ||
| 290 | |||
| 291 | bool RendererVulkan::Init() { | 286 | bool RendererVulkan::Init() { |
| 292 | library = OpenVulkanLibrary(); | 287 | library = OpenVulkanLibrary(); |
| 293 | instance = CreateInstance(library, dld, render_window.GetWindowInfo().type, | 288 | instance = CreateInstance(library, dld, render_window.GetWindowInfo().type, |
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index ddff77942..5085310d0 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h | |||
| @@ -55,7 +55,6 @@ public: | |||
| 55 | bool Init() override; | 55 | bool Init() override; |
| 56 | void ShutDown() override; | 56 | void ShutDown() override; |
| 57 | void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override; | 57 | void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override; |
| 58 | bool TryPresent(int timeout_ms) override; | ||
| 59 | 58 | ||
| 60 | static std::vector<std::string> EnumerateDevices(); | 59 | static std::vector<std::string> EnumerateDevices(); |
| 61 | 60 | ||
diff --git a/src/video_core/shader/ast.h b/src/video_core/shader/ast.h index cca13bcde..8e5a22ab3 100644 --- a/src/video_core/shader/ast.h +++ b/src/video_core/shader/ast.h | |||
| @@ -199,55 +199,48 @@ public: | |||
| 199 | } | 199 | } |
| 200 | 200 | ||
| 201 | std::optional<u32> GetGotoLabel() const { | 201 | std::optional<u32> GetGotoLabel() const { |
| 202 | auto inner = std::get_if<ASTGoto>(&data); | 202 | if (const auto* inner = std::get_if<ASTGoto>(&data)) { |
| 203 | if (inner) { | ||
| 204 | return {inner->label}; | 203 | return {inner->label}; |
| 205 | } | 204 | } |
| 206 | return {}; | 205 | return std::nullopt; |
| 207 | } | 206 | } |
| 208 | 207 | ||
| 209 | Expr GetGotoCondition() const { | 208 | Expr GetGotoCondition() const { |
| 210 | auto inner = std::get_if<ASTGoto>(&data); | 209 | if (const auto* inner = std::get_if<ASTGoto>(&data)) { |
| 211 | if (inner) { | ||
| 212 | return inner->condition; | 210 | return inner->condition; |
| 213 | } | 211 | } |
| 214 | return nullptr; | 212 | return nullptr; |
| 215 | } | 213 | } |
| 216 | 214 | ||
| 217 | void MarkLabelUnused() { | 215 | void MarkLabelUnused() { |
| 218 | auto inner = std::get_if<ASTLabel>(&data); | 216 | if (auto* inner = std::get_if<ASTLabel>(&data)) { |
| 219 | if (inner) { | ||
| 220 | inner->unused = true; | 217 | inner->unused = true; |
| 221 | } | 218 | } |
| 222 | } | 219 | } |
| 223 | 220 | ||
| 224 | bool IsLabelUnused() const { | 221 | bool IsLabelUnused() const { |
| 225 | auto inner = std::get_if<ASTLabel>(&data); | 222 | if (const auto* inner = std::get_if<ASTLabel>(&data)) { |
| 226 | if (inner) { | ||
| 227 | return inner->unused; | 223 | return inner->unused; |
| 228 | } | 224 | } |
| 229 | return true; | 225 | return true; |
| 230 | } | 226 | } |
| 231 | 227 | ||
| 232 | std::optional<u32> GetLabelIndex() const { | 228 | std::optional<u32> GetLabelIndex() const { |
| 233 | auto inner = std::get_if<ASTLabel>(&data); | 229 | if (const auto* inner = std::get_if<ASTLabel>(&data)) { |
| 234 | if (inner) { | ||
| 235 | return {inner->index}; | 230 | return {inner->index}; |
| 236 | } | 231 | } |
| 237 | return {}; | 232 | return std::nullopt; |
| 238 | } | 233 | } |
| 239 | 234 | ||
| 240 | Expr GetIfCondition() const { | 235 | Expr GetIfCondition() const { |
| 241 | auto inner = std::get_if<ASTIfThen>(&data); | 236 | if (const auto* inner = std::get_if<ASTIfThen>(&data)) { |
| 242 | if (inner) { | ||
| 243 | return inner->condition; | 237 | return inner->condition; |
| 244 | } | 238 | } |
| 245 | return nullptr; | 239 | return nullptr; |
| 246 | } | 240 | } |
| 247 | 241 | ||
| 248 | void SetGotoCondition(Expr new_condition) { | 242 | void SetGotoCondition(Expr new_condition) { |
| 249 | auto inner = std::get_if<ASTGoto>(&data); | 243 | if (auto* inner = std::get_if<ASTGoto>(&data)) { |
| 250 | if (inner) { | ||
| 251 | inner->condition = std::move(new_condition); | 244 | inner->condition = std::move(new_condition); |
| 252 | } | 245 | } |
| 253 | } | 246 | } |
diff --git a/src/video_core/shader/control_flow.cpp b/src/video_core/shader/control_flow.cpp index 336397cdb..4c8971615 100644 --- a/src/video_core/shader/control_flow.cpp +++ b/src/video_core/shader/control_flow.cpp | |||
| @@ -547,13 +547,13 @@ bool TryQuery(CFGRebuildState& state) { | |||
| 547 | gather_labels(q2.ssy_stack, state.ssy_labels, block); | 547 | gather_labels(q2.ssy_stack, state.ssy_labels, block); |
| 548 | gather_labels(q2.pbk_stack, state.pbk_labels, block); | 548 | gather_labels(q2.pbk_stack, state.pbk_labels, block); |
| 549 | if (std::holds_alternative<SingleBranch>(*block.branch)) { | 549 | if (std::holds_alternative<SingleBranch>(*block.branch)) { |
| 550 | const auto branch = std::get_if<SingleBranch>(block.branch.get()); | 550 | auto* branch = std::get_if<SingleBranch>(block.branch.get()); |
| 551 | if (!branch->condition.IsUnconditional()) { | 551 | if (!branch->condition.IsUnconditional()) { |
| 552 | q2.address = block.end + 1; | 552 | q2.address = block.end + 1; |
| 553 | state.queries.push_back(q2); | 553 | state.queries.push_back(q2); |
| 554 | } | 554 | } |
| 555 | 555 | ||
| 556 | Query conditional_query{q2}; | 556 | auto& conditional_query = state.queries.emplace_back(q2); |
| 557 | if (branch->is_sync) { | 557 | if (branch->is_sync) { |
| 558 | if (branch->address == unassigned_branch) { | 558 | if (branch->address == unassigned_branch) { |
| 559 | branch->address = conditional_query.ssy_stack.top(); | 559 | branch->address = conditional_query.ssy_stack.top(); |
| @@ -567,21 +567,21 @@ bool TryQuery(CFGRebuildState& state) { | |||
| 567 | conditional_query.pbk_stack.pop(); | 567 | conditional_query.pbk_stack.pop(); |
| 568 | } | 568 | } |
| 569 | conditional_query.address = branch->address; | 569 | conditional_query.address = branch->address; |
| 570 | state.queries.push_back(std::move(conditional_query)); | ||
| 571 | return true; | 570 | return true; |
| 572 | } | 571 | } |
| 573 | const auto multi_branch = std::get_if<MultiBranch>(block.branch.get()); | 572 | |
| 573 | const auto* multi_branch = std::get_if<MultiBranch>(block.branch.get()); | ||
| 574 | for (const auto& branch_case : multi_branch->branches) { | 574 | for (const auto& branch_case : multi_branch->branches) { |
| 575 | Query conditional_query{q2}; | 575 | auto& conditional_query = state.queries.emplace_back(q2); |
| 576 | conditional_query.address = branch_case.address; | 576 | conditional_query.address = branch_case.address; |
| 577 | state.queries.push_back(std::move(conditional_query)); | ||
| 578 | } | 577 | } |
| 578 | |||
| 579 | return true; | 579 | return true; |
| 580 | } | 580 | } |
| 581 | 581 | ||
| 582 | void InsertBranch(ASTManager& mm, const BlockBranchInfo& branch_info) { | 582 | void InsertBranch(ASTManager& mm, const BlockBranchInfo& branch_info) { |
| 583 | const auto get_expr = ([&](const Condition& cond) -> Expr { | 583 | const auto get_expr = [](const Condition& cond) -> Expr { |
| 584 | Expr result{}; | 584 | Expr result; |
| 585 | if (cond.cc != ConditionCode::T) { | 585 | if (cond.cc != ConditionCode::T) { |
| 586 | result = MakeExpr<ExprCondCode>(cond.cc); | 586 | result = MakeExpr<ExprCondCode>(cond.cc); |
| 587 | } | 587 | } |
| @@ -594,10 +594,10 @@ void InsertBranch(ASTManager& mm, const BlockBranchInfo& branch_info) { | |||
| 594 | } | 594 | } |
| 595 | Expr extra = MakeExpr<ExprPredicate>(pred); | 595 | Expr extra = MakeExpr<ExprPredicate>(pred); |
| 596 | if (negate) { | 596 | if (negate) { |
| 597 | extra = MakeExpr<ExprNot>(extra); | 597 | extra = MakeExpr<ExprNot>(std::move(extra)); |
| 598 | } | 598 | } |
| 599 | if (result) { | 599 | if (result) { |
| 600 | return MakeExpr<ExprAnd>(extra, result); | 600 | return MakeExpr<ExprAnd>(std::move(extra), std::move(result)); |
| 601 | } | 601 | } |
| 602 | return extra; | 602 | return extra; |
| 603 | } | 603 | } |
| @@ -605,9 +605,10 @@ void InsertBranch(ASTManager& mm, const BlockBranchInfo& branch_info) { | |||
| 605 | return result; | 605 | return result; |
| 606 | } | 606 | } |
| 607 | return MakeExpr<ExprBoolean>(true); | 607 | return MakeExpr<ExprBoolean>(true); |
| 608 | }); | 608 | }; |
| 609 | |||
| 609 | if (std::holds_alternative<SingleBranch>(*branch_info)) { | 610 | if (std::holds_alternative<SingleBranch>(*branch_info)) { |
| 610 | const auto branch = std::get_if<SingleBranch>(branch_info.get()); | 611 | const auto* branch = std::get_if<SingleBranch>(branch_info.get()); |
| 611 | if (branch->address < 0) { | 612 | if (branch->address < 0) { |
| 612 | if (branch->kill) { | 613 | if (branch->kill) { |
| 613 | mm.InsertReturn(get_expr(branch->condition), true); | 614 | mm.InsertReturn(get_expr(branch->condition), true); |
| @@ -619,7 +620,7 @@ void InsertBranch(ASTManager& mm, const BlockBranchInfo& branch_info) { | |||
| 619 | mm.InsertGoto(get_expr(branch->condition), branch->address); | 620 | mm.InsertGoto(get_expr(branch->condition), branch->address); |
| 620 | return; | 621 | return; |
| 621 | } | 622 | } |
| 622 | const auto multi_branch = std::get_if<MultiBranch>(branch_info.get()); | 623 | const auto* multi_branch = std::get_if<MultiBranch>(branch_info.get()); |
| 623 | for (const auto& branch_case : multi_branch->branches) { | 624 | for (const auto& branch_case : multi_branch->branches) { |
| 624 | mm.InsertGoto(MakeExpr<ExprGprEqual>(multi_branch->gpr, branch_case.cmp_value), | 625 | mm.InsertGoto(MakeExpr<ExprGprEqual>(multi_branch->gpr, branch_case.cmp_value), |
| 625 | branch_case.address); | 626 | branch_case.address); |
diff --git a/src/video_core/shader/track.cpp b/src/video_core/shader/track.cpp index d5ed81442..6be3ea92b 100644 --- a/src/video_core/shader/track.cpp +++ b/src/video_core/shader/track.cpp | |||
| @@ -205,12 +205,12 @@ std::optional<u32> ShaderIR::TrackImmediate(Node tracked, const NodeBlock& code, | |||
| 205 | const auto result = TrackRegister(&std::get<GprNode>(*tracked), code, cursor - 1); | 205 | const auto result = TrackRegister(&std::get<GprNode>(*tracked), code, cursor - 1); |
| 206 | const auto& found = result.first; | 206 | const auto& found = result.first; |
| 207 | if (!found) { | 207 | if (!found) { |
| 208 | return {}; | 208 | return std::nullopt; |
| 209 | } | 209 | } |
| 210 | if (const auto immediate = std::get_if<ImmediateNode>(&*found)) { | 210 | if (const auto immediate = std::get_if<ImmediateNode>(&*found)) { |
| 211 | return immediate->GetValue(); | 211 | return immediate->GetValue(); |
| 212 | } | 212 | } |
| 213 | return {}; | 213 | return std::nullopt; |
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | std::pair<Node, s64> ShaderIR::TrackRegister(const GprNode* tracked, const NodeBlock& code, | 216 | std::pair<Node, s64> ShaderIR::TrackRegister(const GprNode* tracked, const NodeBlock& code, |
diff --git a/src/video_core/texture_cache/surface_base.cpp b/src/video_core/texture_cache/surface_base.cpp index dfcf36e0b..b44c09d71 100644 --- a/src/video_core/texture_cache/surface_base.cpp +++ b/src/video_core/texture_cache/surface_base.cpp | |||
| @@ -115,20 +115,24 @@ std::optional<std::pair<u32, u32>> SurfaceBaseImpl::GetLayerMipmap( | |||
| 115 | if (gpu_addr == candidate_gpu_addr) { | 115 | if (gpu_addr == candidate_gpu_addr) { |
| 116 | return {{0, 0}}; | 116 | return {{0, 0}}; |
| 117 | } | 117 | } |
| 118 | |||
| 118 | if (candidate_gpu_addr < gpu_addr) { | 119 | if (candidate_gpu_addr < gpu_addr) { |
| 119 | return {}; | 120 | return std::nullopt; |
| 120 | } | 121 | } |
| 122 | |||
| 121 | const auto relative_address{static_cast<GPUVAddr>(candidate_gpu_addr - gpu_addr)}; | 123 | const auto relative_address{static_cast<GPUVAddr>(candidate_gpu_addr - gpu_addr)}; |
| 122 | const auto layer{static_cast<u32>(relative_address / layer_size)}; | 124 | const auto layer{static_cast<u32>(relative_address / layer_size)}; |
| 123 | if (layer >= params.depth) { | 125 | if (layer >= params.depth) { |
| 124 | return {}; | 126 | return std::nullopt; |
| 125 | } | 127 | } |
| 128 | |||
| 126 | const GPUVAddr mipmap_address = relative_address - layer_size * layer; | 129 | const GPUVAddr mipmap_address = relative_address - layer_size * layer; |
| 127 | const auto mipmap_it = | 130 | const auto mipmap_it = |
| 128 | Common::BinaryFind(mipmap_offsets.begin(), mipmap_offsets.end(), mipmap_address); | 131 | Common::BinaryFind(mipmap_offsets.begin(), mipmap_offsets.end(), mipmap_address); |
| 129 | if (mipmap_it == mipmap_offsets.end()) { | 132 | if (mipmap_it == mipmap_offsets.end()) { |
| 130 | return {}; | 133 | return std::nullopt; |
| 131 | } | 134 | } |
| 135 | |||
| 132 | const auto level{static_cast<u32>(std::distance(mipmap_offsets.begin(), mipmap_it))}; | 136 | const auto level{static_cast<u32>(std::distance(mipmap_offsets.begin(), mipmap_it))}; |
| 133 | return std::make_pair(layer, level); | 137 | return std::make_pair(layer, level); |
| 134 | } | 138 | } |
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index caa2d06d3..408eac2b7 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -218,15 +218,6 @@ public: | |||
| 218 | 218 | ||
| 219 | virtual ~RenderWidget() = default; | 219 | virtual ~RenderWidget() = default; |
| 220 | 220 | ||
| 221 | /// Called on the UI thread when this Widget is ready to draw | ||
| 222 | /// Dervied classes can override this to draw the latest frame. | ||
| 223 | virtual void Present() {} | ||
| 224 | |||
| 225 | void paintEvent(QPaintEvent* event) override { | ||
| 226 | Present(); | ||
| 227 | update(); | ||
| 228 | } | ||
| 229 | |||
| 230 | QPaintEngine* paintEngine() const override { | 221 | QPaintEngine* paintEngine() const override { |
| 231 | return nullptr; | 222 | return nullptr; |
| 232 | } | 223 | } |
| @@ -245,20 +236,8 @@ public: | |||
| 245 | context = std::move(context_); | 236 | context = std::move(context_); |
| 246 | } | 237 | } |
| 247 | 238 | ||
| 248 | void Present() override { | ||
| 249 | if (!isVisible()) { | ||
| 250 | return; | ||
| 251 | } | ||
| 252 | |||
| 253 | context->MakeCurrent(); | ||
| 254 | if (Core::System::GetInstance().Renderer().TryPresent(100)) { | ||
| 255 | context->SwapBuffers(); | ||
| 256 | glFinish(); | ||
| 257 | } | ||
| 258 | } | ||
| 259 | |||
| 260 | private: | 239 | private: |
| 261 | std::unique_ptr<Core::Frontend::GraphicsContext> context{}; | 240 | std::unique_ptr<Core::Frontend::GraphicsContext> context; |
| 262 | }; | 241 | }; |
| 263 | 242 | ||
| 264 | #ifdef HAS_VULKAN | 243 | #ifdef HAS_VULKAN |
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 6a71d9644..a9738e298 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp | |||
| @@ -56,7 +56,7 @@ bool GameListSearchField::KeyReleaseEater::eventFilter(QObject* obj, QEvent* eve | |||
| 56 | case Qt::Key_Return: | 56 | case Qt::Key_Return: |
| 57 | case Qt::Key_Enter: { | 57 | case Qt::Key_Enter: { |
| 58 | if (gamelist->search_field->visible == 1) { | 58 | if (gamelist->search_field->visible == 1) { |
| 59 | QString file_path = gamelist->getLastFilterResultItem(); | 59 | const QString file_path = gamelist->GetLastFilterResultItem(); |
| 60 | 60 | ||
| 61 | // To avoid loading error dialog loops while confirming them using enter | 61 | // To avoid loading error dialog loops while confirming them using enter |
| 62 | // Also users usually want to run a different game after closing one | 62 | // Also users usually want to run a different game after closing one |
| @@ -83,22 +83,25 @@ void GameListSearchField::setFilterResult(int visible, int total) { | |||
| 83 | label_filter_result->setText(tr("%1 of %n result(s)", "", total).arg(visible)); | 83 | label_filter_result->setText(tr("%1 of %n result(s)", "", total).arg(visible)); |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | QString GameList::getLastFilterResultItem() const { | 86 | QString GameList::GetLastFilterResultItem() const { |
| 87 | QStandardItem* folder; | ||
| 88 | QStandardItem* child; | ||
| 89 | QString file_path; | 87 | QString file_path; |
| 90 | const int folder_count = item_model->rowCount(); | 88 | const int folder_count = item_model->rowCount(); |
| 89 | |||
| 91 | for (int i = 0; i < folder_count; ++i) { | 90 | for (int i = 0; i < folder_count; ++i) { |
| 92 | folder = item_model->item(i, 0); | 91 | const QStandardItem* folder = item_model->item(i, 0); |
| 93 | const QModelIndex folder_index = folder->index(); | 92 | const QModelIndex folder_index = folder->index(); |
| 94 | const int children_count = folder->rowCount(); | 93 | const int children_count = folder->rowCount(); |
| 94 | |||
| 95 | for (int j = 0; j < children_count; ++j) { | 95 | for (int j = 0; j < children_count; ++j) { |
| 96 | if (!tree_view->isRowHidden(j, folder_index)) { | 96 | if (tree_view->isRowHidden(j, folder_index)) { |
| 97 | child = folder->child(j, 0); | 97 | continue; |
| 98 | file_path = child->data(GameListItemPath::FullPathRole).toString(); | ||
| 99 | } | 98 | } |
| 99 | |||
| 100 | const QStandardItem* child = folder->child(j, 0); | ||
| 101 | file_path = child->data(GameListItemPath::FullPathRole).toString(); | ||
| 100 | } | 102 | } |
| 101 | } | 103 | } |
| 104 | |||
| 102 | return file_path; | 105 | return file_path; |
| 103 | } | 106 | } |
| 104 | 107 | ||
| @@ -123,7 +126,7 @@ GameListSearchField::GameListSearchField(GameList* parent) : QWidget{parent} { | |||
| 123 | edit_filter->setPlaceholderText(tr("Enter pattern to filter")); | 126 | edit_filter->setPlaceholderText(tr("Enter pattern to filter")); |
| 124 | edit_filter->installEventFilter(key_release_eater); | 127 | edit_filter->installEventFilter(key_release_eater); |
| 125 | edit_filter->setClearButtonEnabled(true); | 128 | edit_filter->setClearButtonEnabled(true); |
| 126 | connect(edit_filter, &QLineEdit::textChanged, parent, &GameList::onTextChanged); | 129 | connect(edit_filter, &QLineEdit::textChanged, parent, &GameList::OnTextChanged); |
| 127 | label_filter_result = new QLabel; | 130 | label_filter_result = new QLabel; |
| 128 | button_filter_close = new QToolButton(this); | 131 | button_filter_close = new QToolButton(this); |
| 129 | button_filter_close->setText(QStringLiteral("X")); | 132 | button_filter_close->setText(QStringLiteral("X")); |
| @@ -133,7 +136,7 @@ GameListSearchField::GameListSearchField(GameList* parent) : QWidget{parent} { | |||
| 133 | "#000000; font-weight: bold; background: #F0F0F0; }" | 136 | "#000000; font-weight: bold; background: #F0F0F0; }" |
| 134 | "QToolButton:hover{ border: none; padding: 0px; color: " | 137 | "QToolButton:hover{ border: none; padding: 0px; color: " |
| 135 | "#EEEEEE; font-weight: bold; background: #E81123}")); | 138 | "#EEEEEE; font-weight: bold; background: #E81123}")); |
| 136 | connect(button_filter_close, &QToolButton::clicked, parent, &GameList::onFilterCloseClicked); | 139 | connect(button_filter_close, &QToolButton::clicked, parent, &GameList::OnFilterCloseClicked); |
| 137 | layout_filter->setSpacing(10); | 140 | layout_filter->setSpacing(10); |
| 138 | layout_filter->addWidget(label_filter); | 141 | layout_filter->addWidget(label_filter); |
| 139 | layout_filter->addWidget(edit_filter); | 142 | layout_filter->addWidget(edit_filter); |
| @@ -159,16 +162,22 @@ static bool ContainsAllWords(const QString& haystack, const QString& userinput) | |||
| 159 | } | 162 | } |
| 160 | 163 | ||
| 161 | // Syncs the expanded state of Game Directories with settings to persist across sessions | 164 | // Syncs the expanded state of Game Directories with settings to persist across sessions |
| 162 | void GameList::onItemExpanded(const QModelIndex& item) { | 165 | void GameList::OnItemExpanded(const QModelIndex& item) { |
| 163 | const auto type = item.data(GameListItem::TypeRole).value<GameListItemType>(); | 166 | const auto type = item.data(GameListItem::TypeRole).value<GameListItemType>(); |
| 164 | if (type == GameListItemType::CustomDir || type == GameListItemType::SdmcDir || | 167 | const bool is_dir = type == GameListItemType::CustomDir || type == GameListItemType::SdmcDir || |
| 165 | type == GameListItemType::UserNandDir || type == GameListItemType::SysNandDir) | 168 | type == GameListItemType::UserNandDir || |
| 166 | item.data(GameListDir::GameDirRole).value<UISettings::GameDir*>()->expanded = | 169 | type == GameListItemType::SysNandDir; |
| 167 | tree_view->isExpanded(item); | 170 | |
| 171 | if (!is_dir) { | ||
| 172 | return; | ||
| 173 | } | ||
| 174 | |||
| 175 | auto* game_dir = item.data(GameListDir::GameDirRole).value<UISettings::GameDir*>(); | ||
| 176 | game_dir->expanded = tree_view->isExpanded(item); | ||
| 168 | } | 177 | } |
| 169 | 178 | ||
| 170 | // Event in order to filter the gamelist after editing the searchfield | 179 | // Event in order to filter the gamelist after editing the searchfield |
| 171 | void GameList::onTextChanged(const QString& new_text) { | 180 | void GameList::OnTextChanged(const QString& new_text) { |
| 172 | const int folder_count = tree_view->model()->rowCount(); | 181 | const int folder_count = tree_view->model()->rowCount(); |
| 173 | QString edit_filter_text = new_text.toLower(); | 182 | QString edit_filter_text = new_text.toLower(); |
| 174 | QStandardItem* folder; | 183 | QStandardItem* folder; |
| @@ -224,7 +233,7 @@ void GameList::onTextChanged(const QString& new_text) { | |||
| 224 | } | 233 | } |
| 225 | } | 234 | } |
| 226 | 235 | ||
| 227 | void GameList::onUpdateThemedIcons() { | 236 | void GameList::OnUpdateThemedIcons() { |
| 228 | for (int i = 0; i < item_model->invisibleRootItem()->rowCount(); i++) { | 237 | for (int i = 0; i < item_model->invisibleRootItem()->rowCount(); i++) { |
| 229 | QStandardItem* child = item_model->invisibleRootItem()->child(i); | 238 | QStandardItem* child = item_model->invisibleRootItem()->child(i); |
| 230 | 239 | ||
| @@ -276,7 +285,7 @@ void GameList::onUpdateThemedIcons() { | |||
| 276 | } | 285 | } |
| 277 | } | 286 | } |
| 278 | 287 | ||
| 279 | void GameList::onFilterCloseClicked() { | 288 | void GameList::OnFilterCloseClicked() { |
| 280 | main_window->filterBarSetChecked(false); | 289 | main_window->filterBarSetChecked(false); |
| 281 | } | 290 | } |
| 282 | 291 | ||
| @@ -317,11 +326,11 @@ GameList::GameList(FileSys::VirtualFilesystem vfs, FileSys::ManualContentProvide | |||
| 317 | } | 326 | } |
| 318 | item_model->setSortRole(GameListItemPath::SortRole); | 327 | item_model->setSortRole(GameListItemPath::SortRole); |
| 319 | 328 | ||
| 320 | connect(main_window, &GMainWindow::UpdateThemedIcons, this, &GameList::onUpdateThemedIcons); | 329 | connect(main_window, &GMainWindow::UpdateThemedIcons, this, &GameList::OnUpdateThemedIcons); |
| 321 | connect(tree_view, &QTreeView::activated, this, &GameList::ValidateEntry); | 330 | connect(tree_view, &QTreeView::activated, this, &GameList::ValidateEntry); |
| 322 | connect(tree_view, &QTreeView::customContextMenuRequested, this, &GameList::PopupContextMenu); | 331 | connect(tree_view, &QTreeView::customContextMenuRequested, this, &GameList::PopupContextMenu); |
| 323 | connect(tree_view, &QTreeView::expanded, this, &GameList::onItemExpanded); | 332 | connect(tree_view, &QTreeView::expanded, this, &GameList::OnItemExpanded); |
| 324 | connect(tree_view, &QTreeView::collapsed, this, &GameList::onItemExpanded); | 333 | connect(tree_view, &QTreeView::collapsed, this, &GameList::OnItemExpanded); |
| 325 | 334 | ||
| 326 | // We must register all custom types with the Qt Automoc system so that we are able to use | 335 | // We must register all custom types with the Qt Automoc system so that we are able to use |
| 327 | // it with signals/slots. In this case, QList falls under the umbrells of custom types. | 336 | // it with signals/slots. In this case, QList falls under the umbrells of custom types. |
| @@ -338,17 +347,17 @@ GameList::~GameList() { | |||
| 338 | emit ShouldCancelWorker(); | 347 | emit ShouldCancelWorker(); |
| 339 | } | 348 | } |
| 340 | 349 | ||
| 341 | void GameList::setFilterFocus() { | 350 | void GameList::SetFilterFocus() { |
| 342 | if (tree_view->model()->rowCount() > 0) { | 351 | if (tree_view->model()->rowCount() > 0) { |
| 343 | search_field->setFocus(); | 352 | search_field->setFocus(); |
| 344 | } | 353 | } |
| 345 | } | 354 | } |
| 346 | 355 | ||
| 347 | void GameList::setFilterVisible(bool visibility) { | 356 | void GameList::SetFilterVisible(bool visibility) { |
| 348 | search_field->setVisible(visibility); | 357 | search_field->setVisible(visibility); |
| 349 | } | 358 | } |
| 350 | 359 | ||
| 351 | void GameList::clearFilter() { | 360 | void GameList::ClearFilter() { |
| 352 | search_field->clear(); | 361 | search_field->clear(); |
| 353 | } | 362 | } |
| 354 | 363 | ||
| @@ -397,10 +406,11 @@ void GameList::ValidateEntry(const QModelIndex& item) { | |||
| 397 | } | 406 | } |
| 398 | } | 407 | } |
| 399 | 408 | ||
| 400 | bool GameList::isEmpty() const { | 409 | bool GameList::IsEmpty() const { |
| 401 | for (int i = 0; i < item_model->rowCount(); i++) { | 410 | for (int i = 0; i < item_model->rowCount(); i++) { |
| 402 | const QStandardItem* child = item_model->invisibleRootItem()->child(i); | 411 | const QStandardItem* child = item_model->invisibleRootItem()->child(i); |
| 403 | const auto type = static_cast<GameListItemType>(child->type()); | 412 | const auto type = static_cast<GameListItemType>(child->type()); |
| 413 | |||
| 404 | if (!child->hasChildren() && | 414 | if (!child->hasChildren() && |
| 405 | (type == GameListItemType::SdmcDir || type == GameListItemType::UserNandDir || | 415 | (type == GameListItemType::SdmcDir || type == GameListItemType::UserNandDir || |
| 406 | type == GameListItemType::SysNandDir)) { | 416 | type == GameListItemType::SysNandDir)) { |
| @@ -408,11 +418,12 @@ bool GameList::isEmpty() const { | |||
| 408 | i--; | 418 | i--; |
| 409 | } | 419 | } |
| 410 | } | 420 | } |
| 421 | |||
| 411 | return !item_model->invisibleRootItem()->hasChildren(); | 422 | return !item_model->invisibleRootItem()->hasChildren(); |
| 412 | } | 423 | } |
| 413 | 424 | ||
| 414 | void GameList::DonePopulating(QStringList watch_list) { | 425 | void GameList::DonePopulating(const QStringList& watch_list) { |
| 415 | emit ShowList(!isEmpty()); | 426 | emit ShowList(!IsEmpty()); |
| 416 | 427 | ||
| 417 | item_model->invisibleRootItem()->appendRow(new GameListAddDir()); | 428 | item_model->invisibleRootItem()->appendRow(new GameListAddDir()); |
| 418 | 429 | ||
| @@ -472,7 +483,7 @@ void GameList::PopupContextMenu(const QPoint& menu_location) { | |||
| 472 | context_menu.exec(tree_view->viewport()->mapToGlobal(menu_location)); | 483 | context_menu.exec(tree_view->viewport()->mapToGlobal(menu_location)); |
| 473 | } | 484 | } |
| 474 | 485 | ||
| 475 | void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, std::string path) { | 486 | void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::string& path) { |
| 476 | QAction* open_save_location = context_menu.addAction(tr("Open Save Data Location")); | 487 | QAction* open_save_location = context_menu.addAction(tr("Open Save Data Location")); |
| 477 | QAction* open_mod_location = context_menu.addAction(tr("Open Mod Data Location")); | 488 | QAction* open_mod_location = context_menu.addAction(tr("Open Mod Data Location")); |
| 478 | QAction* open_transferable_shader_cache = | 489 | QAction* open_transferable_shader_cache = |
| @@ -690,12 +701,15 @@ void GameList::SaveInterfaceLayout() { | |||
| 690 | } | 701 | } |
| 691 | 702 | ||
| 692 | void GameList::LoadInterfaceLayout() { | 703 | void GameList::LoadInterfaceLayout() { |
| 693 | auto header = tree_view->header(); | 704 | auto* header = tree_view->header(); |
| 694 | if (!header->restoreState(UISettings::values.gamelist_header_state)) { | 705 | |
| 695 | // We are using the name column to display icons and titles | 706 | if (header->restoreState(UISettings::values.gamelist_header_state)) { |
| 696 | // so make it as large as possible as default. | 707 | return; |
| 697 | header->resizeSection(COLUMN_NAME, header->width()); | ||
| 698 | } | 708 | } |
| 709 | |||
| 710 | // We are using the name column to display icons and titles | ||
| 711 | // so make it as large as possible as default. | ||
| 712 | header->resizeSection(COLUMN_NAME, header->width()); | ||
| 699 | } | 713 | } |
| 700 | 714 | ||
| 701 | const QStringList GameList::supported_file_extensions = { | 715 | const QStringList GameList::supported_file_extensions = { |
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index 78e2ba169..58059a3c4 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h | |||
| @@ -67,11 +67,11 @@ public: | |||
| 67 | FileSys::ManualContentProvider* provider, GMainWindow* parent = nullptr); | 67 | FileSys::ManualContentProvider* provider, GMainWindow* parent = nullptr); |
| 68 | ~GameList() override; | 68 | ~GameList() override; |
| 69 | 69 | ||
| 70 | QString getLastFilterResultItem() const; | 70 | QString GetLastFilterResultItem() const; |
| 71 | void clearFilter(); | 71 | void ClearFilter(); |
| 72 | void setFilterFocus(); | 72 | void SetFilterFocus(); |
| 73 | void setFilterVisible(bool visibility); | 73 | void SetFilterVisible(bool visibility); |
| 74 | bool isEmpty() const; | 74 | bool IsEmpty() const; |
| 75 | 75 | ||
| 76 | void LoadCompatibilityList(); | 76 | void LoadCompatibilityList(); |
| 77 | void PopulateAsync(QVector<UISettings::GameDir>& game_dirs); | 77 | void PopulateAsync(QVector<UISettings::GameDir>& game_dirs); |
| @@ -82,7 +82,7 @@ public: | |||
| 82 | static const QStringList supported_file_extensions; | 82 | static const QStringList supported_file_extensions; |
| 83 | 83 | ||
| 84 | signals: | 84 | signals: |
| 85 | void GameChosen(QString game_path); | 85 | void GameChosen(const QString& game_path); |
| 86 | void ShouldCancelWorker(); | 86 | void ShouldCancelWorker(); |
| 87 | void OpenFolderRequested(u64 program_id, GameListOpenTarget target, | 87 | void OpenFolderRequested(u64 program_id, GameListOpenTarget target, |
| 88 | const std::string& game_path); | 88 | const std::string& game_path); |
| @@ -99,21 +99,21 @@ signals: | |||
| 99 | void ShowList(bool show); | 99 | void ShowList(bool show); |
| 100 | 100 | ||
| 101 | private slots: | 101 | private slots: |
| 102 | void onItemExpanded(const QModelIndex& item); | 102 | void OnItemExpanded(const QModelIndex& item); |
| 103 | void onTextChanged(const QString& new_text); | 103 | void OnTextChanged(const QString& new_text); |
| 104 | void onFilterCloseClicked(); | 104 | void OnFilterCloseClicked(); |
| 105 | void onUpdateThemedIcons(); | 105 | void OnUpdateThemedIcons(); |
| 106 | 106 | ||
| 107 | private: | 107 | private: |
| 108 | void AddDirEntry(GameListDir* entry_items); | 108 | void AddDirEntry(GameListDir* entry_items); |
| 109 | void AddEntry(const QList<QStandardItem*>& entry_items, GameListDir* parent); | 109 | void AddEntry(const QList<QStandardItem*>& entry_items, GameListDir* parent); |
| 110 | void ValidateEntry(const QModelIndex& item); | 110 | void ValidateEntry(const QModelIndex& item); |
| 111 | void DonePopulating(QStringList watch_list); | 111 | void DonePopulating(const QStringList& watch_list); |
| 112 | 112 | ||
| 113 | void RefreshGameDirectory(); | 113 | void RefreshGameDirectory(); |
| 114 | 114 | ||
| 115 | void PopupContextMenu(const QPoint& menu_location); | 115 | void PopupContextMenu(const QPoint& menu_location); |
| 116 | void AddGamePopup(QMenu& context_menu, u64 program_id, std::string path); | 116 | void AddGamePopup(QMenu& context_menu, u64 program_id, const std::string& path); |
| 117 | void AddCustomDirPopup(QMenu& context_menu, QModelIndex selected); | 117 | void AddCustomDirPopup(QMenu& context_menu, QModelIndex selected); |
| 118 | void AddPermDirPopup(QMenu& context_menu, QModelIndex selected); | 118 | void AddPermDirPopup(QMenu& context_menu, QModelIndex selected); |
| 119 | 119 | ||
diff --git a/src/yuzu/install_dialog.h b/src/yuzu/install_dialog.h index e4aba1b06..68e03fe4e 100644 --- a/src/yuzu/install_dialog.h +++ b/src/yuzu/install_dialog.h | |||
| @@ -20,9 +20,8 @@ public: | |||
| 20 | explicit InstallDialog(QWidget* parent, const QStringList& files); | 20 | explicit InstallDialog(QWidget* parent, const QStringList& files); |
| 21 | ~InstallDialog() override; | 21 | ~InstallDialog() override; |
| 22 | 22 | ||
| 23 | QStringList GetFiles() const; | 23 | [[nodiscard]] QStringList GetFiles() const; |
| 24 | bool ShouldOverwriteFiles() const; | 24 | [[nodiscard]] int GetMinimumWidth() const; |
| 25 | int GetMinimumWidth() const; | ||
| 26 | 25 | ||
| 27 | private: | 26 | private: |
| 28 | QListWidget* file_list; | 27 | QListWidget* file_list; |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index bb3a08ac7..6a2a88dd8 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -838,7 +838,7 @@ void GMainWindow::RestoreUIState() { | |||
| 838 | OnDisplayTitleBars(ui.action_Display_Dock_Widget_Headers->isChecked()); | 838 | OnDisplayTitleBars(ui.action_Display_Dock_Widget_Headers->isChecked()); |
| 839 | 839 | ||
| 840 | ui.action_Show_Filter_Bar->setChecked(UISettings::values.show_filter_bar); | 840 | ui.action_Show_Filter_Bar->setChecked(UISettings::values.show_filter_bar); |
| 841 | game_list->setFilterVisible(ui.action_Show_Filter_Bar->isChecked()); | 841 | game_list->SetFilterVisible(ui.action_Show_Filter_Bar->isChecked()); |
| 842 | 842 | ||
| 843 | ui.action_Show_Status_Bar->setChecked(UISettings::values.show_status_bar); | 843 | ui.action_Show_Status_Bar->setChecked(UISettings::values.show_status_bar); |
| 844 | statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked()); | 844 | statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked()); |
| @@ -1199,11 +1199,12 @@ void GMainWindow::ShutdownGame() { | |||
| 1199 | render_window->hide(); | 1199 | render_window->hide(); |
| 1200 | loading_screen->hide(); | 1200 | loading_screen->hide(); |
| 1201 | loading_screen->Clear(); | 1201 | loading_screen->Clear(); |
| 1202 | if (game_list->isEmpty()) | 1202 | if (game_list->IsEmpty()) { |
| 1203 | game_list_placeholder->show(); | 1203 | game_list_placeholder->show(); |
| 1204 | else | 1204 | } else { |
| 1205 | game_list->show(); | 1205 | game_list->show(); |
| 1206 | game_list->setFilterFocus(); | 1206 | } |
| 1207 | game_list->SetFilterFocus(); | ||
| 1207 | 1208 | ||
| 1208 | setMouseTracking(false); | 1209 | setMouseTracking(false); |
| 1209 | ui.centralwidget->setMouseTracking(false); | 1210 | ui.centralwidget->setMouseTracking(false); |
| @@ -2361,11 +2362,11 @@ void GMainWindow::OnAbout() { | |||
| 2361 | } | 2362 | } |
| 2362 | 2363 | ||
| 2363 | void GMainWindow::OnToggleFilterBar() { | 2364 | void GMainWindow::OnToggleFilterBar() { |
| 2364 | game_list->setFilterVisible(ui.action_Show_Filter_Bar->isChecked()); | 2365 | game_list->SetFilterVisible(ui.action_Show_Filter_Bar->isChecked()); |
| 2365 | if (ui.action_Show_Filter_Bar->isChecked()) { | 2366 | if (ui.action_Show_Filter_Bar->isChecked()) { |
| 2366 | game_list->setFilterFocus(); | 2367 | game_list->SetFilterFocus(); |
| 2367 | } else { | 2368 | } else { |
| 2368 | game_list->clearFilter(); | 2369 | game_list->ClearFilter(); |
| 2369 | } | 2370 | } |
| 2370 | } | 2371 | } |
| 2371 | 2372 | ||
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp index a804d5185..521209622 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp | |||
| @@ -13,9 +13,8 @@ | |||
| 13 | #include "input_common/sdl/sdl.h" | 13 | #include "input_common/sdl/sdl.h" |
| 14 | #include "yuzu_cmd/emu_window/emu_window_sdl2.h" | 14 | #include "yuzu_cmd/emu_window/emu_window_sdl2.h" |
| 15 | 15 | ||
| 16 | EmuWindow_SDL2::EmuWindow_SDL2(Core::System& system, bool fullscreen, | 16 | EmuWindow_SDL2::EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem_) |
| 17 | InputCommon::InputSubsystem* input_subsystem_) | 17 | : input_subsystem{input_subsystem_} { |
| 18 | : system{system}, input_subsystem{input_subsystem_} { | ||
| 19 | if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) { | 18 | if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) { |
| 20 | LOG_CRITICAL(Frontend, "Failed to initialize SDL2! Exiting..."); | 19 | LOG_CRITICAL(Frontend, "Failed to initialize SDL2! Exiting..."); |
| 21 | exit(1); | 20 | exit(1); |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.h b/src/yuzu_cmd/emu_window/emu_window_sdl2.h index 82750ffec..53d756c3c 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.h +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.h | |||
| @@ -20,8 +20,7 @@ class InputSubsystem; | |||
| 20 | 20 | ||
| 21 | class EmuWindow_SDL2 : public Core::Frontend::EmuWindow { | 21 | class EmuWindow_SDL2 : public Core::Frontend::EmuWindow { |
| 22 | public: | 22 | public: |
| 23 | explicit EmuWindow_SDL2(Core::System& system, bool fullscreen, | 23 | explicit EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem); |
| 24 | InputCommon::InputSubsystem* input_subsystem); | ||
| 25 | ~EmuWindow_SDL2(); | 24 | ~EmuWindow_SDL2(); |
| 26 | 25 | ||
| 27 | /// Polls window events | 26 | /// Polls window events |
| @@ -33,9 +32,6 @@ public: | |||
| 33 | /// Returns if window is shown (not minimized) | 32 | /// Returns if window is shown (not minimized) |
| 34 | bool IsShown() const override; | 33 | bool IsShown() const override; |
| 35 | 34 | ||
| 36 | /// Presents the next frame | ||
| 37 | virtual void Present() = 0; | ||
| 38 | |||
| 39 | protected: | 35 | protected: |
| 40 | /// Called by PollEvents when a key is pressed or released. | 36 | /// Called by PollEvents when a key is pressed or released. |
| 41 | void OnKeyEvent(int key, u8 state); | 37 | void OnKeyEvent(int key, u8 state); |
| @@ -67,9 +63,6 @@ protected: | |||
| 67 | /// Called when a configuration change affects the minimal size of the window | 63 | /// Called when a configuration change affects the minimal size of the window |
| 68 | void OnMinimalClientAreaChangeRequest(std::pair<unsigned, unsigned> minimal_size) override; | 64 | void OnMinimalClientAreaChangeRequest(std::pair<unsigned, unsigned> minimal_size) override; |
| 69 | 65 | ||
| 70 | /// Instance of the system, used to access renderer for the presentation thread | ||
| 71 | Core::System& system; | ||
| 72 | |||
| 73 | /// Is the window still open? | 66 | /// Is the window still open? |
| 74 | bool is_open = true; | 67 | bool is_open = true; |
| 75 | 68 | ||
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp index 881b67a76..5f35233b5 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp | |||
| @@ -87,9 +87,8 @@ bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() { | |||
| 87 | return unsupported_ext.empty(); | 87 | return unsupported_ext.empty(); |
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(Core::System& system, bool fullscreen, | 90 | EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem, bool fullscreen) |
| 91 | InputCommon::InputSubsystem* input_subsystem) | 91 | : EmuWindow_SDL2{input_subsystem} { |
| 92 | : EmuWindow_SDL2{system, fullscreen, input_subsystem} { | ||
| 93 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); | 92 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); |
| 94 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); | 93 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); |
| 95 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); | 94 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); |
| @@ -163,13 +162,3 @@ EmuWindow_SDL2_GL::~EmuWindow_SDL2_GL() { | |||
| 163 | std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL2_GL::CreateSharedContext() const { | 162 | std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL2_GL::CreateSharedContext() const { |
| 164 | return std::make_unique<SDLGLContext>(); | 163 | return std::make_unique<SDLGLContext>(); |
| 165 | } | 164 | } |
| 166 | |||
| 167 | void EmuWindow_SDL2_GL::Present() { | ||
| 168 | SDL_GL_MakeCurrent(render_window, window_context); | ||
| 169 | SDL_GL_SetSwapInterval(Settings::values.use_vsync.GetValue() ? 1 : 0); | ||
| 170 | while (IsOpen()) { | ||
| 171 | system.Renderer().TryPresent(100); | ||
| 172 | SDL_GL_SwapWindow(render_window); | ||
| 173 | } | ||
| 174 | SDL_GL_MakeCurrent(render_window, nullptr); | ||
| 175 | } | ||
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h index 732a64edd..dba5c293c 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h | |||
| @@ -14,12 +14,9 @@ class InputSubsystem; | |||
| 14 | 14 | ||
| 15 | class EmuWindow_SDL2_GL final : public EmuWindow_SDL2 { | 15 | class EmuWindow_SDL2_GL final : public EmuWindow_SDL2 { |
| 16 | public: | 16 | public: |
| 17 | explicit EmuWindow_SDL2_GL(Core::System& system, bool fullscreen, | 17 | explicit EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem, bool fullscreen); |
| 18 | InputCommon::InputSubsystem* input_subsystem); | ||
| 19 | ~EmuWindow_SDL2_GL(); | 18 | ~EmuWindow_SDL2_GL(); |
| 20 | 19 | ||
| 21 | void Present() override; | ||
| 22 | |||
| 23 | std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override; | 20 | std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override; |
| 24 | 21 | ||
| 25 | private: | 22 | private: |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp index 53491f86e..3ba657c00 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp | |||
| @@ -19,9 +19,8 @@ | |||
| 19 | #include <SDL.h> | 19 | #include <SDL.h> |
| 20 | #include <SDL_syswm.h> | 20 | #include <SDL_syswm.h> |
| 21 | 21 | ||
| 22 | EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(Core::System& system, bool fullscreen, | 22 | EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsystem) |
| 23 | InputCommon::InputSubsystem* input_subsystem) | 23 | : EmuWindow_SDL2{input_subsystem} { |
| 24 | : EmuWindow_SDL2{system, fullscreen, input_subsystem} { | ||
| 25 | const std::string window_title = fmt::format("yuzu {} | {}-{} (Vulkan)", Common::g_build_name, | 24 | const std::string window_title = fmt::format("yuzu {} | {}-{} (Vulkan)", Common::g_build_name, |
| 26 | Common::g_scm_branch, Common::g_scm_desc); | 25 | Common::g_scm_branch, Common::g_scm_desc); |
| 27 | render_window = | 26 | render_window = |
| @@ -74,7 +73,3 @@ EmuWindow_SDL2_VK::~EmuWindow_SDL2_VK() = default; | |||
| 74 | std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL2_VK::CreateSharedContext() const { | 73 | std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL2_VK::CreateSharedContext() const { |
| 75 | return std::make_unique<DummyContext>(); | 74 | return std::make_unique<DummyContext>(); |
| 76 | } | 75 | } |
| 77 | |||
| 78 | void EmuWindow_SDL2_VK::Present() { | ||
| 79 | // TODO (bunnei): ImplementMe | ||
| 80 | } | ||
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h index f99704d4c..bdfdc3c6f 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h | |||
| @@ -19,11 +19,8 @@ class InputSubsystem; | |||
| 19 | 19 | ||
| 20 | class EmuWindow_SDL2_VK final : public EmuWindow_SDL2 { | 20 | class EmuWindow_SDL2_VK final : public EmuWindow_SDL2 { |
| 21 | public: | 21 | public: |
| 22 | explicit EmuWindow_SDL2_VK(Core::System& system, bool fullscreen, | 22 | explicit EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsystem); |
| 23 | InputCommon::InputSubsystem* input_subsystem); | 23 | ~EmuWindow_SDL2_VK() override; |
| 24 | ~EmuWindow_SDL2_VK(); | ||
| 25 | |||
| 26 | void Present() override; | ||
| 27 | 24 | ||
| 28 | std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override; | 25 | std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override; |
| 29 | }; | 26 | }; |
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index e960b5413..3a76c785f 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp | |||
| @@ -185,11 +185,11 @@ int main(int argc, char** argv) { | |||
| 185 | std::unique_ptr<EmuWindow_SDL2> emu_window; | 185 | std::unique_ptr<EmuWindow_SDL2> emu_window; |
| 186 | switch (Settings::values.renderer_backend.GetValue()) { | 186 | switch (Settings::values.renderer_backend.GetValue()) { |
| 187 | case Settings::RendererBackend::OpenGL: | 187 | case Settings::RendererBackend::OpenGL: |
| 188 | emu_window = std::make_unique<EmuWindow_SDL2_GL>(system, fullscreen, &input_subsystem); | 188 | emu_window = std::make_unique<EmuWindow_SDL2_GL>(&input_subsystem, fullscreen); |
| 189 | break; | 189 | break; |
| 190 | case Settings::RendererBackend::Vulkan: | 190 | case Settings::RendererBackend::Vulkan: |
| 191 | #ifdef HAS_VULKAN | 191 | #ifdef HAS_VULKAN |
| 192 | emu_window = std::make_unique<EmuWindow_SDL2_VK>(system, fullscreen, &input_subsystem); | 192 | emu_window = std::make_unique<EmuWindow_SDL2_VK>(&input_subsystem); |
| 193 | break; | 193 | break; |
| 194 | #else | 194 | #else |
| 195 | LOG_CRITICAL(Frontend, "Vulkan backend has not been compiled!"); | 195 | LOG_CRITICAL(Frontend, "Vulkan backend has not been compiled!"); |
| @@ -240,14 +240,11 @@ int main(int argc, char** argv) { | |||
| 240 | system.CurrentProcess()->GetTitleID(), false, | 240 | system.CurrentProcess()->GetTitleID(), false, |
| 241 | [](VideoCore::LoadCallbackStage, size_t value, size_t total) {}); | 241 | [](VideoCore::LoadCallbackStage, size_t value, size_t total) {}); |
| 242 | 242 | ||
| 243 | std::thread render_thread([&emu_window] { emu_window->Present(); }); | ||
| 244 | system.Run(); | 243 | system.Run(); |
| 245 | while (emu_window->IsOpen()) { | 244 | while (emu_window->IsOpen()) { |
| 246 | std::this_thread::sleep_for(std::chrono::milliseconds(1)); | 245 | std::this_thread::sleep_for(std::chrono::milliseconds(1)); |
| 247 | } | 246 | } |
| 248 | system.Pause(); | 247 | system.Pause(); |
| 249 | render_thread.join(); | ||
| 250 | |||
| 251 | system.Shutdown(); | 248 | system.Shutdown(); |
| 252 | 249 | ||
| 253 | detached_tasks.WaitForAllTasks(); | 250 | detached_tasks.WaitForAllTasks(); |