From cd46b267f5715c0900b409d7bcb97f6bc9a43d9e Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sun, 22 Jul 2018 15:33:07 -0400 Subject: [PATCH 01/49] string_util: Remove unnecessary std::string instance in TabsToSpaces() We can just use the variant of std::string's replace() function that can replace an occurrence with N copies of the same character, eliminating the need to allocate a std::string containing a buffer of spaces. --- src/common/string_util.cpp | 13 ++++++------- src/common/string_util.h | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index f3ad3d68a4..2099eebb8b 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp @@ -168,15 +168,14 @@ void SplitString(const std::string& str, const char delim, std::vector& output); From 26a157cd31676f419420078e7d99df90d9fbc910 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sun, 22 Jul 2018 15:36:30 -0400 Subject: [PATCH 02/49] string_util: Use emplace_back() in SplitString() instead of push_back() This is equivalent to doing: push_back(std::string("")); which is likely not to cause issues, assuming a decent std::string implementation with small-string optimizations implemented in its design, however it's still a little unnecessary to copy that buffer regardless. Instead, we can use emplace_back() to directly construct the empty string within the std::vector instance, eliminating any possible overhead from the copy. --- src/common/string_util.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index 2099eebb8b..6737655a54 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp @@ -162,8 +162,9 @@ void SplitString(const std::string& str, const char delim, std::vector Date: Sun, 22 Jul 2018 15:47:37 -0400 Subject: [PATCH 03/49] string_util: Get rid of separate resize() in CPToUTF16(), UTF16ToUTF8(), CodeToUTF8() and UTF8ToUTF16() There's no need to perform the resize separately here, since the constructor allows presizing the buffer. Also move the empty string check before the construction of the string to make the early out more straightforward. --- src/common/string_util.cpp | 42 ++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index 6737655a54..1f0456aee9 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp @@ -220,31 +220,37 @@ std::u16string UTF8ToUTF16(const std::string& input) { } static std::wstring CPToUTF16(u32 code_page, const std::string& input) { - auto const size = + const auto size = MultiByteToWideChar(code_page, 0, input.data(), static_cast(input.size()), nullptr, 0); - std::wstring output; - output.resize(size); + if (size == 0) { + return L""; + } - if (size == 0 || - size != MultiByteToWideChar(code_page, 0, input.data(), static_cast(input.size()), - &output[0], static_cast(output.size()))) + std::wstring output(size, L'\0'); + + if (size != MultiByteToWideChar(code_page, 0, input.data(), static_cast(input.size()), + &output[0], static_cast(output.size()))) { output.clear(); + } return output; } std::string UTF16ToUTF8(const std::wstring& input) { - auto const size = WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast(input.size()), + const auto size = WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast(input.size()), nullptr, 0, nullptr, nullptr); + if (size == 0) { + return ""; + } - std::string output; - output.resize(size); + std::string output(size, '\0'); - if (size == 0 || - size != WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast(input.size()), - &output[0], static_cast(output.size()), nullptr, nullptr)) + if (size != WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast(input.size()), + &output[0], static_cast(output.size()), nullptr, + nullptr)) { output.clear(); + } return output; } @@ -265,8 +271,6 @@ std::string CP1252ToUTF8(const std::string& input) { template static std::string CodeToUTF8(const char* fromcode, const std::basic_string& input) { - std::string result; - iconv_t const conv_desc = iconv_open("UTF-8", fromcode); if ((iconv_t)(-1) == conv_desc) { LOG_ERROR(Common, "Iconv initialization failure [{}]: {}", fromcode, strerror(errno)); @@ -278,8 +282,7 @@ static std::string CodeToUTF8(const char* fromcode, const std::basic_string& // Multiply by 4, which is the max number of bytes to encode a codepoint const size_t out_buffer_size = 4 * in_bytes; - std::string out_buffer; - out_buffer.resize(out_buffer_size); + std::string out_buffer(out_buffer_size, '\0'); auto src_buffer = &input[0]; size_t src_bytes = in_bytes; @@ -304,6 +307,7 @@ static std::string CodeToUTF8(const char* fromcode, const std::basic_string& } } + std::string result; out_buffer.resize(out_buffer_size - dst_bytes); out_buffer.swap(result); @@ -313,8 +317,6 @@ static std::string CodeToUTF8(const char* fromcode, const std::basic_string& } std::u16string UTF8ToUTF16(const std::string& input) { - std::u16string result; - iconv_t const conv_desc = iconv_open("UTF-16LE", "UTF-8"); if ((iconv_t)(-1) == conv_desc) { LOG_ERROR(Common, "Iconv initialization failure [UTF-8]: {}", strerror(errno)); @@ -326,8 +328,7 @@ std::u16string UTF8ToUTF16(const std::string& input) { // Multiply by 4, which is the max number of bytes to encode a codepoint const size_t out_buffer_size = 4 * sizeof(char16_t) * in_bytes; - std::u16string out_buffer; - out_buffer.resize(out_buffer_size); + std::u16string out_buffer(out_buffer_size, char16_t{}); char* src_buffer = const_cast(&input[0]); size_t src_bytes = in_bytes; @@ -352,6 +353,7 @@ std::u16string UTF8ToUTF16(const std::string& input) { } } + std::u16string result; out_buffer.resize(out_buffer_size - dst_bytes); out_buffer.swap(result); From 37aeecd29fb71152b58920a73a95a1df485f98c4 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sun, 22 Jul 2018 23:24:46 -0400 Subject: [PATCH 04/49] set: Correct return code size of value in GetAvailableLanguageCodes() The return code should be 32-bit in size. --- src/core/hle/service/set/set.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp index 886133b746..d102aed4b3 100644 --- a/src/core/hle/service/set/set.cpp +++ b/src/core/hle/service/set/set.cpp @@ -33,9 +33,9 @@ void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) { }}; ctx.WriteBuffer(available_language_codes); - IPC::ResponseBuilder rb{ctx, 4}; + IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push(static_cast(available_language_codes.size())); + rb.Push(static_cast(available_language_codes.size())); LOG_DEBUG(Service_SET, "called"); } From 22f448b6327044076959e338811ee576f3dcf093 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 23 Jul 2018 00:06:29 -0400 Subject: [PATCH 05/49] set: Implement GetAvailableLanguageCodeCount() This just returns the size of the language code buffer. --- src/core/hle/service/set/set.cpp | 49 ++++++++++++++++++-------------- src/core/hle/service/set/set.h | 1 + 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp index d102aed4b3..4195c9067a 100644 --- a/src/core/hle/service/set/set.cpp +++ b/src/core/hle/service/set/set.cpp @@ -11,26 +11,27 @@ namespace Service::Set { +constexpr std::array available_language_codes = {{ + LanguageCode::JA, + LanguageCode::EN_US, + LanguageCode::FR, + LanguageCode::DE, + LanguageCode::IT, + LanguageCode::ES, + LanguageCode::ZH_CN, + LanguageCode::KO, + LanguageCode::NL, + LanguageCode::PT, + LanguageCode::RU, + LanguageCode::ZH_TW, + LanguageCode::EN_GB, + LanguageCode::FR_CA, + LanguageCode::ES_419, + LanguageCode::ZH_HANS, + LanguageCode::ZH_HANT, +}}; + void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) { - static constexpr std::array available_language_codes = {{ - LanguageCode::JA, - LanguageCode::EN_US, - LanguageCode::FR, - LanguageCode::DE, - LanguageCode::IT, - LanguageCode::ES, - LanguageCode::ZH_CN, - LanguageCode::KO, - LanguageCode::NL, - LanguageCode::PT, - LanguageCode::RU, - LanguageCode::ZH_TW, - LanguageCode::EN_GB, - LanguageCode::FR_CA, - LanguageCode::ES_419, - LanguageCode::ZH_HANS, - LanguageCode::ZH_HANT, - }}; ctx.WriteBuffer(available_language_codes); IPC::ResponseBuilder rb{ctx, 3}; @@ -40,15 +41,21 @@ void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_SET, "called"); } +void SET::GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push(static_cast(available_language_codes.size())); +} + SET::SET() : ServiceFramework("set") { static const FunctionInfo functions[] = { {0, nullptr, "GetLanguageCode"}, {1, &SET::GetAvailableLanguageCodes, "GetAvailableLanguageCodes"}, {2, nullptr, "MakeLanguageCode"}, - {3, nullptr, "GetAvailableLanguageCodeCount"}, + {3, &SET::GetAvailableLanguageCodeCount, "GetAvailableLanguageCodeCount"}, {4, nullptr, "GetRegionCode"}, {5, &SET::GetAvailableLanguageCodes, "GetAvailableLanguageCodes2"}, - {6, nullptr, "GetAvailableLanguageCodeCount2"}, + {6, &SET::GetAvailableLanguageCodeCount, "GetAvailableLanguageCodeCount2"}, {7, nullptr, "GetKeyCodeMap"}, {8, nullptr, "GetQuestFlag"}, }; diff --git a/src/core/hle/service/set/set.h b/src/core/hle/service/set/set.h index ec0df0152e..a2472ec4cf 100644 --- a/src/core/hle/service/set/set.h +++ b/src/core/hle/service/set/set.h @@ -36,6 +36,7 @@ public: private: void GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx); + void GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx); }; } // namespace Service::Set From e8f641a52de33b33e0d6c73ee7ca07f06dcd8aeb Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Mon, 23 Jul 2018 12:33:24 -0400 Subject: [PATCH 06/49] NRO Assets and NACP file format Cleanup Review fixes --- src/core/CMakeLists.txt | 2 + src/core/file_sys/control_metadata.cpp | 42 +++++++++++++ src/core/file_sys/control_metadata.h | 81 ++++++++++++++++++++++++++ src/core/loader/nro.cpp | 79 ++++++++++++++++++++++++- src/core/loader/nro.h | 12 ++++ 5 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 src/core/file_sys/control_metadata.cpp create mode 100644 src/core/file_sys/control_metadata.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 27a5de7fd0..fd75854b05 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -12,6 +12,8 @@ add_library(core STATIC core_timing.h file_sys/content_archive.cpp file_sys/content_archive.h + file_sys/control_metadata.cpp + file_sys/control_metadata.h file_sys/directory.h file_sys/errors.h file_sys/mode.h diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp new file mode 100644 index 0000000000..3ddc9f162d --- /dev/null +++ b/src/core/file_sys/control_metadata.cpp @@ -0,0 +1,42 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/string_util.h" +#include "common/swap.h" +#include "core/file_sys/control_metadata.h" + +namespace FileSys { + +std::string LanguageEntry::GetApplicationName() const { + return Common::StringFromFixedZeroTerminatedBuffer(application_name.data(), 0x200); +} + +std::string LanguageEntry::GetDeveloperName() const { + return Common::StringFromFixedZeroTerminatedBuffer(developer_name.data(), 0x100); +} + +NACP::NACP(VirtualFile file_) : file(std::move(file_)), raw(std::make_unique()) { + file->ReadObject(raw.get()); +} + +const LanguageEntry& NACP::GetLanguageEntry(Language language) const { + return raw->language_entries.at(static_cast(language)); +} + +std::string NACP::GetApplicationName(Language language) const { + return GetLanguageEntry(language).GetApplicationName(); +} + +std::string NACP::GetDeveloperName(Language language) const { + return GetLanguageEntry(language).GetDeveloperName(); +} + +u64 NACP::GetTitleId() const { + return raw->title_id; +} + +std::string NACP::GetVersionString() const { + return Common::StringFromFixedZeroTerminatedBuffer(raw->version_string.data(), 0x10); +} +} // namespace FileSys diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h new file mode 100644 index 0000000000..cc3b745f7e --- /dev/null +++ b/src/core/file_sys/control_metadata.h @@ -0,0 +1,81 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include "common/common_funcs.h" +#include "core/file_sys/vfs.h" + +namespace FileSys { + +// A localized entry containing strings within the NACP. +// One for each language of type Language. +struct LanguageEntry { + std::array application_name; + std::array developer_name; + + std::string GetApplicationName() const; + std::string GetDeveloperName() const; +}; +static_assert(sizeof(LanguageEntry) == 0x300, "LanguageEntry has incorrect size."); + +// The raw file format of a NACP file. +struct RawNACP { + std::array language_entries; + INSERT_PADDING_BYTES(0x38); + u64_le title_id; + INSERT_PADDING_BYTES(0x20); + std::array version_string; + u64_le dlc_base_title_id; + u64_le title_id_2; + INSERT_PADDING_BYTES(0x28); + u64_le product_code; + u64_le title_id_3; + std::array title_id_array; + INSERT_PADDING_BYTES(0x8); + u64_le title_id_update; + std::array bcat_passphrase; + INSERT_PADDING_BYTES(0xEC0); +}; +static_assert(sizeof(RawNACP) == 0x4000, "RawNACP has incorrect size."); + +// A language on the NX. These are for names and icons. +enum class Language : u8 { + AmericanEnglish = 0, + BritishEnglish = 1, + Japanese = 2, + French = 3, + German = 4, + LatinAmericanSpanish = 5, + Spanish = 6, + Italian = 7, + Dutch = 8, + CanadianFrench = 9, + Portugese = 10, + Russian = 11, + Korean = 12, + Taiwanese = 13, + Chinese = 14, +}; + +// A class representing the format used by NX metadata files, typically named Control.nacp. +// These store application name, dev name, title id, and other miscellaneous data. +class NACP { +public: + explicit NACP(VirtualFile file); + const LanguageEntry& GetLanguageEntry(Language language = Language::AmericanEnglish) const; + std::string GetApplicationName(Language language = Language::AmericanEnglish) const; + std::string GetDeveloperName(Language language = Language::AmericanEnglish) const; + u64 GetTitleId() const; + std::string GetVersionString() const; + +private: + VirtualFile file; + std::unique_ptr raw; +}; + +} // namespace FileSys diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index c020399f27..44158655cb 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -10,6 +10,8 @@ #include "common/logging/log.h" #include "common/swap.h" #include "core/core.h" +#include "core/file_sys/control_metadata.h" +#include "core/file_sys/vfs_offset.h" #include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" @@ -49,7 +51,55 @@ struct ModHeader { }; static_assert(sizeof(ModHeader) == 0x1c, "ModHeader has incorrect size."); -AppLoader_NRO::AppLoader_NRO(FileSys::VirtualFile file) : AppLoader(std::move(file)) {} +struct AssetSection { + u64_le offset; + u64_le size; +}; +static_assert(sizeof(AssetSection) == 0x10, "AssetSection has incorrect size."); + +struct AssetHeader { + u32_le magic; + u32_le format_version; + AssetSection icon; + AssetSection nacp; + AssetSection romfs; +}; +static_assert(sizeof(AssetHeader) == 0x38, "AssetHeader has incorrect size."); + +AppLoader_NRO::AppLoader_NRO(FileSys::VirtualFile file) : AppLoader(file) { + NroHeader nro_header{}; + if (file->ReadObject(&nro_header) != sizeof(NroHeader)) + return; + + if (file->GetSize() >= nro_header.file_size + sizeof(AssetHeader)) { + u64 offset = nro_header.file_size; + AssetHeader asset_header{}; + if (file->ReadObject(&asset_header, offset) != sizeof(AssetHeader)) + return; + + if (asset_header.format_version != 0) + LOG_WARNING(Loader, + "NRO Asset Header has format {}, currently supported format is 0. If " + "strange glitches occur with metadata, check NRO assets.", + asset_header.format_version); + if (asset_header.magic != Common::MakeMagic('A', 'S', 'E', 'T')) + return; + + if (asset_header.nacp.size > 0) { + nacp = std::make_unique(std::make_shared( + file, asset_header.nacp.size, offset + asset_header.nacp.offset, "Control.nacp")); + } + + if (asset_header.romfs.size > 0) { + romfs = std::make_shared( + file, asset_header.romfs.size, offset + asset_header.romfs.offset, "game.romfs"); + } + + if (asset_header.icon.size > 0) { + icon_data = file->ReadBytes(asset_header.icon.size, offset + asset_header.icon.offset); + } + } +} FileType AppLoader_NRO::IdentifyType(const FileSys::VirtualFile& file) { // Read NSO header @@ -136,4 +186,31 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr& process) { return ResultStatus::Success; } +ResultStatus AppLoader_NRO::ReadIcon(std::vector& buffer) { + if (icon_data.empty()) + return ResultStatus::ErrorNotUsed; + buffer = icon_data; + return ResultStatus::Success; +} + +ResultStatus AppLoader_NRO::ReadProgramId(u64& out_program_id) { + if (nacp == nullptr) + return ResultStatus::ErrorNotUsed; + out_program_id = nacp->GetTitleId(); + return ResultStatus::Success; +} + +ResultStatus AppLoader_NRO::ReadRomFS(FileSys::VirtualFile& dir) { + if (romfs == nullptr) + return ResultStatus::ErrorNotUsed; + dir = romfs; + return ResultStatus::Success; +} + +ResultStatus AppLoader_NRO::ReadTitle(std::string& title) { + if (nacp == nullptr) + return ResultStatus::ErrorNotUsed; + title = nacp->GetApplicationName(); + return ResultStatus::Success; +} } // namespace Loader diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h index 2c03d06bb1..5f3fc40d26 100644 --- a/src/core/loader/nro.h +++ b/src/core/loader/nro.h @@ -6,12 +6,15 @@ #include #include "common/common_types.h" +#include "core/file_sys/control_metadata.h" #include "core/hle/kernel/kernel.h" #include "core/loader/linker.h" #include "core/loader/loader.h" namespace Loader { +struct AssetHeader; + /// Loads an NRO file class AppLoader_NRO final : public AppLoader, Linker { public: @@ -30,8 +33,17 @@ public: ResultStatus Load(Kernel::SharedPtr& process) override; + ResultStatus ReadIcon(std::vector& buffer) override; + ResultStatus ReadProgramId(u64& out_program_id) override; + ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; + ResultStatus ReadTitle(std::string& title) override; + private: bool LoadNro(FileSys::VirtualFile file, VAddr load_base); + + std::vector icon_data; + std::unique_ptr nacp; + FileSys::VirtualFile romfs; }; } // namespace Loader From e85308cd90f81885d5f31ed5cd89e82bf6b7d1e6 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 23 Jul 2018 12:37:40 -0400 Subject: [PATCH 07/49] set: Add missing log call in GetAvailableLanguageCodeCount() Forgot to include this in 22f448b6327044076959e338811ee576f3dcf093 --- src/core/hle/service/set/set.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp index 4195c9067a..1651f61229 100644 --- a/src/core/hle/service/set/set.cpp +++ b/src/core/hle/service/set/set.cpp @@ -45,6 +45,8 @@ void SET::GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); rb.Push(static_cast(available_language_codes.size())); + + LOG_DEBUG(Service_SET, "called"); } SET::SET() : ServiceFramework("set") { From 1f3889a2906b924aa3fadb419652d4d2182ec112 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 23 Jul 2018 12:49:44 -0400 Subject: [PATCH 08/49] hle: Remove shared_page.h/.cpp This is a holdover from citra that's essentially unused. --- src/core/CMakeLists.txt | 2 - src/core/hle/kernel/kernel.cpp | 2 - src/core/hle/kernel/memory.cpp | 1 - src/core/hle/kernel/wait_object.cpp | 1 - src/core/hle/shared_page.cpp | 86 ----------------------------- src/core/hle/shared_page.h | 69 ----------------------- 6 files changed, 161 deletions(-) delete mode 100644 src/core/hle/shared_page.cpp delete mode 100644 src/core/hle/shared_page.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 27a5de7fd0..5473723aad 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -249,8 +249,6 @@ add_library(core STATIC hle/service/vi/vi_s.h hle/service/vi/vi_u.cpp hle/service/vi/vi_u.h - hle/shared_page.cpp - hle/shared_page.h hw/hw.cpp hw/hw.h hw/lcd.cpp diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index b325b879b2..fae81e72b0 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -11,7 +11,6 @@ #include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/thread.h" #include "core/hle/kernel/timer.h" -#include "core/hle/shared_page.h" namespace Kernel { @@ -20,7 +19,6 @@ unsigned int Object::next_object_id; /// Initialize the kernel void Init(u32 system_mode) { ConfigMem::Init(); - SharedPage::Init(); Kernel::MemoryInit(system_mode); diff --git a/src/core/hle/kernel/memory.cpp b/src/core/hle/kernel/memory.cpp index d2600cdd79..ecbc5daae5 100644 --- a/src/core/hle/kernel/memory.cpp +++ b/src/core/hle/kernel/memory.cpp @@ -15,7 +15,6 @@ #include "core/hle/kernel/memory.h" #include "core/hle/kernel/vm_manager.h" #include "core/hle/result.h" -#include "core/hle/shared_page.h" #include "core/memory.h" #include "core/memory_setup.h" diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp index eb3c92e66a..e279c5df90 100644 --- a/src/core/hle/kernel/wait_object.cpp +++ b/src/core/hle/kernel/wait_object.cpp @@ -13,7 +13,6 @@ #include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/thread.h" #include "core/hle/kernel/timer.h" -#include "core/hle/shared_page.h" namespace Kernel { diff --git a/src/core/hle/shared_page.cpp b/src/core/hle/shared_page.cpp deleted file mode 100644 index 9ed8ab2490..0000000000 --- a/src/core/hle/shared_page.cpp +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include -#include "core/core_timing.h" -#include "core/hle/shared_page.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -namespace SharedPage { - -SharedPageDef shared_page; - -static CoreTiming::EventType* update_time_event; - -/// Gets system time in 3DS format. The epoch is Jan 1900, and the unit is millisecond. -static u64 GetSystemTime() { - auto now = std::chrono::system_clock::now(); - - // 3DS system does't allow user to set a time before Jan 1 2000, - // so we use it as an auxiliary epoch to calculate the console time. - std::tm epoch_tm; - epoch_tm.tm_sec = 0; - epoch_tm.tm_min = 0; - epoch_tm.tm_hour = 0; - epoch_tm.tm_mday = 1; - epoch_tm.tm_mon = 0; - epoch_tm.tm_year = 100; - epoch_tm.tm_isdst = 0; - auto epoch = std::chrono::system_clock::from_time_t(std::mktime(&epoch_tm)); - - // 3DS console time uses Jan 1 1900 as internal epoch, - // so we use the milliseconds between 1900 and 2000 as base console time - u64 console_time = 3155673600000ULL; - - // Only when system time is after 2000, we set it as 3DS system time - if (now > epoch) { - console_time += std::chrono::duration_cast(now - epoch).count(); - } - - // If the system time is in daylight saving, we give an additional hour to console time - std::time_t now_time_t = std::chrono::system_clock::to_time_t(now); - std::tm* now_tm = std::localtime(&now_time_t); - if (now_tm && now_tm->tm_isdst > 0) - console_time += 60 * 60 * 1000; - - return console_time; -} - -static void UpdateTimeCallback(u64 userdata, int cycles_late) { - DateTime& date_time = - shared_page.date_time_counter % 2 ? shared_page.date_time_0 : shared_page.date_time_1; - - date_time.date_time = GetSystemTime(); - date_time.update_tick = CoreTiming::GetTicks(); - date_time.tick_to_second_coefficient = CoreTiming::BASE_CLOCK_RATE; - date_time.tick_offset = 0; - - ++shared_page.date_time_counter; - - // system time is updated hourly - CoreTiming::ScheduleEvent(CoreTiming::msToCycles(60 * 60 * 1000) - cycles_late, - update_time_event); -} - -void Init() { - std::memset(&shared_page, 0, sizeof(shared_page)); - - shared_page.running_hw = 0x1; // product - - // Some games wait until this value becomes 0x1, before asking running_hw - shared_page.unknown_value = 0x1; - - // Set to a completely full battery - shared_page.battery_state.is_adapter_connected.Assign(1); - shared_page.battery_state.is_charging.Assign(1); - - update_time_event = - CoreTiming::RegisterEvent("SharedPage::UpdateTimeCallback", UpdateTimeCallback); - CoreTiming::ScheduleEvent(0, update_time_event); -} - -} // namespace SharedPage diff --git a/src/core/hle/shared_page.h b/src/core/hle/shared_page.h deleted file mode 100644 index a58259888c..0000000000 --- a/src/core/hle/shared_page.h +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -/** - * The shared page stores various runtime configuration settings. This memory page is - * read-only for user processes (there is a bit in the header that grants the process - * write access, according to 3dbrew; this is not emulated) - */ - -#include "common/bit_field.h" -#include "common/common_funcs.h" -#include "common/common_types.h" -#include "common/swap.h" -#include "core/memory.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -namespace SharedPage { - -// See http://3dbrew.org/wiki/Configuration_Memory#Shared_Memory_Page_For_ARM11_Processes - -struct DateTime { - u64_le date_time; // 0 - u64_le update_tick; // 8 - u64_le tick_to_second_coefficient; // 10 - u64_le tick_offset; // 18 -}; -static_assert(sizeof(DateTime) == 0x20, "Datetime size is wrong"); - -union BatteryState { - u8 raw; - BitField<0, 1, u8> is_adapter_connected; - BitField<1, 1, u8> is_charging; - BitField<2, 3, u8> charge_level; -}; - -struct SharedPageDef { - // Most of these names are taken from the 3dbrew page linked above. - u32_le date_time_counter; // 0 - u8 running_hw; // 4 - /// "Microcontroller hardware info" - u8 mcu_hw_info; // 5 - INSERT_PADDING_BYTES(0x20 - 0x6); // 6 - DateTime date_time_0; // 20 - DateTime date_time_1; // 40 - u8 wifi_macaddr[6]; // 60 - u8 wifi_link_level; // 66 - u8 wifi_unknown2; // 67 - INSERT_PADDING_BYTES(0x80 - 0x68); // 68 - float_le sliderstate_3d; // 80 - u8 ledstate_3d; // 84 - BatteryState battery_state; // 85 - u8 unknown_value; // 86 - INSERT_PADDING_BYTES(0xA0 - 0x87); // 87 - u64_le menu_title_id; // A0 - u64_le active_menu_title_id; // A8 - INSERT_PADDING_BYTES(0x1000 - 0xB0); // B0 -}; -static_assert(sizeof(SharedPageDef) == Memory::SHARED_PAGE_SIZE, - "Shared page structure size is wrong"); - -extern SharedPageDef shared_page; - -void Init(); - -} // namespace SharedPage From cbe841c9c979752c0cf2e0241cd6e51590e3b90c Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 23 Jul 2018 12:57:32 -0400 Subject: [PATCH 09/49] hle: Remove config_mem.h/.cpp This is just an unused hold-over from citra, so we can get rid of this to trim off an exposed global, among other things. --- src/core/CMakeLists.txt | 2 -- src/core/hle/config_mem.cpp | 31 ---------------- src/core/hle/config_mem.h | 56 ----------------------------- src/core/hle/kernel/kernel.cpp | 3 -- src/core/hle/kernel/memory.cpp | 9 ----- src/core/hle/kernel/wait_object.cpp | 1 - 6 files changed, 102 deletions(-) delete mode 100644 src/core/hle/config_mem.cpp delete mode 100644 src/core/hle/config_mem.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 5473723aad..1849c5d2a5 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -38,8 +38,6 @@ add_library(core STATIC frontend/input.h gdbstub/gdbstub.cpp gdbstub/gdbstub.h - hle/config_mem.cpp - hle/config_mem.h hle/ipc.h hle/ipc_helpers.h hle/kernel/address_arbiter.cpp diff --git a/src/core/hle/config_mem.cpp b/src/core/hle/config_mem.cpp deleted file mode 100644 index 038af79096..0000000000 --- a/src/core/hle/config_mem.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include "core/hle/config_mem.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -namespace ConfigMem { - -ConfigMemDef config_mem; - -void Init() { - std::memset(&config_mem, 0, sizeof(config_mem)); - - // Values extracted from firmware 11.2.0-35E - config_mem.kernel_version_min = 0x34; - config_mem.kernel_version_maj = 0x2; - config_mem.ns_tid = 0x0004013000008002; - config_mem.sys_core_ver = 0x2; - config_mem.unit_info = 0x1; // Bit 0 set for Retail - config_mem.prev_firm = 0x1; - config_mem.ctr_sdk_ver = 0x0000F297; - config_mem.firm_version_min = 0x34; - config_mem.firm_version_maj = 0x2; - config_mem.firm_sys_core_ver = 0x2; - config_mem.firm_ctr_sdk_ver = 0x0000F297; -} - -} // namespace ConfigMem diff --git a/src/core/hle/config_mem.h b/src/core/hle/config_mem.h deleted file mode 100644 index 1840d17609..0000000000 --- a/src/core/hle/config_mem.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -// Configuration memory stores various hardware/kernel configuration settings. This memory page is -// read-only for ARM11 processes. I'm guessing this would normally be written to by the firmware/ -// bootrom. Because we're not emulating this, and essentially just "stubbing" the functionality, I'm -// putting this as a subset of HLE for now. - -#include "common/common_funcs.h" -#include "common/common_types.h" -#include "common/swap.h" -#include "core/memory.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -namespace ConfigMem { - -struct ConfigMemDef { - u8 kernel_unk; // 0 - u8 kernel_version_rev; // 1 - u8 kernel_version_min; // 2 - u8 kernel_version_maj; // 3 - u32_le update_flag; // 4 - u64_le ns_tid; // 8 - u32_le sys_core_ver; // 10 - u8 unit_info; // 14 - u8 boot_firm; // 15 - u8 prev_firm; // 16 - INSERT_PADDING_BYTES(0x1); // 17 - u32_le ctr_sdk_ver; // 18 - INSERT_PADDING_BYTES(0x30 - 0x1C); // 1C - u32_le app_mem_type; // 30 - INSERT_PADDING_BYTES(0x40 - 0x34); // 34 - u32_le app_mem_alloc; // 40 - u32_le sys_mem_alloc; // 44 - u32_le base_mem_alloc; // 48 - INSERT_PADDING_BYTES(0x60 - 0x4C); // 4C - u8 firm_unk; // 60 - u8 firm_version_rev; // 61 - u8 firm_version_min; // 62 - u8 firm_version_maj; // 63 - u32_le firm_sys_core_ver; // 64 - u32_le firm_ctr_sdk_ver; // 68 - INSERT_PADDING_BYTES(0x1000 - 0x6C); // 6C -}; -static_assert(sizeof(ConfigMemDef) == Memory::CONFIG_MEMORY_SIZE, - "Config Memory structure size is wrong"); - -extern ConfigMemDef config_mem; - -void Init(); - -} // namespace ConfigMem diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index fae81e72b0..1beb985663 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -2,7 +2,6 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "core/hle/config_mem.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/memory.h" @@ -18,8 +17,6 @@ unsigned int Object::next_object_id; /// Initialize the kernel void Init(u32 system_mode) { - ConfigMem::Init(); - Kernel::MemoryInit(system_mode); Kernel::ResourceLimitsInit(); diff --git a/src/core/hle/kernel/memory.cpp b/src/core/hle/kernel/memory.cpp index ecbc5daae5..94eac677c5 100644 --- a/src/core/hle/kernel/memory.cpp +++ b/src/core/hle/kernel/memory.cpp @@ -11,7 +11,6 @@ #include "common/assert.h" #include "common/common_types.h" #include "common/logging/log.h" -#include "core/hle/config_mem.h" #include "core/hle/kernel/memory.h" #include "core/hle/kernel/vm_manager.h" #include "core/hle/result.h" @@ -62,14 +61,6 @@ void MemoryInit(u32 mem_type) { // We must've allocated the entire FCRAM by the end ASSERT(base == Memory::FCRAM_SIZE); - - using ConfigMem::config_mem; - config_mem.app_mem_type = mem_type; - // app_mem_malloc does not always match the configured size for memory_region[0]: in case the - // n3DS type override is in effect it reports the size the game expects, not the real one. - config_mem.app_mem_alloc = memory_region_sizes[mem_type][0]; - config_mem.sys_mem_alloc = static_cast(memory_regions[1].size); - config_mem.base_mem_alloc = static_cast(memory_regions[2].size); } void MemoryShutdown() { diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp index e279c5df90..23af346d0c 100644 --- a/src/core/hle/kernel/wait_object.cpp +++ b/src/core/hle/kernel/wait_object.cpp @@ -5,7 +5,6 @@ #include #include "common/assert.h" #include "common/logging/log.h" -#include "core/hle/config_mem.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/memory.h" From 344a0c91f27a848d6bd21f9a166bc044054331ff Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 23 Jul 2018 14:48:53 -0400 Subject: [PATCH 10/49] vi: std::move std::vector in constructors where applicable Allows avoiding unnecessary copies of the vector depending on the calling code. While we're at it, remove a redundant no-parameter base constructor call --- src/core/hle/service/vi/vi.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 3a69b85f92..0499575036 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "common/alignment.h" #include "common/math_util.h" @@ -176,7 +177,7 @@ private: class IGBPConnectRequestParcel : public Parcel { public: - explicit IGBPConnectRequestParcel(const std::vector& buffer) : Parcel(buffer) { + explicit IGBPConnectRequestParcel(std::vector buffer) : Parcel(std::move(buffer)) { Deserialize(); } ~IGBPConnectRequestParcel() override = default; @@ -223,8 +224,8 @@ private: class IGBPSetPreallocatedBufferRequestParcel : public Parcel { public: - explicit IGBPSetPreallocatedBufferRequestParcel(const std::vector& buffer) - : Parcel(buffer) { + explicit IGBPSetPreallocatedBufferRequestParcel(std::vector buffer) + : Parcel(std::move(buffer)) { Deserialize(); } ~IGBPSetPreallocatedBufferRequestParcel() override = default; @@ -256,7 +257,7 @@ protected: class IGBPDequeueBufferRequestParcel : public Parcel { public: - explicit IGBPDequeueBufferRequestParcel(const std::vector& buffer) : Parcel(buffer) { + explicit IGBPDequeueBufferRequestParcel(std::vector buffer) : Parcel(std::move(buffer)) { Deserialize(); } ~IGBPDequeueBufferRequestParcel() override = default; @@ -307,7 +308,7 @@ protected: class IGBPRequestBufferRequestParcel : public Parcel { public: - explicit IGBPRequestBufferRequestParcel(const std::vector& buffer) : Parcel(buffer) { + explicit IGBPRequestBufferRequestParcel(std::vector buffer) : Parcel(std::move(buffer)) { Deserialize(); } ~IGBPRequestBufferRequestParcel() override = default; @@ -322,8 +323,7 @@ public: class IGBPRequestBufferResponseParcel : public Parcel { public: - explicit IGBPRequestBufferResponseParcel(NVFlinger::IGBPBuffer buffer) - : Parcel(), buffer(buffer) {} + explicit IGBPRequestBufferResponseParcel(NVFlinger::IGBPBuffer buffer) : buffer(buffer) {} ~IGBPRequestBufferResponseParcel() override = default; protected: @@ -340,7 +340,7 @@ protected: class IGBPQueueBufferRequestParcel : public Parcel { public: - explicit IGBPQueueBufferRequestParcel(const std::vector& buffer) : Parcel(buffer) { + explicit IGBPQueueBufferRequestParcel(std::vector buffer) : Parcel(std::move(buffer)) { Deserialize(); } ~IGBPQueueBufferRequestParcel() override = default; @@ -409,7 +409,7 @@ private: class IGBPQueryRequestParcel : public Parcel { public: - explicit IGBPQueryRequestParcel(const std::vector& buffer) : Parcel(buffer) { + explicit IGBPQueryRequestParcel(std::vector buffer) : Parcel(std::move(buffer)) { Deserialize(); } ~IGBPQueryRequestParcel() override = default; From 1432912ae88e750ae0aae8972d7e260538d271df Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 23 Jul 2018 14:52:32 -0400 Subject: [PATCH 11/49] vi: Add std::is_trivially_copyable checks to Read and Write functions It's undefined behavior to memcpy an object that isn't considered trivially copyable, so put a compile-time check in to make sure this doesn't occur. --- src/core/hle/service/vi/vi.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 0499575036..993f1e65a2 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include "common/alignment.h" @@ -44,7 +45,9 @@ public: template T Read() { + static_assert(std::is_trivially_copyable_v, "T must be trivially copyable."); ASSERT(read_index + sizeof(T) <= buffer.size()); + T val; std::memcpy(&val, buffer.data() + read_index, sizeof(T)); read_index += sizeof(T); @@ -54,7 +57,9 @@ public: template T ReadUnaligned() { + static_assert(std::is_trivially_copyable_v, "T must be trivially copyable."); ASSERT(read_index + sizeof(T) <= buffer.size()); + T val; std::memcpy(&val, buffer.data() + read_index, sizeof(T)); read_index += sizeof(T); @@ -88,8 +93,12 @@ public: template void Write(const T& val) { - if (buffer.size() < write_index + sizeof(T)) + static_assert(std::is_trivially_copyable_v, "T must be trivially copyable."); + + if (buffer.size() < write_index + sizeof(T)) { buffer.resize(buffer.size() + sizeof(T) + DefaultBufferSize); + } + std::memcpy(buffer.data() + write_index, &val, sizeof(T)); write_index += sizeof(T); write_index = Common::AlignUp(write_index, 4); @@ -97,7 +106,9 @@ public: template void WriteObject(const T& val) { - u32_le size = static_cast(sizeof(val)); + static_assert(std::is_trivially_copyable_v, "T must be trivially copyable."); + + const u32_le size = static_cast(sizeof(val)); Write(size); // TODO(Subv): Support file descriptors. Write(0); // Fd count. From 3b88ce3dcb32e293650c719eb3f3b628e19c9479 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 23 Jul 2018 17:09:29 -0400 Subject: [PATCH 12/49] gl_shader_decompiler: Simplify GetCommonDeclarations() --- .../renderer_opengl/gl_shader_decompiler.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index ba827181ba..e771411efa 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -6,6 +6,9 @@ #include #include #include + +#include + #include "common/assert.h" #include "common/common_types.h" #include "video_core/engines/shader_bytecode.h" @@ -1774,11 +1777,8 @@ private: }; // namespace Decompiler std::string GetCommonDeclarations() { - std::string declarations; - declarations += "#define MAX_CONSTBUFFER_ELEMENTS " + - std::to_string(RasterizerOpenGL::MaxConstbufferSize / (sizeof(GLvec4))); - declarations += '\n'; - return declarations; + return fmt::format("#define MAX_CONSTBUFFER_ELEMENTS {}\n", + RasterizerOpenGL::MaxConstbufferSize / sizeof(GLvec4)); } boost::optional DecompileProgram(const ProgramCode& program_code, u32 main_offset, From 1c16700372528665876654da85f486105cb24e71 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 23 Jul 2018 17:19:40 -0400 Subject: [PATCH 13/49] nro: Remove unused forward declaration This isn't used anywhere in the header. --- src/core/loader/nro.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h index 5f3fc40d26..0024ce42bb 100644 --- a/src/core/loader/nro.h +++ b/src/core/loader/nro.h @@ -13,8 +13,6 @@ namespace Loader { -struct AssetHeader; - /// Loads an NRO file class AppLoader_NRO final : public AppLoader, Linker { public: From ac8133b9eea3ad66468aaacc093f494d5e46dbbd Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 23 Jul 2018 17:20:29 -0400 Subject: [PATCH 14/49] nro: Make constructor explicit Makes it consistent with the other Apploader constructors, and prevents implicit conversions. --- src/core/loader/nro.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h index 0024ce42bb..fe61047547 100644 --- a/src/core/loader/nro.h +++ b/src/core/loader/nro.h @@ -16,7 +16,7 @@ namespace Loader { /// Loads an NRO file class AppLoader_NRO final : public AppLoader, Linker { public: - AppLoader_NRO(FileSys::VirtualFile file); + explicit AppLoader_NRO(FileSys::VirtualFile file); /** * Returns the type of the file From 2b497e58306b98eddaf74a3a1fecc6fdd8b8c855 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 23 Jul 2018 17:24:27 -0400 Subject: [PATCH 15/49] nro: Make bracing consistent Makes the code more uniform, and also braces cases where the body of an unbraced conditional travels more than one line. --- src/core/loader/nro.cpp | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 44158655cb..f6f12c31c3 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -68,22 +68,27 @@ static_assert(sizeof(AssetHeader) == 0x38, "AssetHeader has incorrect size."); AppLoader_NRO::AppLoader_NRO(FileSys::VirtualFile file) : AppLoader(file) { NroHeader nro_header{}; - if (file->ReadObject(&nro_header) != sizeof(NroHeader)) + if (file->ReadObject(&nro_header) != sizeof(NroHeader)) { return; + } if (file->GetSize() >= nro_header.file_size + sizeof(AssetHeader)) { - u64 offset = nro_header.file_size; + const u64 offset = nro_header.file_size; AssetHeader asset_header{}; - if (file->ReadObject(&asset_header, offset) != sizeof(AssetHeader)) + if (file->ReadObject(&asset_header, offset) != sizeof(AssetHeader)) { return; + } - if (asset_header.format_version != 0) + if (asset_header.format_version != 0) { LOG_WARNING(Loader, "NRO Asset Header has format {}, currently supported format is 0. If " "strange glitches occur with metadata, check NRO assets.", asset_header.format_version); - if (asset_header.magic != Common::MakeMagic('A', 'S', 'E', 'T')) + } + + if (asset_header.magic != Common::MakeMagic('A', 'S', 'E', 'T')) { return; + } if (asset_header.nacp.size > 0) { nacp = std::make_unique(std::make_shared( @@ -130,8 +135,9 @@ bool AppLoader_NRO::LoadNro(FileSys::VirtualFile file, VAddr load_base) { // Build program image Kernel::SharedPtr codeset = Kernel::CodeSet::Create(""); std::vector program_image = file->ReadBytes(PageAlignSize(nro_header.file_size)); - if (program_image.size() != PageAlignSize(nro_header.file_size)) + if (program_image.size() != PageAlignSize(nro_header.file_size)) { return {}; + } for (std::size_t i = 0; i < nro_header.segments.size(); ++i) { codeset->segments[i].addr = nro_header.segments[i].offset; @@ -187,29 +193,37 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr& process) { } ResultStatus AppLoader_NRO::ReadIcon(std::vector& buffer) { - if (icon_data.empty()) + if (icon_data.empty()) { return ResultStatus::ErrorNotUsed; + } + buffer = icon_data; return ResultStatus::Success; } ResultStatus AppLoader_NRO::ReadProgramId(u64& out_program_id) { - if (nacp == nullptr) + if (nacp == nullptr) { return ResultStatus::ErrorNotUsed; + } + out_program_id = nacp->GetTitleId(); return ResultStatus::Success; } ResultStatus AppLoader_NRO::ReadRomFS(FileSys::VirtualFile& dir) { - if (romfs == nullptr) + if (romfs == nullptr) { return ResultStatus::ErrorNotUsed; + } + dir = romfs; return ResultStatus::Success; } ResultStatus AppLoader_NRO::ReadTitle(std::string& title) { - if (nacp == nullptr) + if (nacp == nullptr) { return ResultStatus::ErrorNotUsed; + } + title = nacp->GetApplicationName(); return ResultStatus::Success; } From 1b4d0ac20e3577b8a330a1e79881edaa0dd0143a Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 23 Jul 2018 17:27:50 -0400 Subject: [PATCH 16/49] nro: Replace inclusion with a forward declaration It's sufficient to use a forward declaration instead of a direct inclusion here. --- src/core/loader/nro.cpp | 3 +++ src/core/loader/nro.h | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index f6f12c31c3..7d3ec2a76d 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -6,6 +6,7 @@ #include #include "common/common_funcs.h" +#include "common/common_types.h" #include "common/file_util.h" #include "common/logging/log.h" #include "common/swap.h" @@ -106,6 +107,8 @@ AppLoader_NRO::AppLoader_NRO(FileSys::VirtualFile file) : AppLoader(file) { } } +AppLoader_NRO::~AppLoader_NRO() = default; + FileType AppLoader_NRO::IdentifyType(const FileSys::VirtualFile& file) { // Read NSO header NroHeader nro_header{}; diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h index fe61047547..04a0f497e1 100644 --- a/src/core/loader/nro.h +++ b/src/core/loader/nro.h @@ -6,17 +6,21 @@ #include #include "common/common_types.h" -#include "core/file_sys/control_metadata.h" #include "core/hle/kernel/kernel.h" #include "core/loader/linker.h" #include "core/loader/loader.h" +namespace FileSys { +class NACP; +} + namespace Loader { /// Loads an NRO file class AppLoader_NRO final : public AppLoader, Linker { public: explicit AppLoader_NRO(FileSys::VirtualFile file); + ~AppLoader_NRO() override; /** * Returns the type of the file From 184c516182c6855f03ec9aec3f3d5e2cae0686cf Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 23 Jul 2018 17:39:21 -0400 Subject: [PATCH 17/49] linker: Remove unused parameter from WriteRelocations() is_jump_relocation is never used within the function, so we can just remove it. --- src/core/loader/linker.cpp | 8 +++----- src/core/loader/linker.h | 3 +-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/core/loader/linker.cpp b/src/core/loader/linker.cpp index 769516b6f3..57ca8c3eeb 100644 --- a/src/core/loader/linker.cpp +++ b/src/core/loader/linker.cpp @@ -49,8 +49,7 @@ struct Elf64_Sym { static_assert(sizeof(Elf64_Sym) == 0x18, "Elf64_Sym has incorrect size."); void Linker::WriteRelocations(std::vector& program_image, const std::vector& symbols, - u64 relocation_offset, u64 size, bool is_jump_relocation, - VAddr load_base) { + u64 relocation_offset, u64 size, VAddr load_base) { for (u64 i = 0; i < size; i += sizeof(Elf64_Rela)) { Elf64_Rela rela; std::memcpy(&rela, &program_image[relocation_offset + i], sizeof(Elf64_Rela)); @@ -124,12 +123,11 @@ void Linker::Relocate(std::vector& program_image, u32 dynamic_section_offset } if (dynamic.find(DT_RELA) != dynamic.end()) { - WriteRelocations(program_image, symbols, dynamic[DT_RELA], dynamic[DT_RELASZ], false, - load_base); + WriteRelocations(program_image, symbols, dynamic[DT_RELA], dynamic[DT_RELASZ], load_base); } if (dynamic.find(DT_JMPREL) != dynamic.end()) { - WriteRelocations(program_image, symbols, dynamic[DT_JMPREL], dynamic[DT_PLTRELSZ], true, + WriteRelocations(program_image, symbols, dynamic[DT_JMPREL], dynamic[DT_PLTRELSZ], load_base); } } diff --git a/src/core/loader/linker.h b/src/core/loader/linker.h index c09d382c12..1076258377 100644 --- a/src/core/loader/linker.h +++ b/src/core/loader/linker.h @@ -24,8 +24,7 @@ protected: }; void WriteRelocations(std::vector& program_image, const std::vector& symbols, - u64 relocation_offset, u64 size, bool is_jump_relocation, - VAddr load_base); + u64 relocation_offset, u64 size, VAddr load_base); void Relocate(std::vector& program_image, u32 dynamic_section_offset, VAddr load_base); void ResolveImports(); From a147fa5825cdcc3d0c776856f44133ed72b3d773 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 23 Jul 2018 17:44:55 -0400 Subject: [PATCH 18/49] loader: Remove unnecessary constructor call in IdentifyFile() RealVfsFile inherits from VfsFile, the instance from std::make_shared is already compatible with the function argument type, making the copy constructor call unnecessary. --- src/core/loader/loader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 4cbd9e2859..cbc4177c61 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -42,7 +42,7 @@ FileType IdentifyFile(FileSys::VirtualFile file) { } FileType IdentifyFile(const std::string& file_name) { - return IdentifyFile(FileSys::VirtualFile(std::make_shared(file_name))); + return IdentifyFile(std::make_shared(file_name)); } FileType GuessFromFilename(const std::string& name) { From db48ebb9c9354a929a24b669851900eebc196110 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 23 Jul 2018 20:27:08 -0400 Subject: [PATCH 19/49] partition_filesystem: Use std::move where applicable Avoids copying a std::string instance and avoids unnecessary atomic reference count incrementing and decrementing. --- src/core/file_sys/partition_filesystem.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/file_sys/partition_filesystem.cpp b/src/core/file_sys/partition_filesystem.cpp index 8d2bd9f6b3..521e210789 100644 --- a/src/core/file_sys/partition_filesystem.cpp +++ b/src/core/file_sys/partition_filesystem.cpp @@ -65,8 +65,8 @@ PartitionFilesystem::PartitionFilesystem(std::shared_ptr file) { std::string name( reinterpret_cast(&file_data[strtab_offset + entry.strtab_offset])); - pfs_files.emplace_back( - std::make_shared(file, entry.size, content_offset + entry.offset, name)); + pfs_files.emplace_back(std::make_shared( + file, entry.size, content_offset + entry.offset, std::move(name))); } status = Loader::ResultStatus::Success; @@ -109,7 +109,7 @@ bool PartitionFilesystem::ReplaceFileWithSubdirectory(VirtualFile file, VirtualD return false; const std::ptrdiff_t offset = std::distance(pfs_files.begin(), iter); - pfs_files[offset] = pfs_files.back(); + pfs_files[offset] = std::move(pfs_files.back()); pfs_files.pop_back(); pfs_dirs.emplace_back(std::move(dir)); From e12c84d5c542c07e6ea62c23a85c76d6f4c7c07f Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 23 Jul 2018 20:33:15 -0400 Subject: [PATCH 20/49] exclusive_monitor: Use consistent type alias for u64 Uses the same type aliases we use for virtual addresses, and converts one lingering usage of std::array to u128 for consistency. --- src/core/arm/dynarmic/arm_dynarmic.cpp | 13 ++++++------- src/core/arm/dynarmic/arm_dynarmic.h | 13 ++++++------- src/core/arm/exclusive_monitor.h | 14 ++++++-------- 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index 83c09db2b6..d23adb28a7 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -257,7 +257,7 @@ void ARM_Dynarmic::PageTableChanged() { DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(size_t core_count) : monitor(core_count) {} DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default; -void DynarmicExclusiveMonitor::SetExclusive(size_t core_index, u64 addr) { +void DynarmicExclusiveMonitor::SetExclusive(size_t core_index, VAddr addr) { // Size doesn't actually matter. monitor.Mark(core_index, addr, 16); } @@ -266,28 +266,27 @@ void DynarmicExclusiveMonitor::ClearExclusive() { monitor.Clear(); } -bool DynarmicExclusiveMonitor::ExclusiveWrite8(size_t core_index, u64 vaddr, u8 value) { +bool DynarmicExclusiveMonitor::ExclusiveWrite8(size_t core_index, VAddr vaddr, u8 value) { return monitor.DoExclusiveOperation(core_index, vaddr, 1, [&] { Memory::Write8(vaddr, value); }); } -bool DynarmicExclusiveMonitor::ExclusiveWrite16(size_t core_index, u64 vaddr, u16 value) { +bool DynarmicExclusiveMonitor::ExclusiveWrite16(size_t core_index, VAddr vaddr, u16 value) { return monitor.DoExclusiveOperation(core_index, vaddr, 2, [&] { Memory::Write16(vaddr, value); }); } -bool DynarmicExclusiveMonitor::ExclusiveWrite32(size_t core_index, u64 vaddr, u32 value) { +bool DynarmicExclusiveMonitor::ExclusiveWrite32(size_t core_index, VAddr vaddr, u32 value) { return monitor.DoExclusiveOperation(core_index, vaddr, 4, [&] { Memory::Write32(vaddr, value); }); } -bool DynarmicExclusiveMonitor::ExclusiveWrite64(size_t core_index, u64 vaddr, u64 value) { +bool DynarmicExclusiveMonitor::ExclusiveWrite64(size_t core_index, VAddr vaddr, u64 value) { return monitor.DoExclusiveOperation(core_index, vaddr, 8, [&] { Memory::Write64(vaddr, value); }); } -bool DynarmicExclusiveMonitor::ExclusiveWrite128(size_t core_index, u64 vaddr, - std::array value) { +bool DynarmicExclusiveMonitor::ExclusiveWrite128(size_t core_index, VAddr vaddr, u128 value) { return monitor.DoExclusiveOperation(core_index, vaddr, 16, [&] { Memory::Write64(vaddr, value[0]); Memory::Write64(vaddr, value[1]); diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h index 0fa8b417c4..350f61fd27 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.h +++ b/src/core/arm/dynarmic/arm_dynarmic.h @@ -68,15 +68,14 @@ public: explicit DynarmicExclusiveMonitor(size_t core_count); ~DynarmicExclusiveMonitor(); - void SetExclusive(size_t core_index, u64 addr) override; + void SetExclusive(size_t core_index, VAddr addr) override; void ClearExclusive() override; - bool ExclusiveWrite8(size_t core_index, u64 vaddr, u8 value) override; - bool ExclusiveWrite16(size_t core_index, u64 vaddr, u16 value) override; - bool ExclusiveWrite32(size_t core_index, u64 vaddr, u32 value) override; - bool ExclusiveWrite64(size_t core_index, u64 vaddr, u64 value) override; - bool ExclusiveWrite128(size_t core_index, u64 vaddr, - std::array value) override; + bool ExclusiveWrite8(size_t core_index, VAddr vaddr, u8 value) override; + bool ExclusiveWrite16(size_t core_index, VAddr vaddr, u16 value) override; + bool ExclusiveWrite32(size_t core_index, VAddr vaddr, u32 value) override; + bool ExclusiveWrite64(size_t core_index, VAddr vaddr, u64 value) override; + bool ExclusiveWrite128(size_t core_index, VAddr vaddr, u128 value) override; private: friend class ARM_Dynarmic; diff --git a/src/core/arm/exclusive_monitor.h b/src/core/arm/exclusive_monitor.h index acfcdb94cc..13671ed7ab 100644 --- a/src/core/arm/exclusive_monitor.h +++ b/src/core/arm/exclusive_monitor.h @@ -4,20 +4,18 @@ #pragma once -#include #include "common/common_types.h" class ExclusiveMonitor { public: virtual ~ExclusiveMonitor(); - virtual void SetExclusive(size_t core_index, u64 addr) = 0; + virtual void SetExclusive(size_t core_index, VAddr addr) = 0; virtual void ClearExclusive() = 0; - virtual bool ExclusiveWrite8(size_t core_index, u64 vaddr, u8 value) = 0; - virtual bool ExclusiveWrite16(size_t core_index, u64 vaddr, u16 value) = 0; - virtual bool ExclusiveWrite32(size_t core_index, u64 vaddr, u32 value) = 0; - virtual bool ExclusiveWrite64(size_t core_index, u64 vaddr, u64 value) = 0; - virtual bool ExclusiveWrite128(size_t core_index, u64 vaddr, - std::array value) = 0; + virtual bool ExclusiveWrite8(size_t core_index, VAddr vaddr, u8 value) = 0; + virtual bool ExclusiveWrite16(size_t core_index, VAddr vaddr, u16 value) = 0; + virtual bool ExclusiveWrite32(size_t core_index, VAddr vaddr, u32 value) = 0; + virtual bool ExclusiveWrite64(size_t core_index, VAddr vaddr, u64 value) = 0; + virtual bool ExclusiveWrite128(size_t core_index, VAddr vaddr, u128 value) = 0; }; From 81aa02424bfd3f6b518684de256e925baccea5fd Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 23 Jul 2018 19:21:28 -0400 Subject: [PATCH 21/49] gl_shader_decompiler: Check if SetRegister result is ZeroIndex. --- src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index ba827181ba..02ed86e5ad 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -485,6 +485,12 @@ private: */ void SetRegister(const Register& reg, u64 elem, const std::string& value, u64 dest_num_components, u64 value_num_components, u64 dest_elem) { + if (reg == Register::ZeroIndex) { + LOG_CRITICAL(HW_GPU, "Cannot set Register::ZeroIndex"); + UNREACHABLE(); + return; + } + std::string dest = GetRegister(reg, static_cast(dest_elem)); if (dest_num_components > 1) { dest += GetSwizzle(elem); From c4322ce87e45452d21b2adb4cbcd1c3f58442dd4 Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 23 Jul 2018 18:36:14 -0400 Subject: [PATCH 22/49] gl_shader_decompiler: Print instruction value in shader comments. --- src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index ba827181ba..0b097aae2d 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -769,7 +769,8 @@ private: return offset + 1; } - shader.AddLine("// " + std::to_string(offset) + ": " + opcode->GetName()); + shader.AddLine("// " + std::to_string(offset) + ": " + opcode->GetName() + " (" + + std::to_string(instr.value) + ')'); using Tegra::Shader::Pred; ASSERT_MSG(instr.pred.full_pred != Pred::NeverExecute, From 89db8c2171b15931060db4eb440271f7179c9660 Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 23 Jul 2018 17:23:45 -0400 Subject: [PATCH 23/49] gl_rasterizer_cache: Add missing log statements. --- src/video_core/renderer_opengl/gl_rasterizer_cache.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index b084c4db4d..fbdab58bec 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -249,6 +249,7 @@ struct SurfaceParams { case PixelFormat::ASTC_2D_4X4: return Tegra::Texture::TextureFormat::ASTC_2D_4X4; default: + LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast(format)); UNREACHABLE(); } } @@ -264,6 +265,7 @@ struct SurfaceParams { case PixelFormat::Z16: return Tegra::DepthFormat::Z16_UNORM; default: + LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast(format)); UNREACHABLE(); } } From bcc184acfa81aee7ad33d9c82f5f4496731a1d1f Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 23 Jul 2018 16:56:52 -0400 Subject: [PATCH 24/49] gl_rasterizer_cache: Implement RenderTargetFormat BGRA8_UNORM. --- src/video_core/gpu.cpp | 1 + src/video_core/gpu.h | 1 + .../renderer_opengl/gl_rasterizer_cache.cpp | 10 ++++++---- .../renderer_opengl/gl_rasterizer_cache.h | 18 ++++++++++++++---- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index a003bc9e34..b094d48c3a 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp @@ -38,6 +38,7 @@ u32 RenderTargetBytesPerPixel(RenderTargetFormat format) { return 8; case RenderTargetFormat::RGBA8_UNORM: case RenderTargetFormat::RGB10_A2_UNORM: + case RenderTargetFormat::BGRA8_UNORM: return 4; default: UNIMPLEMENTED_MSG("Unimplemented render target format {}", static_cast(format)); diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index a32148ecd4..9c74cfac38 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h @@ -18,6 +18,7 @@ enum class RenderTargetFormat : u32 { RGBA32_FLOAT = 0xC0, RGBA32_UINT = 0xC2, RGBA16_FLOAT = 0xCA, + BGRA8_UNORM = 0xCF, RGB10_A2_UNORM = 0xD1, RGBA8_UNORM = 0xD5, RGBA8_SRGB = 0xD6, diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 28f0bc3791..02bd0fa7bc 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -106,6 +106,7 @@ static constexpr std::array tex_form true}, // BC7U {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4 {GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // G8R8 + {GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // BGRA8 // DepthStencil formats {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, ComponentType::UNorm, @@ -197,9 +198,9 @@ static constexpr std::array, MortonCopy, MortonCopy, MortonCopy, MortonCopy, MortonCopy, - MortonCopy, MortonCopy, - MortonCopy, MortonCopy, - MortonCopy, + MortonCopy, MortonCopy, + MortonCopy, MortonCopy, + MortonCopy, MortonCopy, }; static constexpr std::array, MortonCopy, MortonCopy, - // TODO(Subv): Swizzling the DXT1/DXT23/DXT45/DXN1/BC7U formats is not yet supported + // TODO(Subv): Swizzling DXT1/DXT23/DXT45/DXN1/BC7U/ASTC_2D_4X4 formats is not supported nullptr, nullptr, nullptr, @@ -221,6 +222,7 @@ static constexpr std::array, + MortonCopy, MortonCopy, MortonCopy, MortonCopy, diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index fbdab58bec..c0f94936ea 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -37,14 +37,15 @@ struct SurfaceParams { BC7U = 12, ASTC_2D_4X4 = 13, G8R8 = 14, + BGRA8 = 15, MaxColorFormat, // DepthStencil formats - Z24S8 = 15, - S8Z24 = 16, - Z32F = 17, - Z16 = 18, + Z24S8 = 16, + S8Z24 = 17, + Z32F = 18, + Z16 = 19, MaxDepthStencilFormat, @@ -97,6 +98,7 @@ struct SurfaceParams { 4, // BC7U 4, // ASTC_2D_4X4 1, // G8R8 + 1, // BGRA8 1, // Z24S8 1, // S8Z24 1, // Z32F @@ -127,6 +129,7 @@ struct SurfaceParams { 128, // BC7U 32, // ASTC_2D_4X4 16, // G8R8 + 32, // BGRA8 32, // Z24S8 32, // S8Z24 32, // Z32F @@ -162,6 +165,8 @@ struct SurfaceParams { case Tegra::RenderTargetFormat::RGBA8_UNORM: case Tegra::RenderTargetFormat::RGBA8_SRGB: return PixelFormat::ABGR8; + case Tegra::RenderTargetFormat::BGRA8_UNORM: + return PixelFormat::BGRA8; case Tegra::RenderTargetFormat::RGB10_A2_UNORM: return PixelFormat::A2B10G10R10; case Tegra::RenderTargetFormat::RGBA16_FLOAT: @@ -248,6 +253,10 @@ struct SurfaceParams { return Tegra::Texture::TextureFormat::BC7U; case PixelFormat::ASTC_2D_4X4: return Tegra::Texture::TextureFormat::ASTC_2D_4X4; + case PixelFormat::BGRA8: + // TODO(bunnei): This is fine for unswizzling (since we just need the right component + // sizes), but could be a bug if we used this function in different ways. + return Tegra::Texture::TextureFormat::A8R8G8B8; default: LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast(format)); UNREACHABLE(); @@ -286,6 +295,7 @@ struct SurfaceParams { switch (format) { case Tegra::RenderTargetFormat::RGBA8_UNORM: case Tegra::RenderTargetFormat::RGBA8_SRGB: + case Tegra::RenderTargetFormat::BGRA8_UNORM: case Tegra::RenderTargetFormat::RGB10_A2_UNORM: return ComponentType::UNorm; case Tegra::RenderTargetFormat::RGBA16_FLOAT: From 3a19c1098d4d4242ad466f06f2b1df6c17728f4a Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 23 Jul 2018 17:12:16 -0400 Subject: [PATCH 25/49] gl_rasterizer_cache: Implement RenderTargetFormat RGBA32_FLOAT. --- .../renderer_opengl/gl_rasterizer_cache.cpp | 10 ++++-- .../renderer_opengl/gl_rasterizer_cache.h | 34 +++++++++++++++---- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 02bd0fa7bc..133a15a125 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -38,7 +38,8 @@ struct FormatTuple { params.addr = config.tic.Address(); params.is_tiled = config.tic.IsTiled(); params.block_height = params.is_tiled ? config.tic.BlockHeight() : 0, - params.pixel_format = PixelFormatFromTextureFormat(config.tic.format); + params.pixel_format = + PixelFormatFromTextureFormat(config.tic.format, config.tic.r_type.Value()); params.component_type = ComponentTypeFromTexture(config.tic.r_type.Value()); params.type = GetFormatType(params.pixel_format); params.width = Common::AlignUp(config.tic.Width(), GetCompressionFactor(params.pixel_format)); @@ -107,6 +108,7 @@ static constexpr std::array tex_form {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4 {GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // G8R8 {GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // BGRA8 + {GL_RGBA32F, GL_RGBA, GL_FLOAT, ComponentType::Float, false}, // RGBA32F // DepthStencil formats {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, ComponentType::UNorm, @@ -199,8 +201,9 @@ static constexpr std::array, MortonCopy, MortonCopy, MortonCopy, MortonCopy, MortonCopy, - MortonCopy, MortonCopy, - MortonCopy, MortonCopy, + MortonCopy, MortonCopy, + MortonCopy, MortonCopy, + MortonCopy, }; static constexpr std::array, MortonCopy, + MortonCopy, MortonCopy, MortonCopy, MortonCopy, diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index c0f94936ea..2feea3d4db 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -38,14 +38,15 @@ struct SurfaceParams { ASTC_2D_4X4 = 13, G8R8 = 14, BGRA8 = 15, + RGBA32F = 16, MaxColorFormat, // DepthStencil formats - Z24S8 = 16, - S8Z24 = 17, - Z32F = 18, - Z16 = 19, + Z24S8 = 17, + S8Z24 = 18, + Z32F = 19, + Z16 = 20, MaxDepthStencilFormat, @@ -99,6 +100,7 @@ struct SurfaceParams { 4, // ASTC_2D_4X4 1, // G8R8 1, // BGRA8 + 1, // RGBA32F 1, // Z24S8 1, // S8Z24 1, // Z32F @@ -130,6 +132,7 @@ struct SurfaceParams { 32, // ASTC_2D_4X4 16, // G8R8 32, // BGRA8 + 128, // RGBA32F 32, // Z24S8 32, // S8Z24 32, // Z32F @@ -171,6 +174,8 @@ struct SurfaceParams { return PixelFormat::A2B10G10R10; case Tegra::RenderTargetFormat::RGBA16_FLOAT: return PixelFormat::RGBA16F; + case Tegra::RenderTargetFormat::RGBA32_FLOAT: + return PixelFormat::RGBA32F; case Tegra::RenderTargetFormat::R11G11B10_FLOAT: return PixelFormat::R11FG11FB10F; case Tegra::RenderTargetFormat::RGBA32_UINT: @@ -181,7 +186,8 @@ struct SurfaceParams { } } - static PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format) { + static PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format, + Tegra::Texture::ComponentType component_type) { // TODO(Subv): Properly implement this switch (format) { case Tegra::Texture::TextureFormat::A8R8G8B8: @@ -201,7 +207,15 @@ struct SurfaceParams { case Tegra::Texture::TextureFormat::BF10GF11RF11: return PixelFormat::R11FG11FB10F; case Tegra::Texture::TextureFormat::R32_G32_B32_A32: - return PixelFormat::RGBA32UI; + switch (component_type) { + case Tegra::Texture::ComponentType::FLOAT: + return PixelFormat::RGBA32F; + case Tegra::Texture::ComponentType::UINT: + return PixelFormat::RGBA32UI; + } + LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", + static_cast(component_type)); + UNREACHABLE(); case Tegra::Texture::TextureFormat::DXT1: return PixelFormat::DXT1; case Tegra::Texture::TextureFormat::DXT23: @@ -215,7 +229,8 @@ struct SurfaceParams { case Tegra::Texture::TextureFormat::ASTC_2D_4X4: return PixelFormat::ASTC_2D_4X4; default: - LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast(format)); + LOG_CRITICAL(HW_GPU, "Unimplemented format={}, component_type={}", + static_cast(format), static_cast(component_type)); UNREACHABLE(); } } @@ -257,6 +272,8 @@ struct SurfaceParams { // TODO(bunnei): This is fine for unswizzling (since we just need the right component // sizes), but could be a bug if we used this function in different ways. return Tegra::Texture::TextureFormat::A8R8G8B8; + case PixelFormat::RGBA32F: + return Tegra::Texture::TextureFormat::R32_G32_B32_A32; default: LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast(format)); UNREACHABLE(); @@ -284,6 +301,8 @@ struct SurfaceParams { switch (type) { case Tegra::Texture::ComponentType::UNORM: return ComponentType::UNorm; + case Tegra::Texture::ComponentType::FLOAT: + return ComponentType::Float; default: LOG_CRITICAL(HW_GPU, "Unimplemented component type={}", static_cast(type)); UNREACHABLE(); @@ -300,6 +319,7 @@ struct SurfaceParams { return ComponentType::UNorm; case Tegra::RenderTargetFormat::RGBA16_FLOAT: case Tegra::RenderTargetFormat::R11G11B10_FLOAT: + case Tegra::RenderTargetFormat::RGBA32_FLOAT: return ComponentType::Float; case Tegra::RenderTargetFormat::RGBA32_UINT: return ComponentType::UInt; From a27c0099ededac2d1fb1745a437a446450dfea10 Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 23 Jul 2018 19:10:00 -0400 Subject: [PATCH 26/49] gl_rasterizer_cache: Implement RenderTargetFormat RG32_FLOAT. --- src/video_core/gpu.cpp | 1 + src/video_core/gpu.h | 1 + .../renderer_opengl/gl_rasterizer_cache.cpp | 8 +++++--- .../renderer_opengl/gl_rasterizer_cache.h | 18 ++++++++++++++---- src/video_core/textures/decoders.cpp | 4 ++++ 5 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index b094d48c3a..60c49d6723 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp @@ -35,6 +35,7 @@ u32 RenderTargetBytesPerPixel(RenderTargetFormat format) { case RenderTargetFormat::RGBA32_FLOAT: return 16; case RenderTargetFormat::RGBA16_FLOAT: + case RenderTargetFormat::RG32_FLOAT: return 8; case RenderTargetFormat::RGBA8_UNORM: case RenderTargetFormat::RGB10_A2_UNORM: diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index 9c74cfac38..58501ca8b2 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h @@ -18,6 +18,7 @@ enum class RenderTargetFormat : u32 { RGBA32_FLOAT = 0xC0, RGBA32_UINT = 0xC2, RGBA16_FLOAT = 0xCA, + RG32_FLOAT = 0xCB, BGRA8_UNORM = 0xCF, RGB10_A2_UNORM = 0xD1, RGBA8_UNORM = 0xD5, diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 133a15a125..8f99864a04 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -109,6 +109,7 @@ static constexpr std::array tex_form {GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // G8R8 {GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // BGRA8 {GL_RGBA32F, GL_RGBA, GL_FLOAT, ComponentType::Float, false}, // RGBA32F + {GL_RG32F, GL_RG, GL_FLOAT, ComponentType::Float, false}, // RG32F // DepthStencil formats {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, ComponentType::UNorm, @@ -201,9 +202,9 @@ static constexpr std::array, MortonCopy, MortonCopy, MortonCopy, MortonCopy, MortonCopy, - MortonCopy, MortonCopy, - MortonCopy, MortonCopy, - MortonCopy, + MortonCopy, MortonCopy, + MortonCopy, MortonCopy, + MortonCopy, MortonCopy, }; static constexpr std::array, MortonCopy, MortonCopy, + MortonCopy, MortonCopy, MortonCopy, MortonCopy, diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 2feea3d4db..23efbe67c8 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -39,14 +39,15 @@ struct SurfaceParams { G8R8 = 14, BGRA8 = 15, RGBA32F = 16, + RG32F = 17, MaxColorFormat, // DepthStencil formats - Z24S8 = 17, - S8Z24 = 18, - Z32F = 19, - Z16 = 20, + Z24S8 = 18, + S8Z24 = 19, + Z32F = 20, + Z16 = 21, MaxDepthStencilFormat, @@ -101,6 +102,7 @@ struct SurfaceParams { 1, // G8R8 1, // BGRA8 1, // RGBA32F + 1, // RG32F 1, // Z24S8 1, // S8Z24 1, // Z32F @@ -133,6 +135,7 @@ struct SurfaceParams { 16, // G8R8 32, // BGRA8 128, // RGBA32F + 64, // RG32F 32, // Z24S8 32, // S8Z24 32, // Z32F @@ -176,6 +179,8 @@ struct SurfaceParams { return PixelFormat::RGBA16F; case Tegra::RenderTargetFormat::RGBA32_FLOAT: return PixelFormat::RGBA32F; + case Tegra::RenderTargetFormat::RG32_FLOAT: + return PixelFormat::RG32F; case Tegra::RenderTargetFormat::R11G11B10_FLOAT: return PixelFormat::R11FG11FB10F; case Tegra::RenderTargetFormat::RGBA32_UINT: @@ -216,6 +221,8 @@ struct SurfaceParams { LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast(component_type)); UNREACHABLE(); + case Tegra::Texture::TextureFormat::R32_G32: + return PixelFormat::RG32F; case Tegra::Texture::TextureFormat::DXT1: return PixelFormat::DXT1; case Tegra::Texture::TextureFormat::DXT23: @@ -274,6 +281,8 @@ struct SurfaceParams { return Tegra::Texture::TextureFormat::A8R8G8B8; case PixelFormat::RGBA32F: return Tegra::Texture::TextureFormat::R32_G32_B32_A32; + case PixelFormat::RG32F: + return Tegra::Texture::TextureFormat::R32_G32; default: LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast(format)); UNREACHABLE(); @@ -320,6 +329,7 @@ struct SurfaceParams { case Tegra::RenderTargetFormat::RGBA16_FLOAT: case Tegra::RenderTargetFormat::R11G11B10_FLOAT: case Tegra::RenderTargetFormat::RGBA32_FLOAT: + case Tegra::RenderTargetFormat::RG32_FLOAT: return ComponentType::Float; case Tegra::RenderTargetFormat::RGBA32_UINT: return ComponentType::UInt; diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp index a3e67d105f..e5e9e18981 100644 --- a/src/video_core/textures/decoders.cpp +++ b/src/video_core/textures/decoders.cpp @@ -72,6 +72,8 @@ u32 BytesPerPixel(TextureFormat format) { return 8; case TextureFormat::R32_G32_B32_A32: return 16; + case TextureFormat::R32_G32: + return 8; default: UNIMPLEMENTED_MSG("Format not implemented"); break; @@ -118,6 +120,7 @@ std::vector UnswizzleTexture(VAddr address, TextureFormat format, u32 width, case TextureFormat::G8R8: case TextureFormat::R16_G16_B16_A16: case TextureFormat::R32_G32_B32_A32: + case TextureFormat::R32_G32: case TextureFormat::BF10GF11RF11: case TextureFormat::ASTC_2D_4X4: CopySwizzledData(width, height, bytes_per_pixel, bytes_per_pixel, data, @@ -174,6 +177,7 @@ std::vector DecodeTexture(const std::vector& texture_data, TextureFormat case TextureFormat::G8R8: case TextureFormat::BF10GF11RF11: case TextureFormat::R32_G32_B32_A32: + case TextureFormat::R32_G32: // TODO(Subv): For the time being just forward the same data without any decoding. rgba_data = texture_data; break; From 95052839898f5779ab50d798b8941458f6e17a25 Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 23 Jul 2018 20:02:05 -0400 Subject: [PATCH 27/49] gl_shader_decompiler: Implement shader instruction TLDS. --- .../renderer_opengl/gl_shader_decompiler.cpp | 72 +++++++++++-------- 1 file changed, 43 insertions(+), 29 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index e771411efa..4e36b6de85 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -750,6 +750,38 @@ private: } } + std::string WriteTexsInstruction(const Instruction& instr, const std::string& coord, + const std::string& texture) { + // Add an extra scope and declare the texture coords inside to prevent + // overwriting them in case they are used as outputs of the texs instruction. + shader.AddLine('{'); + ++shader.scope; + shader.AddLine(coord); + + // TEXS has two destination registers. RG goes into gpr0+0 and gpr0+1, and BA + // goes into gpr28+0 and gpr28+1 + size_t texs_offset{}; + + for (const auto& dest : {instr.gpr0.Value(), instr.gpr28.Value()}) { + for (unsigned elem = 0; elem < 2; ++elem) { + if (!instr.texs.IsComponentEnabled(elem)) { + // Skip disabled components + continue; + } + regs.SetRegisterToFloat(dest, elem + texs_offset, texture, 1, 4, false, elem); + } + + if (!instr.texs.HasTwoDestinations()) { + // Skip the second destination + break; + } + + texs_offset += 2; + } + --shader.scope; + shader.AddLine('}'); + } + /** * Compiles a single instruction from Tegra to GLSL. * @param offset the offset of the Tegra shader instruction. @@ -1348,36 +1380,18 @@ private: const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20); const std::string sampler = GetSampler(instr.sampler); const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; - // Add an extra scope and declare the texture coords inside to prevent - // overwriting them in case they are used as outputs of the texs instruction. - shader.AddLine("{"); - ++shader.scope; - shader.AddLine(coord); + const std::string texture = "texture(" + sampler + ", coords)"; - - // TEXS has two destination registers. RG goes into gpr0+0 and gpr0+1, and BA - // goes into gpr28+0 and gpr28+1 - size_t texs_offset{}; - - for (const auto& dest : {instr.gpr0.Value(), instr.gpr28.Value()}) { - for (unsigned elem = 0; elem < 2; ++elem) { - if (!instr.texs.IsComponentEnabled(elem)) { - // Skip disabled components - continue; - } - regs.SetRegisterToFloat(dest, elem + texs_offset, texture, 1, 4, false, - elem); - } - - if (!instr.texs.HasTwoDestinations()) { - // Skip the second destination - break; - } - - texs_offset += 2; - } - --shader.scope; - shader.AddLine("}"); + WriteTexsInstruction(instr, coord, texture); + break; + } + case OpCode::Id::TLDS: { + const std::string op_a = regs.GetRegisterAsInteger(instr.gpr8); + const std::string op_b = regs.GetRegisterAsInteger(instr.gpr20); + const std::string sampler = GetSampler(instr.sampler); + const std::string coord = "ivec2 coords = ivec2(" + op_a + ", " + op_b + ");"; + const std::string texture = "texelFetch(" + sampler + ", coords, 0)"; + WriteTexsInstruction(instr, coord, texture); break; } default: { From 2a1daf8f836b4f2bc9e8ac35af949acb1018b14d Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 23 Jul 2018 22:27:17 -0400 Subject: [PATCH 28/49] ipc_helpers: Make member variables of ResponseBuilder private These aren't used externally at all, so they can be made private. --- src/core/hle/ipc_helpers.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index 8b5b06f31d..6a5e438998 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h @@ -58,11 +58,6 @@ class ResponseBuilder : public RequestHelperBase { public: ResponseBuilder(u32* command_buffer) : RequestHelperBase(command_buffer) {} - u32 normal_params_size{}; - u32 num_handles_to_copy{}; - u32 num_objects_to_move{}; ///< Domain objects or move handles, context dependent - std::ptrdiff_t datapayload_index{}; - /// Flags used for customizing the behavior of ResponseBuilder enum class Flags : u32 { None = 0, @@ -206,6 +201,12 @@ public: template void PushCopyObjects(Kernel::SharedPtr... pointers); + +private: + u32 normal_params_size{}; + u32 num_handles_to_copy{}; + u32 num_objects_to_move{}; ///< Domain objects or move handles, context dependent + std::ptrdiff_t datapayload_index{}; }; /// Push /// From 33e2033af5655d13eec57e17154fb831e14acd9b Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 23 Jul 2018 22:31:56 -0400 Subject: [PATCH 29/49] gl_shader_decompiler: Correct return value of WriteTexsInstruction() This should be returning void, not a std::string --- src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 4e36b6de85..d125d5a20c 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -750,8 +750,8 @@ private: } } - std::string WriteTexsInstruction(const Instruction& instr, const std::string& coord, - const std::string& texture) { + void WriteTexsInstruction(const Instruction& instr, const std::string& coord, + const std::string& texture) { // Add an extra scope and declare the texture coords inside to prevent // overwriting them in case they are used as outputs of the texs instruction. shader.AddLine('{'); From 22fd3f0026e42b15d50aef1e6ddc12a8cddea452 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 23 Jul 2018 22:40:24 -0400 Subject: [PATCH 30/49] hle_ipc: Make constructors explicit where applicable --- src/core/hle/ipc_helpers.h | 23 ++++++++++++----------- src/core/hle/kernel/hle_ipc.h | 2 +- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index 6a5e438998..f5bd27a754 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h @@ -25,9 +25,9 @@ protected: ptrdiff_t index = 0; public: - RequestHelperBase(u32* command_buffer) : cmdbuf(command_buffer) {} + explicit RequestHelperBase(u32* command_buffer) : cmdbuf(command_buffer) {} - RequestHelperBase(Kernel::HLERequestContext& context) + explicit RequestHelperBase(Kernel::HLERequestContext& context) : context(&context), cmdbuf(context.CommandBuffer()) {} void Skip(unsigned size_in_words, bool set_to_null) { @@ -56,8 +56,6 @@ public: class ResponseBuilder : public RequestHelperBase { public: - ResponseBuilder(u32* command_buffer) : RequestHelperBase(command_buffer) {} - /// Flags used for customizing the behavior of ResponseBuilder enum class Flags : u32 { None = 0, @@ -66,9 +64,11 @@ public: AlwaysMoveHandles = 1, }; - ResponseBuilder(Kernel::HLERequestContext& context, u32 normal_params_size, - u32 num_handles_to_copy = 0, u32 num_objects_to_move = 0, - Flags flags = Flags::None) + explicit ResponseBuilder(u32* command_buffer) : RequestHelperBase(command_buffer) {} + + explicit ResponseBuilder(Kernel::HLERequestContext& context, u32 normal_params_size, + u32 num_handles_to_copy = 0, u32 num_objects_to_move = 0, + Flags flags = Flags::None) : RequestHelperBase(context), normal_params_size(normal_params_size), num_handles_to_copy(num_handles_to_copy), num_objects_to_move(num_objects_to_move) { @@ -274,9 +274,9 @@ inline void ResponseBuilder::PushMoveObjects(Kernel::SharedPtr... pointers) { class RequestParser : public RequestHelperBase { public: - RequestParser(u32* command_buffer) : RequestHelperBase(command_buffer) {} + explicit RequestParser(u32* command_buffer) : RequestHelperBase(command_buffer) {} - RequestParser(Kernel::HLERequestContext& context) : RequestHelperBase(context) { + explicit RequestParser(Kernel::HLERequestContext& context) : RequestHelperBase(context) { ASSERT_MSG(context.GetDataPayloadOffset(), "context is incomplete"); Skip(context.GetDataPayloadOffset(), false); // Skip the u64 command id, it's already stored in the context @@ -286,8 +286,9 @@ public: ResponseBuilder MakeBuilder(u32 normal_params_size, u32 num_handles_to_copy, u32 num_handles_to_move, - ResponseBuilder::Flags flags = ResponseBuilder::Flags::None) { - return {*context, normal_params_size, num_handles_to_copy, num_handles_to_move, flags}; + ResponseBuilder::Flags flags = ResponseBuilder::Flags::None) const { + return ResponseBuilder{*context, normal_params_size, num_handles_to_copy, + num_handles_to_move, flags}; } template diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 01b805df8d..84727f7485 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -91,7 +91,7 @@ protected: */ class HLERequestContext { public: - HLERequestContext(SharedPtr session); + explicit HLERequestContext(SharedPtr session); ~HLERequestContext(); /// Returns a pointer to the IPC command buffer for this request. From 59cb258409c5cbd6cdc9cc6a6f8e858603924a2b Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Mon, 23 Jul 2018 22:40:35 -0400 Subject: [PATCH 31/49] VFS Regression and Accuracy Fixes (#776) * Regression and Mode Fixes * Review Fixes * string_view correction * Add operator& for FileSys::Mode * Return std::string from SanitizePath * Farming Simulator Fix * Use != With mode operator& --- src/common/file_util.cpp | 11 ++++- src/common/file_util.h | 3 ++ src/core/file_sys/mode.h | 6 +++ src/core/file_sys/vfs_real.cpp | 47 +++++++++++-------- .../hle/service/filesystem/filesystem.cpp | 45 +++++++++++------- 5 files changed, 75 insertions(+), 37 deletions(-) diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index 1bc291cf95..b8dd92b651 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp @@ -826,7 +826,7 @@ std::string_view GetPathWithoutTop(std::string_view path) { } while (path[0] == '\\' || path[0] == '/') { - path.remove_suffix(1); + path.remove_prefix(1); if (path.empty()) { return path; } @@ -870,6 +870,15 @@ std::string_view RemoveTrailingSlash(std::string_view path) { return path; } +std::string SanitizePath(std::string_view path_) { + std::string path(path_); + std::replace(path.begin(), path.end(), '\\', '/'); + path.erase(std::unique(path.begin(), path.end(), + [](char c1, char c2) { return c1 == '/' && c2 == '/'; }), + path.end()); + return std::string(RemoveTrailingSlash(path)); +} + IOFile::IOFile() {} IOFile::IOFile(const std::string& filename, const char openmode[], int flags) { diff --git a/src/common/file_util.h b/src/common/file_util.h index abfa79eaea..bc9272d89d 100644 --- a/src/common/file_util.h +++ b/src/common/file_util.h @@ -178,6 +178,9 @@ std::vector SliceVector(const std::vector& vector, size_t first, size_t la return std::vector(vector.begin() + first, vector.begin() + first + last); } +// Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'. +std::string SanitizePath(std::string_view path); + // simple wrapper for cstdlib file functions to // hopefully will make error checking easier // and make forgetting an fclose() harder diff --git a/src/core/file_sys/mode.h b/src/core/file_sys/mode.h index b4363152a3..c952056682 100644 --- a/src/core/file_sys/mode.h +++ b/src/core/file_sys/mode.h @@ -11,7 +11,13 @@ namespace FileSys { enum class Mode : u32 { Read = 1, Write = 2, + ReadWrite = 3, Append = 4, + WriteAppend = 6, }; +inline u32 operator&(Mode lhs, Mode rhs) { + return static_cast(lhs) & static_cast(rhs); +} + } // namespace FileSys diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp index 095fec77e5..9ce2e1efa0 100644 --- a/src/core/file_sys/vfs_real.cpp +++ b/src/core/file_sys/vfs_real.cpp @@ -13,24 +13,31 @@ namespace FileSys { -static std::string PermissionsToCharArray(Mode perms) { - std::string out; - switch (perms) { - case Mode::Read: - out += "r"; - break; - case Mode::Write: - out += "r+"; - break; - case Mode::Append: - out += "a"; - break; +static std::string ModeFlagsToString(Mode mode) { + std::string mode_str; + + // Calculate the correct open mode for the file. + if (mode & Mode::Read && mode & Mode::Write) { + if (mode & Mode::Append) + mode_str = "a+"; + else + mode_str = "r+"; + } else { + if (mode & Mode::Read) + mode_str = "r"; + else if (mode & Mode::Append) + mode_str = "a"; + else if (mode & Mode::Write) + mode_str = "w"; } - return out + "b"; + + mode_str += "b"; + + return mode_str; } RealVfsFile::RealVfsFile(const std::string& path_, Mode perms_) - : backing(path_, PermissionsToCharArray(perms_).c_str()), path(path_), + : backing(path_, ModeFlagsToString(perms_).c_str()), path(path_), parent_path(FileUtil::GetParentPath(path_)), path_components(FileUtil::SplitPathComponents(path_)), parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)), @@ -53,11 +60,11 @@ std::shared_ptr RealVfsFile::GetContainingDirectory() const { } bool RealVfsFile::IsWritable() const { - return perms == Mode::Append || perms == Mode::Write; + return (perms & Mode::WriteAppend) != 0; } bool RealVfsFile::IsReadable() const { - return perms == Mode::Read || perms == Mode::Write; + return (perms & Mode::ReadWrite) != 0; } size_t RealVfsFile::Read(u8* data, size_t length, size_t offset) const { @@ -79,7 +86,7 @@ bool RealVfsFile::Rename(std::string_view name) { path = (parent_path + DIR_SEP).append(name); path_components = parent_components; path_components.push_back(std::move(name_str)); - backing = FileUtil::IOFile(path, PermissionsToCharArray(perms).c_str()); + backing = FileUtil::IOFile(path, ModeFlagsToString(perms).c_str()); return out; } @@ -93,7 +100,7 @@ RealVfsDirectory::RealVfsDirectory(const std::string& path_, Mode perms_) path_components(FileUtil::SplitPathComponents(path)), parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)), perms(perms_) { - if (!FileUtil::Exists(path) && (perms == Mode::Write || perms == Mode::Append)) + if (!FileUtil::Exists(path) && perms & Mode::WriteAppend) FileUtil::CreateDir(path); if (perms == Mode::Append) @@ -120,11 +127,11 @@ std::vector> RealVfsDirectory::GetSubdirectories() } bool RealVfsDirectory::IsWritable() const { - return perms == Mode::Write || perms == Mode::Append; + return (perms & Mode::WriteAppend) != 0; } bool RealVfsDirectory::IsReadable() const { - return perms == Mode::Read || perms == Mode::Write; + return (perms & Mode::ReadWrite) != 0; } std::string RealVfsDirectory::GetName() const { diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index dbfe06cbc8..fdd2fda182 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -24,7 +24,8 @@ namespace Service::FileSystem { constexpr u64 EMULATED_SD_REPORTED_SIZE = 32000000000; static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base, - std::string_view dir_name) { + std::string_view dir_name_) { + std::string dir_name(FileUtil::SanitizePath(dir_name_)); if (dir_name.empty() || dir_name == "." || dir_name == "/" || dir_name == "\\") return base; @@ -38,7 +39,8 @@ std::string VfsDirectoryServiceWrapper::GetName() const { return backing->GetName(); } -ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path, u64 size) const { +ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64 size) const { + std::string path(FileUtil::SanitizePath(path_)); auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); auto file = dir->CreateFile(FileUtil::GetFilename(path)); if (file == nullptr) { @@ -52,7 +54,8 @@ ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path, u64 s return RESULT_SUCCESS; } -ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path) const { +ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) const { + std::string path(FileUtil::SanitizePath(path_)); auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); if (path == "/" || path == "\\") { // TODO(DarkLordZach): Why do games call this and what should it do? Works as is but... @@ -60,14 +63,15 @@ ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path) const } if (dir->GetFile(FileUtil::GetFilename(path)) == nullptr) return FileSys::ERROR_PATH_NOT_FOUND; - if (!backing->DeleteFile(FileUtil::GetFilename(path))) { + if (!dir->DeleteFile(FileUtil::GetFilename(path))) { // TODO(DarkLordZach): Find a better error code for this return ResultCode(-1); } return RESULT_SUCCESS; } -ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path) const { +ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path_) const { + std::string path(FileUtil::SanitizePath(path_)); auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); if (dir == nullptr && FileUtil::GetFilename(FileUtil::GetParentPath(path)).empty()) dir = backing; @@ -79,7 +83,8 @@ ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path) return RESULT_SUCCESS; } -ResultCode VfsDirectoryServiceWrapper::DeleteDirectory(const std::string& path) const { +ResultCode VfsDirectoryServiceWrapper::DeleteDirectory(const std::string& path_) const { + std::string path(FileUtil::SanitizePath(path_)); auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); if (!dir->DeleteSubdirectory(FileUtil::GetFilename(path))) { // TODO(DarkLordZach): Find a better error code for this @@ -88,7 +93,8 @@ ResultCode VfsDirectoryServiceWrapper::DeleteDirectory(const std::string& path) return RESULT_SUCCESS; } -ResultCode VfsDirectoryServiceWrapper::DeleteDirectoryRecursively(const std::string& path) const { +ResultCode VfsDirectoryServiceWrapper::DeleteDirectoryRecursively(const std::string& path_) const { + std::string path(FileUtil::SanitizePath(path_)); auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); if (!dir->DeleteSubdirectoryRecursive(FileUtil::GetFilename(path))) { // TODO(DarkLordZach): Find a better error code for this @@ -97,8 +103,10 @@ ResultCode VfsDirectoryServiceWrapper::DeleteDirectoryRecursively(const std::str return RESULT_SUCCESS; } -ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path, - const std::string& dest_path) const { +ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_, + const std::string& dest_path_) const { + std::string src_path(FileUtil::SanitizePath(src_path_)); + std::string dest_path(FileUtil::SanitizePath(dest_path_)); auto src = backing->GetFileRelative(src_path); if (FileUtil::GetParentPath(src_path) == FileUtil::GetParentPath(dest_path)) { // Use more-optimized vfs implementation rename. @@ -130,8 +138,10 @@ ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path, return RESULT_SUCCESS; } -ResultCode VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path, - const std::string& dest_path) const { +ResultCode VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path_, + const std::string& dest_path_) const { + std::string src_path(FileUtil::SanitizePath(src_path_)); + std::string dest_path(FileUtil::SanitizePath(dest_path_)); auto src = GetDirectoryRelativeWrapped(backing, src_path); if (FileUtil::GetParentPath(src_path) == FileUtil::GetParentPath(dest_path)) { // Use more-optimized vfs implementation rename. @@ -154,8 +164,9 @@ ResultCode VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_pa return ResultCode(-1); } -ResultVal VfsDirectoryServiceWrapper::OpenFile(const std::string& path, +ResultVal VfsDirectoryServiceWrapper::OpenFile(const std::string& path_, FileSys::Mode mode) const { + std::string path(FileUtil::SanitizePath(path_)); auto npath = path; while (npath.size() > 0 && (npath[0] == '/' || npath[0] == '\\')) npath = npath.substr(1); @@ -171,7 +182,8 @@ ResultVal VfsDirectoryServiceWrapper::OpenFile(const std:: return MakeResult(file); } -ResultVal VfsDirectoryServiceWrapper::OpenDirectory(const std::string& path) { +ResultVal VfsDirectoryServiceWrapper::OpenDirectory(const std::string& path_) { + std::string path(FileUtil::SanitizePath(path_)); auto dir = GetDirectoryRelativeWrapped(backing, path); if (dir == nullptr) { // TODO(DarkLordZach): Find a better error code for this @@ -188,7 +200,8 @@ u64 VfsDirectoryServiceWrapper::GetFreeSpaceSize() const { } ResultVal VfsDirectoryServiceWrapper::GetEntryType( - const std::string& path) const { + const std::string& path_) const { + std::string path(FileUtil::SanitizePath(path_)); auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); if (dir == nullptr) return FileSys::ERROR_PATH_NOT_FOUND; @@ -272,9 +285,9 @@ void RegisterFileSystems() { sdmc_factory = nullptr; auto nand_directory = std::make_shared( - FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), FileSys::Mode::Write); + FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), FileSys::Mode::ReadWrite); auto sd_directory = std::make_shared( - FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir), FileSys::Mode::Write); + FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir), FileSys::Mode::ReadWrite); auto savedata = std::make_unique(std::move(nand_directory)); save_data_factory = std::move(savedata); From 42b5158c9661446984f1f60ed42d44651b6a28ad Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 23 Jul 2018 22:54:32 -0400 Subject: [PATCH 32/49] mutex: Pass SharedPtr to GetHighestPriorityMutexWaitingThread() by reference The pointed to thread's members are simply observed in this case, so we don't need to copy it here. --- src/core/hle/kernel/mutex.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 3f1de32587..feb7b88d20 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -19,7 +19,7 @@ namespace Kernel { /// Returns the number of threads that are waiting for a mutex, and the highest priority one among /// those. static std::pair, u32> GetHighestPriorityMutexWaitingThread( - SharedPtr current_thread, VAddr mutex_addr) { + const SharedPtr& current_thread, VAddr mutex_addr) { SharedPtr highest_priority_thread; u32 num_waiters = 0; From 8b83adfed67eb7e539677747e570688d0023c524 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 23 Jul 2018 23:01:01 -0400 Subject: [PATCH 33/49] apm/interface: Remove redundant declaration of InstallInterfaces() This is already declared in apm/apm.h --- src/core/hle/service/apm/interface.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/core/hle/service/apm/interface.h b/src/core/hle/service/apm/interface.h index 85258a666b..fa68c7d93b 100644 --- a/src/core/hle/service/apm/interface.h +++ b/src/core/hle/service/apm/interface.h @@ -19,7 +19,4 @@ private: std::shared_ptr apm; }; -/// Registers all AM services with the specified service manager. -void InstallInterfaces(SM::ServiceManager& service_manager); - } // namespace Service::APM From 2ff86f5765f8ff2a8c9188efa465e79c44738596 Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 23 Jul 2018 23:12:14 -0400 Subject: [PATCH 34/49] maxwell_to_gl: Implement VertexAttribute::Type::UnsignedInt. --- src/video_core/renderer_opengl/maxwell_to_gl.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h index e19c3b280f..eb823ea91c 100644 --- a/src/video_core/renderer_opengl/maxwell_to_gl.h +++ b/src/video_core/renderer_opengl/maxwell_to_gl.h @@ -56,6 +56,9 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) { return {}; } + case Maxwell::VertexAttribute::Type::UnsignedInt: + return GL_UNSIGNED_INT; + case Maxwell::VertexAttribute::Type::Float: return GL_FLOAT; } From 1d755abce43534aae22f1c8402c8476e2f1f8fec Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 23 Jul 2018 23:10:48 -0400 Subject: [PATCH 35/49] core: Make converting constructors explicit where applicable Avoids unwanted implicit conversions. Thankfully, given the large amount of cleanup in past PRs, only this tiny amount is left over to cover. --- src/core/hle/service/acc/acc.cpp | 2 +- src/core/hle/service/service.h | 2 +- src/core/loader/elf.cpp | 2 +- src/core/loader/loader.h | 2 +- src/core/tracer/recorder.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 3e1c2c0a0e..0b158e015a 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -35,7 +35,7 @@ static constexpr u128 DEFAULT_USER_ID{1ull, 0ull}; class IProfile final : public ServiceFramework { public: - IProfile(u128 user_id) : ServiceFramework("IProfile"), user_id(user_id) { + explicit IProfile(u128 user_id) : ServiceFramework("IProfile"), user_id(user_id) { static const FunctionInfo functions[] = { {0, nullptr, "Get"}, {1, &IProfile::GetBase, "GetBase"}, diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index fee841d464..180f22703a 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -146,7 +146,7 @@ protected: * @param max_sessions Maximum number of sessions that can be * connected to this service at the same time. */ - ServiceFramework(const char* service_name, u32 max_sessions = DefaultMaxSessions) + explicit ServiceFramework(const char* service_name, u32 max_sessions = DefaultMaxSessions) : ServiceFrameworkBase(service_name, max_sessions, Invoker) {} /// Registers handlers in the service. diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index 4bfd5f5364..352938dcb4 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp @@ -190,7 +190,7 @@ private: u32 entryPoint; public: - ElfReader(void* ptr); + explicit ElfReader(void* ptr); u32 Read32(int off) const { return base32[off >> 2]; diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index 6f517ca8c2..fbf11e5d0f 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -79,7 +79,7 @@ enum class ResultStatus { /// Interface for loading an application class AppLoader : NonCopyable { public: - AppLoader(FileSys::VirtualFile file) : file(std::move(file)) {} + explicit AppLoader(FileSys::VirtualFile file) : file(std::move(file)) {} virtual ~AppLoader() {} /** diff --git a/src/core/tracer/recorder.h b/src/core/tracer/recorder.h index 629c2f6d23..e1cefd5fec 100644 --- a/src/core/tracer/recorder.h +++ b/src/core/tracer/recorder.h @@ -32,7 +32,7 @@ public: * Recorder constructor * @param initial_state Initial recorder state */ - Recorder(const InitialState& initial_state); + explicit Recorder(const InitialState& initial_state); /// Finish recording of this Citrace and save it using the given filename. void Finish(const std::string& filename); From 7d124ec82b9339a4cc427eb0867af6b65fc78985 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 23 Jul 2018 23:19:35 -0400 Subject: [PATCH 36/49] arm_dynarmic: Make MakeJit() a const member function This functions doesn't modify instance state, so it can be a made a const member function. --- src/core/arm/dynarmic/arm_dynarmic.cpp | 4 ++-- src/core/arm/dynarmic/arm_dynarmic.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index d23adb28a7..57b8634b93 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -102,8 +102,8 @@ public: u64 tpidr_el0 = 0; }; -std::unique_ptr ARM_Dynarmic::MakeJit() { - const auto page_table = Core::CurrentProcess()->vm_manager.page_table.pointers.data(); +std::unique_ptr ARM_Dynarmic::MakeJit() const { + auto** const page_table = Core::CurrentProcess()->vm_manager.page_table.pointers.data(); Dynarmic::A64::UserConfig config; diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h index 350f61fd27..14c0726013 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.h +++ b/src/core/arm/dynarmic/arm_dynarmic.h @@ -50,7 +50,7 @@ public: void PageTableChanged() override; private: - std::unique_ptr MakeJit(); + std::unique_ptr MakeJit() const; friend class ARM_Dynarmic_Callbacks; std::unique_ptr cb; From ccc42702b53ac7585cc3a0db6dc5691875528167 Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 23 Jul 2018 22:21:31 -0500 Subject: [PATCH 37/49] GPU: Implement texture format R32F. --- .../renderer_opengl/gl_rasterizer_cache.cpp | 7 +++++-- .../renderer_opengl/gl_rasterizer_cache.h | 15 +++++++++++---- src/video_core/textures/decoders.cpp | 3 +++ 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 8f99864a04..1d3aff97b2 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -110,6 +110,7 @@ static constexpr std::array tex_form {GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // BGRA8 {GL_RGBA32F, GL_RGBA, GL_FLOAT, ComponentType::Float, false}, // RGBA32F {GL_RG32F, GL_RG, GL_FLOAT, ComponentType::Float, false}, // RG32F + {GL_R32F, GL_RED, GL_FLOAT, ComponentType::Float, false}, // R32F // DepthStencil formats {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, ComponentType::UNorm, @@ -203,8 +204,9 @@ static constexpr std::array, MortonCopy, MortonCopy, MortonCopy, MortonCopy, MortonCopy, - MortonCopy, MortonCopy, - MortonCopy, MortonCopy, + MortonCopy, MortonCopy, + MortonCopy, MortonCopy, + MortonCopy, }; static constexpr std::array, MortonCopy, MortonCopy, + MortonCopy, MortonCopy, MortonCopy, MortonCopy, diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 23efbe67c8..800d239d96 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -40,14 +40,15 @@ struct SurfaceParams { BGRA8 = 15, RGBA32F = 16, RG32F = 17, + R32F = 18, MaxColorFormat, // DepthStencil formats - Z24S8 = 18, - S8Z24 = 19, - Z32F = 20, - Z16 = 21, + Z24S8 = 19, + S8Z24 = 20, + Z32F = 21, + Z16 = 22, MaxDepthStencilFormat, @@ -103,6 +104,7 @@ struct SurfaceParams { 1, // BGRA8 1, // RGBA32F 1, // RG32F + 1, // R32F 1, // Z24S8 1, // S8Z24 1, // Z32F @@ -136,6 +138,7 @@ struct SurfaceParams { 32, // BGRA8 128, // RGBA32F 64, // RG32F + 32, // R32F 32, // Z24S8 32, // S8Z24 32, // Z32F @@ -223,6 +226,8 @@ struct SurfaceParams { UNREACHABLE(); case Tegra::Texture::TextureFormat::R32_G32: return PixelFormat::RG32F; + case Tegra::Texture::TextureFormat::R32: + return PixelFormat::R32F; case Tegra::Texture::TextureFormat::DXT1: return PixelFormat::DXT1; case Tegra::Texture::TextureFormat::DXT23: @@ -283,6 +288,8 @@ struct SurfaceParams { return Tegra::Texture::TextureFormat::R32_G32_B32_A32; case PixelFormat::RG32F: return Tegra::Texture::TextureFormat::R32_G32; + case PixelFormat::R32F: + return Tegra::Texture::TextureFormat::R32; default: LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast(format)); UNREACHABLE(); diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp index e5e9e18981..cda2646ad2 100644 --- a/src/video_core/textures/decoders.cpp +++ b/src/video_core/textures/decoders.cpp @@ -61,6 +61,7 @@ u32 BytesPerPixel(TextureFormat format) { case TextureFormat::A8R8G8B8: case TextureFormat::A2B10G10R10: case TextureFormat::BF10GF11RF11: + case TextureFormat::R32: return 4; case TextureFormat::A1B5G5R5: case TextureFormat::B5G6R5: @@ -121,6 +122,7 @@ std::vector UnswizzleTexture(VAddr address, TextureFormat format, u32 width, case TextureFormat::R16_G16_B16_A16: case TextureFormat::R32_G32_B32_A32: case TextureFormat::R32_G32: + case TextureFormat::R32: case TextureFormat::BF10GF11RF11: case TextureFormat::ASTC_2D_4X4: CopySwizzledData(width, height, bytes_per_pixel, bytes_per_pixel, data, @@ -178,6 +180,7 @@ std::vector DecodeTexture(const std::vector& texture_data, TextureFormat case TextureFormat::BF10GF11RF11: case TextureFormat::R32_G32_B32_A32: case TextureFormat::R32_G32: + case TextureFormat::R32: // TODO(Subv): For the time being just forward the same data without any decoding. rgba_data = texture_data; break; From 6b3e54621f8f13a754fe4c600f281bd79a3243b9 Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 23 Jul 2018 18:55:24 -0400 Subject: [PATCH 38/49] maxwell_to_gl: Implement Texture::WrapMode::Border. --- src/video_core/renderer_opengl/maxwell_to_gl.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h index e19c3b280f..369bdd9056 100644 --- a/src/video_core/renderer_opengl/maxwell_to_gl.h +++ b/src/video_core/renderer_opengl/maxwell_to_gl.h @@ -112,6 +112,8 @@ inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) { return GL_MIRRORED_REPEAT; case Tegra::Texture::WrapMode::ClampToEdge: return GL_CLAMP_TO_EDGE; + case Tegra::Texture::WrapMode::Border: + return GL_CLAMP_TO_BORDER; case Tegra::Texture::WrapMode::ClampOGL: // TODO(Subv): GL_CLAMP was removed as of OpenGL 3.1, to implement GL_CLAMP, we can use // GL_CLAMP_TO_BORDER to get the border color of the texture, and then sample the edge to From 69c45ce71c5a600f0372746348875a626e06898b Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 23 Jul 2018 23:26:48 -0400 Subject: [PATCH 39/49] gl_rasterizer: Implement texture border color. --- src/video_core/renderer_opengl/gl_rasterizer.cpp | 9 ++++++--- src/video_core/renderer_opengl/gl_rasterizer.h | 5 +---- src/video_core/textures/texture.h | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 56d9c575ba..5d5ad84b7d 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -601,7 +601,6 @@ void RasterizerOpenGL::SamplerInfo::Create() { sampler.Create(); mag_filter = min_filter = Tegra::Texture::TextureFilter::Linear; wrap_u = wrap_v = Tegra::Texture::WrapMode::Wrap; - border_color_r = border_color_g = border_color_b = border_color_a = 0; // default is GL_LINEAR_MIPMAP_LINEAR glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -630,8 +629,12 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr } if (wrap_u == Tegra::Texture::WrapMode::Border || wrap_v == Tegra::Texture::WrapMode::Border) { - // TODO(Subv): Implement border color - ASSERT(false); + const GLvec4 new_border_color = {{config.border_color_r, config.border_color_g, + config.border_color_b, config.border_color_a}}; + if (border_color != new_border_color) { + border_color = new_border_color; + glSamplerParameterfv(s, GL_TEXTURE_BORDER_COLOR, border_color.data()); + } } } diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index c406142e49..ab06e2d959 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -77,10 +77,7 @@ private: Tegra::Texture::TextureFilter min_filter; Tegra::Texture::WrapMode wrap_u; Tegra::Texture::WrapMode wrap_v; - u32 border_color_r; - u32 border_color_g; - u32 border_color_b; - u32 border_color_a; + GLvec4 border_color; }; /// Configures the color and depth framebuffer states and returns the dirty diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h index d1c755033e..c6bd2f4b9d 100644 --- a/src/video_core/textures/texture.h +++ b/src/video_core/textures/texture.h @@ -242,10 +242,10 @@ struct TSCEntry { BitField<6, 2, TextureMipmapFilter> mip_filter; }; INSERT_PADDING_BYTES(8); - u32 border_color_r; - u32 border_color_g; - u32 border_color_b; - u32 border_color_a; + float border_color_r; + float border_color_g; + float border_color_b; + float border_color_a; }; static_assert(sizeof(TSCEntry) == 0x20, "TSCEntry has wrong size"); From c73410bf2c58a17e0411456ea0ddb6d91872e079 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 24 Jul 2018 09:55:15 -0400 Subject: [PATCH 40/49] svc: Resolve sign comparison warnings in WaitSynchronization() The loop's induction variable was signed, but we were comparing against an unsigned variable. --- src/core/hle/kernel/svc.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 7b41c9cfd2..da7cacb577 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -165,11 +165,14 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64 using ObjectPtr = SharedPtr; std::vector objects(handle_count); - for (int i = 0; i < handle_count; ++i) { - Handle handle = Memory::Read32(handles_address + i * sizeof(Handle)); - auto object = g_handle_table.Get(handle); - if (object == nullptr) + for (u64 i = 0; i < handle_count; ++i) { + const Handle handle = Memory::Read32(handles_address + i * sizeof(Handle)); + const auto object = g_handle_table.Get(handle); + + if (object == nullptr) { return ERR_INVALID_HANDLE; + } + objects[i] = object; } From 77daef44b0a8f383c317824347713d97c4dc0053 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 24 Jul 2018 10:21:04 -0400 Subject: [PATCH 41/49] friend: Deduplicate interfaces --- src/core/CMakeLists.txt | 6 ++---- src/core/hle/service/friend/friend.cpp | 7 +++---- src/core/hle/service/friend/friend_u.cpp | 18 ------------------ src/core/hle/service/friend/friend_u.h | 16 ---------------- .../friend/{friend_a.cpp => interface.cpp} | 8 ++++---- .../service/friend/{friend_a.h => interface.h} | 4 ++-- 6 files changed, 11 insertions(+), 48 deletions(-) delete mode 100644 src/core/hle/service/friend/friend_u.cpp delete mode 100644 src/core/hle/service/friend/friend_u.h rename src/core/hle/service/friend/{friend_a.cpp => interface.cpp} (59%) rename src/core/hle/service/friend/{friend_a.h => interface.h} (68%) diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 6b6efbc00f..b7d52babc1 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -146,10 +146,8 @@ add_library(core STATIC hle/service/filesystem/fsp_srv.h hle/service/friend/friend.cpp hle/service/friend/friend.h - hle/service/friend/friend_a.cpp - hle/service/friend/friend_a.h - hle/service/friend/friend_u.cpp - hle/service/friend/friend_u.h + hle/service/friend/interface.cpp + hle/service/friend/interface.h hle/service/hid/hid.cpp hle/service/hid/hid.h hle/service/lm/lm.cpp diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index c98a46e053..3be0dcb9a4 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp @@ -5,8 +5,7 @@ #include "common/logging/log.h" #include "core/hle/ipc_helpers.h" #include "core/hle/service/friend/friend.h" -#include "core/hle/service/friend/friend_a.h" -#include "core/hle/service/friend/friend_u.h" +#include "core/hle/service/friend/interface.h" namespace Service::Friend { @@ -21,8 +20,8 @@ Module::Interface::Interface(std::shared_ptr module, const char* name) void InstallInterfaces(SM::ServiceManager& service_manager) { auto module = std::make_shared(); - std::make_shared(module)->InstallAsService(service_manager); - std::make_shared(module)->InstallAsService(service_manager); + std::make_shared(module, "friend:a")->InstallAsService(service_manager); + std::make_shared(module, "friend:u")->InstallAsService(service_manager); } } // namespace Service::Friend diff --git a/src/core/hle/service/friend/friend_u.cpp b/src/core/hle/service/friend/friend_u.cpp deleted file mode 100644 index 90b30883ff..0000000000 --- a/src/core/hle/service/friend/friend_u.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/service/friend/friend_u.h" - -namespace Service::Friend { - -Friend_U::Friend_U(std::shared_ptr module) - : Module::Interface(std::move(module), "friend:u") { - static const FunctionInfo functions[] = { - {0, &Friend_U::CreateFriendService, "CreateFriendService"}, - {1, nullptr, "CreateNotificationService"}, - }; - RegisterHandlers(functions); -} - -} // namespace Service::Friend diff --git a/src/core/hle/service/friend/friend_u.h b/src/core/hle/service/friend/friend_u.h deleted file mode 100644 index 0d953d807a..0000000000 --- a/src/core/hle/service/friend/friend_u.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/hle/service/friend/friend.h" - -namespace Service::Friend { - -class Friend_U final : public Module::Interface { -public: - explicit Friend_U(std::shared_ptr module); -}; - -} // namespace Service::Friend diff --git a/src/core/hle/service/friend/friend_a.cpp b/src/core/hle/service/friend/interface.cpp similarity index 59% rename from src/core/hle/service/friend/friend_a.cpp rename to src/core/hle/service/friend/interface.cpp index a2cc819264..a43c58ec60 100644 --- a/src/core/hle/service/friend/friend_a.cpp +++ b/src/core/hle/service/friend/interface.cpp @@ -2,14 +2,14 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "core/hle/service/friend/friend_a.h" +#include "core/hle/service/friend/interface.h" namespace Service::Friend { -Friend_A::Friend_A(std::shared_ptr module) - : Module::Interface(std::move(module), "friend:a") { +Friend::Friend(std::shared_ptr module, const char* name) + : Interface(std::move(module), name) { static const FunctionInfo functions[] = { - {0, &Friend_A::CreateFriendService, "CreateFriendService"}, + {0, &Friend::CreateFriendService, "CreateFriendService"}, {1, nullptr, "CreateNotificationService"}, }; RegisterHandlers(functions); diff --git a/src/core/hle/service/friend/friend_a.h b/src/core/hle/service/friend/interface.h similarity index 68% rename from src/core/hle/service/friend/friend_a.h rename to src/core/hle/service/friend/interface.h index 81257583ba..89dae84710 100644 --- a/src/core/hle/service/friend/friend_a.h +++ b/src/core/hle/service/friend/interface.h @@ -8,9 +8,9 @@ namespace Service::Friend { -class Friend_A final : public Module::Interface { +class Friend final : public Module::Interface { public: - explicit Friend_A(std::shared_ptr module); + explicit Friend(std::shared_ptr module, const char* name); }; } // namespace Service::Friend From 9539a1eaddc41ababeae25ab7d0922f708953639 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 24 Jul 2018 10:24:16 -0400 Subject: [PATCH 42/49] friend/interface: Add missing CreateDaemonSuspendSessionService() to the function handler table --- src/core/hle/service/friend/interface.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/hle/service/friend/interface.cpp b/src/core/hle/service/friend/interface.cpp index a43c58ec60..27c6a09e22 100644 --- a/src/core/hle/service/friend/interface.cpp +++ b/src/core/hle/service/friend/interface.cpp @@ -11,6 +11,7 @@ Friend::Friend(std::shared_ptr module, const char* name) static const FunctionInfo functions[] = { {0, &Friend::CreateFriendService, "CreateFriendService"}, {1, nullptr, "CreateNotificationService"}, + {2, nullptr, "CreateDaemonSuspendSessionService"}, }; RegisterHandlers(functions); } From 07c2d057bdae80cd7a7374176cdd16a6667e8482 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 24 Jul 2018 10:25:58 -0400 Subject: [PATCH 43/49] friend: Add friend:m, friend:s, and friend:v services Given we already have friend:a and friend:u, we should add the remaining services as well. --- src/core/hle/service/friend/friend.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index 3be0dcb9a4..fb4d89068e 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp @@ -21,7 +21,10 @@ Module::Interface::Interface(std::shared_ptr module, const char* name) void InstallInterfaces(SM::ServiceManager& service_manager) { auto module = std::make_shared(); std::make_shared(module, "friend:a")->InstallAsService(service_manager); + std::make_shared(module, "friend:m")->InstallAsService(service_manager); + std::make_shared(module, "friend:s")->InstallAsService(service_manager); std::make_shared(module, "friend:u")->InstallAsService(service_manager); + std::make_shared(module, "friend:v")->InstallAsService(service_manager); } } // namespace Service::Friend From 4cf2185e816d438691899a456a50636f6cedfa2d Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 24 Jul 2018 10:53:56 -0400 Subject: [PATCH 44/49] deconstructed_rom_directory: Remove unused FindRomFS() function --- .../loader/deconstructed_rom_directory.cpp | 29 ------------------- 1 file changed, 29 deletions(-) diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 18bd62a088..b0277a8750 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -6,7 +6,6 @@ #include "common/common_funcs.h" #include "common/file_util.h" #include "common/logging/log.h" -#include "common/string_util.h" #include "core/file_sys/content_archive.h" #include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/process.h" @@ -18,34 +17,6 @@ namespace Loader { -static std::string FindRomFS(const std::string& directory) { - std::string filepath_romfs; - const auto callback = [&filepath_romfs](u64*, const std::string& directory, - const std::string& virtual_name) -> bool { - const std::string physical_name = directory + virtual_name; - if (FileUtil::IsDirectory(physical_name)) { - // Skip directories - return true; - } - - // Verify extension - const std::string extension = physical_name.substr(physical_name.find_last_of(".") + 1); - if (Common::ToLower(extension) != "romfs") { - return true; - } - - // Found it - we are done - filepath_romfs = std::move(physical_name); - return false; - }; - - // Search the specified directory recursively, looking for the first .romfs file, which will - // be used for the RomFS - FileUtil::ForeachDirectoryEntry(nullptr, directory, callback); - - return filepath_romfs; -} - AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file) : AppLoader(std::move(file)) {} From b5eb3905cdad545fc2c4c3141d0d3ff22183e442 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 24 Jul 2018 12:08:10 -0400 Subject: [PATCH 45/49] gl_rasterizer: Use in-class member initializers where applicable We can just assign to the members directly in these cases. --- src/video_core/renderer_opengl/gl_rasterizer.cpp | 7 ------- src/video_core/renderer_opengl/gl_rasterizer.h | 10 +++++----- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 5d5ad84b7d..d2ac067c04 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -37,11 +37,6 @@ MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(100, 100, 255)); MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100)); RasterizerOpenGL::RasterizerOpenGL() { - has_ARB_buffer_storage = false; - has_ARB_direct_state_access = false; - has_ARB_separate_shader_objects = false; - has_ARB_vertex_attrib_binding = false; - // Create sampler objects for (size_t i = 0; i < texture_samplers.size(); ++i) { texture_samplers[i].Create(); @@ -110,8 +105,6 @@ RasterizerOpenGL::RasterizerOpenGL() { glBindBufferBase(GL_UNIFORM_BUFFER, index, buffer.handle); } - accelerate_draw = AccelDraw::Disabled; - glEnable(GL_BLEND); LOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!"); diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index ab06e2d959..e150be58f6 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -135,10 +135,10 @@ private: /// Syncs the blend state to match the guest state void SyncBlendState(); - bool has_ARB_buffer_storage; - bool has_ARB_direct_state_access; - bool has_ARB_separate_shader_objects; - bool has_ARB_vertex_attrib_binding; + bool has_ARB_buffer_storage = false; + bool has_ARB_direct_state_access = false; + bool has_ARB_separate_shader_objects = false; + bool has_ARB_vertex_attrib_binding = false; OpenGLState state; @@ -167,5 +167,5 @@ private: void SetupShaders(u8* buffer_ptr, GLintptr buffer_offset); enum class AccelDraw { Disabled, Arrays, Indexed }; - AccelDraw accelerate_draw; + AccelDraw accelerate_draw = AccelDraw::Disabled; }; From 16139ed53b1b4be3ffc985b84ad966c8920082d4 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 24 Jul 2018 12:10:35 -0400 Subject: [PATCH 46/49] gl_rasterizer: Use std::string_view instead of std::string when checking for extensions We can avoid heap allocations here by just using a std::string_view instead of performing unnecessary copying of the string data. --- src/video_core/renderer_opengl/gl_rasterizer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index d2ac067c04..f45fbbcd4a 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -54,7 +55,8 @@ RasterizerOpenGL::RasterizerOpenGL() { GLint ext_num; glGetIntegerv(GL_NUM_EXTENSIONS, &ext_num); for (GLint i = 0; i < ext_num; i++) { - std::string extension{reinterpret_cast(glGetStringi(GL_EXTENSIONS, i))}; + const std::string_view extension{ + reinterpret_cast(glGetStringi(GL_EXTENSIONS, i))}; if (extension == "GL_ARB_buffer_storage") { has_ARB_buffer_storage = true; From 0162f8b3a74498f9ecf974594266239744d3187c Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 24 Jul 2018 12:19:39 -0400 Subject: [PATCH 47/49] gl_rasterizer: Replace magic number with GL_INVALID_INDEX in SetupConstBuffers() This is just the named constant that OpenGL provides, so we can use that instead of using a literal -1 --- src/video_core/renderer_opengl/gl_rasterizer.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index f45fbbcd4a..a1c47bae99 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -689,10 +689,12 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint progr glBindBuffer(GL_UNIFORM_BUFFER, 0); // Now configure the bindpoint of the buffer inside the shader - std::string buffer_name = used_buffer.GetName(); - GLuint index = glGetProgramResourceIndex(program, GL_UNIFORM_BLOCK, buffer_name.c_str()); - if (index != -1) + const std::string buffer_name = used_buffer.GetName(); + const GLuint index = + glGetProgramResourceIndex(program, GL_UNIFORM_BLOCK, buffer_name.c_str()); + if (index != GL_INVALID_INDEX) { glUniformBlockBinding(program, index, buffer_draw_state.bindpoint); + } } state.Apply(); From 4cc1e180eccb4fa4df484badf1eaf60e6728752f Mon Sep 17 00:00:00 2001 From: Subv Date: Tue, 24 Jul 2018 13:39:16 -0500 Subject: [PATCH 48/49] GPU: Implemented the R16 and R16F texture formats. --- .../renderer_opengl/gl_rasterizer_cache.cpp | 7 ++++- .../renderer_opengl/gl_rasterizer_cache.h | 27 ++++++++++++++++--- src/video_core/textures/decoders.cpp | 3 +++ 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 1d3aff97b2..0f50063839 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -111,6 +111,8 @@ static constexpr std::array tex_form {GL_RGBA32F, GL_RGBA, GL_FLOAT, ComponentType::Float, false}, // RGBA32F {GL_RG32F, GL_RG, GL_FLOAT, ComponentType::Float, false}, // RG32F {GL_R32F, GL_RED, GL_FLOAT, ComponentType::Float, false}, // R32F + {GL_R16F, GL_RED, GL_HALF_FLOAT, ComponentType::Float, false}, // R16F + {GL_R16, GL_RED, GL_UNSIGNED_SHORT, ComponentType::UNorm, false}, // R16UNORM // DepthStencil formats {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, ComponentType::UNorm, @@ -204,7 +206,8 @@ static constexpr std::array, MortonCopy, MortonCopy, MortonCopy, MortonCopy, MortonCopy, - MortonCopy, MortonCopy, + MortonCopy, MortonCopy, + MortonCopy, MortonCopy, MortonCopy, MortonCopy, MortonCopy, }; @@ -232,6 +235,8 @@ static constexpr std::array, MortonCopy, MortonCopy, + MortonCopy, + MortonCopy, MortonCopy, MortonCopy, MortonCopy, diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 800d239d96..e1d3670d9c 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -41,14 +41,16 @@ struct SurfaceParams { RGBA32F = 16, RG32F = 17, R32F = 18, + R16F = 19, + R16UNORM = 20, MaxColorFormat, // DepthStencil formats - Z24S8 = 19, - S8Z24 = 20, - Z32F = 21, - Z16 = 22, + Z24S8 = 21, + S8Z24 = 22, + Z32F = 23, + Z16 = 24, MaxDepthStencilFormat, @@ -105,6 +107,8 @@ struct SurfaceParams { 1, // RGBA32F 1, // RG32F 1, // R32F + 1, // R16F + 1, // R16UNORM 1, // Z24S8 1, // S8Z24 1, // Z32F @@ -139,6 +143,8 @@ struct SurfaceParams { 128, // RGBA32F 64, // RG32F 32, // R32F + 16, // R16F + 16, // R16UNORM 32, // Z24S8 32, // S8Z24 32, // Z32F @@ -226,6 +232,16 @@ struct SurfaceParams { UNREACHABLE(); case Tegra::Texture::TextureFormat::R32_G32: return PixelFormat::RG32F; + case Tegra::Texture::TextureFormat::R16: + switch (component_type) { + case Tegra::Texture::ComponentType::FLOAT: + return PixelFormat::R16F; + case Tegra::Texture::ComponentType::UNORM: + return PixelFormat::R16UNORM; + } + LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", + static_cast(component_type)); + UNREACHABLE(); case Tegra::Texture::TextureFormat::R32: return PixelFormat::R32F; case Tegra::Texture::TextureFormat::DXT1: @@ -290,6 +306,9 @@ struct SurfaceParams { return Tegra::Texture::TextureFormat::R32_G32; case PixelFormat::R32F: return Tegra::Texture::TextureFormat::R32; + case PixelFormat::R16F: + case PixelFormat::R16UNORM: + return Tegra::Texture::TextureFormat::R16; default: LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast(format)); UNREACHABLE(); diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp index cda2646ad2..970c06e719 100644 --- a/src/video_core/textures/decoders.cpp +++ b/src/video_core/textures/decoders.cpp @@ -66,6 +66,7 @@ u32 BytesPerPixel(TextureFormat format) { case TextureFormat::A1B5G5R5: case TextureFormat::B5G6R5: case TextureFormat::G8R8: + case TextureFormat::R16: return 2; case TextureFormat::R8: return 1; @@ -123,6 +124,7 @@ std::vector UnswizzleTexture(VAddr address, TextureFormat format, u32 width, case TextureFormat::R32_G32_B32_A32: case TextureFormat::R32_G32: case TextureFormat::R32: + case TextureFormat::R16: case TextureFormat::BF10GF11RF11: case TextureFormat::ASTC_2D_4X4: CopySwizzledData(width, height, bytes_per_pixel, bytes_per_pixel, data, @@ -181,6 +183,7 @@ std::vector DecodeTexture(const std::vector& texture_data, TextureFormat case TextureFormat::R32_G32_B32_A32: case TextureFormat::R32_G32: case TextureFormat::R32: + case TextureFormat::R16: // TODO(Subv): For the time being just forward the same data without any decoding. rgba_data = texture_data; break; From 8f2c4191ab85da496175748728957af23c97252b Mon Sep 17 00:00:00 2001 From: Subv Date: Tue, 24 Jul 2018 13:54:12 -0500 Subject: [PATCH 49/49] GPU: Remove the assert that required the CODE_ADDRESS to be 0. Games usually just leave it at 0 but nouveau sets it to something else. This already works fine, the assert is useless. --- src/video_core/engines/maxwell_3d.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index d7328ff39b..0e205ed72e 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -75,14 +75,6 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) { ProcessMacroUpload(value); break; } - case MAXWELL3D_REG_INDEX(code_address.code_address_high): - case MAXWELL3D_REG_INDEX(code_address.code_address_low): { - // Note: For some reason games (like Puyo Puyo Tetris) seem to write 0 to the CODE_ADDRESS - // register, we do not currently know if that's intended or a bug, so we assert it lest - // stuff breaks in other places (like the shader address calculation). - ASSERT_MSG(regs.code_address.CodeAddress() == 0, "Unexpected CODE_ADDRESS register value."); - break; - } case MAXWELL3D_REG_INDEX(const_buffer.cb_data[0]): case MAXWELL3D_REG_INDEX(const_buffer.cb_data[1]): case MAXWELL3D_REG_INDEX(const_buffer.cb_data[2]):