Compare commits
56 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2c4c2b5eee | |||
| 885d88825e | |||
| 360b0d1b30 | |||
| 02880a8195 | |||
| b6f6733131 | |||
| 7f424d0f60 | |||
| ebb30cbefb | |||
| c5c89a4d5c | |||
| cc9e682021 | |||
| 03b73aa575 | |||
| 61f6eaad45 | |||
| cf770a68a5 | |||
| d1f0d182a7 | |||
| 2cacf97099 | |||
| d24fcaff77 | |||
| f7d4c84807 | |||
| 64cbebc58f | |||
| e0c46e6879 | |||
| d4a1afba4b | |||
| fb9418798d | |||
| b0b0786493 | |||
| 8714d40a77 | |||
| 8dc9f35baf | |||
| 883eb1a1a1 | |||
| 0fc596de6e | |||
| 18c1cb68fd | |||
| 096f339a2a | |||
| fa0d65fc7b | |||
| a056d8de16 | |||
| bfa973a62b | |||
| 3ab0514698 | |||
| cd66395944 | |||
| 56e237d1f9 | |||
| 08b2b1080a | |||
| 3d7c284e0f | |||
| b6ae48966d | |||
| 0e8a3bf3e5 | |||
| 344d15f61e | |||
| ff5a0f370c | |||
| 7b069252f8 | |||
| 46c3047283 | |||
| ae7dfa93be | |||
| deb1b54eed | |||
| c414ebaa9c | |||
| e07dfc4da3 | |||
| 63d30133f8 | |||
| f1e4f3fc0c | |||
| 468576284d | |||
| 4d66ca97e5 | |||
| c1a3d19897 | |||
| 0c8b6b0351 | |||
| ece5287843 | |||
| b0ab803ce8 | |||
| 28bb248db6 | |||
| 442a1cc021 | |||
| 76ca2a5f82 |
@@ -4,9 +4,13 @@
|
||||
cp license.txt "$DIR_NAME"
|
||||
cp README.md "$DIR_NAME"
|
||||
|
||||
tar -cJvf "${REV_NAME}-source.tar.xz" src externals CMakeLists.txt README.md license.txt
|
||||
cp "${REV_NAME}-source.tar.xz" "$DIR_NAME"
|
||||
|
||||
tar $COMPRESSION_FLAGS "$ARCHIVE_NAME" "$DIR_NAME"
|
||||
|
||||
mv "$DIR_NAME" $RELEASE_NAME
|
||||
mv "${REV_NAME}-source.tar.xz" $RELEASE_NAME
|
||||
|
||||
7z a "$REV_NAME.7z" $RELEASE_NAME
|
||||
|
||||
|
||||
@@ -7,9 +7,9 @@ ARCHIVE_NAME="${REV_NAME}.tar.xz"
|
||||
COMPRESSION_FLAGS="-cJvf"
|
||||
|
||||
if [ "${RELEASE_NAME}" = "mainline" ]; then
|
||||
DIR_NAME="${REV_NAME}_${RELEASE_NAME}"
|
||||
else
|
||||
DIR_NAME="${REV_NAME}"
|
||||
else
|
||||
DIR_NAME="${REV_NAME}_${RELEASE_NAME}"
|
||||
fi
|
||||
|
||||
mkdir "$DIR_NAME"
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
param($BUILD_NAME)
|
||||
|
||||
$GITDATE = $(git show -s --date=short --format='%ad') -replace "-",""
|
||||
$GITDATE = $(git show -s --date=short --format='%ad') -replace "-", ""
|
||||
$GITREV = $(git show -s --format='%h')
|
||||
|
||||
if ("$BUILD_NAME" -eq "mainline") {
|
||||
$RELEASE_DIST = "yuzu-windows-msvc-$BUILD_NAME"
|
||||
} else {
|
||||
$RELEASE_DIST = "yuzu-windows-msvc"
|
||||
}
|
||||
else {
|
||||
$RELEASE_DIST = "yuzu-windows-msvc-$BUILD_NAME"
|
||||
}
|
||||
|
||||
$MSVC_BUILD_ZIP = "yuzu-windows-msvc-$GITDATE-$GITREV.zip" -replace " ", ""
|
||||
$MSVC_BUILD_PDB = "yuzu-windows-msvc-$GITDATE-$GITREV-debugsymbols.zip" -replace " ", ""
|
||||
$MSVC_SEVENZIP = "yuzu-windows-msvc-$GITDATE-$GITREV.7z" -replace " ", ""
|
||||
$MSVC_TAR = "yuzu-windows-msvc-$GITDATE-$GITREV.tar" -replace " ", ""
|
||||
$MSVC_TARXZ = "yuzu-windows-msvc-$GITDATE-$GITREV.tar.xz" -replace " ", ""
|
||||
$MSVC_SOURCE = "yuzu-windows-msvc-source-$GITDATE-$GITREV" -replace " ", ""
|
||||
$MSVC_SOURCE_TAR = "$MSVC_SOURCE.tar"
|
||||
$MSVC_SOURCE_TARXZ = "$MSVC_SOURCE_TAR.xz"
|
||||
|
||||
$env:BUILD_ZIP = $MSVC_BUILD_ZIP
|
||||
$env:BUILD_SYMBOLS = $MSVC_BUILD_PDB
|
||||
@@ -21,19 +25,33 @@ $env:BUILD_UPDATE = $MSVC_SEVENZIP
|
||||
|
||||
$BUILD_DIR = ".\build\bin\Release"
|
||||
|
||||
# Upload debugging symbols
|
||||
mkdir pdb
|
||||
Get-ChildItem "$BUILD_DIR\" -Recurse -Filter "*.pdb" | Copy-Item -destination .\pdb
|
||||
7z a -tzip $MSVC_BUILD_PDB .\pdb\*.pdb
|
||||
rm "$BUILD_DIR\*.pdb"
|
||||
|
||||
# Create artifact directories
|
||||
mkdir $RELEASE_DIST
|
||||
mkdir $MSVC_SOURCE
|
||||
mkdir "artifacts"
|
||||
|
||||
# Build a tar.xz for the source of the release
|
||||
Copy-Item .\license.txt -Destination $MSVC_SOURCE
|
||||
Copy-Item .\README.md -Destination $MSVC_SOURCE
|
||||
Copy-Item .\src -Recurse -Destination $MSVC_SOURCE
|
||||
Copy-Item .\externals -Recurse -Destination $MSVC_SOURCE
|
||||
Copy-Item .\dist -Recurse -Destination $MSVC_SOURCE
|
||||
Copy-Item .\CMakeModules -Recurse -Destination $MSVC_SOURCE
|
||||
7z a -r -ttar $MSVC_SOURCE_TAR $MSVC_SOURCE
|
||||
7z a -r -txz $MSVC_SOURCE_TARXZ $MSVC_SOURCE_TAR
|
||||
|
||||
# Build the final release artifacts
|
||||
Copy-Item $MSVC_SOURCE_TARXZ -Destination $RELEASE_DIST
|
||||
Copy-Item "$BUILD_DIR\*" -Destination $RELEASE_DIST -Recurse
|
||||
rm "$RELEASE_DIST\*.exe"
|
||||
Get-ChildItem "$BUILD_DIR" -Recurse -Filter "yuzu*.exe" | Copy-Item -destination $RELEASE_DIST
|
||||
Get-ChildItem "$BUILD_DIR" -Recurse -Filter "QtWebEngineProcess*.exe" | Copy-Item -destination $RELEASE_DIST
|
||||
Copy-Item .\license.txt -Destination $RELEASE_DIST
|
||||
Copy-Item .\README.md -Destination $RELEASE_DIST
|
||||
7z a -tzip $MSVC_BUILD_ZIP $RELEASE_DIST\*
|
||||
7z a $MSVC_SEVENZIP $RELEASE_DIST
|
||||
|
||||
|
||||
@@ -7,9 +7,9 @@ ARCHIVE_NAME="${REV_NAME}.tar.gz"
|
||||
COMPRESSION_FLAGS="-czvf"
|
||||
|
||||
if [ "${RELEASE_NAME}" = "mainline" ]; then
|
||||
DIR_NAME="${REV_NAME}_${RELEASE_NAME}"
|
||||
else
|
||||
DIR_NAME="${REV_NAME}"
|
||||
else
|
||||
DIR_NAME="${REV_NAME}_${RELEASE_NAME}"
|
||||
fi
|
||||
|
||||
mkdir "$DIR_NAME"
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
**The Contributor's Guide has moved to [the Yuzu wiki](https://github.com/yuzu-emu/yuzu/wiki/Contributing).**
|
||||
**The Contributor's Guide has moved to [the yuzu wiki](https://github.com/yuzu-emu/yuzu/wiki/Contributing).**
|
||||
|
||||
+3
-3
@@ -814,7 +814,7 @@ struct MicroProfile
|
||||
|
||||
inline int MicroProfileLogType(MicroProfileLogEntry Index)
|
||||
{
|
||||
return ((MP_LOG_BEGIN_MASK & Index)>>62) & 0x3;
|
||||
return (int)(((MP_LOG_BEGIN_MASK & Index)>>62) & 0x3ULL);
|
||||
}
|
||||
|
||||
inline uint64_t MicroProfileLogTimerIndex(MicroProfileLogEntry Index)
|
||||
@@ -861,12 +861,12 @@ T MicroProfileMax(T a, T b)
|
||||
|
||||
inline int64_t MicroProfileMsToTick(float fMs, int64_t nTicksPerSecond)
|
||||
{
|
||||
return (int64_t)(fMs*0.001f*nTicksPerSecond);
|
||||
return (int64_t)(fMs*0.001f*(float)nTicksPerSecond);
|
||||
}
|
||||
|
||||
inline float MicroProfileTickToMsMultiplier(int64_t nTicksPerSecond)
|
||||
{
|
||||
return 1000.f / nTicksPerSecond;
|
||||
return 1000.f / (float)nTicksPerSecond;
|
||||
}
|
||||
|
||||
inline uint16_t MicroProfileGetGroupIndex(MicroProfileToken t)
|
||||
|
||||
@@ -3,17 +3,8 @@
|
||||
# could affect the result, but much more unlikely than the following files. Keeping a list of files
|
||||
# like this allows for much better caching since it doesn't force the user to recompile binary shaders every update
|
||||
set(VIDEO_CORE "${CMAKE_SOURCE_DIR}/src/video_core")
|
||||
if (DEFINED ENV{CI})
|
||||
if (DEFINED ENV{TRAVIS})
|
||||
set(BUILD_REPOSITORY $ENV{TRAVIS_REPO_SLUG})
|
||||
set(BUILD_TAG $ENV{TRAVIS_TAG})
|
||||
elseif(DEFINED ENV{APPVEYOR})
|
||||
set(BUILD_REPOSITORY $ENV{APPVEYOR_REPO_NAME})
|
||||
set(BUILD_TAG $ENV{APPVEYOR_REPO_TAG_NAME})
|
||||
elseif(DEFINED ENV{AZURE})
|
||||
set(BUILD_REPOSITORY $ENV{AZURE_REPO_NAME})
|
||||
set(BUILD_TAG $ENV{AZURE_REPO_TAG})
|
||||
endif()
|
||||
if (DEFINED ENV{AZURECIREPO})
|
||||
set(BUILD_REPOSITORY $ENV{AZURECIREPO})
|
||||
endif()
|
||||
if (DEFINED ENV{TITLEBARFORMATIDLE})
|
||||
set(TITLE_BAR_FORMAT_IDLE $ENV{TITLEBARFORMATIDLE})
|
||||
|
||||
@@ -56,7 +56,7 @@ std::string GetLastErrorMsg();
|
||||
namespace Common {
|
||||
|
||||
constexpr u32 MakeMagic(char a, char b, char c, char d) {
|
||||
return a | b << 8 | c << 16 | d << 24;
|
||||
return u32(a) | u32(b) << 8 | u32(c) << 16 | u32(d) << 24;
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -35,41 +35,6 @@ static inline u64 ComputeStructHash64(const T& data) {
|
||||
return ComputeHash64(&data, sizeof(data));
|
||||
}
|
||||
|
||||
/// A helper template that ensures the padding in a struct is initialized by memsetting to 0.
|
||||
template <typename T>
|
||||
struct HashableStruct {
|
||||
// In addition to being trivially copyable, T must also have a trivial default constructor,
|
||||
// because any member initialization would be overridden by memset
|
||||
static_assert(std::is_trivial_v<T>, "Type passed to HashableStruct must be trivial");
|
||||
/*
|
||||
* We use a union because "implicitly-defined copy/move constructor for a union X copies the
|
||||
* object representation of X." and "implicitly-defined copy assignment operator for a union X
|
||||
* copies the object representation (3.9) of X." = Bytewise copy instead of memberwise copy.
|
||||
* This is important because the padding bytes are included in the hash and comparison between
|
||||
* objects.
|
||||
*/
|
||||
union {
|
||||
T state;
|
||||
};
|
||||
|
||||
HashableStruct() {
|
||||
// Memset structure to zero padding bits, so that they will be deterministic when hashing
|
||||
std::memset(&state, 0, sizeof(T));
|
||||
}
|
||||
|
||||
bool operator==(const HashableStruct<T>& o) const {
|
||||
return std::memcmp(&state, &o.state, sizeof(T)) == 0;
|
||||
};
|
||||
|
||||
bool operator!=(const HashableStruct<T>& o) const {
|
||||
return !(*this == o);
|
||||
};
|
||||
|
||||
std::size_t Hash() const {
|
||||
return Common::ComputeStructHash64(state);
|
||||
}
|
||||
};
|
||||
|
||||
struct PairHash {
|
||||
template <class T1, class T2>
|
||||
std::size_t operator()(const std::pair<T1, T2>& pair) const noexcept {
|
||||
|
||||
@@ -396,7 +396,7 @@ static std::array<u8, target_size> MGF1(const std::array<u8, in_size>& seed) {
|
||||
while (out.size() < target_size) {
|
||||
out.resize(out.size() + 0x20);
|
||||
seed_exp[in_size + 3] = static_cast<u8>(i);
|
||||
mbedtls_sha256(seed_exp.data(), seed_exp.size(), out.data() + out.size() - 0x20, 0);
|
||||
mbedtls_sha256_ret(seed_exp.data(), seed_exp.size(), out.data() + out.size() - 0x20, 0);
|
||||
++i;
|
||||
}
|
||||
|
||||
@@ -668,23 +668,27 @@ void KeyManager::WriteKeyToFile(KeyCategory category, std::string_view keyname,
|
||||
const std::array<u8, Size>& key) {
|
||||
const std::string yuzu_keys_dir = FileUtil::GetUserPath(FileUtil::UserPath::KeysDir);
|
||||
std::string filename = "title.keys_autogenerated";
|
||||
if (category == KeyCategory::Standard)
|
||||
if (category == KeyCategory::Standard) {
|
||||
filename = dev_mode ? "dev.keys_autogenerated" : "prod.keys_autogenerated";
|
||||
else if (category == KeyCategory::Console)
|
||||
} else if (category == KeyCategory::Console) {
|
||||
filename = "console.keys_autogenerated";
|
||||
const auto add_info_text = !FileUtil::Exists(yuzu_keys_dir + DIR_SEP + filename);
|
||||
FileUtil::CreateFullPath(yuzu_keys_dir + DIR_SEP + filename);
|
||||
std::ofstream file(yuzu_keys_dir + DIR_SEP + filename, std::ios::app);
|
||||
if (!file.is_open())
|
||||
return;
|
||||
if (add_info_text) {
|
||||
file
|
||||
<< "# This file is autogenerated by Yuzu\n"
|
||||
<< "# It serves to store keys that were automatically generated from the normal keys\n"
|
||||
<< "# If you are experiencing issues involving keys, it may help to delete this file\n";
|
||||
}
|
||||
|
||||
file << fmt::format("\n{} = {}", keyname, Common::HexToString(key));
|
||||
const auto path = yuzu_keys_dir + DIR_SEP + filename;
|
||||
const auto add_info_text = !FileUtil::Exists(path);
|
||||
FileUtil::CreateFullPath(path);
|
||||
FileUtil::IOFile file{path, "a"};
|
||||
if (!file.IsOpen()) {
|
||||
return;
|
||||
}
|
||||
if (add_info_text) {
|
||||
file.WriteString(
|
||||
"# This file is autogenerated by Yuzu\n"
|
||||
"# It serves to store keys that were automatically generated from the normal keys\n"
|
||||
"# If you are experiencing issues involving keys, it may help to delete this file\n");
|
||||
}
|
||||
|
||||
file.WriteString(fmt::format("\n{} = {}", keyname, Common::HexToString(key)));
|
||||
AttemptLoadKeyFile(yuzu_keys_dir, yuzu_keys_dir, filename, category == KeyCategory::Title);
|
||||
}
|
||||
|
||||
|
||||
@@ -161,7 +161,7 @@ std::array<u8, key_size> FindKeyFromHex(const std::vector<u8>& binary,
|
||||
|
||||
std::array<u8, 0x20> temp{};
|
||||
for (size_t i = 0; i < binary.size() - key_size; ++i) {
|
||||
mbedtls_sha256(binary.data() + i, key_size, temp.data(), 0);
|
||||
mbedtls_sha256_ret(binary.data() + i, key_size, temp.data(), 0);
|
||||
|
||||
if (temp != hash)
|
||||
continue;
|
||||
@@ -189,7 +189,7 @@ static std::array<Key128, 0x20> FindEncryptedMasterKeyFromHex(const std::vector<
|
||||
AESCipher<Key128> cipher(key, Mode::ECB);
|
||||
for (size_t i = 0; i < binary.size() - 0x10; ++i) {
|
||||
cipher.Transcode(binary.data() + i, dec_temp.size(), dec_temp.data(), Op::Decrypt);
|
||||
mbedtls_sha256(dec_temp.data(), dec_temp.size(), temp.data(), 0);
|
||||
mbedtls_sha256_ret(dec_temp.data(), dec_temp.size(), temp.data(), 0);
|
||||
|
||||
for (size_t k = 0; k < out.size(); ++k) {
|
||||
if (temp == master_key_hashes[k]) {
|
||||
|
||||
@@ -62,7 +62,7 @@ static std::string GetRelativePathFromNcaID(const std::array<u8, 16>& nca_id, bo
|
||||
Common::HexToString(nca_id, second_hex_upper));
|
||||
|
||||
Core::Crypto::SHA256Hash hash{};
|
||||
mbedtls_sha256(nca_id.data(), nca_id.size(), hash.data(), 0);
|
||||
mbedtls_sha256_ret(nca_id.data(), nca_id.size(), hash.data(), 0);
|
||||
return fmt::format(cnmt_suffix ? "/000000{:02X}/{}.cnmt.nca" : "/000000{:02X}/{}.nca", hash[0],
|
||||
Common::HexToString(nca_id, second_hex_upper));
|
||||
}
|
||||
@@ -141,7 +141,7 @@ bool PlaceholderCache::Create(const NcaID& id, u64 size) const {
|
||||
}
|
||||
|
||||
Core::Crypto::SHA256Hash hash{};
|
||||
mbedtls_sha256(id.data(), id.size(), hash.data(), 0);
|
||||
mbedtls_sha256_ret(id.data(), id.size(), hash.data(), 0);
|
||||
const auto dirname = fmt::format("000000{:02X}", hash[0]);
|
||||
|
||||
const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname);
|
||||
@@ -165,7 +165,7 @@ bool PlaceholderCache::Delete(const NcaID& id) const {
|
||||
}
|
||||
|
||||
Core::Crypto::SHA256Hash hash{};
|
||||
mbedtls_sha256(id.data(), id.size(), hash.data(), 0);
|
||||
mbedtls_sha256_ret(id.data(), id.size(), hash.data(), 0);
|
||||
const auto dirname = fmt::format("000000{:02X}", hash[0]);
|
||||
|
||||
const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname);
|
||||
@@ -603,7 +603,7 @@ InstallResult RegisteredCache::InstallEntry(const NCA& nca, TitleType type,
|
||||
OptionalHeader opt_header{0, 0};
|
||||
ContentRecord c_rec{{}, {}, {}, GetCRTypeFromNCAType(nca.GetType()), {}};
|
||||
const auto& data = nca.GetBaseFile()->ReadBytes(0x100000);
|
||||
mbedtls_sha256(data.data(), data.size(), c_rec.hash.data(), 0);
|
||||
mbedtls_sha256_ret(data.data(), data.size(), c_rec.hash.data(), 0);
|
||||
memcpy(&c_rec.nca_id, &c_rec.hash, 16);
|
||||
const CNMT new_cnmt(header, opt_header, {c_rec}, {});
|
||||
if (!RawInstallYuzuMeta(new_cnmt))
|
||||
@@ -626,7 +626,7 @@ InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFuncti
|
||||
id = *override_id;
|
||||
} else {
|
||||
const auto& data = in->ReadBytes(0x100000);
|
||||
mbedtls_sha256(data.data(), data.size(), hash.data(), 0);
|
||||
mbedtls_sha256_ret(data.data(), data.size(), hash.data(), 0);
|
||||
memcpy(id.data(), hash.data(), 16);
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ NAX::NAX(VirtualFile file_) : header(std::make_unique<NAXHeader>()), file(std::m
|
||||
NAX::NAX(VirtualFile file_, std::array<u8, 0x10> nca_id)
|
||||
: header(std::make_unique<NAXHeader>()), file(std::move(file_)) {
|
||||
Core::Crypto::SHA256Hash hash{};
|
||||
mbedtls_sha256(nca_id.data(), nca_id.size(), hash.data(), 0);
|
||||
mbedtls_sha256_ret(nca_id.data(), nca_id.size(), hash.data(), 0);
|
||||
status = Parse(fmt::format("/registered/000000{:02X}/{}.nca", hash[0],
|
||||
Common::HexToString(nca_id, false)));
|
||||
}
|
||||
@@ -93,8 +93,7 @@ Loader::ResultStatus NAX::Parse(std::string_view path) {
|
||||
std::size_t i = 0;
|
||||
for (; i < sd_keys.size(); ++i) {
|
||||
std::array<Core::Crypto::Key128, 2> nax_keys{};
|
||||
if (!CalculateHMAC256(nax_keys.data(), sd_keys[i].data(), 0x10, std::string(path).c_str(),
|
||||
path.size())) {
|
||||
if (!CalculateHMAC256(nax_keys.data(), sd_keys[i].data(), 0x10, path.data(), path.size())) {
|
||||
return Loader::ResultStatus::ErrorNAXKeyHMACFailed;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,8 +58,7 @@ SharedPtr<WritableEvent> HLERequestContext::SleepClientThread(
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
if (!writable_event) {
|
||||
// Create event if not provided
|
||||
const auto pair = WritableEvent::CreateEventPair(kernel, ResetType::Automatic,
|
||||
"HLE Pause Event: " + reason);
|
||||
const auto pair = WritableEvent::CreateEventPair(kernel, "HLE Pause Event: " + reason);
|
||||
writable_event = pair.writable;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,11 +32,6 @@ enum class HandleType : u32 {
|
||||
ServerSession,
|
||||
};
|
||||
|
||||
enum class ResetType {
|
||||
Automatic, ///< Reset automatically on object acquisition
|
||||
Manual, ///< Never reset automatically
|
||||
};
|
||||
|
||||
class Object : NonCopyable {
|
||||
public:
|
||||
explicit Object(KernelCore& kernel);
|
||||
|
||||
@@ -20,15 +20,13 @@ bool ReadableEvent::ShouldWait(const Thread* thread) const {
|
||||
|
||||
void ReadableEvent::Acquire(Thread* thread) {
|
||||
ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
|
||||
|
||||
if (reset_type == ResetType::Automatic) {
|
||||
signaled = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ReadableEvent::Signal() {
|
||||
signaled = true;
|
||||
WakeupAllWaitingThreads();
|
||||
if (!signaled) {
|
||||
signaled = true;
|
||||
WakeupAllWaitingThreads();
|
||||
};
|
||||
}
|
||||
|
||||
void ReadableEvent::Clear() {
|
||||
|
||||
@@ -27,10 +27,6 @@ public:
|
||||
return name;
|
||||
}
|
||||
|
||||
ResetType GetResetType() const {
|
||||
return reset_type;
|
||||
}
|
||||
|
||||
static constexpr HandleType HANDLE_TYPE = HandleType::ReadableEvent;
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
@@ -55,8 +51,7 @@ private:
|
||||
|
||||
void Signal();
|
||||
|
||||
ResetType reset_type;
|
||||
bool signaled;
|
||||
bool signaled{};
|
||||
|
||||
std::string name; ///< Name of event (optional)
|
||||
};
|
||||
|
||||
@@ -2099,7 +2099,7 @@ static ResultCode CreateEvent(Core::System& system, Handle* write_handle, Handle
|
||||
|
||||
auto& kernel = system.Kernel();
|
||||
const auto [readable_event, writable_event] =
|
||||
WritableEvent::CreateEventPair(kernel, ResetType::Manual, "CreateEvent");
|
||||
WritableEvent::CreateEventPair(kernel, "CreateEvent");
|
||||
|
||||
HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable();
|
||||
|
||||
|
||||
@@ -15,8 +15,7 @@ namespace Kernel {
|
||||
WritableEvent::WritableEvent(KernelCore& kernel) : Object{kernel} {}
|
||||
WritableEvent::~WritableEvent() = default;
|
||||
|
||||
EventPair WritableEvent::CreateEventPair(KernelCore& kernel, ResetType reset_type,
|
||||
std::string name) {
|
||||
EventPair WritableEvent::CreateEventPair(KernelCore& kernel, std::string name) {
|
||||
SharedPtr<WritableEvent> writable_event(new WritableEvent(kernel));
|
||||
SharedPtr<ReadableEvent> readable_event(new ReadableEvent(kernel));
|
||||
|
||||
@@ -24,7 +23,6 @@ EventPair WritableEvent::CreateEventPair(KernelCore& kernel, ResetType reset_typ
|
||||
writable_event->readable = readable_event;
|
||||
readable_event->name = name + ":Readable";
|
||||
readable_event->signaled = false;
|
||||
readable_event->reset_type = reset_type;
|
||||
|
||||
return {std::move(readable_event), std::move(writable_event)};
|
||||
}
|
||||
@@ -33,10 +31,6 @@ SharedPtr<ReadableEvent> WritableEvent::GetReadableEvent() const {
|
||||
return readable;
|
||||
}
|
||||
|
||||
ResetType WritableEvent::GetResetType() const {
|
||||
return readable->reset_type;
|
||||
}
|
||||
|
||||
void WritableEvent::Signal() {
|
||||
readable->Signal();
|
||||
}
|
||||
|
||||
@@ -24,11 +24,9 @@ public:
|
||||
/**
|
||||
* Creates an event
|
||||
* @param kernel The kernel instance to create this event under.
|
||||
* @param reset_type ResetType describing how to create event
|
||||
* @param name Optional name of event
|
||||
*/
|
||||
static EventPair CreateEventPair(KernelCore& kernel, ResetType reset_type,
|
||||
std::string name = "Unknown");
|
||||
static EventPair CreateEventPair(KernelCore& kernel, std::string name = "Unknown");
|
||||
|
||||
std::string GetTypeName() const override {
|
||||
return "WritableEvent";
|
||||
@@ -44,8 +42,6 @@ public:
|
||||
|
||||
SharedPtr<ReadableEvent> GetReadableEvent() const;
|
||||
|
||||
ResetType GetResetType() const;
|
||||
|
||||
void Signal();
|
||||
void Clear();
|
||||
bool IsSignaled() const;
|
||||
|
||||
@@ -289,8 +289,8 @@ ISelfController::ISelfController(Core::System& system,
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = system.Kernel();
|
||||
launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual,
|
||||
"ISelfController:LaunchableEvent");
|
||||
launchable_event =
|
||||
Kernel::WritableEvent::CreateEventPair(kernel, "ISelfController:LaunchableEvent");
|
||||
|
||||
// This event is created by AM on the first time GetAccumulatedSuspendedTickChangedEvent() is
|
||||
// called. Yuzu can just create it unconditionally, since it doesn't need to support multiple
|
||||
@@ -298,7 +298,7 @@ ISelfController::ISelfController(Core::System& system,
|
||||
// suspended if the event has previously been created by a call to
|
||||
// GetAccumulatedSuspendedTickChangedEvent.
|
||||
accumulated_suspended_tick_changed_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::Manual, "ISelfController:AccumulatedSuspendedTickChangedEvent");
|
||||
kernel, "ISelfController:AccumulatedSuspendedTickChangedEvent");
|
||||
accumulated_suspended_tick_changed_event.writable->Signal();
|
||||
}
|
||||
|
||||
@@ -523,10 +523,10 @@ void ISelfController::GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequest
|
||||
}
|
||||
|
||||
AppletMessageQueue::AppletMessageQueue(Kernel::KernelCore& kernel) {
|
||||
on_new_message = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual,
|
||||
"AMMessageQueue:OnMessageRecieved");
|
||||
on_operation_mode_changed = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::Automatic, "AMMessageQueue:OperationModeChanged");
|
||||
on_new_message =
|
||||
Kernel::WritableEvent::CreateEventPair(kernel, "AMMessageQueue:OnMessageRecieved");
|
||||
on_operation_mode_changed =
|
||||
Kernel::WritableEvent::CreateEventPair(kernel, "AMMessageQueue:OperationModeChanged");
|
||||
}
|
||||
|
||||
AppletMessageQueue::~AppletMessageQueue() = default;
|
||||
@@ -1077,6 +1077,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
|
||||
{101, &IApplicationFunctions::SetApplicationCopyrightImage, "SetApplicationCopyrightImage"},
|
||||
{102, &IApplicationFunctions::SetApplicationCopyrightVisibility, "SetApplicationCopyrightVisibility"},
|
||||
{110, nullptr, "QueryApplicationPlayStatistics"},
|
||||
{111, &IApplicationFunctions::QueryApplicationPlayStatisticsByUid, "QueryApplicationPlayStatisticsByUid"},
|
||||
{120, nullptr, "ExecuteProgram"},
|
||||
{121, nullptr, "ClearUserChannel"},
|
||||
{122, nullptr, "UnpopToUserChannel"},
|
||||
@@ -1091,7 +1092,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
|
||||
|
||||
auto& kernel = system.Kernel();
|
||||
gpu_error_detected_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::Manual, "IApplicationFunctions:GpuErrorDetectedSystemEvent");
|
||||
kernel, "IApplicationFunctions:GpuErrorDetectedSystemEvent");
|
||||
}
|
||||
|
||||
IApplicationFunctions::~IApplicationFunctions() = default;
|
||||
@@ -1335,12 +1336,16 @@ void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
void IApplicationFunctions::ExtendSaveData(Kernel::HLERequestContext& ctx) {
|
||||
struct Parameters {
|
||||
FileSys::SaveDataType type;
|
||||
u128 user_id;
|
||||
u64 new_normal_size;
|
||||
u64 new_journal_size;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 40);
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto type{rp.PopRaw<FileSys::SaveDataType>()};
|
||||
rp.Skip(1, false);
|
||||
const auto user_id{rp.PopRaw<u128>()};
|
||||
const auto new_normal_size{rp.PopRaw<u64>()};
|
||||
const auto new_journal_size{rp.PopRaw<u64>()};
|
||||
const auto [type, user_id, new_normal_size, new_journal_size] = rp.PopRaw<Parameters>();
|
||||
|
||||
LOG_DEBUG(Service_AM,
|
||||
"called with type={:02X}, user_id={:016X}{:016X}, new_normal={:016X}, "
|
||||
@@ -1359,10 +1364,14 @@ void IApplicationFunctions::ExtendSaveData(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) {
|
||||
struct Parameters {
|
||||
FileSys::SaveDataType type;
|
||||
u128 user_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 24);
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto type{rp.PopRaw<FileSys::SaveDataType>()};
|
||||
rp.Skip(1, false);
|
||||
const auto user_id{rp.PopRaw<u128>()};
|
||||
const auto [type, user_id] = rp.PopRaw<Parameters>();
|
||||
|
||||
LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", static_cast<u8>(type),
|
||||
user_id[1], user_id[0]);
|
||||
@@ -1384,6 +1393,14 @@ void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(Kernel::HLERequestCon
|
||||
rb.PushCopyObjects(gpu_error_detected_event.readable);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(0);
|
||||
}
|
||||
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager,
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system) {
|
||||
auto message_queue = std::make_shared<AppletMessageQueue>(system.Kernel());
|
||||
|
||||
@@ -256,6 +256,7 @@ private:
|
||||
void SetApplicationCopyrightImage(Kernel::HLERequestContext& ctx);
|
||||
void SetApplicationCopyrightVisibility(Kernel::HLERequestContext& ctx);
|
||||
void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx);
|
||||
void QueryApplicationPlayStatisticsByUid(Kernel::HLERequestContext& ctx);
|
||||
|
||||
bool launch_popped_application_specific = false;
|
||||
bool launch_popped_account_preselect = false;
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
namespace Service::AM::Applets {
|
||||
|
||||
AppletDataBroker::AppletDataBroker(Kernel::KernelCore& kernel) {
|
||||
state_changed_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::Manual, "ILibraryAppletAccessor:StateChangedEvent");
|
||||
pop_out_data_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::Manual, "ILibraryAppletAccessor:PopDataOutEvent");
|
||||
state_changed_event =
|
||||
Kernel::WritableEvent::CreateEventPair(kernel, "ILibraryAppletAccessor:StateChangedEvent");
|
||||
pop_out_data_event =
|
||||
Kernel::WritableEvent::CreateEventPair(kernel, "ILibraryAppletAccessor:PopDataOutEvent");
|
||||
pop_interactive_out_data_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::Manual, "ILibraryAppletAccessor:PopInteractiveDataOutEvent");
|
||||
kernel, "ILibraryAppletAccessor:PopInteractiveDataOutEvent");
|
||||
}
|
||||
|
||||
AppletDataBroker::~AppletDataBroker() = default;
|
||||
|
||||
@@ -67,8 +67,8 @@ AOC_U::AOC_U(Core::System& system)
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = system.Kernel();
|
||||
aoc_change_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual,
|
||||
"GetAddOnContentListChanged:Event");
|
||||
aoc_change_event =
|
||||
Kernel::WritableEvent::CreateEventPair(kernel, "GetAddOnContentListChanged:Event");
|
||||
}
|
||||
|
||||
AOC_U::~AOC_U() = default;
|
||||
|
||||
@@ -65,8 +65,8 @@ public:
|
||||
RegisterHandlers(functions);
|
||||
|
||||
// This is the event handle used to check if the audio buffer was released
|
||||
buffer_event = Kernel::WritableEvent::CreateEventPair(
|
||||
system.Kernel(), Kernel::ResetType::Manual, "IAudioOutBufferReleased");
|
||||
buffer_event =
|
||||
Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioOutBufferReleased");
|
||||
|
||||
stream = audio_core.OpenStream(system.CoreTiming(), audio_params.sample_rate,
|
||||
audio_params.channel_count, std::move(unique_name),
|
||||
|
||||
@@ -47,8 +47,8 @@ public:
|
||||
// clang-format on
|
||||
RegisterHandlers(functions);
|
||||
|
||||
system_event = Kernel::WritableEvent::CreateEventPair(
|
||||
system.Kernel(), Kernel::ResetType::Manual, "IAudioRenderer:SystemEvent");
|
||||
system_event =
|
||||
Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioRenderer:SystemEvent");
|
||||
renderer = std::make_unique<AudioCore::AudioRenderer>(
|
||||
system.CoreTiming(), audren_params, system_event.writable, instance_number);
|
||||
}
|
||||
@@ -180,17 +180,17 @@ public:
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = system.Kernel();
|
||||
buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic,
|
||||
"IAudioOutBufferReleasedEvent");
|
||||
buffer_event =
|
||||
Kernel::WritableEvent::CreateEventPair(kernel, "IAudioOutBufferReleasedEvent");
|
||||
|
||||
// Should be similar to audio_output_device_switch_event
|
||||
audio_input_device_switch_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::Automatic, "IAudioDevice:AudioInputDeviceSwitchedEvent");
|
||||
kernel, "IAudioDevice:AudioInputDeviceSwitchedEvent");
|
||||
|
||||
// Should only be signalled when an audio output device has been changed, example: speaker
|
||||
// to headset
|
||||
audio_output_device_switch_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::Automatic, "IAudioDevice:AudioOutputDeviceSwitchedEvent");
|
||||
kernel, "IAudioDevice:AudioOutputDeviceSwitchedEvent");
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -13,8 +13,7 @@ namespace Service::BCAT {
|
||||
ProgressServiceBackend::ProgressServiceBackend(Kernel::KernelCore& kernel,
|
||||
std::string_view event_name) {
|
||||
event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::Automatic,
|
||||
std::string("ProgressServiceBackend:UpdateEvent:").append(event_name));
|
||||
kernel, std::string("ProgressServiceBackend:UpdateEvent:").append(event_name));
|
||||
}
|
||||
|
||||
Kernel::SharedPtr<Kernel::ReadableEvent> ProgressServiceBackend::GetEvent() const {
|
||||
|
||||
@@ -255,7 +255,7 @@ private:
|
||||
using Digest = std::array<u8, 0x20>;
|
||||
static Digest DigestFile(std::vector<u8> bytes) {
|
||||
Digest out{};
|
||||
mbedtls_sha256(bytes.data(), bytes.size(), out.data(), 0);
|
||||
mbedtls_sha256_ret(bytes.data(), bytes.size(), out.data(), 0);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ u64 GetCurrentBuildID(const Core::System::CurrentBuildProcessID& id) {
|
||||
BCATDigest DigestFile(const FileSys::VirtualFile& file) {
|
||||
BCATDigest out{};
|
||||
const auto bytes = file->ReadAllBytes();
|
||||
mbedtls_md5(bytes.data(), bytes.size(), out.data());
|
||||
mbedtls_md5_ret(bytes.data(), bytes.size(), out.data());
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,8 +34,7 @@ public:
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = system.Kernel();
|
||||
register_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::Automatic, "BT:RegisterEvent");
|
||||
register_event = Kernel::WritableEvent::CreateEventPair(kernel, "BT:RegisterEvent");
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -57,14 +57,12 @@ public:
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = system.Kernel();
|
||||
scan_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic,
|
||||
"IBtmUserCore:ScanEvent");
|
||||
connection_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::Automatic, "IBtmUserCore:ConnectionEvent");
|
||||
service_discovery = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::Automatic, "IBtmUserCore:Discovery");
|
||||
config_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic,
|
||||
"IBtmUserCore:ConfigEvent");
|
||||
scan_event = Kernel::WritableEvent::CreateEventPair(kernel, "IBtmUserCore:ScanEvent");
|
||||
connection_event =
|
||||
Kernel::WritableEvent::CreateEventPair(kernel, "IBtmUserCore:ConnectionEvent");
|
||||
service_discovery =
|
||||
Kernel::WritableEvent::CreateEventPair(kernel, "IBtmUserCore:Discovery");
|
||||
config_event = Kernel::WritableEvent::CreateEventPair(kernel, "IBtmUserCore:ConfigEvent");
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -162,7 +162,7 @@ public:
|
||||
RegisterHandlers(functions);
|
||||
|
||||
notification_event = Kernel::WritableEvent::CreateEventPair(
|
||||
system.Kernel(), Kernel::ResetType::Manual, "INotificationService:NotifyEvent");
|
||||
system.Kernel(), "INotificationService:NotifyEvent");
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -174,7 +174,7 @@ void Controller_NPad::OnInit() {
|
||||
auto& kernel = system.Kernel();
|
||||
for (std::size_t i = 0; i < styleset_changed_events.size(); i++) {
|
||||
styleset_changed_events[i] = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::Manual, fmt::format("npad:NpadStyleSetChanged_{}", i));
|
||||
kernel, fmt::format("npad:NpadStyleSetChanged_{}", i));
|
||||
}
|
||||
|
||||
if (!IsControllerActivated()) {
|
||||
|
||||
@@ -294,7 +294,7 @@ public:
|
||||
Memory::ReadBlock(nro_address, nro_data.data(), nro_size);
|
||||
|
||||
SHA256Hash hash{};
|
||||
mbedtls_sha256(nro_data.data(), nro_data.size(), hash.data(), 0);
|
||||
mbedtls_sha256_ret(nro_data.data(), nro_data.size(), hash.data(), 0);
|
||||
|
||||
// NRO Hash is already loaded
|
||||
if (std::any_of(nro.begin(), nro.end(), [&hash](const std::pair<VAddr, NROInfo>& info) {
|
||||
|
||||
@@ -26,8 +26,7 @@ constexpr ResultCode ERR_NO_APPLICATION_AREA(ErrorModule::NFP, 152);
|
||||
Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name)
|
||||
: ServiceFramework(name), module(std::move(module)), system(system) {
|
||||
auto& kernel = system.Kernel();
|
||||
nfc_tag_load = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic,
|
||||
"IUser:NFCTagDetected");
|
||||
nfc_tag_load = Kernel::WritableEvent::CreateEventPair(kernel, "IUser:NFCTagDetected");
|
||||
}
|
||||
|
||||
Module::Interface::~Interface() = default;
|
||||
@@ -66,10 +65,9 @@ public:
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = system.Kernel();
|
||||
deactivate_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::Automatic, "IUser:DeactivateEvent");
|
||||
availability_change_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::Automatic, "IUser:AvailabilityChangeEvent");
|
||||
deactivate_event = Kernel::WritableEvent::CreateEventPair(kernel, "IUser:DeactivateEvent");
|
||||
availability_change_event =
|
||||
Kernel::WritableEvent::CreateEventPair(kernel, "IUser:AvailabilityChangeEvent");
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -69,10 +69,8 @@ public:
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = system.Kernel();
|
||||
event1 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic,
|
||||
"IRequest:Event1");
|
||||
event2 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic,
|
||||
"IRequest:Event2");
|
||||
event1 = Kernel::WritableEvent::CreateEventPair(kernel, "IRequest:Event1");
|
||||
event2 = Kernel::WritableEvent::CreateEventPair(kernel, "IRequest:Event2");
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -141,8 +141,7 @@ public:
|
||||
|
||||
auto& kernel = system.Kernel();
|
||||
finished_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::Automatic,
|
||||
"IEnsureNetworkClockAvailabilityService:FinishEvent");
|
||||
kernel, "IEnsureNetworkClockAvailabilityService:FinishEvent");
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -40,8 +40,7 @@ Module::Module(Core::System& system) {
|
||||
auto& kernel = system.Kernel();
|
||||
for (u32 i = 0; i < MaxNvEvents; i++) {
|
||||
std::string event_label = fmt::format("NVDRV::NvEvent_{}", i);
|
||||
events_interface.events[i] =
|
||||
Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual, event_label);
|
||||
events_interface.events[i] = Kernel::WritableEvent::CreateEventPair(kernel, event_label);
|
||||
events_interface.status[i] = EventState::Free;
|
||||
events_interface.registered[i] = false;
|
||||
}
|
||||
|
||||
@@ -16,8 +16,7 @@ namespace Service::NVFlinger {
|
||||
|
||||
BufferQueue::BufferQueue(Kernel::KernelCore& kernel, u32 id, u64 layer_id)
|
||||
: id(id), layer_id(layer_id) {
|
||||
buffer_wait_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual,
|
||||
"BufferQueue NativeHandle");
|
||||
buffer_wait_event = Kernel::WritableEvent::CreateEventPair(kernel, "BufferQueue NativeHandle");
|
||||
}
|
||||
|
||||
BufferQueue::~BufferQueue() = default;
|
||||
|
||||
@@ -17,8 +17,8 @@ namespace Service::VI {
|
||||
|
||||
Display::Display(u64 id, std::string name, Core::System& system) : id{id}, name{std::move(name)} {
|
||||
auto& kernel = system.Kernel();
|
||||
vsync_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual,
|
||||
fmt::format("Display VSync Event {}", id));
|
||||
vsync_event =
|
||||
Kernel::WritableEvent::CreateEventPair(kernel, fmt::format("Display VSync Event {}", id));
|
||||
}
|
||||
|
||||
Display::~Display() = default;
|
||||
|
||||
@@ -180,3 +180,9 @@ target_link_libraries(video_core PRIVATE glad)
|
||||
if (ENABLE_VULKAN)
|
||||
target_link_libraries(video_core PRIVATE sirit)
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
target_compile_options(video_core PRIVATE /we4267)
|
||||
else()
|
||||
target_compile_options(video_core PRIVATE -Werror=conversion -Wno-error=sign-conversion)
|
||||
endif()
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/icl/interval_map.hpp>
|
||||
#include <boost/icl/interval_set.hpp>
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/core.h"
|
||||
@@ -30,7 +34,7 @@ public:
|
||||
using BufferInfo = std::pair<const TBufferType*, u64>;
|
||||
|
||||
BufferInfo UploadMemory(GPUVAddr gpu_addr, std::size_t size, std::size_t alignment = 4,
|
||||
bool is_written = false) {
|
||||
bool is_written = false, bool use_fast_cbuf = false) {
|
||||
std::lock_guard lock{mutex};
|
||||
|
||||
auto& memory_manager = system.GPU().MemoryManager();
|
||||
@@ -43,9 +47,13 @@ public:
|
||||
// Cache management is a big overhead, so only cache entries with a given size.
|
||||
// TODO: Figure out which size is the best for given games.
|
||||
constexpr std::size_t max_stream_size = 0x800;
|
||||
if (size < max_stream_size) {
|
||||
if (use_fast_cbuf || size < max_stream_size) {
|
||||
if (!is_written && !IsRegionWritten(cache_addr, cache_addr + size - 1)) {
|
||||
return StreamBufferUpload(host_ptr, size, alignment);
|
||||
if (use_fast_cbuf) {
|
||||
return ConstBufferUpload(host_ptr, size);
|
||||
} else {
|
||||
return StreamBufferUpload(host_ptr, size, alignment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,6 +160,10 @@ protected:
|
||||
virtual void CopyBlock(const TBuffer& src, const TBuffer& dst, std::size_t src_offset,
|
||||
std::size_t dst_offset, std::size_t size) = 0;
|
||||
|
||||
virtual BufferInfo ConstBufferUpload(const void* raw_pointer, std::size_t size) {
|
||||
return {};
|
||||
}
|
||||
|
||||
/// Register an object into the cache
|
||||
void Register(const MapInterval& new_map, bool inherit_written = false) {
|
||||
const CacheAddr cache_ptr = new_map->GetStart();
|
||||
|
||||
@@ -261,7 +261,8 @@ void Maxwell3D::CallMacroMethod(u32 method, std::size_t num_parameters, const u3
|
||||
executing_macro = 0;
|
||||
|
||||
// Lookup the macro offset
|
||||
const u32 entry = ((method - MacroRegistersStart) >> 1) % macro_positions.size();
|
||||
const u32 entry =
|
||||
((method - MacroRegistersStart) >> 1) % static_cast<u32>(macro_positions.size());
|
||||
|
||||
// Execute the current macro.
|
||||
macro_interpreter.Execute(macro_positions[entry], num_parameters, parameters);
|
||||
|
||||
@@ -615,6 +615,14 @@ union Instruction {
|
||||
BitField<34, 13, u64> mask_imm;
|
||||
} shfl;
|
||||
|
||||
union {
|
||||
BitField<44, 1, u64> ftz;
|
||||
BitField<39, 2, u64> tab5cb8_2;
|
||||
BitField<38, 1, u64> ndv;
|
||||
BitField<47, 1, u64> cc;
|
||||
BitField<28, 8, u64> swizzle;
|
||||
} fswzadd;
|
||||
|
||||
union {
|
||||
BitField<8, 8, Register> gpr;
|
||||
BitField<20, 24, s64> offset;
|
||||
@@ -1478,7 +1486,8 @@ union Instruction {
|
||||
u32 value = static_cast<u32>(target);
|
||||
// The branch offset is relative to the next instruction and is stored in bytes, so
|
||||
// divide it by the size of an instruction and add 1 to it.
|
||||
return static_cast<s32>((value ^ mask) - mask) / sizeof(Instruction) + 1;
|
||||
return static_cast<s32>((value ^ mask) - mask) / static_cast<s32>(sizeof(Instruction)) +
|
||||
1;
|
||||
}
|
||||
} bra;
|
||||
|
||||
@@ -1492,7 +1501,8 @@ union Instruction {
|
||||
u32 value = static_cast<u32>(target);
|
||||
// The branch offset is relative to the next instruction and is stored in bytes, so
|
||||
// divide it by the size of an instruction and add 1 to it.
|
||||
return static_cast<s32>((value ^ mask) - mask) / sizeof(Instruction) + 1;
|
||||
return static_cast<s32>((value ^ mask) - mask) / static_cast<s32>(sizeof(Instruction)) +
|
||||
1;
|
||||
}
|
||||
} brx;
|
||||
|
||||
@@ -1590,6 +1600,7 @@ public:
|
||||
DEPBAR,
|
||||
VOTE,
|
||||
SHFL,
|
||||
FSWZADD,
|
||||
BFE_C,
|
||||
BFE_R,
|
||||
BFE_IMM,
|
||||
@@ -1851,11 +1862,11 @@ private:
|
||||
const std::size_t bit_position = opcode_bitsize - i - 1;
|
||||
switch (bitstring[i]) {
|
||||
case '0':
|
||||
mask |= 1 << bit_position;
|
||||
mask |= static_cast<u16>(1U << bit_position);
|
||||
break;
|
||||
case '1':
|
||||
expect |= 1 << bit_position;
|
||||
mask |= 1 << bit_position;
|
||||
expect |= static_cast<u16>(1U << bit_position);
|
||||
mask |= static_cast<u16>(1U << bit_position);
|
||||
break;
|
||||
default:
|
||||
// Ignore
|
||||
@@ -1888,6 +1899,7 @@ private:
|
||||
INST("1111000011110---", Id::DEPBAR, Type::Synch, "DEPBAR"),
|
||||
INST("0101000011011---", Id::VOTE, Type::Warp, "VOTE"),
|
||||
INST("1110111100010---", Id::SHFL, Type::Warp, "SHFL"),
|
||||
INST("0101000011111---", Id::FSWZADD, Type::Warp, "FSWZADD"),
|
||||
INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"),
|
||||
INST("1110111101001---", Id::LD_S, Type::Memory, "LD_S"),
|
||||
INST("1110111101000---", Id::LD_L, Type::Memory, "LD_L"),
|
||||
|
||||
@@ -8,13 +8,17 @@
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/microprofile.h"
|
||||
#include "video_core/engines/maxwell_3d.h"
|
||||
#include "video_core/rasterizer_interface.h"
|
||||
#include "video_core/renderer_opengl/gl_buffer_cache.h"
|
||||
#include "video_core/renderer_opengl/gl_device.h"
|
||||
#include "video_core/renderer_opengl/gl_rasterizer.h"
|
||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
||||
|
||||
MICROPROFILE_DEFINE(OpenGL_Buffer_Download, "OpenGL", "Buffer Download", MP_RGB(192, 192, 128));
|
||||
|
||||
CachedBufferBlock::CachedBufferBlock(CacheAddr cache_addr, const std::size_t size)
|
||||
@@ -26,11 +30,22 @@ CachedBufferBlock::CachedBufferBlock(CacheAddr cache_addr, const std::size_t siz
|
||||
CachedBufferBlock::~CachedBufferBlock() = default;
|
||||
|
||||
OGLBufferCache::OGLBufferCache(RasterizerOpenGL& rasterizer, Core::System& system,
|
||||
std::size_t stream_size)
|
||||
: VideoCommon::BufferCache<Buffer, GLuint, OGLStreamBuffer>{
|
||||
rasterizer, system, std::make_unique<OGLStreamBuffer>(stream_size, true)} {}
|
||||
const Device& device, std::size_t stream_size)
|
||||
: GenericBufferCache{rasterizer, system, std::make_unique<OGLStreamBuffer>(stream_size, true)} {
|
||||
if (!device.HasFastBufferSubData()) {
|
||||
return;
|
||||
}
|
||||
|
||||
OGLBufferCache::~OGLBufferCache() = default;
|
||||
static constexpr auto size = static_cast<GLsizeiptr>(Maxwell::MaxConstBufferSize);
|
||||
glCreateBuffers(static_cast<GLsizei>(std::size(cbufs)), std::data(cbufs));
|
||||
for (const GLuint cbuf : cbufs) {
|
||||
glNamedBufferData(cbuf, size, nullptr, GL_STREAM_DRAW);
|
||||
}
|
||||
}
|
||||
|
||||
OGLBufferCache::~OGLBufferCache() {
|
||||
glDeleteBuffers(static_cast<GLsizei>(std::size(cbufs)), std::data(cbufs));
|
||||
}
|
||||
|
||||
Buffer OGLBufferCache::CreateBlock(CacheAddr cache_addr, std::size_t size) {
|
||||
return std::make_shared<CachedBufferBlock>(cache_addr, size);
|
||||
@@ -69,4 +84,12 @@ void OGLBufferCache::CopyBlock(const Buffer& src, const Buffer& dst, std::size_t
|
||||
static_cast<GLsizeiptr>(size));
|
||||
}
|
||||
|
||||
OGLBufferCache::BufferInfo OGLBufferCache::ConstBufferUpload(const void* raw_pointer,
|
||||
std::size_t size) {
|
||||
DEBUG_ASSERT(cbuf_cursor < std::size(cbufs));
|
||||
const GLuint& cbuf = cbufs[cbuf_cursor++];
|
||||
glNamedBufferSubData(cbuf, 0, static_cast<GLsizeiptr>(size), raw_pointer);
|
||||
return {&cbuf, 0};
|
||||
}
|
||||
|
||||
} // namespace OpenGL
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "video_core/buffer_cache/buffer_cache.h"
|
||||
#include "video_core/engines/maxwell_3d.h"
|
||||
#include "video_core/rasterizer_cache.h"
|
||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
||||
#include "video_core/renderer_opengl/gl_stream_buffer.h"
|
||||
@@ -18,12 +20,14 @@ class System;
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
class Device;
|
||||
class OGLStreamBuffer;
|
||||
class RasterizerOpenGL;
|
||||
|
||||
class CachedBufferBlock;
|
||||
|
||||
using Buffer = std::shared_ptr<CachedBufferBlock>;
|
||||
using GenericBufferCache = VideoCommon::BufferCache<Buffer, GLuint, OGLStreamBuffer>;
|
||||
|
||||
class CachedBufferBlock : public VideoCommon::BufferBlock {
|
||||
public:
|
||||
@@ -38,14 +42,18 @@ private:
|
||||
OGLBuffer gl_buffer{};
|
||||
};
|
||||
|
||||
class OGLBufferCache final : public VideoCommon::BufferCache<Buffer, GLuint, OGLStreamBuffer> {
|
||||
class OGLBufferCache final : public GenericBufferCache {
|
||||
public:
|
||||
explicit OGLBufferCache(RasterizerOpenGL& rasterizer, Core::System& system,
|
||||
std::size_t stream_size);
|
||||
const Device& device, std::size_t stream_size);
|
||||
~OGLBufferCache();
|
||||
|
||||
const GLuint* GetEmptyBuffer(std::size_t) override;
|
||||
|
||||
void Acquire() noexcept {
|
||||
cbuf_cursor = 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
Buffer CreateBlock(CacheAddr cache_addr, std::size_t size) override;
|
||||
|
||||
@@ -61,6 +69,14 @@ protected:
|
||||
|
||||
void CopyBlock(const Buffer& src, const Buffer& dst, std::size_t src_offset,
|
||||
std::size_t dst_offset, std::size_t size) override;
|
||||
|
||||
BufferInfo ConstBufferUpload(const void* raw_pointer, std::size_t size) override;
|
||||
|
||||
private:
|
||||
std::size_t cbuf_cursor = 0;
|
||||
std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::MaxConstBuffers *
|
||||
Tegra::Engines::Maxwell3D::Regs::MaxShaderProgram>
|
||||
cbufs;
|
||||
};
|
||||
|
||||
} // namespace OpenGL
|
||||
|
||||
@@ -51,19 +51,24 @@ bool HasExtension(const std::vector<std::string_view>& images, std::string_view
|
||||
} // Anonymous namespace
|
||||
|
||||
Device::Device() {
|
||||
const std::string_view vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
|
||||
const std::vector extensions = GetExtensions();
|
||||
|
||||
const bool is_nvidia = vendor == "NVIDIA Corporation";
|
||||
|
||||
uniform_buffer_alignment = GetInteger<std::size_t>(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT);
|
||||
shader_storage_alignment = GetInteger<std::size_t>(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT);
|
||||
max_vertex_attributes = GetInteger<u32>(GL_MAX_VERTEX_ATTRIBS);
|
||||
max_varyings = GetInteger<u32>(GL_MAX_VARYING_VECTORS);
|
||||
has_warp_intrinsics = GLAD_GL_NV_gpu_shader5 && GLAD_GL_NV_shader_thread_group &&
|
||||
GLAD_GL_NV_shader_thread_shuffle;
|
||||
has_shader_ballot = GLAD_GL_ARB_shader_ballot;
|
||||
has_vertex_viewport_layer = GLAD_GL_ARB_shader_viewport_layer_array;
|
||||
has_image_load_formatted = HasExtension(extensions, "GL_EXT_shader_image_load_formatted");
|
||||
has_variable_aoffi = TestVariableAoffi();
|
||||
has_component_indexing_bug = TestComponentIndexingBug();
|
||||
has_precise_bug = TestPreciseBug();
|
||||
has_fast_buffer_sub_data = is_nvidia;
|
||||
|
||||
LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", has_variable_aoffi);
|
||||
LOG_INFO(Render_OpenGL, "Renderer_ComponentIndexingBug: {}", has_component_indexing_bug);
|
||||
@@ -75,6 +80,7 @@ Device::Device(std::nullptr_t) {
|
||||
max_vertex_attributes = 16;
|
||||
max_varyings = 15;
|
||||
has_warp_intrinsics = true;
|
||||
has_shader_ballot = true;
|
||||
has_vertex_viewport_layer = true;
|
||||
has_image_load_formatted = true;
|
||||
has_variable_aoffi = true;
|
||||
|
||||
@@ -34,6 +34,10 @@ public:
|
||||
return has_warp_intrinsics;
|
||||
}
|
||||
|
||||
bool HasShaderBallot() const {
|
||||
return has_shader_ballot;
|
||||
}
|
||||
|
||||
bool HasVertexViewportLayer() const {
|
||||
return has_vertex_viewport_layer;
|
||||
}
|
||||
@@ -54,6 +58,10 @@ public:
|
||||
return has_precise_bug;
|
||||
}
|
||||
|
||||
bool HasFastBufferSubData() const {
|
||||
return has_fast_buffer_sub_data;
|
||||
}
|
||||
|
||||
private:
|
||||
static bool TestVariableAoffi();
|
||||
static bool TestComponentIndexingBug();
|
||||
@@ -64,11 +72,13 @@ private:
|
||||
u32 max_vertex_attributes{};
|
||||
u32 max_varyings{};
|
||||
bool has_warp_intrinsics{};
|
||||
bool has_shader_ballot{};
|
||||
bool has_vertex_viewport_layer{};
|
||||
bool has_image_load_formatted{};
|
||||
bool has_variable_aoffi{};
|
||||
bool has_component_indexing_bug{};
|
||||
bool has_precise_bug{};
|
||||
bool has_fast_buffer_sub_data{};
|
||||
};
|
||||
|
||||
} // namespace OpenGL
|
||||
|
||||
@@ -67,7 +67,7 @@ static std::size_t GetConstBufferSize(const Tegra::Engines::ConstBufferInfo& buf
|
||||
RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window,
|
||||
ScreenInfo& info)
|
||||
: texture_cache{system, *this, device}, shader_cache{*this, system, emu_window, device},
|
||||
system{system}, screen_info{info}, buffer_cache{*this, system, STREAM_BUFFER_SIZE} {
|
||||
system{system}, screen_info{info}, buffer_cache{*this, system, device, STREAM_BUFFER_SIZE} {
|
||||
shader_program_manager = std::make_unique<GLShader::ProgramManager>();
|
||||
state.draw.shader_program = 0;
|
||||
state.Apply();
|
||||
@@ -375,7 +375,7 @@ void RasterizerOpenGL::ConfigureFramebuffers() {
|
||||
fbkey.color_attachments[index] = GL_COLOR_ATTACHMENT0 + regs.rt_control.GetMap(index);
|
||||
fbkey.colors[index] = std::move(color_surface);
|
||||
}
|
||||
fbkey.colors_count = regs.rt_control.count;
|
||||
fbkey.colors_count = static_cast<u16>(regs.rt_control.count);
|
||||
|
||||
if (depth_surface) {
|
||||
// Assume that a surface will be written to if it is used as a framebuffer, even if
|
||||
@@ -558,6 +558,8 @@ void RasterizerOpenGL::DrawPrelude() {
|
||||
SyncPolygonOffset();
|
||||
SyncAlphaTest();
|
||||
|
||||
buffer_cache.Acquire();
|
||||
|
||||
// Draw the vertex batch
|
||||
const bool is_indexed = accelerate_draw == AccelDraw::Indexed;
|
||||
|
||||
@@ -879,7 +881,8 @@ void RasterizerOpenGL::SetupConstBuffer(const Tegra::Engines::ConstBufferInfo& b
|
||||
const std::size_t size = Common::AlignUp(GetConstBufferSize(buffer, entry), sizeof(GLvec4));
|
||||
|
||||
const auto alignment = device.GetUniformBufferAlignment();
|
||||
const auto [cbuf, offset] = buffer_cache.UploadMemory(buffer.address, size, alignment);
|
||||
const auto [cbuf, offset] = buffer_cache.UploadMemory(buffer.address, size, alignment, false,
|
||||
device.HasFastBufferSubData());
|
||||
bind_ubo_pushbuffer.Push(cbuf, offset, size);
|
||||
}
|
||||
|
||||
|
||||
@@ -275,16 +275,25 @@ CachedProgram BuildShader(const Device& device, u64 unique_identifier, ProgramTy
|
||||
std::string source = fmt::format(R"(// {}
|
||||
#version 430 core
|
||||
#extension GL_ARB_separate_shader_objects : enable
|
||||
#extension GL_ARB_shader_viewport_layer_array : enable
|
||||
#extension GL_EXT_shader_image_load_formatted : enable
|
||||
#extension GL_NV_gpu_shader5 : enable
|
||||
#extension GL_NV_shader_thread_group : enable
|
||||
#extension GL_NV_shader_thread_shuffle : enable
|
||||
)",
|
||||
GetShaderId(unique_identifier, program_type));
|
||||
if (is_compute) {
|
||||
source += "#extension GL_ARB_compute_variable_group_size : require\n";
|
||||
}
|
||||
if (device.HasShaderBallot()) {
|
||||
source += "#extension GL_ARB_shader_ballot : require\n";
|
||||
}
|
||||
if (device.HasVertexViewportLayer()) {
|
||||
source += "#extension GL_ARB_shader_viewport_layer_array : require\n";
|
||||
}
|
||||
if (device.HasImageLoadFormatted()) {
|
||||
source += "#extension GL_EXT_shader_image_load_formatted : require\n";
|
||||
}
|
||||
if (device.HasWarpIntrinsics()) {
|
||||
source += "#extension GL_NV_gpu_shader5 : require\n"
|
||||
"#extension GL_NV_shader_thread_group : require\n"
|
||||
"#extension GL_NV_shader_thread_shuffle : require\n";
|
||||
}
|
||||
source += '\n';
|
||||
|
||||
if (!is_compute) {
|
||||
@@ -394,7 +403,8 @@ Shader CachedShader::CreateStageFromMemory(const ShaderParameters& params,
|
||||
params.disk_cache.SaveRaw(ShaderDiskCacheRaw(
|
||||
params.unique_identifier, GetProgramType(program_type), program_code, program_code_b));
|
||||
|
||||
ConstBufferLocker locker(GetEnginesShaderType(GetProgramType(program_type)));
|
||||
ConstBufferLocker locker(GetEnginesShaderType(GetProgramType(program_type)),
|
||||
params.system.GPU().Maxwell3D());
|
||||
const ShaderIR ir(program_code, STAGE_MAIN_OFFSET, COMPILER_SETTINGS, locker);
|
||||
// TODO(Rodrigo): Handle VertexA shaders
|
||||
// std::optional<ShaderIR> ir_b;
|
||||
@@ -410,7 +420,8 @@ Shader CachedShader::CreateKernelFromMemory(const ShaderParameters& params, Prog
|
||||
params.disk_cache.SaveRaw(
|
||||
ShaderDiskCacheRaw(params.unique_identifier, ProgramType::Compute, code));
|
||||
|
||||
ConstBufferLocker locker(Tegra::Engines::ShaderType::Compute);
|
||||
ConstBufferLocker locker(Tegra::Engines::ShaderType::Compute,
|
||||
params.system.GPU().KeplerCompute());
|
||||
const ShaderIR ir(code, KERNEL_MAIN_OFFSET, COMPILER_SETTINGS, locker);
|
||||
return std::shared_ptr<CachedShader>(new CachedShader(
|
||||
params, ProgramType::Compute, GLShader::GetEntries(ir), std::move(code), {}));
|
||||
|
||||
@@ -1379,6 +1379,26 @@ private:
|
||||
return GenerateUnary(operation, "float", Type::Float, type);
|
||||
}
|
||||
|
||||
Expression FSwizzleAdd(Operation operation) {
|
||||
const std::string op_a = VisitOperand(operation, 0).AsFloat();
|
||||
const std::string op_b = VisitOperand(operation, 1).AsFloat();
|
||||
|
||||
if (!device.HasShaderBallot()) {
|
||||
LOG_ERROR(Render_OpenGL, "Shader ballot is unavailable but required by the shader");
|
||||
return {fmt::format("{} + {}", op_a, op_b), Type::Float};
|
||||
}
|
||||
|
||||
const std::string instr_mask = VisitOperand(operation, 2).AsUint();
|
||||
const std::string mask = code.GenerateTemporary();
|
||||
code.AddLine("uint {} = ({} >> ((gl_SubGroupInvocationARB & 3) << 1)) & 3;", mask,
|
||||
instr_mask);
|
||||
|
||||
const std::string modifier_a = fmt::format("fswzadd_modifiers_a[{}]", mask);
|
||||
const std::string modifier_b = fmt::format("fswzadd_modifiers_b[{}]", mask);
|
||||
return {fmt::format("(({} * {}) + ({} * {}))", op_a, modifier_a, op_b, modifier_b),
|
||||
Type::Float};
|
||||
}
|
||||
|
||||
Expression ICastFloat(Operation operation) {
|
||||
return GenerateUnary(operation, "int", Type::Int, Type::Float);
|
||||
}
|
||||
@@ -1670,7 +1690,7 @@ private:
|
||||
|
||||
const auto type = meta->sampler.IsShadow() ? Type::Float : Type::Int;
|
||||
return {GenerateTexture(operation, "Gather",
|
||||
{TextureArgument{type, meta->component}, TextureAoffi{}}) +
|
||||
{TextureAoffi{}, TextureArgument{type, meta->component}}) +
|
||||
GetSwizzle(meta->element),
|
||||
Type::Float};
|
||||
}
|
||||
@@ -1942,34 +1962,24 @@ private:
|
||||
return Vote(operation, "allThreadsEqualNV");
|
||||
}
|
||||
|
||||
template <const std::string_view& func>
|
||||
Expression Shuffle(Operation operation) {
|
||||
const std::string value = VisitOperand(operation, 0).AsFloat();
|
||||
if (!device.HasWarpIntrinsics()) {
|
||||
LOG_ERROR(Render_OpenGL, "Nvidia shuffle intrinsics are required by this shader");
|
||||
// On a "single-thread" device we are either on the same thread or out of bounds. Both
|
||||
// cases return the passed value.
|
||||
return {value, Type::Float};
|
||||
Expression ThreadId(Operation operation) {
|
||||
if (!device.HasShaderBallot()) {
|
||||
LOG_ERROR(Render_OpenGL, "Shader ballot is unavailable but required by the shader");
|
||||
return {"0U", Type::Uint};
|
||||
}
|
||||
return {"gl_SubGroupInvocationARB", Type::Uint};
|
||||
}
|
||||
|
||||
Expression ShuffleIndexed(Operation operation) {
|
||||
std::string value = VisitOperand(operation, 0).AsFloat();
|
||||
|
||||
if (!device.HasShaderBallot()) {
|
||||
LOG_ERROR(Render_OpenGL, "Shader ballot is unavailable but required by the shader");
|
||||
return {std::move(value), Type::Float};
|
||||
}
|
||||
|
||||
const std::string index = VisitOperand(operation, 1).AsUint();
|
||||
const std::string width = VisitOperand(operation, 2).AsUint();
|
||||
return {fmt::format("{}({}, {}, {})", func, value, index, width), Type::Float};
|
||||
}
|
||||
|
||||
template <const std::string_view& func>
|
||||
Expression InRangeShuffle(Operation operation) {
|
||||
const std::string index = VisitOperand(operation, 0).AsUint();
|
||||
const std::string width = VisitOperand(operation, 1).AsUint();
|
||||
if (!device.HasWarpIntrinsics()) {
|
||||
// On a "single-thread" device we are only in bounds when the requested index is 0.
|
||||
return {fmt::format("({} == 0U)", index), Type::Bool};
|
||||
}
|
||||
|
||||
const std::string in_range = code.GenerateTemporary();
|
||||
code.AddLine("bool {};", in_range);
|
||||
code.AddLine("{}(0U, {}, {}, {});", func, index, width, in_range);
|
||||
return {in_range, Type::Bool};
|
||||
return {fmt::format("readInvocationARB({}, {})", value, index), Type::Float};
|
||||
}
|
||||
|
||||
struct Func final {
|
||||
@@ -1981,11 +1991,6 @@ private:
|
||||
static constexpr std::string_view Or = "Or";
|
||||
static constexpr std::string_view Xor = "Xor";
|
||||
static constexpr std::string_view Exchange = "Exchange";
|
||||
|
||||
static constexpr std::string_view ShuffleIndexed = "shuffleNV";
|
||||
static constexpr std::string_view ShuffleUp = "shuffleUpNV";
|
||||
static constexpr std::string_view ShuffleDown = "shuffleDownNV";
|
||||
static constexpr std::string_view ShuffleButterfly = "shuffleXorNV";
|
||||
};
|
||||
|
||||
static constexpr std::array operation_decompilers = {
|
||||
@@ -2016,6 +2021,7 @@ private:
|
||||
&GLSLDecompiler::FTrunc,
|
||||
&GLSLDecompiler::FCastInteger<Type::Int>,
|
||||
&GLSLDecompiler::FCastInteger<Type::Uint>,
|
||||
&GLSLDecompiler::FSwizzleAdd,
|
||||
|
||||
&GLSLDecompiler::Add<Type::Int>,
|
||||
&GLSLDecompiler::Mul<Type::Int>,
|
||||
@@ -2151,15 +2157,8 @@ private:
|
||||
&GLSLDecompiler::VoteAny,
|
||||
&GLSLDecompiler::VoteEqual,
|
||||
|
||||
&GLSLDecompiler::Shuffle<Func::ShuffleIndexed>,
|
||||
&GLSLDecompiler::Shuffle<Func::ShuffleUp>,
|
||||
&GLSLDecompiler::Shuffle<Func::ShuffleDown>,
|
||||
&GLSLDecompiler::Shuffle<Func::ShuffleButterfly>,
|
||||
|
||||
&GLSLDecompiler::InRangeShuffle<Func::ShuffleIndexed>,
|
||||
&GLSLDecompiler::InRangeShuffle<Func::ShuffleUp>,
|
||||
&GLSLDecompiler::InRangeShuffle<Func::ShuffleDown>,
|
||||
&GLSLDecompiler::InRangeShuffle<Func::ShuffleButterfly>,
|
||||
&GLSLDecompiler::ThreadId,
|
||||
&GLSLDecompiler::ShuffleIndexed,
|
||||
};
|
||||
static_assert(operation_decompilers.size() == static_cast<std::size_t>(OperationCode::Amount));
|
||||
|
||||
@@ -2492,6 +2491,9 @@ bvec2 HalfFloatNanComparison(bvec2 comparison, vec2 pair1, vec2 pair2) {
|
||||
bvec2 is_nan2 = isnan(pair2);
|
||||
return bvec2(comparison.x || is_nan1.x || is_nan2.x, comparison.y || is_nan1.y || is_nan2.y);
|
||||
}
|
||||
|
||||
const float fswzadd_modifiers_a[] = float[4](-1.0f, 1.0f, -1.0f, 0.0f );
|
||||
const float fswzadd_modifiers_b[] = float[4](-1.0f, -1.0f, 1.0f, -1.0f );
|
||||
)";
|
||||
}
|
||||
|
||||
|
||||
@@ -323,10 +323,12 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x,
|
||||
// (e.g. handheld mode) on a 1920x1080 framebuffer.
|
||||
f32 scale_u = 1.f, scale_v = 1.f;
|
||||
if (framebuffer_crop_rect.GetWidth() > 0) {
|
||||
scale_u = static_cast<f32>(framebuffer_crop_rect.GetWidth()) / screen_info.texture.width;
|
||||
scale_u = static_cast<f32>(framebuffer_crop_rect.GetWidth()) /
|
||||
static_cast<f32>(screen_info.texture.width);
|
||||
}
|
||||
if (framebuffer_crop_rect.GetHeight() > 0) {
|
||||
scale_v = static_cast<f32>(framebuffer_crop_rect.GetHeight()) / screen_info.texture.height;
|
||||
scale_v = static_cast<f32>(framebuffer_crop_rect.GetHeight()) /
|
||||
static_cast<f32>(screen_info.texture.height);
|
||||
}
|
||||
|
||||
std::array<ScreenRectVertex, 4> vertices = {{
|
||||
|
||||
@@ -783,6 +783,11 @@ private:
|
||||
return {};
|
||||
}
|
||||
|
||||
Id FSwizzleAdd(Operation operation) {
|
||||
UNIMPLEMENTED();
|
||||
return {};
|
||||
}
|
||||
|
||||
Id HNegate(Operation operation) {
|
||||
UNIMPLEMENTED();
|
||||
return {};
|
||||
@@ -1195,46 +1200,16 @@ private:
|
||||
return {};
|
||||
}
|
||||
|
||||
Id ThreadId(Operation) {
|
||||
UNIMPLEMENTED();
|
||||
return {};
|
||||
}
|
||||
|
||||
Id ShuffleIndexed(Operation) {
|
||||
UNIMPLEMENTED();
|
||||
return {};
|
||||
}
|
||||
|
||||
Id ShuffleUp(Operation) {
|
||||
UNIMPLEMENTED();
|
||||
return {};
|
||||
}
|
||||
|
||||
Id ShuffleDown(Operation) {
|
||||
UNIMPLEMENTED();
|
||||
return {};
|
||||
}
|
||||
|
||||
Id ShuffleButterfly(Operation) {
|
||||
UNIMPLEMENTED();
|
||||
return {};
|
||||
}
|
||||
|
||||
Id InRangeShuffleIndexed(Operation) {
|
||||
UNIMPLEMENTED();
|
||||
return {};
|
||||
}
|
||||
|
||||
Id InRangeShuffleUp(Operation) {
|
||||
UNIMPLEMENTED();
|
||||
return {};
|
||||
}
|
||||
|
||||
Id InRangeShuffleDown(Operation) {
|
||||
UNIMPLEMENTED();
|
||||
return {};
|
||||
}
|
||||
|
||||
Id InRangeShuffleButterfly(Operation) {
|
||||
UNIMPLEMENTED();
|
||||
return {};
|
||||
}
|
||||
|
||||
Id DeclareBuiltIn(spv::BuiltIn builtin, spv::StorageClass storage, Id type,
|
||||
const std::string& name) {
|
||||
const Id id = OpVariable(type, storage);
|
||||
@@ -1393,6 +1368,7 @@ private:
|
||||
&SPIRVDecompiler::Unary<&Module::OpTrunc, Type::Float>,
|
||||
&SPIRVDecompiler::Unary<&Module::OpConvertSToF, Type::Float, Type::Int>,
|
||||
&SPIRVDecompiler::Unary<&Module::OpConvertUToF, Type::Float, Type::Uint>,
|
||||
&SPIRVDecompiler::FSwizzleAdd,
|
||||
|
||||
&SPIRVDecompiler::Binary<&Module::OpIAdd, Type::Int>,
|
||||
&SPIRVDecompiler::Binary<&Module::OpIMul, Type::Int>,
|
||||
@@ -1528,15 +1504,8 @@ private:
|
||||
&SPIRVDecompiler::VoteAny,
|
||||
&SPIRVDecompiler::VoteEqual,
|
||||
|
||||
&SPIRVDecompiler::ThreadId,
|
||||
&SPIRVDecompiler::ShuffleIndexed,
|
||||
&SPIRVDecompiler::ShuffleUp,
|
||||
&SPIRVDecompiler::ShuffleDown,
|
||||
&SPIRVDecompiler::ShuffleButterfly,
|
||||
|
||||
&SPIRVDecompiler::InRangeShuffleIndexed,
|
||||
&SPIRVDecompiler::InRangeShuffleUp,
|
||||
&SPIRVDecompiler::InRangeShuffleDown,
|
||||
&SPIRVDecompiler::InRangeShuffleButterfly,
|
||||
};
|
||||
static_assert(operation_decompilers.size() == static_cast<std::size_t>(OperationCode::Amount));
|
||||
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
#include "video_core/shader/shader_ir.h"
|
||||
|
||||
namespace VideoCommon::Shader {
|
||||
|
||||
namespace {
|
||||
|
||||
using Tegra::Shader::Instruction;
|
||||
using Tegra::Shader::OpCode;
|
||||
|
||||
@@ -68,15 +70,15 @@ struct CFGRebuildState {
|
||||
const ProgramCode& program_code;
|
||||
ConstBufferLocker& locker;
|
||||
u32 start{};
|
||||
std::vector<BlockInfo> block_info{};
|
||||
std::list<u32> inspect_queries{};
|
||||
std::list<Query> queries{};
|
||||
std::unordered_map<u32, u32> registered{};
|
||||
std::set<u32> labels{};
|
||||
std::map<u32, u32> ssy_labels{};
|
||||
std::map<u32, u32> pbk_labels{};
|
||||
std::unordered_map<u32, BlockStack> stacks{};
|
||||
ASTManager* manager;
|
||||
std::vector<BlockInfo> block_info;
|
||||
std::list<u32> inspect_queries;
|
||||
std::list<Query> queries;
|
||||
std::unordered_map<u32, u32> registered;
|
||||
std::set<u32> labels;
|
||||
std::map<u32, u32> ssy_labels;
|
||||
std::map<u32, u32> pbk_labels;
|
||||
std::unordered_map<u32, BlockStack> stacks;
|
||||
ASTManager* manager{};
|
||||
};
|
||||
|
||||
enum class BlockCollision : u32 { None, Found, Inside };
|
||||
@@ -109,7 +111,7 @@ BlockInfo& CreateBlockInfo(CFGRebuildState& state, u32 start, u32 end) {
|
||||
}
|
||||
|
||||
Pred GetPredicate(u32 index, bool negated) {
|
||||
return static_cast<Pred>(index + (negated ? 8 : 0));
|
||||
return static_cast<Pred>(static_cast<u64>(index) + (negated ? 8ULL : 0ULL));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,15 +138,13 @@ struct BranchIndirectInfo {
|
||||
s32 relative_position{};
|
||||
};
|
||||
|
||||
std::optional<BranchIndirectInfo> TrackBranchIndirectInfo(const CFGRebuildState& state,
|
||||
u32 start_address, u32 current_position) {
|
||||
const u32 shader_start = state.start;
|
||||
u32 pos = current_position;
|
||||
BranchIndirectInfo result{};
|
||||
u64 track_register = 0;
|
||||
struct BufferInfo {
|
||||
u32 index;
|
||||
u32 offset;
|
||||
};
|
||||
|
||||
// Step 0 Get BRX Info
|
||||
const Instruction instr = {state.program_code[pos]};
|
||||
std::optional<std::pair<s32, u64>> GetBRXInfo(const CFGRebuildState& state, u32& pos) {
|
||||
const Instruction instr = state.program_code[pos];
|
||||
const auto opcode = OpCode::Decode(instr);
|
||||
if (opcode->get().GetId() != OpCode::Id::BRX) {
|
||||
return std::nullopt;
|
||||
@@ -152,86 +152,94 @@ std::optional<BranchIndirectInfo> TrackBranchIndirectInfo(const CFGRebuildState&
|
||||
if (instr.brx.constant_buffer != 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
track_register = instr.gpr8.Value();
|
||||
result.relative_position = instr.brx.GetBranchExtend();
|
||||
pos--;
|
||||
bool found_track = false;
|
||||
--pos;
|
||||
return std::make_pair(instr.brx.GetBranchExtend(), instr.gpr8.Value());
|
||||
}
|
||||
|
||||
// Step 1 Track LDC
|
||||
while (pos >= shader_start) {
|
||||
if (IsSchedInstruction(pos, shader_start)) {
|
||||
pos--;
|
||||
continue;
|
||||
}
|
||||
const Instruction instr = {state.program_code[pos]};
|
||||
const auto opcode = OpCode::Decode(instr);
|
||||
if (opcode->get().GetId() == OpCode::Id::LD_C) {
|
||||
if (instr.gpr0.Value() == track_register &&
|
||||
instr.ld_c.type.Value() == Tegra::Shader::UniformType::Single) {
|
||||
result.buffer = instr.cbuf36.index.Value();
|
||||
result.offset = static_cast<u32>(instr.cbuf36.GetOffset());
|
||||
track_register = instr.gpr8.Value();
|
||||
pos--;
|
||||
found_track = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pos--;
|
||||
}
|
||||
|
||||
if (!found_track) {
|
||||
return std::nullopt;
|
||||
}
|
||||
found_track = false;
|
||||
|
||||
// Step 2 Track SHL
|
||||
while (pos >= shader_start) {
|
||||
if (IsSchedInstruction(pos, shader_start)) {
|
||||
pos--;
|
||||
template <typename Result, typename TestCallable, typename PackCallable>
|
||||
// requires std::predicate<TestCallable, Instruction, const OpCode::Matcher&>
|
||||
// requires std::invocable<PackCallable, Instruction, const OpCode::Matcher&>
|
||||
std::optional<Result> TrackInstruction(const CFGRebuildState& state, u32& pos, TestCallable test,
|
||||
PackCallable pack) {
|
||||
for (; pos >= state.start; --pos) {
|
||||
if (IsSchedInstruction(pos, state.start)) {
|
||||
continue;
|
||||
}
|
||||
const Instruction instr = state.program_code[pos];
|
||||
const auto opcode = OpCode::Decode(instr);
|
||||
if (opcode->get().GetId() == OpCode::Id::SHL_IMM) {
|
||||
if (instr.gpr0.Value() == track_register) {
|
||||
track_register = instr.gpr8.Value();
|
||||
pos--;
|
||||
found_track = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pos--;
|
||||
}
|
||||
|
||||
if (!found_track) {
|
||||
return std::nullopt;
|
||||
}
|
||||
found_track = false;
|
||||
|
||||
// Step 3 Track IMNMX
|
||||
while (pos >= shader_start) {
|
||||
if (IsSchedInstruction(pos, shader_start)) {
|
||||
pos--;
|
||||
if (!opcode) {
|
||||
continue;
|
||||
}
|
||||
const Instruction instr = state.program_code[pos];
|
||||
const auto opcode = OpCode::Decode(instr);
|
||||
if (opcode->get().GetId() == OpCode::Id::IMNMX_IMM) {
|
||||
if (instr.gpr0.Value() == track_register) {
|
||||
track_register = instr.gpr8.Value();
|
||||
result.entries = instr.alu.GetSignedImm20_20() + 1;
|
||||
pos--;
|
||||
found_track = true;
|
||||
break;
|
||||
}
|
||||
if (test(instr, opcode->get())) {
|
||||
--pos;
|
||||
return std::make_optional(pack(instr, opcode->get()));
|
||||
}
|
||||
pos--;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (!found_track) {
|
||||
std::optional<std::pair<BufferInfo, u64>> TrackLDC(const CFGRebuildState& state, u32& pos,
|
||||
u64 brx_tracked_register) {
|
||||
return TrackInstruction<std::pair<BufferInfo, u64>>(
|
||||
state, pos,
|
||||
[brx_tracked_register](auto instr, const auto& opcode) {
|
||||
return opcode.GetId() == OpCode::Id::LD_C &&
|
||||
instr.gpr0.Value() == brx_tracked_register &&
|
||||
instr.ld_c.type.Value() == Tegra::Shader::UniformType::Single;
|
||||
},
|
||||
[](auto instr, const auto& opcode) {
|
||||
const BufferInfo info = {static_cast<u32>(instr.cbuf36.index.Value()),
|
||||
static_cast<u32>(instr.cbuf36.GetOffset())};
|
||||
return std::make_pair(info, instr.gpr8.Value());
|
||||
});
|
||||
}
|
||||
|
||||
std::optional<u64> TrackSHLRegister(const CFGRebuildState& state, u32& pos,
|
||||
u64 ldc_tracked_register) {
|
||||
return TrackInstruction<u64>(state, pos,
|
||||
[ldc_tracked_register](auto instr, const auto& opcode) {
|
||||
return opcode.GetId() == OpCode::Id::SHL_IMM &&
|
||||
instr.gpr0.Value() == ldc_tracked_register;
|
||||
},
|
||||
[](auto instr, const auto&) { return instr.gpr8.Value(); });
|
||||
}
|
||||
|
||||
std::optional<u32> TrackIMNMXValue(const CFGRebuildState& state, u32& pos,
|
||||
u64 shl_tracked_register) {
|
||||
return TrackInstruction<u32>(state, pos,
|
||||
[shl_tracked_register](auto instr, const auto& opcode) {
|
||||
return opcode.GetId() == OpCode::Id::IMNMX_IMM &&
|
||||
instr.gpr0.Value() == shl_tracked_register;
|
||||
},
|
||||
[](auto instr, const auto&) {
|
||||
return static_cast<u32>(instr.alu.GetSignedImm20_20() + 1);
|
||||
});
|
||||
}
|
||||
|
||||
std::optional<BranchIndirectInfo> TrackBranchIndirectInfo(const CFGRebuildState& state, u32 pos) {
|
||||
const auto brx_info = GetBRXInfo(state, pos);
|
||||
if (!brx_info) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return result;
|
||||
const auto [relative_position, brx_tracked_register] = *brx_info;
|
||||
|
||||
const auto ldc_info = TrackLDC(state, pos, brx_tracked_register);
|
||||
if (!ldc_info) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const auto [buffer_info, ldc_tracked_register] = *ldc_info;
|
||||
|
||||
const auto shl_tracked_register = TrackSHLRegister(state, pos, ldc_tracked_register);
|
||||
if (!shl_tracked_register) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const auto entries = TrackIMNMXValue(state, pos, *shl_tracked_register);
|
||||
if (!entries) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return BranchIndirectInfo{buffer_info.index, buffer_info.offset, *entries, relative_position};
|
||||
}
|
||||
|
||||
std::pair<ParseResult, ParseInfo> ParseCode(CFGRebuildState& state, u32 address) {
|
||||
@@ -420,30 +428,30 @@ std::pair<ParseResult, ParseInfo> ParseCode(CFGRebuildState& state, u32 address)
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::BRX: {
|
||||
auto tmp = TrackBranchIndirectInfo(state, address, offset);
|
||||
if (tmp) {
|
||||
auto result = *tmp;
|
||||
std::vector<CaseBranch> branches{};
|
||||
s32 pc_target = offset + result.relative_position;
|
||||
for (u32 i = 0; i < result.entries; i++) {
|
||||
auto k = state.locker.ObtainKey(result.buffer, result.offset + i * 4);
|
||||
if (!k) {
|
||||
return {ParseResult::AbnormalFlow, parse_info};
|
||||
}
|
||||
u32 value = *k;
|
||||
u32 target = static_cast<u32>((value >> 3) + pc_target);
|
||||
insert_label(state, target);
|
||||
branches.emplace_back(value, target);
|
||||
}
|
||||
parse_info.end_address = offset;
|
||||
parse_info.branch_info = MakeBranchInfo<MultiBranch>(
|
||||
static_cast<u32>(instr.gpr8.Value()), std::move(branches));
|
||||
|
||||
return {ParseResult::ControlCaught, parse_info};
|
||||
} else {
|
||||
const auto tmp = TrackBranchIndirectInfo(state, offset);
|
||||
if (!tmp) {
|
||||
LOG_WARNING(HW_GPU, "BRX Track Unsuccesful");
|
||||
return {ParseResult::AbnormalFlow, parse_info};
|
||||
}
|
||||
return {ParseResult::AbnormalFlow, parse_info};
|
||||
|
||||
const auto result = *tmp;
|
||||
const s32 pc_target = offset + result.relative_position;
|
||||
std::vector<CaseBranch> branches;
|
||||
for (u32 i = 0; i < result.entries; i++) {
|
||||
auto key = state.locker.ObtainKey(result.buffer, result.offset + i * 4);
|
||||
if (!key) {
|
||||
return {ParseResult::AbnormalFlow, parse_info};
|
||||
}
|
||||
u32 value = *key;
|
||||
u32 target = static_cast<u32>((value >> 3) + pc_target);
|
||||
insert_label(state, target);
|
||||
branches.emplace_back(value, target);
|
||||
}
|
||||
parse_info.end_address = offset;
|
||||
parse_info.branch_info = MakeBranchInfo<MultiBranch>(
|
||||
static_cast<u32>(instr.gpr8.Value()), std::move(branches));
|
||||
|
||||
return {ParseResult::ControlCaught, parse_info};
|
||||
}
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -154,10 +154,10 @@ void ShaderIR::Decode() {
|
||||
LOG_CRITICAL(HW_GPU, "Unknown decompilation mode!");
|
||||
[[fallthrough]];
|
||||
case CompileDepth::BruteForce: {
|
||||
const auto shader_end = static_cast<u32>(program_code.size());
|
||||
coverage_begin = main_offset;
|
||||
const std::size_t shader_end = program_code.size();
|
||||
coverage_end = shader_end;
|
||||
for (u32 label = main_offset; label < shader_end; label++) {
|
||||
for (u32 label = main_offset; label < shader_end; ++label) {
|
||||
basic_blocks.insert({label, DecodeRange(label, label + 1)});
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -17,6 +17,7 @@ using Tegra::Shader::ShuffleOperation;
|
||||
using Tegra::Shader::VoteOperation;
|
||||
|
||||
namespace {
|
||||
|
||||
OperationCode GetOperationCode(VoteOperation vote_op) {
|
||||
switch (vote_op) {
|
||||
case VoteOperation::All:
|
||||
@@ -30,6 +31,7 @@ OperationCode GetOperationCode(VoteOperation vote_op) {
|
||||
return OperationCode::VoteAll;
|
||||
}
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
u32 ShaderIR::DecodeWarp(NodeBlock& bb, u32 pc) {
|
||||
@@ -46,50 +48,59 @@ u32 ShaderIR::DecodeWarp(NodeBlock& bb, u32 pc) {
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::SHFL: {
|
||||
Node width = [this, instr] {
|
||||
Node mask = instr.shfl.is_mask_imm ? Immediate(static_cast<u32>(instr.shfl.mask_imm))
|
||||
: GetRegister(instr.gpr39);
|
||||
|
||||
// Convert the obscure SHFL mask back into GL_NV_shader_thread_shuffle's width. This has
|
||||
// been done reversing Nvidia's math. It won't work on all cases due to SHFL having
|
||||
// different parameters that don't properly map to GLSL's interface, but it should work
|
||||
// for cases emitted by Nvidia's compiler.
|
||||
if (instr.shfl.operation == ShuffleOperation::Up) {
|
||||
return Operation(
|
||||
OperationCode::ILogicalShiftRight,
|
||||
Operation(OperationCode::IAdd, std::move(mask), Immediate(-0x2000)),
|
||||
Immediate(8));
|
||||
} else {
|
||||
return Operation(OperationCode::ILogicalShiftRight,
|
||||
Operation(OperationCode::IAdd, Immediate(0x201F),
|
||||
Operation(OperationCode::INegate, std::move(mask))),
|
||||
Immediate(8));
|
||||
}
|
||||
}();
|
||||
|
||||
const auto [operation, in_range] = [instr]() -> std::pair<OperationCode, OperationCode> {
|
||||
switch (instr.shfl.operation) {
|
||||
case ShuffleOperation::Idx:
|
||||
return {OperationCode::ShuffleIndexed, OperationCode::InRangeShuffleIndexed};
|
||||
case ShuffleOperation::Up:
|
||||
return {OperationCode::ShuffleUp, OperationCode::InRangeShuffleUp};
|
||||
case ShuffleOperation::Down:
|
||||
return {OperationCode::ShuffleDown, OperationCode::InRangeShuffleDown};
|
||||
case ShuffleOperation::Bfly:
|
||||
return {OperationCode::ShuffleButterfly, OperationCode::InRangeShuffleButterfly};
|
||||
}
|
||||
UNREACHABLE_MSG("Invalid SHFL operation: {}",
|
||||
static_cast<u64>(instr.shfl.operation.Value()));
|
||||
return {};
|
||||
}();
|
||||
|
||||
// Setting the predicate before the register is intentional to avoid overwriting.
|
||||
Node mask = instr.shfl.is_mask_imm ? Immediate(static_cast<u32>(instr.shfl.mask_imm))
|
||||
: GetRegister(instr.gpr39);
|
||||
Node index = instr.shfl.is_index_imm ? Immediate(static_cast<u32>(instr.shfl.index_imm))
|
||||
: GetRegister(instr.gpr20);
|
||||
SetPredicate(bb, instr.shfl.pred48, Operation(in_range, index, width));
|
||||
|
||||
Node thread_id = Operation(OperationCode::ThreadId);
|
||||
Node clamp = Operation(OperationCode::IBitwiseAnd, mask, Immediate(0x1FU));
|
||||
Node seg_mask = BitfieldExtract(mask, 8, 16);
|
||||
|
||||
Node neg_seg_mask = Operation(OperationCode::IBitwiseNot, seg_mask);
|
||||
Node min_thread_id = Operation(OperationCode::IBitwiseAnd, thread_id, seg_mask);
|
||||
Node max_thread_id = Operation(OperationCode::IBitwiseOr, min_thread_id,
|
||||
Operation(OperationCode::IBitwiseAnd, clamp, neg_seg_mask));
|
||||
|
||||
Node src_thread_id = [instr, index, neg_seg_mask, min_thread_id, thread_id] {
|
||||
switch (instr.shfl.operation) {
|
||||
case ShuffleOperation::Idx:
|
||||
return Operation(OperationCode::IBitwiseOr,
|
||||
Operation(OperationCode::IBitwiseAnd, index, neg_seg_mask),
|
||||
min_thread_id);
|
||||
case ShuffleOperation::Down:
|
||||
return Operation(OperationCode::IAdd, thread_id, index);
|
||||
case ShuffleOperation::Up:
|
||||
return Operation(OperationCode::IAdd, thread_id,
|
||||
Operation(OperationCode::INegate, index));
|
||||
case ShuffleOperation::Bfly:
|
||||
return Operation(OperationCode::IBitwiseXor, thread_id, index);
|
||||
}
|
||||
UNREACHABLE();
|
||||
return Immediate(0U);
|
||||
}();
|
||||
|
||||
Node in_bounds = [instr, src_thread_id, min_thread_id, max_thread_id] {
|
||||
if (instr.shfl.operation == ShuffleOperation::Up) {
|
||||
return Operation(OperationCode::LogicalIGreaterEqual, src_thread_id, min_thread_id);
|
||||
} else {
|
||||
return Operation(OperationCode::LogicalILessEqual, src_thread_id, max_thread_id);
|
||||
}
|
||||
}();
|
||||
|
||||
SetPredicate(bb, instr.shfl.pred48, in_bounds);
|
||||
SetRegister(
|
||||
bb, instr.gpr0,
|
||||
Operation(operation, GetRegister(instr.gpr8), std::move(index), std::move(width)));
|
||||
Operation(OperationCode::ShuffleIndexed, GetRegister(instr.gpr8), src_thread_id));
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::FSWZADD: {
|
||||
UNIMPLEMENTED_IF(instr.fswzadd.ndv);
|
||||
|
||||
Node op_a = GetRegister(instr.gpr8);
|
||||
Node op_b = GetRegister(instr.gpr20);
|
||||
Node mask = Immediate(static_cast<u32>(instr.fswzadd.swizzle));
|
||||
SetRegister(bb, instr.gpr0, Operation(OperationCode::FSwizzleAdd, op_a, op_b, mask));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -47,6 +47,7 @@ enum class OperationCode {
|
||||
FTrunc, /// (MetaArithmetic, float a) -> float
|
||||
FCastInteger, /// (MetaArithmetic, int a) -> float
|
||||
FCastUInteger, /// (MetaArithmetic, uint a) -> float
|
||||
FSwizzleAdd, /// (float a, float b, uint mask) -> float
|
||||
|
||||
IAdd, /// (MetaArithmetic, int a, int b) -> int
|
||||
IMul, /// (MetaArithmetic, int a, int b) -> int
|
||||
@@ -181,15 +182,8 @@ enum class OperationCode {
|
||||
VoteAny, /// (bool) -> bool
|
||||
VoteEqual, /// (bool) -> bool
|
||||
|
||||
ShuffleIndexed, /// (uint value, uint index, uint width) -> uint
|
||||
ShuffleUp, /// (uint value, uint index, uint width) -> uint
|
||||
ShuffleDown, /// (uint value, uint index, uint width) -> uint
|
||||
ShuffleButterfly, /// (uint value, uint index, uint width) -> uint
|
||||
|
||||
InRangeShuffleIndexed, /// (uint index, uint width) -> bool
|
||||
InRangeShuffleUp, /// (uint index, uint width) -> bool
|
||||
InRangeShuffleDown, /// (uint index, uint width) -> bool
|
||||
InRangeShuffleButterfly, /// (uint index, uint width) -> bool
|
||||
ThreadId, /// () -> uint
|
||||
ShuffleIndexed, /// (uint value, uint index) -> uint
|
||||
|
||||
Amount,
|
||||
};
|
||||
|
||||
@@ -49,7 +49,7 @@ public:
|
||||
}
|
||||
|
||||
u32 GetSize() const {
|
||||
return max_offset + sizeof(float);
|
||||
return max_offset + static_cast<u32>(sizeof(float));
|
||||
}
|
||||
|
||||
u32 GetMaxOffset() const {
|
||||
@@ -165,8 +165,8 @@ public:
|
||||
return program_manager.GetVariables();
|
||||
}
|
||||
|
||||
u32 ConvertAddressToNvidiaSpace(const u32 address) const {
|
||||
return (address - main_offset) * sizeof(Tegra::Shader::Instruction);
|
||||
u32 ConvertAddressToNvidiaSpace(u32 address) const {
|
||||
return (address - main_offset) * static_cast<u32>(sizeof(Tegra::Shader::Instruction));
|
||||
}
|
||||
|
||||
/// Returns a condition code evaluated from internal flags
|
||||
|
||||
@@ -92,11 +92,11 @@ private:
|
||||
const unsigned int mask = 1 << m_NextBit++;
|
||||
|
||||
// clear the bit
|
||||
*m_CurByte &= ~mask;
|
||||
*m_CurByte &= static_cast<unsigned char>(~mask);
|
||||
|
||||
// Write the bit, if necessary
|
||||
if (b)
|
||||
*m_CurByte |= mask;
|
||||
*m_CurByte |= static_cast<unsigned char>(mask);
|
||||
|
||||
// Next byte?
|
||||
if (m_NextBit >= 8) {
|
||||
@@ -137,7 +137,7 @@ public:
|
||||
}
|
||||
|
||||
uint64_t mask = (1 << (end - start + 1)) - 1;
|
||||
return (m_Bits >> start) & mask;
|
||||
return (m_Bits >> start) & static_cast<IntType>(mask);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -656,7 +656,7 @@ static IntType Replicate(const IntType& val, uint32_t numBits, uint32_t toBit) {
|
||||
return 0;
|
||||
if (toBit == 0)
|
||||
return 0;
|
||||
IntType v = val & ((1 << numBits) - 1);
|
||||
IntType v = val & static_cast<IntType>((1 << numBits) - 1);
|
||||
IntType res = v;
|
||||
uint32_t reslen = numBits;
|
||||
while (reslen < toBit) {
|
||||
@@ -666,8 +666,8 @@ static IntType Replicate(const IntType& val, uint32_t numBits, uint32_t toBit) {
|
||||
comp = numBits - newshift;
|
||||
numBits = newshift;
|
||||
}
|
||||
res <<= numBits;
|
||||
res |= v >> comp;
|
||||
res = static_cast<IntType>(res << numBits);
|
||||
res = static_cast<IntType>(res | (v >> comp));
|
||||
reslen += numBits;
|
||||
}
|
||||
return res;
|
||||
@@ -714,7 +714,7 @@ public:
|
||||
// Do nothing
|
||||
return val;
|
||||
} else if (oldDepth == 0 && newDepth != 0) {
|
||||
return (1 << newDepth) - 1;
|
||||
return static_cast<ChannelType>((1 << newDepth) - 1);
|
||||
} else if (newDepth > oldDepth) {
|
||||
return Replicate(val, oldDepth, newDepth);
|
||||
} else {
|
||||
@@ -722,10 +722,11 @@ public:
|
||||
if (newDepth == 0) {
|
||||
return 0xFF;
|
||||
} else {
|
||||
uint8_t bitsWasted = oldDepth - newDepth;
|
||||
uint8_t bitsWasted = static_cast<uint8_t>(oldDepth - newDepth);
|
||||
uint16_t v = static_cast<uint16_t>(val);
|
||||
v = (v + (1 << (bitsWasted - 1))) >> bitsWasted;
|
||||
v = ::std::min<uint16_t>(::std::max<uint16_t>(0, v), (1 << newDepth) - 1);
|
||||
v = static_cast<uint16_t>((v + (1 << (bitsWasted - 1))) >> bitsWasted);
|
||||
v = ::std::min<uint16_t>(::std::max<uint16_t>(0, v),
|
||||
static_cast<uint16_t>((1 << newDepth) - 1));
|
||||
return static_cast<uint8_t>(v);
|
||||
}
|
||||
}
|
||||
@@ -1191,18 +1192,18 @@ static uint32_t SelectPartition(int32_t seed, int32_t x, int32_t y, int32_t z,
|
||||
uint8_t seed11 = static_cast<uint8_t>((rnum >> 26) & 0xF);
|
||||
uint8_t seed12 = static_cast<uint8_t>(((rnum >> 30) | (rnum << 2)) & 0xF);
|
||||
|
||||
seed1 *= seed1;
|
||||
seed2 *= seed2;
|
||||
seed3 *= seed3;
|
||||
seed4 *= seed4;
|
||||
seed5 *= seed5;
|
||||
seed6 *= seed6;
|
||||
seed7 *= seed7;
|
||||
seed8 *= seed8;
|
||||
seed9 *= seed9;
|
||||
seed10 *= seed10;
|
||||
seed11 *= seed11;
|
||||
seed12 *= seed12;
|
||||
seed1 = static_cast<uint8_t>(seed1 * seed1);
|
||||
seed2 = static_cast<uint8_t>(seed2 * seed2);
|
||||
seed3 = static_cast<uint8_t>(seed3 * seed3);
|
||||
seed4 = static_cast<uint8_t>(seed4 * seed4);
|
||||
seed5 = static_cast<uint8_t>(seed5 * seed5);
|
||||
seed6 = static_cast<uint8_t>(seed6 * seed6);
|
||||
seed7 = static_cast<uint8_t>(seed7 * seed7);
|
||||
seed8 = static_cast<uint8_t>(seed8 * seed8);
|
||||
seed9 = static_cast<uint8_t>(seed9 * seed9);
|
||||
seed10 = static_cast<uint8_t>(seed10 * seed10);
|
||||
seed11 = static_cast<uint8_t>(seed11 * seed11);
|
||||
seed12 = static_cast<uint8_t>(seed12 * seed12);
|
||||
|
||||
int32_t sh1, sh2, sh3;
|
||||
if (seed & 1) {
|
||||
@@ -1214,18 +1215,18 @@ static uint32_t SelectPartition(int32_t seed, int32_t x, int32_t y, int32_t z,
|
||||
}
|
||||
sh3 = (seed & 0x10) ? sh1 : sh2;
|
||||
|
||||
seed1 >>= sh1;
|
||||
seed2 >>= sh2;
|
||||
seed3 >>= sh1;
|
||||
seed4 >>= sh2;
|
||||
seed5 >>= sh1;
|
||||
seed6 >>= sh2;
|
||||
seed7 >>= sh1;
|
||||
seed8 >>= sh2;
|
||||
seed9 >>= sh3;
|
||||
seed10 >>= sh3;
|
||||
seed11 >>= sh3;
|
||||
seed12 >>= sh3;
|
||||
seed1 = static_cast<uint8_t>(seed1 >> sh1);
|
||||
seed2 = static_cast<uint8_t>(seed2 >> sh2);
|
||||
seed3 = static_cast<uint8_t>(seed3 >> sh1);
|
||||
seed4 = static_cast<uint8_t>(seed4 >> sh2);
|
||||
seed5 = static_cast<uint8_t>(seed5 >> sh1);
|
||||
seed6 = static_cast<uint8_t>(seed6 >> sh2);
|
||||
seed7 = static_cast<uint8_t>(seed7 >> sh1);
|
||||
seed8 = static_cast<uint8_t>(seed8 >> sh2);
|
||||
seed9 = static_cast<uint8_t>(seed9 >> sh3);
|
||||
seed10 = static_cast<uint8_t>(seed10 >> sh3);
|
||||
seed11 = static_cast<uint8_t>(seed11 >> sh3);
|
||||
seed12 = static_cast<uint8_t>(seed12 >> sh3);
|
||||
|
||||
int32_t a = seed1 * x + seed2 * y + seed11 * z + (rnum >> 14);
|
||||
int32_t b = seed3 * x + seed4 * y + seed12 * z + (rnum >> 10);
|
||||
@@ -1558,7 +1559,9 @@ static void DecompressBlock(const uint8_t inBuf[16], const uint32_t blockWidth,
|
||||
|
||||
// Make sure that higher non-texel bits are set to zero
|
||||
const uint32_t clearByteStart = (weightParams.GetPackedBitSize() >> 3) + 1;
|
||||
texelWeightData[clearByteStart - 1] &= (1 << (weightParams.GetPackedBitSize() % 8)) - 1;
|
||||
texelWeightData[clearByteStart - 1] =
|
||||
texelWeightData[clearByteStart - 1] &
|
||||
static_cast<uint8_t>((1 << (weightParams.GetPackedBitSize() % 8)) - 1);
|
||||
memset(texelWeightData + clearByteStart, 0, 16 - clearByteStart);
|
||||
|
||||
std::vector<IntegerEncodedValue> texelWeightValues;
|
||||
|
||||
@@ -342,13 +342,14 @@ struct TSCEntry {
|
||||
float GetLodBias() const {
|
||||
// Sign extend the 13-bit value.
|
||||
constexpr u32 mask = 1U << (13 - 1);
|
||||
return static_cast<s32>((mip_lod_bias ^ mask) - mask) / 256.0f;
|
||||
return static_cast<float>(static_cast<s32>((mip_lod_bias ^ mask) - mask)) / 256.0f;
|
||||
}
|
||||
|
||||
std::array<float, 4> GetBorderColor() const {
|
||||
if (srgb_conversion) {
|
||||
return {srgb_border_color_r / 255.0f, srgb_border_color_g / 255.0f,
|
||||
srgb_border_color_b / 255.0f, border_color[3]};
|
||||
return {static_cast<float>(srgb_border_color_r) / 255.0f,
|
||||
static_cast<float>(srgb_border_color_g) / 255.0f,
|
||||
static_cast<float>(srgb_border_color_b) / 255.0f, border_color[3]};
|
||||
}
|
||||
return border_color;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ std::unique_ptr<Tegra::GPU> CreateGPU(Core::System& system) {
|
||||
|
||||
u16 GetResolutionScaleFactor(const RendererBase& renderer) {
|
||||
return static_cast<u16>(
|
||||
Settings::values.resolution_factor
|
||||
Settings::values.resolution_factor != 0
|
||||
? Settings::values.resolution_factor
|
||||
: renderer.GetRenderWindow().GetFramebufferLayout().GetScalingRatio());
|
||||
}
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <array>
|
||||
#include <cstdlib>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <LUrlParser.h>
|
||||
#include <fmt/format.h>
|
||||
#include <httplib.h>
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
@@ -16,10 +18,10 @@ namespace WebService {
|
||||
|
||||
constexpr std::array<const char, 1> API_VERSION{'1'};
|
||||
|
||||
constexpr u32 HTTP_PORT = 80;
|
||||
constexpr u32 HTTPS_PORT = 443;
|
||||
constexpr int HTTP_PORT = 80;
|
||||
constexpr int HTTPS_PORT = 443;
|
||||
|
||||
constexpr u32 TIMEOUT_SECONDS = 30;
|
||||
constexpr std::size_t TIMEOUT_SECONDS = 30;
|
||||
|
||||
struct Client::Impl {
|
||||
Impl(std::string host, std::string username, std::string token)
|
||||
@@ -31,8 +33,9 @@ struct Client::Impl {
|
||||
}
|
||||
|
||||
/// A generic function handles POST, GET and DELETE request together
|
||||
Common::WebResult GenericJson(const std::string& method, const std::string& path,
|
||||
const std::string& data, bool allow_anonymous) {
|
||||
Common::WebResult GenericRequest(const std::string& method, const std::string& path,
|
||||
const std::string& data, bool allow_anonymous,
|
||||
const std::string& accept) {
|
||||
if (jwt.empty()) {
|
||||
UpdateJWT();
|
||||
}
|
||||
@@ -43,11 +46,11 @@ struct Client::Impl {
|
||||
"Credentials needed"};
|
||||
}
|
||||
|
||||
auto result = GenericJson(method, path, data, jwt);
|
||||
auto result = GenericRequest(method, path, data, accept, jwt);
|
||||
if (result.result_string == "401") {
|
||||
// Try again with new JWT
|
||||
UpdateJWT();
|
||||
result = GenericJson(method, path, data, jwt);
|
||||
result = GenericRequest(method, path, data, accept, jwt);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -56,12 +59,13 @@ struct Client::Impl {
|
||||
/**
|
||||
* A generic function with explicit authentication method specified
|
||||
* JWT is used if the jwt parameter is not empty
|
||||
* username + token is used if jwt is empty but username and token are not empty
|
||||
* anonymous if all of jwt, username and token are empty
|
||||
* username + token is used if jwt is empty but username and token are
|
||||
* not empty anonymous if all of jwt, username and token are empty
|
||||
*/
|
||||
Common::WebResult GenericJson(const std::string& method, const std::string& path,
|
||||
const std::string& data, const std::string& jwt = "",
|
||||
const std::string& username = "", const std::string& token = "") {
|
||||
Common::WebResult GenericRequest(const std::string& method, const std::string& path,
|
||||
const std::string& data, const std::string& accept,
|
||||
const std::string& jwt = "", const std::string& username = "",
|
||||
const std::string& token = "") {
|
||||
if (cli == nullptr) {
|
||||
auto parsedUrl = LUrlParser::clParseURL::ParseURL(host);
|
||||
int port;
|
||||
@@ -132,8 +136,7 @@ struct Client::Impl {
|
||||
return Common::WebResult{Common::WebResult::Code::WrongContent, ""};
|
||||
}
|
||||
|
||||
if (content_type->second.find("application/json") == std::string::npos &&
|
||||
content_type->second.find("text/html; charset=utf-8") == std::string::npos) {
|
||||
if (content_type->second.find(accept) == std::string::npos) {
|
||||
LOG_ERROR(WebService, "{} to {} returned wrong content: {}", method, host + path,
|
||||
content_type->second);
|
||||
return Common::WebResult{Common::WebResult::Code::WrongContent, "Wrong content"};
|
||||
@@ -147,7 +150,7 @@ struct Client::Impl {
|
||||
return;
|
||||
}
|
||||
|
||||
auto result = GenericJson("POST", "/jwt/internal", "", "", username, token);
|
||||
auto result = GenericRequest("POST", "/jwt/internal", "", "text/html", "", username, token);
|
||||
if (result.result_code != Common::WebResult::Code::Success) {
|
||||
LOG_ERROR(WebService, "UpdateJWT failed");
|
||||
} else {
|
||||
@@ -180,16 +183,29 @@ Client::~Client() = default;
|
||||
|
||||
Common::WebResult Client::PostJson(const std::string& path, const std::string& data,
|
||||
bool allow_anonymous) {
|
||||
return impl->GenericJson("POST", path, data, allow_anonymous);
|
||||
return impl->GenericRequest("POST", path, data, allow_anonymous, "application/json");
|
||||
}
|
||||
|
||||
Common::WebResult Client::GetJson(const std::string& path, bool allow_anonymous) {
|
||||
return impl->GenericJson("GET", path, "", allow_anonymous);
|
||||
return impl->GenericRequest("GET", path, "", allow_anonymous, "application/json");
|
||||
}
|
||||
|
||||
Common::WebResult Client::DeleteJson(const std::string& path, const std::string& data,
|
||||
bool allow_anonymous) {
|
||||
return impl->GenericJson("DELETE", path, data, allow_anonymous);
|
||||
return impl->GenericRequest("DELETE", path, data, allow_anonymous, "application/json");
|
||||
}
|
||||
|
||||
Common::WebResult Client::GetPlain(const std::string& path, bool allow_anonymous) {
|
||||
return impl->GenericRequest("GET", path, "", allow_anonymous, "text/plain");
|
||||
}
|
||||
|
||||
Common::WebResult Client::GetImage(const std::string& path, bool allow_anonymous) {
|
||||
return impl->GenericRequest("GET", path, "", allow_anonymous, "image/png");
|
||||
}
|
||||
|
||||
Common::WebResult Client::GetExternalJWT(const std::string& audience) {
|
||||
return impl->GenericRequest("POST", fmt::format("/jwt/external/{}", audience), "", false,
|
||||
"text/html");
|
||||
}
|
||||
|
||||
} // namespace WebService
|
||||
|
||||
@@ -46,6 +46,29 @@ public:
|
||||
Common::WebResult DeleteJson(const std::string& path, const std::string& data,
|
||||
bool allow_anonymous);
|
||||
|
||||
/**
|
||||
* Gets a plain string from the specified path.
|
||||
* @param path the URL segment after the host address.
|
||||
* @param allow_anonymous If true, allow anonymous unauthenticated requests.
|
||||
* @return the result of the request.
|
||||
*/
|
||||
Common::WebResult GetPlain(const std::string& path, bool allow_anonymous);
|
||||
|
||||
/**
|
||||
* Gets an PNG image from the specified path.
|
||||
* @param path the URL segment after the host address.
|
||||
* @param allow_anonymous If true, allow anonymous unauthenticated requests.
|
||||
* @return the result of the request.
|
||||
*/
|
||||
Common::WebResult GetImage(const std::string& path, bool allow_anonymous);
|
||||
|
||||
/**
|
||||
* Requests an external JWT for the specific audience provided.
|
||||
* @param audience the audience of the JWT requested.
|
||||
* @return the result of the request.
|
||||
*/
|
||||
Common::WebResult GetExternalJWT(const std::string& audience);
|
||||
|
||||
private:
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> impl;
|
||||
|
||||
@@ -11,6 +11,31 @@
|
||||
#include "yuzu/configuration/configure_web.h"
|
||||
#include "yuzu/uisettings.h"
|
||||
|
||||
static constexpr char token_delimiter{':'};
|
||||
|
||||
static std::string GenerateDisplayToken(const std::string& username, const std::string& token) {
|
||||
if (username.empty() || token.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const std::string unencoded_display_token{username + token_delimiter + token};
|
||||
QByteArray b{unencoded_display_token.c_str()};
|
||||
QByteArray b64 = b.toBase64();
|
||||
return b64.toStdString();
|
||||
}
|
||||
|
||||
static std::string UsernameFromDisplayToken(const std::string& display_token) {
|
||||
const std::string unencoded_display_token{
|
||||
QByteArray::fromBase64(display_token.c_str()).toStdString()};
|
||||
return unencoded_display_token.substr(0, unencoded_display_token.find(token_delimiter));
|
||||
}
|
||||
|
||||
static std::string TokenFromDisplayToken(const std::string& display_token) {
|
||||
const std::string unencoded_display_token{
|
||||
QByteArray::fromBase64(display_token.c_str()).toStdString()};
|
||||
return unencoded_display_token.substr(unencoded_display_token.find(token_delimiter) + 1);
|
||||
}
|
||||
|
||||
ConfigureWeb::ConfigureWeb(QWidget* parent)
|
||||
: QWidget(parent), ui(std::make_unique<Ui::ConfigureWeb>()) {
|
||||
ui->setupUi(this);
|
||||
@@ -63,13 +88,18 @@ void ConfigureWeb::SetConfiguration() {
|
||||
ui->web_signup_link->setOpenExternalLinks(true);
|
||||
ui->web_token_info_link->setOpenExternalLinks(true);
|
||||
|
||||
if (Settings::values.yuzu_username.empty()) {
|
||||
ui->username->setText(tr("Unspecified"));
|
||||
} else {
|
||||
ui->username->setText(QString::fromStdString(Settings::values.yuzu_username));
|
||||
}
|
||||
|
||||
ui->toggle_telemetry->setChecked(Settings::values.enable_telemetry);
|
||||
ui->edit_username->setText(QString::fromStdString(Settings::values.yuzu_username));
|
||||
ui->edit_token->setText(QString::fromStdString(Settings::values.yuzu_token));
|
||||
ui->edit_token->setText(QString::fromStdString(
|
||||
GenerateDisplayToken(Settings::values.yuzu_username, Settings::values.yuzu_token)));
|
||||
|
||||
// Connect after setting the values, to avoid calling OnLoginChanged now
|
||||
connect(ui->edit_token, &QLineEdit::textChanged, this, &ConfigureWeb::OnLoginChanged);
|
||||
connect(ui->edit_username, &QLineEdit::textChanged, this, &ConfigureWeb::OnLoginChanged);
|
||||
|
||||
user_verified = true;
|
||||
|
||||
@@ -80,12 +110,13 @@ void ConfigureWeb::ApplyConfiguration() {
|
||||
Settings::values.enable_telemetry = ui->toggle_telemetry->isChecked();
|
||||
UISettings::values.enable_discord_presence = ui->toggle_discordrpc->isChecked();
|
||||
if (user_verified) {
|
||||
Settings::values.yuzu_username = ui->edit_username->text().toStdString();
|
||||
Settings::values.yuzu_token = ui->edit_token->text().toStdString();
|
||||
Settings::values.yuzu_username =
|
||||
UsernameFromDisplayToken(ui->edit_token->text().toStdString());
|
||||
Settings::values.yuzu_token = TokenFromDisplayToken(ui->edit_token->text().toStdString());
|
||||
} else {
|
||||
QMessageBox::warning(this, tr("Username and token not verified"),
|
||||
tr("Username and token were not verified. The changes to your "
|
||||
"username and/or token have not been saved."));
|
||||
QMessageBox::warning(
|
||||
this, tr("Token not verified"),
|
||||
tr("Token was not verified. The change to your token has not been saved."));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,17 +127,15 @@ void ConfigureWeb::RefreshTelemetryID() {
|
||||
}
|
||||
|
||||
void ConfigureWeb::OnLoginChanged() {
|
||||
if (ui->edit_username->text().isEmpty() && ui->edit_token->text().isEmpty()) {
|
||||
if (ui->edit_token->text().isEmpty()) {
|
||||
user_verified = true;
|
||||
|
||||
const QPixmap pixmap = QIcon::fromTheme(QStringLiteral("checked")).pixmap(16);
|
||||
ui->label_username_verified->setPixmap(pixmap);
|
||||
ui->label_token_verified->setPixmap(pixmap);
|
||||
} else {
|
||||
user_verified = false;
|
||||
|
||||
const QPixmap pixmap = QIcon::fromTheme(QStringLiteral("failed")).pixmap(16);
|
||||
ui->label_username_verified->setPixmap(pixmap);
|
||||
ui->label_token_verified->setPixmap(pixmap);
|
||||
}
|
||||
}
|
||||
@@ -114,10 +143,11 @@ void ConfigureWeb::OnLoginChanged() {
|
||||
void ConfigureWeb::VerifyLogin() {
|
||||
ui->button_verify_login->setDisabled(true);
|
||||
ui->button_verify_login->setText(tr("Verifying..."));
|
||||
verify_watcher.setFuture(QtConcurrent::run([username = ui->edit_username->text().toStdString(),
|
||||
token = ui->edit_token->text().toStdString()] {
|
||||
return Core::VerifyLogin(username, token);
|
||||
}));
|
||||
verify_watcher.setFuture(QtConcurrent::run(
|
||||
[username = UsernameFromDisplayToken(ui->edit_token->text().toStdString()),
|
||||
token = TokenFromDisplayToken(ui->edit_token->text().toStdString())] {
|
||||
return Core::VerifyLogin(username, token);
|
||||
}));
|
||||
}
|
||||
|
||||
void ConfigureWeb::OnLoginVerified() {
|
||||
@@ -127,16 +157,15 @@ void ConfigureWeb::OnLoginVerified() {
|
||||
user_verified = true;
|
||||
|
||||
const QPixmap pixmap = QIcon::fromTheme(QStringLiteral("checked")).pixmap(16);
|
||||
ui->label_username_verified->setPixmap(pixmap);
|
||||
ui->label_token_verified->setPixmap(pixmap);
|
||||
ui->username->setText(
|
||||
QString::fromStdString(UsernameFromDisplayToken(ui->edit_token->text().toStdString())));
|
||||
} else {
|
||||
const QPixmap pixmap = QIcon::fromTheme(QStringLiteral("failed")).pixmap(16);
|
||||
ui->label_username_verified->setPixmap(pixmap);
|
||||
ui->label_token_verified->setPixmap(pixmap);
|
||||
|
||||
QMessageBox::critical(
|
||||
this, tr("Verification failed"),
|
||||
tr("Verification failed. Check that you have entered your username and token "
|
||||
"correctly, and that your internet connection is working."));
|
||||
ui->username->setText(tr("Unspecified"));
|
||||
QMessageBox::critical(this, tr("Verification failed"),
|
||||
tr("Verification failed. Check that you have entered your token "
|
||||
"correctly, and that your internet connection is working."));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,11 +55,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="3">
|
||||
<widget class="QLineEdit" name="edit_username">
|
||||
<property name="maxLength">
|
||||
<number>36</number>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="username" />
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_token">
|
||||
@@ -79,14 +75,10 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<widget class="QLabel" name="label_username_verified">
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="3">
|
||||
<widget class="QLineEdit" name="edit_token">
|
||||
<property name="maxLength">
|
||||
<number>36</number>
|
||||
<number>80</number>
|
||||
</property>
|
||||
<property name="echoMode">
|
||||
<enum>QLineEdit::Password</enum>
|
||||
|
||||
@@ -172,17 +172,6 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeWaitObject::GetChildren() con
|
||||
return list;
|
||||
}
|
||||
|
||||
QString WaitTreeWaitObject::GetResetTypeQString(Kernel::ResetType reset_type) {
|
||||
switch (reset_type) {
|
||||
case Kernel::ResetType::Automatic:
|
||||
return tr("automatic reset");
|
||||
case Kernel::ResetType::Manual:
|
||||
return tr("manual reset");
|
||||
}
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
|
||||
WaitTreeObjectList::WaitTreeObjectList(
|
||||
const std::vector<Kernel::SharedPtr<Kernel::WaitObject>>& list, bool w_all)
|
||||
: object_list(list), wait_all(w_all) {}
|
||||
@@ -336,16 +325,6 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
|
||||
WaitTreeEvent::WaitTreeEvent(const Kernel::ReadableEvent& object) : WaitTreeWaitObject(object) {}
|
||||
WaitTreeEvent::~WaitTreeEvent() = default;
|
||||
|
||||
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeEvent::GetChildren() const {
|
||||
std::vector<std::unique_ptr<WaitTreeItem>> list(WaitTreeWaitObject::GetChildren());
|
||||
|
||||
list.push_back(std::make_unique<WaitTreeText>(
|
||||
tr("reset type = %1")
|
||||
.arg(GetResetTypeQString(
|
||||
static_cast<const Kernel::ReadableEvent&>(object).GetResetType()))));
|
||||
return list;
|
||||
}
|
||||
|
||||
WaitTreeThreadList::WaitTreeThreadList(const std::vector<Kernel::SharedPtr<Kernel::Thread>>& list)
|
||||
: thread_list(list) {}
|
||||
WaitTreeThreadList::~WaitTreeThreadList() = default;
|
||||
|
||||
@@ -111,8 +111,6 @@ public:
|
||||
|
||||
protected:
|
||||
const Kernel::WaitObject& object;
|
||||
|
||||
static QString GetResetTypeQString(Kernel::ResetType reset_type);
|
||||
};
|
||||
|
||||
class WaitTreeObjectList : public WaitTreeExpandableItem {
|
||||
@@ -146,8 +144,6 @@ class WaitTreeEvent : public WaitTreeWaitObject {
|
||||
public:
|
||||
explicit WaitTreeEvent(const Kernel::ReadableEvent& object);
|
||||
~WaitTreeEvent() override;
|
||||
|
||||
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
|
||||
};
|
||||
|
||||
class WaitTreeThreadList : public WaitTreeExpandableItem {
|
||||
|
||||
Reference in New Issue
Block a user