Compare commits

...
Author SHA1 Message Date
nmzik 5b7d3343cf shader: V_CMP_NLT_F16 2026-09-18 12:25:13 +04:00
nmzik 394e638905 shader: V_MUL_LO_U16 2026-09-18 11:21:57 +04:00
nmzik c2b7b0b58c Revert "BC7-RGBA32_UINT views (Vulkan validation)"
This reverts commit 165234b159.
2026-09-18 11:12:36 +04:00
nmzik 1d2f59dfa4 ajm: reject invalid batch storage 2026-09-18 09:11:55 +04:00
nmzikandBlackCAT 007d7ea2eb audio: infer stereo RAW AAC layout from channel-pair packets
Co-authored-by: BlackCAT <52720489+psnwd@users.noreply.github.com>
2026-09-18 09:11:55 +04:00
nmzikandshadowbeat070 95d3d9d3ad shader: fix packed integer negation
Co-authored-by: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com>
2026-09-18 09:11:55 +04:00
bfc8cd0e0b shader: DPP8 moves
Co-authored-by: foufouadi <attar.foued@gmail.com>
Co-authored-by: fxpw <fxpw@outlook.com>
2026-09-18 09:11:55 +04:00
165234b159 BC7-RGBA32_UINT views (Vulkan validation)
Co-authored-by: Techx3 <56268269+Techx3@users.noreply.github.com>
Co-authored-by: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com>
Co-authored-by: SueryRD <the.ai.tester2@gmail.com>
Co-authored-by: BlackCAT <52720489+psnwd@users.noreply.github.com>
2026-09-18 09:11:55 +04:00
nmzik 6493674726 shader: dual-source blending (Vulkan) 2026-09-18 09:11:55 +04:00
nmzik cbedf5707f UDP P2P sockets 2026-09-18 09:11:55 +04:00
nmzik 57c5b206ca fix network errno 2026-09-18 09:11:55 +04:00
nmzik 87b4417aca fix initial NP sign-in callback 2026-09-18 09:11:55 +04:00
nmzik 104530eafc fix Windows build (#680)
fix Windows Vulkan barrier macro
2026-09-17 21:32:54 +04:00
nmzik 6cfde37e98 avoid extra allocations 2026-09-17 20:35:36 +04:00
nmzik c5cebc1d19 remove unused helpers and the -64 suffix 2026-09-17 20:35:36 +04:00
nmzik 697b18b366 replace ByteBuffer with std::vector 2026-09-17 20:35:36 +04:00
nmzik 5b2935e36c remove the extra virtual memory layer 2026-09-17 20:35:36 +04:00
nmzik 5dc644edb4 clean up graphics helpers 2026-09-17 20:35:36 +04:00
nmzik 1211958b4e clean up runtime helpers 2026-09-17 20:35:36 +04:00
nmzik 218e7200bb clean up launcher helpers 2026-09-17 20:35:36 +04:00
nmzik 2bf78a94e0 remove string wrappers 2026-09-17 20:35:36 +04:00
nmzikandSaadi cc8e02380f remove magic_enum wrappers
Co-authored-by: Saadi <cosxmos@gmail.com>
2026-09-17 20:35:36 +04:00
nmzik c66d977c1d shader: encode SNORM16 formatted stores for skinning buffers 2026-09-17 17:40:05 +04:00
nmzik 4b77686566 shader: V_CMP_NGT_F16 2026-09-17 16:56:32 +04:00
c0sxm0s a6144f794b launcher: report cheat file save failures (#669)
PatchesDialog::Save silently ignored QSaveFile failures, leaving the
status label showing the old "Loaded N cheat(s)" text so the user could
not tell that their selection was not saved. Report the failure in the
status label and the log instead.
2026-09-17 16:13:35 +04:00
Mininaut bab1c3614c libc: treat negative dynamic printf precision as omitted (#625) 2026-09-17 15:18:04 +04:00
c0sxm0s de1545e19a launcher: wire cancel->reject in C++; document glslang for Windows (#663)
uic from Qt 6.12.0 crashes (0xC0000005) on any non-empty <connections>
block in .ui files. Move the cancel_button -> reject connection from
configuration_edit_dialog.ui into configurationEditDialog.cpp, matching
how the other buttons are already connected there.

Also document the glslang (glslangValidator) requirement for Windows
builds; CMake requires it via find_program(... REQUIRED).
2026-09-17 15:13:20 +04:00
Komaryandnmzik ce629e0391 input: add gyroscope and motion sensor support (#634)
input: add controller motion sensor support

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-17 12:28:12 +04:00
BlackCAT 6c03b4aaa5 vscode: point IntelliSense at clang instead of MSVC (#564)
* vscode: point IntelliSense at clang instead of MSVC

KYTY_SYSV_ABI expands to __attribute__((sysv_abi)) with no MSVC fallback,
which is correct for a project that rejects cl.exe at configure time. Nothing
told the C/C++ extension that, so it fell back to windows-msvc-x64 and
flagged every guest-facing function in the tree with "__attribute__ is not a
type name".

Set the IntelliSense mode, compiler path and C++ standard to match the
compiler the build actually uses, and export a compile database for it to
read.

* vscode: resolve the clang toolchain through the VS developer environment

The IntelliSense settings named a specific Visual Studio install, so the
compiler and Ninja only resolved on machines with VS 18 Community under
Program Files. Let CMake Tools source the developer environment instead,
which locates the toolchain through vswhere, and drop the explicit
compilerPath so cpptools takes the compiler from compile_commands.json.

Also point C_Cpp.default.compileCommands at the build directory this
workspace actually configures, and drop CMAKE_EXPORT_COMPILE_COMMANDS
because CMake Tools already exports the database by default.
2026-09-17 11:38:40 +04:00
nmzik 0627e23e92 coderabbit: make it quieter 2026-09-17 11:26:44 +04:00
110 changed files with 2477 additions and 2740 deletions

No files matched your search

+37
View File
@@ -0,0 +1,37 @@
# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
# Keep inherited review profiles, automatic reviews, tools, and pre-merge checks.
inheritance: true
reviews:
# Trim supplemental output and keep the remaining walkthrough collapsed.
high_level_summary: false
review_status: false
review_details: false
collapse_walkthrough: true
changed_files_summary: false
sequence_diagrams: false
estimate_code_review_effort: false
related_issues: false
related_prs: false
in_progress_fortune: false
poem: false
enable_prompt_for_ai_agents: false
# Hide standard finishing-touch controls; this also disables their commands.
finishing_touches:
docstrings:
enabled: false
unit_tests:
enabled: false
simplify:
enabled: false
autofix:
enabled: false
fix_ci:
enabled: false
resolve_merge_conflict:
enabled: false
chat:
art: false
+6 -4
View File
@@ -2,15 +2,17 @@
"cmake.sourceDirectory": "${workspaceFolder}",
"cmake.buildDirectory": "${workspaceFolder}/_Build/vscode-clang",
"cmake.generator": "Ninja",
"cmake.useVsDeveloperEnvironment": "always",
"cmake.environment": {
"CC": "clang-cl",
"CXX": "clang-cl",
"PATH": "${env:ProgramFiles}/Microsoft Visual Studio/18/Community/VC/Tools/Llvm/x64/bin;${env:ProgramFiles}/Microsoft Visual Studio/18/Community/Common7/IDE/CommonExtensions/Microsoft/CMake/Ninja;${env:PATH}"
"CXX": "clang-cl"
},
"cmake.configureSettings": {
"CMAKE_C_COMPILER": "clang-cl",
"CMAKE_CXX_COMPILER": "clang-cl",
"CMAKE_PREFIX_PATH": "C:/Qt/6.11.0/msvc2022_64"
}
},
"C_Cpp.default.intelliSenseMode": "windows-clang-x64",
"C_Cpp.default.compileCommands": "${workspaceFolder}/_Build/vscode-clang/compile_commands.json",
"C_Cpp.default.cppStandard": "c++20"
}
+1
View File
@@ -137,6 +137,7 @@ the Vulkan/SPIR-V validation rules.
- Visual Studio 2022 or Build Tools 2022 with the **Desktop development with C++** workload and
**C++ Clang tools for Windows** component
- Qt 6 for MSVC 2022 64-bit, including Concurrent, Network, and Widgets
- [glslang](https://github.com/KhronosGroup/glslang/releases) (`glslangValidator`) on `PATH`
The Microsoft C++ compiler (`cl.exe`) is not supported; use `clang-cl`.
-166
View File
@@ -1,166 +0,0 @@
#ifndef KYTY_COMMON_BYTEBUFFER_H_
#define KYTY_COMMON_BYTEBUFFER_H_
#include "common/assert.h"
#include "common/common.h"
#include <algorithm>
#include <cstddef> // IWYU pragma: export
#include <cstring>
#include <utility>
#include <vector>
namespace Common {
using Byte = std::byte;
class ByteBuffer {
public:
using DataType = std::vector<Byte>;
static constexpr uint32_t INVALID_INDEX = static_cast<uint32_t>(-1);
using iterator = DataType::iterator;
using const_iterator = DataType::const_iterator;
ByteBuffer() = default;
ByteBuffer(const ByteBuffer&) = default;
ByteBuffer(ByteBuffer&&) = default;
ByteBuffer& operator=(const ByteBuffer&) = default;
ByteBuffer& operator=(ByteBuffer&&) = default;
explicit ByteBuffer(uint32_t size): m_data(size) {}
ByteBuffer(std::initializer_list<uint8_t> list) {
for (const uint8_t& e: list) {
m_data.emplace_back(static_cast<Byte>(e));
}
}
explicit ByteBuffer(const void* buf, uint32_t size)
: ByteBuffer(size) // @suppress("Ambiguous problem")
{
EXIT_IF(buf == nullptr && size != 0);
if (size != 0) {
std::memcpy(m_data.data(), buf, size);
}
}
[[nodiscard]] uint32_t Size() const { return static_cast<uint32_t>(m_data.size()); }
[[nodiscard]] bool IsEmpty() const { return m_data.empty(); }
void Clear() { m_data.clear(); }
void Add(const Byte& val) { m_data.push_back(val); }
void Add(Byte&& val) { m_data.push_back(std::move(val)); }
void Add(const Byte* val, uint32_t num) {
EXIT_IF(val == nullptr && num != 0);
m_data.insert(m_data.end(), val, val + num);
}
void Add(const ByteBuffer& v) {
if (this == &v) {
const ByteBuffer copy(v);
Add(copy.GetDataConst(), copy.Size());
return;
}
Add(v.GetDataConst(), v.Size());
}
void InsertAt(uint32_t index, const Byte& val) {
EXIT_IF(index > Size());
m_data.insert(m_data.begin() + index, val);
}
void InsertAt(uint32_t index, Byte&& val) {
EXIT_IF(index > Size());
m_data.insert(m_data.begin() + index, std::move(val));
}
[[nodiscard]] uint32_t Find(const Byte& t) const {
const auto it = std::find(m_data.begin(), m_data.end(), t);
return (it == m_data.end() ? INVALID_INDEX
: static_cast<uint32_t>(std::distance(m_data.begin(), it)));
}
[[nodiscard]] bool Contains(const Byte& t) const { return Find(t) != INVALID_INDEX; }
bool Remove(const Byte& t) {
const auto it = std::find(m_data.begin(), m_data.end(), t);
if (it == m_data.end()) {
return false;
}
m_data.erase(it);
return true;
}
bool RemoveAt(uint32_t index, uint32_t count = 1) {
if (index >= Size() || count == 0) {
return false;
}
const uint32_t erase_count = std::min(count, Size() - index);
m_data.erase(m_data.begin() + index, m_data.begin() + index + erase_count);
return true;
}
[[nodiscard]] bool IndexValid(uint32_t index) const { return index < Size(); }
Byte& operator[](uint32_t index) {
EXIT_IF(index >= Size());
return m_data[index];
}
const Byte& operator[](uint32_t index) const {
EXIT_IF(index >= Size());
return m_data[index];
}
[[nodiscard]] const Byte& At(uint32_t index) const {
EXIT_IF(index >= Size());
return m_data[index];
}
Byte* GetData() { return m_data.data(); }
[[nodiscard]] const Byte* GetData() const { return m_data.data(); }
[[nodiscard]] const Byte* GetDataConst() const { return m_data.data(); }
void Sort() {
std::sort(m_data.begin(), m_data.end(), [](Byte a, Byte b) {
return std::to_integer<uint8_t>(a) < std::to_integer<uint8_t>(b);
});
}
template <typename OP>
void Sort(OP&& comp_func) {
std::sort(m_data.begin(), m_data.end(), std::forward<OP>(comp_func));
}
bool operator==(const ByteBuffer& s) const { return m_data == s.m_data; }
bool operator!=(const ByteBuffer& s) const { return !(*this == s); }
iterator begin() { return m_data.begin(); } // NOLINT(readability-identifier-naming)
iterator end() { return m_data.end(); } // NOLINT(readability-identifier-naming)
[[nodiscard]] const_iterator begin() const {
return m_data.begin();
} // NOLINT(readability-identifier-naming)
[[nodiscard]] const_iterator end() const {
return m_data.end();
} // NOLINT(readability-identifier-naming)
[[nodiscard]] const_iterator cbegin() const {
return m_data.cbegin();
} // NOLINT(readability-identifier-naming)
[[nodiscard]] const_iterator cend() const {
return m_data.cend();
} // NOLINT(readability-identifier-naming)
private:
DataType m_data;
};
} // namespace Common
#endif /* KYTY_COMMON_BYTEBUFFER_H_ */
-4
View File
@@ -24,8 +24,4 @@ std::string Debug::GetLinker() {
#endif
}
std::string Debug::GetBitness() {
return "64";
}
} // namespace Common
-1
View File
@@ -10,7 +10,6 @@ namespace Common {
namespace Debug {
std::string GetCompiler();
std::string GetLinker();
std::string GetBitness();
} // namespace Debug
} // namespace Common
+13 -28
View File
@@ -136,10 +136,6 @@ bool File::OpenInMem(void* buf, uint32_t buf_size) {
return true;
}
bool File::OpenInMem(ByteBuffer& buf) {
return OpenInMem(buf.GetData(), buf.Size());
}
bool File::CreateInMem() {
EXIT_IF(m_p->f != nullptr);
@@ -251,8 +247,8 @@ void File::Printf(const char* format, ...) {
bool File::IsDirectoryExisting(const std::filesystem::path& path) {
auto path_str = PathToGenericString(path);
return SysFileIsDirectoryExisting(
Common::EndsWith(path_str, "/") ? Common::RemoveLast(path_str, 1) : path_str);
return SysFileIsDirectoryExisting(path_str.ends_with("/") ? Common::RemoveLast(path_str, 1)
: path_str);
}
bool File::IsFileExisting(const std::filesystem::path& name) {
@@ -263,14 +259,14 @@ bool File::CreateDirectory(
const std::filesystem::path& path) // @suppress("Member declaration not found")
{
auto path_str = PathToGenericString(path);
return SysFileCreateDirectory(Common::EndsWith(path_str, "/") ? Common::RemoveLast(path_str, 1)
: path_str);
return SysFileCreateDirectory(path_str.ends_with("/") ? Common::RemoveLast(path_str, 1)
: path_str);
}
bool File::DeleteDirectory(const std::filesystem::path& path) {
auto path_str = PathToGenericString(path);
return SysFileDeleteDirectory(Common::EndsWith(path_str, "/") ? Common::RemoveLast(path_str, 1)
: path_str);
return SysFileDeleteDirectory(path_str.ends_with("/") ? Common::RemoveLast(path_str, 1)
: path_str);
}
bool File::CreateDirectories(const std::filesystem::path& path) {
@@ -283,7 +279,7 @@ bool File::CreateDirectories(const std::filesystem::path& path) {
for (uint32_t si = 0; si < list.size(); si++) {
const std::string& s = list[si];
if (si != 0 || Common::StartsWith(real_path, "/")) {
if (si != 0 || real_path.starts_with("/")) {
p += "/";
}
@@ -313,7 +309,7 @@ bool File::DeleteDirectories(const std::filesystem::path& path) {
for (uint32_t si = 0; si < list.size(); si++) {
const std::string& s = list[si];
if (si != 0 || Common::StartsWith(real_path, "/")) {
if (si != 0 || real_path.starts_with("/")) {
p += "/";
}
@@ -345,7 +341,7 @@ bool File::Flush() {
return SysFileFlush(*m_p->f);
}
ByteBuffer File::ReadWholeBuffer() {
std::vector<std::byte> File::ReadWholeBuffer() {
EXIT_IF(IsInvalid());
EXIT_IF(Tell() != 0);
@@ -353,25 +349,14 @@ ByteBuffer File::ReadWholeBuffer() {
EXIT_IF((s >> 32u) != 0);
ByteBuffer buf(s);
const auto read_size = static_cast<uint32_t>(s);
std::vector<std::byte> buf(read_size);
Read(buf.GetData(), s);
Read(buf.data(), read_size);
return buf;
}
ByteBuffer File::Read(uint32_t size) {
ByteBuffer buf(size);
uint32_t b = 0;
Read(buf.GetData(), size, &b);
buf.RemoveAt(b, size - b);
return buf;
}
void File::Write(const ByteBuffer& buf, uint32_t* bytes_written) {
Write(buf.GetDataConst(), buf.Size(), bytes_written);
}
DateTime File::GetLastAccessTimeUTC(const std::filesystem::path& name) {
SysTimeStruct t {};
SysFileToSystemTimeUtc(SysFileGetLastAccessTimeUtc(name), t);
@@ -478,7 +463,7 @@ std::vector<File::FindInfo> File::FindFiles(const std::filesystem::path& path) {
auto path_str = PathToGenericString(path);
uint32_t len = static_cast<uint32_t>(path_str.size());
if (!Common::EndsWith(path_str, "/") && !Common::EndsWith(path_str, "\\")) {
if (!path_str.ends_with("/") && !path_str.ends_with("\\")) {
len++;
}
+4 -7
View File
@@ -1,10 +1,10 @@
#ifndef KYTY_COMMON_FILE_H_
#define KYTY_COMMON_FILE_H_
#include "common/byteBuffer.h"
#include "common/common.h"
#include "common/dateTime.h"
#include <cstddef>
#include <filesystem>
#include <memory>
#include <string>
@@ -51,7 +51,6 @@ public:
bool Create(const std::filesystem::path& name);
bool Open(const std::filesystem::path& name, Mode mode);
bool OpenInMem(void* buf, uint32_t buf_size);
bool OpenInMem(ByteBuffer& buf); // NOLINT(google-runtime-references)
bool CreateInMem();
void Close();
@@ -73,14 +72,12 @@ public:
void GetLastAccessAndWriteTimeUTC(DateTime* access, DateTime* write);
void Read(void* data, uint32_t size, uint32_t* bytes_read = nullptr);
ByteBuffer Read(uint32_t size);
void Write(const void* data, uint32_t size, uint32_t* bytes_written = nullptr);
void Write(const ByteBuffer& buf, uint32_t* bytes_written = nullptr);
void Read(void* data, uint32_t size, uint32_t* bytes_read = nullptr);
void Write(const void* data, uint32_t size, uint32_t* bytes_written = nullptr);
void Printf(const char* format, ...) KYTY_FORMAT_PRINTF(2, 3);
ByteBuffer ReadWholeBuffer();
std::vector<std::byte> ReadWholeBuffer();
static uint64_t Size(const std::filesystem::path& name);
-97
View File
@@ -54,103 +54,6 @@ inline uint32_t hash(const void* key, uint32_t key_len) {
return hash;
}
inline uint32_t hash8(uint8_t key) {
uint32_t hash = 0;
uint8_t* ptr = &key;
hash += ptr[0];
hash += (hash << 10u);
hash ^= (hash >> 6u);
hash += (hash << 3u);
hash ^= (hash >> 11u);
hash += (hash << 15u);
return hash;
}
inline uint32_t hash16(uint16_t key) {
uint32_t hash = 0;
auto* ptr = reinterpret_cast<uint8_t*>(&key);
hash += ptr[0];
hash += (hash << 10u);
hash ^= (hash >> 6u);
hash += ptr[1];
hash += (hash << 10u);
hash ^= (hash >> 6u);
hash += (hash << 3u);
hash ^= (hash >> 11u);
hash += (hash << 15u);
return hash;
}
inline uint32_t hash32(uint32_t key) {
uint32_t hash = 0;
auto* ptr = reinterpret_cast<uint8_t*>(&key);
hash += ptr[0];
hash += (hash << 10u);
hash ^= (hash >> 6u);
hash += ptr[1];
hash += (hash << 10u);
hash ^= (hash >> 6u);
hash += ptr[2];
hash += (hash << 10u);
hash ^= (hash >> 6u);
hash += ptr[3];
hash += (hash << 10u);
hash ^= (hash >> 6u);
hash += (hash << 3u);
hash ^= (hash >> 11u);
hash += (hash << 15u);
return hash;
}
inline uint32_t hash64(uint64_t key) {
uint32_t hash = 0;
auto* ptr = reinterpret_cast<uint8_t*>(&key);
hash += ptr[0];
hash += (hash << 10u);
hash ^= (hash >> 6u);
hash += ptr[1];
hash += (hash << 10u);
hash ^= (hash >> 6u);
hash += ptr[2];
hash += (hash << 10u);
hash ^= (hash >> 6u);
hash += ptr[3];
hash += (hash << 10u);
hash ^= (hash >> 6u);
hash += ptr[4];
hash += (hash << 10u);
hash ^= (hash >> 6u);
hash += ptr[5];
hash += (hash << 10u);
hash ^= (hash >> 6u);
hash += ptr[6];
hash += (hash << 10u);
hash ^= (hash >> 6u);
hash += ptr[7];
hash += (hash << 10u);
hash ^= (hash >> 6u);
hash += (hash << 3u);
hash ^= (hash >> 11u);
hash += (hash << 15u);
return hash;
}
} // namespace Common
#endif /* KYTY_COMMON_HASH_H_ */
-42
View File
@@ -1,42 +0,0 @@
#ifndef KYTY_COMMON_MAGICENUM_H_
#define KYTY_COMMON_MAGICENUM_H_
#include "common/common.h"
#include "common/stringUtils.h"
#include "magic_enum.hpp" // IWYU pragma: export
namespace Common {
template <typename E>
inline std::string EnumName(E v) {
auto str = magic_enum::enum_name(v);
return std::string(str.data(), str.length());
}
template <typename E>
inline std::string EnumName8(E v) {
auto str = magic_enum::enum_name(v);
return std::string(str.data(), str.length());
}
template <typename E>
inline E EnumValue(const std::string& str, E default_value) {
auto v = magic_enum::enum_cast<E>(str.c_str());
if (v.has_value()) {
return v.value();
}
return default_value;
}
#define KYTY_ENUM_RANGE(e, mx, mn) \
namespace magic_enum::customize { \
template <> \
struct enum_range<e> { \
static constexpr int min = (mx); \
static constexpr int max = (mn); \
}; \
}
} // namespace Common
#endif /* KYTY_COMMON_MAGICENUM_H_ */
-1
View File
@@ -52,7 +52,6 @@ uint64_t SysFileTell(sys_file_t& f); // NOLINT(google-runt
bool SysFileTruncate(sys_file_t& f, uint64_t size); // NOLINT(google-runtime-references)
bool SysFileUnlink(sys_file_t& f,
const std::filesystem::path& name); // NOLINT(google-runtime-references)
void SysFileWrite(uint32_t n, sys_file_t& f); // NOLINT(google-runtime-references)
uint64_t SysFileSize(const std::filesystem::path& file_name);
bool SysFileIsError(sys_file_t& f); // NOLINT(google-runtime-references)
bool SysFileIsDirectoryExisting(const std::filesystem::path& path);
+1 -4
View File
@@ -11,6 +11,7 @@
#include <cerrno>
#include <cstdlib>
#include <cstring>
#include <dirent.h>
#include <fcntl.h>
#include <filesystem>
@@ -151,10 +152,6 @@ void SysFileWrite(const void* data, uint32_t size, sys_file_t& f, uint32_t* byte
}
}
void SysFileWrite(uint32_t n, sys_file_t& f) {
SysFileWrite(&n, 4, f);
}
sys_file_t* SysFileCreate(const std::filesystem::path& file_name) {
auto* ret = new sys_file_t;
+29 -31
View File
@@ -5,7 +5,6 @@
#else
#include "common/assert.h"
#include "common/platform/sysVirtual.h"
#include "common/virtualMemory.h"
#include <atomic>
@@ -28,12 +27,12 @@
#define KYTY_FIXED_NOREPLACE
#endif
namespace Common {
namespace Common::VirtualMemory {
static pthread_mutex_t g_virtual_mutex {};
static std::map<uintptr_t, size_t>* g_allocs = nullptr;
void SysVirtualInit() {
void Init() {
pthread_mutexattr_t attr {};
pthread_mutexattr_init(&attr);
@@ -48,19 +47,19 @@ void SysVirtualInit() {
g_allocs = new std::map<uintptr_t, size_t>;
}
static int get_protection_flag(VirtualMemory::Mode mode) {
static int get_protection_flag(Mode mode) {
int protect = PROT_NONE;
switch (mode) {
case VirtualMemory::Mode::Read: protect = PROT_READ; break;
case VirtualMemory::Mode::Write:
case VirtualMemory::Mode::ReadWrite: protect = PROT_READ | PROT_WRITE; break; // NOLINT
case VirtualMemory::Mode::Execute: protect = PROT_EXEC; break;
case VirtualMemory::Mode::ExecuteRead: protect = PROT_EXEC | PROT_READ; break; // NOLINT
case VirtualMemory::Mode::ExecuteWrite:
case VirtualMemory::Mode::ExecuteReadWrite:
case Mode::Read: protect = PROT_READ; break;
case Mode::Write:
case Mode::ReadWrite: protect = PROT_READ | PROT_WRITE; break; // NOLINT
case Mode::Execute: protect = PROT_EXEC; break;
case Mode::ExecuteRead: protect = PROT_EXEC | PROT_READ; break; // NOLINT
case Mode::ExecuteWrite:
case Mode::ExecuteReadWrite:
protect = PROT_EXEC | PROT_WRITE | PROT_READ;
break; // NOLINT
case VirtualMemory::Mode::NoAccess:
case Mode::NoAccess:
default: protect = PROT_NONE; break;
}
return protect;
@@ -130,7 +129,7 @@ static void* map_anonymous(uintptr_t addr, size_t size, int protect, int flags)
return mmap(nullptr, size, protect, flags, -1, 0); // NOLINT
}
uint64_t SysVirtualAlloc(uint64_t address, uint64_t size, VirtualMemory::Mode mode) {
uint64_t Alloc(uint64_t address, uint64_t size, Mode mode) {
EXIT_IF(g_allocs == nullptr);
auto addr = static_cast<uintptr_t>(address);
@@ -154,8 +153,7 @@ static uintptr_t align_up(uintptr_t addr, uint64_t alignment) {
return (addr + alignment - 1) & ~(alignment - 1);
}
uint64_t SysVirtualAllocAligned(uint64_t address, uint64_t size, VirtualMemory::Mode mode,
uint64_t alignment) {
uint64_t AllocAligned(uint64_t address, uint64_t size, Mode mode, uint64_t alignment) {
if (alignment == 0) {
return 0;
}
@@ -224,7 +222,7 @@ uint64_t SysVirtualAllocAligned(uint64_t address, uint64_t size, VirtualMemory::
}
if (ptr == MAP_FAILED) {
return SysVirtualAllocAligned(address, size, mode, alignment << 1u);
return AllocAligned(address, size, mode, alignment << 1u);
}
pthread_mutex_lock(&g_virtual_mutex);
@@ -281,7 +279,7 @@ static bool is_mapped(void* ptr, size_t length) {
}
#endif
bool SysVirtualAllocFixed(uint64_t address, uint64_t size, VirtualMemory::Mode mode) {
bool AllocFixed(uint64_t address, uint64_t size, Mode mode) {
EXIT_IF(g_allocs == nullptr);
auto addr = static_cast<uintptr_t>(address);
@@ -318,15 +316,15 @@ bool SysVirtualAllocFixed(uint64_t address, uint64_t size, VirtualMemory::Mode m
return false;
}
bool SysVirtualCommit(uint64_t address, uint64_t size, VirtualMemory::Mode mode) {
return SysVirtualProtect(address, size, mode);
bool Commit(uint64_t address, uint64_t size, Mode mode) {
return Protect(address, size, mode);
}
uint64_t SysVirtualReserve(uint64_t address, uint64_t size) {
return SysVirtualReserveAligned(address, size, 1);
uint64_t Reserve(uint64_t address, uint64_t size) {
return ReserveAligned(address, size, 1);
}
uint64_t SysVirtualReserveAligned(uint64_t address, uint64_t size, uint64_t alignment) {
uint64_t ReserveAligned(uint64_t address, uint64_t size, uint64_t alignment) {
if (alignment == 0) {
return 0;
}
@@ -395,7 +393,7 @@ uint64_t SysVirtualReserveAligned(uint64_t address, uint64_t size, uint64_t alig
}
if (ptr == MAP_FAILED) {
return SysVirtualReserveAligned(address, size, alignment << 1u);
return ReserveAligned(address, size, alignment << 1u);
}
pthread_mutex_lock(&g_virtual_mutex);
@@ -405,7 +403,7 @@ uint64_t SysVirtualReserveAligned(uint64_t address, uint64_t size, uint64_t alig
return ret_addr;
}
bool SysVirtualReserveFixed(uint64_t address, uint64_t size) {
bool ReserveFixed(uint64_t address, uint64_t size) {
EXIT_IF(g_allocs == nullptr);
auto addr = static_cast<uintptr_t>(address);
@@ -441,9 +439,9 @@ bool SysVirtualReserveFixed(uint64_t address, uint64_t size) {
return false;
}
bool SysVirtualDecommit(uint64_t address, uint64_t size) {
bool Decommit(uint64_t address, uint64_t size) {
// Drop physical pages while preserving the reservation.
if (!SysVirtualProtect(address, size, VirtualMemory::Mode::NoAccess)) {
if (!Protect(address, size, Mode::NoAccess)) {
return false;
}
@@ -467,7 +465,7 @@ bool SysVirtualDecommit(uint64_t address, uint64_t size) {
return true;
}
bool SysVirtualFree(uint64_t address) {
bool Free(uint64_t address) {
EXIT_IF(g_allocs == nullptr);
size_t size = 0;
@@ -487,7 +485,7 @@ bool SysVirtualFree(uint64_t address) {
return munmap(reinterpret_cast<void*>(addr), size) == 0;
}
bool SysVirtualFreeRange(uint64_t address, uint64_t size) {
bool FreeRange(uint64_t address, uint64_t size) {
EXIT_IF(g_allocs == nullptr);
if (size == 0 || (address & 0xfffu) != 0 || (size & 0xfffu) != 0) {
return false;
@@ -543,7 +541,7 @@ bool SysVirtualFreeRange(uint64_t address, uint64_t size) {
return true;
}
bool SysVirtualProtect(uint64_t address, uint64_t size, VirtualMemory::Mode mode) {
bool Protect(uint64_t address, uint64_t size, Mode mode) {
const auto addr = static_cast<uintptr_t>(address);
const auto page_start = addr >> 12u;
const auto page_end = (addr + size - 1) >> 12u;
@@ -551,10 +549,10 @@ bool SysVirtualProtect(uint64_t address, uint64_t size, VirtualMemory::Mode mode
get_protection_flag(mode)) == 0;
}
bool SysVirtualFlushInstructionCache(uint64_t /*address*/, uint64_t /*size*/) {
bool FlushInstructionCache(uint64_t /*address*/, uint64_t /*size*/) {
return true;
}
} // namespace Common
} // namespace Common::VirtualMemory
#endif
-53
View File
@@ -1,53 +0,0 @@
#ifndef KYTY_COMMON_PLATFORM_SYSSWAPBYTEORDER_H_
#define KYTY_COMMON_PLATFORM_SYSSWAPBYTEORDER_H_
#include "common/common.h"
#include <type_traits>
inline uint16_t SwapByteOrder16(uint16_t value) {
uint16_t hi = value << 8u;
uint16_t lo = value >> 8u;
return hi | lo;
}
inline uint32_t SwapByteOrder32(uint32_t value) {
return __builtin_bswap32(value);
}
inline uint64_t SwapByteOrder64(uint64_t value) {
return __builtin_bswap64(value);
}
template <typename T>
inline void SwapByteOrder(T& x) {
if (sizeof(x) == 2) {
if (std::is_signed_v<T>) {
x = static_cast<std::make_signed_t<T>>(
SwapByteOrder16(static_cast<std::make_unsigned_t<uint16_t>>(x)));
} else {
x = SwapByteOrder16(x);
}
}
if (sizeof(x) == 4) {
if (std::is_signed_v<T>) {
x = static_cast<std::make_signed_t<T>>(
SwapByteOrder32(static_cast<std::make_unsigned_t<uint32_t>>(x)));
} else {
x = SwapByteOrder32(x);
}
}
if (sizeof(x) == 8) {
if (std::is_signed_v<T>) {
x = static_cast<std::make_signed_t<T>>(
SwapByteOrder64(static_cast<std::make_unsigned_t<uint64_t>>(x)));
} else {
x = SwapByteOrder64(x);
}
}
}
template <typename T>
inline void NoSwapByteOrder(T& x) {}
#endif /* KYTY_COMMON_PLATFORM_SYSSWAPBYTEORDER_H_ */
+1 -5
View File
@@ -151,10 +151,6 @@ inline void SysTimeTToSystem(time_t t, SysTimeStruct& s) {
SysFileToSystemTimeUtc(ft, s);
}
inline time_t SysTimegm(struct tm* tm) {
return timegm(tm);
}
inline void SysSystemToFileTimeUtc(const SysTimeStruct& f, SysFileTimeStruct& t) {
struct tm i {};
@@ -165,7 +161,7 @@ inline void SysSystemToFileTimeUtc(const SysTimeStruct& f, SysFileTimeStruct& t)
i.tm_min = f.Minute;
i.tm_sec = f.Second;
t.is_invalid = (f.is_invalid || (t.time = SysTimegm(&i)) == static_cast<time_t>(-1));
t.is_invalid = (f.is_invalid || (t.time = ::timegm(&i)) == static_cast<time_t>(-1));
}
// Retrieves the current local date and time.
-27
View File
@@ -1,27 +0,0 @@
#ifndef KYTY_COMMON_PLATFORM_SYSVIRTUAL_H_
#define KYTY_COMMON_PLATFORM_SYSVIRTUAL_H_
#include "common/common.h"
#include "common/virtualMemory.h"
namespace Common {
void SysVirtualInit();
uint64_t SysVirtualAlloc(uint64_t address, uint64_t size, VirtualMemory::Mode mode);
uint64_t SysVirtualAllocAligned(uint64_t address, uint64_t size, VirtualMemory::Mode mode,
uint64_t alignment);
bool SysVirtualAllocFixed(uint64_t address, uint64_t size, VirtualMemory::Mode mode);
bool SysVirtualCommit(uint64_t address, uint64_t size, VirtualMemory::Mode mode);
uint64_t SysVirtualReserve(uint64_t address, uint64_t size);
uint64_t SysVirtualReserveAligned(uint64_t address, uint64_t size, uint64_t alignment);
bool SysVirtualReserveFixed(uint64_t address, uint64_t size);
bool SysVirtualDecommit(uint64_t address, uint64_t size);
bool SysVirtualFree(uint64_t address);
bool SysVirtualFreeRange(uint64_t address, uint64_t size);
bool SysVirtualProtect(uint64_t address, uint64_t size, VirtualMemory::Mode mode);
bool SysVirtualFlushInstructionCache(uint64_t address, uint64_t size);
} // namespace Common
#endif /* KYTY_COMMON_PLATFORM_SYSVIRTUAL_H_ */
+3 -6
View File
@@ -14,6 +14,7 @@
#include "common/stringUtils.h"
#include <cstdlib>
#include <cstring>
#include <vector>
// NOLINTNEXTLINE(readability-identifier-naming)
@@ -135,10 +136,6 @@ void SysFileWrite(const void* data, uint32_t size, sys_file_t& f, uint32_t* byte
}
}
void SysFileWrite(uint32_t n, sys_file_t& f) {
SysFileWrite(&n, 4, f);
}
sys_file_t* SysFileCreate(const std::filesystem::path& file_name) {
auto* ret = new sys_file_t;
@@ -481,7 +478,7 @@ bool SysFileSetLastAccessAndWriteTimeUtc(const std::filesystem::path& name,
void SysFileFindFiles(const std::filesystem::path& path, std::vector<sys_file_find_t>& out) {
std::string real_path = Common::ReplaceChar(Common::PathToGenericString(path), '\\', '/');
if (!Common::EndsWith(real_path, "/")) {
if (!real_path.ends_with("/")) {
real_path += "/";
}
@@ -528,7 +525,7 @@ void SysFileFindFiles(const std::filesystem::path& path, std::vector<sys_file_fi
void SysFileGetDents(const std::filesystem::path& path, std::vector<sys_dir_entry_t>& out) {
std::string real_path = Common::ReplaceChar(Common::PathToGenericString(path), '\\', '/');
if (!Common::EndsWith(real_path, "/")) {
if (!real_path.ends_with("/")) {
real_path += "/";
}
+31 -33
View File
@@ -10,7 +10,6 @@
#include <windows.h> // IWYU pragma: keep
#include "common/assert.h"
#include "common/platform/sysVirtual.h"
#include "common/virtualMemory.h"
// IWYU pragma: no_include <basetsd.h>
@@ -22,33 +21,33 @@
// IWYU pragma: no_include <winerror.h>
// IWYU pragma: no_include <wtypes.h>
namespace Common {
namespace Common::VirtualMemory {
static DWORD GetProtectionFlag(VirtualMemory::Mode mode) {
static DWORD GetProtectionFlag(Mode mode) {
DWORD protect = PAGE_NOACCESS;
switch (mode) {
case VirtualMemory::Mode::Read: protect = PAGE_READONLY; break;
case Mode::Read: protect = PAGE_READONLY; break;
case VirtualMemory::Mode::Write:
case VirtualMemory::Mode::ReadWrite: protect = PAGE_READWRITE; break;
case Mode::Write:
case Mode::ReadWrite: protect = PAGE_READWRITE; break;
case VirtualMemory::Mode::Execute: protect = PAGE_EXECUTE; break;
case Mode::Execute: protect = PAGE_EXECUTE; break;
case VirtualMemory::Mode::ExecuteRead: protect = PAGE_EXECUTE_READ; break;
case Mode::ExecuteRead: protect = PAGE_EXECUTE_READ; break;
case VirtualMemory::Mode::ExecuteWrite:
case VirtualMemory::Mode::ExecuteReadWrite: protect = PAGE_EXECUTE_READWRITE; break;
case Mode::ExecuteWrite:
case Mode::ExecuteReadWrite: protect = PAGE_EXECUTE_READWRITE; break;
case VirtualMemory::Mode::NoAccess:
case Mode::NoAccess:
default: protect = PAGE_NOACCESS; break;
}
return protect;
}
void SysVirtualInit() {}
void Init() {}
uint64_t SysVirtualAlloc(uint64_t address, uint64_t size, VirtualMemory::Mode mode) {
auto ptr = (address == 0 ? SysVirtualAllocAligned(address, size, mode, 1)
uint64_t Alloc(uint64_t address, uint64_t size, Mode mode) {
auto ptr = (address == 0 ? AllocAligned(address, size, mode, 1)
: reinterpret_cast<uintptr_t>(VirtualAlloc(
reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), size,
static_cast<DWORD>(MEM_COMMIT) | static_cast<DWORD>(MEM_RESERVE),
@@ -59,7 +58,7 @@ uint64_t SysVirtualAlloc(uint64_t address, uint64_t size, VirtualMemory::Mode mo
if (err != ERROR_INVALID_ADDRESS) {
printf("VirtualAlloc() failed: 0x%08" PRIx32 "\n", err);
} else {
return SysVirtualAllocAligned(address, size, mode, 1);
return AllocAligned(address, size, mode, 1);
}
}
return ptr;
@@ -80,8 +79,7 @@ static uint64_t AlignUp(uint64_t addr, uint64_t alignment) {
return (addr + alignment - 1) & ~(alignment - 1);
}
uint64_t SysVirtualAllocAligned(uint64_t address, uint64_t size, VirtualMemory::Mode mode,
uint64_t alignment) {
uint64_t AllocAligned(uint64_t address, uint64_t size, Mode mode, uint64_t alignment) {
if (alignment == 0) {
printf("VirtualAlloc2 failed: 0x%08" PRIx32 "\n", static_cast<uint32_t>(GetLastError()));
return 0;
@@ -135,13 +133,13 @@ uint64_t SysVirtualAllocAligned(uint64_t address, uint64_t size, VirtualMemory::
printf("VirtualAlloc2(alignment = 0x%016" PRIx64 ") failed: 0x%08" PRIx32 "\n",
alignment, err);
} else {
return SysVirtualAllocAligned(address, size, mode, alignment << 1u);
return AllocAligned(address, size, mode, alignment << 1u);
}
}
return ptr;
}
bool SysVirtualAllocFixed(uint64_t address, uint64_t size, VirtualMemory::Mode mode) {
bool AllocFixed(uint64_t address, uint64_t size, Mode mode) {
auto ptr = reinterpret_cast<uintptr_t>(VirtualAlloc(
reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), size,
static_cast<DWORD>(MEM_COMMIT) | static_cast<DWORD>(MEM_RESERVE), GetProtectionFlag(mode)));
@@ -161,7 +159,7 @@ bool SysVirtualAllocFixed(uint64_t address, uint64_t size, VirtualMemory::Mode m
return true;
}
bool SysVirtualCommit(uint64_t address, uint64_t size, VirtualMemory::Mode mode) {
bool Commit(uint64_t address, uint64_t size, Mode mode) {
auto ptr = reinterpret_cast<uintptr_t>(
VirtualAlloc(reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), size,
static_cast<DWORD>(MEM_COMMIT), GetProtectionFlag(mode)));
@@ -179,8 +177,8 @@ bool SysVirtualCommit(uint64_t address, uint64_t size, VirtualMemory::Mode mode)
return true;
}
uint64_t SysVirtualReserve(uint64_t address, uint64_t size) {
auto ptr = (address == 0 ? SysVirtualReserveAligned(address, size, 1)
uint64_t Reserve(uint64_t address, uint64_t size) {
auto ptr = (address == 0 ? ReserveAligned(address, size, 1)
: reinterpret_cast<uintptr_t>(VirtualAlloc(
reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), size,
static_cast<DWORD>(MEM_RESERVE), PAGE_NOACCESS)));
@@ -190,13 +188,13 @@ uint64_t SysVirtualReserve(uint64_t address, uint64_t size) {
if (err != ERROR_INVALID_ADDRESS) {
printf("VirtualAlloc(MEM_RESERVE) failed: 0x%08" PRIx32 "\n", err);
} else {
return SysVirtualReserveAligned(address, size, 1);
return ReserveAligned(address, size, 1);
}
}
return ptr;
}
uint64_t SysVirtualReserveAligned(uint64_t address, uint64_t size, uint64_t alignment) {
uint64_t ReserveAligned(uint64_t address, uint64_t size, uint64_t alignment) {
if (alignment == 0) {
printf("VirtualAlloc2(MEM_RESERVE) failed: 0x%08" PRIx32 "\n",
static_cast<uint32_t>(GetLastError()));
@@ -250,13 +248,13 @@ uint64_t SysVirtualReserveAligned(uint64_t address, uint64_t size, uint64_t alig
"\n",
alignment, err);
} else {
return SysVirtualReserveAligned(address, size, alignment << 1u);
return ReserveAligned(address, size, alignment << 1u);
}
}
return ptr;
}
bool SysVirtualReserveFixed(uint64_t address, uint64_t size) {
bool ReserveFixed(uint64_t address, uint64_t size) {
auto ptr = reinterpret_cast<uintptr_t>(
VirtualAlloc(reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), size,
static_cast<DWORD>(MEM_RESERVE), PAGE_NOACCESS));
@@ -276,7 +274,7 @@ bool SysVirtualReserveFixed(uint64_t address, uint64_t size) {
return true;
}
bool SysVirtualDecommit(uint64_t address, uint64_t size) {
bool Decommit(uint64_t address, uint64_t size) {
if (VirtualFree(reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), size,
MEM_DECOMMIT) == 0) {
printf("VirtualFree(MEM_DECOMMIT) failed: 0x%08" PRIx32 "\n",
@@ -286,7 +284,7 @@ bool SysVirtualDecommit(uint64_t address, uint64_t size) {
return true;
}
bool SysVirtualFree(uint64_t address) {
bool Free(uint64_t address) {
if (VirtualFree(reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), 0, MEM_RELEASE) ==
0) {
printf("VirtualFree() failed: 0x%08" PRIx32 "\n", static_cast<uint32_t>(GetLastError()));
@@ -295,7 +293,7 @@ bool SysVirtualFree(uint64_t address) {
return true;
}
bool SysVirtualFreeRange(uint64_t address, uint64_t size) {
bool FreeRange(uint64_t address, uint64_t size) {
if (address == 0 || size == 0) {
return false;
}
@@ -313,10 +311,10 @@ bool SysVirtualFreeRange(uint64_t address, uint64_t size) {
}
current = next;
}
return current - address == size && SysVirtualFree(address);
return current - address == size && Free(address);
}
bool SysVirtualProtect(uint64_t address, uint64_t size, VirtualMemory::Mode mode) {
bool Protect(uint64_t address, uint64_t size, Mode mode) {
DWORD old_protect = 0;
if (VirtualProtect(reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), size,
GetProtectionFlag(mode), &old_protect) == 0) {
@@ -326,7 +324,7 @@ bool SysVirtualProtect(uint64_t address, uint64_t size, VirtualMemory::Mode mode
return true;
}
bool SysVirtualFlushInstructionCache(uint64_t address, uint64_t size) {
bool FlushInstructionCache(uint64_t address, uint64_t size) {
if (::FlushInstructionCache(GetCurrentProcess(),
reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)),
size) == 0) {
@@ -337,6 +335,6 @@ bool SysVirtualFlushInstructionCache(uint64_t address, uint64_t size) {
return true;
}
} // namespace Common
} // namespace Common::VirtualMemory
#endif
+2 -180
View File
@@ -1,7 +1,6 @@
#ifndef KYTY_COMMON_STRING_UTILS_H_
#define KYTY_COMMON_STRING_UTILS_H_
#include "common/byteBuffer.h"
#include "common/common.h"
#include <algorithm>
@@ -9,7 +8,6 @@
#include <charconv>
#include <codecvt>
#include <filesystem>
#include <fmt/format.h>
#include <locale>
#include <string>
#include <string_view>
@@ -18,8 +16,6 @@
namespace Common {
constexpr uint32_t FIND_INVALID_INDEX = static_cast<uint32_t>(-1);
inline std::string PathToString(const std::filesystem::path& path) {
#if defined(__cpp_char8_t)
auto u8 = path.u8string();
@@ -38,10 +34,6 @@ inline std::string PathToGenericString(const std::filesystem::path& path) {
#endif
}
inline bool IsSpace(char c) {
return std::isspace(static_cast<unsigned char>(c)) != 0;
}
inline bool EqualNoCase(std::string_view lhs, std::string_view rhs) {
if (lhs.size() != rhs.size()) {
return false;
@@ -63,65 +55,6 @@ inline std::string ToLower(std::string_view text) {
return ret;
}
inline bool ContainsStr(std::string_view text, std::string_view needle) {
return text.find(needle) != std::string_view::npos;
}
inline bool StartsWith(std::string_view text, std::string_view prefix) {
return text.starts_with(prefix);
}
inline bool StartsWith(std::string_view text, char prefix) {
return !text.empty() && text.front() == prefix;
}
inline bool EndsWith(std::string_view text, std::string_view suffix) {
return text.ends_with(suffix);
}
inline bool EndsWith(std::string_view text, char suffix) {
return !text.empty() && text.back() == suffix;
}
inline bool ContainsChar(std::string_view text, char needle) {
return text.find(needle) != std::string_view::npos;
}
inline bool IndexValid(std::string_view text, uint32_t index) {
return index < text.size();
}
inline uint32_t FindIndex(std::string_view text, std::string_view needle, size_t from = 0) {
const auto pos = text.find(needle, from);
return pos == std::string_view::npos ? FIND_INVALID_INDEX : static_cast<uint32_t>(pos);
}
inline uint32_t FindIndex(std::string_view text, char needle, size_t from = 0) {
const auto pos = text.find(needle, from);
return pos == std::string_view::npos ? FIND_INVALID_INDEX : static_cast<uint32_t>(pos);
}
inline uint32_t FindLastIndex(std::string_view text, std::string_view needle,
size_t from = FIND_INVALID_INDEX) {
if (needle.empty()) {
return 0;
}
if (from == FIND_INVALID_INDEX || from > text.size()) {
from = text.size();
}
const auto pos = text.rfind(needle, from);
return pos == std::string_view::npos ? FIND_INVALID_INDEX : static_cast<uint32_t>(pos);
}
inline uint32_t FindLastIndex(std::string_view text, char needle,
size_t from = FIND_INVALID_INDEX) {
if (from == FIND_INVALID_INDEX || from > text.size()) {
from = text.size();
}
const auto pos = text.rfind(needle, from);
return pos == std::string_view::npos ? FIND_INVALID_INDEX : static_cast<uint32_t>(pos);
}
inline std::string Mid(std::string_view text, size_t first, size_t count = std::string_view::npos) {
if (first >= text.size()) {
return {};
@@ -129,49 +62,18 @@ inline std::string Mid(std::string_view text, size_t first, size_t count = std::
return std::string(text.substr(first, count));
}
inline std::string Left(std::string_view text, size_t count) {
return Mid(text, 0, count);
}
inline std::string Right(std::string_view text, size_t count) {
if (count >= text.size()) {
return std::string(text);
}
return Mid(text, text.size() - count, count);
}
inline std::string RemoveLast(std::string_view text, size_t count) {
if (count >= text.size()) {
return {};
}
return Left(text, text.size() - count);
return std::string(text.substr(0, text.size() - count));
}
inline std::string RemoveFirst(std::string_view text, size_t count) {
if (count >= text.size()) {
return {};
}
return Right(text, text.size() - count);
}
inline std::string TrimRight(std::string_view text) {
size_t end = text.size();
while (end > 0 && IsSpace(text[end - 1])) {
end--;
}
return std::string(text.substr(0, end));
}
inline std::string TrimLeft(std::string_view text) {
size_t first = 0;
while (first < text.size() && IsSpace(text[first])) {
first++;
}
return std::string(text.substr(first));
}
inline std::string Trim(std::string_view text) {
return TrimRight(TrimLeft(text));
return std::string(text.substr(count));
}
inline std::string ReplaceChar(std::string_view text, char old_char, char new_char) {
@@ -204,16 +106,6 @@ inline std::string FilenameWithoutDirectory(std::string_view text) {
return pos == std::string_view::npos ? std::string(text) : std::string(text.substr(pos + 1));
}
inline std::string FilenameWithoutExtension(std::string_view text) {
const auto pos = text.find_last_of('.');
return pos == std::string_view::npos ? std::string(text) : std::string(text.substr(0, pos));
}
inline std::string ExtensionWithoutFilename(std::string_view text) {
const auto pos = text.find_last_of('.');
return pos == std::string_view::npos ? std::string() : std::string(text.substr(pos));
}
inline std::string FixFilenameSlash(std::string_view text) {
return ReplaceChar(text, '\\', '/');
}
@@ -257,65 +149,12 @@ inline std::vector<std::string> Split(std::string_view text, char sep, bool keep
return Split(text, std::string_view(&sep, 1), keep_empty);
}
inline std::string Concat(const std::vector<std::string>& list, std::string_view sep) {
std::string ret;
for (size_t i = 0; i < list.size(); i++) {
if (i != 0) {
ret += sep;
}
ret += list[i];
}
return ret;
}
inline std::string Concat(const std::vector<std::string>& list, char sep) {
return Concat(list, std::string_view(&sep, 1));
}
inline uint32_t ToUint32(std::string_view text, int base = 10) {
uint32_t value = 0;
std::from_chars(text.data(), text.data() + text.size(), value, base);
return value;
}
inline uint64_t ToUint64(std::string_view text, int base = 10) {
uint64_t value = 0;
std::from_chars(text.data(), text.data() + text.size(), value, base);
return value;
}
inline int32_t ToInt32(std::string_view text, int base = 10) {
int32_t value = 0;
std::from_chars(text.data(), text.data() + text.size(), value, base);
return value;
}
inline int64_t ToInt64(std::string_view text, int base = 10) {
int64_t value = 0;
std::from_chars(text.data(), text.data() + text.size(), value, base);
return value;
}
inline double ToDouble(std::string_view text) {
return std::stod(std::string(text));
}
inline float ToFloat(std::string_view text) {
return std::stof(std::string(text));
}
inline std::string SafeCsv(std::string_view text) {
const bool add_space =
!text.empty() && (text.front() == '+' || text.front() == '=' || text.front() == '-');
if (text.find('"') != std::string_view::npos || text.find(';') != std::string_view::npos ||
text.find('+') != std::string_view::npos || text.find('=') != std::string_view::npos ||
text.find('-') != std::string_view::npos) {
return "\"" + std::string(add_space ? " " : "") +
ReplaceStr(std::string(text), "\"", "\"\"") + "\"";
}
return std::string(text);
}
inline std::string Utf16ToUtf8(std::u16string_view utf16) {
if (utf16.empty()) {
return {};
@@ -324,23 +163,6 @@ inline std::string Utf16ToUtf8(std::u16string_view utf16) {
return convert.to_bytes(utf16.data(), utf16.data() + utf16.size());
}
inline ByteBuffer HexToBin(std::string_view text) {
ByteBuffer ret;
for (size_t i = 0; i + 1 < text.size(); i += 2) {
ret.Add(static_cast<Byte>((ToUint32(text.substr(i, 2), 16) & 0xffu)));
}
return ret;
}
inline std::string HexFromBin(const ByteBuffer& bin) {
std::string ret;
ret.reserve(bin.Size() * 2);
for (uint32_t i = 0; i < bin.Size(); i++) {
ret += fmt::format("{:02X}", std::to_integer<uint8_t>(bin.At(i)));
}
return ret;
}
} // namespace Common
#endif /* KYTY_COMMON_STRING_UTILS_H_ */
-4
View File
@@ -253,10 +253,6 @@ void Thread::Detach() {
m_thread->m_thread.detach();
}
void Thread::Sleep(uint32_t millis) {
std::this_thread::sleep_for(std::chrono::milliseconds(millis));
}
void Thread::SleepMicro(uint32_t micros) {
#ifdef KYTY_WIN_CS
SleepHighResolution100ns(static_cast<uint64_t>(micros) * 10);
-1
View File
@@ -31,7 +31,6 @@ public:
// The id is unique and can't be reused by another thread.
[[nodiscard]] int GetUniqueId() const;
static void Sleep(uint32_t millis);
static void SleepMicro(uint32_t micros);
static void SleepNano(uint64_t nanos);
static bool IsMainThread();
-17
View File
@@ -62,23 +62,6 @@ double Timer::GetTimeS() const {
return (static_cast<double>(current_time - m_StartTime)) / static_cast<double>(m_Frequency);
}
// return time in ticks
uint64_t Timer::GetTicks() const {
if (m_is_paused) {
return (m_PauseTime - m_StartTime);
}
uint64_t current_time = 0;
SysQueryPerformanceCounter(&current_time);
return (current_time - m_StartTime);
}
// return ticks frequency
uint64_t Timer::GetFrequency() const {
return m_Frequency;
}
uint64_t Timer::QueryPerformanceFrequency() {
uint64_t ret = 0;
SysQueryPerformanceFrequency(&ret);
-6
View File
@@ -24,12 +24,6 @@ public:
// return time in seconds
[[nodiscard]] double GetTimeS() const;
// return time in ticks
[[nodiscard]] uint64_t GetTicks() const;
// return ticks frequency
[[nodiscard]] uint64_t GetFrequency() const;
KYTY_CLASS_NO_COPY(Timer);
[[nodiscard]] static uint64_t QueryPerformanceFrequency();
-63
View File
@@ -1,63 +0,0 @@
#include "common/virtualMemory.h"
#include "common/platform/sysVirtual.h"
namespace Common {
namespace VirtualMemory {
void Init() {
SysVirtualInit();
}
uint64_t Alloc(uint64_t address, uint64_t size, Mode mode) {
return SysVirtualAlloc(address, size, mode);
}
uint64_t AllocAligned(uint64_t address, uint64_t size, Mode mode, uint64_t alignment) {
return SysVirtualAllocAligned(address, size, mode, alignment);
}
bool AllocFixed(uint64_t address, uint64_t size, Mode mode) {
return SysVirtualAllocFixed(address, size, mode);
}
bool Commit(uint64_t address, uint64_t size, Mode mode) {
return SysVirtualCommit(address, size, mode);
}
uint64_t Reserve(uint64_t address, uint64_t size) {
return SysVirtualReserve(address, size);
}
uint64_t ReserveAligned(uint64_t address, uint64_t size, uint64_t alignment) {
return SysVirtualReserveAligned(address, size, alignment);
}
bool ReserveFixed(uint64_t address, uint64_t size) {
return SysVirtualReserveFixed(address, size);
}
bool Decommit(uint64_t address, uint64_t size) {
return SysVirtualDecommit(address, size);
}
bool Free(uint64_t address) {
return SysVirtualFree(address);
}
bool FreeRange(uint64_t address, uint64_t size) {
return SysVirtualFreeRange(address, size);
}
bool Protect(uint64_t address, uint64_t size, Mode mode) {
return SysVirtualProtect(address, size, mode);
}
bool FlushInstructionCache(uint64_t address, uint64_t size) {
return SysVirtualFlushInstructionCache(address, size);
}
} // namespace VirtualMemory
} // namespace Common
+2 -10
View File
@@ -4,15 +4,12 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/profiler.h"
#include "common/stringUtils.h"
#include "graphics/guest_gpu/gpu_defs.h"
#include "graphics/guest_gpu/gpu_format.h"
#include <algorithm>
#include <array>
#include <bit>
#include <fmt/format.h>
#include <vector>
namespace Libs::Graphics {
@@ -1322,13 +1319,8 @@ void TileGetTextureSize(Prospero::BufferFormat format, uint32_t width, uint32_t
return;
}
if (total_size != nullptr && total_size->size == 0) {
std::vector<std::string> list;
list.push_back(fmt::format("format = {}", static_cast<uint32_t>(format)));
list.push_back(fmt::format("width = {}", width));
list.push_back(fmt::format("height = {}", height));
list.push_back(fmt::format("levels = {}", levels));
list.push_back(fmt::format("tile = {}", static_cast<uint32_t>(tile)));
EXIT("unknown format:\n%s\n", Common::Concat(list, '\n').c_str());
EXIT("unknown format:\nformat = %u\nwidth = %u\nheight = %u\nlevels = %u\ntile = %u\n",
static_cast<uint32_t>(format), width, height, levels, static_cast<uint32_t>(tile));
}
}
+1
View File
@@ -16,6 +16,7 @@
#include <windows.h>
#undef min
#undef max
#undef MemoryBarrier
#elif defined(__APPLE__)
#include <pthread.h>
#elif defined(__linux__)
@@ -593,6 +593,21 @@ PipelineCache::GraphicsPrograms PipelineCache::GetGraphicsPrograms(
ShaderParams pixel_params;
if (pixel_active) {
pixel_params = PrepareProgram(pixel_regs, sh, target_export_mapping, pixel_info);
const auto& blend = context.GetBlendControl(0);
const auto is_dual_source = [](uint8_t factor) {
return factor >= static_cast<uint8_t>(Prospero::BlendFactor::kSrc1Color) &&
factor <= static_cast<uint8_t>(Prospero::BlendFactor::kOneMinusSrc1Alpha);
};
pixel_info.dual_source_blending =
blend.enable && !context.GetRenderTarget(0).info.blend_bypass &&
(is_dual_source(blend.color_srcblend) || is_dual_source(blend.color_destblend) ||
(blend.separate_alpha_blend &&
(is_dual_source(blend.alpha_srcblend) || is_dual_source(blend.alpha_destblend))));
if (pixel_info.dual_source_blending) {
// MRT1 supplies a second blend source for the same render target as MRT0.
pixel_info.target_output_mode[1] = pixel_info.target_output_mode[0];
pixel_info.target_export_mapping[1] = pixel_info.target_export_mapping[0];
}
}
if (context.GetClipControl().clip_disable) {
const auto& viewport = context.GetScreenViewport().viewports[0];
@@ -46,8 +46,8 @@ vk::PipelineStageFlags ShaderPipelineStages(vk::ShaderStageFlags stages) {
return result;
}
VulkanMemoryBarrier MakeShaderWriteDependency() {
VulkanMemoryBarrier barrier {};
vk::MemoryBarrier MakeShaderWriteDependency() {
vk::MemoryBarrier barrier {};
barrier.srcAccessMask = vk::AccessFlagBits::eShaderWrite;
barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite |
vk::AccessFlagBits::eVertexAttributeRead |
@@ -58,15 +58,15 @@ VulkanMemoryBarrier MakeShaderWriteDependency() {
return barrier;
}
VulkanMemoryBarrier MakeShaderAccessDependency() {
VulkanMemoryBarrier barrier {};
vk::MemoryBarrier MakeShaderAccessDependency() {
vk::MemoryBarrier barrier {};
barrier.srcAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite;
barrier.dstAccessMask = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite;
return barrier;
}
VulkanMemoryBarrier MakeShaderWriteHazardDependency() {
VulkanMemoryBarrier barrier {};
vk::MemoryBarrier MakeShaderWriteHazardDependency() {
vk::MemoryBarrier barrier {};
barrier.srcAccessMask = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite;
barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite;
return barrier;
@@ -10,9 +10,9 @@ struct ShaderStageRuntime;
vk::ShaderStageFlagBits NativeShaderStage(ShaderType stage);
vk::PipelineStageFlags ShaderPipelineStages(vk::ShaderStageFlags stages);
VulkanMemoryBarrier MakeShaderAccessDependency();
VulkanMemoryBarrier MakeShaderWriteHazardDependency();
VulkanMemoryBarrier MakeShaderWriteDependency();
vk::MemoryBarrier MakeShaderAccessDependency();
vk::MemoryBarrier MakeShaderWriteHazardDependency();
vk::MemoryBarrier MakeShaderWriteDependency();
vk::BufferMemoryBarrier MakeGdsDependency(vk::Buffer buffer);
bool HasShaderBufferWrites(const ShaderStageRuntime& runtime);
void ShaderAccessBarrier(vk::CommandBuffer vk_buffer, vk::PipelineStageFlags source_stages);
@@ -225,7 +225,7 @@ void RenderExecutor::DispatchDirect(uint64_t submit_id, CommandBuffer& buffer,
return;
}
if (!ShaderAddressValid(sh_ctx.GetCs().cs_regs.data_addr)) {
if (sh_ctx.GetCs().cs_regs.data_addr == 0) {
return;
}
@@ -421,7 +421,7 @@ static void SetGraphicsDynamicParams(const CommandBuffer& buffer, vk::CommandBuf
static bool DrawHasValidVertexShader(const HW::Shader& sh_ctx) {
const auto& vs = sh_ctx.GetVs();
return ShaderAddressValid(vs.es_regs.data_addr);
return vs.es_regs.data_addr != 0;
}
static bool PixelShaderHasDepthOrCoverageSideEffects(const HW::ShaderRegisters& sh_regs) {
@@ -608,7 +608,7 @@ static bool DrawHasActivePixelShader(const CommandBuffer& buffer) {
const auto& ctx = buffer.GetRegisters();
const auto& sh_regs = ctx.GetShaderRegisters();
const bool has_color_output = (ctx.GetRenderTargetMask() & sh_regs.m_cbShaderMask) != 0;
return ShaderAddressValid(buffer.GetShaders().GetPs().ps_regs.data_addr) &&
return buffer.GetShaders().GetPs().ps_regs.data_addr != 0 &&
(has_color_output || PixelShaderHasDepthOrCoverageSideEffects(sh_regs));
}
-2
View File
@@ -24,8 +24,6 @@
namespace Libs::Graphics {
using VulkanMemoryBarrier = vk::MemoryBarrier;
vk::Format VulkanFormat(Prospero::BufferFormat guest_format);
void RequireVulkanSuccess(vk::Result result, const char* operation);
vk::ShaderModule CompileSPV(std::span<const uint32_t> code, vk::Device device);
@@ -22,9 +22,6 @@
// IWYU pragma: no_include <intrin.h>
#define KYTY_ENABLE_DEBUG_PRINTF
#define KYTY_DBG_INPUT
namespace Libs::Graphics {
struct Presenter::Frame {
@@ -49,7 +49,6 @@
// IWYU pragma: no_include <intrin.h>
#define KYTY_ENABLE_DEBUG_PRINTF
#define KYTY_DBG_INPUT
namespace Libs::Graphics {
@@ -611,10 +610,11 @@ static vk::Device VulkanCreateDevice(GraphicContext& graphics,
graphics.mesh_shader_properties.maxMeshOutputPrimitives,
graphics.mesh_shader_properties.maxMeshSharedMemorySize);
}
// VulkanFindPhysicalDevice already checked the required creation features. These two
// VulkanFindPhysicalDevice already checked the required creation features. These
// requirements are specific to this creation path and are not part of device selection.
EXIT_NOT_IMPLEMENTED(supported_features2.features.shaderInt64 != VK_TRUE);
EXIT_NOT_IMPLEMENTED(supported_features2.features.vertexPipelineStoresAndAtomics != VK_TRUE);
EXIT_NOT_IMPLEMENTED(supported_features2.features.dualSrcBlend != VK_TRUE);
vk::PhysicalDeviceFeatures device_features {};
device_features.fragmentStoresAndAtomics = VK_TRUE;
device_features.samplerAnisotropy = VK_TRUE;
@@ -625,6 +625,7 @@ static vk::Device VulkanCreateDevice(GraphicContext& graphics,
device_features.shaderStorageImageWriteWithoutFormat = VK_TRUE;
device_features.shaderImageGatherExtended = VK_TRUE;
device_features.independentBlend = VK_TRUE;
device_features.dualSrcBlend = VK_TRUE;
device_features.tessellationShader = VK_TRUE;
device_features.sampleRateShading = VK_TRUE;
device_features.depthBiasClamp = VK_TRUE;
+21 -15
View File
@@ -52,7 +52,6 @@
// IWYU pragma: no_include <intrin.h>
#define KYTY_ENABLE_DEBUG_PRINTF
#define KYTY_DBG_INPUT
namespace Libs::Graphics {
@@ -180,12 +179,6 @@ struct EventDisplay {
DisplayOrientation orientation;
};
constexpr uint32_t KYTY_SDL_BUTTON_LMASK = SDL_BUTTON_LMASK; // NOLINT(hicpp-signed-bitwise)
constexpr uint32_t KYTY_SDL_BUTTON_MMASK = SDL_BUTTON_MMASK; // NOLINT(hicpp-signed-bitwise)
constexpr uint32_t KYTY_SDL_BUTTON_RMASK = SDL_BUTTON_RMASK; // NOLINT(hicpp-signed-bitwise)
constexpr uint32_t KYTY_SDL_BUTTON_X1MASK = SDL_BUTTON_X1MASK; // NOLINT(hicpp-signed-bitwise)
constexpr uint32_t KYTY_SDL_BUTTON_X2MASK = SDL_BUTTON_X2MASK; // NOLINT(hicpp-signed-bitwise)
namespace {
std::unique_ptr<WindowContext> g_window;
@@ -193,7 +186,6 @@ std::unique_ptr<WindowContext> g_window;
} // namespace
constexpr const char* KYTY_SDL_WINDOW_CAPTION = "Game";
constexpr int KYTY_SDL_WINDOWPOS_CENTERED = SDL_WINDOWPOS_CENTERED; /*NOLINT(hicpp-signed-bitwise)*/
static void SetPause(WindowLoopState& game, bool flag) {
LOGF("Pause: %s\n", flag ? "true" : "false");
@@ -614,11 +606,11 @@ void WindowContext::ProcessEvent(double time_s) {
mb.down = false;
mb.up = false;
mb.left = ((event->motion.state & KYTY_SDL_BUTTON_LMASK) != 0u);
mb.middle = ((event->motion.state & KYTY_SDL_BUTTON_MMASK) != 0u);
mb.right = ((event->motion.state & KYTY_SDL_BUTTON_RMASK) != 0u);
mb.x1 = ((event->motion.state & KYTY_SDL_BUTTON_X1MASK) != 0u);
mb.x2 = ((event->motion.state & KYTY_SDL_BUTTON_X2MASK) != 0u);
mb.left = ((event->motion.state & SDL_BUTTON_LMASK) != 0u);
mb.middle = ((event->motion.state & SDL_BUTTON_MMASK) != 0u);
mb.right = ((event->motion.state & SDL_BUTTON_RMASK) != 0u);
mb.x1 = ((event->motion.state & SDL_BUTTON_X1MASK) != 0u);
mb.x2 = ((event->motion.state & SDL_BUTTON_X2MASK) != 0u);
mb.touch = (event->motion.which == SDL_TOUCH_MOUSEID);
mb.pressed = false;
mb.released = false;
@@ -713,6 +705,20 @@ void WindowContext::ProcessEvent(double time_s) {
}
break;
case SDL_CONTROLLERSENSORUPDATE: {
const auto& sensor = event->csensor;
if (sensor.sensor == SDL_SENSOR_ACCEL || sensor.sensor == SDL_SENSOR_GYRO) {
Controller::SetSensor(sensor.which,
sensor.sensor == SDL_SENSOR_ACCEL ? Controller::Sensor::Accel
: Controller::Sensor::Gyro,
sensor.data,
sensor.timestamp_us != 0
? sensor.timestamp_us
: static_cast<uint64_t>(sensor.timestamp) * 1000);
}
break;
}
case SDL_CONTROLLERDEVICEADDED:
case SDL_CONTROLLERDEVICEREMOVED:
case SDL_CONTROLLERDEVICEREMAPPED: {
@@ -854,8 +860,8 @@ static void WindowCreate(WindowContext& context) {
window_flags |= static_cast<uint32_t>(SDL_WINDOW_BORDERLESS);
}
#endif
context.window = SDL_CreateWindow(KYTY_SDL_WINDOW_CAPTION, KYTY_SDL_WINDOWPOS_CENTERED,
KYTY_SDL_WINDOWPOS_CENTERED, width, height, window_flags);
context.window = SDL_CreateWindow(KYTY_SDL_WINDOW_CAPTION, SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, width, height, window_flags);
if (context.window == nullptr) {
EXIT("%s\n", SDL_GetError());
@@ -105,8 +105,6 @@ void ClearEmbeddedFetchVectorLanes(EmbeddedFetchVectorLanes* lanes, uint32_t reg
lanes->erase(first, last);
}
using EmbeddedFetchData = Frontend::EmbeddedFetchPlan;
bool IsDecodedSgpr(const Decoder::Operand& op) {
return op.kind == Decoder::OperandKind::Sgpr || op.kind == Decoder::OperandKind::VccLo ||
op.kind == Decoder::OperandKind::VccHi;
@@ -210,13 +208,12 @@ int BufferTableAttribFromOffset(uint32_t raw_offset, int dword) {
return static_cast<int>((raw_offset + static_cast<uint32_t>(dword) * 4u) / 16u);
}
EmbeddedFetchData DetectEmbeddedVertexFetch(const Decoder::Program& decoded,
const ShaderVertexInputInfo* input_info,
uint32_t user_data_base, uint32_t user_data_count,
uint32_t wave_size) {
Frontend::EmbeddedFetchPlan DetectEmbeddedVertexFetch(
const Decoder::Program& decoded, const ShaderVertexInputInfo* input_info,
uint32_t user_data_base, uint32_t user_data_count, uint32_t wave_size) {
const uint32_t vertex_index_reg = input_info->logical_stage == ShaderType::Local ? 2u : 5u;
const uint32_t instance_index_reg = input_info->logical_stage == ShaderType::Local ? 5u : 8u;
EmbeddedFetchData data;
Frontend::EmbeddedFetchPlan data;
data.loads.reserve(input_info->resources_num);
int32_t vertex_offset_candidate = -1;
int32_t instance_offset_candidate = -1;
@@ -560,7 +557,7 @@ TranslateResult TranslateProgram(std::span<const uint32_t> code, const CompileOp
static_cast<uint64_t>(cfg.natural_loops.size()), phase_ms());
}
EmbeddedFetchData embedded_fetch;
Frontend::EmbeddedFetchPlan embedded_fetch;
if ((options.stage == ShaderType::Vertex || options.stage == ShaderType::Local) &&
options.input_info.vertex != nullptr && options.input_info.vertex->fetch_embedded) {
embedded_fetch = DetectEmbeddedVertexFetch(
@@ -138,7 +138,7 @@ uint32_t EmitDppWriteCondition(ValueEmitContext& ctx, const IR::DppMoveFlags& fl
state.builder.AddFunction(spv::OpLogicalAnd, TypeBool(state), masks_ok, bank_ok, row_ok);
uint32_t writable = masks_ok;
if (!flags.bound_control) {
const auto target = EmitDppTargetLane(state, flags.control);
const auto target = EmitDppTargetLane(state, flags);
const auto bounded = state.builder.AllocateId();
state.builder.AddFunction(spv::OpLogicalAnd, TypeBool(state), bounded, writable,
target.valid);
@@ -611,7 +611,7 @@ uint32_t EmitUndefU1(EmitterState& state, const IR::Inst& inst) {
uint32_t EmitDppMoveU32(ValueEmitContext& ctx, const IR::Inst& inst) {
auto& state = ctx.state;
const auto flags = inst.Flags<IR::DppMoveFlags>();
const auto target = EmitDppTargetLane(state, flags.control);
const auto target = EmitDppTargetLane(state, flags);
const auto shuffled = ctx.Shuffle(inst, 0, target.lane);
if (flags.fetch_inactive) {
return shuffled;
@@ -2,24 +2,26 @@
namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter {
DppTargetLane EmitDppQuadPermTargetLane(EmitterState& state, uint32_t subid, uint32_t control) {
const auto quad_base = state.builder.AllocateId();
DppTargetLane EmitDppPermTargetLane(EmitterState& state, uint32_t subid, uint32_t control,
uint32_t lane_bits) {
const auto lane_mask = (1u << lane_bits) - 1u;
const auto group_base = state.builder.AllocateId();
const auto lane = state.builder.AllocateId();
const auto shift = state.builder.AllocateId();
const auto selected0 = state.builder.AllocateId();
const auto selected = state.builder.AllocateId();
const auto target = state.builder.AllocateId();
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), quad_base, subid,
ConstantU32(state, 0xfffffffcu));
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), group_base, subid,
ConstantU32(state, ~lane_mask));
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), lane, subid,
ConstantU32(state, 3));
state.builder.AddFunction(spv::OpShiftLeftLogical, TypeU32(state), shift, lane,
ConstantU32(state, 1));
ConstantU32(state, lane_mask));
state.builder.AddFunction(spv::OpIMul, TypeU32(state), shift, lane,
ConstantU32(state, lane_bits));
state.builder.AddFunction(spv::OpShiftRightLogical, TypeU32(state), selected0,
ConstantU32(state, control), shift);
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), selected, selected0,
ConstantU32(state, 3));
state.builder.AddFunction(spv::OpBitwiseOr, TypeU32(state), target, quad_base, selected);
ConstantU32(state, lane_mask));
state.builder.AddFunction(spv::OpBitwiseOr, TypeU32(state), target, group_base, selected);
return {target, ConstantBool(state, true)};
}
@@ -89,10 +91,14 @@ DppTargetLane EmitDppMirrorTargetLane(EmitterState& state, uint32_t subid, bool
return {target, ConstantBool(state, true)};
}
DppTargetLane EmitDppTargetLane(EmitterState& state, uint32_t control) {
DppTargetLane EmitDppTargetLane(EmitterState& state, const IR::DppMoveFlags& flags) {
const auto subid = EmitSubgroupLocalInvocationId(state);
const auto control = flags.control;
if (flags.dpp8) {
return EmitDppPermTargetLane(state, subid, control, 3u);
}
if (control <= 0xffu) {
return EmitDppQuadPermTargetLane(state, subid, control);
return EmitDppPermTargetLane(state, subid, control, 2u);
}
if (control >= 0x101u && control <= 0x10fu) {
return EmitDppRowShiftTargetLane(state, subid, control & 0xfu, true);
@@ -308,8 +308,6 @@ uint32_t ConstantI32(EmitterState& state, int32_t value);
uint32_t ConstantF32(EmitterState& state, uint32_t bits);
uint32_t FloatBits(float value);
uint32_t ConstantF32Value(EmitterState& state, float value);
uint32_t ConstantBool(EmitterState& state, bool value);
@@ -329,7 +327,8 @@ void EmitMeshAllocate(ValueEmitContext& ctx, const IR::Inst& inst);
uint32_t MeshOutputPointer(EmitterState& state, IR::StageOutputKind kind, uint32_t index = 0);
uint32_t MeshPrimitivePointer(EmitterState& state);
DppTargetLane EmitDppQuadPermTargetLane(EmitterState& state, uint32_t subid, uint32_t control);
DppTargetLane EmitDppPermTargetLane(EmitterState& state, uint32_t subid, uint32_t control,
uint32_t lane_bits);
DppTargetLane EmitDppRowShiftTargetLane(EmitterState& state, uint32_t subid, uint32_t amount,
bool left);
@@ -338,7 +337,7 @@ DppTargetLane EmitDppRowRotateRightTargetLane(EmitterState& state, uint32_t subi
DppTargetLane EmitDppMirrorTargetLane(EmitterState& state, uint32_t subid, bool half_row);
DppTargetLane EmitDppTargetLane(EmitterState& state, uint32_t control);
DppTargetLane EmitDppTargetLane(EmitterState& state, const IR::DppMoveFlags& flags);
uint32_t EmitSubgroupLocalInvocationId(EmitterState& state);
@@ -514,31 +514,6 @@ void StoreWord(ValueEmitContext& ctx, const IR::Inst& inst, IR::MemoryInfo mem)
});
}
void FormattedStorePrepared(ValueEmitContext& ctx, const IR::Inst& inst, const IR::MemoryInfo& mem,
uint32_t component, const MemoryResourceAccess& resource,
uint32_t data) {
const auto info = Format::GetFormatInfo(BufferFormat(ctx, mem));
if (info.type == Format::ComponentType::Unknown) {
StoreWordPrepared(ctx, inst, RebaseRawComponent(mem, component), resource, data);
return;
}
if (component >= info.component_count) return;
const auto bits = info.component_bits[component];
const auto component_mem = RebaseFormattedComponent(mem, info, component);
if (bits == 8u || bits == 16u) {
StoreSubwordPrepared(ctx, inst, component_mem, resource, bits, data);
} else {
StoreWordPrepared(ctx, inst, component_mem, resource, data);
}
}
void FormattedStore(ValueEmitContext& ctx, const IR::Inst& inst, const IR::MemoryInfo& mem) {
EmitIfCondition(ctx.state, ctx.Arg(inst, inst.NumArgs() - 1), [&]() {
const auto resource = PrepareMemoryResourceAccess(ctx.state, mem);
FormattedStorePrepared(ctx, inst, mem, 0u, resource, ctx.Arg(inst, inst.NumArgs() - 2));
});
}
spv::Op SpirvAtomicOpcode(IR::ValueOpcode opcode) {
switch (opcode) {
case IR::ValueOpcode::BufferAtomicCmpSwap32: return spv::OpAtomicCompareExchange;
@@ -729,6 +704,11 @@ void StoreFormattedInBounds(ValueEmitContext& ctx, const IR::MemoryInfo& mem,
uint32_t data) {
if (component >= plan.info.component_count) return;
const auto bits = plan.info.component_bits[component];
if (plan.info.type == Format::ComponentType::Snorm && bits == 16u) {
const auto value = EmitBitCastF32U32(ctx.state, data);
data = EmitPackSnorm2x16(
ctx.state, EmitCompositeConstructF32x2(ctx.state, value, ConstantF32Value(ctx.state, 0.0f)));
}
if (bits == 8u || bits == 16u) {
StoreSubwordInBounds(ctx, mem, plan.resource, plan.addresses[component],
plan.indices[component], bits, data);
@@ -737,6 +717,23 @@ void StoreFormattedInBounds(ValueEmitContext& ctx, const IR::MemoryInfo& mem,
}
}
void FormattedStore(ValueEmitContext& ctx, const IR::Inst& inst, const IR::MemoryInfo& mem) {
EmitIfCondition(ctx.state, ctx.Arg(inst, inst.NumArgs() - 1), [&]() {
const auto resource = PrepareMemoryResourceAccess(ctx.state, mem);
const auto data = ctx.Arg(inst, inst.NumArgs() - 2);
const auto info = Format::GetFormatInfo(BufferFormat(ctx, mem));
if (info.type == Format::ComponentType::Unknown) {
StoreWordPrepared(ctx, inst, RebaseRawComponent(mem, 0u), resource, data);
return;
}
const auto plan = PrepareFormattedMemory(ctx, inst, mem, resource, info, 1u,
FormattedAccess::Store);
EmitIfCondition(ctx.state, plan.in_bounds, [&]() {
StoreFormattedInBounds(ctx, mem, plan, 0u, data);
});
});
}
uint32_t LoadWideBuffer(ValueEmitContext& ctx, const IR::Inst& inst, uint32_t components) {
auto& state = ctx.state;
return EmitValueOrDefaultIfCondition(
@@ -1,6 +1,7 @@
#include "graphics/shader/recompiler/backend/spirv/spirvEmitterInternal.h"
#include <algorithm>
#include <bit>
namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter {
@@ -256,14 +257,8 @@ uint32_t ConstantF32(EmitterState& state, uint32_t bits) {
return state.builder.Constant(spv::OpConstant, TypeF32(state), bits);
}
uint32_t FloatBits(float value) {
uint32_t bits = 0;
std::memcpy(&bits, &value, sizeof(bits));
return bits;
}
uint32_t ConstantF32Value(EmitterState& state, float value) {
return ConstantF32(state, FloatBits(value));
return ConstantF32(state, std::bit_cast<uint32_t>(value));
}
uint32_t ConstantBool(EmitterState& state, bool value) {
@@ -558,8 +553,17 @@ void DefineOutputs(EmitterState& state) {
const auto type = uint_output ? TypeU32Vector(state, 4) : TypeF32Vector(state, 4);
binding.variable_id = DefineInterfaceVariable(state, type, spv::StorageClassOutput,
binding.debug_name.c_str());
const bool dual_source = binding.kind == IR::StageOutputKind::Mrt &&
state.program.stage == ShaderType::Pixel &&
state.input_info.pixel->dual_source_blending;
EXIT_NOT_IMPLEMENTED(dual_source && binding.index > 1);
state.builder.AddAnnotation(spv::OpDecorate, binding.variable_id,
spv::DecorationLocation, binding.location);
spv::DecorationLocation,
dual_source ? 0u : binding.location);
if (dual_source) {
state.builder.AddAnnotation(spv::OpDecorate, binding.variable_id,
spv::DecorationIndex, binding.index);
}
break;
}
}
@@ -3,6 +3,7 @@
#include "graphics/shader/recompiler/frontend/decode/OpcodeTable.h"
#include <algorithm>
#include <bit>
namespace Libs::Graphics::ShaderRecompiler::Decoder {
namespace {
@@ -203,18 +204,6 @@ constexpr auto MIMG_SAMPLE_OPS = Detail::MakeOpcodeTable<0x100>(MIMG_SAMPLE_OPCO
constexpr auto MIMG_GATHER_OPS = Detail::MakeOpcodeTable<0x100>(MIMG_GATHER_OPCODE_LIST);
constexpr auto MIMG_ATOMIC_OPS = Detail::MakeOpcodeTable<0x100>(MIMG_ATOMIC_OPCODE_LIST);
const MimgSampleInfo* LookupSample(uint32_t opcode) {
return Detail::FindOpcode(MIMG_SAMPLE_OPS, opcode);
}
const MimgGatherInfo* LookupGather(uint32_t opcode) {
return Detail::FindOpcode(MIMG_GATHER_OPS, opcode);
}
const Detail::OpcodeMap* LookupAtomic(uint32_t opcode) {
return Detail::FindOpcode(MIMG_ATOMIC_OPS, opcode);
}
Opcode DecodeMimgOpcode(uint32_t opcode, const MimgSampleInfo* sample, const MimgGatherInfo* gather,
const Detail::OpcodeMap* atomic) {
if (sample != nullptr) {
@@ -280,10 +269,6 @@ uint32_t CountDmaskComponents(uint32_t dmask) {
return count != 0 ? count : 1u;
}
bool IsSingleDmaskBit(uint32_t dmask) {
return dmask != 0u && (dmask & (dmask - 1u)) == 0u;
}
} // namespace
ImageAddressComponent ImageAddressComponentLayout(uint32_t flags, uint32_t component) {
@@ -332,9 +317,9 @@ void DecodeMimg(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
const bool r128 = ((word0 >> 15u) & 0x1u) != 0u;
const bool a16 = ((word1 >> 30u) & 0x1u) != 0u;
const bool d16 = ((word1 >> 31u) & 0x1u) != 0u;
const auto* sample = LookupSample(opcode);
const auto* gather = LookupGather(opcode);
const auto* atomic = LookupAtomic(opcode);
const auto* sample = Detail::FindOpcode(MIMG_SAMPLE_OPS, opcode);
const auto* gather = Detail::FindOpcode(MIMG_GATHER_OPS, opcode);
const auto* atomic = Detail::FindOpcode(MIMG_ATOMIC_OPS, opcode);
inst.pc = pc;
inst.word_count = word_count;
@@ -364,7 +349,7 @@ void DecodeMimg(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
if (inst.opcode == Opcode::UNSUPPORTED) {
SetUnsupported(inst, Family::MIMG, opcode, "MIMG opcode is not implemented");
}
if (gather != nullptr && !IsSingleDmaskBit(inst.dmask)) {
if (gather != nullptr && !std::has_single_bit(inst.dmask)) {
SetUnsupported(inst, Family::MIMG, opcode,
"MIMG image gather requires exactly one dmask bit");
}
@@ -382,7 +367,7 @@ void DecodeMimg(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
}
const char* MimgSampleOpcodeName(uint32_t opcode) {
const auto* sample = LookupSample(opcode);
const auto* sample = Detail::FindOpcode(MIMG_SAMPLE_OPS, opcode);
return sample != nullptr ? sample->name : nullptr;
}
@@ -14,10 +14,6 @@
namespace Libs::Graphics::ShaderRecompiler::Decoder {
namespace {
uint32_t FloatBits(float value) {
return std::bit_cast<uint32_t>(value);
}
bool HasLiteral(const Instruction& inst) {
return inst.src0.kind == OperandKind::LiteralConstant ||
inst.src1.kind == OperandKind::LiteralConstant ||
@@ -242,7 +238,7 @@ void DecodeScalarSource(uint32_t code, uint32_t pc, Operand& operand) {
if (code >= 240u && code <= 247u) {
constexpr float values[] = {0.5f, -0.5f, 1.0f, -1.0f, 2.0f, -2.0f, 4.0f, -4.0f};
operand.kind = OperandKind::FloatInlineConstant;
operand.value = FloatBits(values[code - 240u]);
operand.value = std::bit_cast<uint32_t>(values[code - 240u]);
return;
}
if (code >= 256u && code <= 511u) {
@@ -260,7 +256,7 @@ void DecodeScalarSource(uint32_t code, uint32_t pc, Operand& operand) {
case 239u: operand.kind = OperandKind::PopsExitingWaveId; return;
case 248u:
operand.kind = OperandKind::FloatInlineConstant;
operand.value = FloatBits(0.15915494309189535f);
operand.value = std::bit_cast<uint32_t>(0.15915494309189535f);
return;
case 251u: operand.kind = OperandKind::VccZ; return;
case 252u: operand.kind = OperandKind::ExecZ; return;
@@ -476,8 +472,9 @@ std::string OperandToString(const Operand& operand) {
text += ".clamp";
}
if (operand.dpp) {
text += fmt::format(".dpp(ctrl=0x{:x},fi={},bc={})", operand.dpp_ctrl,
operand.dpp_fetch_inactive ? 1u : 0u, operand.dpp_bound_ctrl ? 1u : 0u);
text += fmt::format(".{}(ctrl=0x{:x},fi={},bc={})", operand.dpp8 ? "dpp8" : "dpp",
operand.dpp_ctrl, operand.dpp_fetch_inactive ? 1u : 0u,
operand.dpp_bound_ctrl ? 1u : 0u);
}
return text;
}
@@ -2,8 +2,8 @@
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_RECOMPILER_SHADERDECODER_H_
#include "common/common.h"
#include "common/magicEnum.h"
#include <magic_enum.hpp>
#include <span>
#include <string_view>
#include <vector>
@@ -300,6 +300,7 @@ enum class Opcode {
V_SUBREV_NC_U32,
V_ADD_NC_U16,
V_SUB_NC_U16,
V_MUL_LO_U16,
V_MAX_U16,
V_MAX_I16,
V_MIN_U16,
@@ -378,7 +379,9 @@ enum class Opcode {
V_CMP_GT_F16,
V_CMP_LG_F16,
V_CMP_GE_F16,
V_CMP_NGT_F16,
V_CMP_NEQ_F16,
V_CMP_NLT_F16,
V_CMPX_LT_F16,
V_CMPX_EQ_F16,
V_CMPX_LE_F16,
@@ -666,6 +669,7 @@ struct Operand {
bool absolute = false;
bool clamp = false;
bool dpp = false;
bool dpp8 = false;
};
struct Instruction {
@@ -83,10 +83,6 @@ constexpr Vop2OpcodeInfo VOP2_OPCODE_LIST[] = {
constexpr auto VOP2_OPS = Detail::MakeOpcodeTable<0x40>(VOP2_OPCODE_LIST);
constexpr Opcode LookupVop2Opcode(uint32_t encoding) {
return Detail::LookupOpcode(VOP2_OPS, encoding);
}
constexpr OpcodeMap VOP1_OPCODE_LIST[] = {
{0x00u, Opcode::V_NOP},
{0x01u, Opcode::V_MOV_B32},
@@ -250,7 +246,8 @@ constexpr VopcOpcodeInfo VOPC_OPCODE_LIST[] = {
{0xf5u, Opcode::V_CMPX_NE_U64, false}, {0xc9u, Opcode::V_CMP_LT_F16},
{0xcau, Opcode::V_CMP_EQ_F16}, {0xcbu, Opcode::V_CMP_LE_F16},
{0xccu, Opcode::V_CMP_GT_F16}, {0xcdu, Opcode::V_CMP_LG_F16},
{0xceu, Opcode::V_CMP_GE_F16}, {0xedu, Opcode::V_CMP_NEQ_F16},
{0xceu, Opcode::V_CMP_GE_F16}, {0xebu, Opcode::V_CMP_NGT_F16},
{0xedu, Opcode::V_CMP_NEQ_F16}, {0xeeu, Opcode::V_CMP_NLT_F16},
{0xd9u, Opcode::V_CMPX_LT_F16}, {0xdau, Opcode::V_CMPX_EQ_F16},
{0xdbu, Opcode::V_CMPX_LE_F16}, {0xdcu, Opcode::V_CMPX_GT_F16},
{0xdeu, Opcode::V_CMPX_GE_F16}, {0xfbu, Opcode::V_CMPX_NGT_F16},
@@ -298,6 +295,7 @@ constexpr OpcodeMap VOP3_OPCODE_LIST[] = {
{0x300u, Opcode::V_LSHRREV_B64},
{0x303u, Opcode::V_ADD_NC_U16},
{0x304u, Opcode::V_SUB_NC_U16},
{0x305u, Opcode::V_MUL_LO_U16},
{0x307u, Opcode::V_LSHRREV_B16},
{0x308u, Opcode::V_ASHRREV_I16},
{0x309u, Opcode::V_MAX_U16},
@@ -374,7 +372,7 @@ Opcode LookupVop3Opcode(uint32_t opcode) {
if (IsUnsupportedVop3EncodedVop2Alias(opcode - 0x100u)) {
return Opcode::UNSUPPORTED;
}
return LookupVop2Opcode(opcode - 0x100u);
return Detail::LookupOpcode(VOP2_OPS, opcode - 0x100u);
}
if (opcode >= 0x180u && opcode <= 0x1ffu) {
return Detail::LookupOpcode(VOP3_ENCODED_VOP1_OPS, opcode - 0x180u);
@@ -433,6 +431,7 @@ bool IsNativeVop3B16BinaryOpcode(Opcode opcode) {
switch (opcode) {
case Opcode::V_ADD_NC_U16:
case Opcode::V_SUB_NC_U16:
case Opcode::V_MUL_LO_U16:
case Opcode::V_MAX_U16:
case Opcode::V_MAX_I16:
case Opcode::V_MIN_U16:
@@ -685,10 +684,15 @@ void DecodeVop1Sdwa(uint32_t pc, std::span<const uint32_t> code, uint32_t word_i
ReadLiteralOperands(code, word_index, inst);
}
void ApplyDppModifier(Operand& operand, uint32_t modifier) {
void ApplyDppModifier(Operand& operand, uint32_t modifier, uint32_t encoding) {
operand.dpp = true;
if (encoding == 233u) {
operand.dpp8 = true;
operand.dpp_ctrl = modifier >> 8u;
return;
}
operand.negate = ((modifier >> 20u) & 0x1u) != 0u;
operand.absolute = ((modifier >> 21u) & 0x1u) != 0u;
operand.dpp = true;
operand.dpp_ctrl = (modifier >> 8u) & 0x1ffu;
operand.dpp_fetch_inactive = ((modifier >> 18u) & 0x1u) != 0u;
operand.dpp_bound_ctrl = ((modifier >> 19u) & 0x1u) != 0u;
@@ -709,7 +713,7 @@ void DecodeVop1Dpp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_in
DecodeVectorGpr(vdst, inst.dst);
}
DecodeScalarSource(src0 + 256u, pc, inst.src0);
ApplyDppModifier(inst.src0, modifier);
ApplyDppModifier(inst.src0, modifier, code[word_index] & 0x1ffu);
inst.src_count = 1;
if (!IsVop1FloatSourceOpcode(inst.opcode) && (inst.src0.negate || inst.src0.absolute)) {
@@ -824,7 +828,9 @@ bool IsVopcFloatCompareOpcode(Opcode opcode) {
case Opcode::V_CMP_GT_F16:
case Opcode::V_CMP_LG_F16:
case Opcode::V_CMP_GE_F16:
case Opcode::V_CMP_NGT_F16:
case Opcode::V_CMP_NEQ_F16:
case Opcode::V_CMP_NLT_F16:
case Opcode::V_CMPX_LT_F16:
case Opcode::V_CMPX_EQ_F16:
case Opcode::V_CMPX_LE_F16:
@@ -1046,7 +1052,7 @@ void DecodeVop2Dpp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_in
DecodeVectorGpr(vdst, inst.dst);
DecodeVectorGpr(vsrc1, inst.src1);
DecodeScalarSource(src0 + 256u, pc, inst.src0);
ApplyDppModifier(inst.src0, modifier);
ApplyDppModifier(inst.src0, modifier, code[word_index] & 0x1ffu);
inst.src1.negate = ((modifier >> 22u) & 0x1u) != 0u;
inst.src1.absolute = ((modifier >> 23u) & 0x1u) != 0u;
const bool packed_fmac = inst.opcode == Opcode::V_PK_FMAC_F16;
@@ -1155,7 +1161,7 @@ void DecodeVopcDpp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_in
DecodeVectorGpr(vsrc1, inst.src1);
DecodeScalarSource(src0 + 256u, pc, inst.src0);
inst.dst.kind = IsVopcCompareExec(inst.opcode) ? OperandKind::ExecLo : OperandKind::VccLo;
ApplyDppModifier(inst.src0, modifier);
ApplyDppModifier(inst.src0, modifier, code[word_index] & 0x1ffu);
inst.src1.negate = ((modifier >> 22u) & 0x1u) != 0u;
inst.src1.absolute = ((modifier >> 23u) & 0x1u) != 0u;
inst.src_count = 2;
@@ -1171,6 +1177,7 @@ uint32_t NativeVop3SourceCount(Opcode opcode) {
case Opcode::V_MUL_I32_I24:
case Opcode::V_ADD_NC_U16:
case Opcode::V_SUB_NC_U16:
case Opcode::V_MUL_LO_U16:
case Opcode::V_MAX_U16:
case Opcode::V_MAX_I16:
case Opcode::V_MIN_U16:
@@ -1468,7 +1475,7 @@ void DecodeVop2(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
inst.pc = pc;
inst.family = Family::VOP2;
inst.opcode_id = opcode;
inst.opcode = LookupVop2Opcode(opcode);
inst.opcode = Detail::LookupOpcode(VOP2_OPS, opcode);
SetRawWords(inst, code, word_index, 1);
if (inst.opcode == Opcode::UNSUPPORTED) {
@@ -1510,6 +1517,7 @@ void DecodeVop1(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
return;
}
switch (src0) {
case 233u: DecodeVop1Dpp(pc, code, word_index, opcode, vdst, inst); return;
case 249u: DecodeVop1Sdwa(pc, code, word_index, opcode, vdst, inst); return;
case 250u: DecodeVop1Dpp(pc, code, word_index, opcode, vdst, inst); return;
default: break;
@@ -166,9 +166,9 @@ void Translator::V_CVT_PK_U8_F32(const Decoder::Instruction& inst) {
}
void Translator::V_PACK_B32_F16(const Decoder::Instruction& inst) {
const auto low = ReadF16LaneBits(inst.src0, false);
const auto low = Read16LaneBits(inst.src0, false);
const auto high =
ir.ShiftLeftLogical(ReadF16LaneBits(inst.src1, false), IR::U32(IR::Value(16u)));
ir.ShiftLeftLogical(Read16LaneBits(inst.src1, false), IR::U32(IR::Value(16u)));
WriteOperand(DestinationOperand(inst), ir.BitwiseOr(low, high));
}
@@ -34,6 +34,7 @@ Decoder::Operand OffsetDecodedRegister(const Decoder::Operand& operand, uint32_t
result.negate_hi = false;
result.absolute = false;
result.dpp_ctrl = 0;
result.dpp8 = false;
result.dpp_row_mask = 0xf;
result.dpp_bank_mask = 0xf;
result.explicit_sdwa_dst = false;
@@ -9,6 +9,17 @@
namespace Libs::Graphics::ShaderRecompiler::Frontend {
static IR::DppMoveFlags DppFlags(const Decoder::Operand& operand) {
return {
.control = operand.dpp_ctrl,
.row_mask = operand.dpp_row_mask,
.bank_mask = operand.dpp_bank_mask,
.fetch_inactive = operand.dpp_fetch_inactive,
.bound_control = operand.dpp_bound_ctrl,
.dpp8 = operand.dpp8,
};
}
const Decoder::Operand& Translator::SourceAt(const Decoder::Instruction& inst, uint32_t index) {
switch (index) {
case 0: return inst.src0;
@@ -30,6 +41,7 @@ Decoder::Operand Translator::DestinationOperand(const Decoder::Instruction& inst
continue;
}
destination.dpp = true;
destination.dpp8 = source.dpp8;
destination.dpp_ctrl = source.dpp_ctrl;
destination.dpp_row_mask = source.dpp_row_mask;
destination.dpp_bank_mask = source.dpp_bank_mask;
@@ -106,6 +118,7 @@ Decoder::Operand Translator::PlainOperand(const Decoder::Operand& operand) {
result.dpp_fetch_inactive = false;
result.dpp_bound_ctrl = false;
result.dpp = false;
result.dpp8 = false;
return result;
}
@@ -167,14 +180,8 @@ IR::U32 Translator::ReadScalarCode(uint32_t code) {
IR::U32 Translator::ApplyBitSourceModifiers(const Decoder::Operand& operand, IR::U32 value) {
if (operand.dpp) {
const IR::DppMoveFlags flags {
.control = static_cast<uint16_t>(operand.dpp_ctrl),
.row_mask = static_cast<uint8_t>(operand.dpp_row_mask),
.bank_mask = static_cast<uint8_t>(operand.dpp_bank_mask),
.fetch_inactive = operand.dpp_fetch_inactive,
.bound_control = operand.dpp_bound_ctrl,
};
value = IR::U32(ir.Emit(IR::ValueOpcode::DppMoveU32, {value, ir.GetExec()}, flags));
value =
IR::U32(ir.Emit(IR::ValueOpcode::DppMoveU32, {value, ir.GetExec()}, DppFlags(operand)));
}
if (operand.sdwa_sel != 6u) {
uint32_t offset = 0;
@@ -301,15 +308,8 @@ void Translator::WriteRawU32(const Decoder::Operand& operand, IR::U32 value) {
const auto reg = static_cast<IR::VectorReg>(operand.reg);
const auto old = ir.GetVectorReg(reg);
if (operand.dpp) {
const IR::DppMoveFlags flags {
.control = static_cast<uint16_t>(operand.dpp_ctrl),
.row_mask = static_cast<uint8_t>(operand.dpp_row_mask),
.bank_mask = static_cast<uint8_t>(operand.dpp_bank_mask),
.fetch_inactive = operand.dpp_fetch_inactive,
.bound_control = operand.dpp_bound_ctrl,
};
value = IR::U32(
ir.Emit(IR::ValueOpcode::DppUpdateU32, {value, old, ir.GetExec()}, flags));
value = IR::U32(ir.Emit(IR::ValueOpcode::DppUpdateU32, {value, old, ir.GetExec()},
DppFlags(operand)));
} else {
value = ir.Select(ir.GetExec(), value, old);
}
@@ -541,10 +541,7 @@ IR::U32 Translator::ReadU16LaneRaw(const Decoder::Operand& operand, bool high_la
IR::U32 Translator::ReadU16LaneAsU32(const Decoder::Operand& operand, bool high_lane,
bool sign_extend) {
auto value = ReadU16LaneRaw(operand, high_lane);
if (high_lane ? operand.negate_hi : operand.negate) {
value = ir.BitwiseAnd(ir.ISub(IR::U32(IR::Value(0u)), value), IR::U32(IR::Value(0xffffu)));
}
auto value = Read16LaneBits(operand, high_lane);
if (sign_extend || operand.sdwa_sext) {
value = IR::U32(
ir.Emit(IR::ValueOpcode::BitFieldSExtract, {value, IR::Value(0u), IR::Value(16u)}));
@@ -556,12 +553,13 @@ IR::U32 Translator::ReadU16AsU32(const Decoder::Operand& operand, bool sign_exte
return ReadU16LaneAsU32(operand, false, sign_extend);
}
IR::U32 Translator::ReadF16LaneBits(const Decoder::Operand& operand, bool high_lane) {
IR::U32 Translator::Read16LaneBits(const Decoder::Operand& operand, bool high_lane) {
auto value = ReadU16LaneRaw(operand, high_lane);
if (operand.absolute) {
value = ir.BitwiseAnd(value, IR::U32(IR::Value(0x7fffu)));
}
if (high_lane ? operand.negate_hi : operand.negate) {
// RDNA2 source NEG flips the sign bit, including packed integer operands.
value = ir.BitwiseXor(value, IR::U32(IR::Value(0x8000u)));
}
return value;
@@ -44,7 +44,7 @@ private:
IR::U32 ReadU16LaneRaw(const Decoder::Operand& operand, bool high_lane);
IR::U32 ReadU16LaneAsU32(const Decoder::Operand& operand, bool high_lane, bool sign_extend);
IR::U32 ReadU16AsU32(const Decoder::Operand& operand, bool sign_extend);
IR::U32 ReadF16LaneBits(const Decoder::Operand& operand, bool high_lane);
IR::U32 Read16LaneBits(const Decoder::Operand& operand, bool high_lane);
std::array<IR::U32, 2> ExtractU64(IR::U64 value);
void WriteU32Pair(const Decoder::Operand& operand, const std::array<IR::U32, 2>& value);
IR::U32 ConditionBit(const Decoder::Operand& operand);
@@ -264,6 +264,9 @@ bool Translator::EmitVector(const Decoder::Instruction& inst) {
case O::V_CMPX_LE_F16:
EmitFloatCompare(inst, IR::ValueOpcode::FPOrdLessThanEqual32, true, true);
return true;
case O::V_CMP_NGT_F16:
EmitFloatCompare(inst, IR::ValueOpcode::FPUnordLessThanEqual32, true, false);
return true;
case O::V_CMPX_NGT_F16:
EmitFloatCompare(inst, IR::ValueOpcode::FPUnordLessThanEqual32, true, true);
return true;
@@ -273,6 +276,9 @@ bool Translator::EmitVector(const Decoder::Instruction& inst) {
case O::V_CMPX_NEQ_F16:
EmitFloatCompare(inst, IR::ValueOpcode::FPUnordNotEqual32, true, true);
return true;
case O::V_CMP_NLT_F16:
EmitFloatCompare(inst, IR::ValueOpcode::FPUnordGreaterThanEqual32, true, false);
return true;
case O::V_CMPX_NLT_F16:
EmitFloatCompare(inst, IR::ValueOpcode::FPUnordGreaterThanEqual32, true, true);
return true;
@@ -321,6 +327,7 @@ bool Translator::EmitVector(const Decoder::Instruction& inst) {
case O::V_ADD_NC_I16: return Integer16Binary(inst, IR::ValueOpcode::IAdd32, false);
case O::V_SUB_NC_U16:
case O::V_SUB_NC_I16: return Integer16Binary(inst, IR::ValueOpcode::ISub32, false);
case O::V_MUL_LO_U16: return Integer16Binary(inst, IR::ValueOpcode::IMul32, false);
case O::V_MED3_I16: return V_MED3_I16(inst);
case O::V_MIN_I16: return Integer16Binary(inst, IR::ValueOpcode::SMin32, true);
case O::V_MAX_I16: return Integer16Binary(inst, IR::ValueOpcode::SMax32, true);
@@ -34,11 +34,12 @@ struct ImageOpcodeInfo {
};
struct DppMoveFlags {
uint16_t control = 0;
uint8_t row_mask = 0xf;
uint8_t bank_mask = 0xf;
uint32_t control : 24 = 0;
uint32_t row_mask : 4 = 0xf;
uint32_t bank_mask : 4 = 0xf;
bool fetch_inactive = false;
bool bound_control = false;
bool dpp8 = false;
};
static_assert(sizeof(DppMoveFlags) <= sizeof(uint64_t));
static_assert(std::is_trivially_copyable_v<DppMoveFlags>);
@@ -479,8 +479,6 @@ private:
return std::bit_cast<float>(static_cast<uint32_t>(bits));
}
static uint64_t Float32Bits(float value) { return std::bit_cast<uint32_t>(value); }
bool EvaluateWide(Value value, uint64_t& result) {
value = value.Resolve();
if (value.IsImmediate()) {
@@ -490,7 +488,7 @@ private:
case Type::U16: result = value.U16(); return true;
case Type::U32: result = value.U32(); return true;
case Type::U64: result = value.U64(); return true;
case Type::F32: result = Float32Bits(value.F32Value()); return true;
case Type::F32: result = std::bit_cast<uint32_t>(value.F32Value()); return true;
default: return false;
}
}
@@ -733,7 +731,7 @@ private:
return false;
case ValueOpcode::ConvertF32U32:
if (Arg(inst, 0, a)) {
result = Float32Bits(static_cast<float>(static_cast<uint32_t>(a)));
result = std::bit_cast<uint32_t>(static_cast<float>(static_cast<uint32_t>(a)));
return true;
}
return false;
@@ -750,13 +748,13 @@ private:
return false;
case ValueOpcode::FPMul32:
if (binary()) {
result = Float32Bits(Float32(a) * Float32(b));
result = std::bit_cast<uint32_t>(Float32(a) * Float32(b));
return true;
}
return false;
case ValueOpcode::FPTrunc32:
if (Arg(inst, 0, a)) {
result = Float32Bits(std::trunc(Float32(a)));
result = std::bit_cast<uint32_t>(std::trunc(Float32(a)));
return true;
}
return false;
+17 -27
View File
@@ -60,12 +60,12 @@ public:
: parameters(parameters_) {
builder.AddMemoryModel(spv::AddressingModelLogical, spv::MemoryModelGLSL450);
void_type = Type(spv::OpTypeVoid);
uint_type = Type(spv::OpTypeInt, 32u, 0u);
int_type = Type(spv::OpTypeInt, 32u, 1u);
float_type = Type(spv::OpTypeFloat, 32u);
vec4_float_type = Type(spv::OpTypeVector, float_type, 4u);
function_type = Type(spv::OpTypeFunction, void_type);
void_type = builder.Type(spv::OpTypeVoid);
uint_type = builder.Type(spv::OpTypeInt, 32u, 0u);
int_type = builder.Type(spv::OpTypeInt, 32u, 1u);
float_type = builder.Type(spv::OpTypeFloat, 32u);
vec4_float_type = builder.Type(spv::OpTypeVector, float_type, 4u);
function_type = builder.Type(spv::OpTypeFunction, void_type);
per_vertex_type = builder.DecoratedType(
spv::OpTypeStruct,
@@ -76,12 +76,12 @@ public:
ptr_input_vec4_float = Pointer(spv::StorageClassInput, vec4_float_type);
ptr_output_vec4_float = Pointer(spv::StorageClassOutput, vec4_float_type);
if (model == spv::ExecutionModelTessellationControl) {
bool_type = Type(spv::OpTypeBool);
vec2_bool_type = Type(spv::OpTypeVector, bool_type, 2u);
vec2_float_type = Type(spv::OpTypeVector, float_type, 2u);
bool_type = builder.Type(spv::OpTypeBool);
vec2_bool_type = builder.Type(spv::OpTypeVector, bool_type, 2u);
vec2_float_type = builder.Type(spv::OpTypeVector, float_type, 2u);
ptr_output_float = Pointer(spv::StorageClassOutput, float_type);
} else {
vec3_float_type = Type(spv::OpTypeVector, float_type, 3u);
vec3_float_type = builder.Type(spv::OpTypeVector, float_type, 3u);
ptr_input_float = Pointer(spv::StorageClassInput, float_type);
}
}
@@ -161,8 +161,8 @@ public:
Store(Access(ptr_output_vec4_float, outputs[i], invocation), value);
}
Emit(spv::OpReturn);
Emit(spv::OpFunctionEnd);
builder.AddFunction(spv::OpReturn);
builder.AddFunction(spv::OpFunctionEnd);
return builder.Build();
}
@@ -184,27 +184,22 @@ public:
Load(vec4_float_type, Access(ptr_input_vec4_float, inputs[i], index)));
}
Emit(spv::OpReturn);
Emit(spv::OpFunctionEnd);
builder.AddFunction(spv::OpReturn);
builder.AddFunction(spv::OpFunctionEnd);
return builder.Build();
}
private:
template <typename... Args>
uint32_t Type(spv::Op opcode, Args... operands) {
return builder.Type(opcode, operands...);
}
uint32_t Constant(uint32_t type, uint32_t value) {
return builder.Constant(spv::OpConstant, type, value);
}
uint32_t Pointer(spv::StorageClass storage, uint32_t type) {
return Type(spv::OpTypePointer, storage, type);
return builder.Type(spv::OpTypePointer, storage, type);
}
uint32_t Array(uint32_t type, uint32_t size) {
return Type(spv::OpTypeArray, type, Uint(size));
return builder.Type(spv::OpTypeArray, type, Uint(size));
}
template <typename... Args>
@@ -221,11 +216,6 @@ private:
return id;
}
template <typename... Args>
void Emit(spv::Op opcode, Args... operands) {
builder.AddFunction(opcode, operands...);
}
template <typename... Args>
uint32_t Access(uint32_t pointer_type, uint32_t base, Args... indices) {
return Result(spv::OpAccessChain, pointer_type, base, indices...);
@@ -233,7 +223,7 @@ private:
uint32_t Load(uint32_t type, uint32_t pointer) { return Result(spv::OpLoad, type, pointer); }
void Store(uint32_t pointer, uint32_t value) { Emit(spv::OpStore, pointer, value); }
void Store(uint32_t pointer, uint32_t value) { builder.AddFunction(spv::OpStore, pointer, value); }
uint32_t Int(uint32_t value) { return Constant(int_type, value); }
+1 -5
View File
@@ -4,7 +4,6 @@
#include "common/common.h"
#include "common/emulatorConfig.h"
#include "common/logging/log.h"
#include "common/magicEnum.h"
#include "common/profiler.h"
#include "common/stringUtils.h"
#include "graphics/guest_gpu/gpu_defs.h"
@@ -722,6 +721,7 @@ void BuildStageStaticKey(const ShaderPixelInputInfo& info, std::vector<uint32_t>
key.push_back(static_cast<uint32_t>(info.ps_depth_export_enable));
key.push_back(static_cast<uint32_t>(info.ps_sample_mask_export_enable));
key.push_back(static_cast<uint32_t>(info.ps_early_z));
key.push_back(static_cast<uint32_t>(info.dual_source_blending));
key.insert(key.end(), std::begin(info.target_output_mode), std::end(info.target_output_mode));
for (uint32_t base = 0; base < info.target_export_mapping.size(); base += 4u) {
uint32_t packed = 0;
@@ -1006,8 +1006,4 @@ void ShaderDbgDumpInputInfo(const ShaderComputeInputInfo& info) {
info.group_id[1] ? "true" : "false", info.group_id[2] ? "true" : "false");
}
bool ShaderAddressValid(uint64_t addr) {
return reinterpret_cast<const uint32_t*>(addr) != nullptr;
}
} // namespace Libs::Graphics
+1 -1
View File
@@ -175,6 +175,7 @@ struct ShaderPixelInputInfo {
bool ps_depth_export_enable = false;
bool ps_sample_mask_export_enable = false;
bool ps_sample_shading = false;
bool dual_source_blending = false;
bool ps_early_z = false;
bool ps_execute_on_noop = false;
ShaderStageRuntime stage;
@@ -303,7 +304,6 @@ void ShaderMapUserData(uint64_t addr, const ShaderMappedData& data);
void ShaderDbgDumpInputInfo(const ShaderVertexInputInfo& info);
void ShaderDbgDumpInputInfo(const ShaderPixelInputInfo& info);
void ShaderDbgDumpInputInfo(const ShaderComputeInputInfo& info);
bool ShaderAddressValid(uint64_t addr);
} // namespace Libs::Graphics
+3 -3
View File
@@ -334,13 +334,13 @@ std::filesystem::path MountPoints::ResolvePath(const std::string& mounted_name)
// Match the entire guest path so a mount root works with or without a trailing slash.
const auto mounted_path = Common::FixDirectorySlash(mounted_name);
const auto it = std::find_if(
const auto it = std::find_if(
m_mount_pairs.begin(), m_mount_pairs.end(),
[&mounted_path](const MountPair& p) { return Common::StartsWith(mounted_path, p.point); });
[&mounted_path](const MountPair& p) { return mounted_path.starts_with(p.point); });
if (it != m_mount_pairs.end()) {
const auto& p = *it;
auto rel_path = Common::RemoveFirst(Common::FixFilenameSlash(mounted_name), p.point.size());
while (Common::StartsWith(rel_path, '/')) {
while (rel_path.starts_with('/')) {
rel_path = Common::RemoveFirst(rel_path, 1);
}
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
+10 -13
View File
@@ -2,7 +2,6 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/magicEnum.h"
#include "common/stringUtils.h"
#include "common/threads.h"
#include "common/virtualMemory.h"
@@ -14,9 +13,11 @@
#include <algorithm>
#include <array>
#include <atomic>
#include <bit>
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <magic_enum.hpp>
#include <map>
#include <memory>
#include <mutex>
@@ -2324,8 +2325,8 @@ int32_t KYTY_SYSV_ABI KernelMapNamedFlexibleMemory(void** addr_in_out, size_t le
"\t flags = 0x%08" PRIx32 "\n"
"\t name = %s\n"
"\t gpu_mode = %s\n",
in_addr, out_addr, len, Common::EnumName(mode).c_str(), static_cast<uint32_t>(flags), name,
Common::EnumName(gpu_mode).c_str());
in_addr, out_addr, len, magic_enum::enum_name(mode), static_cast<uint32_t>(flags), name,
magic_enum::enum_name(gpu_mode));
MapGpuRange(out_addr, len);
@@ -3041,8 +3042,8 @@ int KYTY_SYSV_ABI KernelMapDirectMemory(void** addr, size_t len, int prot, int f
"\t shared = %s\n"
"\t reason = %s\n",
in_addr, out_addr, static_cast<uint64_t>(direct_memory_start), len,
Common::EnumName(mode).c_str(), static_cast<uint32_t>(flags), alignment,
Common::EnumName(gpu_mode).c_str(), shared_backing ? "yes" : "no", shared_reason);
magic_enum::enum_name(mode), static_cast<uint32_t>(flags), alignment,
magic_enum::enum_name(gpu_mode), shared_backing ? "yes" : "no", shared_reason);
if (out_addr == 0) {
if (consumed_reservation) {
@@ -3305,7 +3306,7 @@ static bool ReplaceFixedRangeWithReserved(uint64_t start, uint64_t size) {
"\t reserve-fixed replace: backend unmap failed at 0x%016" PRIx64
", size=0x%016" PRIx64 ", type=%s\n",
chunk.range.start, chunk.range.size,
Common::EnumName(chunk.range.type).c_str());
magic_enum::enum_name(chunk.range.type));
if (!restore_chunks()) {
EXIT("reserve-fixed backend-unmap rollback failed\n");
}
@@ -3769,7 +3770,7 @@ int KYTY_SYSV_ABI KernelMprotect(const void* addr, size_t len, int prot) {
}
g_virtual_ranges->Protect(aligned_addr, aligned_len, prot);
LOGF("\t prot: %s -> %s\n", Common::EnumName(old_mode).c_str(), Common::EnumName(mode).c_str());
LOGF("\t prot: %s -> %s\n", magic_enum::enum_name(old_mode), magic_enum::enum_name(mode));
return OK;
}
@@ -3879,10 +3880,6 @@ static bool IsAligned(uint64_t value, uint64_t alignment) {
return alignment == 0 || (value & (alignment - 1u)) == 0;
}
static bool IsPowerOfTwo(uint64_t value) {
return value != 0 && (value & (value - 1u)) == 0;
}
static void MemoryPoolSubtractCommitted(uint64_t len) {
auto current = g_memory_pool_committed.load(std::memory_order_relaxed);
while (current != 0) {
@@ -3904,7 +3901,7 @@ int KYTY_SYSV_ABI KernelMemoryPoolExpand(int64_t search_start, int64_t search_en
if (search_start < 0 || search_end <= search_start || len == 0 ||
(len & (POOL_PAGE_SIZE - 1u)) != 0 || phys_addr_out == nullptr ||
(alignment != 0 &&
(!IsPowerOfTwo(alignment) || (alignment & (POOL_PAGE_SIZE - 1u)) != 0))) {
(!std::has_single_bit(alignment) || (alignment & (POOL_PAGE_SIZE - 1u)) != 0))) {
return KERNEL_ERROR_EINVAL;
}
if (static_cast<uint64_t>(search_end - search_start) < len) {
@@ -3953,7 +3950,7 @@ int KYTY_SYSV_ABI KernelMemoryPoolReserve(void* addr_in, size_t len, size_t alig
return KERNEL_ERROR_EINVAL;
}
if (alignment != 0 &&
(!IsPowerOfTwo(alignment) || !IsAligned(alignment, POOL_RESERVE_ALIGNMENT))) {
(!std::has_single_bit(alignment) || !IsAligned(alignment, POOL_RESERVE_ALIGNMENT))) {
return KERNEL_ERROR_EINVAL;
}
+2 -9
View File
@@ -149,7 +149,7 @@ static uint64_t KernelGetTscFrequencyNative() {
}
KernelReadTscNative();
Common::Thread::Sleep(1);
std::this_thread::sleep_for(std::chrono::milliseconds(1));
KernelReadTscNative();
const auto host_start = Common::Timer::QueryPerformanceCounter();
@@ -993,7 +993,7 @@ static void FreeDetachedThreads(void* /*arg*/) {
auto* pthread_pool = g_pthread_context->GetPthreadPool();
while (true) {
Common::Thread::Sleep(10000);
std::this_thread::sleep_for(std::chrono::milliseconds(10000));
pthread_pool->FreeDetachedThreads();
}
}
@@ -1202,13 +1202,6 @@ static int32_t GetDstSeconds() {
#endif
}
#if KYTY_PLATFORM != KYTY_PLATFORM_WINDOWS
static void sec_to_timeval(KernelTimeval* ts, double sec) {
ts->tv_sec = static_cast<int64_t>(sec);
ts->tv_usec = static_cast<int64_t>((sec - static_cast<double>(ts->tv_sec)) * 1000000.0);
}
#endif
static bool GetPosixClockId(KernelClockid clock_id, clockid_t* out) {
EXIT_IF(out == nullptr);
@@ -329,12 +329,4 @@
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>cancel_button</sender>
<signal>clicked()</signal>
<receiver>ConfigurationEditDialog</receiver>
<slot>reject()</slot>
</connection>
</connections>
</ui>
-20
View File
@@ -1,20 +0,0 @@
#ifndef LAUNCHER_INCLUDE_COMMON_H_
#define LAUNCHER_INCLUDE_COMMON_H_
// IWYU pragma: begin_exports
#include <QArgument>
#include <QObject>
#include <cinttypes>
#include <cstdint>
#include <cstdio>
// IWYU pragma: end_exports
#define KYTY_QT_CLASS_NO_COPY(name) \
public: \
name(const name&) = delete; /* NOLINT(bugprone-macro-parentheses) */ \
name& operator=(const name&) = delete; /* NOLINT(bugprone-macro-parentheses) */ \
name(name&&) noexcept = delete; /* NOLINT(bugprone-macro-parentheses) */ \
name& operator=(name&&) noexcept = delete; /* NOLINT(bugprone-macro-parentheses) */
#endif /* LAUNCHER_INCLUDE_COMMON_H_ */
@@ -1,7 +1,6 @@
#ifndef COMPATIBILITY_DATABASE_H
#define COMPATIBILITY_DATABASE_H
#include "common.h"
#include "configuration.h"
#include <QMap>
@@ -15,7 +14,6 @@ struct CompatibilityEntry {
class CompatibilityDatabase: public QObject {
Q_OBJECT
KYTY_QT_CLASS_NO_COPY(CompatibilityDatabase);
public:
explicit CompatibilityDatabase(bool local, QObject* parent = nullptr);
+1 -1
View File
@@ -1,13 +1,13 @@
#ifndef LAUNCHER_INCLUDE_CONFIGURATION_H_
#define LAUNCHER_INCLUDE_CONFIGURATION_H_
#include "common.h"
#include "common/emulatorConfig.h"
#include <QByteArray>
#include <QChar>
#include <QMetaEnum>
#include <QMetaType>
#include <QObject>
#include <QSettings>
#include <QString>
#include <QStringList>
@@ -1,8 +1,6 @@
#ifndef CONFIGURATION_EDIT_DIALOG_H
#define CONFIGURATION_EDIT_DIALOG_H
#include "common.h"
#include <QDialog>
#include <QString>
#include <QStringList>
@@ -22,7 +20,6 @@ class ConfigurationEditDialog;
class ConfigurationEditDialog: public QDialog {
Q_OBJECT
KYTY_QT_CLASS_NO_COPY(ConfigurationEditDialog);
public:
explicit ConfigurationEditDialog(Configuration& info, QWidget* parent = nullptr);
@@ -31,7 +28,6 @@ public:
static void WriteSettings(QSettings& s);
static void ReadSettings(QSettings& s);
void SetTitle(const QString& str);
void SetGameDirectories(const QStringList& dirs);
[[nodiscard]] QStringList GetGameDirectories() const;
@@ -55,8 +51,6 @@ protected:
/*slots:*/
void update_info();
void adjust_size();
void save();
void clear();
void add_game_directory();
-4
View File
@@ -1,8 +1,6 @@
#ifndef CONFIGURATION_ITEM_H
#define CONFIGURATION_ITEM_H
#include "common.h"
#include <QObject>
#include <QTreeWidgetItem>
@@ -23,8 +21,6 @@ public:
void Update();
bool operator<(const QTreeWidgetItem& other) const override;
KYTY_QT_CLASS_NO_COPY(ConfigurationItem);
Configuration& GetInfo() { return *m_info; }
[[nodiscard]] const Configuration& GetInfo() const { return *m_info; }
// void SetInfo(Configuration* info);
+1 -13
View File
@@ -1,7 +1,6 @@
#ifndef CONFIGURATION_LIST_WIDGET_H
#define CONFIGURATION_LIST_WIDGET_H
#include "common.h"
#include "configuration.h"
#include <QMap>
@@ -14,7 +13,6 @@ class CompatibilityDatabase;
class QEvent;
class QTreeWidgetItem;
class QPoint;
class MainDialog;
namespace Ui {
class ConfigurationListWidget;
@@ -22,27 +20,20 @@ class ConfigurationListWidget;
class ConfigurationListWidget: public QWidget {
Q_OBJECT
KYTY_QT_CLASS_NO_COPY(ConfigurationListWidget);
public:
explicit ConfigurationListWidget(QWidget* parent = nullptr);
~ConfigurationListWidget() override;
void SetRunEnabled(bool flag) { m_run_enabled = flag; }
[[nodiscard]] bool IsRunEnabled() const { return m_run_enabled; }
void SetRunEnabled(bool flag) { m_run_enabled = flag; }
[[nodiscard]] const ConfigurationItem* GetSelectedItem() const { return m_selected_item; }
ConfigurationItem* GetSelectedItem() { return m_selected_item; }
void SetMainDialog(MainDialog* main_dialog) { m_main_dialog = main_dialog; }
MainDialog* GetMainDialog() { return m_main_dialog; }
[[nodiscard]] const QString& GetSettingsFile() const { return m_settings_file; }
[[nodiscard]] const QStringList& GetGameDirectories() const { return m_game_dirs; }
[[nodiscard]] const QStringList& GetHostInputMapping() const {
return m_global_info.host_input_mapping;
}
[[nodiscard]] bool CanViewSelectedTrophies() const;
bool EnsureGameDirectory();
void ScanGameDirectory();
@@ -66,8 +57,6 @@ protected slots:
void delete_configuartion();
void edit_global_settings();
void edit_input_mapping();
void run_configuration();
void list_currentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous);
void list_itemDoubleClicked(QTreeWidgetItem* witem, int column);
void show_context_menu(const QPoint& pos);
void open_game_folder();
@@ -84,7 +73,6 @@ private:
ConfigurationItem* m_selected_item = nullptr;
bool m_run_enabled = true;
Ui::ConfigurationListWidget* m_ui = nullptr;
MainDialog* m_main_dialog = nullptr;
QString m_settings_file;
QStringList m_game_dirs;
Configuration m_global_info;
-4
View File
@@ -1,8 +1,6 @@
#ifndef MAIN_DIALOG_H
#define MAIN_DIALOG_H
#include "common.h"
#include <QDialog>
#include <QString>
@@ -15,11 +13,9 @@ class QResizeEvent;
class Configuration;
class MainDialog: public QDialog {
Q_OBJECT
KYTY_QT_CLASS_NO_COPY(MainDialog);
signals:
void Start();
void Quit();
void Resize();
public:
+1 -2
View File
@@ -1,9 +1,8 @@
#ifndef MANDATORY_LINEEDIT_H
#define MANDATORY_LINEEDIT_H
#include "common.h"
#include <QLineEdit>
#include <QObject>
#include <QString>
class QPaintEvent;
-4
View File
@@ -1,8 +1,6 @@
#ifndef PATCHES_DIALOG_H
#define PATCHES_DIALOG_H
#include "common.h"
#include <QDialog>
#include <QString>
@@ -16,8 +14,6 @@ public:
explicit PatchesDialog(const Configuration& game, QWidget* parent = nullptr);
~PatchesDialog() override = default;
KYTY_QT_CLASS_NO_COPY(PatchesDialog);
[[nodiscard]] static bool IsSupportedTitleId(const QString& title_id);
[[nodiscard]] static QString PatchPlanPath(const QString& title_id);
@@ -1,8 +1,6 @@
#ifndef TROPHY_VIEWER_DIALOG_H
#define TROPHY_VIEWER_DIALOG_H
#include "common.h"
#include <QDialog>
class QTabWidget;
@@ -10,8 +8,6 @@ class QWidget;
class Configuration;
class TrophyViewerDialog: public QDialog {
KYTY_QT_CLASS_NO_COPY(TrophyViewerDialog);
public:
explicit TrophyViewerDialog(QWidget* parent = nullptr);
+2 -13
View File
@@ -108,6 +108,7 @@ ConfigurationEditDialog::ConfigurationEditDialog(Configuration& info, QWidget* p
InitGameDirectories();
connect(m_ui->ok_button, &QPushButton::clicked, this, &ConfigurationEditDialog::save);
connect(m_ui->cancel_button, &QPushButton::clicked, this, &QDialog::reject);
connect(m_ui->clear_button, &QPushButton::clicked, this, &ConfigurationEditDialog::clear);
connect(m_ui->comboBox_shader_log_direction, &QComboBox::currentTextChanged, this,
[this](const QString& text) {
@@ -306,10 +307,6 @@ void ConfigurationEditDialog::InitGameDirectories() {
update_game_directory_buttons();
}
void ConfigurationEditDialog::SetTitle(const QString& str) {
setWindowTitle(str);
}
void ConfigurationEditDialog::SetGameDirectories(const QStringList& dirs) {
m_show_game_dirs = true;
m_game_dirs_list->clear();
@@ -400,14 +397,6 @@ static void UpdateInfo(Configuration& info, Ui::ConfigurationEditDialog& ui) {
info.profiler_enabled = ui.checkBox_profiler->isChecked();
}
void ConfigurationEditDialog::update_info() {
UpdateInfo(m_info, *m_ui);
}
void ConfigurationEditDialog::adjust_size() {
this->adjustSize();
}
void ConfigurationEditDialog::save() {
if (MandatoryLineEdit::FindEmpty(this)) {
QMessageBox::critical(this, tr("Save failed"), tr("Please fill all mandatory fields"));
@@ -427,7 +416,7 @@ void ConfigurationEditDialog::save() {
return;
}
update_info();
UpdateInfo(m_info, *m_ui);
emit accept();
}
+3 -7
View File
@@ -77,10 +77,6 @@ void SetStatus(QComboBox* combo, Configuration::GameStatus status) {
combo->setCurrentIndex(index >= 0 ? index : 0);
}
QIcon StandardIcon(QStyle::StandardPixmap icon) {
return QApplication::style()->standardIcon(icon);
}
QString GetPathText(const Configuration& info) {
return !info.game_path.isEmpty() ? info.game_path : info.basedir;
}
@@ -278,11 +274,11 @@ void ConfigurationItem::UpdateIcon() {
}
if (m_running) {
setIcon(NameColumn, StandardIcon(QStyle::SP_MediaPlay));
setIcon(NameColumn, QApplication::style()->standardIcon(QStyle::SP_MediaPlay));
} else if (m_info->custom_settings) {
setIcon(NameColumn, StandardIcon(QStyle::SP_FileIcon));
setIcon(NameColumn, QApplication::style()->standardIcon(QStyle::SP_FileIcon));
} else {
setIcon(NameColumn, StandardIcon(QStyle::SP_ComputerIcon));
setIcon(NameColumn, QApplication::style()->standardIcon(QStyle::SP_ComputerIcon));
}
}
+4 -19
View File
@@ -1,6 +1,5 @@
#include "configurationListWidget.h"
#include "common.h"
#include "compatibilityDatabase.h"
#include "configuration.h"
#include "configurationEditDialog.h"
@@ -232,7 +231,7 @@ ConfigurationListWidget::ConfigurationListWidget(QWidget* parent)
connect(m_ui->delete_button, &QToolButton::clicked, this,
&ConfigurationListWidget::delete_configuartion);
connect(m_ui->cfgs_list, &QTreeWidget::currentItemChanged, this,
&ConfigurationListWidget::list_currentItemChanged);
&ConfigurationListWidget::SelectItem);
connect(m_ui->cfgs_list, &QTreeWidget::itemDoubleClicked, this,
&ConfigurationListWidget::list_itemDoubleClicked);
connect(m_ui->cfgs_list, &QTreeWidget::customContextMenuRequested, this,
@@ -676,7 +675,7 @@ void ConfigurationListWidget::edit_configuration() {
}
ConfigurationEditDialog dlg(item->GetInfo(), this);
dlg.SetTitle(tr("Edit game settings"));
dlg.setWindowTitle(tr("Edit game settings"));
if (dlg.exec() == QDialog::Accepted) {
item->GetInfo().custom_settings = true;
@@ -708,7 +707,7 @@ void ConfigurationListWidget::edit_global_settings() {
info.name = tr("Global settings");
ConfigurationEditDialog dlg(info, this);
dlg.SetTitle(tr("Global settings"));
dlg.setWindowTitle(tr("Global settings"));
dlg.SetGameDirectories(m_game_dirs);
if (dlg.exec() == QDialog::Accepted) {
@@ -731,15 +730,6 @@ void ConfigurationListWidget::ClearCustomSettings(ConfigurationItem* item) {
delete m_custom_infos.take(item->GetInfo().game_path);
}
void ConfigurationListWidget::run_configuration() {
emit Run();
}
bool ConfigurationListWidget::CanViewSelectedTrophies() const {
return m_selected_item != nullptr &&
TrophyViewerDialog::HasTrophyData(&m_selected_item->GetInfo());
}
void ConfigurationListWidget::ViewTrophies() {
auto* current = static_cast<ConfigurationItem*>(m_ui->cfgs_list->currentItem());
auto* item = current != nullptr ? current : m_selected_item;
@@ -852,11 +842,6 @@ void ConfigurationListWidget::SelectItem(QTreeWidgetItem* witem) {
emit Select();
}
void ConfigurationListWidget::list_currentItemChanged(QTreeWidgetItem* current,
QTreeWidgetItem* /*previous*/) {
SelectItem(current);
}
void ConfigurationListWidget::list_itemDoubleClicked(QTreeWidgetItem* witem, int /*column*/) {
SelectItem(witem);
if (m_run_enabled) {
@@ -877,7 +862,7 @@ void ConfigurationListWidget::show_context_menu(const QPoint& pos) {
const bool has_trophy_data =
item != nullptr && TrophyViewerDialog::HasTrophyData(&item->GetInfo());
QAction* action_run = menu.addAction(tr("Run"), this, SLOT(run_configuration()));
QAction* action_run = menu.addAction(tr("Run"), this, SIGNAL(Run()));
QAction* action_open_folder =
menu.addAction(style()->standardIcon(QStyle::SP_DirOpenIcon), tr("Open game folder"), this,
SLOT(open_game_folder()));
-4
View File
@@ -2,8 +2,6 @@
#include "launcherTheme.h"
#include <QApplication>
#include <QArgument>
#include <QObject>
int main(int argc, char* argv[]) {
QApplication a(argc, argv);
@@ -11,8 +9,6 @@ int main(int argc, char* argv[]) {
MainDialog w;
QObject::connect(&a, &QApplication::aboutToQuit, &w, &MainDialog::Quit);
w.emit Start();
w.show();
+4 -17
View File
@@ -1,6 +1,5 @@
#include "mainDialog.h"
#include "common.h"
#include "configuration.h"
#include "configurationItem.h"
#include "configurationListWidget.h"
@@ -17,6 +16,7 @@
#include <QIODevice>
#include <QLabel>
#include <QMessageBox>
#include <QObject>
#include <QPointer>
#include <QProcess>
#include <QRadioButton>
@@ -27,6 +27,8 @@
#include <QVariant>
#include <QtCore>
#include <cstdint>
#include "ui_main_dialog.h"
#if defined(_WIN32)
@@ -58,20 +60,8 @@ constexpr char SETTINGS_MAIN_DIALOG[] = "MainDialog";
constexpr char SETTINGS_MAIN_LAST_GEOMETRY[] = "geometry";
constexpr char SETTINGS_CHECK_UPDATES[] = "check_updates_on_startup";
class DetachableProcess: public QProcess {
Q_OBJECT;
public:
explicit DetachableProcess(QObject* parent = nullptr): QProcess(parent) {}
void Detach() {
this->waitForStarted();
setProcessState(QProcess::NotRunning);
}
};
class MainDialogPrivate: public QObject {
Q_OBJECT
KYTY_QT_CLASS_NO_COPY(MainDialogPrivate);
public:
explicit MainDialogPrivate(QObject* parent = nullptr): QObject(parent) {}
@@ -99,7 +89,7 @@ private:
UpdateChecker* m_update_checker = nullptr;
QString m_interpreter;
/*DetachableProcess*/ QProcess m_process;
QProcess m_process;
QPointer<ConfigurationItem> m_running_item;
};
@@ -121,7 +111,6 @@ void MainDialogPrivate::Setup(MainDialog* main_dialog) {
m_main_dialog = main_dialog;
m_update_checker = new UpdateChecker(main_dialog);
m_ui->widget->SetMainDialog(main_dialog);
m_ui->check_updates_on_startup->setChecked(g_check_updates_on_startup);
m_ui->check_updates_link->setVisible(UpdateChecker::IsSupported());
m_ui->check_updates_on_startup->setVisible(UpdateChecker::IsSupported());
@@ -154,8 +143,6 @@ void MainDialogPrivate::Setup(MainDialog* main_dialog) {
Update();
});
// connect(main_dialog, &MainDialog::Quit, [=]() { m_process.Detach(); });
m_ui->label_settings_file->setText(tr("Settings file: ") + m_ui->widget->GetSettingsFile());
m_main_dialog->restoreGeometry(g_last_geometry);
+7 -3
View File
@@ -3,6 +3,7 @@
#include "configuration.h"
#include <QCoreApplication>
#include <QDebug>
#include <QDialogButtonBox>
#include <QDir>
#include <QFile>
@@ -129,8 +130,11 @@ void PatchesDialog::Save() {
document.setObject(root);
QSaveFile output(path);
if (output.open(QIODevice::WriteOnly) && output.write(document.toJson()) >= 0 &&
output.commit()) {
m_status->setText(tr("Cheat selection saved."));
if (!output.open(QIODevice::WriteOnly) || output.write(document.toJson()) < 0 ||
!output.commit()) {
qWarning() << "Could not save cheat file:" << output.errorString();
m_status->setText(tr("Could not save cheat file: %1").arg(output.errorString()));
return;
}
m_status->setText(tr("Cheat selection saved."));
}
+12 -25
View File
@@ -20,6 +20,7 @@
#include <QLabel>
#include <QMap>
#include <QMessageBox>
#include <QObject>
#include <QPixmap>
#include <QRegularExpression>
#include <QSet>
@@ -32,8 +33,9 @@
#include <QVBoxLayout>
#include <QVariant>
#include <QWidget>
#include <QtEndian>
#include <limits>
#include <utility>
namespace {
@@ -83,21 +85,6 @@ static bool CanRead(const QByteArray& data, qsizetype offset, qsizetype size) {
return offset >= 0 && size >= 0 && offset <= data.size() && size <= data.size() - offset;
}
static quint32 ReadBe32(const QByteArray& data, qsizetype offset) {
const auto* p = reinterpret_cast<const uchar*>(data.constData() + offset);
return (static_cast<quint32>(p[0]) << 24u) | (static_cast<quint32>(p[1]) << 16u) |
(static_cast<quint32>(p[2]) << 8u) | static_cast<quint32>(p[3]);
}
static quint64 ReadBe64(const QByteArray& data, qsizetype offset) {
return (static_cast<quint64>(ReadBe32(data, offset)) << 32u) |
static_cast<quint64>(ReadBe32(data, offset + 4));
}
static bool FitsQSizeType(quint64 value) {
return value <= static_cast<quint64>(std::numeric_limits<qsizetype>::max());
}
static QString ReadFixedString(const QByteArray& data, qsizetype offset, qsizetype max_size) {
if (!CanRead(data, offset, max_size)) {
return {};
@@ -125,33 +112,33 @@ static bool ReadUcp(const QString& file_name, QMap<QString, QByteArray>& files,
return false;
}
const auto magic = ReadBe32(data, 0x00);
const auto magic = qFromBigEndian<quint32>(data.constData() + 0x00);
if (magic != UCP_MAGIC) {
error = QObject::tr("%1 has an invalid trophy package magic.")
.arg(QFileInfo(file_name).fileName());
return false;
}
const auto version = ReadBe32(data, 0x04);
const auto version = qFromBigEndian<quint32>(data.constData() + 0x04);
if (version != UCP_VERSION) {
error = QObject::tr("%1 uses unsupported trophy package version %2.")
.arg(QFileInfo(file_name).fileName(), QString::number(version));
return false;
}
const auto declared_size = ReadBe64(data, 0x08);
const auto declared_size = qFromBigEndian<quint64>(data.constData() + 0x08);
if (declared_size > static_cast<quint64>(data.size())) {
error = QObject::tr("%1 is truncated.").arg(QFileInfo(file_name).fileName());
return false;
}
const auto file_count = ReadBe32(data, 0x10);
const auto toc_offset = static_cast<quint64>(ReadBe32(data, 0x14));
const auto file_count = qFromBigEndian<quint32>(data.constData() + 0x10);
const auto toc_offset = static_cast<quint64>(qFromBigEndian<quint32>(data.constData() + 0x14));
const auto data_size = static_cast<quint64>(data.size());
const quint64 table_size = UCP_TOC_SKIP + static_cast<quint64>(file_count) * UCP_ENTRY_LEN;
if (toc_offset > data_size || table_size > data_size - toc_offset ||
!FitsQSizeType(toc_offset + table_size)) {
!std::in_range<qsizetype>(toc_offset + table_size)) {
error = QObject::tr("%1 has an invalid table of contents.")
.arg(QFileInfo(file_name).fileName());
return false;
@@ -162,14 +149,14 @@ static bool ReadUcp(const QString& file_name, QMap<QString, QByteArray>& files,
static_cast<quint64>(i) * UCP_ENTRY_LEN);
UcpEntry entry;
entry.name = ReadFixedString(data, entry_offset, UCP_NAME_LEN).trimmed();
entry.offset = ReadBe64(data, entry_offset + 0x20);
entry.size = ReadBe64(data, entry_offset + 0x28);
entry.offset = qFromBigEndian<quint64>(data.constData() + entry_offset + 0x20);
entry.size = qFromBigEndian<quint64>(data.constData() + entry_offset + 0x28);
if (entry.name.isEmpty()) {
continue;
}
if (entry.offset > data_size || entry.size > data_size - entry.offset ||
!FitsQSizeType(entry.offset) || !FitsQSizeType(entry.size)) {
!std::in_range<qsizetype>(entry.offset) || !std::in_range<qsizetype>(entry.size)) {
error = QObject::tr("%1 has an invalid entry for %2.")
.arg(QFileInfo(file_name).fileName(), entry.name);
return false;
+3 -2
View File
@@ -849,8 +849,9 @@ int KYTY_SYSV_ABI AjmMemoryUnregister(uint32_t context, void* ptr) {
int KYTY_SYSV_ABI AjmBatchInitialize(void* buffer, size_t size, AjmBatchInfo* info) {
PRINT_NAME();
EXIT_NOT_IMPLEMENTED(buffer == nullptr);
EXIT_NOT_IMPLEMENTED(info == nullptr);
if (buffer == nullptr || info == nullptr) {
return AJM_ERROR_INVALID_PARAMETER;
}
info->buffer = buffer;
info->offset = 0;
+32 -22
View File
@@ -38,9 +38,9 @@ static constexpr uint32_t AJM_DEC_M4AAC_MAX_SAMPLING_FREQ_INDEX = 11;
class AjmAacDecoder final: public AjmDecoder {
public:
AjmAacDecoder(uint32_t channels, uint32_t sample_rate, AjmSampleEncoding encoding,
AjmAacDecoder(uint32_t max_channels, uint32_t sample_rate, AjmSampleEncoding encoding,
uint64_t flags)
: AjmDecoder(channels, sample_rate, encoding), m_flags(flags) {
: AjmDecoder(0, sample_rate, encoding), m_max_channels(max_channels), m_flags(flags) {
m_codec = avcodec_find_decoder(AV_CODEC_ID_AAC);
if (m_codec == nullptr) {
LOGF("AJM AAC: avcodec_find_decoder failed\n");
@@ -94,6 +94,11 @@ public:
((m_flags & AJM_INSTANCE_FLAG_DEC_M4AAC_ENABLE_NONDELAY_OUTPUT) != 0 ? 0u : 2u);
m_total_decoded_samples = 0;
m_bitrate = 0;
m_channels = 0;
m_raw_configured = false;
if (m_config_number == AJM_DEC_M4AAC_CONFIG_NUMBER_RAW) {
m_sample_rate = SamplingRateFromIndex(m_sampling_freq_index);
}
if (m_is_initialized) {
OpenDecoder();
}
@@ -189,26 +194,6 @@ private:
return;
}
if (m_config_number == AJM_DEC_M4AAC_CONFIG_NUMBER_RAW) {
const auto sample_index =
std::min(m_sampling_freq_index, AJM_DEC_M4AAC_MAX_SAMPLING_FREQ_INDEX);
const auto channels = std::clamp<uint32_t>(m_channels, 1u, AJM_DEC_M4AAC_MAX_CHANNELS);
constexpr uint32_t audio_object_type = 2;
auto* extradata = static_cast<uint8_t*>(av_mallocz(2 + AV_INPUT_BUFFER_PADDING_SIZE));
if (extradata == nullptr) {
Release();
return;
}
extradata[0] = static_cast<uint8_t>((audio_object_type << 3u) | (sample_index >> 1u));
extradata[1] = static_cast<uint8_t>(((sample_index & 0x1u) << 7u) |
(std::min(channels, 7u) << 3u));
m_codec_context->extradata = extradata;
m_codec_context->extradata_size = 2;
SetFormat(channels, SamplingRateFromIndex(sample_index), m_sample_encoding);
}
if (avcodec_open2(m_codec_context, m_codec, nullptr) < 0) {
LOGF("AJM AAC: decoder initialization failed\n");
Release();
@@ -222,6 +207,10 @@ private:
}
const auto channels = static_cast<uint32_t>(std::max(frame->ch_layout.nb_channels, 1));
if (channels > m_max_channels) {
result->result = AJM_RESULT_TOO_MANY_CHANNELS;
return false;
}
const auto bpf = channels * AjmBytesPerSample(m_sample_encoding);
if (bpf == 0) {
result->result = AJM_RESULT_INVALID_PARAMETER;
@@ -306,6 +295,25 @@ private:
return false;
}
std::memcpy(packet->data, packet_data, static_cast<size_t>(packet_size));
if (m_config_number == AJM_DEC_M4AAC_CONFIG_NUMBER_RAW && !m_raw_configured) {
// Only indexed stereo starts with a channel pair; the instance limit is not
// the stream's channel count. A leading SCE remains ambiguous.
const auto channels = (packet_data[0] >> 5u) == 1u
? 2u
: std::clamp(m_max_channels, 1u, AJM_DEC_M4AAC_MAX_CHANNELS);
auto* extradata = av_packet_new_side_data(packet, AV_PKT_DATA_NEW_EXTRADATA, 2);
if (extradata == nullptr) {
av_packet_free(&packet);
result->result = AJM_RESULT_CODEC_ERROR | AJM_RESULT_FATAL;
return false;
}
constexpr uint32_t audio_object_type = 2;
extradata[0] = static_cast<uint8_t>((audio_object_type << 3u) |
(m_sampling_freq_index >> 1u));
extradata[1] = static_cast<uint8_t>(((m_sampling_freq_index & 1u) << 7u) |
(std::min(channels, 7u) << 3u));
m_raw_configured = true;
}
int rc = avcodec_send_packet(m_codec_context, packet);
av_packet_free(&packet);
@@ -353,12 +361,14 @@ private:
const AVCodec* m_codec = nullptr;
AVCodecContext* m_codec_context = nullptr;
const uint32_t m_max_channels;
uint64_t m_flags = 0;
uint32_t m_config_number = AJM_DEC_M4AAC_CONFIG_NUMBER_ADTS;
uint32_t m_sampling_freq_index = 3;
uint32_t m_skip_frames = 2;
uint32_t m_bitrate = 0;
bool m_is_initialized = false;
bool m_raw_configured = false;
};
} // namespace Libs::Audio::Ajm
+1
View File
@@ -72,6 +72,7 @@ constexpr int32_t AJM_RESULT_INVALID_DATA = 0x00000002;
constexpr int32_t AJM_RESULT_INVALID_PARAMETER = 0x00000004;
constexpr int32_t AJM_RESULT_PARTIAL_INPUT = 0x00000008;
constexpr int32_t AJM_RESULT_NOT_ENOUGH_ROOM = 0x00000010;
constexpr int32_t AJM_RESULT_TOO_MANY_CHANNELS = 0x00000040;
constexpr int32_t AJM_RESULT_CODEC_ERROR = 0x40000000;
constexpr int32_t AJM_RESULT_FATAL = static_cast<int32_t>(0x80000000u);
+5 -6
View File
@@ -5,7 +5,6 @@
#include "common/common.h"
#include "common/emulatorConfig.h"
#include "common/logging/log.h"
#include "common/magicEnum.h"
#include "common/stringUtils.h"
#include "common/threads.h"
#include "kernel/pthread.h"
@@ -20,6 +19,7 @@
#include <cstdlib>
#include <cstring>
#include <limits>
#include <magic_enum.hpp>
#include <vector>
#include "libatrac9.h"
@@ -800,8 +800,7 @@ int KYTY_SYSV_ABI AudioOutOpen(int user_id, int type, int index, uint32_t len, u
default:;
}
LOGF("\t param = %u (format=%u, %s)\n", param, format_param,
Common::EnumName(format).c_str());
LOGF("\t param = %u (format=%u, %s)\n", param, format_param, magic_enum::enum_name(format));
EXIT_NOT_IMPLEMENTED(format == Audio::Format::Unknown);
@@ -966,7 +965,7 @@ static int OpenPort(int user_id, int type, int index, uint32_t len, uint32_t fre
default: return AUDIO_IN_ERROR_INVALID_PARAM;
}
LOGF("\t param = %u (%s)\n", param, Common::EnumName(format).c_str());
LOGF("\t param = %u (%s)\n", param, magic_enum::enum_name(format));
EXIT_IF(g_audio == nullptr);
@@ -2361,7 +2360,7 @@ int KYTY_SYSV_ABI Ngs2RackCreate(uintptr_t system_handle, uint32_t rack_id,
default: EXIT("unknown rack_id: 0x%" PRIx32 "\n", rack_id);
}
LOGF("\t type = %s\n", Common::EnumName(rack->type).c_str());
LOGF("\t type = %s\n", magic_enum::enum_name(rack->type));
rack->allocator = Ngs2BufferAllocator();
rack->buffer_info = *buffer_info;
@@ -3120,7 +3119,7 @@ int KYTY_SYSV_ABI Ngs2VoiceGetState(uintptr_t voice_handle, Ngs2VoiceState* stat
sampler->waveform_data = nullptr;
break;
}
default: EXIT("unknown type: %s\n", Common::EnumName(voice->rack->type).c_str());
default: EXIT("unknown type: %s\n", magic_enum::enum_name(voice->rack->type));
}
return OK;
+2 -2
View File
@@ -1,6 +1,5 @@
#include "common/common.h"
#include "common/logging/log.h"
#include "common/magicEnum.h"
#include "common/stringUtils.h"
#include "kernel/fileSystem.h"
#include "kernel/pthread.h"
@@ -16,6 +15,7 @@
#include <cstdio>
#include <cstring>
#include <deque>
#include <magic_enum.hpp>
#include <memory>
#include <mutex>
#include <optional>
@@ -1758,7 +1758,7 @@ static void log_init_common(const AvPlayerMemAllocator& mem, const AvPlayerFileR
"= %d\n\t base_priority "
" = %u\n\t auto_start = %u\n\t default_language "
" = %s\n",
Common::EnumName(debug_level).c_str(), buffers, priority, auto_start,
magic_enum::enum_name(debug_level), buffers, priority, auto_start,
language == nullptr ? "(null)" : language);
}
+112 -2
View File
@@ -13,6 +13,8 @@
#include "libs/padData.h"
#include <algorithm>
#include <array>
#include <cmath>
#include <cstring>
#include <vector>
@@ -87,6 +89,9 @@ struct ControllerState {
uint32_t buttons = 0;
int axes[static_cast<int>(Axis::AxisMax)] = {128, 128, 128, 128, 0, 0};
Touch touch[2];
std::array<float, 3> accel {0.0f, 1.0f, 0.0f};
std::array<float, 3> gyro {};
std::array<float, 4> orientation {0.0f, 0.0f, 0.0f, 1.0f};
};
class GameController {
@@ -101,6 +106,9 @@ public:
void Axis(int id, Axis axis, int value);
void RightStick(int id, int x, int y);
void TouchPad(int id, int finger, bool down, float x, float y);
void Motion(int id, Sensor sensor, const float* data, uint64_t time_us);
void SetMotionSensorState(bool enable);
void ResetOrientation();
void ResetInputState();
void ReleaseHostPads();
void GetConnectionInfo(bool* flag, int* count);
@@ -121,6 +129,8 @@ private:
int m_active_id = -1;
bool m_connected = false;
int m_connected_count = 0;
bool m_motion_enabled = true;
uint64_t m_gyro_time = 0;
ControllerState m_state;
ControllerState m_states[STATES_MAX];
bool m_obtained[STATES_MAX] {};
@@ -144,7 +154,16 @@ static void pad_fill_data(PadData* data, const ControllerState& state, bool conn
data->right_stick_y = state.axes[static_cast<int>(Axis::RightY)];
data->analog_buttons_l2 = state.axes[static_cast<int>(Axis::TriggerLeft)];
data->analog_buttons_r2 = state.axes[static_cast<int>(Axis::TriggerRight)];
data->orientation_w = 1.0f;
data->acceleration_x = state.accel[0];
data->acceleration_y = state.accel[1];
data->acceleration_z = state.accel[2];
data->angular_velocity_x = state.gyro[0];
data->angular_velocity_y = state.gyro[1];
data->angular_velocity_z = state.gyro[2];
data->orientation_x = state.orientation[0];
data->orientation_y = state.orientation[1];
data->orientation_z = state.orientation[2];
data->orientation_w = state.orientation[3];
for (const auto& touch: state.touch) {
if (touch.down) {
auto& output = data->touch_data.touch[data->touch_data.touch_num++];
@@ -273,6 +292,18 @@ void GameController::Connect(int id) {
m_connected_ids.push_back(id);
if (id != HOST_INPUT_CONTROLLER_ID) {
if (auto* pad = SDL_GameControllerFromInstanceID(static_cast<SDL_JoystickID>(id));
pad != nullptr) {
for (auto sensor: {SDL_SENSOR_ACCEL, SDL_SENSOR_GYRO}) {
if (SDL_GameControllerHasSensor(pad, sensor) &&
SDL_GameControllerSetSensorEnabled(pad, sensor, SDL_TRUE) != 0) {
LOGF("\t enabling controller sensor failed: %s\n", SDL_GetError());
}
}
}
}
CheckActive();
}
@@ -311,6 +342,7 @@ void GameController::CheckActive() {
m_active_id = new_active_id;
m_connected = new_connected;
m_state = {};
m_gyro_time = 0;
m_states_num = 0;
m_first_state = 0;
m_next_touch_id = 1;
@@ -402,9 +434,81 @@ void GameController::TouchPad(int id, int finger, bool down, float x, float y) {
}
}
void GameController::Motion(int id, Sensor sensor, const float* data, uint64_t time_us) {
Common::LockGuard lock(m_mutex);
if (id != m_active_id || !m_motion_enabled) {
return;
}
// Convert acceleration to G; angular velocity is already in rad/s.
if (sensor == Sensor::Accel) {
for (int i = 0; i < 3; i++) {
m_state.accel[i] = data[i] / SDL_STANDARD_GRAVITY;
}
} else {
std::copy_n(data, 3, m_state.gyro.begin());
// Do not extrapolate a single sample across lost reports (e.g. loss of window focus).
constexpr uint64_t max_gyro_interval_us = 100000;
if (m_gyro_time != 0 && time_us > m_gyro_time &&
time_us - m_gyro_time <= max_gyro_interval_us) {
const float dt = static_cast<float>(time_us - m_gyro_time) * 0.000001f;
const float speed =
std::sqrt(data[0] * data[0] + data[1] * data[1] + data[2] * data[2]);
const float half_angle = speed * dt * 0.5f;
const float scale = speed > 0.0f ? std::sin(half_angle) / speed : 0.0f;
const float x = data[0] * scale;
const float y = data[1] * scale;
const float z = data[2] * scale;
const float w = std::cos(half_angle);
const auto q = m_state.orientation;
// Accumulate body-local rotation relative to connection / orientation reset.
m_state.orientation = {q[3] * x + q[0] * w + q[1] * z - q[2] * y,
q[3] * y - q[0] * z + q[1] * w + q[2] * x,
q[3] * z + q[0] * y - q[1] * x + q[2] * w,
q[3] * w - q[0] * x - q[1] * y - q[2] * z};
float length = 0.0f;
for (float value: m_state.orientation) {
length += value * value;
}
length = std::sqrt(length);
for (float& value: m_state.orientation) {
value /= length;
}
}
m_gyro_time = time_us;
}
m_state.time = LibKernel::KernelGetProcessTime();
AddState();
}
void GameController::SetMotionSensorState(bool enable) {
Common::LockGuard lock(m_mutex);
if (m_motion_enabled != enable) {
m_motion_enabled = enable;
m_gyro_time = 0;
m_state.accel = {0.0f, 1.0f, 0.0f};
m_state.gyro = {};
m_state.time = LibKernel::KernelGetProcessTime();
AddState();
}
}
void GameController::ResetOrientation() {
Common::LockGuard lock(m_mutex);
m_state.orientation = {0.0f, 0.0f, 0.0f, 1.0f};
m_gyro_time = 0;
m_state.time = LibKernel::KernelGetProcessTime();
AddState();
}
void GameController::ResetInputState() {
Common::LockGuard lock(m_mutex);
m_state = {};
m_state.buttons = 0;
std::fill_n(m_state.axes, 4, 128);
std::fill_n(m_state.axes + 4, 2, 0);
for (auto& touch: m_state.touch) {
touch = {};
}
m_state.time = LibKernel::KernelGetProcessTime();
m_states_num = 0;
m_first_state = 0;
@@ -580,6 +684,10 @@ void SetTouchPad(int id, int finger, bool down, float x, float y) {
g_controller->TouchPad(id, finger, down, x, y);
}
void SetSensor(int id, Sensor sensor, const float* data, uint64_t time_us) {
g_controller->Motion(id, sensor, data, time_us);
}
void ResetInputState() {
g_controller->ResetInputState();
}
@@ -646,6 +754,7 @@ int KYTY_SYSV_ABI PadSetMotionSensorState(int handle, bool enable) {
}
LOGF("\t enable = %s\n", (enable ? "true" : "false"));
g_controller->SetMotionSensorState(enable);
return OK;
}
@@ -669,6 +778,7 @@ int KYTY_SYSV_ABI PadResetOrientation(int handle) {
return PAD_ERROR_INVALID_HANDLE;
}
g_controller->ResetOrientation();
return OK;
}
+3
View File
@@ -46,6 +46,8 @@ enum class Axis {
AxisMax
};
enum class Sensor { Accel, Gyro };
struct PadControllerInformation;
struct PadData;
struct PadVibrationParam;
@@ -69,6 +71,7 @@ void SetButton(int id, uint32_t button, bool down);
void SetAxis(int id, Axis axis, int value);
void SetRightStick(int id, int x, int y);
void SetTouchPad(int id, int finger, bool down, float x, float y);
void SetSensor(int id, Sensor sensor, const float* data, uint64_t time_us);
void ResetInputState();
int KYTY_SYSV_ABI PadInit();
+6 -1
View File
@@ -527,7 +527,12 @@ static int kyty_printf_internal(bool sn, char* sn_s, size_t sn_n, const char* fo
} else if (*format == '*') {
// const int prec = (int)va_arg(va, int);
const int prec = VaArg_int(va_list);
precision = prec > 0 ? static_cast<unsigned int>(prec) : 0U;
if (prec < 0) {
// A negative dynamic precision is treated as omitted.
flags &= ~FLAGS_PRECISION;
} else {
precision = static_cast<unsigned int>(prec);
}
format++;
}
}
+26 -29
View File
@@ -7,6 +7,7 @@
#include <algorithm>
#include <atomic>
#include <cmath>
#include <cstdint>
#include <cstring>
#include <deque>
#include <mutex>
@@ -18,35 +19,31 @@
namespace Libs::Ime {
namespace {
constexpr int Error(uint32_t value) {
return static_cast<int32_t>(value);
}
constexpr int ERROR_BUSY = Error(0x80bc0001);
constexpr int ERROR_NOT_OPENED = Error(0x80bc0002);
constexpr int ERROR_CONNECTION_FAILED = Error(0x80bc0004);
constexpr int ERROR_EVENT_OVERFLOW = Error(0x80bc0007);
constexpr int ERROR_INVALID_TEXT = Error(0x80bc0006);
constexpr int ERROR_INVALID_USER_ID = Error(0x80bc0010);
constexpr int ERROR_INVALID_TYPE = Error(0x80bc0011);
constexpr int ERROR_INVALID_LANGUAGES = Error(0x80bc0012);
constexpr int ERROR_INVALID_ENTER_LABEL = Error(0x80bc0013);
constexpr int ERROR_INVALID_INPUT_METHOD = Error(0x80bc0014);
constexpr int ERROR_INVALID_OPTION = Error(0x80bc0015);
constexpr int ERROR_INVALID_MAX_TEXT_LENGTH = Error(0x80bc0016);
constexpr int ERROR_INVALID_TEXT_BUFFER = Error(0x80bc0017);
constexpr int ERROR_INVALID_POSX = Error(0x80bc0018);
constexpr int ERROR_INVALID_POSY = Error(0x80bc0019);
constexpr int ERROR_INVALID_HALIGN = Error(0x80bc001a);
constexpr int ERROR_INVALID_VALIGN = Error(0x80bc001b);
constexpr int ERROR_INVALID_EXTENDED = Error(0x80bc001c);
constexpr int ERROR_INVALID_WORK = Error(0x80bc0020);
constexpr int ERROR_INVALID_HANDLER = Error(0x80bc0022);
constexpr int ERROR_NO_RESOURCE_ID = Error(0x80bc0023);
constexpr int ERROR_INVALID_MODE = Error(0x80bc0024);
constexpr int ERROR_INVALID_PARAM = Error(0x80bc0030);
constexpr int ERROR_INVALID_ADDRESS = Error(0x80bc0031);
constexpr int ERROR_INVALID_RESERVED = Error(0x80bc0032);
constexpr int ERROR_BUSY = static_cast<int32_t>(0x80bc0001);
constexpr int ERROR_NOT_OPENED = static_cast<int32_t>(0x80bc0002);
constexpr int ERROR_CONNECTION_FAILED = static_cast<int32_t>(0x80bc0004);
constexpr int ERROR_EVENT_OVERFLOW = static_cast<int32_t>(0x80bc0007);
constexpr int ERROR_INVALID_TEXT = static_cast<int32_t>(0x80bc0006);
constexpr int ERROR_INVALID_USER_ID = static_cast<int32_t>(0x80bc0010);
constexpr int ERROR_INVALID_TYPE = static_cast<int32_t>(0x80bc0011);
constexpr int ERROR_INVALID_LANGUAGES = static_cast<int32_t>(0x80bc0012);
constexpr int ERROR_INVALID_ENTER_LABEL = static_cast<int32_t>(0x80bc0013);
constexpr int ERROR_INVALID_INPUT_METHOD = static_cast<int32_t>(0x80bc0014);
constexpr int ERROR_INVALID_OPTION = static_cast<int32_t>(0x80bc0015);
constexpr int ERROR_INVALID_MAX_TEXT_LENGTH = static_cast<int32_t>(0x80bc0016);
constexpr int ERROR_INVALID_TEXT_BUFFER = static_cast<int32_t>(0x80bc0017);
constexpr int ERROR_INVALID_POSX = static_cast<int32_t>(0x80bc0018);
constexpr int ERROR_INVALID_POSY = static_cast<int32_t>(0x80bc0019);
constexpr int ERROR_INVALID_HALIGN = static_cast<int32_t>(0x80bc001a);
constexpr int ERROR_INVALID_VALIGN = static_cast<int32_t>(0x80bc001b);
constexpr int ERROR_INVALID_EXTENDED = static_cast<int32_t>(0x80bc001c);
constexpr int ERROR_INVALID_WORK = static_cast<int32_t>(0x80bc0020);
constexpr int ERROR_INVALID_HANDLER = static_cast<int32_t>(0x80bc0022);
constexpr int ERROR_NO_RESOURCE_ID = static_cast<int32_t>(0x80bc0023);
constexpr int ERROR_INVALID_MODE = static_cast<int32_t>(0x80bc0024);
constexpr int ERROR_INVALID_PARAM = static_cast<int32_t>(0x80bc0030);
constexpr int ERROR_INVALID_ADDRESS = static_cast<int32_t>(0x80bc0031);
constexpr int ERROR_INVALID_RESERVED = static_cast<int32_t>(0x80bc0032);
constexpr uint32_t VALID_OPTIONS = 0x00007bff;
constexpr uint32_t VALID_EXTENDED_OPTIONS = 0x00004fde;
+22 -25
View File
@@ -5,6 +5,7 @@
#include <algorithm>
#include <atomic>
#include <cmath>
#include <cstdint>
#include <cstring>
#include <mutex>
#include <vector>
@@ -13,31 +14,27 @@ namespace Libs::Dialog::ImeDialog {
namespace {
constexpr int Error(uint32_t value) {
return static_cast<int32_t>(value);
}
constexpr int ERROR_BUSY = Error(0x80bc0001);
constexpr int ERROR_INVALID_USER_ID = Error(0x80bc0010);
constexpr int ERROR_INVALID_TYPE = Error(0x80bc0011);
constexpr int ERROR_INVALID_LANGUAGES = Error(0x80bc0012);
constexpr int ERROR_INVALID_ENTER_LABEL = Error(0x80bc0013);
constexpr int ERROR_INVALID_INPUT_METHOD = Error(0x80bc0014);
constexpr int ERROR_INVALID_OPTION = Error(0x80bc0015);
constexpr int ERROR_INVALID_MAX_TEXT_LENGTH = Error(0x80bc0016);
constexpr int ERROR_INVALID_TEXT_BUFFER = Error(0x80bc0017);
constexpr int ERROR_INVALID_POSX = Error(0x80bc0018);
constexpr int ERROR_INVALID_POSY = Error(0x80bc0019);
constexpr int ERROR_INVALID_HALIGN = Error(0x80bc001a);
constexpr int ERROR_INVALID_VALIGN = Error(0x80bc001b);
constexpr int ERROR_INVALID_EXTENDED = Error(0x80bc001c);
constexpr int ERROR_INVALID_PARAM = Error(0x80bc0030);
constexpr int ERROR_INVALID_ADDRESS = Error(0x80bc0031);
constexpr int ERROR_INVALID_RESERVED = Error(0x80bc0032);
constexpr int ERROR_INVALID_TITLE = Error(0x80bc0101);
constexpr int ERROR_NOT_RUNNING = Error(0x80bc0105);
constexpr int ERROR_NOT_FINISHED = Error(0x80bc0106);
constexpr int ERROR_NOT_IN_USE = Error(0x80bc0107);
constexpr int ERROR_BUSY = static_cast<int32_t>(0x80bc0001);
constexpr int ERROR_INVALID_USER_ID = static_cast<int32_t>(0x80bc0010);
constexpr int ERROR_INVALID_TYPE = static_cast<int32_t>(0x80bc0011);
constexpr int ERROR_INVALID_LANGUAGES = static_cast<int32_t>(0x80bc0012);
constexpr int ERROR_INVALID_ENTER_LABEL = static_cast<int32_t>(0x80bc0013);
constexpr int ERROR_INVALID_INPUT_METHOD = static_cast<int32_t>(0x80bc0014);
constexpr int ERROR_INVALID_OPTION = static_cast<int32_t>(0x80bc0015);
constexpr int ERROR_INVALID_MAX_TEXT_LENGTH = static_cast<int32_t>(0x80bc0016);
constexpr int ERROR_INVALID_TEXT_BUFFER = static_cast<int32_t>(0x80bc0017);
constexpr int ERROR_INVALID_POSX = static_cast<int32_t>(0x80bc0018);
constexpr int ERROR_INVALID_POSY = static_cast<int32_t>(0x80bc0019);
constexpr int ERROR_INVALID_HALIGN = static_cast<int32_t>(0x80bc001a);
constexpr int ERROR_INVALID_VALIGN = static_cast<int32_t>(0x80bc001b);
constexpr int ERROR_INVALID_EXTENDED = static_cast<int32_t>(0x80bc001c);
constexpr int ERROR_INVALID_PARAM = static_cast<int32_t>(0x80bc0030);
constexpr int ERROR_INVALID_ADDRESS = static_cast<int32_t>(0x80bc0031);
constexpr int ERROR_INVALID_RESERVED = static_cast<int32_t>(0x80bc0032);
constexpr int ERROR_INVALID_TITLE = static_cast<int32_t>(0x80bc0101);
constexpr int ERROR_NOT_RUNNING = static_cast<int32_t>(0x80bc0105);
constexpr int ERROR_NOT_FINISHED = static_cast<int32_t>(0x80bc0106);
constexpr int ERROR_NOT_IN_USE = static_cast<int32_t>(0x80bc0107);
constexpr uint32_t VALID_OPTIONS = 0x00007bff;
constexpr uint32_t VALID_EXTENDED_OPTIONS = 0x00005fde;
+5 -5
View File
@@ -51,17 +51,17 @@ static bool TryGetTitleIdFromContentId(std::string* title_id) {
return false;
}
const uint32_t dash = Common::FindIndex(content_id, '-');
if (!Common::IndexValid(content_id, dash)) {
const auto dash = content_id.find('-');
if (dash == std::string::npos) {
return false;
}
const uint32_t underscore = Common::FindIndex(content_id, '_', dash + 1);
if (!Common::IndexValid(content_id, underscore) || underscore <= dash + 1) {
const auto underscore = content_id.find('_', dash + 1);
if (underscore == std::string::npos || underscore <= dash + 1) {
return false;
}
*title_id = Common::Mid(content_id, dash + 1, underscore - dash - 1);
*title_id = content_id.substr(dash + 1, underscore - dash - 1);
return !title_id->empty();
}
+1 -1
View File
@@ -1052,7 +1052,7 @@ static int32_t KYTY_SYSV_ABI AudiodecDecode(int32_t handle, AudiodecCtrl* ctrl)
ctrl->pPcmItem->uiPcmSize = static_cast<uint32_t>(result.output_written);
audiodec_fill_info(ctrl, decoder);
auto* info = static_cast<AudiodecM4aacInfo*>(ctrl->pBsiInfo);
info->iResult = (result.result & AJM_RESULT_CODEC_ERROR) != 0
info->iResult = (result.result & (AJM_RESULT_CODEC_ERROR | AJM_RESULT_TOO_MANY_CHANNELS)) != 0
? AUDIODEC_M4AAC_RESULT_DECODE_ERROR
: (result.result & AJM_RESULT_PARTIAL_INPUT) != 0
? AUDIODEC_M4AAC_RESULT_INSUFFICIENT_DATA : 0;
+1
View File
@@ -11,6 +11,7 @@
#include "loader/symbolDatabase.h"
#include <algorithm>
#include <cstring>
#include <vector>
namespace Libs {
+1
View File
@@ -1,3 +1,4 @@
#include "common/assert.h"
#include "common/emulatorConfig.h"
#include "graphics/guest_gpu/tile.h"
#include "libs/agc.h"
+4 -7
View File
@@ -24,6 +24,7 @@
#include <algorithm>
#include <array>
#include <atomic>
#include <bit>
#include <chrono>
#include <cstddef>
#include <cstdio>
@@ -68,10 +69,6 @@ using KernelModule = int32_t;
using get_thread_atexit_count_func_t = KYTY_SYSV_ABI int (*)(KernelModule);
using thread_atexit_report_func_t = KYTY_SYSV_ABI void (*)(KernelModule);
static uint32_t sha1_rol(uint32_t value, uint32_t bits) {
return (value << bits) | (value >> (32u - bits));
}
static std::array<uint8_t, 20> sha1_digest(const uint8_t* data, size_t size) {
uint32_t h0 = 0x67452301u;
uint32_t h1 = 0xefcdab89u;
@@ -99,7 +96,7 @@ static std::array<uint8_t, 20> sha1_digest(const uint8_t* data, size_t size) {
(static_cast<uint32_t>(msg[j + 2]) << 8u) | static_cast<uint32_t>(msg[j + 3]);
}
for (int i = 16; i < 80; i++) {
w[i] = sha1_rol(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1);
w[i] = std::rotl(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1);
}
uint32_t a = h0;
@@ -125,10 +122,10 @@ static std::array<uint8_t, 20> sha1_digest(const uint8_t* data, size_t size) {
k = 0xca62c1d6u;
}
const auto temp = sha1_rol(a, 5) + f + e + k + w[i];
const auto temp = std::rotl(a, 5) + f + e + k + w[i];
e = d;
d = c;
c = sha1_rol(b, 30);
c = std::rotl(b, 30);
b = a;
a = temp;
}
+21 -43
View File
@@ -14,16 +14,6 @@
#include <string>
#include <vector>
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define NET_CALL(func) \
[&]() { \
auto result = func; \
if (result < 0) { \
*GetNetErrorAddr() = result; \
} \
return result; \
}()
namespace Libs {
namespace Network::Net {
@@ -43,8 +33,15 @@ KYTY_SYSV_ABI int* GetNetErrorAddr() {
return &g_net_errno;
}
static int FinishNetCall(int result) {
if (result < 0) {
g_net_errno = result - Network::NET_ERROR_EPERM + 1;
}
return result;
}
static int KYTY_SYSV_ABI NetInit() {
return NET_CALL(Net::NetInit());
return FinishNetCall(Net::NetInit());
}
static int PosixToNetError(int error) {
@@ -66,13 +63,7 @@ static int PosixToNetError(int error) {
}
static int FinishSocketCall(int result) {
if (result >= 0) {
return result;
}
const int net_error = PosixToNetError(*Posix::GetErrorAddr());
*GetNetErrorAddr() = net_error;
return net_error;
return FinishNetCall(result < 0 ? PosixToNetError(*Posix::GetErrorAddr()) : result);
}
int KYTY_SYSV_ABI NetSocket(const char* name, int family, int type, int protocol) {
@@ -102,48 +93,48 @@ int KYTY_SYSV_ABI NetGetsockname(int s, void* addr, uint32_t* addrlen) {
}
int KYTY_SYSV_ABI NetPoolCreate(const char* name, int size, int flags) {
return NET_CALL(Net::NetPoolCreate(name, size, flags));
return FinishNetCall(Net::NetPoolCreate(name, size, flags));
}
int KYTY_SYSV_ABI NetPoolDestroy(int memid) {
return NET_CALL(Net::NetPoolDestroy(memid));
return FinishNetCall(Net::NetPoolDestroy(memid));
}
int KYTY_SYSV_ABI NetResolverCreate(const char* name, int memid, int flags) {
return NET_CALL(Net::NetResolverCreate(name, memid, flags));
return FinishNetCall(Net::NetResolverCreate(name, memid, flags));
}
int KYTY_SYSV_ABI NetResolverDestroy(int rid) {
return NET_CALL(Net::NetResolverDestroy(rid));
return FinishNetCall(Net::NetResolverDestroy(rid));
}
int KYTY_SYSV_ABI NetResolverStartNtoa(int rid, const char* hostname, void* addr, int timeout,
int retry, int flags) {
return NET_CALL(Net::NetResolverStartNtoa(rid, hostname, addr, timeout, retry, flags));
return FinishNetCall(Net::NetResolverStartNtoa(rid, hostname, addr, timeout, retry, flags));
}
int KYTY_SYSV_ABI NetInetPton(int af, const char* src, void* dst) {
return NET_CALL(Net::NetInetPton(af, src, dst));
return FinishNetCall(Net::NetInetPton(af, src, dst));
}
const char* KYTY_SYSV_ABI NetInetNtop(int af, const void* src, char* dst, uint32_t size) {
const char* result = Net::NetInetNtop(af, src, dst, size);
if (result == nullptr) {
*GetNetErrorAddr() = PosixToNetError(*Posix::GetErrorAddr());
FinishNetCall(PosixToNetError(*Posix::GetErrorAddr()));
}
return result;
}
int KYTY_SYSV_ABI NetEtherNtostr(const Net::NetEtherAddr* n, char* str, size_t len) {
return NET_CALL(Net::NetEtherNtostr(n, str, len));
return FinishNetCall(Net::NetEtherNtostr(n, str, len));
}
int KYTY_SYSV_ABI NetGetMacAddress(Net::NetEtherAddr* addr, int flags) {
return NET_CALL(Net::NetGetMacAddress(addr, flags));
return FinishNetCall(Net::NetGetMacAddress(addr, flags));
}
int KYTY_SYSV_ABI NetGetSockInfo(int s, void* info, int n, int flags) {
return NET_CALL(Net::NetGetSockInfo(s, info, n, flags));
return FinishNetCall(Net::NetGetSockInfo(s, info, n, flags));
}
int KYTY_SYSV_ABI NetEpollCreate(const char* name, int flags) {
@@ -163,7 +154,7 @@ int KYTY_SYSV_ABI NetEpollDestroy(int eid) {
}
int KYTY_SYSV_ABI NetSocketClose(int s) {
return NET_CALL(Net::SocketClose(s));
return FinishNetCall(Net::SocketClose(s));
}
int KYTY_SYSV_ABI NetSetsockopt(int s, int level, int optname, const void* optval,
@@ -1465,7 +1456,7 @@ LIB_DEFINE(InitNet_1_NpManager) {
LIB_FUNC("Ec63y59l9tw", NpManager::NpSetNpTitleId);
LIB_FUNC("A2CQ3kgSopQ", NpManager::NpSetContentRestriction);
LIB_FUNC("VfRSmPmj8Q8", NpManager::NpRegisterStateCallback);
LIB_FUNC("qQJfO8HAiaY", NpManager::NpRegisterStateCallback);
LIB_FUNC("qQJfO8HAiaY", NpManager::NpRegisterStateCallbackA);
LIB_FUNC("M3wFXbYQtAA", NpManager::NpUnregisterStateCallback);
LIB_FUNC("uFJpaKNBAj4", NpManager::NpRegisterGamePresenceCallback);
LIB_FUNC("GImICnh+boA", NpManager::NpRegisterPlusEventCallback);
@@ -3118,16 +3109,6 @@ static std::map<int64_t, NpWebApi2Request>& NpWebApi2Requests() {
return requests;
}
[[maybe_unused]] static std::string NpWebApi2MakeResponse(const NpWebApi2Request& request) {
if (request.api_group.find("sessionManager") != std::string::npos ||
request.path.find("sessions") != std::string::npos ||
request.path.find("Sessions") != std::string::npos) {
return R"({"gameSessions":[],"playerSessions":[]})";
}
return "{}";
}
static int KYTY_SYSV_ABI NpWebApi2Initialize(int lib_http_ctx_id, size_t pool_size) {
PRINT_NAME();
@@ -3224,12 +3205,10 @@ NpWebApi2SendRequest(int64_t request_id, const void* data, size_t data_size,
return NP_WEBAPI2_ERROR_REQUEST_NOT_FOUND;
}
// request->second.response = NpWebApi2MakeResponse(request->second);
request->second.response.clear();
request->second.read_offset = 0;
if (response_info_option != nullptr) {
// response_info_option->http_status = 200;
response_info_option->http_status = 0;
response_info_option->response_data_size = request->second.response.size();
if (response_info_option->error_object != nullptr &&
@@ -3238,7 +3217,6 @@ NpWebApi2SendRequest(int64_t request_id, const void* data, size_t data_size,
}
}
// return 0;
return NP_WEBAPI2_ERROR_NOT_SIGNED_IN;
}
+5 -9
View File
@@ -13,15 +13,11 @@ LIB_VERSION("Psml", 1, "Psml", 1, 1);
namespace Psml {
constexpr int Error(uint32_t value) {
return static_cast<int>(value);
}
constexpr int PSML_ERROR_NOT_INITIALIZED = Error(0x8a810001u);
constexpr int PSML_ERROR_INVALID_OBJECT = Error(0x8a810005u);
constexpr int PSML_ERROR_INVALID_POINTER = Error(0x8a810009u);
constexpr int PSML_ERROR_INVALID_VALUE = Error(0x8a81000du);
constexpr int PSML_ERROR_NULL_OBJECT = Error(0x8a810014u);
constexpr int PSML_ERROR_NOT_INITIALIZED = static_cast<int>(0x8a810001u);
constexpr int PSML_ERROR_INVALID_OBJECT = static_cast<int>(0x8a810005u);
constexpr int PSML_ERROR_INVALID_POINTER = static_cast<int>(0x8a810009u);
constexpr int PSML_ERROR_INVALID_VALUE = static_cast<int>(0x8a81000du);
constexpr int PSML_ERROR_NULL_OBJECT = static_cast<int>(0x8a810014u);
constexpr uint32_t SHARED_RESOURCES_MAGIC = 0xa9c4;
constexpr uint32_t CONTEXT_MAGIC = 0x9231;
+1 -1
View File
@@ -376,7 +376,7 @@ int KYTY_SYSV_ABI SaveDataDirNameSearch(const SaveDataDirNameSearchCond* cond,
if (Common::File::IsDirectoryExisting(root)) {
for (const auto& entry: Common::File::GetDirEntries(root)) {
if (!entry.is_file && entry.name != "." && entry.name != ".." &&
!Common::StartsWith(entry.name, "sce_")) {
!entry.name.starts_with("sce_")) {
if (cond->dir_name == nullptr || cond->dir_name->data[0] == '\0' ||
dir_name_match(Common::ToLower(entry.name).c_str(),
Common::ToLower(std::string(cond->dir_name->data)).c_str())) {
+296 -87
View File
@@ -14,18 +14,18 @@
#endif
#else
#include <arpa/inet.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <unistd.h>
#endif
#include "common/assert.h"
#include "common/byteBuffer.h"
#include "common/common.h"
#include "common/emulatorConfig.h"
#include "common/logging/log.h"
#include "common/stringUtils.h"
#include "common/threads.h"
#include "kernel/pthread.h"
#include "libs/errno.h"
@@ -40,9 +40,13 @@
#include <cstdio>
#include <cstring>
#include <fmt/format.h>
#include <fmt/ranges.h>
#include <limits>
#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include <utility>
#include <vector>
namespace Libs::Network {
@@ -844,9 +848,37 @@ using SocketLength = socklen_t;
using SocketIoLength = size_t;
#endif
struct SocketTransport {
explicit SocketTransport(NativeSocket value): socket(value) {}
~SocketTransport() { Close(); }
int Close() {
if (socket == INVALID_NATIVE_SOCKET) {
return 0;
}
const auto value = std::exchange(socket, INVALID_NATIVE_SOCKET);
#if defined(_WIN32)
return closesocket(value);
#else
return ::close(value);
#endif
}
NativeSocket socket;
};
struct P2pEndpoint {
bool bound = false;
uint32_t address = 0;
uint16_t port = 0;
uint16_t virtual_port = 0;
int nonblocking = 0;
int broadcast = 0;
int send_buffer = 9216;
int receive_buffer = 40 * 1024;
};
struct SocketSlot {
bool used = false;
NativeSocket socket = INVALID_NATIVE_SOCKET;
std::shared_ptr<SocketTransport> transport;
std::optional<P2pEndpoint> p2p;
};
struct NetTimeval {
@@ -998,6 +1030,16 @@ static int ConvertSocketOptionLevel(int level) {
return (level == 0xffff ? SOL_SOCKET : level);
}
static int* P2pSocketOption(P2pEndpoint& endpoint, int option) {
switch (option) {
case 0x0020: return &endpoint.broadcast;
case 0x1001: return &endpoint.send_buffer;
case 0x1002: return &endpoint.receive_buffer;
case 0x1200: return &endpoint.nonblocking;
default: return nullptr;
}
}
static int ConvertMessageFlags(int flags) {
constexpr int guest_msg_peek = 0x00000002;
constexpr int guest_msg_dontroute = 0x00000004;
@@ -1104,19 +1146,30 @@ static int ConvertHostSockaddr(const sockaddr_storage* addr, SocketLength addrle
return 0;
}
static bool GetSocketBackend(int guest_fd, NativeSocket* out) {
static bool GetSocketBackend(int guest_fd, NativeSocket* out, SocketSlot* state = nullptr) {
EXIT_IF(out == nullptr);
if (guest_fd < 0 || guest_fd >= SOCKET_FD_MAX) {
SetGuestSocketError(Posix::POSIX_EBADF);
return false;
}
Common::LockGuard lock(g_socket_mutex);
if (!g_sockets[static_cast<size_t>(guest_fd)].used) {
const auto& slot = g_sockets[static_cast<size_t>(guest_fd)];
if (!slot.transport) {
SetGuestSocketError(Posix::POSIX_EBADF);
return false;
}
// Native-only operations cannot act on a transport shared by virtual ports.
if (slot.p2p && state == nullptr) {
SetGuestSocketError(Posix::POSIX_EOPNOTSUPP);
return false;
}
*out = g_sockets[static_cast<size_t>(guest_fd)].socket;
*out = slot.transport->socket;
if (state != nullptr) {
*state = slot;
}
return true;
}
@@ -1126,10 +1179,10 @@ bool KYTY_SYSV_ABI IsSocket(int s) {
}
Common::LockGuard lock(g_socket_mutex);
return g_sockets[static_cast<size_t>(s)].used;
return g_sockets[static_cast<size_t>(s)].transport != nullptr;
}
static bool TakeSocketBackend(int guest_fd, NativeSocket* out) {
static bool TakeSocketBackend(int guest_fd, SocketSlot* out) {
EXIT_IF(out == nullptr);
if (guest_fd < 0 || guest_fd >= SOCKET_FD_MAX) {
@@ -1138,22 +1191,24 @@ static bool TakeSocketBackend(int guest_fd, NativeSocket* out) {
Common::LockGuard lock(g_socket_mutex);
auto& slot = g_sockets[static_cast<size_t>(guest_fd)];
if (!slot.used) {
if (!slot.transport) {
return false;
}
*out = slot.socket;
*out = std::move(slot);
slot = {};
return true;
}
static int AllocSocketFd(NativeSocket socket) {
static int AllocSocketFd(const std::shared_ptr<SocketTransport>& transport, bool p2p = false) {
Common::LockGuard lock(g_socket_mutex);
for (int fd = SOCKET_FD_MIN; fd < SOCKET_FD_MAX; fd++) {
auto& slot = g_sockets[static_cast<size_t>(fd)];
if (!slot.used) {
slot.used = true;
slot.socket = socket;
if (!slot.transport) {
slot.transport = transport;
if (p2p) {
slot.p2p.emplace();
}
return fd;
}
}
@@ -1528,10 +1583,10 @@ int KYTY_SYSV_ABI EpollWait(int eid, NetEpollEvent* events, int maxevents, int t
return 0;
}
#if defined(_WIN32)
struct HostRegistration {
EpollRegistration guest;
NativeSocket socket = INVALID_NATIVE_SOCKET;
SocketSlot state;
};
fd_set host_read {};
@@ -1543,14 +1598,23 @@ int KYTY_SYSV_ABI EpollWait(int eid, NetEpollEvent* events, int maxevents, int t
std::vector<HostRegistration> host_registrations;
host_registrations.reserve(registrations.size());
int host_nfds = 0;
for (const auto& registration: registrations) {
NativeSocket socket = INVALID_NATIVE_SOCKET;
if (!GetSocketBackend(registration.id, &socket)) {
SocketSlot state;
if (!GetSocketBackend(registration.id, &socket, &state)) {
continue;
}
#if defined(_WIN32)
if (host_registrations.size() >= FD_SETSIZE) {
return SetGuestSocketError(Posix::POSIX_EINVAL);
}
#else
if (socket >= FD_SETSIZE) {
return SetGuestSocketError(Posix::POSIX_EINVAL);
}
host_nfds = std::max(host_nfds, socket + 1);
#endif
if ((registration.event.events & EPOLL_IN) != 0) {
FD_SET(socket, &host_read);
}
@@ -1558,7 +1622,7 @@ int KYTY_SYSV_ABI EpollWait(int eid, NetEpollEvent* events, int maxevents, int t
FD_SET(socket, &host_write);
}
FD_SET(socket, &host_except);
host_registrations.push_back({registration, socket});
host_registrations.push_back({registration, socket, std::move(state)});
}
if (host_registrations.empty()) {
@@ -1573,8 +1637,8 @@ int KYTY_SYSV_ABI EpollWait(int eid, NetEpollEvent* events, int maxevents, int t
host_timeout_ptr = &host_timeout;
}
const int result = ::select(0, &host_read, &host_write, &host_except, host_timeout_ptr);
if (result == SOCKET_ERROR) {
const int result = ::select(host_nfds, &host_read, &host_write, &host_except, host_timeout_ptr);
if (result < 0) {
return SetHostSocketError();
}
if (result == 0) {
@@ -1584,10 +1648,15 @@ int KYTY_SYSV_ABI EpollWait(int eid, NetEpollEvent* events, int maxevents, int t
int count = 0;
for (const auto& registration: host_registrations) {
uint32_t ready = 0;
if (FD_ISSET(registration.socket, &host_read)) {
if ((registration.guest.event.events & EPOLL_IN) != 0 &&
FD_ISSET(registration.socket, &host_read)) {
if (registration.state.p2p) {
return SetGuestSocketError(Posix::POSIX_EOPNOTSUPP);
}
ready |= EPOLL_IN;
}
if (FD_ISSET(registration.socket, &host_write)) {
if ((registration.guest.event.events & EPOLL_OUT) != 0 &&
FD_ISSET(registration.socket, &host_write)) {
ready |= EPOLL_OUT;
}
if (FD_ISSET(registration.socket, &host_except)) {
@@ -1607,10 +1676,6 @@ int KYTY_SYSV_ABI EpollWait(int eid, NetEpollEvent* events, int maxevents, int t
}
}
return count;
#else
(void)timeout;
return SetGuestSocketError(Posix::POSIX_ENOSYS);
#endif
}
int KYTY_SYSV_ABI EpollDestroy(int eid) {
@@ -1632,18 +1697,13 @@ int KYTY_SYSV_ABI SocketClose(int s) {
LOGF("\t s = %d\n", s);
NativeSocket socket = INVALID_NATIVE_SOCKET;
if (!TakeSocketBackend(s, &socket)) {
SocketSlot slot;
if (!TakeSocketBackend(s, &slot)) {
return NET_ERROR_EBADF;
}
RemoveSocketFromEpolls(s);
#if defined(_WIN32)
const int result = closesocket(socket);
#else
const int result = ::close(socket);
#endif
if (result != 0) {
if (slot.transport.use_count() == 1 && slot.transport->Close() != 0) {
return NET_ERROR_EBADF;
}
@@ -1668,18 +1728,31 @@ int KYTY_SYSV_ABI Socket(int family, int type, int protocol) {
return -1;
}
NativeSocket socket = ::socket(host_family, type, protocol);
constexpr int socket_dgram_p2p = 6;
const bool p2p = type == socket_dgram_p2p;
if (p2p && (family != 2 || protocol != 0)) {
return SetGuestSocketError(Posix::POSIX_EPROTONOSUPPORT);
}
NativeSocket socket = ::socket(host_family, p2p ? SOCK_DGRAM : type, protocol);
if (socket == INVALID_NATIVE_SOCKET) {
return SetHostSocketError();
}
const int fd = AllocSocketFd(socket);
if (fd < 0) {
auto transport = std::make_shared<SocketTransport>(socket);
if (p2p) {
// Logical sockets keep their own blocking mode; the shared transport never blocks.
#if defined(_WIN32)
closesocket(socket);
u_long enabled = 1;
const int result = ioctlsocket(socket, FIONBIO, &enabled);
#else
::close(socket);
const int result = ::fcntl(socket, F_SETFL, O_NONBLOCK);
#endif
if (result != 0) {
return SetHostSocketError();
}
}
const int fd = AllocSocketFd(transport, p2p);
if (fd < 0) {
*Posix::GetErrorAddr() = Posix::POSIX_EMFILE;
return -1;
}
@@ -1697,8 +1770,11 @@ int KYTY_SYSV_ABI Bind(int s, const void* addr, uint32_t addrlen) {
s, reinterpret_cast<uint64_t>(addr), addrlen);
NativeSocket socket = INVALID_NATIVE_SOCKET;
if (addr == nullptr || !GetSocketBackend(s, &socket)) {
*Posix::GetErrorAddr() = (addr == nullptr ? Posix::POSIX_EFAULT : Posix::POSIX_EBADF);
SocketSlot state;
if (addr == nullptr) {
return SetGuestSocketError(Posix::POSIX_EFAULT);
}
if (!GetSocketBackend(s, &socket, &state)) {
return -1;
}
@@ -1708,6 +1784,67 @@ int KYTY_SYSV_ABI Bind(int s, const void* addr, uint32_t addrlen) {
return -1;
}
if (state.p2p) {
if (addrlen < 16) {
return SetGuestSocketError(Posix::POSIX_EINVAL);
}
const auto& in = *reinterpret_cast<const sockaddr_in*>(&host_addr);
uint32_t address = 0;
std::memcpy(&address, &in.sin_addr, sizeof(address));
uint16_t virtual_port = 0;
std::memcpy(&virtual_port, static_cast<const uint8_t*>(addr) + 8, sizeof(virtual_port));
const auto requested_port = ntohs(virtual_port);
if (requested_port == 0) {
return SetGuestSocketError(Posix::POSIX_EOPNOTSUPP);
}
if (ntohs(in.sin_port) != 3658) {
return SetGuestSocketError(Posix::POSIX_EINVAL);
}
if (requested_port == 5353 || requested_port >= 32768) {
return SetGuestSocketError(Posix::POSIX_EACCES);
}
Common::LockGuard lock(g_socket_mutex);
auto& slot = g_sockets[static_cast<size_t>(s)];
if (slot.transport != state.transport) {
return SetGuestSocketError(Posix::POSIX_EBADF);
}
auto& endpoint = *slot.p2p;
if (endpoint.bound) {
return SetGuestSocketError(Posix::POSIX_EINVAL);
}
auto conflicts = [&](uint16_t port) {
return std::any_of(g_sockets.begin(), g_sockets.end(), [&](const auto& other) {
return other.p2p && other.p2p->bound && other.p2p->port == in.sin_port &&
other.p2p->address == address && other.p2p->virtual_port == port;
});
};
if (conflicts(virtual_port)) {
return SetGuestSocketError(Posix::POSIX_EADDRINUSE);
}
std::shared_ptr<SocketTransport> shared;
for (const auto& other: g_sockets) {
if (other.p2p && other.p2p->bound && other.p2p->port == in.sin_port &&
other.p2p->address == address) {
shared = other.transport;
break;
}
}
if (shared) {
slot.transport = std::move(shared);
} else if (::bind(socket, reinterpret_cast<const sockaddr*>(&host_addr), host_addrlen) !=
0) {
return SetHostSocketError();
}
endpoint.bound = true;
endpoint.address = address;
endpoint.port = in.sin_port;
endpoint.virtual_port = virtual_port;
LOGF("\t UDPP2P bound UDP port=%u virtual port=%u\n", ntohs(endpoint.port),
ntohs(endpoint.virtual_port));
return 0;
}
if (::bind(socket, reinterpret_cast<const sockaddr*>(&host_addr), host_addrlen) != 0) {
return SetHostSocketError();
}
@@ -1724,8 +1861,10 @@ int KYTY_SYSV_ABI Connect(int s, const void* addr, uint32_t addrlen) {
s, reinterpret_cast<uint64_t>(addr), addrlen);
NativeSocket socket = INVALID_NATIVE_SOCKET;
if (addr == nullptr || !GetSocketBackend(s, &socket)) {
*Posix::GetErrorAddr() = (addr == nullptr ? Posix::POSIX_EFAULT : Posix::POSIX_EBADF);
if (addr == nullptr) {
return SetGuestSocketError(Posix::POSIX_EFAULT);
}
if (!GetSocketBackend(s, &socket)) {
return -1;
}
@@ -1751,7 +1890,6 @@ int KYTY_SYSV_ABI Listen(int s, int backlog) {
NativeSocket socket = INVALID_NATIVE_SOCKET;
if (!GetSocketBackend(s, &socket)) {
*Posix::GetErrorAddr() = Posix::POSIX_EBADF;
return -1;
}
@@ -1772,7 +1910,6 @@ int KYTY_SYSV_ABI Accept(int s, void* addr, uint32_t* addrlen) {
NativeSocket socket = INVALID_NATIVE_SOCKET;
if (!GetSocketBackend(s, &socket)) {
*Posix::GetErrorAddr() = Posix::POSIX_EBADF;
return -1;
}
@@ -1784,13 +1921,9 @@ int KYTY_SYSV_ABI Accept(int s, void* addr, uint32_t* addrlen) {
return SetHostSocketError();
}
const int fd = AllocSocketFd(accepted);
auto transport = std::make_shared<SocketTransport>(accepted);
const int fd = AllocSocketFd(transport);
if (fd < 0) {
#if defined(_WIN32)
closesocket(accepted);
#else
::close(accepted);
#endif
*Posix::GetErrorAddr() = Posix::POSIX_EMFILE;
return -1;
}
@@ -1819,7 +1952,6 @@ int KYTY_SYSV_ABI Shutdown(int s, int how) {
NativeSocket socket = INVALID_NATIVE_SOCKET;
if (!GetSocketBackend(s, &socket)) {
*Posix::GetErrorAddr() = Posix::POSIX_EBADF;
return -1;
}
@@ -1848,12 +1980,14 @@ int KYTY_SYSV_ABI Getsockname(int s, void* addr, uint32_t* addrlen) {
"\t addrlen = 0x%016" PRIx64 "\n",
s, reinterpret_cast<uint64_t>(addr), reinterpret_cast<uint64_t>(addrlen));
NativeSocket socket = INVALID_NATIVE_SOCKET;
const bool socket_ok = GetSocketBackend(s, &socket);
if (addr == nullptr || addrlen == nullptr || !socket_ok) {
*Posix::GetErrorAddr() = (!socket_ok ? Posix::POSIX_EBADF : Posix::POSIX_EFAULT);
NativeSocket socket = INVALID_NATIVE_SOCKET;
SocketSlot state;
if (!GetSocketBackend(s, &socket, &state)) {
return -1;
}
if (addr == nullptr || addrlen == nullptr) {
return SetGuestSocketError(Posix::POSIX_EFAULT);
}
sockaddr_storage host_addr {};
SocketLength host_addrlen = sizeof(host_addr);
@@ -1861,7 +1995,11 @@ int KYTY_SYSV_ABI Getsockname(int s, void* addr, uint32_t* addrlen) {
return SetHostSocketError();
}
return ConvertHostSockaddr(&host_addr, host_addrlen, addr, addrlen);
const int result = ConvertHostSockaddr(&host_addr, host_addrlen, addr, addrlen);
if (result == 0 && state.p2p) {
std::memcpy(static_cast<uint8_t*>(addr) + 8, &state.p2p->virtual_port, sizeof(uint16_t));
}
return result;
}
int KYTY_SYSV_ABI Getsockopt(int s, int level, int optname, void* optval, uint32_t* optlen) {
@@ -1872,12 +2010,26 @@ int KYTY_SYSV_ABI Getsockopt(int s, int level, int optname, void* optval, uint32
"\t optname = 0x%08" PRIx32 "\n",
s, static_cast<uint32_t>(level), static_cast<uint32_t>(optname));
NativeSocket socket = INVALID_NATIVE_SOCKET;
const bool socket_ok = GetSocketBackend(s, &socket);
if (optval == nullptr || optlen == nullptr || !socket_ok) {
*Posix::GetErrorAddr() = (!socket_ok ? Posix::POSIX_EBADF : Posix::POSIX_EFAULT);
NativeSocket socket = INVALID_NATIVE_SOCKET;
SocketSlot state;
if (!GetSocketBackend(s, &socket, &state)) {
return -1;
}
if (optval == nullptr || optlen == nullptr) {
return SetGuestSocketError(Posix::POSIX_EFAULT);
}
if (state.p2p) {
const auto* value = level == 0xffff ? P2pSocketOption(*state.p2p, optname) : nullptr;
if (value == nullptr) {
return SetGuestSocketError(Posix::POSIX_ENOPROTOOPT);
}
if (*optlen < sizeof(int)) {
return SetGuestSocketError(Posix::POSIX_EINVAL);
}
std::memcpy(optval, value, sizeof(int));
*optlen = sizeof(int);
return 0;
}
// Guest socket options: SOL_SOCKET=0xffff, SO_ERROR=0x1007.
const bool socket_error = (level == 0xffff && optname == 0x1007);
@@ -1912,10 +2064,38 @@ int KYTY_SYSV_ABI Setsockopt(int s, int level, int optname, const void* optval,
s, static_cast<uint32_t>(level), static_cast<uint32_t>(optname), optlen);
NativeSocket socket = INVALID_NATIVE_SOCKET;
if (optval == nullptr || !GetSocketBackend(s, &socket)) {
*Posix::GetErrorAddr() = (optval == nullptr ? Posix::POSIX_EFAULT : Posix::POSIX_EBADF);
SocketSlot state;
if (optval == nullptr) {
return SetGuestSocketError(Posix::POSIX_EFAULT);
}
if (!GetSocketBackend(s, &socket, &state)) {
return -1;
}
if (state.p2p) {
Common::LockGuard lock(g_socket_mutex);
auto& slot = g_sockets[static_cast<size_t>(s)];
if (slot.transport != state.transport) {
return SetGuestSocketError(Posix::POSIX_EBADF);
}
auto* option = level == 0xffff ? P2pSocketOption(*slot.p2p, optname) : nullptr;
if (option == nullptr) {
return SetGuestSocketError(Posix::POSIX_ENOPROTOOPT);
}
if (optlen != sizeof(int)) {
return SetGuestSocketError(Posix::POSIX_EINVAL);
}
int value = 0;
std::memcpy(&value, optval, sizeof(value));
if (optname == 0x1001 || optname == 0x1002) {
if (value <= 0) {
return SetGuestSocketError(Posix::POSIX_EINVAL);
}
*option = optname == 0x1002 ? std::min(value, 512 * 1024) : value;
} else {
*option = value != 0;
}
return 0;
}
#if defined(_WIN32)
constexpr int ORBIS_SO_NBIO = 0x1200;
@@ -1962,8 +2142,11 @@ int64_t KYTY_SYSV_ABI Sendto(int s, const void* buf, uint64_t len, int flags, co
reinterpret_cast<uint64_t>(addr), addrlen);
NativeSocket socket = INVALID_NATIVE_SOCKET;
if (buf == nullptr || !GetSocketBackend(s, &socket)) {
*Posix::GetErrorAddr() = (buf == nullptr ? Posix::POSIX_EFAULT : Posix::POSIX_EBADF);
if (buf == nullptr) {
return SetGuestSocketError(Posix::POSIX_EFAULT);
}
// UDPP2P requires protocol framing; the native-only lookup rejects raw sends.
if (!GetSocketBackend(s, &socket)) {
return -1;
}
@@ -2017,7 +2200,6 @@ int64_t KYTY_SYSV_ABI Recvfrom(int s, void* buf, uint64_t len, int flags, void*
NativeSocket socket = INVALID_NATIVE_SOCKET;
if (!GetSocketBackend(s, &socket)) {
*Posix::GetErrorAddr() = Posix::POSIX_EBADF;
return -1;
}
@@ -2107,7 +2289,7 @@ int KYTY_SYSV_ABI Select(int nfds, void* readfds, void* writefds, void* exceptfd
} else
#endif
if (!GetSocketBackend(fd, &socket)) {
return SetGuestSocketError(Posix::POSIX_EBADF);
return -1;
}
#if defined(_WIN32)
if ((read && host_read.fd_count == FD_SETSIZE) ||
@@ -3103,17 +3285,10 @@ static HostNetworkInfo QueryHostNetworkInfo() {
#endif
}
[[maybe_unused]] static bool HostNetworkConnected() {
return QueryHostNetworkInfo().connected;
}
static bool NetCtlConnected() {
if (!g_net_ctl_status_initialized.load()) {
// g_net_ctl_connected = HostNetworkConnected();
g_net_ctl_connected = false;
g_net_ctl_status_initialized = true;
// LOGF("\t host network connected = %s\n", (g_net_ctl_connected.load() ? "true" :
// "false"));
LOGF("\t host network connected = false (forced offline)\n");
}
@@ -3123,10 +3298,8 @@ static bool NetCtlConnected() {
int KYTY_SYSV_ABI NetCtlInit() {
PRINT_NAME();
// g_net_ctl_connected = HostNetworkConnected();
g_net_ctl_connected = false;
g_net_ctl_status_initialized = true;
// LOGF("\t host network connected = %s\n", (g_net_ctl_connected.load() ? "true" : "false"));
LOGF("\t host network connected = false (forced offline)\n");
return OK;
@@ -3380,14 +3553,24 @@ struct NpCheckPremiumResult {
uint8_t reserved[32];
};
constexpr int np_error_invalid_argument = -2141913085; /* 0x80550003 */
constexpr int np_error_signed_out = -2141913082; /* 0x80550006 */
constexpr int np_error_invalid_size = -2141913071; /* 0x80550011 */
constexpr int np_error_aborted = -2141913070; /* 0x80550012 */
constexpr int np_error_request_max = -2141913069; /* 0x80550013 */
constexpr int np_error_request_not_found = -2141913068; /* 0x80550014 */
constexpr int np_error_invalid_id = -2141913067; /* 0x80550015 */
constexpr int np_request_max = 128;
constexpr int np_error_invalid_argument = -2141913085; /* 0x80550003 */
constexpr int np_error_signed_out = -2141913082; /* 0x80550006 */
constexpr int np_error_callback_already_registered = -2141913080; /* 0x80550008 */
constexpr int np_error_invalid_size = -2141913071; /* 0x80550011 */
constexpr int np_error_aborted = -2141913070; /* 0x80550012 */
constexpr int np_error_request_max = -2141913069; /* 0x80550013 */
constexpr int np_error_request_not_found = -2141913068; /* 0x80550014 */
constexpr int np_error_invalid_id = -2141913067; /* 0x80550015 */
constexpr int np_request_max = 128;
constexpr uint32_t np_state_signed_out = 1;
struct NpStateCallback {
NpStateCallbackA callback = nullptr;
void* userdata = nullptr;
bool pending = false;
};
static std::vector<NpStateCallback> g_np_state_callbacks;
enum class NpRequestState {
Free,
@@ -3458,6 +3641,17 @@ static int np_complete_signed_out_locked(NpRequest* request) {
int KYTY_SYSV_ABI NpCheckCallback() {
PRINT_NAME();
std::vector<NpStateCallback> pending;
for (auto& entry: g_np_state_callbacks) {
if (entry.pending) {
pending.push_back(entry);
entry.pending = false;
}
}
for (const auto& entry: pending) {
entry.callback(Config::GetUserId(), np_state_signed_out, entry.userdata);
}
return OK;
}
@@ -3469,7 +3663,7 @@ int KYTY_SYSV_ABI NpSetNpTitleId(const NpTitleId* title_id, const NpTitleSecret*
LOGF("\t title_id = %.12s\n"
"\t title_secret = %s\n",
title_id->id, Common::HexFromBin(Common::ByteBuffer(title_secret->data, 128)).c_str());
title_id->id, fmt::format("{:02X}", fmt::join(title_secret->data, "")));
return OK;
}
@@ -3506,6 +3700,21 @@ int KYTY_SYSV_ABI NpUnregisterStateCallback() {
return OK;
}
int KYTY_SYSV_ABI NpRegisterStateCallbackA(NpStateCallbackA callback, void* userdata) {
PRINT_NAME();
if (callback == nullptr) {
return np_error_invalid_argument;
}
for (const auto& entry: g_np_state_callbacks) {
if (entry.callback == callback) {
return np_error_callback_already_registered;
}
}
g_np_state_callbacks.push_back({callback, userdata, true});
return static_cast<int>(g_np_state_callbacks.size());
}
void KYTY_SYSV_ABI NpRegisterGamePresenceCallback(void* /*callback*/, void* /*userdata*/) {
PRINT_NAME();
}
@@ -3811,7 +4020,7 @@ int KYTY_SYSV_ABI NpGetState(int user_id, uint32_t* state) {
LOGF("\t user_id = %d\n", user_id);
*state = 1; // Signed out
*state = np_state_signed_out;
return OK;
}
+3
View File
@@ -167,11 +167,14 @@ struct NpCreateAsyncRequestParameter;
struct NpCheckPremiumParameter;
struct NpCheckPremiumResult;
using NpStateCallbackA = KYTY_SYSV_ABI void (*)(int user_id, uint32_t state, void* userdata);
int KYTY_SYSV_ABI NpCheckCallback();
int KYTY_SYSV_ABI NpSetNpTitleId(const NpTitleId* title_id, const NpTitleSecret* title_secret);
int KYTY_SYSV_ABI NpSetContentRestriction(const NpContentRestriction* restriction);
int KYTY_SYSV_ABI NpRegisterStateCallback(void* callback, void* userdata);
int KYTY_SYSV_ABI NpUnregisterStateCallback();
int KYTY_SYSV_ABI NpRegisterStateCallbackA(NpStateCallbackA callback, void* userdata);
void KYTY_SYSV_ABI NpRegisterGamePresenceCallback(void* callback, void* userdata);
int KYTY_SYSV_ABI NpRegisterPlusEventCallback(void* callback, void* userdata);
int KYTY_SYSV_ABI NpRegisterPremiumEventCallback(void* callback, void* userdata);
+1
View File
@@ -1,5 +1,6 @@
#include "loader/gamePatch.h"
#include "common/assert.h"
#include "common/stringUtils.h"
#include "common/virtualMemory.h"
#include "kernel/memory.h"
+3 -7
View File
@@ -103,11 +103,6 @@ static ZydisDecoder& GetDecoder() {
return decoder;
}
static ZyanStatus DecodeInstruction(ZydisDecodedInstruction& instruction,
ZydisDecodedOperand* operands, void* data, u64 size) {
return ZydisDecoderDecodeFull(&GetDecoder(), data, size, &instruction, operands);
}
#endif
#if defined(_WIN32)
@@ -177,8 +172,9 @@ uintptr_t GetRelativeTarget(const DecodedCodeInstruction& decoded) {
DecodedCodeInstruction DecodeCodeInstruction(uintptr_t address, uintptr_t end) {
DecodedCodeInstruction decoded {.address = address};
const auto status = DecodeInstruction(decoded.instruction, decoded.operands.data(),
reinterpret_cast<void*>(address), end - address);
const auto status = ZydisDecoderDecodeFull(&GetDecoder(), reinterpret_cast<void*>(address),
end - address, &decoded.instruction,
decoded.operands.data());
if (!ZYAN_SUCCESS(status)) {
decoded.instruction.length = 0;
return decoded;
+18 -19
View File
@@ -6,7 +6,6 @@
#include "common/file.h"
#include "common/hostException.h"
#include "common/logging/log.h"
#include "common/magicEnum.h"
#include "common/platform/sysDbg.h"
#include "common/profiler.h"
#include "common/singleton.h"
@@ -29,6 +28,7 @@
#include <cstdlib>
#include <cstring>
#include <fmt/format.h>
#include <magic_enum.hpp>
#include <memory>
#include <vector>
@@ -301,9 +301,9 @@ static KYTY_SYSV_ABI uint64_t ResolveImportStubWithId(uint64_t record_id) {
if (record_id < g_stubbed_imports.size()) {
auto& record = g_stubbed_imports[record_id];
auto nid = record.name;
auto pos = Common::FindIndex(nid, "[");
if (Common::IndexValid(nid, pos)) {
nid = Common::Left(nid, pos);
auto pos = nid.find('[');
if (pos != std::string::npos) {
nid.resize(pos);
}
SymbolRecord resolved {};
@@ -330,7 +330,7 @@ static KYTY_SYSV_ABI uint64_t ResolveImportStubWithId(uint64_t record_id) {
LOGF("Unresolved import stub called [%u]: patch_vaddr=0x%016" PRIx64
" jmprela_index=%" PRIu32 " symbol=%s type=%s bind=%s program=%s\n",
log_index, record.patch_vaddr, record.index, record.name.c_str(),
Common::EnumName(record.type).c_str(), Common::EnumName(record.bind).c_str(),
magic_enum::enum_name(record.type), magic_enum::enum_name(record.bind),
record.program.c_str());
} else {
printf("Unresolved import stub called: <bad-record>\n");
@@ -1046,8 +1046,8 @@ static void RelocateRecord(uint32_t index, Elf64_Rela* r, Program* program, bool
patched = PatchGuestMemory64(ri.vaddr, value);
} else {
auto dbg_str = fmt::format("[{:016x}] <- {:016x}, {}, {}, {}, {}", ri.vaddr, ri.value,
ri.name.c_str(), Common::EnumName(ri.type).c_str(),
Common::EnumName(ri.bind).c_str(), ri.dbg_name.c_str());
ri.name.c_str(), magic_enum::enum_name(ri.type),
magic_enum::enum_name(ri.bind), ri.dbg_name.c_str());
if (unresolved != nullptr) {
unresolved->push_back(dbg_str);
@@ -1077,23 +1077,23 @@ static void RelocateRecord(uint32_t index, Elf64_Rela* r, Program* program, bool
const auto thunk = RegisterStubbedImport(index, program, ri);
LOGF("Relocate: unresolved PLT import patched to stub [%u] [%016" PRIx64 "] <- %016" PRIx64
", %s, %s, %s, %s\n",
index, ri.vaddr, thunk, ri.name.c_str(), Common::EnumName(ri.type).c_str(),
Common::EnumName(ri.bind).c_str(), Common::PathToString(program->file_name).c_str());
index, ri.vaddr, thunk, ri.name.c_str(), magic_enum::enum_name(ri.type),
magic_enum::enum_name(ri.bind), Common::PathToString(program->file_name).c_str());
} else if (patched && stubbed_func) {
const auto thunk = RegisterStubbedImport(index, program, ri);
LOGF("Relocate: unresolved non-PLT function patched to stub [%u] [%016" PRIx64
"] <- %016" PRIx64 ", %s, %s, %s, %s\n",
index, ri.vaddr, thunk, ri.name.c_str(), Common::EnumName(ri.type).c_str(),
Common::EnumName(ri.bind).c_str(), Common::PathToString(program->file_name).c_str());
index, ri.vaddr, thunk, ri.name.c_str(), magic_enum::enum_name(ri.type),
magic_enum::enum_name(ri.bind), Common::PathToString(program->file_name).c_str());
}
if (program->dbg_print_reloc) {
if (/* !dbg_str.ContainsStr("libc_") && */ patched && !ri.bind_self &&
if (patched && !ri.bind_self &&
(ri.bind == BindType::Global || ri.bind == BindType::Weak ||
ri.type == SymbolType::TlsModule)) {
auto dbg_str = fmt::format("[{:016x}] <- {:016x}, {}, {}, {}, {}", ri.vaddr, ri.value,
ri.name.c_str(), Common::EnumName(ri.type).c_str(),
Common::EnumName(ri.bind).c_str(), ri.dbg_name.c_str());
ri.name.c_str(), magic_enum::enum_name(ri.type),
magic_enum::enum_name(ri.bind), ri.dbg_name.c_str());
LOGF("Relocate: %s\n", dbg_str.c_str());
}
@@ -1390,9 +1390,8 @@ Program* RuntimeLinker::LoadProgram(const std::filesystem::path& elf_name) {
Libs::LibKernel::SetProgName(elf_name.filename().string());
}
if (Common::EndsWith(Common::ToLower(Common::DirectoryWithoutFilename(
Common::PathToGenericString(elf_name))),
"_module/")) {
if (Common::ToLower(Common::DirectoryWithoutFilename(Common::PathToGenericString(elf_name)))
.ends_with("_module/")) {
program->fail_if_global_not_resolved = false;
}
@@ -1818,7 +1817,7 @@ void RuntimeLinker::StopAllModules() {
static bool IsAdjacentModuleFile(const std::string& name) {
auto lower = Common::ToLower(name);
return Common::EndsWith(lower, ".prx") || Common::EndsWith(lower, ".sprx");
return lower.ends_with(".prx") || lower.ends_with(".sprx");
}
static bool SkipAdjacentModuleFile(const std::string& name) {
@@ -2082,7 +2081,7 @@ void RuntimeLinker::LoadProgramToMemory(Program* program) {
"[%d] memory_size = %" PRIu64 "\n"
"[%d] mode = %s\n",
i, segment_addr, i, segment_file_size, i, segment_memory_size, i,
Common::EnumName(mode).c_str());
magic_enum::enum_name(mode));
program->elf->LoadSegment(segment_addr, phdr[i].p_offset, segment_file_size);
+7 -7
View File
@@ -1,16 +1,16 @@
#include "loader/symbolDatabase.h"
#include "common/file.h"
#include "common/magicEnum.h"
#include <fmt/format.h>
#include <magic_enum.hpp>
namespace Loader {
constexpr char LIB_PREFIX[] = "libSce";
static std::string UpdateName(const std::string& str) {
return Common::StartsWith(str, LIB_PREFIX) ? Common::RemoveFirst(str, 6) : str;
return str.starts_with(LIB_PREFIX) ? Common::RemoveFirst(str, 6) : str;
}
std::string SymbolDatabase::GenerateName(const SymbolResolve& s) {
@@ -18,7 +18,7 @@ std::string SymbolDatabase::GenerateName(const SymbolResolve& s) {
auto module = UpdateName(s.module);
return fmt::format("{}[{}_v{}][{}_v{}.{}][{}]", s.name.c_str(), library.c_str(),
s.library_version, module.c_str(), s.module_version_major,
s.module_version_minor, Common::EnumName(s.type).c_str());
s.module_version_minor, magic_enum::enum_name(s.type));
}
void SymbolDatabase::Add(const SymbolResolve& s, uint64_t vaddr) {
@@ -67,10 +67,10 @@ const SymbolRecord* SymbolDatabase::Find(const SymbolResolve& s) const {
const SymbolRecord* SymbolDatabase::FindByNid(const std::string& nid, SymbolType type) const {
auto prefix = nid + "[";
auto suffix = fmt::format("[{}]", Common::EnumName(type).c_str());
auto suffix = fmt::format("[{}]", magic_enum::enum_name(type));
for (const auto& symbol: m_symbols) {
if (Common::StartsWith(symbol.name, prefix) && Common::EndsWith(symbol.name, suffix)) {
if (symbol.name.starts_with(prefix) && symbol.name.ends_with(suffix)) {
return &symbol;
}
}
@@ -80,10 +80,10 @@ const SymbolRecord* SymbolDatabase::FindByNid(const std::string& nid, SymbolType
const SymbolRecord* SymbolDatabase::FindByName(const std::string& name, SymbolType type) const {
auto prefix = name + "[";
auto suffix = fmt::format("[{}]", Common::EnumName(type).c_str());
auto suffix = fmt::format("[{}]", magic_enum::enum_name(type));
for (const auto& symbol: m_symbols) {
if (Common::StartsWith(symbol.name, prefix) && Common::EndsWith(symbol.name, suffix)) {
if (symbol.name.starts_with(prefix) && symbol.name.ends_with(suffix)) {
return &symbol;
}
}
Loaded 100 of 110 files, more files were not shown because too many files have changed in this diff. Show more