diff options
Diffstat (limited to 'src')
35 files changed, 515 insertions, 201 deletions
diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp index c8fa912bf..e065e592f 100644 --- a/src/core/file_sys/control_metadata.cpp +++ b/src/core/file_sys/control_metadata.cpp | |||
| @@ -8,13 +8,23 @@ | |||
| 8 | 8 | ||
| 9 | namespace FileSys { | 9 | namespace FileSys { |
| 10 | 10 | ||
| 11 | const std::array<const char*, 15> LANGUAGE_NAMES = { | 11 | const std::array<const char*, 15> LANGUAGE_NAMES{{ |
| 12 | "AmericanEnglish", "BritishEnglish", "Japanese", | 12 | "AmericanEnglish", |
| 13 | "French", "German", "LatinAmericanSpanish", | 13 | "BritishEnglish", |
| 14 | "Spanish", "Italian", "Dutch", | 14 | "Japanese", |
| 15 | "CanadianFrench", "Portugese", "Russian", | 15 | "French", |
| 16 | "Korean", "Taiwanese", "Chinese", | 16 | "German", |
| 17 | }; | 17 | "LatinAmericanSpanish", |
| 18 | "Spanish", | ||
| 19 | "Italian", | ||
| 20 | "Dutch", | ||
| 21 | "CanadianFrench", | ||
| 22 | "Portuguese", | ||
| 23 | "Russian", | ||
| 24 | "Korean", | ||
| 25 | "Taiwanese", | ||
| 26 | "Chinese", | ||
| 27 | }}; | ||
| 18 | 28 | ||
| 19 | std::string LanguageEntry::GetApplicationName() const { | 29 | std::string LanguageEntry::GetApplicationName() const { |
| 20 | return Common::StringFromFixedZeroTerminatedBuffer(application_name.data(), | 30 | return Common::StringFromFixedZeroTerminatedBuffer(application_name.data(), |
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index a3f8f2f73..07c3af64a 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp | |||
| @@ -381,22 +381,22 @@ std::vector<RegisteredCacheEntry> RegisteredCache::ListEntriesFilter( | |||
| 381 | return out; | 381 | return out; |
| 382 | } | 382 | } |
| 383 | 383 | ||
| 384 | static std::shared_ptr<NCA> GetNCAFromNSPForID(std::shared_ptr<NSP> nsp, const NcaID& id) { | 384 | static std::shared_ptr<NCA> GetNCAFromNSPForID(const NSP& nsp, const NcaID& id) { |
| 385 | const auto file = nsp->GetFile(fmt::format("{}.nca", Common::HexArrayToString(id, false))); | 385 | const auto file = nsp.GetFile(fmt::format("{}.nca", Common::HexArrayToString(id, false))); |
| 386 | if (file == nullptr) | 386 | if (file == nullptr) |
| 387 | return nullptr; | 387 | return nullptr; |
| 388 | return std::make_shared<NCA>(file); | 388 | return std::make_shared<NCA>(file); |
| 389 | } | 389 | } |
| 390 | 390 | ||
| 391 | InstallResult RegisteredCache::InstallEntry(std::shared_ptr<XCI> xci, bool overwrite_if_exists, | 391 | InstallResult RegisteredCache::InstallEntry(const XCI& xci, bool overwrite_if_exists, |
| 392 | const VfsCopyFunction& copy) { | 392 | const VfsCopyFunction& copy) { |
| 393 | return InstallEntry(xci->GetSecurePartitionNSP(), overwrite_if_exists, copy); | 393 | return InstallEntry(*xci.GetSecurePartitionNSP(), overwrite_if_exists, copy); |
| 394 | } | 394 | } |
| 395 | 395 | ||
| 396 | InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NSP> nsp, bool overwrite_if_exists, | 396 | InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_exists, |
| 397 | const VfsCopyFunction& copy) { | 397 | const VfsCopyFunction& copy) { |
| 398 | const auto& ncas = nsp->GetNCAsCollapsed(); | 398 | const auto ncas = nsp.GetNCAsCollapsed(); |
| 399 | const auto& meta_iter = std::find_if(ncas.begin(), ncas.end(), [](std::shared_ptr<NCA> nca) { | 399 | const auto meta_iter = std::find_if(ncas.begin(), ncas.end(), [](const auto& nca) { |
| 400 | return nca->GetType() == NCAContentType::Meta; | 400 | return nca->GetType() == NCAContentType::Meta; |
| 401 | }); | 401 | }); |
| 402 | 402 | ||
| @@ -410,7 +410,7 @@ InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NSP> nsp, bool overw | |||
| 410 | const auto meta_id_raw = (*meta_iter)->GetName().substr(0, 32); | 410 | const auto meta_id_raw = (*meta_iter)->GetName().substr(0, 32); |
| 411 | const auto meta_id = Common::HexStringToArray<16>(meta_id_raw); | 411 | const auto meta_id = Common::HexStringToArray<16>(meta_id_raw); |
| 412 | 412 | ||
| 413 | const auto res = RawInstallNCA(*meta_iter, copy, overwrite_if_exists, meta_id); | 413 | const auto res = RawInstallNCA(**meta_iter, copy, overwrite_if_exists, meta_id); |
| 414 | if (res != InstallResult::Success) | 414 | if (res != InstallResult::Success) |
| 415 | return res; | 415 | return res; |
| 416 | 416 | ||
| @@ -422,7 +422,7 @@ InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NSP> nsp, bool overw | |||
| 422 | const auto nca = GetNCAFromNSPForID(nsp, record.nca_id); | 422 | const auto nca = GetNCAFromNSPForID(nsp, record.nca_id); |
| 423 | if (nca == nullptr) | 423 | if (nca == nullptr) |
| 424 | return InstallResult::ErrorCopyFailed; | 424 | return InstallResult::ErrorCopyFailed; |
| 425 | const auto res2 = RawInstallNCA(nca, copy, overwrite_if_exists, record.nca_id); | 425 | const auto res2 = RawInstallNCA(*nca, copy, overwrite_if_exists, record.nca_id); |
| 426 | if (res2 != InstallResult::Success) | 426 | if (res2 != InstallResult::Success) |
| 427 | return res2; | 427 | return res2; |
| 428 | } | 428 | } |
| @@ -431,21 +431,21 @@ InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NSP> nsp, bool overw | |||
| 431 | return InstallResult::Success; | 431 | return InstallResult::Success; |
| 432 | } | 432 | } |
| 433 | 433 | ||
| 434 | InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NCA> nca, TitleType type, | 434 | InstallResult RegisteredCache::InstallEntry(const NCA& nca, TitleType type, |
| 435 | bool overwrite_if_exists, const VfsCopyFunction& copy) { | 435 | bool overwrite_if_exists, const VfsCopyFunction& copy) { |
| 436 | CNMTHeader header{ | 436 | CNMTHeader header{ |
| 437 | nca->GetTitleId(), ///< Title ID | 437 | nca.GetTitleId(), ///< Title ID |
| 438 | 0, ///< Ignore/Default title version | 438 | 0, ///< Ignore/Default title version |
| 439 | type, ///< Type | 439 | type, ///< Type |
| 440 | {}, ///< Padding | 440 | {}, ///< Padding |
| 441 | 0x10, ///< Default table offset | 441 | 0x10, ///< Default table offset |
| 442 | 1, ///< 1 Content Entry | 442 | 1, ///< 1 Content Entry |
| 443 | 0, ///< No Meta Entries | 443 | 0, ///< No Meta Entries |
| 444 | {}, ///< Padding | 444 | {}, ///< Padding |
| 445 | }; | 445 | }; |
| 446 | OptionalHeader opt_header{0, 0}; | 446 | OptionalHeader opt_header{0, 0}; |
| 447 | ContentRecord c_rec{{}, {}, {}, GetCRTypeFromNCAType(nca->GetType()), {}}; | 447 | ContentRecord c_rec{{}, {}, {}, GetCRTypeFromNCAType(nca.GetType()), {}}; |
| 448 | const auto& data = nca->GetBaseFile()->ReadBytes(0x100000); | 448 | const auto& data = nca.GetBaseFile()->ReadBytes(0x100000); |
| 449 | mbedtls_sha256(data.data(), data.size(), c_rec.hash.data(), 0); | 449 | mbedtls_sha256(data.data(), data.size(), c_rec.hash.data(), 0); |
| 450 | memcpy(&c_rec.nca_id, &c_rec.hash, 16); | 450 | memcpy(&c_rec.nca_id, &c_rec.hash, 16); |
| 451 | const CNMT new_cnmt(header, opt_header, {c_rec}, {}); | 451 | const CNMT new_cnmt(header, opt_header, {c_rec}, {}); |
| @@ -454,10 +454,10 @@ InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NCA> nca, TitleType | |||
| 454 | return RawInstallNCA(nca, copy, overwrite_if_exists, c_rec.nca_id); | 454 | return RawInstallNCA(nca, copy, overwrite_if_exists, c_rec.nca_id); |
| 455 | } | 455 | } |
| 456 | 456 | ||
| 457 | InstallResult RegisteredCache::RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy, | 457 | InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFunction& copy, |
| 458 | bool overwrite_if_exists, | 458 | bool overwrite_if_exists, |
| 459 | std::optional<NcaID> override_id) { | 459 | std::optional<NcaID> override_id) { |
| 460 | const auto in = nca->GetBaseFile(); | 460 | const auto in = nca.GetBaseFile(); |
| 461 | Core::Crypto::SHA256Hash hash{}; | 461 | Core::Crypto::SHA256Hash hash{}; |
| 462 | 462 | ||
| 463 | // Calculate NcaID | 463 | // Calculate NcaID |
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h index 6b89db8de..3b77af4e0 100644 --- a/src/core/file_sys/registered_cache.h +++ b/src/core/file_sys/registered_cache.h | |||
| @@ -6,7 +6,6 @@ | |||
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <functional> | 8 | #include <functional> |
| 9 | #include <map> | ||
| 10 | #include <memory> | 9 | #include <memory> |
| 11 | #include <string> | 10 | #include <string> |
| 12 | #include <vector> | 11 | #include <vector> |
| @@ -104,17 +103,16 @@ public: | |||
| 104 | 103 | ||
| 105 | // Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure | 104 | // Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure |
| 106 | // there is a meta NCA and all of them are accessible. | 105 | // there is a meta NCA and all of them are accessible. |
| 107 | InstallResult InstallEntry(std::shared_ptr<XCI> xci, bool overwrite_if_exists = false, | 106 | InstallResult InstallEntry(const XCI& xci, bool overwrite_if_exists = false, |
| 108 | const VfsCopyFunction& copy = &VfsRawCopy); | 107 | const VfsCopyFunction& copy = &VfsRawCopy); |
| 109 | InstallResult InstallEntry(std::shared_ptr<NSP> nsp, bool overwrite_if_exists = false, | 108 | InstallResult InstallEntry(const NSP& nsp, bool overwrite_if_exists = false, |
| 110 | const VfsCopyFunction& copy = &VfsRawCopy); | 109 | const VfsCopyFunction& copy = &VfsRawCopy); |
| 111 | 110 | ||
| 112 | // Due to the fact that we must use Meta-type NCAs to determine the existance of files, this | 111 | // Due to the fact that we must use Meta-type NCAs to determine the existance of files, this |
| 113 | // poses quite a challenge. Instead of creating a new meta NCA for this file, yuzu will create a | 112 | // poses quite a challenge. Instead of creating a new meta NCA for this file, yuzu will create a |
| 114 | // dir inside the NAND called 'yuzu_meta' and store the raw CNMT there. | 113 | // dir inside the NAND called 'yuzu_meta' and store the raw CNMT there. |
| 115 | // TODO(DarkLordZach): Author real meta-type NCAs and install those. | 114 | // TODO(DarkLordZach): Author real meta-type NCAs and install those. |
| 116 | InstallResult InstallEntry(std::shared_ptr<NCA> nca, TitleType type, | 115 | InstallResult InstallEntry(const NCA& nca, TitleType type, bool overwrite_if_exists = false, |
| 117 | bool overwrite_if_exists = false, | ||
| 118 | const VfsCopyFunction& copy = &VfsRawCopy); | 116 | const VfsCopyFunction& copy = &VfsRawCopy); |
| 119 | 117 | ||
| 120 | private: | 118 | private: |
| @@ -128,7 +126,7 @@ private: | |||
| 128 | std::optional<NcaID> GetNcaIDFromMetadata(u64 title_id, ContentRecordType type) const; | 126 | std::optional<NcaID> GetNcaIDFromMetadata(u64 title_id, ContentRecordType type) const; |
| 129 | VirtualFile GetFileAtID(NcaID id) const; | 127 | VirtualFile GetFileAtID(NcaID id) const; |
| 130 | VirtualFile OpenFileOrDirectoryConcat(const VirtualDir& dir, std::string_view path) const; | 128 | VirtualFile OpenFileOrDirectoryConcat(const VirtualDir& dir, std::string_view path) const; |
| 131 | InstallResult RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy, | 129 | InstallResult RawInstallNCA(const NCA& nca, const VfsCopyFunction& copy, |
| 132 | bool overwrite_if_exists, std::optional<NcaID> override_id = {}); | 130 | bool overwrite_if_exists, std::optional<NcaID> override_id = {}); |
| 133 | bool RawInstallYuzuMeta(const CNMT& cnmt); | 131 | bool RawInstallYuzuMeta(const CNMT& cnmt); |
| 134 | 132 | ||
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 687dea409..e6b5171ee 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp | |||
| @@ -282,7 +282,7 @@ static void FpuWrite(std::size_t id, u128 val, Kernel::Thread* thread = nullptr) | |||
| 282 | if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { | 282 | if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { |
| 283 | thread_context.vector_registers[id - UC_ARM64_REG_Q0] = val; | 283 | thread_context.vector_registers[id - UC_ARM64_REG_Q0] = val; |
| 284 | } else if (id == FPCR_REGISTER) { | 284 | } else if (id == FPCR_REGISTER) { |
| 285 | thread_context.fpcr = val[0]; | 285 | thread_context.fpcr = static_cast<u32>(val[0]); |
| 286 | } | 286 | } |
| 287 | } | 287 | } |
| 288 | 288 | ||
diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h index bec065543..59dc11c22 100644 --- a/src/core/hle/kernel/resource_limit.h +++ b/src/core/hle/kernel/resource_limit.h | |||
| @@ -14,7 +14,7 @@ namespace Kernel { | |||
| 14 | 14 | ||
| 15 | class KernelCore; | 15 | class KernelCore; |
| 16 | 16 | ||
| 17 | enum class ResourceType { | 17 | enum class ResourceType : u32 { |
| 18 | PhysicalMemory, | 18 | PhysicalMemory, |
| 19 | Threads, | 19 | Threads, |
| 20 | Events, | 20 | Events, |
| @@ -25,6 +25,10 @@ enum class ResourceType { | |||
| 25 | ResourceTypeCount | 25 | ResourceTypeCount |
| 26 | }; | 26 | }; |
| 27 | 27 | ||
| 28 | constexpr bool IsValidResourceType(ResourceType type) { | ||
| 29 | return type < ResourceType::ResourceTypeCount; | ||
| 30 | } | ||
| 31 | |||
| 28 | class ResourceLimit final : public Object { | 32 | class ResourceLimit final : public Object { |
| 29 | public: | 33 | public: |
| 30 | /** | 34 | /** |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index f287f7c97..1f19d5576 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -105,6 +105,38 @@ ResultCode MapUnmapMemorySanityChecks(const VMManager& vm_manager, VAddr dst_add | |||
| 105 | 105 | ||
| 106 | return RESULT_SUCCESS; | 106 | return RESULT_SUCCESS; |
| 107 | } | 107 | } |
| 108 | |||
| 109 | enum class ResourceLimitValueType { | ||
| 110 | CurrentValue, | ||
| 111 | LimitValue, | ||
| 112 | }; | ||
| 113 | |||
| 114 | ResultVal<s64> RetrieveResourceLimitValue(Handle resource_limit, u32 resource_type, | ||
| 115 | ResourceLimitValueType value_type) { | ||
| 116 | const auto type = static_cast<ResourceType>(resource_type); | ||
| 117 | if (!IsValidResourceType(type)) { | ||
| 118 | LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type); | ||
| 119 | return ERR_INVALID_ENUM_VALUE; | ||
| 120 | } | ||
| 121 | |||
| 122 | const auto& kernel = Core::System::GetInstance().Kernel(); | ||
| 123 | const auto* const current_process = kernel.CurrentProcess(); | ||
| 124 | ASSERT(current_process != nullptr); | ||
| 125 | |||
| 126 | const auto resource_limit_object = | ||
| 127 | current_process->GetHandleTable().Get<ResourceLimit>(resource_limit); | ||
| 128 | if (!resource_limit_object) { | ||
| 129 | LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}", | ||
| 130 | resource_limit); | ||
| 131 | return ERR_INVALID_HANDLE; | ||
| 132 | } | ||
| 133 | |||
| 134 | if (value_type == ResourceLimitValueType::CurrentValue) { | ||
| 135 | return MakeResult(resource_limit_object->GetCurrentResourceValue(type)); | ||
| 136 | } | ||
| 137 | |||
| 138 | return MakeResult(resource_limit_object->GetMaxResourceValue(type)); | ||
| 139 | } | ||
| 108 | } // Anonymous namespace | 140 | } // Anonymous namespace |
| 109 | 141 | ||
| 110 | /// Set the process heap to a given Size. It can both extend and shrink the heap. | 142 | /// Set the process heap to a given Size. It can both extend and shrink the heap. |
| @@ -1346,6 +1378,87 @@ static ResultCode GetProcessInfo(u64* out, Handle process_handle, u32 type) { | |||
| 1346 | return RESULT_SUCCESS; | 1378 | return RESULT_SUCCESS; |
| 1347 | } | 1379 | } |
| 1348 | 1380 | ||
| 1381 | static ResultCode CreateResourceLimit(Handle* out_handle) { | ||
| 1382 | LOG_DEBUG(Kernel_SVC, "called"); | ||
| 1383 | |||
| 1384 | auto& kernel = Core::System::GetInstance().Kernel(); | ||
| 1385 | auto resource_limit = ResourceLimit::Create(kernel); | ||
| 1386 | |||
| 1387 | auto* const current_process = kernel.CurrentProcess(); | ||
| 1388 | ASSERT(current_process != nullptr); | ||
| 1389 | |||
| 1390 | const auto handle = current_process->GetHandleTable().Create(std::move(resource_limit)); | ||
| 1391 | if (handle.Failed()) { | ||
| 1392 | return handle.Code(); | ||
| 1393 | } | ||
| 1394 | |||
| 1395 | *out_handle = *handle; | ||
| 1396 | return RESULT_SUCCESS; | ||
| 1397 | } | ||
| 1398 | |||
| 1399 | static ResultCode GetResourceLimitLimitValue(u64* out_value, Handle resource_limit, | ||
| 1400 | u32 resource_type) { | ||
| 1401 | LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type); | ||
| 1402 | |||
| 1403 | const auto limit_value = RetrieveResourceLimitValue(resource_limit, resource_type, | ||
| 1404 | ResourceLimitValueType::LimitValue); | ||
| 1405 | if (limit_value.Failed()) { | ||
| 1406 | return limit_value.Code(); | ||
| 1407 | } | ||
| 1408 | |||
| 1409 | *out_value = static_cast<u64>(*limit_value); | ||
| 1410 | return RESULT_SUCCESS; | ||
| 1411 | } | ||
| 1412 | |||
| 1413 | static ResultCode GetResourceLimitCurrentValue(u64* out_value, Handle resource_limit, | ||
| 1414 | u32 resource_type) { | ||
| 1415 | LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type); | ||
| 1416 | |||
| 1417 | const auto current_value = RetrieveResourceLimitValue(resource_limit, resource_type, | ||
| 1418 | ResourceLimitValueType::CurrentValue); | ||
| 1419 | if (current_value.Failed()) { | ||
| 1420 | return current_value.Code(); | ||
| 1421 | } | ||
| 1422 | |||
| 1423 | *out_value = static_cast<u64>(*current_value); | ||
| 1424 | return RESULT_SUCCESS; | ||
| 1425 | } | ||
| 1426 | |||
| 1427 | static ResultCode SetResourceLimitLimitValue(Handle resource_limit, u32 resource_type, u64 value) { | ||
| 1428 | LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}, Value={}", resource_limit, | ||
| 1429 | resource_type, value); | ||
| 1430 | |||
| 1431 | const auto type = static_cast<ResourceType>(resource_type); | ||
| 1432 | if (!IsValidResourceType(type)) { | ||
| 1433 | LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type); | ||
| 1434 | return ERR_INVALID_ENUM_VALUE; | ||
| 1435 | } | ||
| 1436 | |||
| 1437 | auto& kernel = Core::System::GetInstance().Kernel(); | ||
| 1438 | auto* const current_process = kernel.CurrentProcess(); | ||
| 1439 | ASSERT(current_process != nullptr); | ||
| 1440 | |||
| 1441 | auto resource_limit_object = | ||
| 1442 | current_process->GetHandleTable().Get<ResourceLimit>(resource_limit); | ||
| 1443 | if (!resource_limit_object) { | ||
| 1444 | LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}", | ||
| 1445 | resource_limit); | ||
| 1446 | return ERR_INVALID_HANDLE; | ||
| 1447 | } | ||
| 1448 | |||
| 1449 | const auto set_result = resource_limit_object->SetLimitValue(type, static_cast<s64>(value)); | ||
| 1450 | if (set_result.IsError()) { | ||
| 1451 | LOG_ERROR( | ||
| 1452 | Kernel_SVC, | ||
| 1453 | "Attempted to lower resource limit ({}) for category '{}' below its current value ({})", | ||
| 1454 | resource_limit_object->GetMaxResourceValue(type), resource_type, | ||
| 1455 | resource_limit_object->GetCurrentResourceValue(type)); | ||
| 1456 | return set_result; | ||
| 1457 | } | ||
| 1458 | |||
| 1459 | return RESULT_SUCCESS; | ||
| 1460 | } | ||
| 1461 | |||
| 1349 | namespace { | 1462 | namespace { |
| 1350 | struct FunctionDef { | 1463 | struct FunctionDef { |
| 1351 | using Func = void(); | 1464 | using Func = void(); |
| @@ -1405,8 +1518,8 @@ static const FunctionDef SVC_Table[] = { | |||
| 1405 | {0x2D, nullptr, "UnmapPhysicalMemory"}, | 1518 | {0x2D, nullptr, "UnmapPhysicalMemory"}, |
| 1406 | {0x2E, nullptr, "GetFutureThreadInfo"}, | 1519 | {0x2E, nullptr, "GetFutureThreadInfo"}, |
| 1407 | {0x2F, nullptr, "GetLastThreadInfo"}, | 1520 | {0x2F, nullptr, "GetLastThreadInfo"}, |
| 1408 | {0x30, nullptr, "GetResourceLimitLimitValue"}, | 1521 | {0x30, SvcWrap<GetResourceLimitLimitValue>, "GetResourceLimitLimitValue"}, |
| 1409 | {0x31, nullptr, "GetResourceLimitCurrentValue"}, | 1522 | {0x31, SvcWrap<GetResourceLimitCurrentValue>, "GetResourceLimitCurrentValue"}, |
| 1410 | {0x32, SvcWrap<SetThreadActivity>, "SetThreadActivity"}, | 1523 | {0x32, SvcWrap<SetThreadActivity>, "SetThreadActivity"}, |
| 1411 | {0x33, SvcWrap<GetThreadContext>, "GetThreadContext"}, | 1524 | {0x33, SvcWrap<GetThreadContext>, "GetThreadContext"}, |
| 1412 | {0x34, SvcWrap<WaitForAddress>, "WaitForAddress"}, | 1525 | {0x34, SvcWrap<WaitForAddress>, "WaitForAddress"}, |
| @@ -1482,8 +1595,8 @@ static const FunctionDef SVC_Table[] = { | |||
| 1482 | {0x7A, nullptr, "StartProcess"}, | 1595 | {0x7A, nullptr, "StartProcess"}, |
| 1483 | {0x7B, nullptr, "TerminateProcess"}, | 1596 | {0x7B, nullptr, "TerminateProcess"}, |
| 1484 | {0x7C, SvcWrap<GetProcessInfo>, "GetProcessInfo"}, | 1597 | {0x7C, SvcWrap<GetProcessInfo>, "GetProcessInfo"}, |
| 1485 | {0x7D, nullptr, "CreateResourceLimit"}, | 1598 | {0x7D, SvcWrap<CreateResourceLimit>, "CreateResourceLimit"}, |
| 1486 | {0x7E, nullptr, "SetResourceLimitLimitValue"}, | 1599 | {0x7E, SvcWrap<SetResourceLimitLimitValue>, "SetResourceLimitLimitValue"}, |
| 1487 | {0x7F, nullptr, "CallSecureMonitor"}, | 1600 | {0x7F, nullptr, "CallSecureMonitor"}, |
| 1488 | }; | 1601 | }; |
| 1489 | 1602 | ||
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 233a99fb0..fa1116624 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h | |||
| @@ -43,6 +43,14 @@ void SvcWrap() { | |||
| 43 | FuncReturn(func(static_cast<u32>(Param(0)), static_cast<u32>(Param(1))).raw); | 43 | FuncReturn(func(static_cast<u32>(Param(0)), static_cast<u32>(Param(1))).raw); |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | template <ResultCode func(u32*)> | ||
| 47 | void SvcWrap() { | ||
| 48 | u32 param = 0; | ||
| 49 | const u32 retval = func(¶m).raw; | ||
| 50 | Core::CurrentArmInterface().SetReg(1, param); | ||
| 51 | FuncReturn(retval); | ||
| 52 | } | ||
| 53 | |||
| 46 | template <ResultCode func(u32*, u32)> | 54 | template <ResultCode func(u32*, u32)> |
| 47 | void SvcWrap() { | 55 | void SvcWrap() { |
| 48 | u32 param_1 = 0; | 56 | u32 param_1 = 0; |
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index c629f9357..9521431bb 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp | |||
| @@ -21,17 +21,6 @@ | |||
| 21 | 21 | ||
| 22 | namespace Service::Account { | 22 | namespace Service::Account { |
| 23 | 23 | ||
| 24 | // TODO: RE this structure | ||
| 25 | struct UserData { | ||
| 26 | INSERT_PADDING_WORDS(1); | ||
| 27 | u32 icon_id; | ||
| 28 | u8 bg_color_id; | ||
| 29 | INSERT_PADDING_BYTES(0x7); | ||
| 30 | INSERT_PADDING_BYTES(0x10); | ||
| 31 | INSERT_PADDING_BYTES(0x60); | ||
| 32 | }; | ||
| 33 | static_assert(sizeof(UserData) == 0x80, "UserData structure has incorrect size"); | ||
| 34 | |||
| 35 | // Smallest JPEG https://github.com/mathiasbynens/small/blob/master/jpeg.jpg | 24 | // Smallest JPEG https://github.com/mathiasbynens/small/blob/master/jpeg.jpg |
| 36 | // used as a backup should the one on disk not exist | 25 | // used as a backup should the one on disk not exist |
| 37 | constexpr u32 backup_jpeg_size = 107; | 26 | constexpr u32 backup_jpeg_size = 107; |
| @@ -72,9 +61,11 @@ private: | |||
| 72 | void Get(Kernel::HLERequestContext& ctx) { | 61 | void Get(Kernel::HLERequestContext& ctx) { |
| 73 | LOG_INFO(Service_ACC, "called user_id={}", user_id.Format()); | 62 | LOG_INFO(Service_ACC, "called user_id={}", user_id.Format()); |
| 74 | ProfileBase profile_base{}; | 63 | ProfileBase profile_base{}; |
| 75 | std::array<u8, MAX_DATA> data{}; | 64 | ProfileData data{}; |
| 76 | if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) { | 65 | if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) { |
| 77 | ctx.WriteBuffer(data); | 66 | std::array<u8, sizeof(ProfileData)> raw_data; |
| 67 | std::memcpy(raw_data.data(), &data, sizeof(ProfileData)); | ||
| 68 | ctx.WriteBuffer(raw_data); | ||
| 78 | IPC::ResponseBuilder rb{ctx, 16}; | 69 | IPC::ResponseBuilder rb{ctx, 16}; |
| 79 | rb.Push(RESULT_SUCCESS); | 70 | rb.Push(RESULT_SUCCESS); |
| 80 | rb.PushRaw(profile_base); | 71 | rb.PushRaw(profile_base); |
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp index 968263846..1316d0b07 100644 --- a/src/core/hle/service/acc/profile_manager.cpp +++ b/src/core/hle/service/acc/profile_manager.cpp | |||
| @@ -18,7 +18,7 @@ struct UserRaw { | |||
| 18 | UUID uuid2; | 18 | UUID uuid2; |
| 19 | u64 timestamp; | 19 | u64 timestamp; |
| 20 | ProfileUsername username; | 20 | ProfileUsername username; |
| 21 | INSERT_PADDING_BYTES(0x80); | 21 | ProfileData extra_data; |
| 22 | }; | 22 | }; |
| 23 | static_assert(sizeof(UserRaw) == 0xC8, "UserRaw has incorrect size."); | 23 | static_assert(sizeof(UserRaw) == 0xC8, "UserRaw has incorrect size."); |
| 24 | 24 | ||
| @@ -346,7 +346,7 @@ void ProfileManager::ParseUserSaveFile() { | |||
| 346 | continue; | 346 | continue; |
| 347 | } | 347 | } |
| 348 | 348 | ||
| 349 | AddUser({user.uuid, user.username, user.timestamp, {}, false}); | 349 | AddUser({user.uuid, user.username, user.timestamp, user.extra_data, false}); |
| 350 | } | 350 | } |
| 351 | 351 | ||
| 352 | std::stable_partition(profiles.begin(), profiles.end(), | 352 | std::stable_partition(profiles.begin(), profiles.end(), |
| @@ -361,6 +361,7 @@ void ProfileManager::WriteUserSaveFile() { | |||
| 361 | raw.users[i].uuid2 = profiles[i].user_uuid; | 361 | raw.users[i].uuid2 = profiles[i].user_uuid; |
| 362 | raw.users[i].uuid = profiles[i].user_uuid; | 362 | raw.users[i].uuid = profiles[i].user_uuid; |
| 363 | raw.users[i].timestamp = profiles[i].creation_time; | 363 | raw.users[i].timestamp = profiles[i].creation_time; |
| 364 | raw.users[i].extra_data = profiles[i].data; | ||
| 364 | } | 365 | } |
| 365 | 366 | ||
| 366 | const auto raw_path = | 367 | const auto raw_path = |
diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h index d2d8e6c6b..c4ce2e0b3 100644 --- a/src/core/hle/service/acc/profile_manager.h +++ b/src/core/hle/service/acc/profile_manager.h | |||
| @@ -13,7 +13,6 @@ | |||
| 13 | 13 | ||
| 14 | namespace Service::Account { | 14 | namespace Service::Account { |
| 15 | constexpr std::size_t MAX_USERS = 8; | 15 | constexpr std::size_t MAX_USERS = 8; |
| 16 | constexpr std::size_t MAX_DATA = 128; | ||
| 17 | constexpr u128 INVALID_UUID{{0, 0}}; | 16 | constexpr u128 INVALID_UUID{{0, 0}}; |
| 18 | 17 | ||
| 19 | struct UUID { | 18 | struct UUID { |
| @@ -50,9 +49,20 @@ static_assert(sizeof(UUID) == 16, "UUID is an invalid size!"); | |||
| 50 | 49 | ||
| 51 | constexpr std::size_t profile_username_size = 32; | 50 | constexpr std::size_t profile_username_size = 32; |
| 52 | using ProfileUsername = std::array<u8, profile_username_size>; | 51 | using ProfileUsername = std::array<u8, profile_username_size>; |
| 53 | using ProfileData = std::array<u8, MAX_DATA>; | ||
| 54 | using UserIDArray = std::array<UUID, MAX_USERS>; | 52 | using UserIDArray = std::array<UUID, MAX_USERS>; |
| 55 | 53 | ||
| 54 | /// Contains extra data related to a user. | ||
| 55 | /// TODO: RE this structure | ||
| 56 | struct ProfileData { | ||
| 57 | INSERT_PADDING_WORDS(1); | ||
| 58 | u32 icon_id; | ||
| 59 | u8 bg_color_id; | ||
| 60 | INSERT_PADDING_BYTES(0x7); | ||
| 61 | INSERT_PADDING_BYTES(0x10); | ||
| 62 | INSERT_PADDING_BYTES(0x60); | ||
| 63 | }; | ||
| 64 | static_assert(sizeof(ProfileData) == 0x80, "ProfileData structure has incorrect size"); | ||
| 65 | |||
| 56 | /// This holds general information about a users profile. This is where we store all the information | 66 | /// This holds general information about a users profile. This is where we store all the information |
| 57 | /// based on a specific user | 67 | /// based on a specific user |
| 58 | struct ProfileInfo { | 68 | struct ProfileInfo { |
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index ea8057b80..abff6544d 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h | |||
| @@ -80,9 +80,9 @@ public: | |||
| 80 | struct LedPattern { | 80 | struct LedPattern { |
| 81 | explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) { | 81 | explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) { |
| 82 | position1.Assign(light1); | 82 | position1.Assign(light1); |
| 83 | position1.Assign(light2); | 83 | position2.Assign(light2); |
| 84 | position1.Assign(light3); | 84 | position3.Assign(light3); |
| 85 | position1.Assign(light4); | 85 | position4.Assign(light4); |
| 86 | } | 86 | } |
| 87 | union { | 87 | union { |
| 88 | u64 raw{}; | 88 | u64 raw{}; |
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index 28e8c13aa..8b9c548cc 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp | |||
| @@ -34,6 +34,9 @@ MICROPROFILE_DEFINE(ProcessCommandLists, "GPU", "Execute command buffer", MP_RGB | |||
| 34 | void GPU::ProcessCommandLists(const std::vector<CommandListHeader>& commands) { | 34 | void GPU::ProcessCommandLists(const std::vector<CommandListHeader>& commands) { |
| 35 | MICROPROFILE_SCOPE(ProcessCommandLists); | 35 | MICROPROFILE_SCOPE(ProcessCommandLists); |
| 36 | 36 | ||
| 37 | // On entering GPU code, assume all memory may be touched by the ARM core. | ||
| 38 | maxwell_3d->dirty_flags.OnMemoryWrite(); | ||
| 39 | |||
| 37 | auto WriteReg = [this](u32 method, u32 subchannel, u32 value, u32 remaining_params) { | 40 | auto WriteReg = [this](u32 method, u32 subchannel, u32 value, u32 remaining_params) { |
| 38 | LOG_TRACE(HW_GPU, | 41 | LOG_TRACE(HW_GPU, |
| 39 | "Processing method {:08X} on subchannel {} value " | 42 | "Processing method {:08X} on subchannel {} value " |
diff --git a/src/video_core/engines/fermi_2d.cpp b/src/video_core/engines/fermi_2d.cpp index ee8ebf678..e7721a2be 100644 --- a/src/video_core/engines/fermi_2d.cpp +++ b/src/video_core/engines/fermi_2d.cpp | |||
| @@ -2,8 +2,10 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "core/core.h" | ||
| 5 | #include "core/memory.h" | 6 | #include "core/memory.h" |
| 6 | #include "video_core/engines/fermi_2d.h" | 7 | #include "video_core/engines/fermi_2d.h" |
| 8 | #include "video_core/engines/maxwell_3d.h" | ||
| 7 | #include "video_core/rasterizer_interface.h" | 9 | #include "video_core/rasterizer_interface.h" |
| 8 | #include "video_core/textures/decoders.h" | 10 | #include "video_core/textures/decoders.h" |
| 9 | 11 | ||
| @@ -47,6 +49,9 @@ void Fermi2D::HandleSurfaceCopy() { | |||
| 47 | u32 dst_bytes_per_pixel = RenderTargetBytesPerPixel(regs.dst.format); | 49 | u32 dst_bytes_per_pixel = RenderTargetBytesPerPixel(regs.dst.format); |
| 48 | 50 | ||
| 49 | if (!rasterizer.AccelerateSurfaceCopy(regs.src, regs.dst)) { | 51 | if (!rasterizer.AccelerateSurfaceCopy(regs.src, regs.dst)) { |
| 52 | // All copies here update the main memory, so mark all rasterizer states as invalid. | ||
| 53 | Core::System::GetInstance().GPU().Maxwell3D().dirty_flags.OnMemoryWrite(); | ||
| 54 | |||
| 50 | rasterizer.FlushRegion(source_cpu, src_bytes_per_pixel * regs.src.width * regs.src.height); | 55 | rasterizer.FlushRegion(source_cpu, src_bytes_per_pixel * regs.src.width * regs.src.height); |
| 51 | // We have to invalidate the destination region to evict any outdated surfaces from the | 56 | // We have to invalidate the destination region to evict any outdated surfaces from the |
| 52 | // cache. We do this before actually writing the new data because the destination address | 57 | // cache. We do this before actually writing the new data because the destination address |
diff --git a/src/video_core/engines/kepler_memory.cpp b/src/video_core/engines/kepler_memory.cpp index 585290d9f..2adbc9eaf 100644 --- a/src/video_core/engines/kepler_memory.cpp +++ b/src/video_core/engines/kepler_memory.cpp | |||
| @@ -3,8 +3,10 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/logging/log.h" | 5 | #include "common/logging/log.h" |
| 6 | #include "core/core.h" | ||
| 6 | #include "core/memory.h" | 7 | #include "core/memory.h" |
| 7 | #include "video_core/engines/kepler_memory.h" | 8 | #include "video_core/engines/kepler_memory.h" |
| 9 | #include "video_core/engines/maxwell_3d.h" | ||
| 8 | #include "video_core/rasterizer_interface.h" | 10 | #include "video_core/rasterizer_interface.h" |
| 9 | 11 | ||
| 10 | namespace Tegra::Engines { | 12 | namespace Tegra::Engines { |
| @@ -47,6 +49,7 @@ void KeplerMemory::ProcessData(u32 data) { | |||
| 47 | rasterizer.InvalidateRegion(dest_address, sizeof(u32)); | 49 | rasterizer.InvalidateRegion(dest_address, sizeof(u32)); |
| 48 | 50 | ||
| 49 | Memory::Write32(dest_address, data); | 51 | Memory::Write32(dest_address, data); |
| 52 | Core::System::GetInstance().GPU().Maxwell3D().dirty_flags.OnMemoryWrite(); | ||
| 50 | 53 | ||
| 51 | state.write_offset++; | 54 | state.write_offset++; |
| 52 | } | 55 | } |
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 2bc534be3..f0a5470b9 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -135,10 +135,24 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) { | |||
| 135 | 135 | ||
| 136 | if (regs.reg_array[method] != value) { | 136 | if (regs.reg_array[method] != value) { |
| 137 | regs.reg_array[method] = value; | 137 | regs.reg_array[method] = value; |
| 138 | // Vertex format | ||
| 138 | if (method >= MAXWELL3D_REG_INDEX(vertex_attrib_format) && | 139 | if (method >= MAXWELL3D_REG_INDEX(vertex_attrib_format) && |
| 139 | method < MAXWELL3D_REG_INDEX(vertex_attrib_format) + regs.vertex_attrib_format.size()) { | 140 | method < MAXWELL3D_REG_INDEX(vertex_attrib_format) + regs.vertex_attrib_format.size()) { |
| 140 | dirty_flags.vertex_attrib_format = true; | 141 | dirty_flags.vertex_attrib_format = true; |
| 141 | } | 142 | } |
| 143 | |||
| 144 | // Vertex buffer | ||
| 145 | if (method >= MAXWELL3D_REG_INDEX(vertex_array) && | ||
| 146 | method < MAXWELL3D_REG_INDEX(vertex_array) + 4 * 32) { | ||
| 147 | dirty_flags.vertex_array |= 1u << ((method - MAXWELL3D_REG_INDEX(vertex_array)) >> 2); | ||
| 148 | } else if (method >= MAXWELL3D_REG_INDEX(vertex_array_limit) && | ||
| 149 | method < MAXWELL3D_REG_INDEX(vertex_array_limit) + 2 * 32) { | ||
| 150 | dirty_flags.vertex_array |= | ||
| 151 | 1u << ((method - MAXWELL3D_REG_INDEX(vertex_array_limit)) >> 1); | ||
| 152 | } else if (method >= MAXWELL3D_REG_INDEX(instanced_arrays) && | ||
| 153 | method < MAXWELL3D_REG_INDEX(instanced_arrays) + 32) { | ||
| 154 | dirty_flags.vertex_array |= 1u << (method - MAXWELL3D_REG_INDEX(instanced_arrays)); | ||
| 155 | } | ||
| 142 | } | 156 | } |
| 143 | 157 | ||
| 144 | switch (method) { | 158 | switch (method) { |
| @@ -270,6 +284,7 @@ void Maxwell3D::ProcessQueryGet() { | |||
| 270 | query_result.timestamp = CoreTiming::GetTicks(); | 284 | query_result.timestamp = CoreTiming::GetTicks(); |
| 271 | Memory::WriteBlock(*address, &query_result, sizeof(query_result)); | 285 | Memory::WriteBlock(*address, &query_result, sizeof(query_result)); |
| 272 | } | 286 | } |
| 287 | dirty_flags.OnMemoryWrite(); | ||
| 273 | break; | 288 | break; |
| 274 | } | 289 | } |
| 275 | default: | 290 | default: |
| @@ -346,6 +361,7 @@ void Maxwell3D::ProcessCBData(u32 value) { | |||
| 346 | memory_manager.GpuToCpuAddress(buffer_address + regs.const_buffer.cb_pos); | 361 | memory_manager.GpuToCpuAddress(buffer_address + regs.const_buffer.cb_pos); |
| 347 | 362 | ||
| 348 | Memory::Write32(*address, value); | 363 | Memory::Write32(*address, value); |
| 364 | dirty_flags.OnMemoryWrite(); | ||
| 349 | 365 | ||
| 350 | // Increment the current buffer position. | 366 | // Increment the current buffer position. |
| 351 | regs.const_buffer.cb_pos = regs.const_buffer.cb_pos + 4; | 367 | regs.const_buffer.cb_pos = regs.const_buffer.cb_pos + 4; |
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 4f137e693..9324d9710 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -590,10 +590,18 @@ public: | |||
| 590 | 590 | ||
| 591 | float clear_color[4]; | 591 | float clear_color[4]; |
| 592 | float clear_depth; | 592 | float clear_depth; |
| 593 | |||
| 593 | INSERT_PADDING_WORDS(0x3); | 594 | INSERT_PADDING_WORDS(0x3); |
| 595 | |||
| 594 | s32 clear_stencil; | 596 | s32 clear_stencil; |
| 595 | 597 | ||
| 596 | INSERT_PADDING_WORDS(0x17); | 598 | INSERT_PADDING_WORDS(0x7); |
| 599 | |||
| 600 | u32 polygon_offset_point_enable; | ||
| 601 | u32 polygon_offset_line_enable; | ||
| 602 | u32 polygon_offset_fill_enable; | ||
| 603 | |||
| 604 | INSERT_PADDING_WORDS(0xD); | ||
| 597 | 605 | ||
| 598 | std::array<ScissorTest, NumViewports> scissor_test; | 606 | std::array<ScissorTest, NumViewports> scissor_test; |
| 599 | 607 | ||
| @@ -728,6 +736,7 @@ public: | |||
| 728 | u32 frag_color_clamp; | 736 | u32 frag_color_clamp; |
| 729 | 737 | ||
| 730 | union { | 738 | union { |
| 739 | BitField<0, 1, u32> y_negate; | ||
| 731 | BitField<4, 1, u32> triangle_rast_flip; | 740 | BitField<4, 1, u32> triangle_rast_flip; |
| 732 | } screen_y_control; | 741 | } screen_y_control; |
| 733 | 742 | ||
| @@ -761,7 +770,11 @@ public: | |||
| 761 | } | 770 | } |
| 762 | } tsc; | 771 | } tsc; |
| 763 | 772 | ||
| 764 | INSERT_PADDING_WORDS(0x3); | 773 | INSERT_PADDING_WORDS(0x1); |
| 774 | |||
| 775 | float polygon_offset_factor; | ||
| 776 | |||
| 777 | INSERT_PADDING_WORDS(0x1); | ||
| 765 | 778 | ||
| 766 | struct { | 779 | struct { |
| 767 | u32 tic_address_high; | 780 | u32 tic_address_high; |
| @@ -786,7 +799,9 @@ public: | |||
| 786 | 799 | ||
| 787 | u32 framebuffer_srgb; | 800 | u32 framebuffer_srgb; |
| 788 | 801 | ||
| 789 | INSERT_PADDING_WORDS(0x12); | 802 | float polygon_offset_units; |
| 803 | |||
| 804 | INSERT_PADDING_WORDS(0x11); | ||
| 790 | 805 | ||
| 791 | union { | 806 | union { |
| 792 | BitField<2, 1, u32> coord_origin; | 807 | BitField<2, 1, u32> coord_origin; |
| @@ -863,7 +878,9 @@ public: | |||
| 863 | 878 | ||
| 864 | INSERT_PADDING_WORDS(0x7); | 879 | INSERT_PADDING_WORDS(0x7); |
| 865 | 880 | ||
| 866 | INSERT_PADDING_WORDS(0x20); | 881 | INSERT_PADDING_WORDS(0x1F); |
| 882 | |||
| 883 | float polygon_offset_clamp; | ||
| 867 | 884 | ||
| 868 | struct { | 885 | struct { |
| 869 | u32 is_instanced[NumVertexArrays]; | 886 | u32 is_instanced[NumVertexArrays]; |
| @@ -879,7 +896,13 @@ public: | |||
| 879 | 896 | ||
| 880 | Cull cull; | 897 | Cull cull; |
| 881 | 898 | ||
| 882 | INSERT_PADDING_WORDS(0x28); | 899 | u32 pixel_center_integer; |
| 900 | |||
| 901 | INSERT_PADDING_WORDS(0x1); | ||
| 902 | |||
| 903 | u32 viewport_transform_enabled; | ||
| 904 | |||
| 905 | INSERT_PADDING_WORDS(0x25); | ||
| 883 | 906 | ||
| 884 | struct { | 907 | struct { |
| 885 | u32 enable; | 908 | u32 enable; |
| @@ -1044,6 +1067,11 @@ public: | |||
| 1044 | 1067 | ||
| 1045 | struct DirtyFlags { | 1068 | struct DirtyFlags { |
| 1046 | bool vertex_attrib_format = true; | 1069 | bool vertex_attrib_format = true; |
| 1070 | u32 vertex_array = 0xFFFFFFFF; | ||
| 1071 | |||
| 1072 | void OnMemoryWrite() { | ||
| 1073 | vertex_array = 0xFFFFFFFF; | ||
| 1074 | } | ||
| 1047 | }; | 1075 | }; |
| 1048 | 1076 | ||
| 1049 | DirtyFlags dirty_flags; | 1077 | DirtyFlags dirty_flags; |
| @@ -1136,6 +1164,9 @@ ASSERT_REG_POSITION(vertex_buffer, 0x35D); | |||
| 1136 | ASSERT_REG_POSITION(clear_color[0], 0x360); | 1164 | ASSERT_REG_POSITION(clear_color[0], 0x360); |
| 1137 | ASSERT_REG_POSITION(clear_depth, 0x364); | 1165 | ASSERT_REG_POSITION(clear_depth, 0x364); |
| 1138 | ASSERT_REG_POSITION(clear_stencil, 0x368); | 1166 | ASSERT_REG_POSITION(clear_stencil, 0x368); |
| 1167 | ASSERT_REG_POSITION(polygon_offset_point_enable, 0x370); | ||
| 1168 | ASSERT_REG_POSITION(polygon_offset_line_enable, 0x371); | ||
| 1169 | ASSERT_REG_POSITION(polygon_offset_fill_enable, 0x372); | ||
| 1139 | ASSERT_REG_POSITION(scissor_test, 0x380); | 1170 | ASSERT_REG_POSITION(scissor_test, 0x380); |
| 1140 | ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5); | 1171 | ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5); |
| 1141 | ASSERT_REG_POSITION(stencil_back_mask, 0x3D6); | 1172 | ASSERT_REG_POSITION(stencil_back_mask, 0x3D6); |
| @@ -1174,6 +1205,7 @@ ASSERT_REG_POSITION(point_size, 0x546); | |||
| 1174 | ASSERT_REG_POSITION(zeta_enable, 0x54E); | 1205 | ASSERT_REG_POSITION(zeta_enable, 0x54E); |
| 1175 | ASSERT_REG_POSITION(multisample_control, 0x54F); | 1206 | ASSERT_REG_POSITION(multisample_control, 0x54F); |
| 1176 | ASSERT_REG_POSITION(tsc, 0x557); | 1207 | ASSERT_REG_POSITION(tsc, 0x557); |
| 1208 | ASSERT_REG_POSITION(polygon_offset_factor, 0x55b); | ||
| 1177 | ASSERT_REG_POSITION(tic, 0x55D); | 1209 | ASSERT_REG_POSITION(tic, 0x55D); |
| 1178 | ASSERT_REG_POSITION(stencil_two_side_enable, 0x565); | 1210 | ASSERT_REG_POSITION(stencil_two_side_enable, 0x565); |
| 1179 | ASSERT_REG_POSITION(stencil_back_op_fail, 0x566); | 1211 | ASSERT_REG_POSITION(stencil_back_op_fail, 0x566); |
| @@ -1181,13 +1213,17 @@ ASSERT_REG_POSITION(stencil_back_op_zfail, 0x567); | |||
| 1181 | ASSERT_REG_POSITION(stencil_back_op_zpass, 0x568); | 1213 | ASSERT_REG_POSITION(stencil_back_op_zpass, 0x568); |
| 1182 | ASSERT_REG_POSITION(stencil_back_func_func, 0x569); | 1214 | ASSERT_REG_POSITION(stencil_back_func_func, 0x569); |
| 1183 | ASSERT_REG_POSITION(framebuffer_srgb, 0x56E); | 1215 | ASSERT_REG_POSITION(framebuffer_srgb, 0x56E); |
| 1216 | ASSERT_REG_POSITION(polygon_offset_units, 0x56F); | ||
| 1184 | ASSERT_REG_POSITION(point_coord_replace, 0x581); | 1217 | ASSERT_REG_POSITION(point_coord_replace, 0x581); |
| 1185 | ASSERT_REG_POSITION(code_address, 0x582); | 1218 | ASSERT_REG_POSITION(code_address, 0x582); |
| 1186 | ASSERT_REG_POSITION(draw, 0x585); | 1219 | ASSERT_REG_POSITION(draw, 0x585); |
| 1187 | ASSERT_REG_POSITION(primitive_restart, 0x591); | 1220 | ASSERT_REG_POSITION(primitive_restart, 0x591); |
| 1188 | ASSERT_REG_POSITION(index_array, 0x5F2); | 1221 | ASSERT_REG_POSITION(index_array, 0x5F2); |
| 1222 | ASSERT_REG_POSITION(polygon_offset_clamp, 0x61F); | ||
| 1189 | ASSERT_REG_POSITION(instanced_arrays, 0x620); | 1223 | ASSERT_REG_POSITION(instanced_arrays, 0x620); |
| 1190 | ASSERT_REG_POSITION(cull, 0x646); | 1224 | ASSERT_REG_POSITION(cull, 0x646); |
| 1225 | ASSERT_REG_POSITION(pixel_center_integer, 0x649); | ||
| 1226 | ASSERT_REG_POSITION(viewport_transform_enabled, 0x64B); | ||
| 1191 | ASSERT_REG_POSITION(logic_op, 0x671); | 1227 | ASSERT_REG_POSITION(logic_op, 0x671); |
| 1192 | ASSERT_REG_POSITION(clear_buffers, 0x674); | 1228 | ASSERT_REG_POSITION(clear_buffers, 0x674); |
| 1193 | ASSERT_REG_POSITION(color_mask, 0x680); | 1229 | ASSERT_REG_POSITION(color_mask, 0x680); |
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp index b8a78cf82..a34e884fe 100644 --- a/src/video_core/engines/maxwell_dma.cpp +++ b/src/video_core/engines/maxwell_dma.cpp | |||
| @@ -2,7 +2,9 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "core/core.h" | ||
| 5 | #include "core/memory.h" | 6 | #include "core/memory.h" |
| 7 | #include "video_core/engines/maxwell_3d.h" | ||
| 6 | #include "video_core/engines/maxwell_dma.h" | 8 | #include "video_core/engines/maxwell_dma.h" |
| 7 | #include "video_core/rasterizer_interface.h" | 9 | #include "video_core/rasterizer_interface.h" |
| 8 | #include "video_core/textures/decoders.h" | 10 | #include "video_core/textures/decoders.h" |
| @@ -54,6 +56,9 @@ void MaxwellDMA::HandleCopy() { | |||
| 54 | return; | 56 | return; |
| 55 | } | 57 | } |
| 56 | 58 | ||
| 59 | // All copies here update the main memory, so mark all rasterizer states as invalid. | ||
| 60 | Core::System::GetInstance().GPU().Maxwell3D().dirty_flags.OnMemoryWrite(); | ||
| 61 | |||
| 57 | if (regs.exec.is_dst_linear && regs.exec.is_src_linear) { | 62 | if (regs.exec.is_dst_linear && regs.exec.is_src_linear) { |
| 58 | // When the enable_2d bit is disabled, the copy is performed as if we were copying a 1D | 63 | // When the enable_2d bit is disabled, the copy is performed as if we were copying a 1D |
| 59 | // buffer of length `x_count`, otherwise we copy a 2D image of dimensions (x_count, | 64 | // buffer of length `x_count`, otherwise we copy a 2D image of dimensions (x_count, |
diff --git a/src/video_core/morton.cpp b/src/video_core/morton.cpp index 1cf27ee25..a310491a8 100644 --- a/src/video_core/morton.cpp +++ b/src/video_core/morton.cpp | |||
| @@ -184,13 +184,14 @@ static constexpr ConversionArray linear_to_morton_fns = { | |||
| 184 | // clang-format on | 184 | // clang-format on |
| 185 | }; | 185 | }; |
| 186 | 186 | ||
| 187 | constexpr MortonCopyFn GetSwizzleFunction(MortonSwizzleMode mode, Surface::PixelFormat format) { | 187 | static MortonCopyFn GetSwizzleFunction(MortonSwizzleMode mode, Surface::PixelFormat format) { |
| 188 | switch (mode) { | 188 | switch (mode) { |
| 189 | case MortonSwizzleMode::MortonToLinear: | 189 | case MortonSwizzleMode::MortonToLinear: |
| 190 | return morton_to_linear_fns[static_cast<std::size_t>(format)]; | 190 | return morton_to_linear_fns[static_cast<std::size_t>(format)]; |
| 191 | case MortonSwizzleMode::LinearToMorton: | 191 | case MortonSwizzleMode::LinearToMorton: |
| 192 | return linear_to_morton_fns[static_cast<std::size_t>(format)]; | 192 | return linear_to_morton_fns[static_cast<std::size_t>(format)]; |
| 193 | } | 193 | } |
| 194 | UNREACHABLE(); | ||
| 194 | } | 195 | } |
| 195 | 196 | ||
| 196 | /// 8x8 Z-Order coordinate from 2D coordinates | 197 | /// 8x8 Z-Order coordinate from 2D coordinates |
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp index 075192c3f..46a6c0308 100644 --- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp | |||
| @@ -76,7 +76,7 @@ std::tuple<u8*, GLintptr> OGLBufferCache::ReserveMemory(std::size_t size, std::s | |||
| 76 | return std::make_tuple(uploaded_ptr, uploaded_offset); | 76 | return std::make_tuple(uploaded_ptr, uploaded_offset); |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | void OGLBufferCache::Map(std::size_t max_size) { | 79 | bool OGLBufferCache::Map(std::size_t max_size) { |
| 80 | bool invalidate; | 80 | bool invalidate; |
| 81 | std::tie(buffer_ptr, buffer_offset_base, invalidate) = | 81 | std::tie(buffer_ptr, buffer_offset_base, invalidate) = |
| 82 | stream_buffer.Map(static_cast<GLsizeiptr>(max_size), 4); | 82 | stream_buffer.Map(static_cast<GLsizeiptr>(max_size), 4); |
| @@ -85,6 +85,7 @@ void OGLBufferCache::Map(std::size_t max_size) { | |||
| 85 | if (invalidate) { | 85 | if (invalidate) { |
| 86 | InvalidateAll(); | 86 | InvalidateAll(); |
| 87 | } | 87 | } |
| 88 | return invalidate; | ||
| 88 | } | 89 | } |
| 89 | 90 | ||
| 90 | void OGLBufferCache::Unmap() { | 91 | void OGLBufferCache::Unmap() { |
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.h b/src/video_core/renderer_opengl/gl_buffer_cache.h index 91fca3f6c..c11acfb79 100644 --- a/src/video_core/renderer_opengl/gl_buffer_cache.h +++ b/src/video_core/renderer_opengl/gl_buffer_cache.h | |||
| @@ -50,7 +50,7 @@ public: | |||
| 50 | /// Reserves memory to be used by host's CPU. Returns mapped address and offset. | 50 | /// Reserves memory to be used by host's CPU. Returns mapped address and offset. |
| 51 | std::tuple<u8*, GLintptr> ReserveMemory(std::size_t size, std::size_t alignment = 4); | 51 | std::tuple<u8*, GLintptr> ReserveMemory(std::size_t size, std::size_t alignment = 4); |
| 52 | 52 | ||
| 53 | void Map(std::size_t max_size); | 53 | bool Map(std::size_t max_size); |
| 54 | void Unmap(); | 54 | void Unmap(); |
| 55 | 55 | ||
| 56 | GLuint GetHandle() const; | 56 | GLuint GetHandle() const; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 630a58e49..82b7a0649 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -176,15 +176,25 @@ void RasterizerOpenGL::SetupVertexFormat() { | |||
| 176 | } | 176 | } |
| 177 | state.draw.vertex_array = VAO.handle; | 177 | state.draw.vertex_array = VAO.handle; |
| 178 | state.ApplyVertexBufferState(); | 178 | state.ApplyVertexBufferState(); |
| 179 | |||
| 180 | // Rebinding the VAO invalidates the vertex buffer bindings. | ||
| 181 | gpu.dirty_flags.vertex_array = 0xFFFFFFFF; | ||
| 179 | } | 182 | } |
| 180 | 183 | ||
| 181 | void RasterizerOpenGL::SetupVertexBuffer() { | 184 | void RasterizerOpenGL::SetupVertexBuffer() { |
| 182 | MICROPROFILE_SCOPE(OpenGL_VB); | 185 | auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); |
| 183 | const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); | ||
| 184 | const auto& regs = gpu.regs; | 186 | const auto& regs = gpu.regs; |
| 185 | 187 | ||
| 188 | if (!gpu.dirty_flags.vertex_array) | ||
| 189 | return; | ||
| 190 | |||
| 191 | MICROPROFILE_SCOPE(OpenGL_VB); | ||
| 192 | |||
| 186 | // Upload all guest vertex arrays sequentially to our buffer | 193 | // Upload all guest vertex arrays sequentially to our buffer |
| 187 | for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) { | 194 | for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) { |
| 195 | if (~gpu.dirty_flags.vertex_array & (1u << index)) | ||
| 196 | continue; | ||
| 197 | |||
| 188 | const auto& vertex_array = regs.vertex_array[index]; | 198 | const auto& vertex_array = regs.vertex_array[index]; |
| 189 | if (!vertex_array.IsEnabled()) | 199 | if (!vertex_array.IsEnabled()) |
| 190 | continue; | 200 | continue; |
| @@ -211,6 +221,8 @@ void RasterizerOpenGL::SetupVertexBuffer() { | |||
| 211 | 221 | ||
| 212 | // Implicit set by glBindVertexBuffer. Stupid glstate handling... | 222 | // Implicit set by glBindVertexBuffer. Stupid glstate handling... |
| 213 | state.draw.vertex_buffer = buffer_cache.GetHandle(); | 223 | state.draw.vertex_buffer = buffer_cache.GetHandle(); |
| 224 | |||
| 225 | gpu.dirty_flags.vertex_array = 0; | ||
| 214 | } | 226 | } |
| 215 | 227 | ||
| 216 | DrawParameters RasterizerOpenGL::SetupDraw() { | 228 | DrawParameters RasterizerOpenGL::SetupDraw() { |
| @@ -600,7 +612,7 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 600 | return; | 612 | return; |
| 601 | 613 | ||
| 602 | MICROPROFILE_SCOPE(OpenGL_Drawing); | 614 | MICROPROFILE_SCOPE(OpenGL_Drawing); |
| 603 | const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); | 615 | auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); |
| 604 | const auto& regs = gpu.regs; | 616 | const auto& regs = gpu.regs; |
| 605 | 617 | ||
| 606 | ScopeAcquireGLContext acquire_context{emu_window}; | 618 | ScopeAcquireGLContext acquire_context{emu_window}; |
| @@ -620,7 +632,7 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 620 | SyncTransformFeedback(); | 632 | SyncTransformFeedback(); |
| 621 | SyncPointState(); | 633 | SyncPointState(); |
| 622 | CheckAlphaTests(); | 634 | CheckAlphaTests(); |
| 623 | 635 | SyncPolygonOffset(); | |
| 624 | // TODO(bunnei): Sync framebuffer_scale uniform here | 636 | // TODO(bunnei): Sync framebuffer_scale uniform here |
| 625 | // TODO(bunnei): Sync scissorbox uniform(s) here | 637 | // TODO(bunnei): Sync scissorbox uniform(s) here |
| 626 | 638 | ||
| @@ -653,7 +665,11 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 653 | // Add space for at least 18 constant buffers | 665 | // Add space for at least 18 constant buffers |
| 654 | buffer_size += Maxwell::MaxConstBuffers * (MaxConstbufferSize + uniform_buffer_alignment); | 666 | buffer_size += Maxwell::MaxConstBuffers * (MaxConstbufferSize + uniform_buffer_alignment); |
| 655 | 667 | ||
| 656 | buffer_cache.Map(buffer_size); | 668 | bool invalidate = buffer_cache.Map(buffer_size); |
| 669 | if (invalidate) { | ||
| 670 | // As all cached buffers are invalidated, we need to recheck their state. | ||
| 671 | gpu.dirty_flags.vertex_array = 0xFFFFFFFF; | ||
| 672 | } | ||
| 657 | 673 | ||
| 658 | SetupVertexFormat(); | 674 | SetupVertexFormat(); |
| 659 | SetupVertexBuffer(); | 675 | SetupVertexBuffer(); |
| @@ -969,13 +985,25 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, | |||
| 969 | 985 | ||
| 970 | void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { | 986 | void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { |
| 971 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 987 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; |
| 972 | for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) { | 988 | const bool geometry_shaders_enabled = |
| 973 | const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()}; | 989 | regs.IsShaderConfigEnabled(static_cast<size_t>(Maxwell::ShaderProgram::Geometry)); |
| 990 | const std::size_t viewport_count = | ||
| 991 | geometry_shaders_enabled ? Tegra::Engines::Maxwell3D::Regs::NumViewports : 1; | ||
| 992 | for (std::size_t i = 0; i < viewport_count; i++) { | ||
| 974 | auto& viewport = current_state.viewports[i]; | 993 | auto& viewport = current_state.viewports[i]; |
| 975 | viewport.x = viewport_rect.left; | 994 | const auto& src = regs.viewports[i]; |
| 976 | viewport.y = viewport_rect.bottom; | 995 | if (regs.viewport_transform_enabled) { |
| 977 | viewport.width = viewport_rect.GetWidth(); | 996 | const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()}; |
| 978 | viewport.height = viewport_rect.GetHeight(); | 997 | viewport.x = viewport_rect.left; |
| 998 | viewport.y = viewport_rect.bottom; | ||
| 999 | viewport.width = viewport_rect.GetWidth(); | ||
| 1000 | viewport.height = viewport_rect.GetHeight(); | ||
| 1001 | } else { | ||
| 1002 | viewport.x = src.x; | ||
| 1003 | viewport.y = src.y; | ||
| 1004 | viewport.width = src.width; | ||
| 1005 | viewport.height = src.height; | ||
| 1006 | } | ||
| 979 | viewport.depth_range_far = regs.viewports[i].depth_range_far; | 1007 | viewport.depth_range_far = regs.viewports[i].depth_range_far; |
| 980 | viewport.depth_range_near = regs.viewports[i].depth_range_near; | 1008 | viewport.depth_range_near = regs.viewports[i].depth_range_near; |
| 981 | } | 1009 | } |
| @@ -1149,7 +1177,11 @@ void RasterizerOpenGL::SyncLogicOpState() { | |||
| 1149 | 1177 | ||
| 1150 | void RasterizerOpenGL::SyncScissorTest(OpenGLState& current_state) { | 1178 | void RasterizerOpenGL::SyncScissorTest(OpenGLState& current_state) { |
| 1151 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 1179 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; |
| 1152 | for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) { | 1180 | const bool geometry_shaders_enabled = |
| 1181 | regs.IsShaderConfigEnabled(static_cast<size_t>(Maxwell::ShaderProgram::Geometry)); | ||
| 1182 | const std::size_t viewport_count = | ||
| 1183 | geometry_shaders_enabled ? Tegra::Engines::Maxwell3D::Regs::NumViewports : 1; | ||
| 1184 | for (std::size_t i = 0; i < viewport_count; i++) { | ||
| 1153 | const auto& src = regs.scissor_test[i]; | 1185 | const auto& src = regs.scissor_test[i]; |
| 1154 | auto& dst = current_state.viewports[i].scissor; | 1186 | auto& dst = current_state.viewports[i].scissor; |
| 1155 | dst.enabled = (src.enable != 0); | 1187 | dst.enabled = (src.enable != 0); |
| @@ -1179,6 +1211,16 @@ void RasterizerOpenGL::SyncPointState() { | |||
| 1179 | state.point.size = regs.point_size; | 1211 | state.point.size = regs.point_size; |
| 1180 | } | 1212 | } |
| 1181 | 1213 | ||
| 1214 | void RasterizerOpenGL::SyncPolygonOffset() { | ||
| 1215 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | ||
| 1216 | state.polygon_offset.fill_enable = regs.polygon_offset_fill_enable != 0; | ||
| 1217 | state.polygon_offset.line_enable = regs.polygon_offset_line_enable != 0; | ||
| 1218 | state.polygon_offset.point_enable = regs.polygon_offset_point_enable != 0; | ||
| 1219 | state.polygon_offset.units = regs.polygon_offset_units; | ||
| 1220 | state.polygon_offset.factor = regs.polygon_offset_factor; | ||
| 1221 | state.polygon_offset.clamp = regs.polygon_offset_clamp; | ||
| 1222 | } | ||
| 1223 | |||
| 1182 | void RasterizerOpenGL::CheckAlphaTests() { | 1224 | void RasterizerOpenGL::CheckAlphaTests() { |
| 1183 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 1225 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; |
| 1184 | 1226 | ||
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index f4354289c..dfb4616f2 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -183,6 +183,9 @@ private: | |||
| 183 | /// Syncs Color Mask | 183 | /// Syncs Color Mask |
| 184 | void SyncColorMask(); | 184 | void SyncColorMask(); |
| 185 | 185 | ||
| 186 | /// Syncs the polygon offsets | ||
| 187 | void SyncPolygonOffset(); | ||
| 188 | |||
| 186 | /// Check asserts for alpha testing. | 189 | /// Check asserts for alpha testing. |
| 187 | void CheckAlphaTests(); | 190 | void CheckAlphaTests(); |
| 188 | 191 | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 05fe2d370..0c4524d5c 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -520,7 +520,7 @@ public: | |||
| 520 | switch (attribute) { | 520 | switch (attribute) { |
| 521 | case Attribute::Index::ClipDistances0123: | 521 | case Attribute::Index::ClipDistances0123: |
| 522 | case Attribute::Index::ClipDistances4567: { | 522 | case Attribute::Index::ClipDistances4567: { |
| 523 | const u64 index = attribute == Attribute::Index::ClipDistances4567 ? 4 : 0 + elem; | 523 | const u64 index = (attribute == Attribute::Index::ClipDistances4567 ? 4 : 0) + elem; |
| 524 | UNIMPLEMENTED_IF_MSG( | 524 | UNIMPLEMENTED_IF_MSG( |
| 525 | ((header.vtg.clip_distances >> index) & 1) == 0, | 525 | ((header.vtg.clip_distances >> index) & 1) == 0, |
| 526 | "Shader is setting gl_ClipDistance{} without enabling it in the header", index); | 526 | "Shader is setting gl_ClipDistance{} without enabling it in the header", index); |
| @@ -867,7 +867,8 @@ private: | |||
| 867 | // vertex shader, and what's the value of the fourth element when inside a Tess Eval | 867 | // vertex shader, and what's the value of the fourth element when inside a Tess Eval |
| 868 | // shader. | 868 | // shader. |
| 869 | ASSERT(stage == Maxwell3D::Regs::ShaderStage::Vertex); | 869 | ASSERT(stage == Maxwell3D::Regs::ShaderStage::Vertex); |
| 870 | return "vec4(0, 0, uintBitsToFloat(instance_id.x), uintBitsToFloat(gl_VertexID))"; | 870 | // Config pack's first value is instance_id. |
| 871 | return "vec4(0, 0, uintBitsToFloat(config_pack[0]), uintBitsToFloat(gl_VertexID))"; | ||
| 871 | case Attribute::Index::FrontFacing: | 872 | case Attribute::Index::FrontFacing: |
| 872 | // TODO(Subv): Find out what the values are for the other elements. | 873 | // TODO(Subv): Find out what the values are for the other elements. |
| 873 | ASSERT(stage == Maxwell3D::Regs::ShaderStage::Fragment); | 874 | ASSERT(stage == Maxwell3D::Regs::ShaderStage::Fragment); |
| @@ -3400,6 +3401,10 @@ private: | |||
| 3400 | regs.SetRegisterToInteger(instr.gpr0, false, 0, predicate + " ? 0xFFFFFFFF : 0", 1, | 3401 | regs.SetRegisterToInteger(instr.gpr0, false, 0, predicate + " ? 0xFFFFFFFF : 0", 1, |
| 3401 | 1); | 3402 | 1); |
| 3402 | } | 3403 | } |
| 3404 | if (instr.generates_cc.Value() != 0) { | ||
| 3405 | regs.SetInternalFlag(InternalFlag::ZeroFlag, predicate); | ||
| 3406 | LOG_WARNING(HW_GPU, "FSET Condition Code is incomplete"); | ||
| 3407 | } | ||
| 3403 | break; | 3408 | break; |
| 3404 | } | 3409 | } |
| 3405 | case OpCode::Type::IntegerSet: { | 3410 | case OpCode::Type::IntegerSet: { |
| @@ -3653,6 +3658,11 @@ private: | |||
| 3653 | regs.SetRegisterToInteger(instr.gpr0, false, 0, "0u", 1, 1); | 3658 | regs.SetRegisterToInteger(instr.gpr0, false, 0, "0u", 1, 1); |
| 3654 | break; | 3659 | break; |
| 3655 | } | 3660 | } |
| 3661 | case Tegra::Shader::SystemVariable::Ydirection: { | ||
| 3662 | // Config pack's third value is Y_NEGATE's state. | ||
| 3663 | regs.SetRegisterToFloat(instr.gpr0, 0, "uintBitsToFloat(config_pack[2])", 1, 1); | ||
| 3664 | break; | ||
| 3665 | } | ||
| 3656 | default: { | 3666 | default: { |
| 3657 | UNIMPLEMENTED_MSG("Unhandled system move: {}", | 3667 | UNIMPLEMENTED_MSG("Unhandled system move: {}", |
| 3658 | static_cast<u32>(instr.sys20.Value())); | 3668 | static_cast<u32>(instr.sys20.Value())); |
| @@ -3676,11 +3686,17 @@ private: | |||
| 3676 | "BRA with constant buffers are not implemented"); | 3686 | "BRA with constant buffers are not implemented"); |
| 3677 | 3687 | ||
| 3678 | const Tegra::Shader::ConditionCode cc = instr.flow_condition_code; | 3688 | const Tegra::Shader::ConditionCode cc = instr.flow_condition_code; |
| 3679 | UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T, | ||
| 3680 | "BRA condition code used: {}", static_cast<u32>(cc)); | ||
| 3681 | |||
| 3682 | const u32 target = offset + instr.bra.GetBranchTarget(); | 3689 | const u32 target = offset + instr.bra.GetBranchTarget(); |
| 3683 | shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }"); | 3690 | if (cc != Tegra::Shader::ConditionCode::T) { |
| 3691 | const std::string condition_code = regs.GetConditionCode(cc); | ||
| 3692 | shader.AddLine("if (" + condition_code + "){"); | ||
| 3693 | shader.scope++; | ||
| 3694 | shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }"); | ||
| 3695 | shader.scope--; | ||
| 3696 | shader.AddLine('}'); | ||
| 3697 | } else { | ||
| 3698 | shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }"); | ||
| 3699 | } | ||
| 3684 | break; | 3700 | break; |
| 3685 | } | 3701 | } |
| 3686 | case OpCode::Id::IPA: { | 3702 | case OpCode::Id::IPA: { |
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index eea090e52..23ed91e27 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp | |||
| @@ -24,8 +24,7 @@ layout (location = 0) out vec4 position; | |||
| 24 | 24 | ||
| 25 | layout(std140) uniform vs_config { | 25 | layout(std140) uniform vs_config { |
| 26 | vec4 viewport_flip; | 26 | vec4 viewport_flip; |
| 27 | uvec4 instance_id; | 27 | uvec4 config_pack; // instance_id, flip_stage, y_direction, padding |
| 28 | uvec4 flip_stage; | ||
| 29 | uvec4 alpha_test; | 28 | uvec4 alpha_test; |
| 30 | }; | 29 | }; |
| 31 | )"; | 30 | )"; |
| @@ -63,7 +62,8 @@ void main() { | |||
| 63 | out += R"( | 62 | out += R"( |
| 64 | 63 | ||
| 65 | // Check if the flip stage is VertexB | 64 | // Check if the flip stage is VertexB |
| 66 | if (flip_stage[0] == 1) { | 65 | // Config pack's second value is flip_stage |
| 66 | if (config_pack[1] == 1) { | ||
| 67 | // Viewport can be flipped, which is unsupported by glViewport | 67 | // Viewport can be flipped, which is unsupported by glViewport |
| 68 | position.xy *= viewport_flip.xy; | 68 | position.xy *= viewport_flip.xy; |
| 69 | } | 69 | } |
| @@ -71,7 +71,7 @@ void main() { | |||
| 71 | 71 | ||
| 72 | // TODO(bunnei): This is likely a hack, position.w should be interpolated as 1.0 | 72 | // TODO(bunnei): This is likely a hack, position.w should be interpolated as 1.0 |
| 73 | // For now, this is here to bring order in lieu of proper emulation | 73 | // For now, this is here to bring order in lieu of proper emulation |
| 74 | if (flip_stage[0] == 1) { | 74 | if (config_pack[1] == 1) { |
| 75 | position.w = 1.0; | 75 | position.w = 1.0; |
| 76 | } | 76 | } |
| 77 | } | 77 | } |
| @@ -101,8 +101,7 @@ layout (location = 0) out vec4 position; | |||
| 101 | 101 | ||
| 102 | layout (std140) uniform gs_config { | 102 | layout (std140) uniform gs_config { |
| 103 | vec4 viewport_flip; | 103 | vec4 viewport_flip; |
| 104 | uvec4 instance_id; | 104 | uvec4 config_pack; // instance_id, flip_stage, y_direction, padding |
| 105 | uvec4 flip_stage; | ||
| 106 | uvec4 alpha_test; | 105 | uvec4 alpha_test; |
| 107 | }; | 106 | }; |
| 108 | 107 | ||
| @@ -139,8 +138,7 @@ layout (location = 0) in vec4 position; | |||
| 139 | 138 | ||
| 140 | layout (std140) uniform fs_config { | 139 | layout (std140) uniform fs_config { |
| 141 | vec4 viewport_flip; | 140 | vec4 viewport_flip; |
| 142 | uvec4 instance_id; | 141 | uvec4 config_pack; // instance_id, flip_stage, y_direction, padding |
| 143 | uvec4 flip_stage; | ||
| 144 | uvec4 alpha_test; | 142 | uvec4 alpha_test; |
| 145 | }; | 143 | }; |
| 146 | 144 | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp index 8b8869ecb..6a30c28d2 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.cpp +++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp | |||
| @@ -27,16 +27,18 @@ void MaxwellUniformData::SetFromRegs(const Maxwell3D::State::ShaderStageInfo& sh | |||
| 27 | alpha_test.func = func; | 27 | alpha_test.func = func; |
| 28 | alpha_test.ref = regs.alpha_test_ref; | 28 | alpha_test.ref = regs.alpha_test_ref; |
| 29 | 29 | ||
| 30 | // We only assign the instance to the first component of the vector, the rest is just padding. | 30 | instance_id = state.current_instance; |
| 31 | instance_id[0] = state.current_instance; | ||
| 32 | 31 | ||
| 33 | // Assign in which stage the position has to be flipped | 32 | // Assign in which stage the position has to be flipped |
| 34 | // (the last stage before the fragment shader). | 33 | // (the last stage before the fragment shader). |
| 35 | if (gpu.regs.shader_config[static_cast<u32>(Maxwell3D::Regs::ShaderProgram::Geometry)].enable) { | 34 | if (gpu.regs.shader_config[static_cast<u32>(Maxwell3D::Regs::ShaderProgram::Geometry)].enable) { |
| 36 | flip_stage[0] = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::Geometry); | 35 | flip_stage = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::Geometry); |
| 37 | } else { | 36 | } else { |
| 38 | flip_stage[0] = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::VertexB); | 37 | flip_stage = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::VertexB); |
| 39 | } | 38 | } |
| 39 | |||
| 40 | // Y_NEGATE controls what value S2R returns for the Y_DIRECTION system value. | ||
| 41 | y_direction = regs.screen_y_control.y_negate == 0 ? 1.f : -1.f; | ||
| 40 | } | 42 | } |
| 41 | 43 | ||
| 42 | } // namespace OpenGL::GLShader | 44 | } // namespace OpenGL::GLShader |
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h index 9a5d7e289..b757f5f44 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.h +++ b/src/video_core/renderer_opengl/gl_shader_manager.h | |||
| @@ -21,8 +21,11 @@ using Tegra::Engines::Maxwell3D; | |||
| 21 | struct MaxwellUniformData { | 21 | struct MaxwellUniformData { |
| 22 | void SetFromRegs(const Maxwell3D::State::ShaderStageInfo& shader_stage); | 22 | void SetFromRegs(const Maxwell3D::State::ShaderStageInfo& shader_stage); |
| 23 | alignas(16) GLvec4 viewport_flip; | 23 | alignas(16) GLvec4 viewport_flip; |
| 24 | alignas(16) GLuvec4 instance_id; | 24 | struct alignas(16) { |
| 25 | alignas(16) GLuvec4 flip_stage; | 25 | GLuint instance_id; |
| 26 | GLuint flip_stage; | ||
| 27 | GLfloat y_direction; | ||
| 28 | }; | ||
| 26 | struct alignas(16) { | 29 | struct alignas(16) { |
| 27 | GLuint enabled; | 30 | GLuint enabled; |
| 28 | GLuint func; | 31 | GLuint func; |
| @@ -30,7 +33,7 @@ struct MaxwellUniformData { | |||
| 30 | GLuint padding; | 33 | GLuint padding; |
| 31 | } alpha_test; | 34 | } alpha_test; |
| 32 | }; | 35 | }; |
| 33 | static_assert(sizeof(MaxwellUniformData) == 64, "MaxwellUniformData structure size is incorrect"); | 36 | static_assert(sizeof(MaxwellUniformData) == 48, "MaxwellUniformData structure size is incorrect"); |
| 34 | static_assert(sizeof(MaxwellUniformData) < 16384, | 37 | static_assert(sizeof(MaxwellUniformData) < 16384, |
| 35 | "MaxwellUniformData structure must be less than 16kb as per the OpenGL spec"); | 38 | "MaxwellUniformData structure must be less than 16kb as per the OpenGL spec"); |
| 36 | 39 | ||
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index 934f4db78..b3bfad6a0 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp | |||
| @@ -92,6 +92,13 @@ OpenGLState::OpenGLState() { | |||
| 92 | 92 | ||
| 93 | point.size = 1; | 93 | point.size = 1; |
| 94 | fragment_color_clamp.enabled = false; | 94 | fragment_color_clamp.enabled = false; |
| 95 | |||
| 96 | polygon_offset.fill_enable = false; | ||
| 97 | polygon_offset.line_enable = false; | ||
| 98 | polygon_offset.point_enable = false; | ||
| 99 | polygon_offset.factor = 0.0f; | ||
| 100 | polygon_offset.units = 0.0f; | ||
| 101 | polygon_offset.clamp = 0.0f; | ||
| 95 | } | 102 | } |
| 96 | 103 | ||
| 97 | void OpenGLState::ApplyDefaultState() { | 104 | void OpenGLState::ApplyDefaultState() { |
| @@ -406,6 +413,55 @@ void OpenGLState::ApplyLogicOp() const { | |||
| 406 | } | 413 | } |
| 407 | } | 414 | } |
| 408 | 415 | ||
| 416 | void OpenGLState::ApplyPolygonOffset() const { | ||
| 417 | |||
| 418 | const bool fill_enable_changed = | ||
| 419 | polygon_offset.fill_enable != cur_state.polygon_offset.fill_enable; | ||
| 420 | const bool line_enable_changed = | ||
| 421 | polygon_offset.line_enable != cur_state.polygon_offset.line_enable; | ||
| 422 | const bool point_enable_changed = | ||
| 423 | polygon_offset.point_enable != cur_state.polygon_offset.point_enable; | ||
| 424 | const bool factor_changed = polygon_offset.factor != cur_state.polygon_offset.factor; | ||
| 425 | const bool units_changed = polygon_offset.units != cur_state.polygon_offset.units; | ||
| 426 | const bool clamp_changed = polygon_offset.clamp != cur_state.polygon_offset.clamp; | ||
| 427 | |||
| 428 | if (fill_enable_changed) { | ||
| 429 | if (polygon_offset.fill_enable) { | ||
| 430 | glEnable(GL_POLYGON_OFFSET_FILL); | ||
| 431 | } else { | ||
| 432 | glDisable(GL_POLYGON_OFFSET_FILL); | ||
| 433 | } | ||
| 434 | } | ||
| 435 | |||
| 436 | if (line_enable_changed) { | ||
| 437 | if (polygon_offset.line_enable) { | ||
| 438 | glEnable(GL_POLYGON_OFFSET_LINE); | ||
| 439 | } else { | ||
| 440 | glDisable(GL_POLYGON_OFFSET_LINE); | ||
| 441 | } | ||
| 442 | } | ||
| 443 | |||
| 444 | if (point_enable_changed) { | ||
| 445 | if (polygon_offset.point_enable) { | ||
| 446 | glEnable(GL_POLYGON_OFFSET_POINT); | ||
| 447 | } else { | ||
| 448 | glDisable(GL_POLYGON_OFFSET_POINT); | ||
| 449 | } | ||
| 450 | } | ||
| 451 | |||
| 452 | if ((polygon_offset.fill_enable || polygon_offset.line_enable || polygon_offset.point_enable) && | ||
| 453 | (factor_changed || units_changed || clamp_changed)) { | ||
| 454 | |||
| 455 | if (GLAD_GL_EXT_polygon_offset_clamp && polygon_offset.clamp != 0) { | ||
| 456 | glPolygonOffsetClamp(polygon_offset.factor, polygon_offset.units, polygon_offset.clamp); | ||
| 457 | } else { | ||
| 458 | glPolygonOffset(polygon_offset.factor, polygon_offset.units); | ||
| 459 | UNIMPLEMENTED_IF_MSG(polygon_offset.clamp != 0, | ||
| 460 | "Unimplemented Depth polygon offset clamp."); | ||
| 461 | } | ||
| 462 | } | ||
| 463 | } | ||
| 464 | |||
| 409 | void OpenGLState::ApplyTextures() const { | 465 | void OpenGLState::ApplyTextures() const { |
| 410 | for (std::size_t i = 0; i < std::size(texture_units); ++i) { | 466 | for (std::size_t i = 0; i < std::size(texture_units); ++i) { |
| 411 | const auto& texture_unit = texture_units[i]; | 467 | const auto& texture_unit = texture_units[i]; |
| @@ -532,6 +588,7 @@ void OpenGLState::Apply() const { | |||
| 532 | ApplyLogicOp(); | 588 | ApplyLogicOp(); |
| 533 | ApplyTextures(); | 589 | ApplyTextures(); |
| 534 | ApplySamplers(); | 590 | ApplySamplers(); |
| 591 | ApplyPolygonOffset(); | ||
| 535 | cur_state = *this; | 592 | cur_state = *this; |
| 536 | } | 593 | } |
| 537 | 594 | ||
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index 032fc43f0..0bf19ed07 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h | |||
| @@ -176,6 +176,15 @@ public: | |||
| 176 | float size; // GL_POINT_SIZE | 176 | float size; // GL_POINT_SIZE |
| 177 | } point; | 177 | } point; |
| 178 | 178 | ||
| 179 | struct { | ||
| 180 | bool point_enable; | ||
| 181 | bool line_enable; | ||
| 182 | bool fill_enable; | ||
| 183 | GLfloat units; | ||
| 184 | GLfloat factor; | ||
| 185 | GLfloat clamp; | ||
| 186 | } polygon_offset; | ||
| 187 | |||
| 179 | std::array<bool, 2> clip_distance; // GL_CLIP_DISTANCE | 188 | std::array<bool, 2> clip_distance; // GL_CLIP_DISTANCE |
| 180 | 189 | ||
| 181 | OpenGLState(); | 190 | OpenGLState(); |
| @@ -226,6 +235,7 @@ private: | |||
| 226 | void ApplyLogicOp() const; | 235 | void ApplyLogicOp() const; |
| 227 | void ApplyTextures() const; | 236 | void ApplyTextures() const; |
| 228 | void ApplySamplers() const; | 237 | void ApplySamplers() const; |
| 238 | void ApplyPolygonOffset() const; | ||
| 229 | }; | 239 | }; |
| 230 | 240 | ||
| 231 | } // namespace OpenGL | 241 | } // namespace OpenGL |
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index 7ee572761..ec46dc4e3 100644 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp | |||
| @@ -4,11 +4,9 @@ | |||
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <memory> | 6 | #include <memory> |
| 7 | #include <utility> | 7 | |
| 8 | #include <QMenu> | ||
| 9 | #include <QMessageBox> | ||
| 10 | #include <QTimer> | 8 | #include <QTimer> |
| 11 | #include "common/param_package.h" | 9 | |
| 12 | #include "configuration/configure_touchscreen_advanced.h" | 10 | #include "configuration/configure_touchscreen_advanced.h" |
| 13 | #include "core/core.h" | 11 | #include "core/core.h" |
| 14 | #include "core/hle/service/am/am.h" | 12 | #include "core/hle/service/am/am.h" |
| @@ -16,16 +14,25 @@ | |||
| 16 | #include "core/hle/service/am/applet_oe.h" | 14 | #include "core/hle/service/am/applet_oe.h" |
| 17 | #include "core/hle/service/hid/controllers/npad.h" | 15 | #include "core/hle/service/hid/controllers/npad.h" |
| 18 | #include "core/hle/service/sm/sm.h" | 16 | #include "core/hle/service/sm/sm.h" |
| 19 | #include "input_common/main.h" | ||
| 20 | #include "ui_configure_input.h" | 17 | #include "ui_configure_input.h" |
| 21 | #include "ui_configure_input_player.h" | 18 | #include "ui_configure_input_player.h" |
| 22 | #include "ui_configure_mouse_advanced.h" | ||
| 23 | #include "ui_configure_touchscreen_advanced.h" | ||
| 24 | #include "yuzu/configuration/config.h" | ||
| 25 | #include "yuzu/configuration/configure_input.h" | 19 | #include "yuzu/configuration/configure_input.h" |
| 26 | #include "yuzu/configuration/configure_input_player.h" | 20 | #include "yuzu/configuration/configure_input_player.h" |
| 27 | #include "yuzu/configuration/configure_mouse_advanced.h" | 21 | #include "yuzu/configuration/configure_mouse_advanced.h" |
| 28 | 22 | ||
| 23 | namespace { | ||
| 24 | template <typename Dialog, typename... Args> | ||
| 25 | void CallConfigureDialog(ConfigureInput& parent, Args&&... args) { | ||
| 26 | parent.applyConfiguration(); | ||
| 27 | Dialog dialog(&parent, std::forward<Args>(args)...); | ||
| 28 | |||
| 29 | const auto res = dialog.exec(); | ||
| 30 | if (res == QDialog::Accepted) { | ||
| 31 | dialog.applyConfiguration(); | ||
| 32 | } | ||
| 33 | } | ||
| 34 | } // Anonymous namespace | ||
| 35 | |||
| 29 | ConfigureInput::ConfigureInput(QWidget* parent) | 36 | ConfigureInput::ConfigureInput(QWidget* parent) |
| 30 | : QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()) { | 37 | : QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()) { |
| 31 | ui->setupUi(this); | 38 | ui->setupUi(this); |
| @@ -65,31 +72,20 @@ ConfigureInput::ConfigureInput(QWidget* parent) | |||
| 65 | 72 | ||
| 66 | for (std::size_t i = 0; i < players_configure.size(); ++i) { | 73 | for (std::size_t i = 0; i < players_configure.size(); ++i) { |
| 67 | connect(players_configure[i], &QPushButton::pressed, this, | 74 | connect(players_configure[i], &QPushButton::pressed, this, |
| 68 | [this, i]() { CallConfigureDialog<ConfigureInputPlayer>(i, false); }); | 75 | [this, i] { CallConfigureDialog<ConfigureInputPlayer>(*this, i, false); }); |
| 69 | } | 76 | } |
| 70 | 77 | ||
| 71 | connect(ui->handheld_configure, &QPushButton::pressed, this, | 78 | connect(ui->handheld_configure, &QPushButton::pressed, this, |
| 72 | [this]() { CallConfigureDialog<ConfigureInputPlayer>(8, false); }); | 79 | [this] { CallConfigureDialog<ConfigureInputPlayer>(*this, 8, false); }); |
| 73 | 80 | ||
| 74 | connect(ui->debug_configure, &QPushButton::pressed, this, | 81 | connect(ui->debug_configure, &QPushButton::pressed, this, |
| 75 | [this]() { CallConfigureDialog<ConfigureInputPlayer>(9, true); }); | 82 | [this] { CallConfigureDialog<ConfigureInputPlayer>(*this, 9, true); }); |
| 76 | 83 | ||
| 77 | connect(ui->mouse_advanced, &QPushButton::pressed, this, | 84 | connect(ui->mouse_advanced, &QPushButton::pressed, this, |
| 78 | [this]() { CallConfigureDialog<ConfigureMouseAdvanced>(); }); | 85 | [this] { CallConfigureDialog<ConfigureMouseAdvanced>(*this); }); |
| 79 | 86 | ||
| 80 | connect(ui->touchscreen_advanced, &QPushButton::pressed, this, | 87 | connect(ui->touchscreen_advanced, &QPushButton::pressed, this, |
| 81 | [this]() { CallConfigureDialog<ConfigureTouchscreenAdvanced>(); }); | 88 | [this] { CallConfigureDialog<ConfigureTouchscreenAdvanced>(*this); }); |
| 82 | } | ||
| 83 | |||
| 84 | template <typename Dialog, typename... Args> | ||
| 85 | void ConfigureInput::CallConfigureDialog(Args&&... args) { | ||
| 86 | this->applyConfiguration(); | ||
| 87 | Dialog dialog(this, std::forward<Args>(args)...); | ||
| 88 | |||
| 89 | const auto res = dialog.exec(); | ||
| 90 | if (res == QDialog::Accepted) { | ||
| 91 | dialog.applyConfiguration(); | ||
| 92 | } | ||
| 93 | } | 89 | } |
| 94 | 90 | ||
| 95 | void ConfigureInput::OnDockedModeChanged(bool last_state, bool new_state) { | 91 | void ConfigureInput::OnDockedModeChanged(bool last_state, bool new_state) { |
diff --git a/src/yuzu/configuration/configure_input.h b/src/yuzu/configuration/configure_input.h index 29a8a03f8..e8723dfcb 100644 --- a/src/yuzu/configuration/configure_input.h +++ b/src/yuzu/configuration/configure_input.h | |||
| @@ -5,20 +5,12 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <functional> | ||
| 9 | #include <memory> | 8 | #include <memory> |
| 10 | #include <optional> | ||
| 11 | #include <string> | ||
| 12 | #include <unordered_map> | ||
| 13 | 9 | ||
| 14 | #include <QKeyEvent> | 10 | #include <QKeyEvent> |
| 15 | #include <QWidget> | 11 | #include <QWidget> |
| 16 | 12 | ||
| 17 | #include "common/param_package.h" | ||
| 18 | #include "core/settings.h" | ||
| 19 | #include "input_common/main.h" | ||
| 20 | #include "ui_configure_input.h" | 13 | #include "ui_configure_input.h" |
| 21 | #include "yuzu/configuration/config.h" | ||
| 22 | 14 | ||
| 23 | class QPushButton; | 15 | class QPushButton; |
| 24 | class QString; | 16 | class QString; |
| @@ -40,9 +32,6 @@ public: | |||
| 40 | private: | 32 | private: |
| 41 | void updateUIEnabled(); | 33 | void updateUIEnabled(); |
| 42 | 34 | ||
| 43 | template <typename Dialog, typename... Args> | ||
| 44 | void CallConfigureDialog(Args&&... args); | ||
| 45 | |||
| 46 | void OnDockedModeChanged(bool last_state, bool new_state); | 35 | void OnDockedModeChanged(bool last_state, bool new_state); |
| 47 | 36 | ||
| 48 | /// Load configuration settings. | 37 | /// Load configuration settings. |
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index ba6e09368..7dadd83c1 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp | |||
| @@ -25,13 +25,6 @@ const std::array<std::string, ConfigureInputPlayer::ANALOG_SUB_BUTTONS_NUM> | |||
| 25 | "modifier", | 25 | "modifier", |
| 26 | }}; | 26 | }}; |
| 27 | 27 | ||
| 28 | static void MoveGridElement(QGridLayout* grid, int row_old, int column_old, int row_new, | ||
| 29 | int column_new) { | ||
| 30 | const auto item = grid->itemAtPosition(row_old, column_old); | ||
| 31 | // grid->removeItem(item); | ||
| 32 | grid->addItem(item, row_new, column_new); | ||
| 33 | } | ||
| 34 | |||
| 35 | static void LayerGridElements(QGridLayout* grid, QWidget* item, QWidget* onTopOf) { | 28 | static void LayerGridElements(QGridLayout* grid, QWidget* item, QWidget* onTopOf) { |
| 36 | const int index1 = grid->indexOf(item); | 29 | const int index1 = grid->indexOf(item); |
| 37 | const int index2 = grid->indexOf(onTopOf); | 30 | const int index2 = grid->indexOf(onTopOf); |
| @@ -111,11 +104,10 @@ static QString AnalogToText(const Common::ParamPackage& param, const std::string | |||
| 111 | } | 104 | } |
| 112 | }; | 105 | }; |
| 113 | 106 | ||
| 114 | ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, u8 player_index, bool debug) | 107 | ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_index, bool debug) |
| 115 | : QDialog(parent), ui(std::make_unique<Ui::ConfigureInputPlayer>()), | 108 | : QDialog(parent), ui(std::make_unique<Ui::ConfigureInputPlayer>()), player_index(player_index), |
| 116 | timeout_timer(std::make_unique<QTimer>()), poll_timer(std::make_unique<QTimer>()), | 109 | debug(debug), timeout_timer(std::make_unique<QTimer>()), |
| 117 | player_index(player_index), debug(debug) { | 110 | poll_timer(std::make_unique<QTimer>()) { |
| 118 | |||
| 119 | ui->setupUi(this); | 111 | ui->setupUi(this); |
| 120 | setFocusPolicy(Qt::ClickFocus); | 112 | setFocusPolicy(Qt::ClickFocus); |
| 121 | 113 | ||
| @@ -315,7 +307,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, u8 player_index, boo | |||
| 315 | 307 | ||
| 316 | for (std::size_t i = 0; i < controller_color_buttons.size(); ++i) { | 308 | for (std::size_t i = 0; i < controller_color_buttons.size(); ++i) { |
| 317 | connect(controller_color_buttons[i], &QPushButton::clicked, this, | 309 | connect(controller_color_buttons[i], &QPushButton::clicked, this, |
| 318 | std::bind(&ConfigureInputPlayer::OnControllerButtonClick, this, i)); | 310 | [this, i] { OnControllerButtonClick(static_cast<int>(i)); }); |
| 319 | } | 311 | } |
| 320 | 312 | ||
| 321 | this->loadConfiguration(); | 313 | this->loadConfiguration(); |
diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h index b0e5550c5..7a53f6715 100644 --- a/src/yuzu/configuration/configure_input_player.h +++ b/src/yuzu/configuration/configure_input_player.h | |||
| @@ -9,9 +9,10 @@ | |||
| 9 | #include <memory> | 9 | #include <memory> |
| 10 | #include <optional> | 10 | #include <optional> |
| 11 | #include <string> | 11 | #include <string> |
| 12 | #include <unordered_map> | 12 | |
| 13 | #include <QDialog> | 13 | #include <QDialog> |
| 14 | #include <QKeyEvent> | 14 | #include <QKeyEvent> |
| 15 | |||
| 15 | #include "common/param_package.h" | 16 | #include "common/param_package.h" |
| 16 | #include "core/settings.h" | 17 | #include "core/settings.h" |
| 17 | #include "input_common/main.h" | 18 | #include "input_common/main.h" |
| @@ -29,16 +30,39 @@ class ConfigureInputPlayer : public QDialog { | |||
| 29 | Q_OBJECT | 30 | Q_OBJECT |
| 30 | 31 | ||
| 31 | public: | 32 | public: |
| 32 | explicit ConfigureInputPlayer(QWidget* parent, u8 player_index, bool debug = false); | 33 | explicit ConfigureInputPlayer(QWidget* parent, std::size_t player_index, bool debug = false); |
| 33 | ~ConfigureInputPlayer() override; | 34 | ~ConfigureInputPlayer() override; |
| 34 | 35 | ||
| 35 | /// Save all button configurations to settings file | 36 | /// Save all button configurations to settings file |
| 36 | void applyConfiguration(); | 37 | void applyConfiguration(); |
| 37 | 38 | ||
| 38 | private: | 39 | private: |
| 40 | void OnControllerButtonClick(int i); | ||
| 41 | |||
| 42 | /// Load configuration settings. | ||
| 43 | void loadConfiguration(); | ||
| 44 | /// Restore all buttons to their default values. | ||
| 45 | void restoreDefaults(); | ||
| 46 | /// Clear all input configuration | ||
| 47 | void ClearAll(); | ||
| 48 | |||
| 49 | /// Update UI to reflect current configuration. | ||
| 50 | void updateButtonLabels(); | ||
| 51 | |||
| 52 | /// Called when the button was pressed. | ||
| 53 | void handleClick(QPushButton* button, | ||
| 54 | std::function<void(const Common::ParamPackage&)> new_input_setter, | ||
| 55 | InputCommon::Polling::DeviceType type); | ||
| 56 | |||
| 57 | /// Finish polling and configure input using the input_setter | ||
| 58 | void setPollingResult(const Common::ParamPackage& params, bool abort); | ||
| 59 | |||
| 60 | /// Handle key press events. | ||
| 61 | void keyPressEvent(QKeyEvent* event) override; | ||
| 62 | |||
| 39 | std::unique_ptr<Ui::ConfigureInputPlayer> ui; | 63 | std::unique_ptr<Ui::ConfigureInputPlayer> ui; |
| 40 | 64 | ||
| 41 | u8 player_index; | 65 | std::size_t player_index; |
| 42 | bool debug; | 66 | bool debug; |
| 43 | 67 | ||
| 44 | std::unique_ptr<QTimer> timeout_timer; | 68 | std::unique_ptr<QTimer> timeout_timer; |
| @@ -77,27 +101,4 @@ private: | |||
| 77 | 101 | ||
| 78 | std::array<QPushButton*, 4> controller_color_buttons; | 102 | std::array<QPushButton*, 4> controller_color_buttons; |
| 79 | std::array<QColor, 4> controller_colors; | 103 | std::array<QColor, 4> controller_colors; |
| 80 | |||
| 81 | void OnControllerButtonClick(int i); | ||
| 82 | |||
| 83 | /// Load configuration settings. | ||
| 84 | void loadConfiguration(); | ||
| 85 | /// Restore all buttons to their default values. | ||
| 86 | void restoreDefaults(); | ||
| 87 | /// Clear all input configuration | ||
| 88 | void ClearAll(); | ||
| 89 | |||
| 90 | /// Update UI to reflect current configuration. | ||
| 91 | void updateButtonLabels(); | ||
| 92 | |||
| 93 | /// Called when the button was pressed. | ||
| 94 | void handleClick(QPushButton* button, | ||
| 95 | std::function<void(const Common::ParamPackage&)> new_input_setter, | ||
| 96 | InputCommon::Polling::DeviceType type); | ||
| 97 | |||
| 98 | /// Finish polling and configure input using the input_setter | ||
| 99 | void setPollingResult(const Common::ParamPackage& params, bool abort); | ||
| 100 | |||
| 101 | /// Handle key press events. | ||
| 102 | void keyPressEvent(QKeyEvent* event) override; | ||
| 103 | }; | 104 | }; |
diff --git a/src/yuzu/configuration/configure_mouse_advanced.cpp b/src/yuzu/configuration/configure_mouse_advanced.cpp index dab58fbaa..ef857035e 100644 --- a/src/yuzu/configuration/configure_mouse_advanced.cpp +++ b/src/yuzu/configuration/configure_mouse_advanced.cpp | |||
| @@ -4,11 +4,11 @@ | |||
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <memory> | 6 | #include <memory> |
| 7 | #include <utility> | 7 | |
| 8 | #include <QKeyEvent> | 8 | #include <QKeyEvent> |
| 9 | #include <QMenu> | 9 | #include <QMenu> |
| 10 | #include <QMessageBox> | ||
| 11 | #include <QTimer> | 10 | #include <QTimer> |
| 11 | |||
| 12 | #include "common/assert.h" | 12 | #include "common/assert.h" |
| 13 | #include "common/param_package.h" | 13 | #include "common/param_package.h" |
| 14 | #include "input_common/main.h" | 14 | #include "input_common/main.h" |
diff --git a/src/yuzu/configuration/configure_mouse_advanced.h b/src/yuzu/configuration/configure_mouse_advanced.h index 218df2bda..e04da4bf2 100644 --- a/src/yuzu/configuration/configure_mouse_advanced.h +++ b/src/yuzu/configuration/configure_mouse_advanced.h | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <optional> | 8 | #include <optional> |
| 9 | #include <QDialog> | 9 | #include <QDialog> |
| 10 | #include <QWidget> | 10 | |
| 11 | #include "core/settings.h" | 11 | #include "core/settings.h" |
| 12 | 12 | ||
| 13 | class QCheckBox; | 13 | class QCheckBox; |
| @@ -28,23 +28,6 @@ public: | |||
| 28 | void applyConfiguration(); | 28 | void applyConfiguration(); |
| 29 | 29 | ||
| 30 | private: | 30 | private: |
| 31 | std::unique_ptr<Ui::ConfigureMouseAdvanced> ui; | ||
| 32 | |||
| 33 | /// This will be the the setting function when an input is awaiting configuration. | ||
| 34 | std::optional<std::function<void(const Common::ParamPackage&)>> input_setter; | ||
| 35 | |||
| 36 | std::array<QPushButton*, Settings::NativeMouseButton::NumMouseButtons> button_map; | ||
| 37 | std::array<Common::ParamPackage, Settings::NativeMouseButton::NumMouseButtons> buttons_param; | ||
| 38 | |||
| 39 | std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> device_pollers; | ||
| 40 | |||
| 41 | std::unique_ptr<QTimer> timeout_timer; | ||
| 42 | std::unique_ptr<QTimer> poll_timer; | ||
| 43 | |||
| 44 | /// A flag to indicate if keyboard keys are okay when configuring an input. If this is false, | ||
| 45 | /// keyboard events are ignored. | ||
| 46 | bool want_keyboard_keys = false; | ||
| 47 | |||
| 48 | /// Load configuration settings. | 31 | /// Load configuration settings. |
| 49 | void loadConfiguration(); | 32 | void loadConfiguration(); |
| 50 | /// Restore all buttons to their default values. | 33 | /// Restore all buttons to their default values. |
| @@ -65,4 +48,21 @@ private: | |||
| 65 | 48 | ||
| 66 | /// Handle key press events. | 49 | /// Handle key press events. |
| 67 | void keyPressEvent(QKeyEvent* event) override; | 50 | void keyPressEvent(QKeyEvent* event) override; |
| 51 | |||
| 52 | std::unique_ptr<Ui::ConfigureMouseAdvanced> ui; | ||
| 53 | |||
| 54 | /// This will be the the setting function when an input is awaiting configuration. | ||
| 55 | std::optional<std::function<void(const Common::ParamPackage&)>> input_setter; | ||
| 56 | |||
| 57 | std::array<QPushButton*, Settings::NativeMouseButton::NumMouseButtons> button_map; | ||
| 58 | std::array<Common::ParamPackage, Settings::NativeMouseButton::NumMouseButtons> buttons_param; | ||
| 59 | |||
| 60 | std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> device_pollers; | ||
| 61 | |||
| 62 | std::unique_ptr<QTimer> timeout_timer; | ||
| 63 | std::unique_ptr<QTimer> poll_timer; | ||
| 64 | |||
| 65 | /// A flag to indicate if keyboard keys are okay when configuring an input. If this is false, | ||
| 66 | /// keyboard events are ignored. | ||
| 67 | bool want_keyboard_keys = false; | ||
| 68 | }; | 68 | }; |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 9c6d150a5..93bf117c8 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -1105,14 +1105,14 @@ void GMainWindow::OnMenuInstallToNAND() { | |||
| 1105 | return; | 1105 | return; |
| 1106 | } | 1106 | } |
| 1107 | const auto res = | 1107 | const auto res = |
| 1108 | Service::FileSystem::GetUserNANDContents()->InstallEntry(nsp, false, qt_raw_copy); | 1108 | Service::FileSystem::GetUserNANDContents()->InstallEntry(*nsp, false, qt_raw_copy); |
| 1109 | if (res == FileSys::InstallResult::Success) { | 1109 | if (res == FileSys::InstallResult::Success) { |
| 1110 | success(); | 1110 | success(); |
| 1111 | } else { | 1111 | } else { |
| 1112 | if (res == FileSys::InstallResult::ErrorAlreadyExists) { | 1112 | if (res == FileSys::InstallResult::ErrorAlreadyExists) { |
| 1113 | if (overwrite()) { | 1113 | if (overwrite()) { |
| 1114 | const auto res2 = Service::FileSystem::GetUserNANDContents()->InstallEntry( | 1114 | const auto res2 = Service::FileSystem::GetUserNANDContents()->InstallEntry( |
| 1115 | nsp, true, qt_raw_copy); | 1115 | *nsp, true, qt_raw_copy); |
| 1116 | if (res2 == FileSys::InstallResult::Success) { | 1116 | if (res2 == FileSys::InstallResult::Success) { |
| 1117 | success(); | 1117 | success(); |
| 1118 | } else { | 1118 | } else { |
| @@ -1167,10 +1167,10 @@ void GMainWindow::OnMenuInstallToNAND() { | |||
| 1167 | FileSys::InstallResult res; | 1167 | FileSys::InstallResult res; |
| 1168 | if (index >= static_cast<size_t>(FileSys::TitleType::Application)) { | 1168 | if (index >= static_cast<size_t>(FileSys::TitleType::Application)) { |
| 1169 | res = Service::FileSystem::GetUserNANDContents()->InstallEntry( | 1169 | res = Service::FileSystem::GetUserNANDContents()->InstallEntry( |
| 1170 | nca, static_cast<FileSys::TitleType>(index), false, qt_raw_copy); | 1170 | *nca, static_cast<FileSys::TitleType>(index), false, qt_raw_copy); |
| 1171 | } else { | 1171 | } else { |
| 1172 | res = Service::FileSystem::GetSystemNANDContents()->InstallEntry( | 1172 | res = Service::FileSystem::GetSystemNANDContents()->InstallEntry( |
| 1173 | nca, static_cast<FileSys::TitleType>(index), false, qt_raw_copy); | 1173 | *nca, static_cast<FileSys::TitleType>(index), false, qt_raw_copy); |
| 1174 | } | 1174 | } |
| 1175 | 1175 | ||
| 1176 | if (res == FileSys::InstallResult::Success) { | 1176 | if (res == FileSys::InstallResult::Success) { |
| @@ -1178,7 +1178,7 @@ void GMainWindow::OnMenuInstallToNAND() { | |||
| 1178 | } else if (res == FileSys::InstallResult::ErrorAlreadyExists) { | 1178 | } else if (res == FileSys::InstallResult::ErrorAlreadyExists) { |
| 1179 | if (overwrite()) { | 1179 | if (overwrite()) { |
| 1180 | const auto res2 = Service::FileSystem::GetUserNANDContents()->InstallEntry( | 1180 | const auto res2 = Service::FileSystem::GetUserNANDContents()->InstallEntry( |
| 1181 | nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy); | 1181 | *nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy); |
| 1182 | if (res2 == FileSys::InstallResult::Success) { | 1182 | if (res2 == FileSys::InstallResult::Success) { |
| 1183 | success(); | 1183 | success(); |
| 1184 | } else { | 1184 | } else { |