mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 08:13:05 +00:00
Compare commits
13
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc2f077c37 | ||
|
|
498d63b620 | ||
|
|
566a45017e | ||
|
|
7a40dad90f | ||
|
|
a9e843b38e | ||
|
|
9a76719544 | ||
|
|
472c8213db | ||
|
|
a4f9c022ff | ||
|
|
97514884b1 | ||
|
|
4980efa9b7 | ||
|
|
34cf130e4d | ||
|
|
21aa7b66ce | ||
|
|
11b95bed20 |
No files matched your search
@@ -378,6 +378,7 @@ add_executable(page_manager_tests EXCLUDE_FROM_ALL
|
||||
"${KYTY_TESTS_DIR}/PageManagerTests.cpp"
|
||||
"${KYTY_SOURCE_DIR}/graphics/host_gpu/pageManager.cpp"
|
||||
)
|
||||
target_link_libraries(page_manager_tests common)
|
||||
target_include_directories(page_manager_tests PRIVATE ${inc_headers})
|
||||
|
||||
add_executable(bit_array_tests EXCLUDE_FROM_ALL
|
||||
@@ -387,6 +388,7 @@ target_include_directories(bit_array_tests PRIVATE ${inc_headers})
|
||||
|
||||
add_executable(ime_dialog_tests EXCLUDE_FROM_ALL
|
||||
"${KYTY_TESTS_DIR}/ImeDialogTests.cpp"
|
||||
"${KYTY_SOURCE_DIR}/libs/imeCommon.cpp"
|
||||
"${KYTY_SOURCE_DIR}/libs/imeDialog.cpp"
|
||||
)
|
||||
target_include_directories(ime_dialog_tests PRIVATE ${inc_headers})
|
||||
|
||||
@@ -55,7 +55,7 @@ graphical glitches, low compatibility, and poor performance.
|
||||
<tr>
|
||||
<td align="center">
|
||||
<strong>Neptunia ReVerse</strong><br>
|
||||
<img src="docs/screenshots/ps5-04.png" width="300" alt="Minecraft Legends running in KytyPS5">
|
||||
<img src="docs/screenshots/ps5-04.png" width="300" alt="Neptunia ReVerse running in KytyPS5">
|
||||
</td>
|
||||
<td align="center">
|
||||
<strong>SILENT HILL: The Short Message</strong><br>
|
||||
@@ -65,11 +65,11 @@ graphical glitches, low compatibility, and poor performance.
|
||||
<tr>
|
||||
<td align="center">
|
||||
<strong>Hellboy</strong><br>
|
||||
<img src="docs/screenshots/ps5-02.png" width="300" alt="Disgaea 6 running in KytyPS5">
|
||||
<img src="docs/screenshots/ps5-02.png" width="300" alt="Hellboy running in KytyPS5">
|
||||
</td>
|
||||
<td align="center">
|
||||
<strong>Paleo Pines</strong><br>
|
||||
<img src="docs/screenshots/ps5-06.png" width="300" alt="Dreaming Sarah running in KytyPS5">
|
||||
<img src="docs/screenshots/ps5-06.png" width="300" alt="Paleo Pines running in KytyPS5">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -35,7 +35,7 @@ static std::string BuildFatalReport(const char* title, std::string_view text, co
|
||||
|
||||
static int DbgReport(const char* title, std::string_view text, const char* file, int line) {
|
||||
Log::WriteFatal(BuildFatalReport(title, text, file, line));
|
||||
SubsystemsListSingleton::Instance()->ShutdownAll();
|
||||
Subsystems::EmergencyShutdownActive();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
#include "common/commonSubsystem.h"
|
||||
|
||||
#include "common/byteBuffer.h" // IWYU pragma: associated
|
||||
#include "common/common.h" // IWYU pragma: associated
|
||||
#include "common/debug.h" // IWYU pragma: associated
|
||||
#include "common/hash.h" // IWYU pragma: associated
|
||||
#include "common/magicEnum.h" // IWYU pragma: associated
|
||||
#include "common/singleton.h" // IWYU pragma: associated
|
||||
#include "common/virtualMemory.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
KYTY_SUBSYSTEM_INIT(Common) {
|
||||
VirtualMemory::Init();
|
||||
}
|
||||
|
||||
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Common) {}
|
||||
|
||||
KYTY_SUBSYSTEM_DESTROY(Common) {}
|
||||
|
||||
} // namespace Common
|
||||
@@ -1,12 +0,0 @@
|
||||
#ifndef KYTY_COMMON_COMMON_SUBSYSTEM_H_
|
||||
#define KYTY_COMMON_COMMON_SUBSYSTEM_H_
|
||||
|
||||
#include "common/subsystems.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
KYTY_SUBSYSTEM_DEFINE(Common);
|
||||
|
||||
} // namespace Common
|
||||
|
||||
#endif /* KYTY_COMMON_COMMON_SUBSYSTEM_H_ */
|
||||
@@ -9,15 +9,15 @@ namespace Config {
|
||||
|
||||
static std::unique_ptr<ConfigOptions> g_config;
|
||||
|
||||
KYTY_SUBSYSTEM_INIT(Config) {
|
||||
void Initialize() {
|
||||
EXIT_IF(g_config != nullptr);
|
||||
|
||||
g_config = std::make_unique<ConfigOptions>();
|
||||
}
|
||||
|
||||
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Config) {}
|
||||
|
||||
KYTY_SUBSYSTEM_DESTROY(Config) {}
|
||||
void Shutdown() {
|
||||
g_config.reset();
|
||||
}
|
||||
|
||||
void Load(const ConfigOptions& cfg) {
|
||||
EXIT_IF(g_config == nullptr);
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#define KYTY_COMMON_EMULATOR_CONFIG_H_
|
||||
|
||||
#include "common/common.h"
|
||||
#include "common/subsystems.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
@@ -10,7 +9,14 @@
|
||||
|
||||
namespace Config {
|
||||
|
||||
KYTY_SUBSYSTEM_DEFINE(Config);
|
||||
void Initialize();
|
||||
void Shutdown();
|
||||
|
||||
struct Lifecycle {
|
||||
static constexpr const char* name = "Config";
|
||||
static constexpr auto initialize = Config::Initialize;
|
||||
static constexpr auto shutdown = Config::Shutdown;
|
||||
};
|
||||
|
||||
enum class ShaderOptimizationType { None, Size, Performance };
|
||||
|
||||
|
||||
@@ -149,7 +149,7 @@ void WriteFatal(fmt::text_style style, std::string_view text) {
|
||||
Flush();
|
||||
}
|
||||
|
||||
KYTY_SUBSYSTEM_INIT(Log) {
|
||||
void Initialize() {
|
||||
g_initialized = true;
|
||||
switch (Config::GetPrintfDirection()) {
|
||||
case Config::OutputDirection::Silent: g_direction = Direction::Silent; break;
|
||||
@@ -161,13 +161,7 @@ KYTY_SUBSYSTEM_INIT(Log) {
|
||||
SetupLogger();
|
||||
}
|
||||
|
||||
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Log) {
|
||||
Flush();
|
||||
std::lock_guard lock(g_logger_mutex);
|
||||
g_logger.reset();
|
||||
}
|
||||
|
||||
KYTY_SUBSYSTEM_DESTROY(Log) {
|
||||
void Shutdown() {
|
||||
Flush();
|
||||
std::lock_guard lock(g_logger_mutex);
|
||||
g_logger.reset();
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#define KYTY_COMMON_LOGGING_LOG_H_
|
||||
|
||||
#include "common/common.h"
|
||||
#include "common/subsystems.h"
|
||||
|
||||
#include <fmt/color.h>
|
||||
#include <fmt/printf.h>
|
||||
@@ -10,7 +9,15 @@
|
||||
|
||||
namespace Log {
|
||||
|
||||
KYTY_SUBSYSTEM_DEFINE(Log);
|
||||
void Initialize();
|
||||
void Shutdown();
|
||||
|
||||
struct Lifecycle {
|
||||
static constexpr const char* name = "Log";
|
||||
static constexpr auto initialize = Log::Initialize;
|
||||
static constexpr auto shutdown = Log::Shutdown;
|
||||
static constexpr auto emergency_shutdown = Log::Shutdown;
|
||||
};
|
||||
|
||||
enum class Direction { Silent, Console, File };
|
||||
|
||||
|
||||
@@ -15,56 +15,8 @@
|
||||
#include "common/assert.h"
|
||||
#include "common/platform/sysDbg.h"
|
||||
|
||||
struct FrameS {
|
||||
struct FrameS* next;
|
||||
void* ret_addr;
|
||||
};
|
||||
|
||||
int WalkStack(int z_stack_depth, void** z_stack_trace) {
|
||||
CONTEXT context;
|
||||
// KNONVOLATILE_CONTEXT_POINTERS NvContext;
|
||||
PRUNTIME_FUNCTION runtime_function = nullptr;
|
||||
PVOID handler_data = nullptr;
|
||||
ULONG64 establisher_frame = 0;
|
||||
ULONG64 image_base = 0;
|
||||
|
||||
RtlCaptureContext(&context);
|
||||
|
||||
int frame = 0;
|
||||
|
||||
while (true) {
|
||||
if (frame >= z_stack_depth) {
|
||||
break;
|
||||
}
|
||||
|
||||
z_stack_trace[frame] = reinterpret_cast<void*>(context.Rip);
|
||||
|
||||
frame++;
|
||||
|
||||
runtime_function = RtlLookupFunctionEntry(context.Rip, &image_base, nullptr);
|
||||
|
||||
if (runtime_function == nullptr) {
|
||||
break;
|
||||
}
|
||||
|
||||
// RtlZeroMemory(&NvContext, sizeof(KNONVOLATILE_CONTEXT_POINTERS));
|
||||
RtlVirtualUnwind(0, image_base, context.Rip, runtime_function, &context, &handler_data,
|
||||
&establisher_frame, nullptr /*&NvContext*/);
|
||||
|
||||
if (context.Rip == 0u) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
void SysStackWalk(void** stack, int* depth) {
|
||||
int n = WalkStack(*depth, stack);
|
||||
*depth = n;
|
||||
// unwind_info_t info = {stack, 0, *depth};
|
||||
// _Unwind_Backtrace(&trace_fcn, &info);
|
||||
// *depth = info.depth;
|
||||
*depth = static_cast<int>(CaptureStackBackTrace(0, static_cast<DWORD>(*depth), stack, nullptr));
|
||||
}
|
||||
|
||||
void SysStackUsagePrint(sys_dbg_stack_info_t& stack) {
|
||||
|
||||
+5
-14
@@ -1,7 +1,6 @@
|
||||
#include "common/profiler.h"
|
||||
|
||||
#include "common/emulatorConfig.h"
|
||||
#include "common/subsystems.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <common/TracyProtocol.hpp>
|
||||
@@ -55,13 +54,7 @@ void SetThreadName(const char* name) {
|
||||
}
|
||||
}
|
||||
|
||||
void Close() {
|
||||
if (tracy::ProfilerAvailable()) {
|
||||
tracy::ShutdownProfiler();
|
||||
}
|
||||
}
|
||||
|
||||
KYTY_SUBSYSTEM_INIT(Profiler) {
|
||||
void Initialize() {
|
||||
switch (Config::GetProfilerDirection()) {
|
||||
case Config::ProfilerDirection::Network:
|
||||
if (!tracy::ProfilerAvailable()) {
|
||||
@@ -78,12 +71,10 @@ KYTY_SUBSYSTEM_INIT(Profiler) {
|
||||
}
|
||||
}
|
||||
|
||||
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Profiler) {
|
||||
Close();
|
||||
}
|
||||
|
||||
KYTY_SUBSYSTEM_DESTROY(Profiler) {
|
||||
Close();
|
||||
void Shutdown() {
|
||||
if (tracy::ProfilerAvailable()) {
|
||||
tracy::ShutdownProfiler();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Profiler
|
||||
@@ -2,7 +2,6 @@
|
||||
#define KYTY_COMMON_PROFILER_H_
|
||||
|
||||
#include "common/common.h"
|
||||
#include "common/subsystems.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
@@ -42,7 +41,15 @@ private:
|
||||
void EndBlock();
|
||||
void SetThreadName(const char* name);
|
||||
|
||||
KYTY_SUBSYSTEM_DEFINE(Profiler);
|
||||
void Initialize();
|
||||
void Shutdown();
|
||||
|
||||
struct Lifecycle {
|
||||
static constexpr const char* name = "Profiler";
|
||||
static constexpr auto initialize = Profiler::Initialize;
|
||||
static constexpr auto shutdown = Profiler::Shutdown;
|
||||
static constexpr auto emergency_shutdown = Profiler::Shutdown;
|
||||
};
|
||||
|
||||
} // namespace Profiler
|
||||
|
||||
|
||||
+25
-214
@@ -1,232 +1,43 @@
|
||||
#include "common/subsystems.h"
|
||||
|
||||
#include "common/assert.h"
|
||||
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace Common {
|
||||
|
||||
class SubsystemPrivate {
|
||||
public:
|
||||
SubsystemPrivate() = default;
|
||||
virtual ~SubsystemPrivate() = default;
|
||||
static Subsystems* g_active_subsystems = nullptr;
|
||||
|
||||
KYTY_CLASS_NO_COPY(SubsystemPrivate);
|
||||
Subsystems::Subsystems(bool print): m_print(print) {
|
||||
m_active.reserve(16);
|
||||
g_active_subsystems = this;
|
||||
}
|
||||
|
||||
bool failed {false};
|
||||
std::string fail_msg;
|
||||
};
|
||||
|
||||
class SubsystemsListPrivate {
|
||||
public:
|
||||
explicit SubsystemsListPrivate(SubsystemsList& p): parent(p) {}
|
||||
|
||||
virtual ~SubsystemsListPrivate() = default;
|
||||
|
||||
void SetArgs(int argc, char** argv) {
|
||||
this->m_argc = argc;
|
||||
this->m_argv = argv;
|
||||
Subsystems::~Subsystems() {
|
||||
Destroy();
|
||||
if (g_active_subsystems == this) {
|
||||
g_active_subsystems = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Add(Subsystem* s, std::initializer_list<Subsystem*> deps) {
|
||||
EXIT_IF(!s);
|
||||
|
||||
const char* name = s->Id();
|
||||
|
||||
EXIT_IF(FindByName(name) != nullptr);
|
||||
|
||||
auto nl = std::make_unique<SubsListStruct>();
|
||||
|
||||
nl->s = s;
|
||||
nl->name = name;
|
||||
nl->deps = nullptr;
|
||||
nl->next = std::move(list);
|
||||
nl->prev_init = nullptr;
|
||||
|
||||
auto* node = nl.get();
|
||||
list = std::move(nl);
|
||||
|
||||
for (auto* dep: deps) {
|
||||
const char* str = dep->Id();
|
||||
|
||||
auto l = std::make_unique<DepsListStruct>();
|
||||
l->dep_name = str;
|
||||
l->next = std::move(node->deps);
|
||||
|
||||
node->deps = std::move(l);
|
||||
void Subsystems::Destroy() {
|
||||
for (auto it = m_active.rbegin(); it != m_active.rend(); ++it) {
|
||||
if (it->shutdown != nullptr) {
|
||||
it->shutdown();
|
||||
}
|
||||
|
||||
node->initialized = false;
|
||||
}
|
||||
m_active.clear();
|
||||
}
|
||||
|
||||
bool InitAll(bool print_msg) {
|
||||
while (SubsListStruct* n = FindNextToInitialize()) {
|
||||
n->s->Init(&parent);
|
||||
|
||||
if (n->s->m_p->failed) {
|
||||
fail_msg = n->s->m_p->fail_msg.c_str();
|
||||
fail_name = n->name;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (print_msg) {
|
||||
printf("Initialized: %s\n", n->name);
|
||||
}
|
||||
|
||||
n->initialized = true;
|
||||
|
||||
SubsListStruct* last = last_init;
|
||||
last_init = n;
|
||||
n->prev_init = last;
|
||||
void Subsystems::EmergencyShutdown() {
|
||||
for (auto it = m_active.rbegin(); it != m_active.rend(); ++it) {
|
||||
if (it->emergency_shutdown != nullptr) {
|
||||
it->emergency_shutdown();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
m_active.clear();
|
||||
}
|
||||
|
||||
void DestroyAll(bool print_msg) {
|
||||
for (SubsListStruct* n = last_init; n != nullptr; n = n->prev_init) {
|
||||
n->s->Destroy(&parent);
|
||||
n->initialized = false;
|
||||
|
||||
if (print_msg) {
|
||||
printf("Destroyed: %s\n", n->name);
|
||||
}
|
||||
}
|
||||
|
||||
last_init = nullptr;
|
||||
void Subsystems::EmergencyShutdownActive() {
|
||||
if (g_active_subsystems != nullptr) {
|
||||
g_active_subsystems->EmergencyShutdown();
|
||||
}
|
||||
|
||||
void ShutdownAll() {
|
||||
for (SubsListStruct* n = last_init; n != nullptr; n = n->prev_init) {
|
||||
n->s->UnexpectedShutdown(&parent);
|
||||
n->initialized = false;
|
||||
}
|
||||
|
||||
last_init = nullptr;
|
||||
}
|
||||
|
||||
struct DepsListStruct {
|
||||
const char* dep_name;
|
||||
std::unique_ptr<DepsListStruct> next;
|
||||
};
|
||||
|
||||
struct SubsListStruct {
|
||||
Subsystem* s;
|
||||
const char* name;
|
||||
std::unique_ptr<DepsListStruct> deps;
|
||||
std::unique_ptr<SubsListStruct> next;
|
||||
SubsListStruct* prev_init;
|
||||
bool initialized;
|
||||
};
|
||||
|
||||
[[nodiscard]] SubsListStruct* FindByName(const char* name) const {
|
||||
for (SubsListStruct* n = list.get(); n != nullptr; n = n->next.get()) {
|
||||
if (std::strcmp(n->name, name) == 0) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] SubsListStruct* FindNextToInitialize() const {
|
||||
for (SubsListStruct* n = list.get(); n != nullptr; n = n->next.get()) {
|
||||
if (n->initialized) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DepsListStruct* d = n->deps.get();
|
||||
for (; d != nullptr; d = d->next.get()) {
|
||||
SubsListStruct* s = FindByName(d->dep_name);
|
||||
if ((s == nullptr) || !s->initialized) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (d == nullptr) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
KYTY_CLASS_NO_COPY(SubsystemsListPrivate);
|
||||
|
||||
std::unique_ptr<SubsListStruct> list;
|
||||
SubsListStruct* last_init = nullptr;
|
||||
int m_argc = 0;
|
||||
char** m_argv = nullptr;
|
||||
const char* fail_msg = nullptr;
|
||||
const char* fail_name = nullptr;
|
||||
SubsystemsList& parent;
|
||||
};
|
||||
|
||||
SubsystemsList::SubsystemsList(): m_p(std::make_unique<SubsystemsListPrivate>(*this)) {}
|
||||
|
||||
SubsystemsList::~SubsystemsList() = default;
|
||||
|
||||
void SubsystemsList::Add(Subsystem* s, std::initializer_list<Subsystem*> deps) {
|
||||
m_p->Add(s, deps);
|
||||
}
|
||||
|
||||
bool SubsystemsList::InitAll(bool print_msg) {
|
||||
return m_p->InitAll(print_msg);
|
||||
}
|
||||
|
||||
void SubsystemsList::DestroyAll(bool print_msg) {
|
||||
m_p->DestroyAll(print_msg);
|
||||
}
|
||||
|
||||
int* SubsystemsList::GetArgc() {
|
||||
return &m_p->m_argc;
|
||||
}
|
||||
|
||||
char** SubsystemsList::GetArgv() {
|
||||
return m_p->m_argv;
|
||||
}
|
||||
|
||||
Subsystem::Subsystem(): m_p(std::make_unique<SubsystemPrivate>()) {}
|
||||
|
||||
Subsystem::~Subsystem() = default;
|
||||
|
||||
void Subsystem::Fail(const char* format, ...) {
|
||||
va_list args {};
|
||||
va_start(args, format);
|
||||
|
||||
va_list args_copy {};
|
||||
va_copy(args_copy, args);
|
||||
int len = std::vsnprintf(nullptr, 0, format, args_copy);
|
||||
va_end(args_copy);
|
||||
|
||||
if (len > 0) {
|
||||
std::string msg(static_cast<size_t>(len) + 1, '\0');
|
||||
std::vsnprintf(msg.data(), msg.size(), format, args);
|
||||
m_p->fail_msg = msg.c_str();
|
||||
m_p->failed = true;
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
const char* SubsystemsList::GetFailName() const {
|
||||
return m_p->fail_name;
|
||||
}
|
||||
|
||||
const char* SubsystemsList::GetFailMsg() const {
|
||||
return m_p->fail_msg;
|
||||
}
|
||||
|
||||
void SubsystemsList::SetArgs(int argc, char* argv[]) {
|
||||
m_p->SetArgs(argc, argv);
|
||||
}
|
||||
|
||||
void SubsystemsList::ShutdownAll() {
|
||||
m_p->ShutdownAll();
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
+41
-70
@@ -2,90 +2,61 @@
|
||||
#define KYTY_COMMON_SUBSYSTEMS_H_
|
||||
|
||||
#include "common/common.h"
|
||||
#include "common/singleton.h"
|
||||
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
#include <cstdio>
|
||||
#include <vector>
|
||||
|
||||
namespace Common {
|
||||
|
||||
class Subsystem;
|
||||
class SubsystemsListPrivate;
|
||||
class SubsystemPrivate;
|
||||
|
||||
class SubsystemsList {
|
||||
class Subsystems {
|
||||
public:
|
||||
SubsystemsList();
|
||||
virtual ~SubsystemsList();
|
||||
void SetArgs(int argc, char* argv[]);
|
||||
using Callback = void (*)();
|
||||
|
||||
// void Add(Subsystem* s, const char* name, ...);
|
||||
void Add(Subsystem* s, std::initializer_list<Subsystem*> deps);
|
||||
explicit Subsystems(bool print = false);
|
||||
~Subsystems();
|
||||
|
||||
bool InitAll(bool print_msg = false);
|
||||
void DestroyAll(bool print_msg = false);
|
||||
template <typename Lifecycle>
|
||||
void Initialize() {
|
||||
Lifecycle::initialize();
|
||||
m_active.push_back({ShutdownCallback<Lifecycle>(), EmergencyCallback<Lifecycle>()});
|
||||
if (m_print) {
|
||||
std::printf("Initialized: %s\n", Lifecycle::name);
|
||||
}
|
||||
}
|
||||
|
||||
int* GetArgc();
|
||||
char** GetArgv();
|
||||
void Destroy();
|
||||
void EmergencyShutdown();
|
||||
|
||||
[[nodiscard]] const char* GetFailName() const;
|
||||
[[nodiscard]] const char* GetFailMsg() const;
|
||||
static void EmergencyShutdownActive();
|
||||
|
||||
void ShutdownAll();
|
||||
|
||||
static SubsystemsList* Instance() { return Common::Singleton<SubsystemsList>::Instance(); }
|
||||
|
||||
KYTY_CLASS_NO_COPY(SubsystemsList);
|
||||
KYTY_CLASS_NO_COPY(Subsystems);
|
||||
|
||||
private:
|
||||
std::unique_ptr<SubsystemsListPrivate> m_p;
|
||||
template <typename Lifecycle>
|
||||
static consteval Callback ShutdownCallback() {
|
||||
if constexpr (requires { Lifecycle::shutdown; }) {
|
||||
return Lifecycle::shutdown;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename Lifecycle>
|
||||
static consteval Callback EmergencyCallback() {
|
||||
if constexpr (requires { Lifecycle::emergency_shutdown; }) {
|
||||
return Lifecycle::emergency_shutdown;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
struct Entry {
|
||||
Callback shutdown;
|
||||
Callback emergency_shutdown;
|
||||
};
|
||||
|
||||
std::vector<Entry> m_active;
|
||||
bool m_print;
|
||||
};
|
||||
|
||||
using SubsystemsListSingleton = Common::Singleton<SubsystemsList>;
|
||||
|
||||
class Subsystem {
|
||||
public:
|
||||
Subsystem();
|
||||
virtual ~Subsystem();
|
||||
|
||||
virtual const char* Id() = 0;
|
||||
virtual void Init(SubsystemsList* parent) = 0;
|
||||
virtual void Destroy(SubsystemsList* parent) = 0;
|
||||
virtual void UnexpectedShutdown(SubsystemsList* parent) = 0;
|
||||
|
||||
friend class SubsystemsListPrivate;
|
||||
|
||||
KYTY_CLASS_NO_COPY(Subsystem);
|
||||
|
||||
protected:
|
||||
void Fail(const char* format, ...) KYTY_FORMAT_PRINTF(2, 3);
|
||||
|
||||
private:
|
||||
std::unique_ptr<SubsystemPrivate> m_p;
|
||||
};
|
||||
|
||||
#define KYTY_SUBSYSTEM_DEFINE(s) \
|
||||
class s##Subsystem: public Common::Subsystem { \
|
||||
public: \
|
||||
static Subsystem* Instance() { return Common::Singleton<s##Subsystem>::Instance(); } \
|
||||
const char* Id() { return #s; } \
|
||||
void Init(Common::SubsystemsList* parent); \
|
||||
void Destroy(Common::SubsystemsList* parent); \
|
||||
void UnexpectedShutdown(Common::SubsystemsList* parent); \
|
||||
}; \
|
||||
typedef Common::Singleton<s##Subsystem> s##SubsystemSingleton;
|
||||
|
||||
#define KYTY_SUBSYSTEM_INIT(s) \
|
||||
void s##Subsystem::Init([[maybe_unused]] Common::SubsystemsList* parent)
|
||||
#define KYTY_SUBSYSTEM_DESTROY(s) \
|
||||
void s##Subsystem::Destroy([[maybe_unused]] Common::SubsystemsList* parent)
|
||||
#define KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(s) \
|
||||
void s##Subsystem::UnexpectedShutdown([[maybe_unused]] Common::SubsystemsList* parent)
|
||||
|
||||
// #define KYTY_SUBSYSTEM_ADD(list, s, ...) list.push_back(s##SubsystemSingleton::Instance(), #s,
|
||||
// __VA_ARGS__); #define KYTY_SUBSYSTEM_ADD2(list, ...) list.Add2(s##SubsystemSingleton::Instance(),
|
||||
// __VA_ARGS__);
|
||||
|
||||
} // namespace Common
|
||||
|
||||
#endif /* KYTY_COMMON_SUBSYSTEMS_H_ */
|
||||
@@ -252,15 +252,11 @@ static thread_id_t g_main_thread;
|
||||
static int g_main_thread_int;
|
||||
static std::atomic<int> g_thread_counter = 0;
|
||||
|
||||
KYTY_SUBSYSTEM_INIT(Threads) {
|
||||
void InitializeThreads() {
|
||||
g_main_thread = std::this_thread::get_id();
|
||||
g_main_thread_int = Thread::GetThreadIdUnique();
|
||||
}
|
||||
|
||||
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Threads) {}
|
||||
|
||||
KYTY_SUBSYSTEM_DESTROY(Threads) {}
|
||||
|
||||
Thread::Thread(thread_func_t func, void* arg)
|
||||
: m_thread(std::make_unique<ThreadPrivate>(func, arg)) {
|
||||
while (!m_thread->started) {
|
||||
|
||||
@@ -2,14 +2,13 @@
|
||||
#define KYTY_COMMON_THREADS_H_
|
||||
|
||||
#include "common/common.h"
|
||||
#include "common/subsystems.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace Common {
|
||||
|
||||
KYTY_SUBSYSTEM_DEFINE(Threads);
|
||||
void InitializeThreads();
|
||||
|
||||
using thread_func_t = void (*)(void*);
|
||||
using wait_poll_func_t = void (*)();
|
||||
|
||||
+18
-36
@@ -2,7 +2,6 @@
|
||||
|
||||
#include "common/abi.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/commonSubsystem.h"
|
||||
#include "common/emulatorConfig.h"
|
||||
#include "common/file.h"
|
||||
#include "common/logging/log.h"
|
||||
@@ -43,7 +42,7 @@ static void KytyClose() {
|
||||
|
||||
LOGF("done!\n");
|
||||
|
||||
Common::SubsystemsListSingleton::Instance()->ShutdownAll();
|
||||
Common::Subsystems::EmergencyShutdownActive();
|
||||
}
|
||||
|
||||
static void MountOrCreateDir(const std::filesystem::path& dir, const std::string& point) {
|
||||
@@ -105,30 +104,13 @@ static void ClearDebugTextureFolder() {
|
||||
}
|
||||
}
|
||||
|
||||
static void Init(const Config::ConfigOptions& cfg, const std::filesystem::path& param_json) {
|
||||
static void Init(const Config::ConfigOptions& cfg, const std::filesystem::path& param_json,
|
||||
Common::Subsystems& subsystems) {
|
||||
EXIT_IF(!Common::Thread::IsMainThread());
|
||||
|
||||
auto* slist = Common::SubsystemsList::Instance();
|
||||
|
||||
auto* audio = Libs::Audio::AudioSubsystem::Instance();
|
||||
auto* config = Config::ConfigSubsystem::Instance();
|
||||
auto* controller = Libs::Controller::ControllerSubsystem::Instance();
|
||||
auto* core = Common::CommonSubsystem::Instance();
|
||||
auto* file_system = Libs::LibKernel::FileSystem::FileSystemSubsystem::Instance();
|
||||
auto* graphics = Libs::Graphics::GraphicsSubsystem::Instance();
|
||||
auto* log = Log::LogSubsystem::Instance();
|
||||
auto* memory = Libs::LibKernel::Memory::MemorySubsystem::Instance();
|
||||
auto* network = Libs::Network::NetworkSubsystem::Instance();
|
||||
auto* profiler = Profiler::ProfilerSubsystem::Instance();
|
||||
auto* pthread = Libs::LibKernel::PthreadSubsystem::Instance();
|
||||
auto* timer = Loader::Timer::TimerSubsystem::Instance();
|
||||
|
||||
slist->Add(config, {core});
|
||||
slist->InitAll(true);
|
||||
|
||||
subsystems.Initialize<Config::Lifecycle>();
|
||||
Config::Load(cfg);
|
||||
slist->Add(log, {core, config});
|
||||
slist->InitAll(true);
|
||||
subsystems.Initialize<Log::Lifecycle>();
|
||||
|
||||
if (Common::File::IsFileExisting(param_json)) {
|
||||
Loader::SystemContentLoadParamSfo(param_json);
|
||||
@@ -138,17 +120,16 @@ static void Init(const Config::ConfigOptions& cfg, const std::filesystem::path&
|
||||
}
|
||||
}
|
||||
|
||||
slist->Add(audio, {core, log, pthread, memory});
|
||||
slist->Add(controller, {core, log, config});
|
||||
slist->Add(file_system, {core, log, pthread});
|
||||
slist->Add(graphics, {core, log, pthread, memory, config, profiler, controller});
|
||||
slist->Add(memory, {core, log});
|
||||
slist->Add(network, {core, log, pthread});
|
||||
slist->Add(profiler, {core, config});
|
||||
slist->Add(pthread, {core, log, timer});
|
||||
slist->Add(timer, {core, log});
|
||||
|
||||
slist->InitAll(true);
|
||||
// Initialization order is explicit; destruction is automatic and reversed.
|
||||
subsystems.Initialize<Loader::Timer::Lifecycle>();
|
||||
subsystems.Initialize<Libs::LibKernel::PthreadLifecycle>();
|
||||
subsystems.Initialize<Profiler::Lifecycle>();
|
||||
subsystems.Initialize<Libs::Network::Lifecycle>();
|
||||
subsystems.Initialize<Libs::LibKernel::Memory::Lifecycle>();
|
||||
subsystems.Initialize<Libs::LibKernel::FileSystem::Lifecycle>();
|
||||
subsystems.Initialize<Libs::Controller::Lifecycle>();
|
||||
subsystems.Initialize<Libs::Audio::Lifecycle>();
|
||||
subsystems.Initialize<Libs::Graphics::Lifecycle>();
|
||||
}
|
||||
|
||||
static void LoadElf(const std::filesystem::path& elf, bool dbg_print_reloc = false,
|
||||
@@ -189,8 +170,9 @@ void Run(const RunOptions& options) {
|
||||
EXIT("ELF is required\n");
|
||||
}
|
||||
|
||||
const auto param_json = options.app0_dir / "sce_sys" / "param.json";
|
||||
Init(options.config, param_json);
|
||||
const auto param_json = options.app0_dir / "sce_sys" / "param.json";
|
||||
Common::Subsystems subsystems(true);
|
||||
Init(options.config, param_json, subsystems);
|
||||
|
||||
ClearDebugTextureFolder();
|
||||
|
||||
|
||||
@@ -103,6 +103,128 @@ void LogUnknownReleaseMemGcr(uint32_t gcr_cntl) {
|
||||
|
||||
} // namespace
|
||||
|
||||
static HW::BlendControl DecodeBlendControl(uint32_t value) {
|
||||
HW::BlendControl r {};
|
||||
|
||||
r.color_srcblend = KYTY_PM4_GET(value, CB_BLEND0_CONTROL, COLOR_SRCBLEND);
|
||||
r.color_comb_fcn = KYTY_PM4_GET(value, CB_BLEND0_CONTROL, COLOR_COMB_FCN);
|
||||
r.color_destblend = KYTY_PM4_GET(value, CB_BLEND0_CONTROL, COLOR_DESTBLEND);
|
||||
r.alpha_srcblend = KYTY_PM4_GET(value, CB_BLEND0_CONTROL, ALPHA_SRCBLEND);
|
||||
r.alpha_comb_fcn = KYTY_PM4_GET(value, CB_BLEND0_CONTROL, ALPHA_COMB_FCN);
|
||||
r.alpha_destblend = KYTY_PM4_GET(value, CB_BLEND0_CONTROL, ALPHA_DESTBLEND);
|
||||
r.separate_alpha_blend = KYTY_PM4_GET(value, CB_BLEND0_CONTROL, SEPARATE_ALPHA_BLEND) != 0;
|
||||
r.enable = KYTY_PM4_GET(value, CB_BLEND0_CONTROL, ENABLE) != 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static HW::ClipControl DecodeClipControl(uint32_t value) {
|
||||
HW::ClipControl r {};
|
||||
|
||||
r.user_clip_planes = KYTY_PM4_GET(value, PA_CL_CLIP_CNTL, UCP_ENA);
|
||||
r.user_clip_plane_mode = KYTY_PM4_GET(value, PA_CL_CLIP_CNTL, PS_UCP_MODE);
|
||||
r.dx_clip_space = KYTY_PM4_GET(value, PA_CL_CLIP_CNTL, DX_CLIP_SPACE_DEF) != 0;
|
||||
r.vertex_kill_any = KYTY_PM4_GET(value, PA_CL_CLIP_CNTL, VTX_KILL_OR) != 0;
|
||||
r.min_z_clip_disable = KYTY_PM4_GET(value, PA_CL_CLIP_CNTL, ZCLIP_NEAR_DISABLE) != 0;
|
||||
r.max_z_clip_disable = KYTY_PM4_GET(value, PA_CL_CLIP_CNTL, ZCLIP_FAR_DISABLE) != 0;
|
||||
r.user_clip_plane_negate_y = KYTY_PM4_GET(value, PA_CL_CLIP_CNTL, PS_UCP_Y_SCALE_NEG) != 0;
|
||||
r.clip_disable = KYTY_PM4_GET(value, PA_CL_CLIP_CNTL, CLIP_DISABLE) != 0;
|
||||
r.user_clip_plane_cull_only = KYTY_PM4_GET(value, PA_CL_CLIP_CNTL, UCP_CULL_ONLY_ENA) != 0;
|
||||
r.cull_on_clipping_error_disable =
|
||||
KYTY_PM4_GET(value, PA_CL_CLIP_CNTL, DIS_CLIP_ERR_DETECT) != 0;
|
||||
r.linear_attribute_clip_enable =
|
||||
KYTY_PM4_GET(value, PA_CL_CLIP_CNTL, DX_LINEAR_ATTR_CLIP_ENA) != 0;
|
||||
r.force_viewport_index_from_vs_enable =
|
||||
KYTY_PM4_GET(value, PA_CL_CLIP_CNTL, VTE_VPORT_PROVOKE_DISABLE) != 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static HW::ColorControl DecodeColorControl(uint32_t value) {
|
||||
HW::ColorControl r {};
|
||||
r.mode = KYTY_PM4_GET(value, CB_COLOR_CONTROL, MODE);
|
||||
r.op = KYTY_PM4_GET(value, CB_COLOR_CONTROL, ROP3);
|
||||
return r;
|
||||
}
|
||||
|
||||
static HW::DepthControl DecodeDepthControl(uint32_t value) {
|
||||
HW::DepthControl r {};
|
||||
|
||||
r.stencil_enable = KYTY_PM4_GET(value, DB_DEPTH_CONTROL, STENCIL_ENABLE) != 0;
|
||||
r.z_enable = KYTY_PM4_GET(value, DB_DEPTH_CONTROL, Z_ENABLE) != 0;
|
||||
r.z_write_enable = KYTY_PM4_GET(value, DB_DEPTH_CONTROL, Z_WRITE_ENABLE) != 0;
|
||||
r.depth_bounds_enable = KYTY_PM4_GET(value, DB_DEPTH_CONTROL, DEPTH_BOUNDS_ENABLE) != 0;
|
||||
r.zfunc = KYTY_PM4_GET(value, DB_DEPTH_CONTROL, ZFUNC);
|
||||
r.backface_enable = KYTY_PM4_GET(value, DB_DEPTH_CONTROL, BACKFACE_ENABLE) != 0;
|
||||
r.stencilfunc = KYTY_PM4_GET(value, DB_DEPTH_CONTROL, STENCILFUNC);
|
||||
r.stencilfunc_bf = KYTY_PM4_GET(value, DB_DEPTH_CONTROL, STENCILFUNC_BF);
|
||||
r.color_writes_on_depth_fail_enable =
|
||||
KYTY_PM4_GET(value, DB_DEPTH_CONTROL, ENABLE_COLOR_WRITES_ON_DEPTH_FAIL) != 0;
|
||||
r.color_writes_on_depth_pass_disable =
|
||||
KYTY_PM4_GET(value, DB_DEPTH_CONTROL, DISABLE_COLOR_WRITES_ON_DEPTH_PASS) != 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static HW::ModeControl DecodeModeControl(uint32_t value) {
|
||||
HW::ModeControl r {};
|
||||
|
||||
r.cull_front = KYTY_PM4_GET(value, PA_SU_SC_MODE_CNTL, CULL_FRONT) != 0;
|
||||
r.cull_back = KYTY_PM4_GET(value, PA_SU_SC_MODE_CNTL, CULL_BACK) != 0;
|
||||
r.face = KYTY_PM4_GET(value, PA_SU_SC_MODE_CNTL, FACE) != 0;
|
||||
r.poly_mode = KYTY_PM4_GET(value, PA_SU_SC_MODE_CNTL, POLY_MODE);
|
||||
r.polymode_front_ptype = KYTY_PM4_GET(value, PA_SU_SC_MODE_CNTL, POLYMODE_FRONT_PTYPE);
|
||||
r.polymode_back_ptype = KYTY_PM4_GET(value, PA_SU_SC_MODE_CNTL, POLYMODE_BACK_PTYPE);
|
||||
r.poly_offset_front_enable =
|
||||
KYTY_PM4_GET(value, PA_SU_SC_MODE_CNTL, POLY_OFFSET_FRONT_ENABLE) != 0;
|
||||
r.poly_offset_back_enable =
|
||||
KYTY_PM4_GET(value, PA_SU_SC_MODE_CNTL, POLY_OFFSET_BACK_ENABLE) != 0;
|
||||
r.vtx_window_offset_enable =
|
||||
KYTY_PM4_GET(value, PA_SU_SC_MODE_CNTL, VTX_WINDOW_OFFSET_ENABLE) != 0;
|
||||
r.provoking_vtx_last = KYTY_PM4_GET(value, PA_SU_SC_MODE_CNTL, PROVOKING_VTX_LAST) != 0;
|
||||
r.persp_corr_dis = KYTY_PM4_GET(value, PA_SU_SC_MODE_CNTL, PERSP_CORR_DIS) != 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static HW::RenderControl DecodeRenderControl(uint32_t value) {
|
||||
HW::RenderControl r {};
|
||||
|
||||
r.depth_clear_enable = KYTY_PM4_GET(value, DB_RENDER_CONTROL, DEPTH_CLEAR_ENABLE) != 0;
|
||||
r.stencil_clear_enable = KYTY_PM4_GET(value, DB_RENDER_CONTROL, STENCIL_CLEAR_ENABLE) != 0;
|
||||
r.resummarize_enable = KYTY_PM4_GET(value, DB_RENDER_CONTROL, RESUMMARIZE_ENABLE) != 0;
|
||||
r.stencil_compress_disable =
|
||||
KYTY_PM4_GET(value, DB_RENDER_CONTROL, STENCIL_COMPRESS_DISABLE) != 0;
|
||||
r.depth_compress_disable = KYTY_PM4_GET(value, DB_RENDER_CONTROL, DEPTH_COMPRESS_DISABLE) != 0;
|
||||
r.copy_centroid = KYTY_PM4_GET(value, DB_RENDER_CONTROL, COPY_CENTROID) != 0;
|
||||
r.copy_sample = KYTY_PM4_GET(value, DB_RENDER_CONTROL, COPY_SAMPLE);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static HW::ScanModeControl DecodeScanModeControl(uint32_t value) {
|
||||
HW::ScanModeControl r {};
|
||||
|
||||
r.msaa_enable = KYTY_PM4_GET(value, PA_SC_MODE_CNTL_0, MSAA_ENABLE) != 0;
|
||||
r.vport_scissor_enable = KYTY_PM4_GET(value, PA_SC_MODE_CNTL_0, VPORT_SCISSOR_ENABLE) != 0;
|
||||
r.line_stipple_enable = KYTY_PM4_GET(value, PA_SC_MODE_CNTL_0, LINE_STIPPLE_ENABLE) != 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static HW::StencilControl DecodeStencilControl(uint32_t value) {
|
||||
HW::StencilControl r {};
|
||||
|
||||
r.stencil_fail = KYTY_PM4_GET(value, DB_STENCIL_CONTROL, STENCILFAIL);
|
||||
r.stencil_zpass = KYTY_PM4_GET(value, DB_STENCIL_CONTROL, STENCILZPASS);
|
||||
r.stencil_zfail = KYTY_PM4_GET(value, DB_STENCIL_CONTROL, STENCILZFAIL);
|
||||
r.stencil_fail_bf = KYTY_PM4_GET(value, DB_STENCIL_CONTROL, STENCILFAIL_BF);
|
||||
r.stencil_zpass_bf = KYTY_PM4_GET(value, DB_STENCIL_CONTROL, STENCILZPASS_BF);
|
||||
r.stencil_zfail_bf = KYTY_PM4_GET(value, DB_STENCIL_CONTROL, STENCILZFAIL_BF);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static HW::AaConfig ParseAaConfig(uint32_t value) {
|
||||
HW::AaConfig r;
|
||||
|
||||
@@ -429,26 +551,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetBlendControl) {
|
||||
|
||||
uint32_t param = (cmd_offset - Pm4::CB_BLEND0_CONTROL) / 1;
|
||||
|
||||
HW::BlendControl r;
|
||||
|
||||
r.color_srcblend = (buffer[0] >> Pm4::CB_BLEND0_CONTROL_COLOR_SRCBLEND_SHIFT) &
|
||||
Pm4::CB_BLEND0_CONTROL_COLOR_SRCBLEND_MASK;
|
||||
r.color_comb_fcn = (buffer[0] >> Pm4::CB_BLEND0_CONTROL_COLOR_COMB_FCN_SHIFT) &
|
||||
Pm4::CB_BLEND0_CONTROL_COLOR_COMB_FCN_MASK;
|
||||
r.color_destblend = (buffer[0] >> Pm4::CB_BLEND0_CONTROL_COLOR_DESTBLEND_SHIFT) &
|
||||
Pm4::CB_BLEND0_CONTROL_COLOR_DESTBLEND_MASK;
|
||||
r.alpha_srcblend = (buffer[0] >> Pm4::CB_BLEND0_CONTROL_ALPHA_SRCBLEND_SHIFT) &
|
||||
Pm4::CB_BLEND0_CONTROL_ALPHA_SRCBLEND_MASK;
|
||||
r.alpha_comb_fcn = (buffer[0] >> Pm4::CB_BLEND0_CONTROL_ALPHA_COMB_FCN_SHIFT) &
|
||||
Pm4::CB_BLEND0_CONTROL_ALPHA_COMB_FCN_MASK;
|
||||
r.alpha_destblend = (buffer[0] >> Pm4::CB_BLEND0_CONTROL_ALPHA_DESTBLEND_SHIFT) &
|
||||
Pm4::CB_BLEND0_CONTROL_ALPHA_DESTBLEND_MASK;
|
||||
r.separate_alpha_blend = ((buffer[0] >> Pm4::CB_BLEND0_CONTROL_SEPARATE_ALPHA_BLEND_SHIFT) &
|
||||
Pm4::CB_BLEND0_CONTROL_SEPARATE_ALPHA_BLEND_MASK) != 0;
|
||||
r.enable = ((buffer[0] >> Pm4::CB_BLEND0_CONTROL_ENABLE_SHIFT) &
|
||||
Pm4::CB_BLEND0_CONTROL_ENABLE_MASK) != 0;
|
||||
|
||||
cp.GetCtx().SetBlendControl(param, r);
|
||||
cp.GetCtx().SetBlendControl(param, DecodeBlendControl(buffer[0]));
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -457,38 +560,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetClipControl) {
|
||||
EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0016900);
|
||||
EXIT_NOT_IMPLEMENTED(cmd_offset != Pm4::PA_CL_CLIP_CNTL);
|
||||
|
||||
HW::ClipControl r;
|
||||
|
||||
// r.user_clip_planes = buffer[0] & 0x3fu;
|
||||
// r.user_clip_plane_mode = (buffer[0] >> 14u) & 0x3u;
|
||||
// r.clip_space = (buffer[0] >> 19u) & 0x1u;
|
||||
// r.vertex_kill_mode = (buffer[0] >> 21u) & 0x1u;
|
||||
// r.min_z_clip_enable = (buffer[0] >> 26u) & 0x1u;
|
||||
// r.max_z_clip_enable = (buffer[0] >> 27u) & 0x1u;
|
||||
// r.user_clip_plane_negate_y = (buffer[0] & 0x00002000u) != 0;
|
||||
// r.clip_enable = (buffer[0] & 0x00010000u) != 0;
|
||||
// r.user_clip_plane_cull_only = (buffer[0] & 0x00020000u) != 0;
|
||||
// r.cull_on_clipping_error_disable = (buffer[0] & 0x00100000u) != 0;
|
||||
// r.linear_attribute_clip_enable = (buffer[0] & 0x01000000u) != 0;
|
||||
// r.force_viewport_index_from_vs_enable = (buffer[0] & 0x02000000u) != 0;
|
||||
|
||||
r.user_clip_planes = KYTY_PM4_GET(buffer[0], PA_CL_CLIP_CNTL, UCP_ENA);
|
||||
r.user_clip_plane_mode = KYTY_PM4_GET(buffer[0], PA_CL_CLIP_CNTL, PS_UCP_MODE);
|
||||
r.dx_clip_space = KYTY_PM4_GET(buffer[0], PA_CL_CLIP_CNTL, DX_CLIP_SPACE_DEF) != 0;
|
||||
r.vertex_kill_any = KYTY_PM4_GET(buffer[0], PA_CL_CLIP_CNTL, VTX_KILL_OR) != 0;
|
||||
r.min_z_clip_disable = KYTY_PM4_GET(buffer[0], PA_CL_CLIP_CNTL, ZCLIP_NEAR_DISABLE) != 0;
|
||||
r.max_z_clip_disable = KYTY_PM4_GET(buffer[0], PA_CL_CLIP_CNTL, ZCLIP_FAR_DISABLE) != 0;
|
||||
r.user_clip_plane_negate_y = KYTY_PM4_GET(buffer[0], PA_CL_CLIP_CNTL, PS_UCP_Y_SCALE_NEG) != 0;
|
||||
r.clip_disable = KYTY_PM4_GET(buffer[0], PA_CL_CLIP_CNTL, CLIP_DISABLE) != 0;
|
||||
r.user_clip_plane_cull_only = KYTY_PM4_GET(buffer[0], PA_CL_CLIP_CNTL, UCP_CULL_ONLY_ENA) != 0;
|
||||
r.cull_on_clipping_error_disable =
|
||||
KYTY_PM4_GET(buffer[0], PA_CL_CLIP_CNTL, DIS_CLIP_ERR_DETECT) != 0;
|
||||
r.linear_attribute_clip_enable =
|
||||
KYTY_PM4_GET(buffer[0], PA_CL_CLIP_CNTL, DX_LINEAR_ATTR_CLIP_ENA) != 0;
|
||||
r.force_viewport_index_from_vs_enable =
|
||||
KYTY_PM4_GET(buffer[0], PA_CL_CLIP_CNTL, VTE_VPORT_PROVOKE_DISABLE) != 0;
|
||||
|
||||
cp.GetCtx().SetClipControl(r);
|
||||
cp.GetCtx().SetClipControl(DecodeClipControl(buffer[0]));
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -497,12 +569,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetColorControl) {
|
||||
EXIT_NOT_IMPLEMENTED(cmd_id != 0xc0016900);
|
||||
EXIT_NOT_IMPLEMENTED(cmd_offset != Pm4::CB_COLOR_CONTROL);
|
||||
|
||||
HW::ColorControl r;
|
||||
|
||||
r.mode = KYTY_PM4_GET(buffer[0], CB_COLOR_CONTROL, MODE);
|
||||
r.op = KYTY_PM4_GET(buffer[0], CB_COLOR_CONTROL, ROP3);
|
||||
|
||||
cp.GetCtx().SetColorControl(r);
|
||||
cp.GetCtx().SetColorControl(DecodeColorControl(buffer[0]));
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -526,9 +593,12 @@ KYTY_HW_CTX_PARSER(HwCtxSetColorInfo) {
|
||||
// r.format = (buffer[4] >> 2u) & 0x1fu;
|
||||
// r.channel_type = (buffer[4] >> 8u) & 0x7u;
|
||||
// r.channel_order = (buffer[4] >> 11u) & 0x3u;
|
||||
r.format = KYTY_PM4_GET(buffer[0], CB_COLOR0_INFO, FORMAT);
|
||||
r.channel_type = KYTY_PM4_GET(buffer[0], CB_COLOR0_INFO, NUMBER_TYPE);
|
||||
r.channel_order = KYTY_PM4_GET(buffer[0], CB_COLOR0_INFO, COMP_SWAP);
|
||||
r.format =
|
||||
static_cast<Prospero::ChannelLayout>(KYTY_PM4_GET(buffer[0], CB_COLOR0_INFO, FORMAT));
|
||||
r.channel_type =
|
||||
static_cast<Prospero::ChannelType>(KYTY_PM4_GET(buffer[0], CB_COLOR0_INFO, NUMBER_TYPE));
|
||||
r.channel_order =
|
||||
static_cast<Prospero::ChannelOrder>(KYTY_PM4_GET(buffer[0], CB_COLOR0_INFO, COMP_SWAP));
|
||||
r.cmask_fast_clear_enable = KYTY_PM4_GET(buffer[0], CB_COLOR0_INFO, FAST_CLEAR) != 0;
|
||||
r.fmask_compression_enable = KYTY_PM4_GET(buffer[0], CB_COLOR0_INFO, COMPRESSION) != 0;
|
||||
r.blend_clamp = KYTY_PM4_GET(buffer[0], CB_COLOR0_INFO, BLEND_CLAMP) != 0;
|
||||
@@ -560,22 +630,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetDepthControl) {
|
||||
EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0016900);
|
||||
EXIT_NOT_IMPLEMENTED(cmd_offset != Pm4::DB_DEPTH_CONTROL);
|
||||
|
||||
HW::DepthControl r;
|
||||
|
||||
r.stencil_enable = KYTY_PM4_GET(buffer[0], DB_DEPTH_CONTROL, STENCIL_ENABLE) != 0;
|
||||
r.z_enable = KYTY_PM4_GET(buffer[0], DB_DEPTH_CONTROL, Z_ENABLE) != 0;
|
||||
r.z_write_enable = KYTY_PM4_GET(buffer[0], DB_DEPTH_CONTROL, Z_WRITE_ENABLE) != 0;
|
||||
r.depth_bounds_enable = KYTY_PM4_GET(buffer[0], DB_DEPTH_CONTROL, DEPTH_BOUNDS_ENABLE) != 0;
|
||||
r.zfunc = KYTY_PM4_GET(buffer[0], DB_DEPTH_CONTROL, ZFUNC);
|
||||
r.backface_enable = KYTY_PM4_GET(buffer[0], DB_DEPTH_CONTROL, BACKFACE_ENABLE) != 0;
|
||||
r.stencilfunc = KYTY_PM4_GET(buffer[0], DB_DEPTH_CONTROL, STENCILFUNC);
|
||||
r.stencilfunc_bf = KYTY_PM4_GET(buffer[0], DB_DEPTH_CONTROL, STENCILFUNC_BF);
|
||||
r.color_writes_on_depth_fail_enable =
|
||||
KYTY_PM4_GET(buffer[0], DB_DEPTH_CONTROL, ENABLE_COLOR_WRITES_ON_DEPTH_FAIL) != 0;
|
||||
r.color_writes_on_depth_pass_disable =
|
||||
KYTY_PM4_GET(buffer[0], DB_DEPTH_CONTROL, DISABLE_COLOR_WRITES_ON_DEPTH_PASS) != 0;
|
||||
|
||||
cp.GetCtx().SetDepthControl(r);
|
||||
cp.GetCtx().SetDepthControl(DecodeDepthControl(buffer[0]));
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -879,24 +934,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetModeControl) {
|
||||
EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0016900);
|
||||
EXIT_NOT_IMPLEMENTED(cmd_offset != Pm4::PA_SU_SC_MODE_CNTL);
|
||||
|
||||
HW::ModeControl r;
|
||||
|
||||
r.cull_front = KYTY_PM4_GET(buffer[0], PA_SU_SC_MODE_CNTL, CULL_FRONT) != 0;
|
||||
r.cull_back = KYTY_PM4_GET(buffer[0], PA_SU_SC_MODE_CNTL, CULL_BACK) != 0;
|
||||
r.face = KYTY_PM4_GET(buffer[0], PA_SU_SC_MODE_CNTL, FACE) != 0;
|
||||
r.poly_mode = KYTY_PM4_GET(buffer[0], PA_SU_SC_MODE_CNTL, POLY_MODE);
|
||||
r.polymode_front_ptype = KYTY_PM4_GET(buffer[0], PA_SU_SC_MODE_CNTL, POLYMODE_FRONT_PTYPE);
|
||||
r.polymode_back_ptype = KYTY_PM4_GET(buffer[0], PA_SU_SC_MODE_CNTL, POLYMODE_BACK_PTYPE);
|
||||
r.poly_offset_front_enable =
|
||||
KYTY_PM4_GET(buffer[0], PA_SU_SC_MODE_CNTL, POLY_OFFSET_FRONT_ENABLE) != 0;
|
||||
r.poly_offset_back_enable =
|
||||
KYTY_PM4_GET(buffer[0], PA_SU_SC_MODE_CNTL, POLY_OFFSET_BACK_ENABLE) != 0;
|
||||
r.vtx_window_offset_enable =
|
||||
KYTY_PM4_GET(buffer[0], PA_SU_SC_MODE_CNTL, VTX_WINDOW_OFFSET_ENABLE) != 0;
|
||||
r.provoking_vtx_last = KYTY_PM4_GET(buffer[0], PA_SU_SC_MODE_CNTL, PROVOKING_VTX_LAST) != 0;
|
||||
r.persp_corr_dis = KYTY_PM4_GET(buffer[0], PA_SU_SC_MODE_CNTL, PERSP_CORR_DIS) != 0;
|
||||
|
||||
cp.GetCtx().SetModeControl(r);
|
||||
cp.GetCtx().SetModeControl(DecodeModeControl(buffer[0]));
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -962,19 +1000,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetRenderControl) {
|
||||
EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0016900);
|
||||
EXIT_NOT_IMPLEMENTED(cmd_offset != Pm4::DB_RENDER_CONTROL);
|
||||
|
||||
HW::RenderControl r;
|
||||
|
||||
r.depth_clear_enable = KYTY_PM4_GET(buffer[0], DB_RENDER_CONTROL, DEPTH_CLEAR_ENABLE) != 0;
|
||||
r.stencil_clear_enable = KYTY_PM4_GET(buffer[0], DB_RENDER_CONTROL, STENCIL_CLEAR_ENABLE) != 0;
|
||||
r.resummarize_enable = KYTY_PM4_GET(buffer[0], DB_RENDER_CONTROL, RESUMMARIZE_ENABLE) != 0;
|
||||
r.stencil_compress_disable =
|
||||
KYTY_PM4_GET(buffer[0], DB_RENDER_CONTROL, STENCIL_COMPRESS_DISABLE) != 0;
|
||||
r.depth_compress_disable =
|
||||
KYTY_PM4_GET(buffer[0], DB_RENDER_CONTROL, DEPTH_COMPRESS_DISABLE) != 0;
|
||||
r.copy_centroid = KYTY_PM4_GET(buffer[0], DB_RENDER_CONTROL, COPY_CENTROID) != 0;
|
||||
r.copy_sample = KYTY_PM4_GET(buffer[0], DB_RENDER_CONTROL, COPY_SAMPLE);
|
||||
|
||||
cp.GetCtx().SetRenderControl(r);
|
||||
cp.GetCtx().SetRenderControl(DecodeRenderControl(buffer[0]));
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1042,9 +1068,12 @@ KYTY_HW_CTX_PARSER(HwCtxSetRenderTarget) {
|
||||
// info.format = (buffer[4] >> 2u) & 0x1fu;
|
||||
// info.channel_type = (buffer[4] >> 8u) & 0x7u;
|
||||
// info.channel_order = (buffer[4] >> 11u) & 0x3u;
|
||||
info.format = KYTY_PM4_GET(buffer[4], CB_COLOR0_INFO, FORMAT);
|
||||
info.channel_type = KYTY_PM4_GET(buffer[4], CB_COLOR0_INFO, NUMBER_TYPE);
|
||||
info.channel_order = KYTY_PM4_GET(buffer[4], CB_COLOR0_INFO, COMP_SWAP);
|
||||
info.format =
|
||||
static_cast<Prospero::ChannelLayout>(KYTY_PM4_GET(buffer[4], CB_COLOR0_INFO, FORMAT));
|
||||
info.channel_type =
|
||||
static_cast<Prospero::ChannelType>(KYTY_PM4_GET(buffer[4], CB_COLOR0_INFO, NUMBER_TYPE));
|
||||
info.channel_order =
|
||||
static_cast<Prospero::ChannelOrder>(KYTY_PM4_GET(buffer[4], CB_COLOR0_INFO, COMP_SWAP));
|
||||
info.cmask_fast_clear_enable = KYTY_PM4_GET(buffer[4], CB_COLOR0_INFO, FAST_CLEAR) != 0;
|
||||
info.fmask_compression_enable = KYTY_PM4_GET(buffer[4], CB_COLOR0_INFO, COMPRESSION) != 0;
|
||||
info.blend_clamp = KYTY_PM4_GET(buffer[4], CB_COLOR0_INFO, BLEND_CLAMP) != 0;
|
||||
@@ -1066,10 +1095,12 @@ KYTY_HW_CTX_PARSER(HwCtxSetRenderTarget) {
|
||||
// attrib.num_fragments = (buffer[5] >> 15u) & 0x3u;
|
||||
attrib.force_dest_alpha_to_one =
|
||||
KYTY_PM4_GET(buffer[5], CB_COLOR0_ATTRIB, FORCE_DST_ALPHA_1) != 0;
|
||||
attrib.tile_mode = KYTY_PM4_GET(buffer[5], CB_COLOR0_ATTRIB, TILE_MODE_INDEX);
|
||||
attrib.fmask_tile_mode = KYTY_PM4_GET(buffer[5], CB_COLOR0_ATTRIB, FMASK_TILE_MODE_INDEX);
|
||||
attrib.num_samples = KYTY_PM4_GET(buffer[5], CB_COLOR0_ATTRIB, NUM_SAMPLES);
|
||||
attrib.num_fragments = KYTY_PM4_GET(buffer[5], CB_COLOR0_ATTRIB, NUM_FRAGMENTS);
|
||||
attrib.tile_mode =
|
||||
static_cast<Prospero::TileMode>(KYTY_PM4_GET(buffer[5], CB_COLOR0_ATTRIB, TILE_MODE_INDEX));
|
||||
attrib.fmask_tile_mode = static_cast<Prospero::TileMode>(
|
||||
KYTY_PM4_GET(buffer[5], CB_COLOR0_ATTRIB, FMASK_TILE_MODE_INDEX));
|
||||
attrib.num_samples = KYTY_PM4_GET(buffer[5], CB_COLOR0_ATTRIB, NUM_SAMPLES);
|
||||
attrib.num_fragments = KYTY_PM4_GET(buffer[5], CB_COLOR0_ATTRIB, NUM_FRAGMENTS);
|
||||
|
||||
// dcc.max_uncompressed_block_size = (buffer[6] >> 2u) & 0x3u;
|
||||
// dcc.max_compressed_block_size = (buffer[6] >> 5u) & 0x3u;
|
||||
@@ -1162,13 +1193,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetScanModeControl) {
|
||||
EXIT_NOT_IMPLEMENTED(cmd_id != 0xc0016900);
|
||||
EXIT_NOT_IMPLEMENTED(cmd_offset != Pm4::PA_SC_MODE_CNTL_0);
|
||||
|
||||
HW::ScanModeControl r;
|
||||
|
||||
r.msaa_enable = KYTY_PM4_GET(buffer[0], PA_SC_MODE_CNTL_0, MSAA_ENABLE) != 0;
|
||||
r.vport_scissor_enable = KYTY_PM4_GET(buffer[0], PA_SC_MODE_CNTL_0, VPORT_SCISSOR_ENABLE) != 0;
|
||||
r.line_stipple_enable = KYTY_PM4_GET(buffer[0], PA_SC_MODE_CNTL_0, LINE_STIPPLE_ENABLE) != 0;
|
||||
|
||||
cp.GetCtx().SetScanModeControl(r);
|
||||
cp.GetCtx().SetScanModeControl(DecodeScanModeControl(buffer[0]));
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1208,16 +1233,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetStencilControl) {
|
||||
EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0016900);
|
||||
EXIT_NOT_IMPLEMENTED(cmd_offset != Pm4::DB_STENCIL_CONTROL);
|
||||
|
||||
HW::StencilControl r;
|
||||
|
||||
r.stencil_fail = KYTY_PM4_GET(buffer[0], DB_STENCIL_CONTROL, STENCILFAIL);
|
||||
r.stencil_zpass = KYTY_PM4_GET(buffer[0], DB_STENCIL_CONTROL, STENCILZPASS);
|
||||
r.stencil_zfail = KYTY_PM4_GET(buffer[0], DB_STENCIL_CONTROL, STENCILZFAIL);
|
||||
r.stencil_fail_bf = KYTY_PM4_GET(buffer[0], DB_STENCIL_CONTROL, STENCILFAIL_BF);
|
||||
r.stencil_zpass_bf = KYTY_PM4_GET(buffer[0], DB_STENCIL_CONTROL, STENCILZPASS_BF);
|
||||
r.stencil_zfail_bf = KYTY_PM4_GET(buffer[0], DB_STENCIL_CONTROL, STENCILZFAIL_BF);
|
||||
|
||||
cp.GetCtx().SetStencilControl(r);
|
||||
cp.GetCtx().SetStencilControl(DecodeStencilControl(buffer[0]));
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1568,7 +1584,7 @@ KYTY_HW_UC_PARSER(HwUcSetPrimitiveType) {
|
||||
|
||||
uint32_t prim_type = KYTY_PM4_GET(buffer[0], VGT_PRIMITIVE_TYPE, PRIM_TYPE);
|
||||
|
||||
cp.GetUcfg().SetPrimitiveType(prim_type);
|
||||
cp.GetUcfg().SetPrimitiveType(static_cast<Prospero::PrimitiveType>(prim_type));
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -3106,9 +3122,12 @@ void GraphicsInitJmpTablesCxIndirect() {
|
||||
g_hw_ctx_indirect_func[cmd_offset] = [](KYTY_HW_CTX_INDIRECT_ARGS) {
|
||||
uint32_t slot = (cmd_offset - Pm4::CB_COLOR0_INFO) / 15;
|
||||
HW::ColorInfo info;
|
||||
info.format = KYTY_PM4_GET(value, CB_COLOR0_INFO, FORMAT);
|
||||
info.channel_type = KYTY_PM4_GET(value, CB_COLOR0_INFO, NUMBER_TYPE);
|
||||
info.channel_order = KYTY_PM4_GET(value, CB_COLOR0_INFO, COMP_SWAP);
|
||||
info.format =
|
||||
static_cast<Prospero::ChannelLayout>(KYTY_PM4_GET(value, CB_COLOR0_INFO, FORMAT));
|
||||
info.channel_type = static_cast<Prospero::ChannelType>(
|
||||
KYTY_PM4_GET(value, CB_COLOR0_INFO, NUMBER_TYPE));
|
||||
info.channel_order =
|
||||
static_cast<Prospero::ChannelOrder>(KYTY_PM4_GET(value, CB_COLOR0_INFO, COMP_SWAP));
|
||||
info.cmask_fast_clear_enable = KYTY_PM4_GET(value, CB_COLOR0_INFO, FAST_CLEAR) != 0;
|
||||
info.fmask_compression_enable = KYTY_PM4_GET(value, CB_COLOR0_INFO, COMPRESSION) != 0;
|
||||
info.blend_clamp = KYTY_PM4_GET(value, CB_COLOR0_INFO, BLEND_CLAMP) != 0;
|
||||
@@ -3133,10 +3152,12 @@ void GraphicsInitJmpTablesCxIndirect() {
|
||||
HW::ColorAttrib attrib;
|
||||
attrib.force_dest_alpha_to_one =
|
||||
KYTY_PM4_GET(value, CB_COLOR0_ATTRIB, FORCE_DST_ALPHA_1) != 0;
|
||||
attrib.tile_mode = KYTY_PM4_GET(value, CB_COLOR0_ATTRIB, TILE_MODE_INDEX);
|
||||
attrib.fmask_tile_mode = KYTY_PM4_GET(value, CB_COLOR0_ATTRIB, FMASK_TILE_MODE_INDEX);
|
||||
attrib.num_samples = KYTY_PM4_GET(value, CB_COLOR0_ATTRIB, NUM_SAMPLES);
|
||||
attrib.num_fragments = KYTY_PM4_GET(value, CB_COLOR0_ATTRIB, NUM_FRAGMENTS);
|
||||
attrib.tile_mode = static_cast<Prospero::TileMode>(
|
||||
KYTY_PM4_GET(value, CB_COLOR0_ATTRIB, TILE_MODE_INDEX));
|
||||
attrib.fmask_tile_mode = static_cast<Prospero::TileMode>(
|
||||
KYTY_PM4_GET(value, CB_COLOR0_ATTRIB, FMASK_TILE_MODE_INDEX));
|
||||
attrib.num_samples = KYTY_PM4_GET(value, CB_COLOR0_ATTRIB, NUM_SAMPLES);
|
||||
attrib.num_fragments = KYTY_PM4_GET(value, CB_COLOR0_ATTRIB, NUM_FRAGMENTS);
|
||||
cp.GetCtx().SetColorAttrib(slot, attrib);
|
||||
};
|
||||
}
|
||||
@@ -3290,8 +3311,9 @@ void GraphicsInitJmpTablesCxIndirect() {
|
||||
g_hw_ctx_indirect_func[cmd_offset] = [](KYTY_HW_CTX_INDIRECT_ARGS) {
|
||||
uint32_t slot = (cmd_offset - Pm4::CB_COLOR0_ATTRIB3);
|
||||
HW::ColorAttrib3 attrib3;
|
||||
attrib3.depth = KYTY_PM4_GET(value, CB_COLOR0_ATTRIB3, MIP0_DEPTH);
|
||||
attrib3.tile_mode = KYTY_PM4_GET(value, CB_COLOR0_ATTRIB3, COLOR_SW_MODE);
|
||||
attrib3.depth = KYTY_PM4_GET(value, CB_COLOR0_ATTRIB3, MIP0_DEPTH);
|
||||
attrib3.tile_mode = static_cast<Prospero::TileMode>(
|
||||
KYTY_PM4_GET(value, CB_COLOR0_ATTRIB3, COLOR_SW_MODE));
|
||||
attrib3.dimension = KYTY_PM4_GET(value, CB_COLOR0_ATTRIB3, RESOURCE_TYPE);
|
||||
attrib3.cmask_pipe_aligned = KYTY_PM4_GET(value, CB_COLOR0_ATTRIB3, CMASK_PIPE_ALIGNED);
|
||||
attrib3.dcc_pipe_aligned = KYTY_PM4_GET(value, CB_COLOR0_ATTRIB3, DCC_PIPE_ALIGNED);
|
||||
@@ -3691,39 +3713,12 @@ void GraphicsInitJmpTablesCxIndirect() {
|
||||
for (uint32_t slot = 0; slot < 8; slot++) {
|
||||
g_hw_ctx_indirect_func[Pm4::CB_BLEND0_CONTROL + slot] = [](KYTY_HW_CTX_INDIRECT_ARGS) {
|
||||
uint32_t param = cmd_offset - Pm4::CB_BLEND0_CONTROL;
|
||||
|
||||
HW::BlendControl r;
|
||||
r.color_srcblend = KYTY_PM4_GET(value, CB_BLEND0_CONTROL, COLOR_SRCBLEND);
|
||||
r.color_comb_fcn = KYTY_PM4_GET(value, CB_BLEND0_CONTROL, COLOR_COMB_FCN);
|
||||
r.color_destblend = KYTY_PM4_GET(value, CB_BLEND0_CONTROL, COLOR_DESTBLEND);
|
||||
r.alpha_srcblend = KYTY_PM4_GET(value, CB_BLEND0_CONTROL, ALPHA_SRCBLEND);
|
||||
r.alpha_comb_fcn = KYTY_PM4_GET(value, CB_BLEND0_CONTROL, ALPHA_COMB_FCN);
|
||||
r.alpha_destblend = KYTY_PM4_GET(value, CB_BLEND0_CONTROL, ALPHA_DESTBLEND);
|
||||
r.separate_alpha_blend =
|
||||
KYTY_PM4_GET(value, CB_BLEND0_CONTROL, SEPARATE_ALPHA_BLEND) != 0;
|
||||
r.enable = KYTY_PM4_GET(value, CB_BLEND0_CONTROL, ENABLE) != 0;
|
||||
|
||||
cp.GetCtx().SetBlendControl(param, r);
|
||||
cp.GetCtx().SetBlendControl(param, DecodeBlendControl(value));
|
||||
};
|
||||
}
|
||||
|
||||
g_hw_ctx_indirect_func[Pm4::PA_SU_SC_MODE_CNTL] = [](KYTY_HW_CTX_INDIRECT_ARGS) {
|
||||
HW::ModeControl r;
|
||||
r.cull_front = KYTY_PM4_GET(value, PA_SU_SC_MODE_CNTL, CULL_FRONT) != 0;
|
||||
r.cull_back = KYTY_PM4_GET(value, PA_SU_SC_MODE_CNTL, CULL_BACK) != 0;
|
||||
r.face = KYTY_PM4_GET(value, PA_SU_SC_MODE_CNTL, FACE) != 0;
|
||||
r.poly_mode = KYTY_PM4_GET(value, PA_SU_SC_MODE_CNTL, POLY_MODE);
|
||||
r.polymode_front_ptype = KYTY_PM4_GET(value, PA_SU_SC_MODE_CNTL, POLYMODE_FRONT_PTYPE);
|
||||
r.polymode_back_ptype = KYTY_PM4_GET(value, PA_SU_SC_MODE_CNTL, POLYMODE_BACK_PTYPE);
|
||||
r.poly_offset_front_enable =
|
||||
KYTY_PM4_GET(value, PA_SU_SC_MODE_CNTL, POLY_OFFSET_FRONT_ENABLE) != 0;
|
||||
r.poly_offset_back_enable =
|
||||
KYTY_PM4_GET(value, PA_SU_SC_MODE_CNTL, POLY_OFFSET_BACK_ENABLE) != 0;
|
||||
r.vtx_window_offset_enable =
|
||||
KYTY_PM4_GET(value, PA_SU_SC_MODE_CNTL, VTX_WINDOW_OFFSET_ENABLE) != 0;
|
||||
r.provoking_vtx_last = KYTY_PM4_GET(value, PA_SU_SC_MODE_CNTL, PROVOKING_VTX_LAST) != 0;
|
||||
r.persp_corr_dis = KYTY_PM4_GET(value, PA_SU_SC_MODE_CNTL, PERSP_CORR_DIS) != 0;
|
||||
cp.GetCtx().SetModeControl(r);
|
||||
cp.GetCtx().SetModeControl(DecodeModeControl(value));
|
||||
};
|
||||
|
||||
g_hw_ctx_indirect_func[Pm4::PA_SU_POLY_OFFSET_DB_FMT_CNTL] = [](KYTY_HW_CTX_INDIRECT_ARGS) {
|
||||
@@ -3891,28 +3886,11 @@ void GraphicsInitJmpTablesCxIndirect() {
|
||||
};
|
||||
|
||||
g_hw_ctx_indirect_func[Pm4::DB_STENCIL_CONTROL] = [](KYTY_HW_CTX_INDIRECT_ARGS) {
|
||||
HW::StencilControl r;
|
||||
r.stencil_fail = KYTY_PM4_GET(value, DB_STENCIL_CONTROL, STENCILFAIL);
|
||||
r.stencil_zpass = KYTY_PM4_GET(value, DB_STENCIL_CONTROL, STENCILZPASS);
|
||||
r.stencil_zfail = KYTY_PM4_GET(value, DB_STENCIL_CONTROL, STENCILZFAIL);
|
||||
r.stencil_fail_bf = KYTY_PM4_GET(value, DB_STENCIL_CONTROL, STENCILFAIL_BF);
|
||||
r.stencil_zpass_bf = KYTY_PM4_GET(value, DB_STENCIL_CONTROL, STENCILZPASS_BF);
|
||||
r.stencil_zfail_bf = KYTY_PM4_GET(value, DB_STENCIL_CONTROL, STENCILZFAIL_BF);
|
||||
cp.GetCtx().SetStencilControl(r);
|
||||
cp.GetCtx().SetStencilControl(DecodeStencilControl(value));
|
||||
};
|
||||
|
||||
g_hw_ctx_indirect_func[Pm4::DB_RENDER_CONTROL] = [](KYTY_HW_CTX_INDIRECT_ARGS) {
|
||||
HW::RenderControl r;
|
||||
r.depth_clear_enable = KYTY_PM4_GET(value, DB_RENDER_CONTROL, DEPTH_CLEAR_ENABLE) != 0;
|
||||
r.stencil_clear_enable = KYTY_PM4_GET(value, DB_RENDER_CONTROL, STENCIL_CLEAR_ENABLE) != 0;
|
||||
r.resummarize_enable = KYTY_PM4_GET(value, DB_RENDER_CONTROL, RESUMMARIZE_ENABLE) != 0;
|
||||
r.stencil_compress_disable =
|
||||
KYTY_PM4_GET(value, DB_RENDER_CONTROL, STENCIL_COMPRESS_DISABLE) != 0;
|
||||
r.depth_compress_disable =
|
||||
KYTY_PM4_GET(value, DB_RENDER_CONTROL, DEPTH_COMPRESS_DISABLE) != 0;
|
||||
r.copy_centroid = KYTY_PM4_GET(value, DB_RENDER_CONTROL, COPY_CENTROID) != 0;
|
||||
r.copy_sample = KYTY_PM4_GET(value, DB_RENDER_CONTROL, COPY_SAMPLE);
|
||||
cp.GetCtx().SetRenderControl(r);
|
||||
cp.GetCtx().SetRenderControl(DecodeRenderControl(value));
|
||||
};
|
||||
|
||||
g_hw_ctx_indirect_func[Pm4::DB_STENCILREFMASK] = [](KYTY_HW_CTX_INDIRECT_ARGS) {
|
||||
@@ -3934,23 +3912,7 @@ void GraphicsInitJmpTablesCxIndirect() {
|
||||
};
|
||||
|
||||
g_hw_ctx_indirect_func[Pm4::PA_CL_CLIP_CNTL] = [](KYTY_HW_CTX_INDIRECT_ARGS) {
|
||||
HW::ClipControl r;
|
||||
r.user_clip_planes = KYTY_PM4_GET(value, PA_CL_CLIP_CNTL, UCP_ENA);
|
||||
r.user_clip_plane_mode = KYTY_PM4_GET(value, PA_CL_CLIP_CNTL, PS_UCP_MODE);
|
||||
r.dx_clip_space = KYTY_PM4_GET(value, PA_CL_CLIP_CNTL, DX_CLIP_SPACE_DEF) != 0;
|
||||
r.vertex_kill_any = KYTY_PM4_GET(value, PA_CL_CLIP_CNTL, VTX_KILL_OR) != 0;
|
||||
r.min_z_clip_disable = KYTY_PM4_GET(value, PA_CL_CLIP_CNTL, ZCLIP_NEAR_DISABLE) != 0;
|
||||
r.max_z_clip_disable = KYTY_PM4_GET(value, PA_CL_CLIP_CNTL, ZCLIP_FAR_DISABLE) != 0;
|
||||
r.user_clip_plane_negate_y = KYTY_PM4_GET(value, PA_CL_CLIP_CNTL, PS_UCP_Y_SCALE_NEG) != 0;
|
||||
r.clip_disable = KYTY_PM4_GET(value, PA_CL_CLIP_CNTL, CLIP_DISABLE) != 0;
|
||||
r.user_clip_plane_cull_only = KYTY_PM4_GET(value, PA_CL_CLIP_CNTL, UCP_CULL_ONLY_ENA) != 0;
|
||||
r.cull_on_clipping_error_disable =
|
||||
KYTY_PM4_GET(value, PA_CL_CLIP_CNTL, DIS_CLIP_ERR_DETECT) != 0;
|
||||
r.linear_attribute_clip_enable =
|
||||
KYTY_PM4_GET(value, PA_CL_CLIP_CNTL, DX_LINEAR_ATTR_CLIP_ENA) != 0;
|
||||
r.force_viewport_index_from_vs_enable =
|
||||
KYTY_PM4_GET(value, PA_CL_CLIP_CNTL, VTE_VPORT_PROVOKE_DISABLE) != 0;
|
||||
cp.GetCtx().SetClipControl(r);
|
||||
cp.GetCtx().SetClipControl(DecodeClipControl(value));
|
||||
};
|
||||
|
||||
g_hw_ctx_indirect_func[Pm4::PA_SU_LINE_CNTL] = [](KYTY_HW_CTX_INDIRECT_ARGS) {
|
||||
@@ -3978,11 +3940,7 @@ void GraphicsInitJmpTablesCxIndirect() {
|
||||
};
|
||||
|
||||
g_hw_ctx_indirect_func[Pm4::PA_SC_MODE_CNTL_0] = [](KYTY_HW_CTX_INDIRECT_ARGS) {
|
||||
HW::ScanModeControl r;
|
||||
r.msaa_enable = KYTY_PM4_GET(value, PA_SC_MODE_CNTL_0, MSAA_ENABLE) != 0;
|
||||
r.vport_scissor_enable = KYTY_PM4_GET(value, PA_SC_MODE_CNTL_0, VPORT_SCISSOR_ENABLE) != 0;
|
||||
r.line_stipple_enable = KYTY_PM4_GET(value, PA_SC_MODE_CNTL_0, LINE_STIPPLE_ENABLE) != 0;
|
||||
cp.GetCtx().SetScanModeControl(r);
|
||||
cp.GetCtx().SetScanModeControl(DecodeScanModeControl(value));
|
||||
};
|
||||
g_hw_ctx_indirect_func[Pm4::PA_SC_MODE_CNTL_1] = [](KYTY_HW_CTX_INDIRECT_ARGS) {
|
||||
HwCtxIgnoreScanModeControl1(value);
|
||||
@@ -4041,27 +3999,11 @@ void GraphicsInitJmpTablesCxIndirect() {
|
||||
HwCtxIgnoreAlphaToMaskRegister(value);
|
||||
};
|
||||
g_hw_ctx_indirect_func[Pm4::CB_COLOR_CONTROL] = [](KYTY_HW_CTX_INDIRECT_ARGS) {
|
||||
HW::ColorControl r;
|
||||
r.mode = KYTY_PM4_GET(value, CB_COLOR_CONTROL, MODE);
|
||||
r.op = KYTY_PM4_GET(value, CB_COLOR_CONTROL, ROP3);
|
||||
cp.GetCtx().SetColorControl(r);
|
||||
cp.GetCtx().SetColorControl(DecodeColorControl(value));
|
||||
};
|
||||
|
||||
g_hw_ctx_indirect_func[Pm4::DB_DEPTH_CONTROL] = [](KYTY_HW_CTX_INDIRECT_ARGS) {
|
||||
HW::DepthControl r;
|
||||
r.stencil_enable = KYTY_PM4_GET(value, DB_DEPTH_CONTROL, STENCIL_ENABLE) != 0;
|
||||
r.z_enable = KYTY_PM4_GET(value, DB_DEPTH_CONTROL, Z_ENABLE) != 0;
|
||||
r.z_write_enable = KYTY_PM4_GET(value, DB_DEPTH_CONTROL, Z_WRITE_ENABLE) != 0;
|
||||
r.depth_bounds_enable = KYTY_PM4_GET(value, DB_DEPTH_CONTROL, DEPTH_BOUNDS_ENABLE) != 0;
|
||||
r.zfunc = KYTY_PM4_GET(value, DB_DEPTH_CONTROL, ZFUNC);
|
||||
r.backface_enable = KYTY_PM4_GET(value, DB_DEPTH_CONTROL, BACKFACE_ENABLE) != 0;
|
||||
r.stencilfunc = KYTY_PM4_GET(value, DB_DEPTH_CONTROL, STENCILFUNC);
|
||||
r.stencilfunc_bf = KYTY_PM4_GET(value, DB_DEPTH_CONTROL, STENCILFUNC_BF);
|
||||
r.color_writes_on_depth_fail_enable =
|
||||
KYTY_PM4_GET(value, DB_DEPTH_CONTROL, ENABLE_COLOR_WRITES_ON_DEPTH_FAIL) != 0;
|
||||
r.color_writes_on_depth_pass_disable =
|
||||
KYTY_PM4_GET(value, DB_DEPTH_CONTROL, DISABLE_COLOR_WRITES_ON_DEPTH_PASS) != 0;
|
||||
cp.GetCtx().SetDepthControl(r);
|
||||
cp.GetCtx().SetDepthControl(DecodeDepthControl(value));
|
||||
};
|
||||
|
||||
g_hw_ctx_indirect_func[Pm4::DB_EQAA] = [](KYTY_HW_CTX_INDIRECT_ARGS) {
|
||||
@@ -4467,7 +4409,7 @@ void GraphicsInitJmpTablesUcIndirect() {
|
||||
|
||||
g_hw_uc_indirect_func[Pm4::VGT_PRIMITIVE_TYPE] = [](KYTY_HW_UC_INDIRECT_ARGS) {
|
||||
uint32_t prim_type = KYTY_PM4_GET(value, VGT_PRIMITIVE_TYPE, PRIM_TYPE);
|
||||
cp.GetUcfg().SetPrimitiveType(prim_type);
|
||||
cp.GetUcfg().SetPrimitiveType(static_cast<Prospero::PrimitiveType>(prim_type));
|
||||
};
|
||||
g_hw_uc_indirect_func[Pm4::VGT_INDEX_TYPE] = [](KYTY_HW_UC_INDIRECT_ARGS) {
|
||||
cp.SetIndexType(value & 0x3u);
|
||||
|
||||
@@ -3,15 +3,8 @@
|
||||
|
||||
#include "common/common.h"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace Libs::Graphics::Prospero {
|
||||
|
||||
template <typename T>
|
||||
constexpr auto GpuEnumValue(T value) {
|
||||
return static_cast<std::underlying_type_t<T>>(value);
|
||||
}
|
||||
|
||||
enum class PrimitiveType : uint32_t {
|
||||
kNone = 0,
|
||||
kPointList = 1,
|
||||
@@ -115,32 +108,52 @@ enum class ChannelOrder : uint32_t {
|
||||
kAltReversed = 3,
|
||||
};
|
||||
|
||||
// Maps a shader's logical RGBA export to the host color-attachment components. Two bits per
|
||||
// component keep this cheap to carry in shader and pipeline keys.
|
||||
// Selects the logical shader component written to each physical color-attachment component.
|
||||
// Two bits per component keep this cheap to carry in shader and pipeline keys.
|
||||
struct ColorComponentMapping {
|
||||
uint8_t packed = 0xe4u; // RGBA: 0, 1, 2, 3
|
||||
static constexpr uint8_t kIdentity = 0xe4u;
|
||||
|
||||
uint8_t packed = kIdentity;
|
||||
|
||||
[[nodiscard]] constexpr uint32_t Map(uint32_t component) const {
|
||||
return component < 4u ? (packed >> (component * 2u)) & 0x3u : component;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr uint32_t ApplyMask(uint32_t mask) const {
|
||||
[[nodiscard]] constexpr uint32_t ApplyMask(uint32_t logical_mask) const {
|
||||
uint32_t mapped = 0;
|
||||
for (uint32_t component = 0; component < 4u; component++) {
|
||||
mapped |= ((mask >> component) & 1u) << Map(component);
|
||||
for (uint32_t physical_component = 0; physical_component < 4u; physical_component++) {
|
||||
mapped |= ((logical_mask >> Map(physical_component)) & 1u) << physical_component;
|
||||
}
|
||||
return mapped;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool IsIdentity() const { return packed == 0xe4u; }
|
||||
// This mapping selects an intermediate component; next selects the final logical component.
|
||||
[[nodiscard]] constexpr ColorComponentMapping Then(ColorComponentMapping next) const {
|
||||
ColorComponentMapping result {0u};
|
||||
for (uint32_t physical_component = 0; physical_component < 4u; physical_component++) {
|
||||
result.packed |= static_cast<uint8_t>(next.Map(Map(physical_component))
|
||||
<< (physical_component * 2u));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool IsIdentity() const { return packed == kIdentity; }
|
||||
|
||||
bool operator==(const ColorComponentMapping&) const = default;
|
||||
};
|
||||
|
||||
static_assert(sizeof(ColorComponentMapping) == sizeof(uint8_t));
|
||||
|
||||
inline constexpr ColorComponentMapping ColorMappingAbgr {0x1bu}; // 3, 2, 1, 0
|
||||
inline constexpr ColorComponentMapping ColorMappingRgba {ColorComponentMapping::kIdentity};
|
||||
inline constexpr ColorComponentMapping ColorMappingGr {0xe1u}; // 1, 0, 2, 3
|
||||
inline constexpr ColorComponentMapping ColorMappingRabg {0x6cu}; // 0, 3, 2, 1
|
||||
inline constexpr ColorComponentMapping ColorMappingRgab {0xb4u}; // 0, 1, 3, 2
|
||||
inline constexpr ColorComponentMapping ColorMappingBgra {0xc6u}; // 2, 1, 0, 3
|
||||
inline constexpr ColorComponentMapping ColorMappingAbgr {0x1bu}; // 3, 2, 1, 0
|
||||
inline constexpr ColorComponentMapping ColorMappingAgba {0x27u}; // 3, 1, 2, 0
|
||||
inline constexpr ColorComponentMapping ColorMappingArbg {0x63u}; // 3, 0, 2, 1
|
||||
inline constexpr ColorComponentMapping ColorMappingAgbr {0x87u}; // 3, 1, 0, 2
|
||||
inline constexpr ColorComponentMapping ColorMappingArgb {0x93u}; // 3, 0, 1, 2
|
||||
|
||||
enum class DepthFormat : uint32_t {
|
||||
kInvalid = 0,
|
||||
@@ -388,9 +401,11 @@ enum class BufferFormat : uint32_t {
|
||||
k8Srgb = 128,
|
||||
k8_8Srgb = 129,
|
||||
k8_8_8_8Srgb = 130,
|
||||
k10_10_10_2Float = 131,
|
||||
k9_9_9_5Float = 132,
|
||||
k5_6_5UNorm = 133,
|
||||
k5_5_5_1UNorm = 134,
|
||||
k1_5_5_5UNorm = 135,
|
||||
k4_4_4_4UNorm = 136,
|
||||
kFmask8_S4_F4 = 161,
|
||||
kBc1UNorm = 169,
|
||||
|
||||
@@ -3,129 +3,216 @@
|
||||
#include "graphics/guest_gpu/gpu_defs.h"
|
||||
|
||||
#include <array>
|
||||
#include <bit>
|
||||
|
||||
namespace Libs::Graphics::Prospero {
|
||||
namespace {
|
||||
|
||||
struct FormatInfo {
|
||||
uint32_t format;
|
||||
uint32_t bytes_per_element;
|
||||
uint32_t block_compressed_bytes_per_block;
|
||||
uint32_t render_target_bytes_per_element;
|
||||
bool supported_sampled_texture_format;
|
||||
bool unsigned_integer_texture_format;
|
||||
BufferFormat format;
|
||||
uint32_t bytes_per_element;
|
||||
uint32_t block_compressed_bytes_per_block;
|
||||
uint32_t render_target_bytes_per_element;
|
||||
bool supported_sampled_texture_format;
|
||||
bool unsigned_integer_texture_format;
|
||||
};
|
||||
|
||||
constexpr FormatInfo kFormatInfo[] = {
|
||||
{GpuEnumValue(BufferFormat::k8UNorm), 1, 0, 1, true, false},
|
||||
{GpuEnumValue(BufferFormat::k8SNorm), 0, 0, 1, false, false},
|
||||
{GpuEnumValue(BufferFormat::k8UInt), 1, 0, 1, true, true},
|
||||
{GpuEnumValue(BufferFormat::k16UNorm), 2, 0, 2, true, false},
|
||||
{GpuEnumValue(BufferFormat::k16SNorm), 2, 0, 2, true, false},
|
||||
{GpuEnumValue(BufferFormat::k16UInt), 2, 0, 2, true, true},
|
||||
{GpuEnumValue(BufferFormat::k16SInt), 2, 0, 2, false, false},
|
||||
{GpuEnumValue(BufferFormat::k16Float), 2, 0, 2, true, false},
|
||||
{GpuEnumValue(BufferFormat::k8_8UNorm), 2, 0, 2, true, false},
|
||||
{GpuEnumValue(BufferFormat::k8_8SNorm), 2, 0, 2, true, false},
|
||||
{GpuEnumValue(BufferFormat::k8_8UInt), 2, 0, 2, true, true},
|
||||
{GpuEnumValue(BufferFormat::k8_8SInt), 2, 0, 2, false, false},
|
||||
{GpuEnumValue(BufferFormat::k32UInt), 4, 0, 4, true, true},
|
||||
{GpuEnumValue(BufferFormat::k32SInt), 4, 0, 4, false, false},
|
||||
{GpuEnumValue(BufferFormat::k32Float), 4, 0, 4, true, false},
|
||||
{GpuEnumValue(BufferFormat::k16_16UNorm), 4, 0, 4, true, false},
|
||||
{GpuEnumValue(BufferFormat::k16_16SNorm), 4, 0, 4, true, false},
|
||||
{GpuEnumValue(BufferFormat::k16_16UInt), 4, 0, 4, true, true},
|
||||
{GpuEnumValue(BufferFormat::k16_16SInt), 4, 0, 4, false, false},
|
||||
{GpuEnumValue(BufferFormat::k16_16Float), 4, 0, 4, true, false},
|
||||
{GpuEnumValue(BufferFormat::k11_11_10Float), 4, 0, 4, true, false},
|
||||
{GpuEnumValue(BufferFormat::k10_10_10_2UNorm), 4, 0, 4, true, false},
|
||||
{GpuEnumValue(BufferFormat::k10_10_10_2UInt), 4, 0, 4, true, true},
|
||||
{GpuEnumValue(BufferFormat::k8_8_8_8UNorm), 4, 0, 4, true, false},
|
||||
{GpuEnumValue(BufferFormat::k8_8_8_8SNorm), 4, 0, 4, true, false},
|
||||
{GpuEnumValue(BufferFormat::k8_8_8_8UInt), 4, 0, 4, true, true},
|
||||
{GpuEnumValue(BufferFormat::k8_8_8_8SInt), 4, 0, 4, false, false},
|
||||
{GpuEnumValue(BufferFormat::k32_32UInt), 8, 0, 8, true, true},
|
||||
{GpuEnumValue(BufferFormat::k32_32SInt), 8, 0, 8, false, false},
|
||||
{GpuEnumValue(BufferFormat::k32_32Float), 8, 0, 8, true, false},
|
||||
{GpuEnumValue(BufferFormat::k16_16_16_16UNorm), 8, 0, 8, true, false},
|
||||
{GpuEnumValue(BufferFormat::k16_16_16_16SNorm), 8, 0, 8, true, false},
|
||||
{GpuEnumValue(BufferFormat::k16_16_16_16UInt), 8, 0, 8, true, true},
|
||||
{GpuEnumValue(BufferFormat::k16_16_16_16SInt), 8, 0, 8, false, false},
|
||||
{GpuEnumValue(BufferFormat::k16_16_16_16Float), 8, 0, 8, true, false},
|
||||
{GpuEnumValue(BufferFormat::k32_32_32UInt), 12, 0, 12, true, true},
|
||||
{GpuEnumValue(BufferFormat::k32_32_32SInt), 12, 0, 12, false, false},
|
||||
{GpuEnumValue(BufferFormat::k32_32_32Float), 12, 0, 12, true, false},
|
||||
{GpuEnumValue(BufferFormat::k32_32_32_32UInt), 16, 0, 16, true, true},
|
||||
{GpuEnumValue(BufferFormat::k32_32_32_32SInt), 16, 0, 16, false, false},
|
||||
{GpuEnumValue(BufferFormat::k32_32_32_32Float), 16, 0, 16, true, false},
|
||||
{GpuEnumValue(BufferFormat::k8Srgb), 1, 0, 0, true, false},
|
||||
{GpuEnumValue(BufferFormat::k8_8Srgb), 2, 0, 0, true, false},
|
||||
{GpuEnumValue(BufferFormat::k8_8_8_8Srgb), 4, 0, 4, true, false},
|
||||
{GpuEnumValue(BufferFormat::k9_9_9_5Float), 4, 0, 0, true, false},
|
||||
{GpuEnumValue(BufferFormat::k5_6_5UNorm), 2, 0, 2, true, false},
|
||||
{GpuEnumValue(BufferFormat::k5_5_5_1UNorm), 2, 0, 2, true, false},
|
||||
{GpuEnumValue(BufferFormat::k4_4_4_4UNorm), 2, 0, 2, true, false},
|
||||
{GpuEnumValue(BufferFormat::kFmask8_S4_F4), 1, 0, 1, true, false},
|
||||
{GpuEnumValue(BufferFormat::kBc1UNorm), 0, 8, 0, true, false},
|
||||
{GpuEnumValue(BufferFormat::kBc1Srgb), 0, 8, 0, true, false},
|
||||
{GpuEnumValue(BufferFormat::kBc2UNorm), 0, 16, 0, true, false},
|
||||
{GpuEnumValue(BufferFormat::kBc2Srgb), 0, 16, 0, true, false},
|
||||
{GpuEnumValue(BufferFormat::kBc3UNorm), 0, 16, 0, true, false},
|
||||
{GpuEnumValue(BufferFormat::kBc3Srgb), 0, 16, 0, true, false},
|
||||
{GpuEnumValue(BufferFormat::kBc4UNorm), 0, 8, 0, true, false},
|
||||
{GpuEnumValue(BufferFormat::kBc4SNorm), 0, 8, 0, true, false},
|
||||
{GpuEnumValue(BufferFormat::kBc5UNorm), 0, 16, 0, true, false},
|
||||
{GpuEnumValue(BufferFormat::kBc5SNorm), 0, 16, 0, true, false},
|
||||
{GpuEnumValue(BufferFormat::kBc6UFloat), 0, 16, 0, true, false},
|
||||
{GpuEnumValue(BufferFormat::kBc6SFloat), 0, 16, 0, true, false},
|
||||
{GpuEnumValue(BufferFormat::kBc7UNorm), 0, 16, 0, true, false},
|
||||
{GpuEnumValue(BufferFormat::kBc7Srgb), 0, 16, 0, true, false},
|
||||
{BufferFormat::k8UNorm, 1, 0, 1, true, false},
|
||||
{BufferFormat::k8SNorm, 0, 0, 1, false, false},
|
||||
{BufferFormat::k8UInt, 1, 0, 1, true, true},
|
||||
{BufferFormat::k16UNorm, 2, 0, 2, true, false},
|
||||
{BufferFormat::k16SNorm, 2, 0, 2, true, false},
|
||||
{BufferFormat::k16UInt, 2, 0, 2, true, true},
|
||||
{BufferFormat::k16SInt, 2, 0, 2, false, false},
|
||||
{BufferFormat::k16Float, 2, 0, 2, true, false},
|
||||
{BufferFormat::k8_8UNorm, 2, 0, 2, true, false},
|
||||
{BufferFormat::k8_8SNorm, 2, 0, 2, true, false},
|
||||
{BufferFormat::k8_8UInt, 2, 0, 2, true, true},
|
||||
{BufferFormat::k8_8SInt, 2, 0, 2, false, false},
|
||||
{BufferFormat::k32UInt, 4, 0, 4, true, true},
|
||||
{BufferFormat::k32SInt, 4, 0, 4, false, false},
|
||||
{BufferFormat::k32Float, 4, 0, 4, true, false},
|
||||
{BufferFormat::k16_16UNorm, 4, 0, 4, true, false},
|
||||
{BufferFormat::k16_16SNorm, 4, 0, 4, true, false},
|
||||
{BufferFormat::k16_16UInt, 4, 0, 4, true, true},
|
||||
{BufferFormat::k16_16SInt, 4, 0, 4, false, false},
|
||||
{BufferFormat::k16_16Float, 4, 0, 4, true, false},
|
||||
{BufferFormat::k11_11_10Float, 4, 0, 4, true, false},
|
||||
{BufferFormat::k10_10_10_2UNorm, 4, 0, 4, true, false},
|
||||
{BufferFormat::k10_10_10_2UInt, 4, 0, 4, true, true},
|
||||
{BufferFormat::k8_8_8_8UNorm, 4, 0, 4, true, false},
|
||||
{BufferFormat::k8_8_8_8SNorm, 4, 0, 4, true, false},
|
||||
{BufferFormat::k8_8_8_8UInt, 4, 0, 4, true, true},
|
||||
{BufferFormat::k8_8_8_8SInt, 4, 0, 4, false, false},
|
||||
{BufferFormat::k32_32UInt, 8, 0, 8, true, true},
|
||||
{BufferFormat::k32_32SInt, 8, 0, 8, false, false},
|
||||
{BufferFormat::k32_32Float, 8, 0, 8, true, false},
|
||||
{BufferFormat::k16_16_16_16UNorm, 8, 0, 8, true, false},
|
||||
{BufferFormat::k16_16_16_16SNorm, 8, 0, 8, true, false},
|
||||
{BufferFormat::k16_16_16_16UInt, 8, 0, 8, true, true},
|
||||
{BufferFormat::k16_16_16_16SInt, 8, 0, 8, false, false},
|
||||
{BufferFormat::k16_16_16_16Float, 8, 0, 8, true, false},
|
||||
{BufferFormat::k32_32_32UInt, 12, 0, 12, true, true},
|
||||
{BufferFormat::k32_32_32SInt, 12, 0, 12, false, false},
|
||||
{BufferFormat::k32_32_32Float, 12, 0, 12, true, false},
|
||||
{BufferFormat::k32_32_32_32UInt, 16, 0, 16, true, true},
|
||||
{BufferFormat::k32_32_32_32SInt, 16, 0, 16, false, false},
|
||||
{BufferFormat::k32_32_32_32Float, 16, 0, 16, true, false},
|
||||
{BufferFormat::k8Srgb, 1, 0, 0, true, false},
|
||||
{BufferFormat::k8_8Srgb, 2, 0, 0, true, false},
|
||||
{BufferFormat::k8_8_8_8Srgb, 4, 0, 4, true, false},
|
||||
{BufferFormat::k9_9_9_5Float, 4, 0, 0, true, false},
|
||||
{BufferFormat::k5_6_5UNorm, 2, 0, 2, true, false},
|
||||
{BufferFormat::k5_5_5_1UNorm, 2, 0, 2, true, false},
|
||||
{BufferFormat::k1_5_5_5UNorm, 0, 0, 2, false, false},
|
||||
{BufferFormat::k4_4_4_4UNorm, 2, 0, 2, true, false},
|
||||
{BufferFormat::kFmask8_S4_F4, 1, 0, 1, true, false},
|
||||
{BufferFormat::kBc1UNorm, 0, 8, 0, true, false},
|
||||
{BufferFormat::kBc1Srgb, 0, 8, 0, true, false},
|
||||
{BufferFormat::kBc2UNorm, 0, 16, 0, true, false},
|
||||
{BufferFormat::kBc2Srgb, 0, 16, 0, true, false},
|
||||
{BufferFormat::kBc3UNorm, 0, 16, 0, true, false},
|
||||
{BufferFormat::kBc3Srgb, 0, 16, 0, true, false},
|
||||
{BufferFormat::kBc4UNorm, 0, 8, 0, true, false},
|
||||
{BufferFormat::kBc4SNorm, 0, 8, 0, true, false},
|
||||
{BufferFormat::kBc5UNorm, 0, 16, 0, true, false},
|
||||
{BufferFormat::kBc5SNorm, 0, 16, 0, true, false},
|
||||
{BufferFormat::kBc6UFloat, 0, 16, 0, true, false},
|
||||
{BufferFormat::kBc6SFloat, 0, 16, 0, true, false},
|
||||
{BufferFormat::kBc7UNorm, 0, 16, 0, true, false},
|
||||
{BufferFormat::kBc7Srgb, 0, 16, 0, true, false},
|
||||
};
|
||||
|
||||
constexpr uint8_t RenderTargetTypeBit(ChannelType type) {
|
||||
return static_cast<uint8_t>(1u << static_cast<uint32_t>(type));
|
||||
}
|
||||
|
||||
constexpr auto kUNormType = RenderTargetTypeBit(ChannelType::kUNorm);
|
||||
constexpr auto kIntegerTypes =
|
||||
RenderTargetTypeBit(ChannelType::kUInt) | RenderTargetTypeBit(ChannelType::kSInt);
|
||||
constexpr auto kNormalizedIntegerTypes =
|
||||
kUNormType | RenderTargetTypeBit(ChannelType::kSNorm) | kIntegerTypes;
|
||||
|
||||
struct RenderTargetLayoutInfo {
|
||||
ChannelLayout layout;
|
||||
BufferFormat first_linear_format;
|
||||
uint8_t linear_type_mask;
|
||||
uint8_t components;
|
||||
BufferFormat extra_format = BufferFormat::kInvalid;
|
||||
ChannelType extra_type = ChannelType::kUNorm;
|
||||
ChannelOrderSupport order_support = ChannelOrderSupport::kAll;
|
||||
};
|
||||
|
||||
constexpr RenderTargetLayoutInfo kRenderTargetLayouts[] = {
|
||||
{ChannelLayout::k8, BufferFormat::k8UNorm, kNormalizedIntegerTypes, 1, BufferFormat::k8Srgb,
|
||||
ChannelType::kSrgb},
|
||||
{ChannelLayout::k16, BufferFormat::k16UNorm, kNormalizedIntegerTypes, 1, BufferFormat::k16Float,
|
||||
ChannelType::kFloat},
|
||||
{ChannelLayout::k8_8, BufferFormat::k8_8UNorm, kNormalizedIntegerTypes, 2,
|
||||
BufferFormat::k8_8Srgb, ChannelType::kSrgb},
|
||||
{ChannelLayout::k32, BufferFormat::k32UInt, kIntegerTypes, 1, BufferFormat::k32Float,
|
||||
ChannelType::kFloat},
|
||||
{ChannelLayout::k16_16, BufferFormat::k16_16UNorm, kNormalizedIntegerTypes, 2,
|
||||
BufferFormat::k16_16Float, ChannelType::kFloat},
|
||||
{ChannelLayout::k11_11_10, BufferFormat::k11_11_10UNorm, kNormalizedIntegerTypes, 3,
|
||||
BufferFormat::k11_11_10Float, ChannelType::kFloat},
|
||||
{ChannelLayout::k10_11_11, BufferFormat::k10_11_11UNorm, kNormalizedIntegerTypes, 3,
|
||||
BufferFormat::k10_11_11Float, ChannelType::kFloat},
|
||||
{ChannelLayout::k2_10_10_10, BufferFormat::k2_10_10_10UNorm, kNormalizedIntegerTypes, 4},
|
||||
{ChannelLayout::k10_10_10_2, BufferFormat::k10_10_10_2UNorm, kNormalizedIntegerTypes, 4},
|
||||
{ChannelLayout::k8_8_8_8, BufferFormat::k8_8_8_8UNorm, kNormalizedIntegerTypes, 4,
|
||||
BufferFormat::k8_8_8_8Srgb, ChannelType::kSrgb},
|
||||
{ChannelLayout::k32_32, BufferFormat::k32_32UInt, kIntegerTypes, 2, BufferFormat::k32_32Float,
|
||||
ChannelType::kFloat},
|
||||
{ChannelLayout::k16_16_16_16, BufferFormat::k16_16_16_16UNorm, kNormalizedIntegerTypes, 4,
|
||||
BufferFormat::k16_16_16_16Float, ChannelType::kFloat},
|
||||
{ChannelLayout::k32_32_32_32, BufferFormat::k32_32_32_32UInt, kIntegerTypes, 4,
|
||||
BufferFormat::k32_32_32_32Float, ChannelType::kFloat},
|
||||
{ChannelLayout::k5_6_5, BufferFormat::k5_6_5UNorm, kUNormType, 3},
|
||||
{ChannelLayout::k5_5_5_1, BufferFormat::k5_5_5_1UNorm, kUNormType, 4},
|
||||
{ChannelLayout::k1_5_5_5, BufferFormat::k1_5_5_5UNorm, kUNormType, 4},
|
||||
{ChannelLayout::k4_4_4_4, BufferFormat::k4_4_4_4UNorm, kUNormType, 4},
|
||||
{ChannelLayout::k10_10_10_2Float, BufferFormat::kInvalid, 0, 4, BufferFormat::k10_10_10_2Float,
|
||||
ChannelType::kFloat, ChannelOrderSupport::kStandardOnly},
|
||||
};
|
||||
|
||||
const RenderTargetLayoutInfo* FindRenderTargetLayout(ChannelLayout layout) {
|
||||
for (const auto& info: kRenderTargetLayouts) {
|
||||
if (info.layout == layout) {
|
||||
return &info;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
constexpr auto MakeFormatInfoLookup() {
|
||||
constexpr uint32_t kMaxFormat = GpuEnumValue(BufferFormat::kBc7Srgb);
|
||||
constexpr size_t kMaxFormat = static_cast<size_t>(BufferFormat::kBc7Srgb);
|
||||
std::array<const FormatInfo*, kMaxFormat + 1> lookup {};
|
||||
for (const auto& info: kFormatInfo) {
|
||||
lookup[info.format] = &info;
|
||||
lookup[static_cast<size_t>(info.format)] = &info;
|
||||
}
|
||||
return lookup;
|
||||
}
|
||||
|
||||
constexpr auto kFormatInfoLookup = MakeFormatInfoLookup();
|
||||
|
||||
const FormatInfo* FindFormatInfo(uint32_t format) {
|
||||
return format < kFormatInfoLookup.size() ? kFormatInfoLookup[format] : nullptr;
|
||||
const FormatInfo* FindFormatInfo(BufferFormat format) {
|
||||
const auto index = static_cast<size_t>(format);
|
||||
return index < kFormatInfoLookup.size() ? kFormatInfoLookup[index] : nullptr;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
uint32_t NumBytesPerElement(uint32_t format) {
|
||||
RenderTargetFormatEncoding ResolveRenderTargetFormat(ChannelLayout layout, ChannelType type) {
|
||||
const auto* layout_info = FindRenderTargetLayout(layout);
|
||||
const auto raw_type = static_cast<uint32_t>(type);
|
||||
if (layout_info == nullptr || raw_type >= 8u) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto format = BufferFormat::kInvalid;
|
||||
if (layout_info->extra_format != BufferFormat::kInvalid && type == layout_info->extra_type) {
|
||||
format = layout_info->extra_format;
|
||||
} else if ((layout_info->linear_type_mask & (1u << raw_type)) != 0) {
|
||||
const auto first_type =
|
||||
std::countr_zero(static_cast<uint32_t>(layout_info->linear_type_mask));
|
||||
format = static_cast<BufferFormat>(static_cast<uint32_t>(layout_info->first_linear_format) +
|
||||
raw_type - first_type);
|
||||
}
|
||||
if (format == BufferFormat::kInvalid) {
|
||||
return {};
|
||||
}
|
||||
return {format, layout_info->components, layout_info->order_support};
|
||||
}
|
||||
|
||||
uint32_t NumBytesPerElement(BufferFormat format) {
|
||||
const auto* info = FindFormatInfo(format);
|
||||
return info != nullptr ? info->bytes_per_element : 0;
|
||||
}
|
||||
|
||||
uint32_t BlockCompressedBytesPerBlock(uint32_t format) {
|
||||
uint32_t BlockCompressedBytesPerBlock(BufferFormat format) {
|
||||
const auto* info = FindFormatInfo(format);
|
||||
return info != nullptr ? info->block_compressed_bytes_per_block : 0;
|
||||
}
|
||||
|
||||
uint32_t RenderTargetBytesPerElement(uint32_t format) {
|
||||
uint32_t RenderTargetBytesPerElement(BufferFormat format) {
|
||||
const auto* info = FindFormatInfo(format);
|
||||
return info != nullptr ? info->render_target_bytes_per_element : 0;
|
||||
}
|
||||
|
||||
bool IsSupportedTextureFormat(uint32_t format) {
|
||||
bool IsSupportedTextureFormat(BufferFormat format) {
|
||||
const auto* info = FindFormatInfo(format);
|
||||
return info != nullptr && info->supported_sampled_texture_format;
|
||||
}
|
||||
|
||||
bool IsUintTextureFormat(uint32_t format) {
|
||||
bool IsUintTextureFormat(BufferFormat format) {
|
||||
const auto* info = FindFormatInfo(format);
|
||||
return info != nullptr && info->unsigned_integer_texture_format;
|
||||
}
|
||||
|
||||
bool IsFmaskTextureFormat(uint32_t format) {
|
||||
return format == GpuEnumValue(BufferFormat::kFmask8_S4_F4);
|
||||
bool IsFmaskTextureFormat(BufferFormat format) {
|
||||
return format == BufferFormat::kFmask8_S4_F4;
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics::Prospero
|
||||
@@ -1,16 +1,49 @@
|
||||
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GUEST_GPU_GPU_FORMAT_H_
|
||||
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GUEST_GPU_GPU_FORMAT_H_
|
||||
|
||||
#include "common/common.h"
|
||||
#include "graphics/guest_gpu/gpu_defs.h"
|
||||
|
||||
namespace Libs::Graphics::Prospero {
|
||||
|
||||
uint32_t NumBytesPerElement(uint32_t format);
|
||||
uint32_t BlockCompressedBytesPerBlock(uint32_t format);
|
||||
uint32_t RenderTargetBytesPerElement(uint32_t format);
|
||||
bool IsSupportedTextureFormat(uint32_t format);
|
||||
bool IsUintTextureFormat(uint32_t format);
|
||||
bool IsFmaskTextureFormat(uint32_t format);
|
||||
enum class ChannelOrderSupport : uint8_t {
|
||||
kNone,
|
||||
kStandardOnly,
|
||||
kAll,
|
||||
};
|
||||
|
||||
struct RenderTargetFormatEncoding {
|
||||
BufferFormat buffer_format = BufferFormat::kInvalid;
|
||||
uint8_t components = 0;
|
||||
ChannelOrderSupport order_support = ChannelOrderSupport::kNone;
|
||||
|
||||
[[nodiscard]] constexpr bool IsValid() const {
|
||||
return buffer_format != BufferFormat::kInvalid && components >= 1u && components <= 4u &&
|
||||
order_support != ChannelOrderSupport::kNone;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool SupportsOrder(ChannelOrder order) const {
|
||||
switch (order_support) {
|
||||
case ChannelOrderSupport::kStandardOnly: return order == ChannelOrder::kStandard;
|
||||
case ChannelOrderSupport::kAll:
|
||||
switch (order) {
|
||||
case ChannelOrder::kStandard:
|
||||
case ChannelOrder::kAlt:
|
||||
case ChannelOrder::kReversed:
|
||||
case ChannelOrder::kAltReversed: return true;
|
||||
}
|
||||
return false;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
RenderTargetFormatEncoding ResolveRenderTargetFormat(ChannelLayout layout, ChannelType type);
|
||||
uint32_t NumBytesPerElement(BufferFormat format);
|
||||
uint32_t BlockCompressedBytesPerBlock(BufferFormat format);
|
||||
uint32_t RenderTargetBytesPerElement(BufferFormat format);
|
||||
bool IsSupportedTextureFormat(BufferFormat format);
|
||||
bool IsUintTextureFormat(BufferFormat format);
|
||||
bool IsFmaskTextureFormat(BufferFormat format);
|
||||
|
||||
} // namespace Libs::Graphics::Prospero
|
||||
|
||||
|
||||
@@ -1384,9 +1384,14 @@ void CommandProcessor::WriteAtEndOfPipe(uint32_t cache_policy, uint32_t event_wr
|
||||
case 0x00:
|
||||
switch (eop_event_type) {
|
||||
case 0x04:
|
||||
if (event_index == 0x05) {
|
||||
write64(false);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 0x14:
|
||||
case 0x28:
|
||||
if ((eop_event_type == 0x04 && event_index == 0x05) ||
|
||||
(eop_event_type == 0x28 && event_index == 0x00)) {
|
||||
if (event_index == 0x00) {
|
||||
write64(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -29,27 +29,27 @@ struct ColorView {
|
||||
struct ColorInfo {
|
||||
bool fmask_compression_enable = false;
|
||||
// uint32_t fmask_compression_mode = 0;
|
||||
bool fmask_data_compression_disable = false;
|
||||
bool fmask_one_frag_mode = false;
|
||||
bool cmask_fast_clear_enable = false;
|
||||
bool dcc_compression_enable = false;
|
||||
bool blend_clamp = false;
|
||||
bool blend_bypass = false;
|
||||
bool round_mode = false;
|
||||
uint32_t cmask_is_linear = 0;
|
||||
uint32_t cmask_addr_type = 0;
|
||||
bool alt_tile_mode = false;
|
||||
uint32_t format = 0;
|
||||
uint32_t channel_type = 0;
|
||||
uint32_t channel_order = 0;
|
||||
bool fmask_data_compression_disable = false;
|
||||
bool fmask_one_frag_mode = false;
|
||||
bool cmask_fast_clear_enable = false;
|
||||
bool dcc_compression_enable = false;
|
||||
bool blend_clamp = false;
|
||||
bool blend_bypass = false;
|
||||
bool round_mode = false;
|
||||
uint32_t cmask_is_linear = 0;
|
||||
uint32_t cmask_addr_type = 0;
|
||||
bool alt_tile_mode = false;
|
||||
Prospero::ChannelLayout format = Prospero::ChannelLayout::kInvalid;
|
||||
Prospero::ChannelType channel_type = Prospero::ChannelType::kUNorm;
|
||||
Prospero::ChannelOrder channel_order = Prospero::ChannelOrder::kStandard;
|
||||
};
|
||||
|
||||
struct ColorAttrib {
|
||||
bool force_dest_alpha_to_one = false;
|
||||
uint32_t tile_mode = 0;
|
||||
uint32_t fmask_tile_mode = 0;
|
||||
uint32_t num_samples = 0;
|
||||
uint32_t num_fragments = 0;
|
||||
bool force_dest_alpha_to_one = false;
|
||||
Prospero::TileMode tile_mode = Prospero::TileMode::kLinear;
|
||||
Prospero::TileMode fmask_tile_mode = Prospero::TileMode::kLinear;
|
||||
uint32_t num_samples = 0;
|
||||
uint32_t num_fragments = 0;
|
||||
};
|
||||
|
||||
struct ColorAttrib2 {
|
||||
@@ -59,11 +59,11 @@ struct ColorAttrib2 {
|
||||
};
|
||||
|
||||
struct ColorAttrib3 {
|
||||
uint32_t depth = 0;
|
||||
uint32_t tile_mode = 0;
|
||||
uint32_t dimension = 0;
|
||||
bool cmask_pipe_aligned = false;
|
||||
bool dcc_pipe_aligned = false;
|
||||
uint32_t depth = 0;
|
||||
Prospero::TileMode tile_mode = Prospero::TileMode::kLinear;
|
||||
uint32_t dimension = 0;
|
||||
bool cmask_pipe_aligned = false;
|
||||
bool dcc_pipe_aligned = false;
|
||||
};
|
||||
|
||||
struct ColorDccControl {
|
||||
@@ -132,7 +132,7 @@ struct RenderTarget {
|
||||
};
|
||||
|
||||
struct DepthZInfo {
|
||||
uint32_t format = 0;
|
||||
Prospero::DepthFormat format = Prospero::DepthFormat::kInvalid;
|
||||
uint32_t num_samples = 0;
|
||||
Prospero::TextureCompatiblePlaneCompression texture_compatibility =
|
||||
Prospero::TextureCompatiblePlaneCompression::kDisable;
|
||||
@@ -144,16 +144,16 @@ struct DepthZInfo {
|
||||
|
||||
[[nodiscard]] static DepthZInfo Decode(uint32_t value) {
|
||||
DepthZInfo info;
|
||||
info.format = value & 0x3u;
|
||||
info.format = static_cast<Prospero::DepthFormat>(value & 0x3u);
|
||||
info.num_samples = (value >> 2u) & 0x3u;
|
||||
info.texture_compatibility = static_cast<Prospero::TextureCompatiblePlaneCompression>(
|
||||
value & Prospero::GpuEnumValue(Prospero::TextureCompatiblePlaneCompression::kBitMask));
|
||||
value & static_cast<uint32_t>(Prospero::TextureCompatiblePlaneCompression::kBitMask));
|
||||
info.partially_resident = (value & 0x00001000u) != 0;
|
||||
info.max_mip_level = static_cast<uint8_t>((value >> 16u) & 0x0fu);
|
||||
info.expclear_enabled = (value & 0x08000000u) != 0;
|
||||
info.htile_acceleration = (value & 0x20000000u) != 0;
|
||||
info.z_compare_base = static_cast<Prospero::ZCompareBase>(
|
||||
value & Prospero::GpuEnumValue(Prospero::ZCompareBase::kBitMask));
|
||||
value & static_cast<uint32_t>(Prospero::ZCompareBase::kBitMask));
|
||||
return info;
|
||||
}
|
||||
|
||||
@@ -167,7 +167,7 @@ struct DepthZInfo {
|
||||
};
|
||||
|
||||
struct DepthStencilInfo {
|
||||
uint32_t format = 0;
|
||||
Prospero::StencilFormat format = Prospero::StencilFormat::kInvalid;
|
||||
Prospero::TextureCompatibleStencil texture_compatibility =
|
||||
Prospero::TextureCompatibleStencil::kDisable;
|
||||
bool expclear_enabled = false;
|
||||
@@ -176,9 +176,9 @@ struct DepthStencilInfo {
|
||||
|
||||
[[nodiscard]] static DepthStencilInfo Decode(uint32_t value) {
|
||||
DepthStencilInfo info;
|
||||
info.format = value & 0x1u;
|
||||
info.format = static_cast<Prospero::StencilFormat>(value & 0x1u);
|
||||
info.texture_compatibility = static_cast<Prospero::TextureCompatibleStencil>(
|
||||
value & Prospero::GpuEnumValue(Prospero::TextureCompatibleStencil::kBitMask));
|
||||
value & static_cast<uint32_t>(Prospero::TextureCompatibleStencil::kBitMask));
|
||||
info.partially_resident = (value & 0x00001000u) != 0;
|
||||
info.expclear_enabled = (value & 0x08000000u) != 0;
|
||||
info.htile_stencil_disabled = (value & 0x20000000u) != 0;
|
||||
@@ -1029,8 +1029,8 @@ public:
|
||||
|
||||
void Reset() { *this = UserConfig(); }
|
||||
|
||||
void SetPrimitiveType(uint32_t prim_type) { m_prim_type = prim_type; }
|
||||
[[nodiscard]] uint32_t GetPrimType() const { return m_prim_type; }
|
||||
void SetPrimitiveType(Prospero::PrimitiveType prim_type) { m_prim_type = prim_type; }
|
||||
[[nodiscard]] Prospero::PrimitiveType GetPrimType() const { return m_prim_type; }
|
||||
void SetIndexOffset(uint32_t index_offset) { m_index_offset = index_offset; }
|
||||
[[nodiscard]] uint32_t GetIndexOffset() const { return m_index_offset; }
|
||||
void SetObjectId(uint32_t object_id) { m_object_id = object_id; }
|
||||
@@ -1049,9 +1049,9 @@ public:
|
||||
void SetGdsOaAddress(uint32_t value) { m_gds_oa.counters[m_gds_oa.GetIndex()].address = value; }
|
||||
|
||||
private:
|
||||
uint32_t m_prim_type = 0;
|
||||
uint32_t m_index_offset = 0;
|
||||
uint32_t m_object_id = 0;
|
||||
Prospero::PrimitiveType m_prim_type = Prospero::PrimitiveType::kNone;
|
||||
uint32_t m_index_offset = 0;
|
||||
uint32_t m_object_id = 0;
|
||||
|
||||
GeControl m_ge_cntl;
|
||||
GeUserVgprEn m_ge_user_vgpr_en;
|
||||
|
||||
@@ -265,7 +265,7 @@ static bool GetMipTailLayout(const TileBlockLayout& block, MipTailLayout& out) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TileGetTextureElementLayout(uint32_t format, TileTextureElementLayout& out) {
|
||||
bool TileGetTextureElementLayout(Prospero::BufferFormat format, TileTextureElementLayout& out) {
|
||||
if (const auto bytes = Prospero::NumBytesPerElement(format); std::has_single_bit(bytes)) {
|
||||
out = {bytes, 1, 1};
|
||||
return true;
|
||||
@@ -277,10 +277,10 @@ bool TileGetTextureElementLayout(uint32_t format, TileTextureElementLayout& out)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TileGetTextureBlockLayout(uint32_t format, uint32_t tile, bool volume,
|
||||
bool TileGetTextureBlockLayout(Prospero::BufferFormat format, Prospero::TileMode tile, bool volume,
|
||||
TileTextureBlockLayout& out) {
|
||||
TileBlockFamily family = TileBlockFamily::Count;
|
||||
switch (static_cast<Prospero::TileMode>(tile)) {
|
||||
switch (tile) {
|
||||
case Prospero::TileMode::kStandard256B:
|
||||
if (!volume) family = TileBlockFamily::Standard256B;
|
||||
break;
|
||||
@@ -1130,15 +1130,18 @@ static bool TileGetHtileSize(uint32_t width, uint32_t height, TileSizeAlign& hti
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TileGetDepthSize(uint32_t width, uint32_t height, uint32_t pitch, uint32_t z_format,
|
||||
uint32_t stencil_format, bool htile, TileSizeAlign& stencil_size,
|
||||
TileSizeAlign& htile_size, TileSizeAlign& depth_size,
|
||||
uint32_t num_fragments_log2) {
|
||||
bool TileGetDepthSize(uint32_t width, uint32_t height, uint32_t pitch,
|
||||
Prospero::DepthFormat z_format, Prospero::StencilFormat stencil_format,
|
||||
bool htile, TileSizeAlign& stencil_size, TileSizeAlign& htile_size,
|
||||
TileSizeAlign& depth_size, uint32_t num_fragments_log2) {
|
||||
EXIT_IF(pitch != 0);
|
||||
// Prospero derives uncompressed depth/stencil as independent 64 KiB block surfaces.
|
||||
if (width > 0 && width <= 16384 && height > 0 && height <= 16384 &&
|
||||
(z_format == 1 || z_format == 3) && stencil_format <= 1 && num_fragments_log2 <= 3) {
|
||||
const uint32_t depth_bytes = z_format == 1 ? 2u : 4u;
|
||||
(z_format == Prospero::DepthFormat::kZ16 || z_format == Prospero::DepthFormat::kZ32F) &&
|
||||
(stencil_format == Prospero::StencilFormat::kInvalid ||
|
||||
stencil_format == Prospero::StencilFormat::k8UInt) &&
|
||||
num_fragments_log2 <= 3) {
|
||||
const uint32_t depth_bytes = z_format == Prospero::DepthFormat::kZ16 ? 2u : 4u;
|
||||
uint32_t depth_block_width = 0;
|
||||
uint32_t depth_block_height = 0;
|
||||
uint32_t stencil_block_width = 0;
|
||||
@@ -1146,7 +1149,7 @@ bool TileGetDepthSize(uint32_t width, uint32_t height, uint32_t pitch, uint32_t
|
||||
const bool valid_blocks =
|
||||
Gen5Msaa64KBBlockSizeFromElementBytes(depth_bytes, num_fragments_log2,
|
||||
&depth_block_width, &depth_block_height) &&
|
||||
(stencil_format == 0 ||
|
||||
(stencil_format == Prospero::StencilFormat::kInvalid ||
|
||||
Gen5Msaa64KBBlockSizeFromElementBytes(1, num_fragments_log2, &stencil_block_width,
|
||||
&stencil_block_height));
|
||||
const uint32_t fragments = 1u << num_fragments_log2;
|
||||
@@ -1155,7 +1158,7 @@ bool TileGetDepthSize(uint32_t width, uint32_t height, uint32_t pitch, uint32_t
|
||||
AlignUp(height, depth_block_height) * depth_bytes * fragments
|
||||
: 0;
|
||||
const uint64_t stencil_bytes_total =
|
||||
stencil_format == 1 && valid_blocks
|
||||
stencil_format == Prospero::StencilFormat::k8UInt && valid_blocks
|
||||
? static_cast<uint64_t>(AlignUp(width, stencil_block_width)) *
|
||||
AlignUp(height, stencil_block_height) * fragments
|
||||
: 0;
|
||||
@@ -1163,7 +1166,7 @@ bool TileGetDepthSize(uint32_t width, uint32_t height, uint32_t pitch, uint32_t
|
||||
const bool htile_valid = !htile || TileGetHtileSize(width, height, calculated_htile);
|
||||
if (depth_bytes_total <= UINT32_MAX && stencil_bytes_total <= UINT32_MAX && htile_valid) {
|
||||
depth_size = {static_cast<uint32_t>(depth_bytes_total), 65536};
|
||||
stencil_size = stencil_format == 1
|
||||
stencil_size = stencil_format == Prospero::StencilFormat::k8UInt
|
||||
? TileSizeAlign {static_cast<uint32_t>(stencil_bytes_total), 65536}
|
||||
: TileSizeAlign {};
|
||||
htile_size = calculated_htile;
|
||||
@@ -1236,31 +1239,29 @@ bool TileGetRenderTargetMipLayout(uint32_t width, uint32_t height, uint32_t pitc
|
||||
if (levels > max_levels) {
|
||||
return false;
|
||||
}
|
||||
uint32_t format = 0;
|
||||
auto format = Prospero::BufferFormat::kInvalid;
|
||||
switch (bytes_per_element) {
|
||||
case 1: format = Prospero::GpuEnumValue(Prospero::BufferFormat::k8UNorm); break;
|
||||
case 2: format = Prospero::GpuEnumValue(Prospero::BufferFormat::k16UNorm); break;
|
||||
case 4: format = Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float); break;
|
||||
case 8: format = Prospero::GpuEnumValue(Prospero::BufferFormat::k16_16_16_16Float); break;
|
||||
case 16: format = Prospero::GpuEnumValue(Prospero::BufferFormat::k32_32_32_32Float); break;
|
||||
case 1: format = Prospero::BufferFormat::k8UNorm; break;
|
||||
case 2: format = Prospero::BufferFormat::k16UNorm; break;
|
||||
case 4: format = Prospero::BufferFormat::k32Float; break;
|
||||
case 8: format = Prospero::BufferFormat::k16_16_16_16Float; break;
|
||||
case 16: format = Prospero::BufferFormat::k32_32_32_32Float; break;
|
||||
default: return false;
|
||||
}
|
||||
TileGetTextureSize(format, width, height, levels,
|
||||
Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget), &total_size,
|
||||
level_sizes, padded_size);
|
||||
TileGetTextureSize(format, width, height, levels, Prospero::TileMode::kRenderTarget,
|
||||
&total_size, level_sizes, padded_size);
|
||||
return total_size.size != 0 && total_size.align == 65536;
|
||||
}
|
||||
|
||||
void TileGetTextureSize(uint32_t format, uint32_t width, uint32_t height, uint32_t levels,
|
||||
uint32_t tile, TileSizeAlign* total_size, TileSizeOffset* level_sizes,
|
||||
TilePaddedSize* padded_size) {
|
||||
void TileGetTextureSize(Prospero::BufferFormat format, uint32_t width, uint32_t height,
|
||||
uint32_t levels, Prospero::TileMode tile, TileSizeAlign* total_size,
|
||||
TileSizeOffset* level_sizes, TilePaddedSize* padded_size) {
|
||||
KYTY_PROFILER_FUNCTION();
|
||||
|
||||
EXIT_IF(levels == 0 || levels > 16);
|
||||
|
||||
TileTextureElementLayout element {};
|
||||
if (static_cast<Prospero::TileMode>(tile) == Prospero::TileMode::kLinear &&
|
||||
TileGetTextureElementLayout(format, element)) {
|
||||
if (tile == Prospero::TileMode::kLinear && TileGetTextureElementLayout(format, element)) {
|
||||
uint32_t mip_pitch[16] {};
|
||||
uint32_t mip_height[16] {};
|
||||
uint32_t mip_size[16] {};
|
||||
@@ -1302,26 +1303,27 @@ void TileGetTextureSize(uint32_t format, uint32_t width, uint32_t height, uint32
|
||||
}
|
||||
if (total_size != nullptr && total_size->size == 0) {
|
||||
std::vector<std::string> list;
|
||||
list.push_back(fmt::format("format = {}", format));
|
||||
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 = {}", tile));
|
||||
list.push_back(fmt::format("tile = {}", static_cast<uint32_t>(tile)));
|
||||
EXIT("unknown format:\n%s\n", Common::Concat(list, '\n').c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void TileGetTextureTotalSize(uint32_t format, uint32_t width, uint32_t height, uint32_t depth,
|
||||
uint32_t levels, uint32_t tile, bool volume_texture,
|
||||
TileSizeAlign& total_size) {
|
||||
void TileGetTextureTotalSize(Prospero::BufferFormat format, uint32_t width, uint32_t height,
|
||||
uint32_t depth, uint32_t levels, Prospero::TileMode tile,
|
||||
bool volume_texture, TileSizeAlign& total_size) {
|
||||
EXIT_NOT_IMPLEMENTED(depth == 0);
|
||||
if (volume_texture && static_cast<Prospero::TileMode>(tile) != Prospero::TileMode::kLinear) {
|
||||
if (volume_texture && tile != Prospero::TileMode::kLinear) {
|
||||
TileSurfaceLayout layout {};
|
||||
const TileSurfaceDescription description {
|
||||
format, tile, TileSurfaceDimension::Dim3D, width, height, depth, levels, 1};
|
||||
if (!TileGetTiledTextureLayout(description, layout)) {
|
||||
EXIT("unsupported 3D texture layout: format=%u tile=%u extent=%ux%ux%u levels=%u\n",
|
||||
format, tile, width, height, depth, levels);
|
||||
static_cast<uint32_t>(format), static_cast<uint32_t>(tile), width, height, depth,
|
||||
levels);
|
||||
}
|
||||
EXIT_NOT_IMPLEMENTED(layout.total_size > UINT32_MAX);
|
||||
total_size.size = static_cast<uint32_t>(layout.total_size);
|
||||
@@ -1337,9 +1339,10 @@ void TileGetTextureTotalSize(uint32_t format, uint32_t width, uint32_t height, u
|
||||
total_size.size = static_cast<uint32_t>(total);
|
||||
}
|
||||
|
||||
uint32_t TileGetTexturePitch(uint32_t format, uint32_t width, uint32_t tile) {
|
||||
uint32_t TileGetTexturePitch(Prospero::BufferFormat format, uint32_t width,
|
||||
Prospero::TileMode tile) {
|
||||
uint32_t pitch = width;
|
||||
switch (static_cast<Prospero::TileMode>(tile)) {
|
||||
switch (tile) {
|
||||
case Prospero::TileMode::kLinear: {
|
||||
TileTextureElementLayout element {};
|
||||
if (TileGetTextureElementLayout(format, element) && element.texel_width == 1 &&
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "common/abi.h"
|
||||
#include "common/common.h"
|
||||
#include "graphics/guest_gpu/gpu_defs.h"
|
||||
|
||||
namespace Libs::Graphics {
|
||||
|
||||
@@ -65,14 +66,14 @@ enum class TileSurfaceDimension : uint32_t {
|
||||
};
|
||||
|
||||
struct TileSurfaceDescription {
|
||||
uint32_t format = 0;
|
||||
uint32_t tile_mode = 0;
|
||||
TileSurfaceDimension dimension = TileSurfaceDimension::Dim2D;
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
uint32_t depth = 1;
|
||||
uint32_t levels = 1;
|
||||
uint32_t layers = 1;
|
||||
Prospero::BufferFormat format = Prospero::BufferFormat::kInvalid;
|
||||
Prospero::TileMode tile_mode = Prospero::TileMode::kLinear;
|
||||
TileSurfaceDimension dimension = TileSurfaceDimension::Dim2D;
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
uint32_t depth = 1;
|
||||
uint32_t levels = 1;
|
||||
uint32_t layers = 1;
|
||||
};
|
||||
|
||||
// Width/height fields are measured in addressable elements, not texture texels.
|
||||
@@ -98,8 +99,8 @@ struct TileSurfaceLayout {
|
||||
|
||||
bool TileGetBlockLayout(TileBlockFamily family, uint32_t bytes_per_element,
|
||||
TileBlockLayout& layout);
|
||||
bool TileGetTextureElementLayout(uint32_t format, TileTextureElementLayout& layout);
|
||||
bool TileGetTextureBlockLayout(uint32_t format, uint32_t tile, bool volume,
|
||||
bool TileGetTextureElementLayout(Prospero::BufferFormat format, TileTextureElementLayout& layout);
|
||||
bool TileGetTextureBlockLayout(Prospero::BufferFormat format, Prospero::TileMode tile, bool volume,
|
||||
TileTextureBlockLayout& layout);
|
||||
bool TileGetTiledTextureLayout(const TileSurfaceDescription& description,
|
||||
TileSurfaceLayout& layout);
|
||||
@@ -110,10 +111,10 @@ bool TileGetBlockXor(const TileBlockLayout& layout, uint32_t block_x, uint32_t b
|
||||
bool TileGetBlockXor(const TileBlockLayout& layout, uint32_t block_x, uint32_t block_y,
|
||||
uint32_t block_z, uint32_t& byte_offset);
|
||||
|
||||
bool TileGetDepthSize(uint32_t width, uint32_t height, uint32_t pitch, uint32_t z_format,
|
||||
uint32_t stencil_format, bool htile, TileSizeAlign& stencil_size,
|
||||
TileSizeAlign& htile_size, TileSizeAlign& depth_size,
|
||||
uint32_t num_fragments_log2 = 0);
|
||||
bool TileGetDepthSize(uint32_t width, uint32_t height, uint32_t pitch,
|
||||
Prospero::DepthFormat z_format, Prospero::StencilFormat stencil_format,
|
||||
bool htile, TileSizeAlign& stencil_size, TileSizeAlign& htile_size,
|
||||
TileSizeAlign& depth_size, uint32_t num_fragments_log2 = 0);
|
||||
uint32_t TileGetRenderTargetPitch(uint32_t width, uint32_t bytes_per_element,
|
||||
uint32_t num_fragments_log2 = 0);
|
||||
uint32_t TileGetDepthPitch(uint32_t width, uint32_t bytes_per_element,
|
||||
@@ -125,13 +126,14 @@ bool TileGetRenderTargetMipLayout(uint32_t width, uint32_t height, uint32_t
|
||||
uint32_t bytes_per_element, uint32_t levels,
|
||||
TileSizeAlign& total_size, TileSizeOffset* level_sizes,
|
||||
TilePaddedSize* padded_size);
|
||||
void TileGetTextureSize(uint32_t format, uint32_t width, uint32_t height, uint32_t levels,
|
||||
uint32_t tile, TileSizeAlign* total_size, TileSizeOffset* level_sizes,
|
||||
TilePaddedSize* padded_size);
|
||||
void TileGetTextureTotalSize(uint32_t format, uint32_t width, uint32_t height, uint32_t depth,
|
||||
uint32_t levels, uint32_t tile, bool volume_texture,
|
||||
TileSizeAlign& total_size);
|
||||
uint32_t TileGetTexturePitch(uint32_t format, uint32_t width, uint32_t tile);
|
||||
void TileGetTextureSize(Prospero::BufferFormat format, uint32_t width, uint32_t height,
|
||||
uint32_t levels, Prospero::TileMode tile, TileSizeAlign* total_size,
|
||||
TileSizeOffset* level_sizes, TilePaddedSize* padded_size);
|
||||
void TileGetTextureTotalSize(Prospero::BufferFormat format, uint32_t width, uint32_t height,
|
||||
uint32_t depth, uint32_t levels, Prospero::TileMode tile,
|
||||
bool volume_texture, TileSizeAlign& total_size);
|
||||
uint32_t TileGetTexturePitch(Prospero::BufferFormat format, uint32_t width,
|
||||
Prospero::TileMode tile);
|
||||
|
||||
} // namespace Libs::Graphics
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "graphics/host_gpu/pageManager.h"
|
||||
|
||||
#include "common/platform/sysDbg.h"
|
||||
#include "graphics/host_gpu/regionDefinitions.h"
|
||||
#include "kernel/memory.h"
|
||||
|
||||
@@ -52,20 +53,20 @@ constexpr uint32_t READ_WRITE_PROTECTION = PAGE_READWRITE;
|
||||
std::fputs("PageManager fail-fast: ", stderr);
|
||||
std::fputs(reason != nullptr ? reason : "invalid page state", stderr);
|
||||
std::fputc('\n', stderr);
|
||||
#if !defined(__APPLE__)
|
||||
void* frames[16] {};
|
||||
int frame_count = static_cast<int>(std::size(frames));
|
||||
SysStackWalk(frames, &frame_count);
|
||||
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
||||
void* frames[16] {};
|
||||
const auto frame_count =
|
||||
CaptureStackBackTrace(0, static_cast<DWORD>(std::size(frames)), frames, nullptr);
|
||||
const auto image_base = reinterpret_cast<uintptr_t>(GetModuleHandleW(nullptr));
|
||||
for (uint16_t i = 0; i < frame_count; i++) {
|
||||
for (int i = 0; i < frame_count; i++) {
|
||||
const auto address = reinterpret_cast<uintptr_t>(frames[i]);
|
||||
std::fprintf(stderr, " frame[%u]=0x%016" PRIxPTR " image_rva=0x%016" PRIxPTR "\n", i,
|
||||
std::fprintf(stderr, " frame[%d]=0x%016" PRIxPTR " image_rva=0x%016" PRIxPTR "\n", i,
|
||||
address, address >= image_base ? address - image_base : 0);
|
||||
}
|
||||
#elif !defined(__APPLE__)
|
||||
void* frames[16] {};
|
||||
const int frame_count = ::backtrace(frames, static_cast<int>(std::size(frames)));
|
||||
#else
|
||||
::backtrace_symbols_fd(frames, frame_count, STDERR_FILENO);
|
||||
#endif
|
||||
#endif
|
||||
std::fflush(stderr);
|
||||
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
||||
|
||||
+7
-7
@@ -516,7 +516,7 @@ ImageId TextureCache::GetNullImage(const ImageDesc& desc) {
|
||||
info.pitch = 1;
|
||||
info.bytes_per_block = std::max(desc.info.bytes_per_block, 1u);
|
||||
info.samples = 1;
|
||||
info.tile_mode = Prospero::GpuEnumValue(Prospero::TileMode::kLinear);
|
||||
info.tile_mode = Prospero::TileMode::kLinear;
|
||||
info.mip_layout[0] = {0, info.bytes_per_block, 1, 1};
|
||||
const auto id = InsertImage(info);
|
||||
m_null_images.emplace(format, id);
|
||||
@@ -822,7 +822,8 @@ TextureCache::OverlapResult TextureCache::ResolveOverlap(const ImageInfo& reques
|
||||
requested.data.address, requested.resources.levels, requested.resources.layers,
|
||||
cached.info.resources.levels, cached.info.resources.layers, requested.data.size,
|
||||
cached.info.data.size, static_cast<uint32_t>(requested.type),
|
||||
static_cast<uint32_t>(cached.info.type), requested.tile_mode, cached.info.tile_mode);
|
||||
static_cast<uint32_t>(cached.info.type), static_cast<uint32_t>(requested.tile_mode),
|
||||
static_cast<uint32_t>(cached.info.tile_mode));
|
||||
}
|
||||
|
||||
if (requested.data.address > cached.info.data.address) {
|
||||
@@ -905,7 +906,7 @@ TextureCache::ColorTransferPlan
|
||||
TextureCache::BuildColorTransfer(const Image& image, BindingType binding,
|
||||
TransferDirection direction) const {
|
||||
const auto& info = image.info;
|
||||
uint32_t format = info.guest_format;
|
||||
auto format = info.guest_format;
|
||||
uint32_t layers = info.TransferLayers();
|
||||
bool volume = info.IsVolume();
|
||||
bool allow_depth_tile = direction == TransferDirection::Upload;
|
||||
@@ -957,8 +958,7 @@ TextureCache::BuildColorTransfer(const Image& image, BindingType binding,
|
||||
info.resources.levels, layers, info.tile_mode,
|
||||
info.data.size, allow_depth_tile, volume, owner);
|
||||
plan.regions = TextureBuildImageCopies(plan.layout);
|
||||
plan.tiled = static_cast<Prospero::TileMode>(plan.layout.surface.description.tile_mode) !=
|
||||
Prospero::TileMode::kLinear;
|
||||
plan.tiled = plan.layout.surface.description.tile_mode != Prospero::TileMode::kLinear;
|
||||
if (plan.tiled) {
|
||||
if (!TextureBuildGpuTileInfos(info.data.size, plan.regions, plan.layout,
|
||||
info.resources.levels, plan.tiles)) {
|
||||
@@ -1007,7 +1007,7 @@ void TextureCache::UploadImage(Image& image, const ImageDesc& desc, Buffer& sour
|
||||
" size=0x%016" PRIx64 " format=%u tile=%u family=%u extent=%ux%ux%u "
|
||||
"pitch=%u levels=%u layers=%u samples=%u\n",
|
||||
static_cast<uint32_t>(desc.type), info.data.address, info.data.size,
|
||||
info.guest_format, info.tile_mode,
|
||||
static_cast<uint32_t>(info.guest_format), static_cast<uint32_t>(info.tile_mode),
|
||||
static_cast<uint32_t>(plan.layout.surface.texture.block.family), info.extent.width,
|
||||
info.extent.height, info.extent.depth, info.pitch, info.resources.levels,
|
||||
info.resources.layers, info.samples);
|
||||
@@ -1045,7 +1045,7 @@ void TextureCache::UploadImage(Image& image, const ImageDesc& desc, Buffer& sour
|
||||
copy.bufferImageHeight = info.extent.height;
|
||||
copy.imageSubresource = {vk::ImageAspectFlagBits::eDepth, 0, layer, 1};
|
||||
copy.imageExtent = {info.extent.width, info.extent.height, 1};
|
||||
if (static_cast<Prospero::TileMode>(info.tile_mode) != Prospero::TileMode::kLinear) {
|
||||
if (info.tile_mode != Prospero::TileMode::kLinear) {
|
||||
tiles.push_back({block.family, block.bytes_per_element, offset, full_slice_size, offset,
|
||||
full_slice_size, 0, info.extent.width, info.extent.height, 1,
|
||||
info.pitch});
|
||||
|
||||
@@ -101,8 +101,9 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, RenderCommandB
|
||||
" attrib3_tile=0x%08" PRIx32 " attrib3_dim=0x%08" PRIx32 " fmt=0x%08" PRIx32
|
||||
" nfmt=0x%08" PRIx32 " order=0x%08" PRIx32 "\n",
|
||||
rt_slot, rt.base.addr, mask, rt.attrib2.width, rt.attrib2.height,
|
||||
rt.attrib3.tile_mode, rt.attrib3.dimension, rt.info.format, rt.info.channel_type,
|
||||
rt.info.channel_order);
|
||||
static_cast<uint32_t>(rt.attrib3.tile_mode), rt.attrib3.dimension,
|
||||
static_cast<uint32_t>(rt.info.format), static_cast<uint32_t>(rt.info.channel_type),
|
||||
static_cast<uint32_t>(rt.info.channel_order));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,17 +130,16 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, RenderCommandB
|
||||
if (volume && samples != 1) {
|
||||
EXIT("multisampled 3D render targets are unsupported\n");
|
||||
}
|
||||
const uint32_t depth = volume ? rt.attrib3.depth + 1u : 1u;
|
||||
const bool standard64 =
|
||||
rt.attrib3.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kStandard64KB);
|
||||
const uint32_t depth = volume ? rt.attrib3.depth + 1u : 1u;
|
||||
const bool standard64 = rt.attrib3.tile_mode == Prospero::TileMode::kStandard64KB;
|
||||
|
||||
switch (rt.attrib3.tile_mode) {
|
||||
case Prospero::GpuEnumValue(Prospero::TileMode::kLinear):
|
||||
case Prospero::GpuEnumValue(Prospero::TileMode::kStandard64KB):
|
||||
case Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget):
|
||||
case Prospero::TileMode::kLinear:
|
||||
case Prospero::TileMode::kStandard64KB:
|
||||
case Prospero::TileMode::kRenderTarget:
|
||||
tile = !RenderIsColorTileModeLinear(rt.attrib3.tile_mode);
|
||||
break;
|
||||
default: EXIT("unknown tile mode: %u\n", rt.attrib3.tile_mode);
|
||||
default: EXIT("unknown tile mode: %u\n", static_cast<uint32_t>(rt.attrib3.tile_mode));
|
||||
}
|
||||
if (!tile && levels > 1) {
|
||||
EXIT("linear mipmapped render targets are unsupported\n");
|
||||
@@ -180,8 +180,8 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, RenderCommandB
|
||||
if (volume) {
|
||||
pitch = TileGetTexturePitch(transfer_format, width, rt.attrib3.tile_mode);
|
||||
} else if (standard64) {
|
||||
pitch = TileGetTexturePitch(Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float),
|
||||
width, rt.attrib3.tile_mode);
|
||||
pitch =
|
||||
TileGetTexturePitch(Prospero::BufferFormat::k32Float, width, rt.attrib3.tile_mode);
|
||||
} else {
|
||||
pitch = TileGetRenderTargetPitch(width, bytes_per_element, rt.attrib.num_fragments);
|
||||
}
|
||||
@@ -207,7 +207,7 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, RenderCommandB
|
||||
1};
|
||||
if (!tile || !TileGetTiledTextureLayout(description, volume_layout)) {
|
||||
EXIT("unsupported 3D render-target layout: %ux%ux%u levels=%u tile=%u\n", width, height,
|
||||
depth, levels, rt.attrib3.tile_mode);
|
||||
depth, levels, static_cast<uint32_t>(rt.attrib3.tile_mode));
|
||||
}
|
||||
size = volume_layout.block_slice_size;
|
||||
backing_size = volume_layout.total_size;
|
||||
@@ -215,9 +215,8 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, RenderCommandB
|
||||
TileSizeAlign layout {};
|
||||
bool valid_layout = false;
|
||||
if (standard64) {
|
||||
TileGetTextureSize(Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float), width,
|
||||
height, levels, rt.attrib3.tile_mode, &layout, mip_sizes,
|
||||
mip_padded);
|
||||
TileGetTextureSize(Prospero::BufferFormat::k32Float, width, height, levels,
|
||||
rt.attrib3.tile_mode, &layout, mip_sizes, mip_padded);
|
||||
valid_layout = layout.size != 0 && layout.align == 65536;
|
||||
} else {
|
||||
valid_layout =
|
||||
@@ -278,8 +277,9 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, RenderCommandB
|
||||
" extent=%ux%ux%u view_mip=%u view_extent=%ux%u levels=%u pitch=%u"
|
||||
" fmt=0x%08" PRIx32 " nfmt=0x%08" PRIx32 " order=0x%08" PRIx32 " samples=%u tile=%s\n",
|
||||
rt_slot, rt.base.addr, backing_size, width, height, depth, rt.view.current_mip_level,
|
||||
view_extent.width, view_extent.height, levels, pitch, rt.info.format,
|
||||
rt.info.channel_type, rt.info.channel_order, samples, tile ? "tiled" : "linear");
|
||||
view_extent.width, view_extent.height, levels, pitch,
|
||||
static_cast<uint32_t>(rt.info.format), static_cast<uint32_t>(rt.info.channel_type),
|
||||
static_cast<uint32_t>(rt.info.channel_order), samples, tile ? "tiled" : "linear");
|
||||
}
|
||||
|
||||
TextureCache::ImageDesc desc {};
|
||||
|
||||
@@ -76,8 +76,8 @@ void uc_print(const char* func, const HW::UserConfig& uc) {
|
||||
"\t en_user_vgpr1 = %s\n"
|
||||
"\t en_user_vgpr2 = %s\n"
|
||||
"\t en_user_vgpr3 = %s\n",
|
||||
uc.GetPrimType(), uc.GetIndexOffset(), uc.GetObjectId(), ge_cntl.primitive_group_size,
|
||||
ge_cntl.vertex_group_size, user_en.vgpr1 ? "true" : "false",
|
||||
static_cast<uint32_t>(uc.GetPrimType()), uc.GetIndexOffset(), uc.GetObjectId(),
|
||||
ge_cntl.primitive_group_size, ge_cntl.vertex_group_size, user_en.vgpr1 ? "true" : "false",
|
||||
user_en.vgpr2 ? "true" : "false", user_en.vgpr3 ? "true" : "false");
|
||||
}
|
||||
|
||||
@@ -141,11 +141,12 @@ std::vector<std::string> rt_print(const char* func, const HW::RenderTarget& rt)
|
||||
fmt::format("\t info.cmask_addr_type = 0x{:08x}\n", rt.info.cmask_addr_type));
|
||||
dst.push_back(fmt::format("\t info.alt_tile_mode = {}\n",
|
||||
rt.info.alt_tile_mode ? "true" : "false"));
|
||||
dst.push_back(fmt::format("\t info.format = 0x{:08x}\n", rt.info.format));
|
||||
dst.push_back(
|
||||
fmt::format("\t info.channel_type = 0x{:08x}\n", rt.info.channel_type));
|
||||
dst.push_back(
|
||||
fmt::format("\t info.channel_order = 0x{:08x}\n", rt.info.channel_order));
|
||||
dst.push_back(fmt::format("\t info.format = 0x{:08x}\n",
|
||||
static_cast<uint32_t>(rt.info.format)));
|
||||
dst.push_back(fmt::format("\t info.channel_type = 0x{:08x}\n",
|
||||
static_cast<uint32_t>(rt.info.channel_type)));
|
||||
dst.push_back(fmt::format("\t info.channel_order = 0x{:08x}\n",
|
||||
static_cast<uint32_t>(rt.info.channel_order)));
|
||||
dst.push_back(fmt::format("\t info.blend_bypa = {}\n",
|
||||
rt.info.blend_bypass ? "true" : "false"));
|
||||
dst.push_back(fmt::format("\t info.blend_clamp = {}\n",
|
||||
@@ -154,10 +155,10 @@ std::vector<std::string> rt_print(const char* func, const HW::RenderTarget& rt)
|
||||
rt.info.round_mode ? "true" : "false"));
|
||||
dst.push_back(fmt::format("\t attrib.force_dest_alpha_to_one = {}\n",
|
||||
rt.attrib.force_dest_alpha_to_one ? "true" : "false"));
|
||||
dst.push_back(
|
||||
fmt::format("\t attrib.tile_mode = 0x{:08x}\n", rt.attrib.tile_mode));
|
||||
dst.push_back(
|
||||
fmt::format("\t attrib.fmask_tile_mode = 0x{:08x}\n", rt.attrib.fmask_tile_mode));
|
||||
dst.push_back(fmt::format("\t attrib.tile_mode = 0x{:08x}\n",
|
||||
static_cast<uint32_t>(rt.attrib.tile_mode)));
|
||||
dst.push_back(fmt::format("\t attrib.fmask_tile_mode = 0x{:08x}\n",
|
||||
static_cast<uint32_t>(rt.attrib.fmask_tile_mode)));
|
||||
dst.push_back(
|
||||
fmt::format("\t attrib.num_samples = 0x{:08x}\n", rt.attrib.num_samples));
|
||||
dst.push_back(
|
||||
@@ -168,8 +169,8 @@ std::vector<std::string> rt_print(const char* func, const HW::RenderTarget& rt)
|
||||
dst.push_back(
|
||||
fmt::format("\t attrib2.num_mip_levels = 0x{:08x}\n", rt.attrib2.num_mip_levels));
|
||||
dst.push_back(fmt::format("\t attrib3.depth = 0x{:08x}\n", rt.attrib3.depth));
|
||||
dst.push_back(
|
||||
fmt::format("\t attrib3.tile_mode = 0x{:08x}\n", rt.attrib3.tile_mode));
|
||||
dst.push_back(fmt::format("\t attrib3.tile_mode = 0x{:08x}\n",
|
||||
static_cast<uint32_t>(rt.attrib3.tile_mode)));
|
||||
dst.push_back(
|
||||
fmt::format("\t attrib3.dimension = 0x{:08x}\n", rt.attrib3.dimension));
|
||||
dst.push_back(fmt::format("\t attrib3.cmask_pipe_aligned = {}\n",
|
||||
@@ -212,22 +213,22 @@ std::vector<std::string> rt_print(const char* func, const HW::RenderTarget& rt)
|
||||
return dst;
|
||||
}
|
||||
|
||||
static bool RenderIsColorTileMode(uint32_t tile_mode) {
|
||||
static bool RenderIsColorTileMode(Prospero::TileMode tile_mode) {
|
||||
// AGC CxRenderTarget::TileMode shifted by CB_COLOR*_ATTRIB3.COLOR_SW_MODE.
|
||||
switch (tile_mode) {
|
||||
case Prospero::GpuEnumValue(Prospero::TileMode::kLinear):
|
||||
case Prospero::GpuEnumValue(Prospero::TileMode::kStandard256B):
|
||||
case Prospero::GpuEnumValue(Prospero::TileMode::kStandard4KB):
|
||||
case Prospero::GpuEnumValue(Prospero::TileMode::kStandard64KB):
|
||||
case Prospero::GpuEnumValue(Prospero::TileMode::kPrt):
|
||||
case Prospero::GpuEnumValue(Prospero::TileMode::kDepth):
|
||||
case Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget): return true;
|
||||
case Prospero::TileMode::kLinear:
|
||||
case Prospero::TileMode::kStandard256B:
|
||||
case Prospero::TileMode::kStandard4KB:
|
||||
case Prospero::TileMode::kStandard64KB:
|
||||
case Prospero::TileMode::kPrt:
|
||||
case Prospero::TileMode::kDepth:
|
||||
case Prospero::TileMode::kRenderTarget: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderIsColorTileModeLinear(uint32_t tile_mode) {
|
||||
return tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kLinear);
|
||||
bool RenderIsColorTileModeLinear(Prospero::TileMode tile_mode) {
|
||||
return tile_mode == Prospero::TileMode::kLinear;
|
||||
}
|
||||
|
||||
static bool RenderIsColorDimension(uint32_t dimension) {
|
||||
@@ -361,7 +362,8 @@ static void RtCheck(const HW::RenderTarget& rt) {
|
||||
}
|
||||
}
|
||||
if (!RenderIsColorTileMode(rt.attrib3.tile_mode)) {
|
||||
EXIT("unknown PS5 render-target tile mode: 0x%08" PRIx32 "\n", rt.attrib3.tile_mode);
|
||||
EXIT("unknown PS5 render-target tile mode: 0x%08" PRIx32 "\n",
|
||||
static_cast<uint32_t>(rt.attrib3.tile_mode));
|
||||
}
|
||||
if (!RenderIsColorDimension(rt.attrib3.dimension)) {
|
||||
EXIT("unknown PS5 render-target dimension: 0x%08" PRIx32 "\n", rt.attrib3.dimension);
|
||||
@@ -456,13 +458,14 @@ static void ZPrint(const char* func, const HW::DepthRenderTarget& z) {
|
||||
"\t height = 0x%08" PRIx32 "\n"
|
||||
"\t size.x_max = 0x%04" PRIx16 "\n"
|
||||
"\t size.y_max = 0x%04" PRIx16 "\n",
|
||||
z.z_info.format, z.z_info.num_samples,
|
||||
Prospero::GpuEnumValue(z.z_info.texture_compatibility),
|
||||
static_cast<uint32_t>(z.z_info.format), z.z_info.num_samples,
|
||||
static_cast<uint32_t>(z.z_info.texture_compatibility),
|
||||
z.z_info.htile_acceleration ? "true" : "false",
|
||||
z.z_info.expclear_enabled ? "true" : "false",
|
||||
Prospero::GpuEnumValue(z.z_info.z_compare_base),
|
||||
static_cast<uint32_t>(z.z_info.z_compare_base),
|
||||
z.z_info.partially_resident ? "true" : "false", z.z_info.max_mip_level,
|
||||
z.stencil_info.format, Prospero::GpuEnumValue(z.stencil_info.texture_compatibility),
|
||||
static_cast<uint32_t>(z.stencil_info.format),
|
||||
static_cast<uint32_t>(z.stencil_info.texture_compatibility),
|
||||
z.stencil_info.htile_stencil_disabled ? "true" : "false",
|
||||
z.stencil_info.expclear_enabled ? "true" : "false",
|
||||
z.stencil_info.partially_resident ? "true" : "false", z.depth_info.addr5_swizzle_mask,
|
||||
@@ -491,15 +494,16 @@ static void ZCheck(const HW::DepthRenderTarget& z, const HW::DepthControl& dc,
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(!z.z_info.HasValidTextureCompatibility());
|
||||
EXIT_NOT_IMPLEMENTED(!z.stencil_info.HasValidTextureCompatibility());
|
||||
if (z.z_info.format == 0) {
|
||||
EXIT_NOT_IMPLEMENTED(z.z_info.format != 0);
|
||||
if (z.z_info.format == Prospero::DepthFormat::kInvalid) {
|
||||
EXIT_NOT_IMPLEMENTED(z.z_info.format != Prospero::DepthFormat::kInvalid);
|
||||
EXIT_NOT_IMPLEMENTED(z.z_info.num_samples != 0);
|
||||
EXIT_NOT_IMPLEMENTED(z.z_info.htile_acceleration != false);
|
||||
EXIT_NOT_IMPLEMENTED(z.z_info.expclear_enabled != false);
|
||||
EXIT_NOT_IMPLEMENTED(z.z_info.partially_resident != false);
|
||||
EXIT_NOT_IMPLEMENTED(z.z_info.max_mip_level != 0);
|
||||
} else {
|
||||
EXIT_NOT_IMPLEMENTED(z.z_info.format != 0x00000001 && z.z_info.format != 0x00000003);
|
||||
EXIT_NOT_IMPLEMENTED(z.z_info.format != Prospero::DepthFormat::kZ16 &&
|
||||
z.z_info.format != Prospero::DepthFormat::kZ32F);
|
||||
if (z.z_info.num_samples != 0x00000000) {
|
||||
static bool logged = false;
|
||||
if (!logged) {
|
||||
@@ -513,16 +517,17 @@ static void ZCheck(const HW::DepthRenderTarget& z, const HW::DepthControl& dc,
|
||||
EXIT_NOT_IMPLEMENTED(z.z_info.max_mip_level != 0);
|
||||
}
|
||||
|
||||
if (z.stencil_info.format == 0) {
|
||||
if (z.stencil_info.format == Prospero::StencilFormat::kInvalid) {
|
||||
EXIT_NOT_IMPLEMENTED(z.stencil_info.expclear_enabled != false);
|
||||
EXIT_NOT_IMPLEMENTED(z.stencil_info.partially_resident != false);
|
||||
} else {
|
||||
EXIT_NOT_IMPLEMENTED(z.stencil_info.format != 0x00000001);
|
||||
EXIT_NOT_IMPLEMENTED(z.stencil_info.format != Prospero::StencilFormat::k8UInt);
|
||||
EXIT_NOT_IMPLEMENTED(z.stencil_info.expclear_enabled != false);
|
||||
EXIT_NOT_IMPLEMENTED(z.stencil_info.partially_resident != false);
|
||||
}
|
||||
|
||||
if (z.z_info.format != 0 || z.stencil_info.format != 0) {
|
||||
if (z.z_info.format != Prospero::DepthFormat::kInvalid ||
|
||||
z.stencil_info.format != Prospero::StencilFormat::kInvalid) {
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(z.depth_info.addr5_swizzle_mask != 0x00000000);
|
||||
EXIT_NOT_IMPLEMENTED(z.depth_info.array_mode != 0x00000000);
|
||||
@@ -557,7 +562,8 @@ static void ZCheck(const HW::DepthRenderTarget& z, const HW::DepthControl& dc,
|
||||
EXIT_NOT_IMPLEMENTED(z.z_read_base_addr != z.z_write_base_addr);
|
||||
EXIT_NOT_IMPLEMENTED(z.stencil_read_base_addr != z.stencil_write_base_addr);
|
||||
EXIT_NOT_IMPLEMENTED(z.z_write_base_addr == 0);
|
||||
if (z.stencil_info.format != 0 && z.stencil_write_base_addr == 0) {
|
||||
if (z.stencil_info.format != Prospero::StencilFormat::kInvalid &&
|
||||
z.stencil_write_base_addr == 0) {
|
||||
LOGF("\t warning: stencil format is set without a stencil base address, continuing "
|
||||
"without stencil attachment\n");
|
||||
}
|
||||
@@ -1218,8 +1224,9 @@ void hw_check(const RenderCommandBuffer& buffer) {
|
||||
const auto& mrt = hw.GetRenderTarget(i);
|
||||
LOGF("\t RT%u addr=0x%010" PRIx64 " mask=0x%x fmt=0x%08" PRIx32
|
||||
" width=%u height=%u tile=%u\n",
|
||||
i, mrt.base.addr, (hw.GetRenderTargetMask() >> (i * 4u)) & 0x0fu, mrt.info.format,
|
||||
mrt.attrib2.width + 1, mrt.attrib2.height + 1, mrt.attrib3.tile_mode);
|
||||
i, mrt.base.addr, (hw.GetRenderTargetMask() >> (i * 4u)) & 0x0fu,
|
||||
static_cast<uint32_t>(mrt.info.format), mrt.attrib2.width + 1,
|
||||
mrt.attrib2.height + 1, static_cast<uint32_t>(mrt.attrib3.tile_mode));
|
||||
}
|
||||
}
|
||||
if (rc.depth_clear_enable && hw.GetDepthClearValue() != 0.0f &&
|
||||
|
||||
@@ -34,7 +34,7 @@ void uc_print(const char* func, const HW::UserConfig& uc);
|
||||
void uc_check(const HW::UserConfig& uc);
|
||||
void sh_print(const char* func, const HW::Shader& uc);
|
||||
std::vector<std::string> rt_print(const char* func, const HW::RenderTarget& rt);
|
||||
bool RenderIsColorTileModeLinear(uint32_t tile_mode);
|
||||
bool RenderIsColorTileModeLinear(Prospero::TileMode tile_mode);
|
||||
void hw_print(const RenderCommandBuffer& buffer);
|
||||
void hw_check(const RenderCommandBuffer& buffer);
|
||||
void LogDrawPhase(const char* draw_name, const char* phase);
|
||||
|
||||
@@ -67,9 +67,8 @@ static vk::StencilOp ConvertStencilOp(uint8_t value, uint8_t write_mask, uint8_t
|
||||
}
|
||||
|
||||
static bool UsesStencilOpValue(uint8_t fail, uint8_t pass, uint8_t depth_fail) {
|
||||
return fail == Prospero::GpuEnumValue(Prospero::StencilOp::kReplaceOp) ||
|
||||
pass == Prospero::GpuEnumValue(Prospero::StencilOp::kReplaceOp) ||
|
||||
depth_fail == Prospero::GpuEnumValue(Prospero::StencilOp::kReplaceOp);
|
||||
constexpr auto replace_op = static_cast<uint8_t>(Prospero::StencilOp::kReplaceOp);
|
||||
return fail == replace_op || pass == replace_op || depth_fail == replace_op;
|
||||
}
|
||||
|
||||
[[nodiscard]] static vk::Format ResolveHostDepthAttachmentFormat(const RenderCommandBuffer& buffer,
|
||||
@@ -103,15 +102,14 @@ void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandB
|
||||
RenderDepthInfo& r) {
|
||||
KYTY_PROFILER_FUNCTION();
|
||||
(void)submit_id;
|
||||
const auto& hw = buffer.GetRegisters();
|
||||
const auto& z = hw.GetDepthRenderTarget();
|
||||
const auto& rc = hw.GetRenderControl();
|
||||
const auto& dc = hw.GetDepthControl();
|
||||
const auto& sc = hw.GetStencilControl();
|
||||
const auto& sm = hw.GetStencilMask();
|
||||
const bool has_stencil =
|
||||
z.stencil_info.format != Prospero::GpuEnumValue(Prospero::StencilFormat::kInvalid);
|
||||
const bool depth_active =
|
||||
const auto& hw = buffer.GetRegisters();
|
||||
const auto& z = hw.GetDepthRenderTarget();
|
||||
const auto& rc = hw.GetRenderControl();
|
||||
const auto& dc = hw.GetDepthControl();
|
||||
const auto& sc = hw.GetStencilControl();
|
||||
const auto& sm = hw.GetStencilMask();
|
||||
const bool has_stencil = z.stencil_info.format != Prospero::StencilFormat::kInvalid;
|
||||
const bool depth_active =
|
||||
dc.z_enable || dc.z_write_enable || dc.depth_bounds_enable || rc.depth_clear_enable;
|
||||
const bool stencil_active = has_stencil && (dc.stencil_enable || rc.stencil_clear_enable);
|
||||
if (!depth_active && !stencil_active) {
|
||||
@@ -122,9 +120,8 @@ void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandB
|
||||
DepthFatal("invalid PS5 depth texture-compatibility encoding");
|
||||
}
|
||||
const bool attachment_unbound =
|
||||
z.z_info.format == Prospero::GpuEnumValue(Prospero::DepthFormat::kInvalid) &&
|
||||
z.stencil_info.format == Prospero::GpuEnumValue(Prospero::StencilFormat::kInvalid) &&
|
||||
z.z_info.num_samples == 0 &&
|
||||
z.z_info.format == Prospero::DepthFormat::kInvalid &&
|
||||
z.stencil_info.format == Prospero::StencilFormat::kInvalid && z.z_info.num_samples == 0 &&
|
||||
z.z_info.texture_compatibility == Prospero::TextureCompatiblePlaneCompression::kDisable &&
|
||||
!z.z_info.expclear_enabled && !z.z_info.partially_resident && z.z_info.max_mip_level == 0 &&
|
||||
z.stencil_info.texture_compatibility == Prospero::TextureCompatibleStencil::kDisable &&
|
||||
@@ -186,8 +183,8 @@ void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandB
|
||||
DepthFatal("unsupported depth register state");
|
||||
}
|
||||
if (has_stencil) {
|
||||
if (z.stencil_info.format != Prospero::GpuEnumValue(Prospero::StencilFormat::k8UInt) ||
|
||||
!htile_stencil_compat || z.stencil_read_base_addr == 0 ||
|
||||
if (z.stencil_info.format != Prospero::StencilFormat::k8UInt || !htile_stencil_compat ||
|
||||
z.stencil_read_base_addr == 0 ||
|
||||
z.stencil_write_base_addr != z.stencil_read_base_addr ||
|
||||
(z.stencil_read_base_addr & 0xffffu) != 0 || z.depth_view.stencil_write_disable) {
|
||||
DepthFatal("unsupported stencil attachment state");
|
||||
@@ -229,7 +226,7 @@ void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandB
|
||||
DepthFatal("no host depth/stencil format supports required usage for %s",
|
||||
VulkanToString(ideal_format).c_str());
|
||||
}
|
||||
const uint32_t guest_format = Prospero::GpuEnumValue(policy->guest_format);
|
||||
const auto guest_format = policy->guest_format;
|
||||
const uint32_t bytes = policy->bytes_per_element;
|
||||
const auto pitch = TileGetDepthPitch(width, bytes, z.z_info.num_samples);
|
||||
if (z.pitch_height_valid && ((static_cast<uint64_t>(z.pitch_div8_minus1) + 1u) * 8u != pitch ||
|
||||
@@ -343,7 +340,7 @@ void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandB
|
||||
desc.info.pitch = pitch;
|
||||
desc.info.bytes_per_block = bytes;
|
||||
desc.info.samples = samples;
|
||||
desc.info.tile_mode = Prospero::GpuEnumValue(Prospero::TileMode::kDepth);
|
||||
desc.info.tile_mode = Prospero::TileMode::kDepth;
|
||||
desc.info.mip_layout[0] = {0, r.depth_buffer_size, pitch, height};
|
||||
desc.info.metadata.range = {r.htile_buffer_vaddr, r.htile_buffer_size};
|
||||
desc.info.metadata.kind = has_htile ? ImageMetadataKind::Htile : ImageMetadataKind::None;
|
||||
|
||||
@@ -646,13 +646,13 @@ void Validate(const ImageInfo& info) {
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t RenderTargetTransferFormat(uint32_t bytes_per_element) {
|
||||
Prospero::BufferFormat RenderTargetTransferFormat(uint32_t bytes_per_element) {
|
||||
switch (bytes_per_element) {
|
||||
case 1: return Prospero::GpuEnumValue(Prospero::BufferFormat::k8UNorm);
|
||||
case 2: return Prospero::GpuEnumValue(Prospero::BufferFormat::k16UNorm);
|
||||
case 4: return Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float);
|
||||
case 8: return Prospero::GpuEnumValue(Prospero::BufferFormat::k16_16_16_16Float);
|
||||
case 16: return Prospero::GpuEnumValue(Prospero::BufferFormat::k32_32_32_32Float);
|
||||
case 1: return Prospero::BufferFormat::k8UNorm;
|
||||
case 2: return Prospero::BufferFormat::k16UNorm;
|
||||
case 4: return Prospero::BufferFormat::k32Float;
|
||||
case 8: return Prospero::BufferFormat::k16_16_16_16Float;
|
||||
case 16: return Prospero::BufferFormat::k32_32_32_32Float;
|
||||
default: EXIT("unsupported render-target element size: %u\n", bytes_per_element);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,8 +188,8 @@ private:
|
||||
|
||||
namespace ImageOps {
|
||||
|
||||
void Validate(const ImageInfo& info);
|
||||
[[nodiscard]] uint32_t RenderTargetTransferFormat(uint32_t bytes_per_element);
|
||||
void Validate(const ImageInfo& info);
|
||||
[[nodiscard]] Prospero::BufferFormat RenderTargetTransferFormat(uint32_t bytes_per_element);
|
||||
|
||||
} // namespace ImageOps
|
||||
|
||||
|
||||
@@ -67,14 +67,14 @@ struct ImageInfo {
|
||||
ImageMetadataInfo metadata;
|
||||
uint32_t htile_clear_mask = UINT32_MAX;
|
||||
vk::Format pixel_format = vk::Format::eUndefined;
|
||||
uint32_t guest_format = 0;
|
||||
Prospero::BufferFormat guest_format = Prospero::BufferFormat::kInvalid;
|
||||
Prospero::ImageType type = Prospero::ImageType::kColor2D;
|
||||
vk::Extent3D extent = {1, 1, 1};
|
||||
ImageSubresources resources;
|
||||
uint32_t pitch = 0;
|
||||
uint32_t bytes_per_block = 0;
|
||||
uint32_t samples = 1;
|
||||
uint32_t tile_mode = 0;
|
||||
Prospero::TileMode tile_mode = Prospero::TileMode::kLinear;
|
||||
bool bgra16 = false;
|
||||
std::array<ImageMipInfo, 16> mip_layout {};
|
||||
|
||||
@@ -86,9 +86,7 @@ struct ImageInfo {
|
||||
[[nodiscard]] bool IsBlock() const noexcept {
|
||||
return Prospero::BlockCompressedBytesPerBlock(guest_format) != 0;
|
||||
}
|
||||
[[nodiscard]] bool IsTiled() const noexcept {
|
||||
return tile_mode != Prospero::GpuEnumValue(Prospero::TileMode::kLinear);
|
||||
}
|
||||
[[nodiscard]] bool IsTiled() const noexcept { return tile_mode != Prospero::TileMode::kLinear; }
|
||||
[[nodiscard]] constexpr bool IsVolume() const noexcept {
|
||||
return type == Prospero::ImageType::kColor3D;
|
||||
}
|
||||
@@ -235,9 +233,9 @@ inline constexpr std::array<DepthFormatPolicy, 2> DEPTH_FORMAT_POLICIES {{
|
||||
}};
|
||||
|
||||
[[nodiscard]] inline constexpr const DepthFormatPolicy*
|
||||
FindDepthFormatPolicy(uint32_t depth_format) noexcept {
|
||||
FindDepthFormatPolicy(Prospero::DepthFormat depth_format) noexcept {
|
||||
for (const auto& policy: DEPTH_FORMAT_POLICIES) {
|
||||
if (Prospero::GpuEnumValue(policy.depth_format) == depth_format) {
|
||||
if (policy.depth_format == depth_format) {
|
||||
return &policy;
|
||||
}
|
||||
}
|
||||
@@ -245,9 +243,9 @@ FindDepthFormatPolicy(uint32_t depth_format) noexcept {
|
||||
}
|
||||
|
||||
[[nodiscard]] inline constexpr const DepthFormatPolicy*
|
||||
FindGuestDepthFormatPolicy(uint32_t guest_format) noexcept {
|
||||
FindGuestDepthFormatPolicy(Prospero::BufferFormat guest_format) noexcept {
|
||||
for (const auto& policy: DEPTH_FORMAT_POLICIES) {
|
||||
if (Prospero::GpuEnumValue(policy.guest_format) == guest_format) {
|
||||
if (policy.guest_format == guest_format) {
|
||||
return &policy;
|
||||
}
|
||||
}
|
||||
@@ -269,10 +267,11 @@ FindGuestDepthFormatPolicy(uint32_t guest_format) noexcept {
|
||||
return has_stencil ? policy.stencil_attachment_formats.front() : policy.depth_attachment_format;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline constexpr vk::Format DepthAttachmentFormat(uint32_t depth_format,
|
||||
uint32_t stencil_format) noexcept {
|
||||
[[nodiscard]] inline constexpr vk::Format
|
||||
DepthAttachmentFormat(Prospero::DepthFormat depth_format,
|
||||
Prospero::StencilFormat stencil_format) noexcept {
|
||||
bool has_stencil = false;
|
||||
switch (static_cast<Prospero::StencilFormat>(stencil_format)) {
|
||||
switch (stencil_format) {
|
||||
case Prospero::StencilFormat::kInvalid: break;
|
||||
case Prospero::StencilFormat::k8UInt: has_stencil = true; break;
|
||||
default: return vk::Format::eUndefined;
|
||||
@@ -318,9 +317,9 @@ inline bool ImageInfo::IsDepth() const noexcept {
|
||||
return std::bit_cast<uint32_t>(static_cast<float>(value) / 65535.0f);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline constexpr bool IsSupportedSampledDepthFormat(vk::Format image_format,
|
||||
uint32_t guest_format,
|
||||
vk::Format view_format) noexcept {
|
||||
[[nodiscard]] inline constexpr bool
|
||||
IsSupportedSampledDepthFormat(vk::Format image_format, Prospero::BufferFormat guest_format,
|
||||
vk::Format view_format) noexcept {
|
||||
const auto* policy = FindGuestDepthFormatPolicy(guest_format);
|
||||
return policy != nullptr && view_format == policy->sampled_view_format &&
|
||||
(image_format == policy->depth_attachment_format ||
|
||||
@@ -330,8 +329,7 @@ inline bool ImageInfo::IsDepth() const noexcept {
|
||||
[[nodiscard]] inline constexpr bool IsSupportedSampledDepthFormat(vk::Format image_format,
|
||||
vk::Format view_format) noexcept {
|
||||
for (const auto& policy: DEPTH_FORMAT_POLICIES) {
|
||||
if (IsSupportedSampledDepthFormat(image_format, Prospero::GpuEnumValue(policy.guest_format),
|
||||
view_format)) {
|
||||
if (IsSupportedSampledDepthFormat(image_format, policy.guest_format, view_format)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -383,10 +381,10 @@ CanUseVideoOutNativeWithoutUpload(VideoOutCompression compression, bool render_t
|
||||
}
|
||||
|
||||
struct VideoOutPixelFormatInfo {
|
||||
vk::Format format = vk::Format::eUndefined;
|
||||
uint32_t guest_format = 0;
|
||||
uint32_t bytes_per_element = 0;
|
||||
bool bgra16 = false;
|
||||
vk::Format format = vk::Format::eUndefined;
|
||||
Prospero::BufferFormat guest_format = Prospero::BufferFormat::kInvalid;
|
||||
uint32_t bytes_per_element = 0;
|
||||
bool bgra16 = false;
|
||||
};
|
||||
|
||||
struct VideoOutFormatPolicy {
|
||||
@@ -396,23 +394,17 @@ struct VideoOutFormatPolicy {
|
||||
|
||||
inline constexpr std::array<VideoOutFormatPolicy, 6> VIDEO_OUT_FORMAT_POLICIES {{
|
||||
{0x8000000022000000ull,
|
||||
{vk::Format::eR8G8B8A8Srgb, Prospero::GpuEnumValue(Prospero::BufferFormat::k8_8_8_8Srgb), 4,
|
||||
false}},
|
||||
{vk::Format::eR8G8B8A8Srgb, Prospero::BufferFormat::k8_8_8_8Srgb, 4, false}},
|
||||
{0x8000000000000000ull,
|
||||
{vk::Format::eB8G8R8A8Srgb, Prospero::GpuEnumValue(Prospero::BufferFormat::k8_8_8_8Srgb), 4,
|
||||
false}},
|
||||
{vk::Format::eB8G8R8A8Srgb, Prospero::BufferFormat::k8_8_8_8Srgb, 4, false}},
|
||||
{0x8100000022000000ull,
|
||||
{vk::Format::eA2B10G10R10UnormPack32,
|
||||
Prospero::GpuEnumValue(Prospero::BufferFormat::k10_10_10_2UNorm), 4, false}},
|
||||
{vk::Format::eA2B10G10R10UnormPack32, Prospero::BufferFormat::k10_10_10_2UNorm, 4, false}},
|
||||
{0x8100000000000000ull,
|
||||
{vk::Format::eA2R10G10B10UnormPack32,
|
||||
Prospero::GpuEnumValue(Prospero::BufferFormat::k10_10_10_2UNorm), 4, false}},
|
||||
{vk::Format::eA2R10G10B10UnormPack32, Prospero::BufferFormat::k10_10_10_2UNorm, 4, false}},
|
||||
{0xc001000622000000ull,
|
||||
{vk::Format::eR16G16B16A16Sfloat,
|
||||
Prospero::GpuEnumValue(Prospero::BufferFormat::k16_16_16_16Float), 8, false}},
|
||||
{vk::Format::eR16G16B16A16Sfloat, Prospero::BufferFormat::k16_16_16_16Float, 8, false}},
|
||||
{0xc001000600000000ull,
|
||||
{vk::Format::eR16G16B16A16Sfloat,
|
||||
Prospero::GpuEnumValue(Prospero::BufferFormat::k16_16_16_16Float), 8, true}},
|
||||
{vk::Format::eR16G16B16A16Sfloat, Prospero::BufferFormat::k16_16_16_16Float, 8, true}},
|
||||
}};
|
||||
|
||||
[[nodiscard]] inline bool DecodeVideoOutPixelFormat(uint64_t pixel_format,
|
||||
@@ -439,15 +431,15 @@ inline constexpr std::array<VideoOutFormatPolicy, 6> VIDEO_OUT_FORMAT_POLICIES {
|
||||
}
|
||||
|
||||
[[nodiscard]] inline constexpr bool
|
||||
IsSupportedDisplayRenderTargetTileMode(uint32_t tile_mode) noexcept {
|
||||
return tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget);
|
||||
IsSupportedDisplayRenderTargetTileMode(Prospero::TileMode tile_mode) noexcept {
|
||||
return tile_mode == Prospero::TileMode::kRenderTarget;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline constexpr bool IsSupportedStandard64RenderTarget(const ImageInfo& info) {
|
||||
if (info.tile_mode != Prospero::GpuEnumValue(Prospero::TileMode::kStandard64KB) ||
|
||||
info.data.address == 0 || (info.data.address & 0xffffu) != 0 || info.extent.width == 0 ||
|
||||
info.extent.height == 0 || info.bytes_per_block != 4 || info.resources.levels != 1 ||
|
||||
info.resources.layers != 1 || info.samples != 1) {
|
||||
if (info.tile_mode != Prospero::TileMode::kStandard64KB || info.data.address == 0 ||
|
||||
(info.data.address & 0xffffu) != 0 || info.extent.width == 0 || info.extent.height == 0 ||
|
||||
info.bytes_per_block != 4 || info.resources.levels != 1 || info.resources.layers != 1 ||
|
||||
info.samples != 1) {
|
||||
return false;
|
||||
}
|
||||
const auto expected_pitch =
|
||||
@@ -460,7 +452,7 @@ IsSupportedDisplayRenderTargetTileMode(uint32_t tile_mode) noexcept {
|
||||
}
|
||||
|
||||
[[nodiscard]] inline constexpr bool IsTiledRenderTarget(const ImageInfo& info) noexcept {
|
||||
return info.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) ||
|
||||
return info.tile_mode == Prospero::TileMode::kRenderTarget ||
|
||||
IsSupportedStandard64RenderTarget(info);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,156 +14,67 @@
|
||||
namespace Libs::Graphics {
|
||||
namespace {
|
||||
|
||||
struct RenderTargetFormatMapping {
|
||||
Prospero::ChannelLayout layout;
|
||||
Prospero::ChannelType type;
|
||||
Prospero::ChannelOrder order;
|
||||
RenderTargetFormatInfo info;
|
||||
// Rows are channel order; columns are the number of physical components minus one. Unused
|
||||
// selectors complete each entry to a permutation so logical write masks can be inverted.
|
||||
constexpr Prospero::ColorComponentMapping kRenderTargetColorMappings[4][4] = {
|
||||
{Prospero::ColorMappingRgba, Prospero::ColorMappingRgba, Prospero::ColorMappingRgba,
|
||||
Prospero::ColorMappingRgba},
|
||||
{Prospero::ColorMappingGr, Prospero::ColorMappingRabg, Prospero::ColorMappingRgab,
|
||||
Prospero::ColorMappingBgra},
|
||||
{Prospero::ColorMappingBgra, Prospero::ColorMappingGr, Prospero::ColorMappingBgra,
|
||||
Prospero::ColorMappingAbgr},
|
||||
{Prospero::ColorMappingAgba, Prospero::ColorMappingArbg, Prospero::ColorMappingAgbr,
|
||||
Prospero::ColorMappingArgb},
|
||||
};
|
||||
|
||||
constexpr RenderTargetFormatMapping kRenderTargetFormats[] = {
|
||||
{Prospero::ChannelLayout::k8,
|
||||
Prospero::ChannelType::kUInt,
|
||||
Prospero::ChannelOrder::kStandard,
|
||||
{vk::Format::eR8Uint, 1}},
|
||||
{Prospero::ChannelLayout::k8_8,
|
||||
Prospero::ChannelType::kUNorm,
|
||||
Prospero::ChannelOrder::kStandard,
|
||||
{vk::Format::eR8G8Unorm, 2}},
|
||||
{Prospero::ChannelLayout::k8_8_8_8,
|
||||
Prospero::ChannelType::kUNorm,
|
||||
Prospero::ChannelOrder::kStandard,
|
||||
{vk::Format::eR8G8B8A8Unorm, 4}},
|
||||
{Prospero::ChannelLayout::k8_8_8_8,
|
||||
Prospero::ChannelType::kSNorm,
|
||||
Prospero::ChannelOrder::kStandard,
|
||||
{vk::Format::eR8G8B8A8Snorm, 4}},
|
||||
{Prospero::ChannelLayout::k8_8_8_8,
|
||||
Prospero::ChannelType::kSrgb,
|
||||
Prospero::ChannelOrder::kStandard,
|
||||
{vk::Format::eR8G8B8A8Srgb, 4}},
|
||||
{Prospero::ChannelLayout::k8_8_8_8,
|
||||
Prospero::ChannelType::kUNorm,
|
||||
Prospero::ChannelOrder::kAlt,
|
||||
{vk::Format::eB8G8R8A8Unorm, 4}},
|
||||
{Prospero::ChannelLayout::k8_8_8_8,
|
||||
Prospero::ChannelType::kSNorm,
|
||||
Prospero::ChannelOrder::kAlt,
|
||||
{vk::Format::eB8G8R8A8Snorm, 4}},
|
||||
{Prospero::ChannelLayout::k8_8_8_8,
|
||||
Prospero::ChannelType::kSrgb,
|
||||
Prospero::ChannelOrder::kAlt,
|
||||
{vk::Format::eB8G8R8A8Srgb, 4}},
|
||||
{Prospero::ChannelLayout::k5_5_5_1,
|
||||
Prospero::ChannelType::kUNorm,
|
||||
Prospero::ChannelOrder::kStandard,
|
||||
{vk::Format::eR5G5B5A1UnormPack16, 2}},
|
||||
{Prospero::ChannelLayout::k4_4_4_4,
|
||||
Prospero::ChannelType::kUNorm,
|
||||
Prospero::ChannelOrder::kReversed,
|
||||
{vk::Format::eB4G4R4A4UnormPack16, 2}},
|
||||
{Prospero::ChannelLayout::k10_10_10_2,
|
||||
Prospero::ChannelType::kUNorm,
|
||||
Prospero::ChannelOrder::kStandard,
|
||||
{vk::Format::eA2B10G10R10UnormPack32, 4}},
|
||||
{Prospero::ChannelLayout::k10_10_10_2,
|
||||
Prospero::ChannelType::kUNorm,
|
||||
Prospero::ChannelOrder::kAlt,
|
||||
{vk::Format::eA2R10G10B10UnormPack32, 4}},
|
||||
{Prospero::ChannelLayout::k11_11_10,
|
||||
Prospero::ChannelType::kFloat,
|
||||
Prospero::ChannelOrder::kStandard,
|
||||
{vk::Format::eB10G11R11UfloatPack32, 4}},
|
||||
{Prospero::ChannelLayout::k5_6_5,
|
||||
Prospero::ChannelType::kUNorm,
|
||||
Prospero::ChannelOrder::kStandard,
|
||||
{vk::Format::eB5G6R5UnormPack16, 2}},
|
||||
{Prospero::ChannelLayout::k16,
|
||||
Prospero::ChannelType::kUNorm,
|
||||
Prospero::ChannelOrder::kStandard,
|
||||
{vk::Format::eR16Unorm, 2}},
|
||||
{Prospero::ChannelLayout::k16,
|
||||
Prospero::ChannelType::kUInt,
|
||||
Prospero::ChannelOrder::kStandard,
|
||||
{vk::Format::eR16Uint, 2}},
|
||||
{Prospero::ChannelLayout::k16,
|
||||
Prospero::ChannelType::kFloat,
|
||||
Prospero::ChannelOrder::kStandard,
|
||||
{vk::Format::eR16Sfloat, 2}},
|
||||
{Prospero::ChannelLayout::k16_16,
|
||||
Prospero::ChannelType::kUNorm,
|
||||
Prospero::ChannelOrder::kStandard,
|
||||
{vk::Format::eR16G16Unorm, 4}},
|
||||
{Prospero::ChannelLayout::k16_16,
|
||||
Prospero::ChannelType::kSNorm,
|
||||
Prospero::ChannelOrder::kStandard,
|
||||
{vk::Format::eR16G16Snorm, 4}},
|
||||
{Prospero::ChannelLayout::k16_16,
|
||||
Prospero::ChannelType::kUInt,
|
||||
Prospero::ChannelOrder::kStandard,
|
||||
{vk::Format::eR16G16Uint, 4}},
|
||||
{Prospero::ChannelLayout::k16_16,
|
||||
Prospero::ChannelType::kFloat,
|
||||
Prospero::ChannelOrder::kStandard,
|
||||
{vk::Format::eR16G16Sfloat, 4}},
|
||||
{Prospero::ChannelLayout::k16_16_16_16,
|
||||
Prospero::ChannelType::kUNorm,
|
||||
Prospero::ChannelOrder::kStandard,
|
||||
{vk::Format::eR16G16B16A16Unorm, 8}},
|
||||
{Prospero::ChannelLayout::k16_16_16_16,
|
||||
Prospero::ChannelType::kUInt,
|
||||
Prospero::ChannelOrder::kStandard,
|
||||
{vk::Format::eR16G16B16A16Uint, 8}},
|
||||
{Prospero::ChannelLayout::k16_16_16_16,
|
||||
Prospero::ChannelType::kFloat,
|
||||
Prospero::ChannelOrder::kStandard,
|
||||
{vk::Format::eR16G16B16A16Sfloat, 8}},
|
||||
{Prospero::ChannelLayout::k16_16_16_16,
|
||||
Prospero::ChannelType::kFloat,
|
||||
Prospero::ChannelOrder::kAlt,
|
||||
{vk::Format::eR16G16B16A16Sfloat, 8, Prospero::ColorMappingBgra}},
|
||||
{Prospero::ChannelLayout::k16_16_16_16,
|
||||
Prospero::ChannelType::kFloat,
|
||||
Prospero::ChannelOrder::kReversed,
|
||||
{vk::Format::eR16G16B16A16Sfloat, 8, Prospero::ColorMappingAbgr}},
|
||||
{Prospero::ChannelLayout::k32,
|
||||
Prospero::ChannelType::kFloat,
|
||||
Prospero::ChannelOrder::kStandard,
|
||||
{vk::Format::eR32Sfloat, 4}},
|
||||
{Prospero::ChannelLayout::k32_32,
|
||||
Prospero::ChannelType::kUInt,
|
||||
Prospero::ChannelOrder::kStandard,
|
||||
{vk::Format::eR32G32Uint, 8}},
|
||||
{Prospero::ChannelLayout::k32_32,
|
||||
Prospero::ChannelType::kFloat,
|
||||
Prospero::ChannelOrder::kStandard,
|
||||
{vk::Format::eR32G32Sfloat, 8}},
|
||||
{Prospero::ChannelLayout::k32_32_32_32,
|
||||
Prospero::ChannelType::kFloat,
|
||||
Prospero::ChannelOrder::kStandard,
|
||||
{vk::Format::eR32G32B32A32Sfloat, 16}},
|
||||
struct RenderTargetHostFormatInfo {
|
||||
vk::Format format = vk::Format::eUndefined;
|
||||
Prospero::ColorComponentMapping host_to_storage;
|
||||
};
|
||||
|
||||
RenderTargetHostFormatInfo ResolveRenderTargetHostFormat(Prospero::BufferFormat guest_format,
|
||||
Prospero::ChannelOrder order) {
|
||||
if (order == Prospero::ChannelOrder::kAlt) {
|
||||
switch (guest_format) {
|
||||
case Prospero::BufferFormat::k8_8_8_8UNorm:
|
||||
return {vk::Format::eB8G8R8A8Unorm, Prospero::ColorMappingBgra};
|
||||
case Prospero::BufferFormat::k8_8_8_8SNorm:
|
||||
return {vk::Format::eB8G8R8A8Snorm, Prospero::ColorMappingBgra};
|
||||
case Prospero::BufferFormat::k8_8_8_8Srgb:
|
||||
return {vk::Format::eB8G8R8A8Srgb, Prospero::ColorMappingBgra};
|
||||
case Prospero::BufferFormat::k10_10_10_2UNorm:
|
||||
return {vk::Format::eA2R10G10B10UnormPack32, Prospero::ColorMappingBgra};
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
switch (guest_format) {
|
||||
case Prospero::BufferFormat::k5_5_5_1UNorm:
|
||||
return {vk::Format::eA1R5G5B5UnormPack16, Prospero::ColorMappingBgra};
|
||||
case Prospero::BufferFormat::k1_5_5_5UNorm:
|
||||
return {vk::Format::eR5G5B5A1UnormPack16, Prospero::ColorMappingAbgr};
|
||||
case Prospero::BufferFormat::k4_4_4_4UNorm:
|
||||
return {vk::Format::eR4G4B4A4UnormPack16, Prospero::ColorMappingAbgr};
|
||||
default: return {VulkanFormat(guest_format), {}};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// TODO: cleanup!
|
||||
RenderTargetFormatInfo TextureGetRenderTargetFormat(uint32_t raw_layout, uint32_t raw_type,
|
||||
uint32_t raw_order) {
|
||||
const auto layout = static_cast<Prospero::ChannelLayout>(raw_layout);
|
||||
const auto type = static_cast<Prospero::ChannelType>(raw_type);
|
||||
const auto order = static_cast<Prospero::ChannelOrder>(raw_order);
|
||||
|
||||
if (layout == Prospero::ChannelLayout::k8 && type == Prospero::ChannelType::kUNorm &&
|
||||
raw_order <= Prospero::GpuEnumValue(Prospero::ChannelOrder::kAltReversed)) {
|
||||
return {vk::Format::eR8Unorm, 1};
|
||||
}
|
||||
for (const auto& mapping: kRenderTargetFormats) {
|
||||
if (mapping.layout == layout && mapping.type == type && mapping.order == order) {
|
||||
return mapping.info;
|
||||
RenderTargetFormatInfo TextureGetRenderTargetFormat(Prospero::ChannelLayout layout,
|
||||
Prospero::ChannelType type,
|
||||
Prospero::ChannelOrder order) {
|
||||
const auto encoding = Prospero::ResolveRenderTargetFormat(layout, type);
|
||||
if (encoding.IsValid() && encoding.SupportsOrder(order)) {
|
||||
const auto host = ResolveRenderTargetHostFormat(encoding.buffer_format, order);
|
||||
const auto bytes = Prospero::RenderTargetBytesPerElement(encoding.buffer_format);
|
||||
if (host.format != vk::Format::eUndefined && bytes != 0) {
|
||||
const auto order_mapping =
|
||||
kRenderTargetColorMappings[static_cast<size_t>(order)][encoding.components - 1u];
|
||||
return {host.format, bytes, host.host_to_storage.Then(order_mapping)};
|
||||
}
|
||||
}
|
||||
EXIT("unsupported render-target format combination: layout=%u type=%u order=%u\n", raw_layout,
|
||||
raw_type, raw_order);
|
||||
EXIT("unsupported render-target format combination: layout=%u type=%u order=%u\n",
|
||||
static_cast<uint32_t>(layout), static_cast<uint32_t>(type), static_cast<uint32_t>(order));
|
||||
}
|
||||
|
||||
namespace {
|
||||
@@ -208,12 +119,12 @@ vk::ComponentMapping TextureGetComponentMapping(uint32_t swizzle) {
|
||||
return components;
|
||||
}
|
||||
|
||||
vk::Format TextureGetFormat(uint32_t fmt) {
|
||||
const auto vk_format = VulkanFormat(fmt);
|
||||
vk::Format TextureGetFormat(Prospero::BufferFormat format) {
|
||||
const auto vk_format = VulkanFormat(format);
|
||||
if (vk_format != vk::Format::eUndefined) {
|
||||
return vk_format;
|
||||
}
|
||||
EXIT("unknown format: fmt = %u\n", fmt);
|
||||
EXIT("unknown format: fmt = %u\n", static_cast<uint32_t>(format));
|
||||
return vk::Format::eUndefined;
|
||||
}
|
||||
|
||||
@@ -271,13 +182,14 @@ uint64_t SetLinearUploadLevels(TextureUploadMipLayout* mips,
|
||||
|
||||
} // namespace
|
||||
|
||||
TextureUploadLayout TextureCalcUploadLayout(uint32_t fmt, uint32_t width, uint32_t height,
|
||||
uint32_t levels, uint32_t depth, uint32_t tile,
|
||||
uint64_t upload_size, bool allow_depth_tile,
|
||||
bool volume_texture, const char* owner) {
|
||||
TextureUploadLayout TextureCalcUploadLayout(Prospero::BufferFormat format, uint32_t width,
|
||||
uint32_t height, uint32_t levels, uint32_t depth,
|
||||
Prospero::TileMode tile, uint64_t upload_size,
|
||||
bool allow_depth_tile, bool volume_texture,
|
||||
const char* owner) {
|
||||
TextureUploadLayout layout {};
|
||||
layout.surface.description = {
|
||||
fmt,
|
||||
format,
|
||||
tile,
|
||||
volume_texture ? TileSurfaceDimension::Dim3D : TileSurfaceDimension::Dim2D,
|
||||
width,
|
||||
@@ -287,35 +199,39 @@ TextureUploadLayout TextureCalcUploadLayout(uint32_t fmt, uint32_t width, uint32
|
||||
volume_texture ? 1u : depth,
|
||||
};
|
||||
const auto& description = layout.surface.description;
|
||||
const auto tile_mode = static_cast<Prospero::TileMode>(description.tile_mode);
|
||||
const auto tile_mode = description.tile_mode;
|
||||
TileTextureElementLayout element {};
|
||||
|
||||
if (fmt == 0) {
|
||||
if (format == Prospero::BufferFormat::kInvalid) {
|
||||
EXIT("%s: legacy texture upload format unsupported: fmt=0 tile=%u size=%" PRIu64
|
||||
" extent=%ux%u levels=%u\n",
|
||||
owner, description.tile_mode, upload_size, width, height, levels);
|
||||
owner, static_cast<uint32_t>(description.tile_mode), upload_size, width, height,
|
||||
levels);
|
||||
}
|
||||
|
||||
switch (tile_mode) {
|
||||
case Prospero::TileMode::kLinear:
|
||||
if (!TileGetTextureElementLayout(fmt, element)) {
|
||||
EXIT("%s: unsupported linear texture format: fmt=%u\n", owner, fmt);
|
||||
if (!TileGetTextureElementLayout(format, element)) {
|
||||
EXIT("%s: unsupported linear texture format: fmt=%u\n", owner,
|
||||
static_cast<uint32_t>(format));
|
||||
}
|
||||
break;
|
||||
case Prospero::TileMode::kDepth:
|
||||
if (!allow_depth_tile || !TileGetTiledTextureLayout(description, layout.surface)) {
|
||||
EXIT("%s: unsupported typed tiled upload: fmt=%u tile=%u "
|
||||
"size=%" PRIu64 " extent=%ux%u levels=%u\n",
|
||||
owner, static_cast<uint32_t>(fmt), description.tile_mode, upload_size, width,
|
||||
height, levels);
|
||||
owner, static_cast<uint32_t>(format),
|
||||
static_cast<uint32_t>(description.tile_mode), upload_size, width, height,
|
||||
levels);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (!TileGetTiledTextureLayout(description, layout.surface)) {
|
||||
EXIT("%s: unsupported typed tiled upload: fmt=%u tile=%u "
|
||||
"size=%" PRIu64 " extent=%ux%u levels=%u\n",
|
||||
owner, static_cast<uint32_t>(fmt), description.tile_mode, upload_size, width,
|
||||
height, levels);
|
||||
owner, static_cast<uint32_t>(format),
|
||||
static_cast<uint32_t>(description.tile_mode), upload_size, width, height,
|
||||
levels);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -324,12 +240,12 @@ TextureUploadLayout TextureCalcUploadLayout(uint32_t fmt, uint32_t width, uint32
|
||||
element = {layout.surface.texture.block.bytes_per_element,
|
||||
layout.surface.texture.texel_width, layout.surface.texture.texel_height};
|
||||
}
|
||||
layout.pitch = TileGetTexturePitch(fmt, width, description.tile_mode);
|
||||
layout.pitch = TileGetTexturePitch(format, width, description.tile_mode);
|
||||
if (tile_mode == Prospero::TileMode::kLinear) {
|
||||
TileSizeOffset level_sizes[16] {};
|
||||
TilePaddedSize padded_sizes[16] {};
|
||||
TileGetTextureSize(fmt, width, height, levels, description.tile_mode, nullptr, level_sizes,
|
||||
padded_sizes);
|
||||
TileGetTextureSize(format, width, height, levels, description.tile_mode, nullptr,
|
||||
level_sizes, padded_sizes);
|
||||
for (uint32_t level = 0; level < levels; ++level) {
|
||||
layout.mips[level] = {level_sizes[level].offset, level_sizes[level].size,
|
||||
padded_sizes[level].width, padded_sizes[level].height};
|
||||
@@ -356,10 +272,9 @@ std::vector<vk::BufferImageCopy> TextureBuildImageCopies(const TextureUploadLayo
|
||||
const auto depth = volume_texture ? description.depth : description.layers;
|
||||
uint32_t mip_width = description.width;
|
||||
uint32_t mip_height = description.height;
|
||||
uint32_t mip_pitch = volume_texture && static_cast<Prospero::TileMode>(description.tile_mode) !=
|
||||
Prospero::TileMode::kLinear
|
||||
? description.width
|
||||
: layout.pitch;
|
||||
uint32_t mip_pitch = volume_texture && description.tile_mode != Prospero::TileMode::kLinear
|
||||
? description.width
|
||||
: layout.pitch;
|
||||
|
||||
std::vector<vk::BufferImageCopy> regions;
|
||||
regions.reserve(GetTextureRegionCount(depth, description.levels, volume_texture));
|
||||
@@ -376,8 +291,7 @@ std::vector<vk::BufferImageCopy> TextureBuildImageCopies(const TextureUploadLayo
|
||||
1};
|
||||
region.imageOffset.z = volume_texture ? static_cast<int>(z) : 0;
|
||||
region.imageExtent = {mip_width, mip_height, 1};
|
||||
const bool linear = static_cast<Prospero::TileMode>(description.tile_mode) ==
|
||||
Prospero::TileMode::kLinear;
|
||||
const bool linear = description.tile_mode == Prospero::TileMode::kLinear;
|
||||
if (linear) {
|
||||
region.bufferRowLength = layout.mips[i].row_length;
|
||||
region.bufferImageHeight = layout.mips[i].image_height;
|
||||
|
||||
@@ -35,12 +35,15 @@ struct TextureUploadLayout {
|
||||
};
|
||||
|
||||
vk::ComponentMapping TextureGetComponentMapping(uint32_t swizzle);
|
||||
vk::Format TextureGetFormat(uint32_t fmt);
|
||||
RenderTargetFormatInfo TextureGetRenderTargetFormat(uint32_t layout, uint32_t type, uint32_t order);
|
||||
TextureUploadLayout TextureCalcUploadLayout(uint32_t fmt, uint32_t width, uint32_t height,
|
||||
uint32_t levels, uint32_t depth, uint32_t tile,
|
||||
uint64_t upload_size, bool allow_depth_tile,
|
||||
bool volume_texture, const char* owner);
|
||||
vk::Format TextureGetFormat(Prospero::BufferFormat format);
|
||||
RenderTargetFormatInfo TextureGetRenderTargetFormat(Prospero::ChannelLayout layout,
|
||||
Prospero::ChannelType type,
|
||||
Prospero::ChannelOrder order);
|
||||
TextureUploadLayout TextureCalcUploadLayout(Prospero::BufferFormat format, uint32_t width,
|
||||
uint32_t height, uint32_t levels, uint32_t depth,
|
||||
Prospero::TileMode tile, uint64_t upload_size,
|
||||
bool allow_depth_tile, bool volume_texture,
|
||||
const char* owner);
|
||||
std::vector<vk::BufferImageCopy> TextureBuildImageCopies(const TextureUploadLayout& layout);
|
||||
bool TextureBuildGpuTileInfos(uint64_t tiled_size, const std::vector<vk::BufferImageCopy>& regions,
|
||||
const TextureUploadLayout& layout, uint32_t levels,
|
||||
|
||||
@@ -59,7 +59,7 @@ static void CopyNativeDescriptor(const ShaderRecompiler::IR::DescriptorValue& so
|
||||
}
|
||||
|
||||
static Prospero::ImageType TextureType(const ShaderTextureResource& descriptor) {
|
||||
const auto type = static_cast<Prospero::ImageType>(descriptor.Type());
|
||||
const auto type = descriptor.Type();
|
||||
return type == Prospero::ImageType::kCube ? Prospero::ImageType::kColor2DArray : type;
|
||||
}
|
||||
|
||||
@@ -227,14 +227,14 @@ bool IsSupportedSampledVideoOutView(const ShaderRecompiler::IR::ImageResource& r
|
||||
return image.usage.video_out && image.info.resources.layers == 1 &&
|
||||
IsSupportedSampledColorResource(resource) &&
|
||||
resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2D &&
|
||||
descriptor.Type() == Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) &&
|
||||
descriptor.Depth() == 0 && descriptor.BaseArray5() == 0;
|
||||
descriptor.Type() == Prospero::ImageType::kColor2D && descriptor.Depth() == 0 &&
|
||||
descriptor.BaseArray5() == 0;
|
||||
}
|
||||
|
||||
bool IsSupportedDepthTargetDescriptor(const ShaderTextureResource& descriptor, const Image& image) {
|
||||
const auto width = static_cast<uint32_t>(descriptor.Width5()) + 1u;
|
||||
const auto height = static_cast<uint32_t>(descriptor.Height5()) + 1u;
|
||||
const auto type = static_cast<Prospero::ImageType>(descriptor.Type());
|
||||
const auto type = descriptor.Type();
|
||||
const bool multisampled = IsMultisampledTexture(type);
|
||||
const auto samples = multisampled ? 1u << descriptor.LastLevel() : 1u;
|
||||
const auto pitch =
|
||||
@@ -269,9 +269,8 @@ bool IsSupportedDepthTargetDescriptor(const ShaderTextureResource& descriptor, c
|
||||
(supported_2d || supported_array || supported_cube || supported_msaa_2d ||
|
||||
supported_msaa_array) &&
|
||||
levels_ok && descriptor.MinLod() == 0 &&
|
||||
descriptor.TileMode() == Prospero::GpuEnumValue(Prospero::TileMode::kDepth) &&
|
||||
descriptor.BCSwizzle() == 0 && (!descriptor.MsaaDepth() || multisampled) &&
|
||||
pitch >= width && pitch == image.info.pitch;
|
||||
descriptor.TileMode() == Prospero::TileMode::kDepth && descriptor.BCSwizzle() == 0 &&
|
||||
(!descriptor.MsaaDepth() || multisampled) && pitch >= width && pitch == image.info.pitch;
|
||||
}
|
||||
|
||||
bool IsSupportedDepthTextureEncoding(const ShaderTextureResource& descriptor, const Image& image) {
|
||||
@@ -283,13 +282,13 @@ bool IsSupportedDepthTextureEncoding(const ShaderTextureResource& descriptor, co
|
||||
(static_cast<uint32_t>(descriptor.TileMode()) << 20u) |
|
||||
(static_cast<uint32_t>(descriptor.Type()) << 28u);
|
||||
const uint32_t field4_expected = descriptor.Depth() | (descriptor.BaseArray5() << 16u);
|
||||
const uint32_t field5_expected =
|
||||
0x00700000u | (static_cast<uint32_t>(descriptor.MaxMip()) << 4u);
|
||||
const bool common = (descriptor.fields[1] & field1_reserved_mask) == 0 &&
|
||||
(descriptor.fields[2] & field2_reserved_mask) == 0 &&
|
||||
descriptor.fields[3] == field3_expected &&
|
||||
descriptor.fields[4] == field4_expected &&
|
||||
descriptor.fields[5] == field5_expected;
|
||||
const uint32_t field5_expected = (static_cast<uint32_t>(descriptor.PerfMod5()) << 20u) |
|
||||
(static_cast<uint32_t>(descriptor.MaxMip()) << 4u);
|
||||
const bool common = (descriptor.fields[1] & field1_reserved_mask) == 0 &&
|
||||
(descriptor.fields[2] & field2_reserved_mask) == 0 &&
|
||||
descriptor.fields[3] == field3_expected &&
|
||||
descriptor.fields[4] == field4_expected &&
|
||||
descriptor.fields[5] == field5_expected;
|
||||
if (!common || (descriptor.fields[6] == 0 && descriptor.fields[7] != 0)) {
|
||||
return false;
|
||||
}
|
||||
@@ -300,8 +299,8 @@ bool IsSupportedDepthTextureEncoding(const ShaderTextureResource& descriptor, co
|
||||
const uint32_t expected_control = htile_control | (descriptor.MsaaDepth() ? (1u << 10u) : 0u);
|
||||
const auto metadata_addr = descriptor.MetaAddr() << 8u;
|
||||
return (descriptor.fields[6] & 0x00ffffffu) == expected_control && metadata_addr != 0 &&
|
||||
descriptor.TileMode() == Prospero::GpuEnumValue(Prospero::TileMode::kDepth) &&
|
||||
image.info.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kDepth) &&
|
||||
descriptor.TileMode() == Prospero::TileMode::kDepth &&
|
||||
image.info.tile_mode == Prospero::TileMode::kDepth &&
|
||||
image.info.metadata.kind == ImageMetadataKind::Htile &&
|
||||
image.info.metadata.range.Valid() && image.info.metadata.range.address == metadata_addr;
|
||||
}
|
||||
@@ -332,23 +331,21 @@ static void ValidateDepthTargetBinding(const ShaderRecompiler::IR::ImageResource
|
||||
resource_ok, descriptor_ok, encoding_ok, format_ok, static_cast<uint32_t>(resource.kind),
|
||||
static_cast<uint32_t>(resource.dimension), static_cast<uint32_t>(resource.mip_mode),
|
||||
resource.read, resource.written, resource.atomic, resource.depth_compare,
|
||||
descriptor.Format(), descriptor.DstSelXYZW(),
|
||||
static_cast<uint32_t>(descriptor.Format()), descriptor.DstSelXYZW(),
|
||||
image == nullptr ? static_cast<int>(vk::Format::eUndefined)
|
||||
: static_cast<int>(image->info.pixel_format),
|
||||
static_cast<int>(view_format), image == nullptr ? 0u : image->info.resources.layers,
|
||||
descriptor.Type(), descriptor.BaseArray5(), descriptor.Depth(), descriptor_pitch,
|
||||
image == nullptr ? 0u : image->info.pitch, descriptor.Base40(), size, descriptor.fields[0],
|
||||
descriptor.fields[1], descriptor.fields[2], descriptor.fields[3], descriptor.fields[4],
|
||||
descriptor.fields[5], descriptor.fields[6], descriptor.fields[7]);
|
||||
static_cast<uint32_t>(descriptor.Type()), descriptor.BaseArray5(), descriptor.Depth(),
|
||||
descriptor_pitch, image == nullptr ? 0u : image->info.pitch, descriptor.Base40(), size,
|
||||
descriptor.fields[0], descriptor.fields[1], descriptor.fields[2], descriptor.fields[3],
|
||||
descriptor.fields[4], descriptor.fields[5], descriptor.fields[6], descriptor.fields[7]);
|
||||
}
|
||||
|
||||
static bool IsSupportedStorageTextureDescriptor(const ShaderRecompiler::IR::ImageResource& resource,
|
||||
const ShaderTextureResource& descriptor) {
|
||||
const auto tile = descriptor.TileMode();
|
||||
const bool is_color_1d =
|
||||
descriptor.Type() == Prospero::GpuEnumValue(Prospero::ImageType::kColor1D);
|
||||
const bool is_color_1d_array =
|
||||
descriptor.Type() == Prospero::GpuEnumValue(Prospero::ImageType::kColor1DArray);
|
||||
const auto tile = descriptor.TileMode();
|
||||
const bool is_color_1d = descriptor.Type() == Prospero::ImageType::kColor1D;
|
||||
const bool is_color_1d_array = descriptor.Type() == Prospero::ImageType::kColor1DArray;
|
||||
const bool valid_1d_slice =
|
||||
(is_color_1d && descriptor.Depth() == 0 && descriptor.BaseArray5() == 0) ||
|
||||
(is_color_1d_array && descriptor.BaseArray5() <= descriptor.Depth());
|
||||
@@ -358,24 +355,27 @@ static bool IsSupportedStorageTextureDescriptor(const ShaderRecompiler::IR::Imag
|
||||
resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim1DArray &&
|
||||
is_color_1d_array && descriptor.Height5() == 0 &&
|
||||
descriptor.BaseArray5() <= descriptor.Depth();
|
||||
const bool is_color_2d =
|
||||
descriptor.Type() == Prospero::GpuEnumValue(Prospero::ImageType::kColor2D);
|
||||
const bool is_color_2d_array =
|
||||
descriptor.Type() == Prospero::GpuEnumValue(Prospero::ImageType::kColor2DArray);
|
||||
const bool is_color_2d = descriptor.Type() == Prospero::ImageType::kColor2D;
|
||||
const bool is_color_2d_array = descriptor.Type() == Prospero::ImageType::kColor2DArray;
|
||||
const bool valid_2d_slice =
|
||||
(is_color_2d && descriptor.Depth() == 0 && descriptor.BaseArray5() == 0) ||
|
||||
(is_color_2d_array && descriptor.BaseArray5() <= descriptor.Depth());
|
||||
const bool is_2d =
|
||||
resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2D && valid_2d_slice;
|
||||
const bool is_cube = resource.cube && descriptor.Type() == Prospero::ImageType::kCube &&
|
||||
descriptor.Width5() == descriptor.Height5() &&
|
||||
descriptor.BaseArray5() <= descriptor.Depth() &&
|
||||
(descriptor.Depth() - descriptor.BaseArray5() + 1u) % 6u == 0;
|
||||
const bool is_2d_array =
|
||||
resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2DArray &&
|
||||
is_color_2d_array && descriptor.BaseArray5() <= descriptor.Depth();
|
||||
((!resource.cube && is_color_2d_array && descriptor.BaseArray5() <= descriptor.Depth()) ||
|
||||
is_cube);
|
||||
const bool is_3d = resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim3D &&
|
||||
descriptor.Type() == Prospero::GpuEnumValue(Prospero::ImageType::kColor3D) &&
|
||||
descriptor.Type() == Prospero::ImageType::kColor3D &&
|
||||
descriptor.BaseArray5() == 0;
|
||||
TileTextureBlockLayout tile_layout {};
|
||||
bool supported_tile = false;
|
||||
switch (static_cast<Prospero::TileMode>(tile)) {
|
||||
switch (tile) {
|
||||
case Prospero::TileMode::kLinear: supported_tile = true; break;
|
||||
case Prospero::TileMode::kDepth:
|
||||
supported_tile =
|
||||
@@ -435,14 +435,12 @@ void ValidateStorageTexture(const ShaderRecompiler::IR::ImageResource& resource,
|
||||
const bool encoding_ok = IsSupportedStorageTextureEncoding(descriptor);
|
||||
const bool uint_resource =
|
||||
resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImageUint;
|
||||
const bool raw_sint_storage =
|
||||
format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32SInt) && uint_resource &&
|
||||
resource.written && !resource.read && !resource.atomic;
|
||||
const bool raw_sint_storage = format == Prospero::BufferFormat::k32SInt && uint_resource &&
|
||||
resource.written && !resource.read && !resource.atomic;
|
||||
const bool format_ok =
|
||||
raw_sint_storage ||
|
||||
(Prospero::IsSupportedTextureFormat(format) &&
|
||||
uint_resource == Prospero::IsUintTextureFormat(format) &&
|
||||
(!resource.atomic || format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32UInt)));
|
||||
raw_sint_storage || (Prospero::IsSupportedTextureFormat(format) &&
|
||||
uint_resource == Prospero::IsUintTextureFormat(format) &&
|
||||
(!resource.atomic || format == Prospero::BufferFormat::k32UInt));
|
||||
if (resource_ok && descriptor_ok && encoding_ok && format_ok && size != 0) {
|
||||
return;
|
||||
}
|
||||
@@ -461,24 +459,23 @@ void ValidateStorageTexture(const ShaderRecompiler::IR::ImageResource& resource,
|
||||
IsValidImageSwizzle(descriptor.DstSelXYZW()), descriptor.Base40(), size,
|
||||
static_cast<uint32_t>(descriptor.Width5()) + 1u,
|
||||
static_cast<uint32_t>(descriptor.Height5()) + 1u,
|
||||
static_cast<uint32_t>(descriptor.Depth()) + 1u, descriptor.Type(), format,
|
||||
descriptor.TileMode(), descriptor.DstSelXYZW(), resource.read, resource.written,
|
||||
descriptor.fields[0], descriptor.fields[1], descriptor.fields[2], descriptor.fields[3],
|
||||
descriptor.fields[4], descriptor.fields[5], descriptor.fields[6], descriptor.fields[7]);
|
||||
static_cast<uint32_t>(descriptor.Depth()) + 1u, static_cast<uint32_t>(descriptor.Type()),
|
||||
static_cast<uint32_t>(format), static_cast<uint32_t>(descriptor.TileMode()),
|
||||
descriptor.DstSelXYZW(), resource.read, resource.written, descriptor.fields[0],
|
||||
descriptor.fields[1], descriptor.fields[2], descriptor.fields[3], descriptor.fields[4],
|
||||
descriptor.fields[5], descriptor.fields[6], descriptor.fields[7]);
|
||||
}
|
||||
|
||||
struct NullImageSpec {
|
||||
vk::Format format;
|
||||
uint32_t guest_format;
|
||||
vk::Format format;
|
||||
Prospero::BufferFormat guest_format;
|
||||
};
|
||||
|
||||
static NullImageSpec NullTextureSpec(const ShaderRecompiler::IR::ImageResource& resource) {
|
||||
const bool uint_image = resource.kind == ShaderRecompiler::IR::ResourceKind::ImageUint ||
|
||||
resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImageUint;
|
||||
return uint_image ? NullImageSpec {vk::Format::eR32Uint,
|
||||
Prospero::GpuEnumValue(Prospero::BufferFormat::k32UInt)}
|
||||
: NullImageSpec {vk::Format::eR32Sfloat,
|
||||
Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float)};
|
||||
return uint_image ? NullImageSpec {vk::Format::eR32Uint, Prospero::BufferFormat::k32UInt}
|
||||
: NullImageSpec {vk::Format::eR32Sfloat, Prospero::BufferFormat::k32Float};
|
||||
}
|
||||
|
||||
static TextureCache::ImageDesc NullTextureDesc(const ShaderRecompiler::IR::ImageResource& resource,
|
||||
@@ -504,7 +501,7 @@ static TextureCache::ImageDesc NullTextureDesc(const ShaderRecompiler::IR::Image
|
||||
}
|
||||
|
||||
static void PopulateTextureMipLayout(ImageInfo& info) {
|
||||
if (info.IsVolume() && info.tile_mode != Prospero::GpuEnumValue(Prospero::TileMode::kLinear)) {
|
||||
if (info.IsVolume() && info.tile_mode != Prospero::TileMode::kLinear) {
|
||||
TileSurfaceLayout surface {};
|
||||
const TileSurfaceDescription description {
|
||||
info.guest_format, info.tile_mode, TileSurfaceDimension::Dim3D, info.extent.width,
|
||||
@@ -631,10 +628,9 @@ RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& reso
|
||||
const bool multisampled = IsMultisampledTexture(type);
|
||||
const auto levels = multisampled ? 1u : static_cast<uint32_t>(descriptor.MaxMip()) + 1u;
|
||||
const auto tile = descriptor.TileMode();
|
||||
const bool depth_tile = tile == Prospero::GpuEnumValue(Prospero::TileMode::kDepth);
|
||||
const bool msaa_tile =
|
||||
depth_tile || tile == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget);
|
||||
const bool msaa_array = type == Prospero::ImageType::kColor2DMsaaArray;
|
||||
const bool depth_tile = tile == Prospero::TileMode::kDepth;
|
||||
const bool msaa_tile = depth_tile || tile == Prospero::TileMode::kRenderTarget;
|
||||
const bool msaa_array = type == Prospero::ImageType::kColor2DMsaaArray;
|
||||
if ((!multisampled && (base_level > last_level || last_level >= levels)) ||
|
||||
(multisampled &&
|
||||
(base_level != 0 || last_level == 0 || last_level > 3 ||
|
||||
@@ -644,7 +640,8 @@ RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& reso
|
||||
EXIT("unsupported texture mip view: base=%u last=%u levels=%u max=%u type=%u tile=%u "
|
||||
"kind=%u dimension=%u mip_mode=%u read=%d written=%d "
|
||||
"dwords=%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x\n",
|
||||
base_level, last_level, levels, descriptor.MaxMip(), descriptor.Type(), tile,
|
||||
base_level, last_level, levels, descriptor.MaxMip(),
|
||||
static_cast<uint32_t>(descriptor.Type()), static_cast<uint32_t>(tile),
|
||||
static_cast<uint32_t>(resource.kind), static_cast<uint32_t>(resource.dimension),
|
||||
static_cast<uint32_t>(resource.mip_mode), resource.read, resource.written,
|
||||
descriptor.fields[0], descriptor.fields[1], descriptor.fields[2], descriptor.fields[3],
|
||||
@@ -664,7 +661,7 @@ RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& reso
|
||||
resource.kind == ShaderRecompiler::IR::ResourceKind::ImageUint) &&
|
||||
!sampled_numeric_class) {
|
||||
EXIT("sampled image numeric class mismatch: kind=%u format=%u addr=0x%016" PRIx64 "\n",
|
||||
static_cast<uint32_t>(resource.kind), format, address);
|
||||
static_cast<uint32_t>(resource.kind), static_cast<uint32_t>(format), address);
|
||||
}
|
||||
|
||||
const bool volume = type == Prospero::ImageType::kColor3D;
|
||||
@@ -694,15 +691,14 @@ RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& reso
|
||||
ValidateStorageTexture(resource, descriptor, size.size);
|
||||
}
|
||||
|
||||
const auto pixel_format = TextureGetFormat(format);
|
||||
const auto storage_view_format =
|
||||
storage && format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32SInt)
|
||||
? vk::Format::eR32Uint
|
||||
: SrgbStorageViewFormat(pixel_format);
|
||||
const auto view_format = storage && storage_view_format != vk::Format::eUndefined
|
||||
? storage_view_format
|
||||
: pixel_format;
|
||||
const auto block_bytes = Prospero::BlockCompressedBytesPerBlock(format);
|
||||
const auto pixel_format = TextureGetFormat(format);
|
||||
const auto storage_view_format = storage && format == Prospero::BufferFormat::k32SInt
|
||||
? vk::Format::eR32Uint
|
||||
: SrgbStorageViewFormat(pixel_format);
|
||||
const auto view_format = storage && storage_view_format != vk::Format::eUndefined
|
||||
? storage_view_format
|
||||
: pixel_format;
|
||||
const auto block_bytes = Prospero::BlockCompressedBytesPerBlock(format);
|
||||
TextureCache::ImageDesc desc {};
|
||||
desc.info.data = {address, size.size};
|
||||
desc.info.pixel_format = pixel_format;
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
namespace Libs::Graphics {
|
||||
|
||||
// IDK: maybe we can remove it?
|
||||
constexpr uint8_t kTemporaryVertexAttribFormat113 =
|
||||
static_cast<uint8_t>(Prospero::VertexAttribFormat::k16_16SInt);
|
||||
constexpr uint32_t kTemporaryPs5BufferFormat121 = 121u;
|
||||
|
||||
static bool NarrowInputFormat(vk::Format& format, uint32_t& size, uint32_t used_components) {
|
||||
@@ -88,8 +90,9 @@ static bool NarrowInputFormat(vk::Format& format, uint32_t& size, uint32_t used_
|
||||
|
||||
static void GetInputFormat(const ShaderBufferResource& res, vk::Format& format, uint32_t& size,
|
||||
uint32_t used_components) {
|
||||
auto fmt = res.Format();
|
||||
if (fmt == Prospero::GpuEnumValue(Prospero::VertexAttribFormat::k16_16SInt)) {
|
||||
const auto fmt = res.Format();
|
||||
const auto raw_format = res.RawFormat();
|
||||
if (raw_format == kTemporaryVertexAttribFormat113) {
|
||||
static bool logged_113 = false;
|
||||
if (!logged_113) {
|
||||
LOGF("InputFormat: temporary: accepting invalid PS5 buffer format 113 as "
|
||||
@@ -99,12 +102,12 @@ static void GetInputFormat(const ShaderBufferResource& res, vk::Format& format,
|
||||
format = vk::Format::eR32G32B32A32Sfloat;
|
||||
size = 4;
|
||||
if (NarrowInputFormat(format, size, used_components)) {
|
||||
LOGF("InputFormat: narrowing fmt=%u to %s for used_components=%u\n", fmt,
|
||||
LOGF("InputFormat: narrowing fmt=%u to %s for used_components=%u\n", raw_format,
|
||||
VulkanToString(format).c_str(), used_components);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (fmt == kTemporaryPs5BufferFormat121) {
|
||||
if (raw_format == kTemporaryPs5BufferFormat121) {
|
||||
static bool logged_121 = false;
|
||||
if (!logged_121) {
|
||||
LOGF("InputFormat: accepting PS5 buffer format 121 as vk::Format::eR16G16Sfloat\n");
|
||||
@@ -113,13 +116,13 @@ static void GetInputFormat(const ShaderBufferResource& res, vk::Format& format,
|
||||
format = vk::Format::eR16G16Sfloat;
|
||||
size = 2;
|
||||
if (NarrowInputFormat(format, size, used_components)) {
|
||||
LOGF("InputFormat: narrowing fmt=%u to %s for used_components=%u\n", fmt,
|
||||
LOGF("InputFormat: narrowing fmt=%u to %s for used_components=%u\n", raw_format,
|
||||
VulkanToString(format).c_str(), used_components);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (static_cast<Prospero::BufferFormat>(fmt)) {
|
||||
switch (fmt) {
|
||||
case Prospero::BufferFormat::k32_32_32_32Float:
|
||||
format = vk::Format::eR32G32B32A32Sfloat;
|
||||
size = 4;
|
||||
@@ -329,7 +332,7 @@ static void GetInputFormat(const ShaderBufferResource& res, vk::Format& format,
|
||||
size = 1;
|
||||
break;
|
||||
default:
|
||||
EXIT("unknown format: fmt = %u\n", fmt);
|
||||
EXIT("unknown format: fmt = %u\n", raw_format);
|
||||
format = vk::Format::eUndefined;
|
||||
size = 4;
|
||||
break;
|
||||
|
||||
@@ -93,7 +93,7 @@ bool ResolveComputeImageClear(const ShaderComputeInputInfo& input, uint32_t grou
|
||||
const auto descriptor = DecodeNativeDescriptor<ShaderBufferResource>(raw);
|
||||
if (!resource.formatted || !resource.written || resource.read || resource.atomic ||
|
||||
resource.scalar || resource.max_byte_extent != 16 || descriptor.Stride() != 16 ||
|
||||
descriptor.Format() != Prospero::GpuEnumValue(Prospero::BufferFormat::k32_32_32_32UInt) ||
|
||||
descriptor.Format() != Prospero::BufferFormat::k32_32_32_32UInt ||
|
||||
descriptor.SwizzleEnabled() || descriptor.IndexStride() != 0 || descriptor.AddTid() ||
|
||||
resource.packed_stride != descriptor.PackedStride() || raw.dword_count != 4 ||
|
||||
program.user_data_base != 0 || resources.user_data.size() != 8) {
|
||||
@@ -246,7 +246,7 @@ void RenderExecutor::DispatchDirect(uint64_t submit_id, RenderCommandBuffer& buf
|
||||
LOGF(" CS buffer[%u]: source=%u usage=%s addr=0x%012" PRIx64
|
||||
" stride=%u records=%u format=%u\n",
|
||||
i, buffer.source, buffer.written ? "read-write" : "read-only", r.Base48(),
|
||||
r.Stride(), r.NumRecords(), r.Format());
|
||||
r.Stride(), r.NumRecords(), r.RawFormat());
|
||||
}
|
||||
for (uint32_t i = 0; i < program.info.images.size(); i++) {
|
||||
const auto& image = program.info.images[i];
|
||||
@@ -258,13 +258,13 @@ void RenderExecutor::DispatchDirect(uint64_t submit_id, RenderCommandBuffer& buf
|
||||
image.kind == ShaderRecompiler::IR::ResourceKind::ImageUint)
|
||||
? "true"
|
||||
: "false",
|
||||
r.Base40(), static_cast<uint32_t>(r.Type()), r.Format(),
|
||||
r.Base40(), static_cast<uint32_t>(r.Type()), static_cast<uint32_t>(r.Format()),
|
||||
static_cast<uint32_t>(r.Width5()) + 1u, static_cast<uint32_t>(r.Height5()) + 1u,
|
||||
static_cast<uint32_t>(r.Depth()) + 1u,
|
||||
std::max<uint32_t>(static_cast<uint32_t>(r.LastLevel()),
|
||||
static_cast<uint32_t>(r.MaxMip())) +
|
||||
1u,
|
||||
r.TileMode());
|
||||
static_cast<uint32_t>(r.TileMode()));
|
||||
}
|
||||
for (uint32_t i = 0; i < program.info.samplers.size(); i++) {
|
||||
const auto r = DecodeNativeDescriptor<ShaderSamplerResource>(resources.samplers[i]);
|
||||
|
||||
@@ -123,7 +123,7 @@ static void LogFramebufferSkip(const char* draw_name, const RenderColorInfo& col
|
||||
log_id, draw_name, RenderColorTypeName(color.type), color.base_addr, color.buffer_size,
|
||||
color.image_id ? "yes" : "no", VulkanToString(depth.format).c_str(),
|
||||
depth.image_id ? "yes" : "no", depth.vaddr_num, ctx.GetRenderTargetMask(),
|
||||
ucfg.GetPrimType(), index_count, flags);
|
||||
static_cast<uint32_t>(ucfg.GetPrimType()), index_count, flags);
|
||||
}
|
||||
|
||||
static void LogMrtState(const char* draw_name, const RenderCommandBuffer& buffer,
|
||||
@@ -179,10 +179,12 @@ static void LogMrtState(const char* draw_name, const RenderCommandBuffer& buffer
|
||||
" fmt=0x%08" PRIx32 " nfmt=0x%08" PRIx32 " order=0x%08" PRIx32
|
||||
" width=%u height=%u tile=%u"
|
||||
" blend=%s src=%u dst=%u alpha_src=%u alpha_dst=%u\n",
|
||||
log_id, i, rt.base.addr, ctm, csm, ps_input_info.target_output_mode[i], rt.info.format,
|
||||
rt.info.channel_type, rt.info.channel_order, rt.attrib2.width + 1,
|
||||
rt.attrib2.height + 1, rt.attrib3.tile_mode, bc.enable ? "true" : "false",
|
||||
bc.color_srcblend, bc.color_destblend, bc.alpha_srcblend, bc.alpha_destblend);
|
||||
log_id, i, rt.base.addr, ctm, csm, ps_input_info.target_output_mode[i],
|
||||
static_cast<uint32_t>(rt.info.format), static_cast<uint32_t>(rt.info.channel_type),
|
||||
static_cast<uint32_t>(rt.info.channel_order), rt.attrib2.width + 1,
|
||||
rt.attrib2.height + 1, static_cast<uint32_t>(rt.attrib3.tile_mode),
|
||||
bc.enable ? "true" : "false", bc.color_srcblend, bc.color_destblend, bc.alpha_srcblend,
|
||||
bc.alpha_destblend);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,7 +227,7 @@ static void LogDrawTargetState(const char* draw_name, const RenderColorInfo& col
|
||||
"scissor=(%d,%d)-(%d,%d)\n",
|
||||
log_id, buffer.GetContext().GetGpu().GetFrameNum(), draw_name,
|
||||
RenderColorTypeName(color.type), color.base_addr, extent.width, extent.height,
|
||||
ucfg.GetPrimType(), index_count, flags, ctx.GetRenderTargetMask(),
|
||||
static_cast<uint32_t>(ucfg.GetPrimType()), index_count, flags, ctx.GetRenderTargetMask(),
|
||||
color.color_clear_enable ? "true" : "false", color.color_clear_value.float32[0],
|
||||
color.color_clear_value.float32[1], color.color_clear_value.float32[2],
|
||||
color.color_clear_value.float32[3], cc.mode, cc.op, bc.enable ? "true" : "false",
|
||||
@@ -289,8 +291,7 @@ static void LogDrawInputState(const RenderCommandBuffer& buffer, const RenderCol
|
||||
const auto& rd = vs_input_info.resources_dst[res_index];
|
||||
const auto offset = b.attr_offsets[ai];
|
||||
if (offset + 4u <= b.stride &&
|
||||
r.Format() ==
|
||||
Prospero::GpuEnumValue(Prospero::BufferFormat::k8_8_8_8UNorm)) {
|
||||
r.Format() == Prospero::BufferFormat::k8_8_8_8UNorm) {
|
||||
uint32_t packed = 0;
|
||||
std::memcpy(&packed, rec_bytes + offset, sizeof(packed));
|
||||
const auto r8 = (packed >> 0u) & 0xffu;
|
||||
@@ -844,7 +845,7 @@ static bool GetDrawTopology(const HW::UserConfig& ucfg, bool auto_draw,
|
||||
|
||||
topology = vk::PrimitiveTopology::ePointList;
|
||||
|
||||
switch (static_cast<Prospero::PrimitiveType>(ucfg.GetPrimType())) {
|
||||
switch (ucfg.GetPrimType()) {
|
||||
case Prospero::PrimitiveType::kNone: return false;
|
||||
case Prospero::PrimitiveType::kPointList:
|
||||
topology = vk::PrimitiveTopology::ePointList;
|
||||
@@ -867,14 +868,14 @@ static bool GetDrawTopology(const HW::UserConfig& ucfg, bool auto_draw,
|
||||
break;
|
||||
case Prospero::PrimitiveType::kRectListLegacy:
|
||||
if (!auto_draw) {
|
||||
EXIT("unknown primitive type: %u\n", ucfg.GetPrimType());
|
||||
EXIT("unknown primitive type: %u\n", static_cast<uint32_t>(ucfg.GetPrimType()));
|
||||
}
|
||||
topology = vk::PrimitiveTopology::eTriangleStrip;
|
||||
break;
|
||||
case Prospero::PrimitiveType::kQuadListLegacy:
|
||||
topology = vk::PrimitiveTopology::eTriangleFan;
|
||||
break;
|
||||
default: EXIT("unknown primitive type: %u\n", ucfg.GetPrimType());
|
||||
default: EXIT("unknown primitive type: %u\n", static_cast<uint32_t>(ucfg.GetPrimType()));
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1051,7 +1052,7 @@ static void EmitDrawPrimitives(const HW::UserConfig& ucfg, vk::CommandBuffer vk_
|
||||
const DrawEmitInfo& emit) {
|
||||
EXIT_IF(draw.name == nullptr);
|
||||
|
||||
switch (static_cast<Prospero::PrimitiveType>(ucfg.GetPrimType())) {
|
||||
switch (ucfg.GetPrimType()) {
|
||||
case Prospero::PrimitiveType::kPointList:
|
||||
case Prospero::PrimitiveType::kLineList:
|
||||
case Prospero::PrimitiveType::kLineStrip:
|
||||
@@ -1069,7 +1070,7 @@ static void EmitDrawPrimitives(const HW::UserConfig& ucfg, vk::CommandBuffer vk_
|
||||
break;
|
||||
case Prospero::PrimitiveType::kRectListLegacy:
|
||||
if (emit.indexed) {
|
||||
EXIT("unknown primitive type: %u\n", ucfg.GetPrimType());
|
||||
EXIT("unknown primitive type: %u\n", static_cast<uint32_t>(ucfg.GetPrimType()));
|
||||
}
|
||||
// Sarah
|
||||
EXIT_NOT_IMPLEMENTED(!(draw.index_count == 3 && vs_input_info.buffers_num == 0));
|
||||
@@ -1087,7 +1088,7 @@ static void EmitDrawPrimitives(const HW::UserConfig& ucfg, vk::CommandBuffer vk_
|
||||
}
|
||||
}
|
||||
break;
|
||||
default: EXIT("unknown primitive type: %u\n", ucfg.GetPrimType());
|
||||
default: EXIT("unknown primitive type: %u\n", static_cast<uint32_t>(ucfg.GetPrimType()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1387,9 +1388,8 @@ void RenderExecutor::DrawAuto(uint64_t submit_id, RenderCommandBuffer& buffer, u
|
||||
}
|
||||
|
||||
LogDrawStateIfNeeded(buffer, draw, state, false,
|
||||
ucfg.GetPrimType() ==
|
||||
Prospero::GpuEnumValue(Prospero::PrimitiveType::kRectListLegacy),
|
||||
0, nullptr);
|
||||
ucfg.GetPrimType() == Prospero::PrimitiveType::kRectListLegacy, 0,
|
||||
nullptr);
|
||||
|
||||
const auto vertex_offset = ResolveVertexOffset(ucfg.GetIndexOffset(), state.vs_input_info) +
|
||||
static_cast<int32_t>(first_vertex);
|
||||
|
||||
@@ -83,11 +83,11 @@ constexpr FormatMapping kFormatMappings[] = {
|
||||
};
|
||||
|
||||
constexpr auto MakeFormatLookup() {
|
||||
constexpr auto kMaxFormat = Prospero::GpuEnumValue(Prospero::BufferFormat::kBc7Srgb);
|
||||
constexpr auto kMaxFormat = static_cast<size_t>(Prospero::BufferFormat::kBc7Srgb);
|
||||
std::array<vk::Format, kMaxFormat + 1> lookup {};
|
||||
lookup.fill(vk::Format::eUndefined);
|
||||
for (const auto& mapping: kFormatMappings) {
|
||||
lookup[Prospero::GpuEnumValue(mapping.guest)] = mapping.host;
|
||||
lookup[static_cast<size_t>(mapping.guest)] = mapping.host;
|
||||
}
|
||||
return lookup;
|
||||
}
|
||||
@@ -112,9 +112,9 @@ std::string VulkanToString(vk::QueueFlags value) {
|
||||
return vk::to_string(value);
|
||||
}
|
||||
|
||||
vk::Format VulkanFormat(uint32_t guest_format) {
|
||||
return guest_format < kFormatLookup.size() ? kFormatLookup[guest_format]
|
||||
: vk::Format::eUndefined;
|
||||
vk::Format VulkanFormat(Prospero::BufferFormat guest_format) {
|
||||
const auto index = static_cast<size_t>(guest_format);
|
||||
return index < kFormatLookup.size() ? kFormatLookup[index] : vk::Format::eUndefined;
|
||||
}
|
||||
|
||||
void RequireVulkanSuccess(vk::Result result, const char* operation) {
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#define VMA_STATIC_VULKAN_FUNCTIONS 0
|
||||
#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
|
||||
|
||||
#include "graphics/guest_gpu/gpu_defs.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -29,7 +31,7 @@ std::string VulkanToString(vk::Result value);
|
||||
std::string VulkanToString(vk::Format value);
|
||||
std::string VulkanToString(vk::ImageLayout value);
|
||||
std::string VulkanToString(vk::QueueFlags value);
|
||||
vk::Format VulkanFormat(uint32_t guest_format);
|
||||
vk::Format VulkanFormat(Prospero::BufferFormat guest_format);
|
||||
void RequireVulkanSuccess(vk::Result result, const char* operation);
|
||||
|
||||
template <typename T, typename Enumerator>
|
||||
|
||||
@@ -32,64 +32,21 @@ namespace DialogIme = Libs::Dialog::ImeDialog;
|
||||
|
||||
namespace Ime {
|
||||
|
||||
enum class Type : uint32_t { Default = 0, BasicLatin = 1, Url = 2, Mail = 3, Number = 4 };
|
||||
enum class EnterLabel : uint32_t { Default = 0, Send = 1, Search = 2, Go = 3 };
|
||||
enum class Alignment : uint32_t { Start = 0, Center = 1, End = 2 };
|
||||
enum class ExternalAction : uint8_t {
|
||||
None,
|
||||
Text,
|
||||
Backspace,
|
||||
MoveLeft,
|
||||
MoveRight,
|
||||
Cancel,
|
||||
Accept,
|
||||
Newline,
|
||||
};
|
||||
using Type = ImeCommon::Type;
|
||||
using EnterLabel = ImeCommon::EnterLabel;
|
||||
using Alignment = ImeCommon::Alignment;
|
||||
using ExternalAction = ImeCommon::ExternalAction;
|
||||
using ExternalInput = ImeCommon::ExternalInput;
|
||||
using HostSnapshot = ImeCommon::HostSnapshot;
|
||||
|
||||
struct Keycode {
|
||||
uint16_t keycode = 0;
|
||||
char16_t character = u'\0';
|
||||
uint32_t status = 0;
|
||||
uint32_t type = 0;
|
||||
int32_t user_id = 0;
|
||||
uint32_t resource_id = 0;
|
||||
uint64_t timestamp = 0;
|
||||
};
|
||||
|
||||
struct ExternalInput {
|
||||
Keycode key;
|
||||
ExternalAction action = ExternalAction::None;
|
||||
std::u16string text;
|
||||
};
|
||||
|
||||
struct HostSnapshot {
|
||||
uint64_t generation = 0;
|
||||
Type type = Type::Default;
|
||||
EnterLabel enter_label = EnterLabel::Default;
|
||||
uint32_t option = 0;
|
||||
uint32_t max_text_length = 0;
|
||||
uint32_t cursor = 0;
|
||||
uint32_t disable_device = 0;
|
||||
bool key_panel_visible = true;
|
||||
float posx = 0.0f;
|
||||
float posy = 0.0f;
|
||||
Alignment horizontal_alignment = Alignment::Start;
|
||||
Alignment vertical_alignment = Alignment::Start;
|
||||
uint32_t panel_width = 0;
|
||||
uint32_t panel_height = 0;
|
||||
std::u16string text;
|
||||
std::u16string title;
|
||||
std::u16string placeholder;
|
||||
};
|
||||
|
||||
constexpr uint32_t OPTION_MULTILINE = 0x00000001;
|
||||
constexpr uint32_t OPTION_NO_AUTO_CAPITALIZE = 0x00000002;
|
||||
constexpr uint32_t OPTION_PASSWORD = 0x00000004;
|
||||
constexpr uint32_t OPTION_FIXED_POSITION = 0x00000040;
|
||||
constexpr uint32_t OPTION_DISABLE_POSITION_ADJ = 0x00000800;
|
||||
constexpr uint32_t OPTION_USE_OVER_2K = 0x00004000;
|
||||
constexpr uint32_t DISABLE_DEVICE_CONTROLLER = 0x00000001;
|
||||
constexpr uint32_t DISABLE_DEVICE_EXT_KEYBOARD = 0x00000002;
|
||||
constexpr uint32_t OPTION_MULTILINE = ImeCommon::OPTION_MULTILINE;
|
||||
constexpr uint32_t OPTION_NO_AUTO_CAPITALIZE = ImeCommon::OPTION_NO_AUTO_CAPITALIZE;
|
||||
constexpr uint32_t OPTION_PASSWORD = ImeCommon::OPTION_PASSWORD;
|
||||
constexpr uint32_t OPTION_FIXED_POSITION = ImeCommon::OPTION_FIXED_POSITION;
|
||||
constexpr uint32_t OPTION_DISABLE_POSITION_ADJ = ImeCommon::OPTION_DISABLE_POSITION_ADJUST;
|
||||
constexpr uint32_t OPTION_USE_OVER_2K = ImeCommon::OPTION_USE_OVER_2K;
|
||||
constexpr uint32_t DISABLE_DEVICE_CONTROLLER = ImeCommon::DISABLE_DEVICE_CONTROLLER;
|
||||
constexpr uint32_t DISABLE_DEVICE_EXT_KEYBOARD = ImeCommon::DISABLE_DEVICE_EXT_KEYBOARD;
|
||||
constexpr uint64_t CORE_GENERATION_BIT = uint64_t {1} << 63;
|
||||
|
||||
uint64_t PackCoreGeneration(uint64_t generation) {
|
||||
@@ -108,49 +65,11 @@ bool GetHostSnapshot(HostSnapshot* snapshot) {
|
||||
if (snapshot == nullptr) {
|
||||
return false;
|
||||
}
|
||||
CoreIme::HostSnapshot core;
|
||||
if (CoreIme::GetHostSnapshot(&core)) {
|
||||
snapshot->generation = PackCoreGeneration(core.generation);
|
||||
snapshot->type = static_cast<Type>(core.type);
|
||||
snapshot->enter_label = static_cast<EnterLabel>(core.enter_label);
|
||||
snapshot->option = core.option;
|
||||
snapshot->max_text_length = core.max_text_length;
|
||||
snapshot->cursor = core.cursor;
|
||||
snapshot->disable_device = core.disable_device;
|
||||
snapshot->key_panel_visible = core.key_panel_visible;
|
||||
snapshot->posx = core.posx;
|
||||
snapshot->posy = core.posy;
|
||||
snapshot->horizontal_alignment = static_cast<Alignment>(core.horizontal_alignment);
|
||||
snapshot->vertical_alignment = static_cast<Alignment>(core.vertical_alignment);
|
||||
snapshot->panel_width = core.panel_width;
|
||||
snapshot->panel_height = core.panel_height;
|
||||
snapshot->text = std::move(core.text);
|
||||
snapshot->title.clear();
|
||||
snapshot->placeholder.clear();
|
||||
if (CoreIme::GetHostSnapshot(snapshot)) {
|
||||
snapshot->generation = PackCoreGeneration(snapshot->generation);
|
||||
return true;
|
||||
}
|
||||
DialogIme::HostSnapshot dialog;
|
||||
if (!DialogIme::GetHostSnapshot(&dialog)) {
|
||||
return false;
|
||||
}
|
||||
snapshot->generation = dialog.generation;
|
||||
snapshot->type = static_cast<Type>(dialog.type);
|
||||
snapshot->enter_label = static_cast<EnterLabel>(dialog.enter_label);
|
||||
snapshot->option = dialog.option;
|
||||
snapshot->max_text_length = dialog.max_text_length;
|
||||
snapshot->cursor = dialog.cursor;
|
||||
snapshot->disable_device = dialog.disable_device;
|
||||
snapshot->key_panel_visible = dialog.key_panel_visible;
|
||||
snapshot->posx = dialog.posx;
|
||||
snapshot->posy = dialog.posy;
|
||||
snapshot->horizontal_alignment = static_cast<Alignment>(dialog.horizontal_alignment);
|
||||
snapshot->vertical_alignment = static_cast<Alignment>(dialog.vertical_alignment);
|
||||
snapshot->panel_width = dialog.panel_width;
|
||||
snapshot->panel_height = dialog.panel_height;
|
||||
snapshot->text = std::move(dialog.text);
|
||||
snapshot->title = std::move(dialog.title);
|
||||
snapshot->placeholder = std::move(dialog.placeholder);
|
||||
return true;
|
||||
return DialogIme::GetHostSnapshot(snapshot);
|
||||
}
|
||||
|
||||
bool HostInsertText(uint64_t generation, std::u16string_view text) {
|
||||
@@ -175,30 +94,9 @@ bool HostCancel(uint64_t generation) {
|
||||
}
|
||||
|
||||
bool HostQueueExternalInput(uint64_t generation, ExternalInput input) {
|
||||
if (!IsCoreGeneration(generation)) {
|
||||
DialogIme::ExternalInput dialog;
|
||||
dialog.key.keycode = input.key.keycode;
|
||||
dialog.key.character = input.key.character;
|
||||
dialog.key.status = input.key.status;
|
||||
dialog.key.type = input.key.type;
|
||||
dialog.key.user_id = input.key.user_id;
|
||||
dialog.key.resource_id = input.key.resource_id;
|
||||
dialog.key.timestamp = input.key.timestamp;
|
||||
dialog.action = static_cast<DialogIme::ExternalAction>(input.action);
|
||||
dialog.text = std::move(input.text);
|
||||
return DialogIme::HostQueueExternalInput(generation, std::move(dialog));
|
||||
}
|
||||
CoreIme::ExternalInput core;
|
||||
core.key.keycode = input.key.keycode;
|
||||
core.key.character = input.key.character;
|
||||
core.key.status = input.key.status;
|
||||
core.key.type = input.key.type;
|
||||
core.key.user_id = input.key.user_id;
|
||||
core.key.resource_id = input.key.resource_id;
|
||||
core.key.timestamp = input.key.timestamp;
|
||||
core.action = static_cast<CoreIme::ExternalAction>(input.action);
|
||||
core.text = std::move(input.text);
|
||||
return CoreIme::HostQueueExternalInput(UnpackGeneration(generation), std::move(core));
|
||||
return IsCoreGeneration(generation)
|
||||
? CoreIme::HostQueueExternalInput(UnpackGeneration(generation), std::move(input))
|
||||
: DialogIme::HostQueueExternalInput(generation, std::move(input));
|
||||
}
|
||||
|
||||
} // namespace Ime
|
||||
|
||||
@@ -534,8 +534,7 @@ Graphics::ImageInfo BufferAttributeGroup::ImageInfo(const VideoOutBuffer& buffer
|
||||
if (!Graphics::DecodeVideoOutPixelFormat(attribute.pixel_format, pixel_format)) {
|
||||
EXIT("unsupported video-out pixel format: 0x%016" PRIx64 "\n", attribute.pixel_format);
|
||||
}
|
||||
const auto tile_mode =
|
||||
Graphics::Prospero::GpuEnumValue(Graphics::Prospero::TileMode::kRenderTarget);
|
||||
const auto tile_mode = Graphics::Prospero::TileMode::kRenderTarget;
|
||||
const auto pitch =
|
||||
Graphics::TileGetTexturePitch(pixel_format.guest_format, attribute.width, tile_mode);
|
||||
Graphics::TileSizeAlign total {};
|
||||
|
||||
@@ -119,7 +119,8 @@ public:
|
||||
}
|
||||
|
||||
const bool reserved =
|
||||
binding.key == SDLK_ESCAPE || binding.key == SDLK_SPACE || binding.key == SDLK_F1;
|
||||
binding.key == SDLK_ESCAPE || binding.key == SDLK_SPACE || binding.key == SDLK_F1 ||
|
||||
binding.key == SDLK_F11;
|
||||
if (binding.control == INVALID_CONTROL || reserved ||
|
||||
(binding.key == SDLK_UNKNOWN && binding.mouse_button == 0)) {
|
||||
EXIT("Invalid input mapping: %s\n", value.c_str());
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "common/profiler.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/subsystems.h"
|
||||
#include "common/systemInfo.h"
|
||||
#include "common/threads.h"
|
||||
#include "common/timer.h"
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "common/profiler.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/subsystems.h"
|
||||
#include "common/systemInfo.h"
|
||||
#include "common/threads.h"
|
||||
#include "common/timer.h"
|
||||
|
||||
@@ -219,7 +219,24 @@ static void GameEventTerminate(WindowLoopState& game) {
|
||||
game.need_exit = true;
|
||||
}
|
||||
|
||||
static void ToggleDesktopFullscreen() {
|
||||
if (g_window == nullptr || g_window->window == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto flags = static_cast<uint32_t>(SDL_GetWindowFlags(g_window->window));
|
||||
const bool fullscreen =
|
||||
(flags & static_cast<uint32_t>(SDL_WINDOW_FULLSCREEN_DESKTOP)) != 0u;
|
||||
const auto mode =
|
||||
fullscreen ? 0u : static_cast<uint32_t>(SDL_WINDOW_FULLSCREEN_DESKTOP);
|
||||
if (SDL_SetWindowFullscreen(g_window->window, mode) != 0) {
|
||||
LOGF("Toggle fullscreen failed: %s\n", SDL_GetError());
|
||||
}
|
||||
}
|
||||
|
||||
static void GameEventKeyboard(WindowLoopState& game, const EventKeyboard& key) {
|
||||
static SDL_Keycode fullscreen_key = SDLK_UNKNOWN;
|
||||
|
||||
#ifdef KYTY_DBG_INPUT
|
||||
LOGF("Key: time = %.04f, %s%s, %s%s, %s, scan = %d, key = %d, mod = %04" PRIx16 "\n",
|
||||
key.timestamp_seconds, (key.down ? "down" : ""), (key.up ? "up" : ""),
|
||||
@@ -237,13 +254,30 @@ static void GameEventKeyboard(WindowLoopState& game, const EventKeyboard& key) {
|
||||
RenderDocRequestCapture();
|
||||
}
|
||||
break;
|
||||
case SDLK_F11:
|
||||
if (!key.repeat) {
|
||||
ToggleDesktopFullscreen();
|
||||
}
|
||||
break;
|
||||
case SDLK_RETURN:
|
||||
case SDLK_KP_ENTER:
|
||||
if (!key.repeat && (key.mod & KMOD_ALT) != 0) {
|
||||
ToggleDesktopFullscreen();
|
||||
fullscreen_key = key.key_code;
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if ((key.down || key.up) && !key.repeat) {
|
||||
const bool fullscreen_key_event =
|
||||
fullscreen_key != SDLK_UNKNOWN && key.key_code == fullscreen_key;
|
||||
if (fullscreen_key_event && key.up) {
|
||||
fullscreen_key = SDLK_UNKNOWN;
|
||||
}
|
||||
if ((key.down || key.up) && !key.repeat && !fullscreen_key_event) {
|
||||
HostInputKey(key.key_code, key.down);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -893,7 +893,8 @@ uint32_t EmitByteAddress(EmitterState& state, const IR::Instruction& inst, uint3
|
||||
uint32_t StorageBufferPackedStride(const EmitterState& state, const IR::MemoryInfo& mem,
|
||||
uint32_t use_pc);
|
||||
|
||||
uint32_t StorageBufferFormat(const EmitterState& state, const IR::MemoryInfo& mem, uint32_t use_pc);
|
||||
Prospero::BufferFormat StorageBufferFormat(const EmitterState& state, const IR::MemoryInfo& mem,
|
||||
uint32_t use_pc);
|
||||
|
||||
bool ShouldApplyBufferAddTid(const IR::Instruction& inst);
|
||||
|
||||
|
||||
@@ -153,8 +153,8 @@ uint32_t StorageBufferPackedStride(const EmitterState& state, const IR::MemoryIn
|
||||
return state.program.info.buffers[mem.resource].packed_stride;
|
||||
}
|
||||
|
||||
uint32_t StorageBufferFormat(const EmitterState& state, const IR::MemoryInfo& mem,
|
||||
uint32_t use_pc) {
|
||||
Prospero::BufferFormat StorageBufferFormat(const EmitterState& state, const IR::MemoryInfo& mem,
|
||||
uint32_t use_pc) {
|
||||
(void)use_pc;
|
||||
if (mem.resource >= state.program.info.buffers.size()) {
|
||||
ExitDescriptorBindingFailure(state, IR::DescriptorBindingKind::Buffers, mem.resource,
|
||||
@@ -749,8 +749,7 @@ Prospero::BufferFormat FormattedBufferFormat(const EmitterState& state,
|
||||
const IR::Instruction& inst) {
|
||||
return inst.memory.typed
|
||||
? Format::DecodeTBufferFormat(inst.memory.data_format, inst.memory.number_format)
|
||||
: static_cast<Prospero::BufferFormat>(
|
||||
StorageBufferFormat(state, inst.memory, inst.pc));
|
||||
: StorageBufferFormat(state, inst.memory, inst.pc);
|
||||
}
|
||||
|
||||
IR::Instruction WithFormatComponentByteOffset(const IR::Instruction& inst,
|
||||
|
||||
@@ -64,26 +64,26 @@ VertexInputScalarKind VertexParameterScalarKind(const EmitterState& state, uint3
|
||||
}
|
||||
|
||||
switch (state.vertex_input_info->resources[location].Format()) {
|
||||
case 5:
|
||||
case 11:
|
||||
case 18:
|
||||
case 20:
|
||||
case 27:
|
||||
case 60:
|
||||
case 62:
|
||||
case 69:
|
||||
case 72:
|
||||
case 75: return VertexInputScalarKind::Uint;
|
||||
case 6:
|
||||
case 12:
|
||||
case 19:
|
||||
case 21:
|
||||
case 28:
|
||||
case 61:
|
||||
case 63:
|
||||
case 70:
|
||||
case 73:
|
||||
case 76: return VertexInputScalarKind::Sint;
|
||||
case Prospero::BufferFormat::k8UInt:
|
||||
case Prospero::BufferFormat::k16UInt:
|
||||
case Prospero::BufferFormat::k8_8UInt:
|
||||
case Prospero::BufferFormat::k32UInt:
|
||||
case Prospero::BufferFormat::k16_16UInt:
|
||||
case Prospero::BufferFormat::k8_8_8_8UInt:
|
||||
case Prospero::BufferFormat::k32_32UInt:
|
||||
case Prospero::BufferFormat::k16_16_16_16UInt:
|
||||
case Prospero::BufferFormat::k32_32_32UInt:
|
||||
case Prospero::BufferFormat::k32_32_32_32UInt: return VertexInputScalarKind::Uint;
|
||||
case Prospero::BufferFormat::k8SInt:
|
||||
case Prospero::BufferFormat::k16SInt:
|
||||
case Prospero::BufferFormat::k8_8SInt:
|
||||
case Prospero::BufferFormat::k32SInt:
|
||||
case Prospero::BufferFormat::k16_16SInt:
|
||||
case Prospero::BufferFormat::k8_8_8_8SInt:
|
||||
case Prospero::BufferFormat::k32_32SInt:
|
||||
case Prospero::BufferFormat::k16_16_16_16SInt:
|
||||
case Prospero::BufferFormat::k32_32_32SInt:
|
||||
case Prospero::BufferFormat::k32_32_32_32SInt: return VertexInputScalarKind::Sint;
|
||||
default: return VertexInputScalarKind::Float;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,13 +220,13 @@ bool ValidateResourceSpecialization(const Program& program, const ResourceSnapsh
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const auto format = (descriptor.dwords[1] >> 20u) & 0x1ffu;
|
||||
const bool raw_sint_storage =
|
||||
storage && format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32SInt) &&
|
||||
!image.read && !image.atomic;
|
||||
const bool uint_descriptor = Prospero::IsUintTextureFormat(format) || raw_sint_storage;
|
||||
const auto uint_program = image.kind == ResourceKind::ImageUint ||
|
||||
image.kind == ResourceKind::StorageImageUint;
|
||||
const auto format =
|
||||
static_cast<Prospero::BufferFormat>((descriptor.dwords[1] >> 20u) & 0x1ffu);
|
||||
const bool raw_sint_storage = storage && format == Prospero::BufferFormat::k32SInt &&
|
||||
!image.read && !image.atomic;
|
||||
const bool uint_descriptor = Prospero::IsUintTextureFormat(format) || raw_sint_storage;
|
||||
const auto uint_program = image.kind == ResourceKind::ImageUint ||
|
||||
image.kind == ResourceKind::StorageImageUint;
|
||||
if (uint_descriptor != uint_program && !(image.atomic && uint_program)) {
|
||||
if (error != nullptr) {
|
||||
*error = fmt::format(
|
||||
@@ -415,12 +415,12 @@ bool SpecializeResources(Program& program, const ResourceSnapshot& snapshot, std
|
||||
image.kind == ResourceKind::StorageImageUint) {
|
||||
image.storage_swizzle = DescriptorImageSwizzle(descriptor);
|
||||
}
|
||||
const auto format = (descriptor.dwords[1] >> 20u) & 0x1ffu;
|
||||
const auto format =
|
||||
static_cast<Prospero::BufferFormat>((descriptor.dwords[1] >> 20u) & 0x1ffu);
|
||||
const bool storage = image.kind == ResourceKind::StorageImage ||
|
||||
image.kind == ResourceKind::StorageImageUint;
|
||||
const bool raw_sint_storage =
|
||||
storage && format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32SInt) &&
|
||||
!image.read && !image.atomic;
|
||||
storage && format == Prospero::BufferFormat::k32SInt && !image.read && !image.atomic;
|
||||
const bool uint_image = Prospero::IsUintTextureFormat(format) || raw_sint_storage;
|
||||
if (uint_image) {
|
||||
switch (image.kind) {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "common/common.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "graphics/guest_gpu/gpu_defs.h"
|
||||
#include "graphics/shader/recompiler/cfg/ShaderCFG.h"
|
||||
#include "graphics/shader/recompiler/decompiler/ShaderDecoder.h"
|
||||
#include "graphics/shader/shader.h"
|
||||
@@ -276,17 +277,17 @@ struct SrtPlan {
|
||||
struct BufferResource {
|
||||
static constexpr uint32_t NoImageAlias = UINT32_MAX;
|
||||
|
||||
uint32_t source = 0;
|
||||
uint32_t first_use_pc = 0;
|
||||
uint32_t max_byte_extent = 0;
|
||||
uint32_t packed_stride = 0;
|
||||
uint32_t descriptor_format = 0;
|
||||
uint32_t image_alias = NoImageAlias;
|
||||
bool read = false;
|
||||
bool written = false;
|
||||
bool atomic = false;
|
||||
bool formatted = false;
|
||||
bool scalar = false;
|
||||
uint32_t source = 0;
|
||||
uint32_t first_use_pc = 0;
|
||||
uint32_t max_byte_extent = 0;
|
||||
uint32_t packed_stride = 0;
|
||||
Prospero::BufferFormat descriptor_format = Prospero::BufferFormat::kInvalid;
|
||||
uint32_t image_alias = NoImageAlias;
|
||||
bool read = false;
|
||||
bool written = false;
|
||||
bool atomic = false;
|
||||
bool formatted = false;
|
||||
bool scalar = false;
|
||||
|
||||
bool operator==(const BufferResource& other) const = default;
|
||||
};
|
||||
|
||||
@@ -535,7 +535,8 @@ static void ShaderDetectBuffers(ShaderVertexInputInfo& info) {
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t VertexAttribFormatToBufferFormat(uint32_t format) {
|
||||
static Prospero::BufferFormat
|
||||
VertexAttribFormatToBufferFormat(Prospero::VertexAttribFormat format) {
|
||||
struct FormatMap {
|
||||
Prospero::VertexAttribFormat vertex;
|
||||
Prospero::BufferFormat buffer;
|
||||
@@ -633,12 +634,12 @@ static uint32_t VertexAttribFormatToBufferFormat(uint32_t format) {
|
||||
};
|
||||
|
||||
for (const auto& entry: format_map) {
|
||||
if (format == Prospero::GpuEnumValue(entry.vertex)) {
|
||||
return Prospero::GpuEnumValue(entry.buffer);
|
||||
if (format == entry.vertex) {
|
||||
return entry.buffer;
|
||||
}
|
||||
}
|
||||
|
||||
return format;
|
||||
return static_cast<Prospero::BufferFormat>(static_cast<uint32_t>(format));
|
||||
}
|
||||
|
||||
static void ShaderApplyAttribSemantics(ShaderVertexInputInfo& info,
|
||||
@@ -659,8 +660,9 @@ static void ShaderApplyAttribSemantics(ShaderVertexInputInfo& info,
|
||||
|
||||
LOGF("reg = %u, size = %u, va[%u] = 0x%08" PRIx32 "\n", reg, size, i, attrib[in.semantic]);
|
||||
|
||||
size_t index = attrib[in.semantic] & 0x1fu;
|
||||
uint32_t format = (attrib[in.semantic] >> 5u) & 0x1ffu;
|
||||
size_t index = attrib[in.semantic] & 0x1fu;
|
||||
auto format =
|
||||
static_cast<Prospero::VertexAttribFormat>((attrib[in.semantic] >> 5u) & 0x1ffu);
|
||||
uint32_t offset = (attrib[in.semantic] >> 14u) & 0xfffu;
|
||||
uint32_t fetch_index = (attrib[in.semantic] >> 26u) & 0x1u;
|
||||
|
||||
@@ -690,17 +692,19 @@ static void ShaderApplyAttribSemantics(ShaderVertexInputInfo& info,
|
||||
r.fields[1] = sharp[1];
|
||||
r.fields[2] = sharp[2];
|
||||
r.fields[3] = sharp[3];
|
||||
if (format != 0) {
|
||||
if (format != Prospero::VertexAttribFormat::kInvalid) {
|
||||
auto buffer_format = VertexAttribFormatToBufferFormat(format);
|
||||
static std::atomic<uint64_t> log_count = 0;
|
||||
auto log_id = log_count.fetch_add(1);
|
||||
if (log_id < 64) {
|
||||
LOGF("\t temporary: PS5 vertex attrib semantic %u uses attrib format %u -> buffer "
|
||||
"format %u, offset %u, buffer index %zu\n",
|
||||
static_cast<uint32_t>(in.semantic), format, buffer_format, offset, index);
|
||||
static_cast<uint32_t>(in.semantic), static_cast<uint32_t>(format),
|
||||
static_cast<uint32_t>(buffer_format), offset, index);
|
||||
}
|
||||
const auto buffer_format_raw = static_cast<uint32_t>(buffer_format);
|
||||
r.fields[3] = (r.fields[3] & ~((0x7fu << 12u) | 0xfffu)) |
|
||||
((buffer_format & 0x7fu) << 12u) | DstSel(4, 5, 6, 7);
|
||||
((buffer_format_raw & 0x7fu) << 12u) | DstSel(4, 5, 6, 7);
|
||||
}
|
||||
if (offset != 0) {
|
||||
r.UpdateAddress48(r.Base48() + offset);
|
||||
@@ -1011,7 +1015,7 @@ static std::string ShaderDescribeSpecialization(const ShaderRecompiler::IR::Prog
|
||||
for (uint32_t i = 0; i < program.info.buffers.size(); i++) {
|
||||
const auto& buffer = program.info.buffers[i];
|
||||
ret += fmt::format(" b{}[stride={} format={}]", i, buffer.packed_stride,
|
||||
buffer.descriptor_format);
|
||||
static_cast<uint32_t>(buffer.descriptor_format));
|
||||
}
|
||||
for (uint32_t i = 0; i < program.info.images.size(); i++) {
|
||||
const auto& image = program.info.images[i];
|
||||
@@ -1047,7 +1051,7 @@ static void ShaderAppendNativeSpecialization(std::vector<uint32_t>&
|
||||
ids.push_back(static_cast<uint32_t>(program.info.buffers.size()));
|
||||
for (const auto& buffer: program.info.buffers) {
|
||||
ids.push_back(buffer.packed_stride);
|
||||
ids.push_back(buffer.descriptor_format);
|
||||
ids.push_back(static_cast<uint32_t>(buffer.descriptor_format));
|
||||
}
|
||||
ids.push_back(static_cast<uint32_t>(program.info.images.size()));
|
||||
for (const auto& image: program.info.images) {
|
||||
@@ -1250,7 +1254,7 @@ void ShaderDbgDumpInputInfo(const ShaderVertexInputInfo& info) {
|
||||
r.DstSelX(), r.DstSelY(), r.DstSelZ(), r.DstSelW());
|
||||
LOGF("\t\t Format() = %" PRIu8 "\n"
|
||||
"\t\t OutOfBounds() = %" PRIu8 "\n",
|
||||
r.Format(), r.OutOfBounds());
|
||||
r.RawFormat(), r.OutOfBounds());
|
||||
LOGF("\t\t AddTid() = %s\n", r.AddTid() ? "true" : "false");
|
||||
}
|
||||
|
||||
@@ -1596,7 +1600,7 @@ ShaderId ShaderGetIdVS(const HW::VertexShaderInfo& regs, const ShaderVertexInput
|
||||
ret.ids.push_back(r.DstSelY());
|
||||
ret.ids.push_back(r.DstSelZ());
|
||||
ret.ids.push_back(r.DstSelW());
|
||||
ret.ids.push_back(r.Format());
|
||||
ret.ids.push_back(r.RawFormat());
|
||||
ret.ids.push_back(r.OutOfBounds());
|
||||
ret.ids.push_back(static_cast<uint32_t>(r.AddTid()));
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ ResourceDescriptorType ShaderClassifyResourceDescriptor(const uint32_t* desc) {
|
||||
default: break;
|
||||
}
|
||||
|
||||
return (raw_type & Prospero::GpuEnumValue(Prospero::ImageType::kColor1D)) == 0
|
||||
return (raw_type & static_cast<uint32_t>(Prospero::ImageType::kColor1D)) == 0
|
||||
? ResourceDescriptorType::Buffer
|
||||
: ResourceDescriptorType::Unused;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "common/abi.h"
|
||||
#include "common/common.h"
|
||||
#include "graphics/guest_gpu/gpu_defs.h"
|
||||
|
||||
namespace Libs::Graphics {
|
||||
|
||||
@@ -61,7 +62,10 @@ struct ShaderBufferResource {
|
||||
[[nodiscard]] uint64_t Base48() const {
|
||||
return (fields[0] | (static_cast<uint64_t>(fields[1]) << 32u)) & 0xFFFFFFFFFFFFu;
|
||||
}
|
||||
[[nodiscard]] uint8_t Format() const { return (fields[3] >> 12u) & 0x7Fu; }
|
||||
[[nodiscard]] uint8_t RawFormat() const { return (fields[3] >> 12u) & 0x7Fu; }
|
||||
[[nodiscard]] Prospero::BufferFormat Format() const {
|
||||
return static_cast<Prospero::BufferFormat>(RawFormat());
|
||||
}
|
||||
[[nodiscard]] uint8_t OutOfBounds() const { return (fields[3] >> 28u) & 0x3u; }
|
||||
[[nodiscard]] uint8_t Type() const { return (fields[3] >> 30u) & 0x3u; }
|
||||
};
|
||||
@@ -69,25 +73,31 @@ struct ShaderBufferResource {
|
||||
struct ShaderTextureResource {
|
||||
uint32_t fields[8] = {0};
|
||||
|
||||
[[nodiscard]] uint16_t MinLod() const { return (fields[1] >> 8u) & 0xFFFu; }
|
||||
[[nodiscard]] uint8_t DstSelX() const { return (fields[3] >> 0u) & 0x7u; }
|
||||
[[nodiscard]] uint8_t DstSelY() const { return (fields[3] >> 3u) & 0x7u; }
|
||||
[[nodiscard]] uint8_t DstSelZ() const { return (fields[3] >> 6u) & 0x7u; }
|
||||
[[nodiscard]] uint8_t DstSelW() const { return (fields[3] >> 9u) & 0x7u; }
|
||||
[[nodiscard]] uint32_t DstSelXY() const { return (fields[3] >> 0u) & 0x3Fu; }
|
||||
[[nodiscard]] uint32_t DstSelXYZ() const { return (fields[3] >> 0u) & 0x1FFu; }
|
||||
[[nodiscard]] uint32_t DstSelXYZW() const { return (fields[3] >> 0u) & 0xFFFu; }
|
||||
[[nodiscard]] uint8_t BaseLevel() const { return (fields[3] >> 12u) & 0xFu; }
|
||||
[[nodiscard]] uint8_t LastLevel() const { return (fields[3] >> 16u) & 0xFu; }
|
||||
[[nodiscard]] uint8_t TileMode() const { return (fields[3] >> 20u) & 0x1Fu; }
|
||||
[[nodiscard]] uint8_t Type() const { return (fields[3] >> 28u) & 0xFu; }
|
||||
[[nodiscard]] uint16_t MinLod() const { return (fields[1] >> 8u) & 0xFFFu; }
|
||||
[[nodiscard]] uint8_t DstSelX() const { return (fields[3] >> 0u) & 0x7u; }
|
||||
[[nodiscard]] uint8_t DstSelY() const { return (fields[3] >> 3u) & 0x7u; }
|
||||
[[nodiscard]] uint8_t DstSelZ() const { return (fields[3] >> 6u) & 0x7u; }
|
||||
[[nodiscard]] uint8_t DstSelW() const { return (fields[3] >> 9u) & 0x7u; }
|
||||
[[nodiscard]] uint32_t DstSelXY() const { return (fields[3] >> 0u) & 0x3Fu; }
|
||||
[[nodiscard]] uint32_t DstSelXYZ() const { return (fields[3] >> 0u) & 0x1FFu; }
|
||||
[[nodiscard]] uint32_t DstSelXYZW() const { return (fields[3] >> 0u) & 0xFFFu; }
|
||||
[[nodiscard]] uint8_t BaseLevel() const { return (fields[3] >> 12u) & 0xFu; }
|
||||
[[nodiscard]] uint8_t LastLevel() const { return (fields[3] >> 16u) & 0xFu; }
|
||||
[[nodiscard]] Prospero::TileMode TileMode() const {
|
||||
return static_cast<Prospero::TileMode>((fields[3] >> 20u) & 0x1Fu);
|
||||
}
|
||||
[[nodiscard]] Prospero::ImageType Type() const {
|
||||
return static_cast<Prospero::ImageType>((fields[3] >> 28u) & 0xFu);
|
||||
}
|
||||
[[nodiscard]] uint16_t Depth() const { return (fields[4] >> 0u) & 0x1FFFu; }
|
||||
|
||||
[[nodiscard]] uint64_t Base40() const {
|
||||
return ((fields[0] | (static_cast<uint64_t>(fields[1]) << 32u)) & 0xFFFFFFFFFFu) << 8u;
|
||||
}
|
||||
[[nodiscard]] bool IsNull() const { return Base40() == 0; }
|
||||
[[nodiscard]] uint16_t Format() const { return (fields[1] >> 20u) & 0x1FFu; }
|
||||
[[nodiscard]] bool IsNull() const { return Base40() == 0; }
|
||||
[[nodiscard]] Prospero::BufferFormat Format() const {
|
||||
return static_cast<Prospero::BufferFormat>((fields[1] >> 20u) & 0x1FFu);
|
||||
}
|
||||
[[nodiscard]] uint16_t Width5() const {
|
||||
return ((fields[1] >> 30u) & 0x3u) | (((fields[2] >> 0u) & 0xFFFu) << 2u);
|
||||
}
|
||||
|
||||
@@ -337,21 +337,23 @@ std::filesystem::path MountPoints::GetRealDirectory(const std::string& mounted_d
|
||||
return mounted_directory;
|
||||
}
|
||||
|
||||
KYTY_SUBSYSTEM_INIT(FileSystem) {
|
||||
void Initialize() {
|
||||
g_mount_points = new MountPoints;
|
||||
g_files = new FileDescriptors;
|
||||
}
|
||||
|
||||
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(FileSystem) {
|
||||
void EmergencyShutdown() {
|
||||
if (g_files != nullptr) {
|
||||
g_files->CloseAll();
|
||||
}
|
||||
}
|
||||
|
||||
KYTY_SUBSYSTEM_DESTROY(FileSystem) {
|
||||
if (g_files != nullptr) {
|
||||
g_files->CloseAll();
|
||||
}
|
||||
void Shutdown() {
|
||||
EmergencyShutdown();
|
||||
delete g_files;
|
||||
delete g_mount_points;
|
||||
g_files = nullptr;
|
||||
g_mount_points = nullptr;
|
||||
}
|
||||
|
||||
void Mount(const std::filesystem::path& folder, const std::string& point) {
|
||||
|
||||
+10
-2
@@ -4,7 +4,6 @@
|
||||
#include "common/abi.h"
|
||||
#include "common/common.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/subsystems.h"
|
||||
#include "kernel/pthread.h"
|
||||
|
||||
#include <filesystem>
|
||||
@@ -33,7 +32,16 @@ struct FileStat {
|
||||
unsigned int: (8 / 2) * (16 - static_cast<int>(sizeof(KernelTimespec)));
|
||||
};
|
||||
|
||||
KYTY_SUBSYSTEM_DEFINE(FileSystem);
|
||||
void Initialize();
|
||||
void Shutdown();
|
||||
void EmergencyShutdown();
|
||||
|
||||
struct Lifecycle {
|
||||
static constexpr const char* name = "FileSystem";
|
||||
static constexpr auto initialize = Libs::LibKernel::FileSystem::Initialize;
|
||||
static constexpr auto shutdown = Libs::LibKernel::FileSystem::Shutdown;
|
||||
static constexpr auto emergency_shutdown = Libs::LibKernel::FileSystem::EmergencyShutdown;
|
||||
};
|
||||
|
||||
void Mount(const std::filesystem::path& folder, const std::string& point);
|
||||
void Umount(const std::string& folder_or_point);
|
||||
|
||||
@@ -976,7 +976,7 @@ static bool SelfTestSub64SharedPlaceholderAlias() {
|
||||
|
||||
static bool ReplaceFixedRangeWithReserved(uint64_t start, uint64_t size);
|
||||
|
||||
KYTY_SUBSYSTEM_INIT(Memory) {
|
||||
void Initialize() {
|
||||
g_flexible_memory_size_frozen = true;
|
||||
VirtualMemory::Init();
|
||||
g_guest_address_space = std::make_unique<GuestAddressSpace>(PhysicalMemory::TotalSize());
|
||||
@@ -988,9 +988,7 @@ KYTY_SUBSYSTEM_INIT(Memory) {
|
||||
EXIT_IF(!SelfTestSub64SharedPlaceholderAlias());
|
||||
}
|
||||
|
||||
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Memory) {}
|
||||
|
||||
KYTY_SUBSYSTEM_DESTROY(Memory) {
|
||||
void Shutdown() {
|
||||
g_pooled_memory.reset();
|
||||
g_flexible_memory.reset();
|
||||
g_physical_memory.reset();
|
||||
|
||||
+8
-2
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "common/abi.h"
|
||||
#include "common/common.h"
|
||||
#include "common/subsystems.h"
|
||||
#include "common/virtualMemory.h"
|
||||
|
||||
namespace Libs::Graphics {
|
||||
@@ -13,7 +12,14 @@ enum class PageFaultAccess;
|
||||
|
||||
namespace Libs::LibKernel::Memory {
|
||||
|
||||
KYTY_SUBSYSTEM_DEFINE(Memory);
|
||||
void Initialize();
|
||||
void Shutdown();
|
||||
|
||||
struct Lifecycle {
|
||||
static constexpr const char* name = "Memory";
|
||||
static constexpr auto initialize = Libs::LibKernel::Memory::Initialize;
|
||||
static constexpr auto shutdown = Libs::LibKernel::Memory::Shutdown;
|
||||
};
|
||||
|
||||
using callback_func_t = void (*)(uintptr_t addr, size_t size);
|
||||
|
||||
|
||||
@@ -1124,7 +1124,7 @@ void* PthreadCreateMainGuestStack() {
|
||||
return stack_top;
|
||||
}
|
||||
|
||||
KYTY_SUBSYSTEM_INIT(Pthread) {
|
||||
void Initialize() {
|
||||
PRINT_NAME_ENABLE(false);
|
||||
|
||||
EXIT_IF(g_pthread_context != nullptr);
|
||||
@@ -1157,10 +1157,6 @@ KYTY_SUBSYSTEM_INIT(Pthread) {
|
||||
thread.Detach();
|
||||
}
|
||||
|
||||
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Pthread) {}
|
||||
|
||||
KYTY_SUBSYSTEM_DESTROY(Pthread) {}
|
||||
|
||||
static int PthreadAttrCopy(PthreadAttr* dst, const PthreadAttr* src) {
|
||||
if (dst == nullptr || *dst == nullptr || src == nullptr || *src == nullptr) {
|
||||
return KERNEL_ERROR_EINVAL;
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "common/abi.h"
|
||||
#include "common/common.h"
|
||||
#include "common/subsystems.h"
|
||||
|
||||
// IWYU pragma: no_include <pthread.h>
|
||||
|
||||
@@ -19,7 +18,12 @@ namespace Libs {
|
||||
|
||||
namespace LibKernel {
|
||||
|
||||
KYTY_SUBSYSTEM_DEFINE(Pthread);
|
||||
void Initialize();
|
||||
|
||||
struct PthreadLifecycle {
|
||||
static constexpr const char* name = "Pthread";
|
||||
static constexpr auto initialize = Libs::LibKernel::Initialize;
|
||||
};
|
||||
|
||||
struct PthreadAttrPrivate;
|
||||
struct PthreadPrivate;
|
||||
|
||||
@@ -335,6 +335,23 @@ static bool FindTerminal(QString* program, QStringList* prefix) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
// Quote one token for cmd.exe so paths with spaces survive /K parsing.
|
||||
static QString WinCmdQuote(QString value) {
|
||||
value.replace(QLatin1Char('"'), QStringLiteral("\\\""));
|
||||
return QLatin1Char('"') + value + QLatin1Char('"');
|
||||
}
|
||||
|
||||
static QString BuildWinCmdKCommand(const QString& interpreter, const QStringList& args) {
|
||||
QString command = WinCmdQuote(QDir::toNativeSeparators(interpreter));
|
||||
for (const auto& arg: args) {
|
||||
command += QLatin1Char(' ');
|
||||
command += WinCmdQuote(arg);
|
||||
}
|
||||
return command;
|
||||
}
|
||||
#endif
|
||||
|
||||
void MainDialog::RunInterpreter(QProcess* process, const Configuration& info) {
|
||||
const auto& interpreter = m_p->GetInterpreter();
|
||||
|
||||
@@ -359,22 +376,23 @@ void MainDialog::RunInterpreter(QProcess* process, const Configuration& info) {
|
||||
{
|
||||
QString terminal;
|
||||
QStringList terminal_prefix;
|
||||
// Pass the script as a file argument (not bash -c) so paths with spaces work.
|
||||
if (FindTerminal(&terminal, &terminal_prefix)) {
|
||||
process->setProgram(terminal);
|
||||
process->setArguments(terminal_prefix + QStringList {"bash", "-c", bash_file_name});
|
||||
process->setArguments(terminal_prefix + QStringList {"bash", bash_file_name});
|
||||
} else {
|
||||
// Run without a terminal as a fallback.
|
||||
process->setProgram(QStringLiteral("bash"));
|
||||
process->setArguments({QStringLiteral("-c"), bash_file_name});
|
||||
process->setArguments({bash_file_name});
|
||||
}
|
||||
}
|
||||
#elif defined(_WIN32)
|
||||
{
|
||||
// Use nativeArguments so Qt does not re-quote the /K command string.
|
||||
process->setProgram(CMD_EXE);
|
||||
QStringList process_args;
|
||||
process_args << QStringLiteral("/K") << interpreter;
|
||||
process_args += args;
|
||||
process->setArguments(process_args);
|
||||
process->setArguments({});
|
||||
process->setNativeArguments(QStringLiteral("/K \"") +
|
||||
BuildWinCmdKCommand(interpreter, args) + QLatin1Char('"'));
|
||||
}
|
||||
#else
|
||||
process->setProgram(interpreter);
|
||||
|
||||
+80
-67
@@ -43,7 +43,7 @@ namespace Libs::Graphics {
|
||||
|
||||
static RenderContext* g_renderer = nullptr;
|
||||
|
||||
KYTY_SUBSYSTEM_INIT(Graphics) {
|
||||
void Initialize() {
|
||||
// Some games lock up if this is not called first
|
||||
if (Config::RenderDocEnabled()) {
|
||||
RenderDocInit();
|
||||
@@ -59,9 +59,7 @@ KYTY_SUBSYSTEM_INIT(Graphics) {
|
||||
ShaderInit();
|
||||
}
|
||||
|
||||
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Graphics) {}
|
||||
|
||||
KYTY_SUBSYSTEM_DESTROY(Graphics) {
|
||||
void Shutdown() {
|
||||
EXIT_IF(g_renderer == nullptr);
|
||||
g_renderer->ShutdownGpu();
|
||||
VideoOut::VideoOutShutdown();
|
||||
@@ -1076,18 +1074,18 @@ int KYTY_SYSV_ABI GraphicsSetUcRegIndirectPatchAddRegisters(uint32_t* cmd, uint3
|
||||
static uint32_t GraphicsPrimitiveTypeToGsOut(uint32_t prim_type) {
|
||||
switch (static_cast<Prospero::PrimitiveType>(prim_type)) {
|
||||
case Prospero::PrimitiveType::kPointList:
|
||||
return Prospero::GpuEnumValue(Prospero::GsOutputPrimitiveType::kPoints);
|
||||
return static_cast<uint32_t>(Prospero::GsOutputPrimitiveType::kPoints);
|
||||
case Prospero::PrimitiveType::kLineList:
|
||||
case Prospero::PrimitiveType::kLineStrip:
|
||||
case Prospero::PrimitiveType::kLineListAdjacency:
|
||||
case Prospero::PrimitiveType::kLineStripAdjacency:
|
||||
case Prospero::PrimitiveType::kLineLoop:
|
||||
return Prospero::GpuEnumValue(Prospero::GsOutputPrimitiveType::kLines);
|
||||
return static_cast<uint32_t>(Prospero::GsOutputPrimitiveType::kLines);
|
||||
case Prospero::PrimitiveType::kRectList:
|
||||
return Prospero::GpuEnumValue(Prospero::GsOutputPrimitiveType::k2dRectangle);
|
||||
return static_cast<uint32_t>(Prospero::GsOutputPrimitiveType::k2dRectangle);
|
||||
case Prospero::PrimitiveType::kRectListLegacy:
|
||||
return Prospero::GpuEnumValue(Prospero::GsOutputPrimitiveType::kRectList);
|
||||
default: return Prospero::GpuEnumValue(Prospero::GsOutputPrimitiveType::kTriangles);
|
||||
return static_cast<uint32_t>(Prospero::GsOutputPrimitiveType::kRectList);
|
||||
default: return static_cast<uint32_t>(Prospero::GsOutputPrimitiveType::kTriangles);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1261,8 +1259,8 @@ int KYTY_SYSV_ABI GraphicsGetGsOversubscription(ShaderRegister* regs, const Shad
|
||||
regs[1].value |= FULL_SH_OVERSUBSCRIPTION;
|
||||
} else {
|
||||
const auto range = std::max(expanded.export_count - base.export_count, 1u);
|
||||
const auto value = static_cast<uint32_t>(
|
||||
std::min<uint64_t>((static_cast<uint64_t>(target - base.export_count) * 127u) / range, 127));
|
||||
const auto value = static_cast<uint32_t>(std::min<uint64_t>(
|
||||
(static_cast<uint64_t>(target - base.export_count) * 127u) / range, 127));
|
||||
regs[0].value |= FULL_PC_OVERSUBSCRIPTION;
|
||||
regs[1].value = (regs[1].value & ~FULL_SH_OVERSUBSCRIPTION) | (value << 16u);
|
||||
}
|
||||
@@ -3859,12 +3857,6 @@ struct TessellationDriverState {
|
||||
|
||||
static TessellationDriverState g_tessellation_driver_state {};
|
||||
|
||||
struct Packet {
|
||||
uint32_t* addr;
|
||||
uint32_t dw_num;
|
||||
uint8_t pad[4];
|
||||
};
|
||||
|
||||
static bool dcb_has_queued_interrupt(const uint32_t* dcb, uint32_t size_in_dwords) {
|
||||
if (dcb == nullptr) {
|
||||
return false;
|
||||
@@ -3902,11 +3894,11 @@ int KYTY_SYSV_ABI GraphicsDriverSubmitDcb(const Packet* packet) {
|
||||
PRINT_NAME();
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(packet == nullptr);
|
||||
EXIT_NOT_IMPLEMENTED(packet->pad[0] != 0);
|
||||
|
||||
LOGF("\t addr = 0x%016" PRIx64 "\n"
|
||||
"\t dw_num = 0x%08" PRIx32 "\n",
|
||||
reinterpret_cast<uint64_t>(packet->addr), packet->dw_num);
|
||||
"\t dw_num = 0x%08" PRIx32 "\n"
|
||||
"\t flags = 0x%02" PRIx8 "\n",
|
||||
reinterpret_cast<uint64_t>(packet->addr), packet->dw_num, packet->flags);
|
||||
|
||||
submit_dcb(packet->addr, packet->dw_num);
|
||||
|
||||
@@ -3935,51 +3927,9 @@ int KYTY_SYSV_ABI GraphicsDriverSubmitMultiDcbs(uint32_t* const* dcb_gpu_addrs,
|
||||
"\t size[%" PRIu32 "] = 0x%08" PRIx32 "\n",
|
||||
i, reinterpret_cast<uint64_t>(dcb), i, size_in_dwords);
|
||||
|
||||
if (dcb == nullptr) {
|
||||
continue;
|
||||
if (dcb != nullptr) {
|
||||
submit_dcb(dcb, size_in_dwords);
|
||||
}
|
||||
submit_dcb(dcb, size_in_dwords);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int KYTY_SYSV_ABI GraphicsDriverSubmitCommandBuffer(uint32_t queue, uint32_t* dcb,
|
||||
uint32_t size_in_dwords) {
|
||||
PRINT_NAME();
|
||||
|
||||
LOGF("\t queue = 0x%08" PRIx32 "\n"
|
||||
"\t dcb = 0x%016" PRIx64 "\n"
|
||||
"\t size = 0x%08" PRIx32 "\n",
|
||||
queue, reinterpret_cast<uint64_t>(dcb), size_in_dwords);
|
||||
|
||||
if (dcb == nullptr || size_in_dwords == 0) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
submit_dcb(dcb, size_in_dwords);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int KYTY_SYSV_ABI GraphicsDriverSubmitMultiCommandBuffers(uint32_t queue, uint32_t* const* dcbs,
|
||||
const uint32_t* sizes_in_dwords,
|
||||
uint32_t count) {
|
||||
PRINT_NAME();
|
||||
|
||||
LOGF("\t queue = 0x%08" PRIx32 "\n"
|
||||
"\t count = %" PRIu32 "\n",
|
||||
queue, count);
|
||||
|
||||
if (count == 0) {
|
||||
return OK;
|
||||
}
|
||||
if (dcbs == nullptr || sizes_in_dwords == nullptr) {
|
||||
return LibKernel::KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
GraphicsDriverSubmitCommandBuffer(queue, dcbs[i], sizes_in_dwords[i]);
|
||||
}
|
||||
|
||||
return OK;
|
||||
@@ -4018,10 +3968,74 @@ static void submit_acb(uint32_t queue, uint32_t* acb, uint32_t size_in_dwords) {
|
||||
g_renderer->GetGpu().SubmitCompute(queue, acb, size_in_dwords, trigger_interrupt_on_done);
|
||||
}
|
||||
|
||||
static uint32_t get_driver_queue(const void* queue_context) {
|
||||
uint32_t queue = 0;
|
||||
std::memcpy(&queue, static_cast<const uint8_t*>(queue_context) + 4, sizeof(queue));
|
||||
return queue;
|
||||
}
|
||||
|
||||
static void submit_command_buffer(uint32_t queue, uint32_t* commands, uint32_t size_in_dwords) {
|
||||
if (commands == nullptr || size_in_dwords == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (queue >= 0x20 && queue < 0x58) {
|
||||
submit_acb(queue, commands, size_in_dwords);
|
||||
} else {
|
||||
submit_dcb(commands, size_in_dwords);
|
||||
}
|
||||
}
|
||||
|
||||
int KYTY_SYSV_ABI GraphicsDriverSubmitCommandBuffer(void* queue_context, const Packet* packet) {
|
||||
PRINT_NAME();
|
||||
|
||||
LOGF("\t queue_context = 0x%016" PRIx64 "\n"
|
||||
"\t packet = 0x%016" PRIx64 "\n",
|
||||
reinterpret_cast<uint64_t>(queue_context), reinterpret_cast<uint64_t>(packet));
|
||||
|
||||
if (queue_context == nullptr || packet == nullptr) {
|
||||
return LibKernel::KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
const uint32_t queue = get_driver_queue(queue_context);
|
||||
LOGF("\t queue = 0x%08" PRIx32 "\n"
|
||||
"\t addr = 0x%016" PRIx64 "\n"
|
||||
"\t size = 0x%08" PRIx32 "\n"
|
||||
"\t flags = 0x%02" PRIx8 "\n",
|
||||
queue, reinterpret_cast<uint64_t>(packet->addr), packet->dw_num, packet->flags);
|
||||
|
||||
submit_command_buffer(queue, packet->addr, packet->dw_num);
|
||||
return OK;
|
||||
}
|
||||
|
||||
int KYTY_SYSV_ABI GraphicsDriverSubmitMultiCommandBuffers(void* queue_context,
|
||||
uint32_t* const* command_buffers,
|
||||
const uint32_t* sizes_in_dwords,
|
||||
uint32_t count) {
|
||||
PRINT_NAME();
|
||||
|
||||
LOGF("\t queue_context = 0x%016" PRIx64 "\n"
|
||||
"\t count = %" PRIu32 "\n",
|
||||
reinterpret_cast<uint64_t>(queue_context), count);
|
||||
|
||||
if (count == 0) {
|
||||
return OK;
|
||||
}
|
||||
if (queue_context == nullptr || command_buffers == nullptr || sizes_in_dwords == nullptr) {
|
||||
return LibKernel::KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
const uint32_t queue = get_driver_queue(queue_context);
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
submit_command_buffer(queue, command_buffers[i], sizes_in_dwords[i]);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
int KYTY_SYSV_ABI GraphicsDriverSubmitAcb(uint32_t queue, const Packet* packet) {
|
||||
PRINT_NAME();
|
||||
|
||||
LOGF("\t queue = 0x%08" PRIx32 "\n"
|
||||
LOGF("\t queue = 0x%08" PRIx32 "\n"
|
||||
"\t packet = 0x%016" PRIx64 "\n",
|
||||
queue, reinterpret_cast<uint64_t>(packet));
|
||||
|
||||
@@ -4031,10 +4045,9 @@ int KYTY_SYSV_ABI GraphicsDriverSubmitAcb(uint32_t queue, const Packet* packet)
|
||||
LOGF("\t acb = 0x%016" PRIx64 "\n"
|
||||
"\t size = 0x%08" PRIx32 "\n"
|
||||
"\t flags = 0x%02" PRIx8 "\n",
|
||||
reinterpret_cast<uint64_t>(packet->addr), packet->dw_num, packet->pad[0]);
|
||||
reinterpret_cast<uint64_t>(packet->addr), packet->dw_num, packet->flags);
|
||||
|
||||
submit_acb(queue, packet->addr, packet->dw_num);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
+24
-8
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "common/abi.h"
|
||||
#include "common/common.h"
|
||||
#include "common/subsystems.h"
|
||||
#include "kernel/eventQueue.h"
|
||||
|
||||
namespace Libs::Graphics {
|
||||
@@ -21,7 +20,14 @@ struct MemoryRange {
|
||||
uint64_t m_size;
|
||||
};
|
||||
|
||||
KYTY_SUBSYSTEM_DEFINE(Graphics);
|
||||
void Initialize();
|
||||
void Shutdown();
|
||||
|
||||
struct Lifecycle {
|
||||
static constexpr const char* name = "Graphics";
|
||||
static constexpr auto initialize = Libs::Graphics::Initialize;
|
||||
static constexpr auto shutdown = Libs::Graphics::Shutdown;
|
||||
};
|
||||
|
||||
void GraphicsDbgDumpDcb(const char* type, uint32_t num_dw, uint32_t* cmd_buffer);
|
||||
|
||||
@@ -285,17 +291,27 @@ uint32_t* KYTY_SYSV_ABI GraphicsDcbSetFlip(CommandBuffer* buf, uint32_t video_ou
|
||||
|
||||
namespace Gen5Driver {
|
||||
|
||||
struct Packet;
|
||||
struct Packet {
|
||||
uint32_t* addr;
|
||||
uint32_t dw_num;
|
||||
uint8_t flags;
|
||||
uint8_t reserved[3];
|
||||
};
|
||||
|
||||
static_assert(sizeof(Packet) == 0x10);
|
||||
static_assert(offsetof(Packet, addr) == 0x0);
|
||||
static_assert(offsetof(Packet, dw_num) == 0x8);
|
||||
static_assert(offsetof(Packet, flags) == 0xc);
|
||||
|
||||
int KYTY_SYSV_ABI GraphicsDriverSubmitDcb(const Packet* packet);
|
||||
int KYTY_SYSV_ABI GraphicsDriverSubmitMultiDcbs(uint32_t* const* dcb_gpu_addrs,
|
||||
const uint32_t* dcb_sizes_in_dwords,
|
||||
uint32_t count);
|
||||
int KYTY_SYSV_ABI GraphicsDriverSubmitCommandBuffer(uint32_t queue, uint32_t* dcb,
|
||||
uint32_t size_in_dwords);
|
||||
int KYTY_SYSV_ABI GraphicsDriverSubmitMultiCommandBuffers(uint32_t queue, uint32_t* const* dcbs,
|
||||
const uint32_t* sizes_in_dwords,
|
||||
uint32_t count);
|
||||
int KYTY_SYSV_ABI GraphicsDriverSubmitCommandBuffer(void* queue_context, const Packet* packet);
|
||||
int KYTY_SYSV_ABI GraphicsDriverSubmitMultiCommandBuffers(void* queue_context,
|
||||
uint32_t* const* command_buffers,
|
||||
const uint32_t* sizes_in_dwords,
|
||||
uint32_t count);
|
||||
int KYTY_SYSV_ABI GraphicsDriverSubmitAcb(uint32_t queue, const Packet* packet);
|
||||
int KYTY_SYSV_ABI GraphicsDriverSubmitMultiAcbs(uint32_t queue, uint32_t* const* acbs,
|
||||
const uint32_t* sizes_in_dwords, uint32_t count);
|
||||
|
||||
+11
-13
@@ -181,15 +181,13 @@ uint32_t AudioOutOutputs(const OutputParam* params, uint32_t num, bool blocking)
|
||||
|
||||
} // namespace AudioInternal
|
||||
|
||||
KYTY_SUBSYSTEM_INIT(Audio) {
|
||||
void Initialize() {
|
||||
EXIT_IF(g_audio != nullptr);
|
||||
|
||||
g_audio = new Audio;
|
||||
}
|
||||
|
||||
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Audio) {}
|
||||
|
||||
KYTY_SUBSYSTEM_DESTROY(Audio) {
|
||||
void Shutdown() {
|
||||
delete g_audio;
|
||||
g_audio = nullptr;
|
||||
}
|
||||
@@ -1461,14 +1459,14 @@ struct Ngs2CustomSamplerRackOption {
|
||||
};
|
||||
|
||||
union Ngs2RackOptionUnion {
|
||||
Ngs2RackOption common;
|
||||
Ngs2SamplerRackOption sampler;
|
||||
Ngs2MasteringRackOption mastering;
|
||||
Ngs2SubmixerRackOption submixer;
|
||||
Ngs2ReverbRackOption reverb;
|
||||
Ngs2CustomSubmixerRackOption custom_submixer;
|
||||
Ngs2RackOption common;
|
||||
Ngs2SamplerRackOption sampler;
|
||||
Ngs2MasteringRackOption mastering;
|
||||
Ngs2SubmixerRackOption submixer;
|
||||
Ngs2ReverbRackOption reverb;
|
||||
Ngs2CustomSubmixerRackOption custom_submixer;
|
||||
Ngs2CustomMasteringRackOption custom_mastering;
|
||||
Ngs2CustomSamplerRackOption custom_sampler;
|
||||
Ngs2CustomSamplerRackOption custom_sampler;
|
||||
};
|
||||
|
||||
struct Ngs2ContextBufferInfo {
|
||||
@@ -2653,8 +2651,8 @@ int KYTY_SYSV_ABI Ngs2VoiceGetState(uintptr_t voice_handle, Ngs2VoiceState* stat
|
||||
switch (voice->rack->type) {
|
||||
case Ngs2RackType::Submixer: {
|
||||
EXIT_NOT_IMPLEMENTED(state_size != sizeof(Ngs2SubmixerVoiceState));
|
||||
auto* submixer = reinterpret_cast<Ngs2SubmixerVoiceState*>(state);
|
||||
*submixer = {};
|
||||
auto* submixer = reinterpret_cast<Ngs2SubmixerVoiceState*>(state);
|
||||
*submixer = {};
|
||||
submixer->voice_state.state_flags = Ngs2GetStateFlags(voice);
|
||||
LOGF("\t state_flags = %u\n", submixer->voice_state.state_flags);
|
||||
break;
|
||||
|
||||
+8
-3
@@ -3,11 +3,16 @@
|
||||
|
||||
#include "common/abi.h"
|
||||
#include "common/common.h"
|
||||
#include "common/subsystems.h"
|
||||
|
||||
namespace Libs::Audio {
|
||||
|
||||
KYTY_SUBSYSTEM_DEFINE(Audio);
|
||||
void Initialize();
|
||||
void Shutdown();
|
||||
|
||||
struct Lifecycle {
|
||||
static constexpr const char* name = "Audio";
|
||||
static constexpr auto initialize = Libs::Audio::Initialize;
|
||||
static constexpr auto shutdown = Libs::Audio::Shutdown;
|
||||
};
|
||||
|
||||
namespace AudioOut {
|
||||
|
||||
|
||||
@@ -112,16 +112,17 @@ static void pad_fill_data(PadData* data, const ControllerState& state, bool conn
|
||||
data->device_unique_data_len = 0;
|
||||
}
|
||||
|
||||
KYTY_SUBSYSTEM_INIT(Controller) {
|
||||
void Initialize() {
|
||||
EXIT_IF(g_controller != nullptr);
|
||||
|
||||
g_controller = new GameController;
|
||||
g_controller->Connect(HOST_INPUT_CONTROLLER_ID);
|
||||
}
|
||||
|
||||
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Controller) {}
|
||||
|
||||
KYTY_SUBSYSTEM_DESTROY(Controller) {}
|
||||
void Shutdown() {
|
||||
delete g_controller;
|
||||
g_controller = nullptr;
|
||||
}
|
||||
|
||||
void GameController::Connect(int id) {
|
||||
Common::LockGuard lock(m_mutex);
|
||||
|
||||
@@ -3,11 +3,16 @@
|
||||
|
||||
#include "common/abi.h"
|
||||
#include "common/common.h"
|
||||
#include "common/subsystems.h"
|
||||
|
||||
namespace Libs::Controller {
|
||||
|
||||
KYTY_SUBSYSTEM_DEFINE(Controller);
|
||||
void Initialize();
|
||||
void Shutdown();
|
||||
|
||||
struct Lifecycle {
|
||||
static constexpr const char* name = "Controller";
|
||||
static constexpr auto initialize = Libs::Controller::Initialize;
|
||||
static constexpr auto shutdown = Libs::Controller::Shutdown;
|
||||
};
|
||||
|
||||
constexpr int HOST_INPUT_CONTROLLER_ID = -1000;
|
||||
|
||||
|
||||
+80
-231
@@ -55,13 +55,13 @@ constexpr uint32_t VALID_KEYBOARD_OPTIONS = 0x0000003f;
|
||||
constexpr uint32_t VALID_KEYBOARD_MODE = 0x0000007f;
|
||||
constexpr uint64_t VALID_LANGUAGES = 0x00000001ff1fffffULL;
|
||||
|
||||
constexpr uint32_t OPTION_MULTILINE = 0x00000001;
|
||||
constexpr uint32_t OPTION_PASSWORD = 0x00000004;
|
||||
constexpr uint32_t OPTION_EXT_KEYBOARD = 0x00000010;
|
||||
constexpr uint32_t OPTION_EXPANDED_PREEDIT = 0x00001000;
|
||||
constexpr uint32_t OPTION_USE_OVER_2K = 0x00004000;
|
||||
constexpr uint32_t OPTION_MULTILINE = ImeCommon::OPTION_MULTILINE;
|
||||
constexpr uint32_t OPTION_PASSWORD = ImeCommon::OPTION_PASSWORD;
|
||||
constexpr uint32_t OPTION_EXT_KEYBOARD = ImeCommon::OPTION_EXT_KEYBOARD;
|
||||
constexpr uint32_t OPTION_EXPANDED_PREEDIT = ImeCommon::OPTION_EXPANDED_PREEDIT;
|
||||
constexpr uint32_t OPTION_USE_OVER_2K = ImeCommon::OPTION_USE_OVER_2K;
|
||||
|
||||
constexpr uint32_t EXT_OPTION_HIDE_KEY_PANEL = 0x00000400;
|
||||
constexpr uint32_t EXT_OPTION_HIDE_KEY_PANEL = ImeCommon::EXT_OPTION_HIDE_KEY_PANEL;
|
||||
constexpr size_t EVENT_QUEUE_CAPACITY = 128;
|
||||
|
||||
struct QueuedEvent {
|
||||
@@ -71,18 +71,15 @@ struct QueuedEvent {
|
||||
};
|
||||
|
||||
struct State {
|
||||
bool open = false;
|
||||
bool event_overflow = false;
|
||||
uint64_t generation = 0;
|
||||
uint64_t revision = 0;
|
||||
uint32_t option = 0;
|
||||
uint32_t max_text_length = 0;
|
||||
uint32_t cursor = 0;
|
||||
bool open = false;
|
||||
bool event_overflow = false;
|
||||
uint64_t generation = 0;
|
||||
uint64_t revision = 0;
|
||||
Param param {};
|
||||
ExtendedParam extended {};
|
||||
void* arg = nullptr;
|
||||
EventHandler handler = nullptr;
|
||||
std::u16string text;
|
||||
ImeCommon::TextEditEngine editor;
|
||||
std::deque<QueuedEvent> events;
|
||||
std::vector<ExternalInput> external_inputs;
|
||||
};
|
||||
@@ -130,97 +127,6 @@ bool ValidateText(const char16_t* text, uint32_t length, bool multiline, uint32_
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsAllowedInput(char16_t value, Type type, uint32_t option) {
|
||||
if (value == u'\r' || value == u'\0') {
|
||||
return false;
|
||||
}
|
||||
if (value == u'\n') {
|
||||
return (option & OPTION_MULTILINE) != 0;
|
||||
}
|
||||
if (type == Type::Number) {
|
||||
return (value >= u'0' && value <= u'9') || value == u',' || value == u'-' || value == u'.';
|
||||
}
|
||||
if (type == Type::BasicLatin) {
|
||||
return value >= u' ' && value <= u'~';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
char16_t HidCharacter(uint16_t keycode, uint32_t status) {
|
||||
const bool shift = (status & 0x00002200) != 0;
|
||||
const bool caps = (status & 0x00020000) != 0;
|
||||
if (keycode >= 4 && keycode <= 29) {
|
||||
return static_cast<char16_t>(((shift != caps) ? u'A' : u'a') + keycode - 4);
|
||||
}
|
||||
if (keycode >= 30 && keycode <= 39) {
|
||||
static constexpr char16_t plain[] = u"1234567890";
|
||||
static constexpr char16_t shifted[] = u"!@#$%^&*()";
|
||||
return (shift ? shifted : plain)[keycode - 30];
|
||||
}
|
||||
if (keycode == 44) {
|
||||
return u' ';
|
||||
}
|
||||
if (keycode >= 45 && keycode <= 56) {
|
||||
static constexpr char16_t plain[] = u"-=[]\\#;'`,./";
|
||||
static constexpr char16_t shifted[] = u"_+{}|~:\"~<>?";
|
||||
return (shift ? shifted : plain)[keycode - 45];
|
||||
}
|
||||
if (keycode >= 89 && keycode <= 98) {
|
||||
static constexpr char16_t keypad[] = u"1234567890";
|
||||
return keypad[keycode - 89];
|
||||
}
|
||||
return keycode == 99 ? u'.' : u'\0';
|
||||
}
|
||||
|
||||
bool ApplyKeyboardFilterOutput(ExternalInput* input, uint16_t keycode, uint32_t status,
|
||||
bool multiline) {
|
||||
constexpr uint32_t KEYCODE_VALID = 0x00000001;
|
||||
constexpr uint32_t CHARACTER_VALID = 0x00000002;
|
||||
if (keycode == input->key.keycode && status == input->key.status) {
|
||||
return true;
|
||||
}
|
||||
if ((status & KEYCODE_VALID) == 0 || keycode == 0) {
|
||||
return input->action == ExternalAction::Text && (status & CHARACTER_VALID) != 0;
|
||||
}
|
||||
input->key.keycode = keycode;
|
||||
input->key.status = status;
|
||||
input->text.clear();
|
||||
switch (keycode) {
|
||||
case 40:
|
||||
case 88:
|
||||
case 158:
|
||||
input->action = multiline ? ExternalAction::Newline : ExternalAction::Accept;
|
||||
break;
|
||||
case 41: input->action = ExternalAction::Cancel; break;
|
||||
case 42:
|
||||
case 187: input->action = ExternalAction::Backspace; break;
|
||||
case 43:
|
||||
case 186: input->action = ExternalAction::None; break;
|
||||
case 79: input->action = ExternalAction::MoveRight; break;
|
||||
case 80: input->action = ExternalAction::MoveLeft; break;
|
||||
default: {
|
||||
const char16_t character = HidCharacter(keycode, status);
|
||||
if (character == u'\0') {
|
||||
return false;
|
||||
}
|
||||
input->action = ExternalAction::Text;
|
||||
input->key.character = character;
|
||||
input->text.push_back(character);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t NormalizeCursor(std::u16string_view text, uint32_t cursor) {
|
||||
cursor = std::min<uint32_t>(cursor, static_cast<uint32_t>(text.size()));
|
||||
if (cursor > 0 && cursor < text.size() && text[cursor - 1] >= 0xd800 &&
|
||||
text[cursor - 1] <= 0xdbff && text[cursor] >= 0xdc00 && text[cursor] <= 0xdfff) {
|
||||
cursor++;
|
||||
}
|
||||
return cursor;
|
||||
}
|
||||
|
||||
void NotifyVisibility(bool visible, uint64_t generation) {
|
||||
if (const auto callback = g_visibility_callback.load(std::memory_order_acquire);
|
||||
callback != nullptr) {
|
||||
@@ -247,7 +153,7 @@ void SyncGuestText(char16_t* work, char16_t* input, uint32_t max_length, std::u1
|
||||
|
||||
void SyncTextBuffersLocked() {
|
||||
SyncGuestText(static_cast<char16_t*>(g_state.param.work), g_state.param.input_text_buffer,
|
||||
g_state.max_text_length, g_state.text);
|
||||
g_state.editor.GetMaxLength(), g_state.editor.GetText());
|
||||
}
|
||||
|
||||
bool QueueEventLocked(QueuedEvent event) {
|
||||
@@ -263,53 +169,33 @@ QueuedEvent MakeTextEventLocked(uint32_t id, uint32_t edit_index, int32_t edit_l
|
||||
QueuedEvent queued;
|
||||
queued.event.id = id;
|
||||
queued.event.param.text.str = static_cast<char16_t*>(g_state.param.work);
|
||||
queued.event.param.text.caret_index = g_state.cursor;
|
||||
queued.event.param.text.caret_index = g_state.editor.GetCursor();
|
||||
queued.event.param.text.area_num = 1;
|
||||
queued.event.param.text.text_area[0] = {TextAreaMode::Edit, edit_index, edit_length};
|
||||
queued.text_payload = true;
|
||||
queued.text = g_state.text;
|
||||
queued.text = g_state.editor.GetText();
|
||||
return queued;
|
||||
}
|
||||
|
||||
bool CommitFilteredText(uint64_t generation, uint64_t revision, std::u16string old_text,
|
||||
std::u16string candidate, uint32_t cursor, TextFilter filter,
|
||||
uint32_t max_length, bool multiline) {
|
||||
ImeCommon::TextEditEngine candidate, TextFilter filter, bool multiline) {
|
||||
if (filter != nullptr) {
|
||||
std::vector<char16_t> output(max_length + 1, u'\0');
|
||||
uint32_t output_length = max_length;
|
||||
if (filter(output.data(), &output_length, candidate.c_str(),
|
||||
static_cast<uint32_t>(candidate.size())) == 0 &&
|
||||
output_length <= max_length) {
|
||||
uint32_t actual_length = 0;
|
||||
if (ValidateText(output.data(), output_length, multiline, &actual_length) &&
|
||||
actual_length == output_length) {
|
||||
candidate.assign(output.data(), output.data() + output_length);
|
||||
}
|
||||
std::u16string filtered;
|
||||
if (ImeCommon::RunTextFilter(filter, candidate.GetText(), candidate.GetMaxLength(),
|
||||
&filtered) &&
|
||||
ImeCommon::IsValidInputText(filtered, multiline)) {
|
||||
candidate.ReplaceText(std::move(filtered), candidate.GetCursor());
|
||||
}
|
||||
}
|
||||
|
||||
std::scoped_lock lock(g_mutex);
|
||||
if (!g_state.open || g_state.generation != generation || g_state.revision != revision ||
|
||||
g_state.text != old_text || candidate == old_text) {
|
||||
g_state.editor.GetText() != old_text || candidate.GetText() == old_text) {
|
||||
return false;
|
||||
}
|
||||
size_t prefix = 0;
|
||||
while (prefix < old_text.size() && prefix < candidate.size() &&
|
||||
old_text[prefix] == candidate[prefix]) {
|
||||
prefix++;
|
||||
}
|
||||
size_t old_tail = old_text.size();
|
||||
size_t new_tail = candidate.size();
|
||||
while (old_tail > prefix && new_tail > prefix &&
|
||||
old_text[old_tail - 1] == candidate[new_tail - 1]) {
|
||||
old_tail--;
|
||||
new_tail--;
|
||||
}
|
||||
const int32_t edit_length =
|
||||
static_cast<int32_t>(new_tail - prefix) - static_cast<int32_t>(old_tail - prefix);
|
||||
g_state.text = std::move(candidate);
|
||||
g_state.cursor = NormalizeCursor(g_state.text, cursor);
|
||||
QueueEventLocked(MakeTextEventLocked(1, static_cast<uint32_t>(prefix), edit_length));
|
||||
const auto edit = ImeCommon::ComputeEditDelta(old_text, candidate.GetText());
|
||||
g_state.editor = std::move(candidate);
|
||||
QueueEventLocked(MakeTextEventLocked(1, edit.index, edit.length));
|
||||
UpdateRevisionLocked();
|
||||
return true;
|
||||
}
|
||||
@@ -475,16 +361,13 @@ int KYTY_SYSV_ABI ImeOpen(const Param* param, const ExtendedParam* extended) {
|
||||
g_state.open = true;
|
||||
g_state.generation = next_generation;
|
||||
g_state.revision = next_revision;
|
||||
g_state.option = param->option;
|
||||
g_state.max_text_length = param->max_text_length;
|
||||
g_state.cursor = static_cast<uint32_t>(text.size());
|
||||
g_state.param = *param;
|
||||
if (extended != nullptr) {
|
||||
g_state.extended = *extended;
|
||||
}
|
||||
g_state.arg = param->arg;
|
||||
g_state.handler = param->handler;
|
||||
g_state.text = std::move(text);
|
||||
g_state.editor.Reset(param->type, param->option, param->max_text_length, std::move(text));
|
||||
std::memset(param->work, 0, WORK_BUFFER_SIZE);
|
||||
SyncTextBuffersLocked();
|
||||
|
||||
@@ -550,7 +433,7 @@ int KYTY_SYSV_ABI ImeUpdate(EventHandler handler) {
|
||||
while (!g_state.events.empty()) {
|
||||
dispatch.push_back({g_state.arg, std::move(g_state.events.front()),
|
||||
static_cast<char16_t*>(g_state.param.work),
|
||||
g_state.param.input_text_buffer, g_state.max_text_length,
|
||||
g_state.param.input_text_buffer, g_state.editor.GetMaxLength(),
|
||||
g_state.generation});
|
||||
g_state.events.pop_front();
|
||||
}
|
||||
@@ -607,14 +490,14 @@ int KYTY_SYSV_ABI ImeSetText(const char16_t* text, uint32_t length) {
|
||||
if (text == nullptr) {
|
||||
return ERROR_INVALID_ADDRESS;
|
||||
}
|
||||
const uint32_t clamped_length = std::min(length, g_state.max_text_length);
|
||||
const uint32_t clamped_length = std::min(length, g_state.editor.GetMaxLength());
|
||||
uint32_t actual_length = 0;
|
||||
if (!ValidateText(text, clamped_length, (g_state.option & OPTION_MULTILINE) != 0,
|
||||
if (!ValidateText(text, clamped_length, (g_state.editor.GetOption() & OPTION_MULTILINE) != 0,
|
||||
&actual_length)) {
|
||||
return ERROR_INVALID_TEXT;
|
||||
}
|
||||
g_state.text.assign(text, text + actual_length);
|
||||
g_state.cursor = NormalizeCursor(g_state.text, g_state.cursor);
|
||||
g_state.editor.ReplaceText(std::u16string(text, text + actual_length),
|
||||
g_state.editor.GetCursor());
|
||||
SyncTextBuffersLocked();
|
||||
UpdateRevisionLocked();
|
||||
return OK;
|
||||
@@ -628,10 +511,10 @@ int KYTY_SYSV_ABI ImeSetCaret(const Caret* caret) {
|
||||
if (caret == nullptr) {
|
||||
return ERROR_INVALID_ADDRESS;
|
||||
}
|
||||
if (caret->index > g_state.text.size()) {
|
||||
if (caret->index > g_state.editor.GetText().size()) {
|
||||
return ERROR_INVALID_PARAM;
|
||||
}
|
||||
g_state.cursor = NormalizeCursor(g_state.text, caret->index);
|
||||
g_state.editor.SetCursor(caret->index);
|
||||
UpdateRevisionLocked();
|
||||
return OK;
|
||||
}
|
||||
@@ -644,7 +527,7 @@ int KYTY_SYSV_ABI ImeSetTextGeometry(TextAreaMode mode, const TextGeometry* geom
|
||||
if (geometry == nullptr) {
|
||||
return ERROR_INVALID_ADDRESS;
|
||||
}
|
||||
const bool over_2k = (g_state.option & OPTION_USE_OVER_2K) != 0;
|
||||
const bool over_2k = (g_state.editor.GetOption() & OPTION_USE_OVER_2K) != 0;
|
||||
const float max_x = over_2k ? 3840.0f : 1920.0f;
|
||||
const float max_y = over_2k ? 2160.0f : 1080.0f;
|
||||
if (!std::isfinite(geometry->x) || !std::isfinite(geometry->y) || geometry->x < 0.0f ||
|
||||
@@ -754,11 +637,11 @@ bool GetHostSnapshot(HostSnapshot* snapshot) {
|
||||
snapshot->generation = g_state.generation;
|
||||
snapshot->type = g_state.param.type;
|
||||
snapshot->enter_label = g_state.param.enter_label;
|
||||
snapshot->option = g_state.option;
|
||||
snapshot->max_text_length = g_state.max_text_length;
|
||||
snapshot->cursor = g_state.cursor;
|
||||
snapshot->option = g_state.editor.GetOption();
|
||||
snapshot->max_text_length = g_state.editor.GetMaxLength();
|
||||
snapshot->cursor = g_state.editor.GetCursor();
|
||||
snapshot->disable_device = g_state.extended.disable_device;
|
||||
snapshot->key_panel_visible = (g_state.option & OPTION_EXT_KEYBOARD) == 0 ||
|
||||
snapshot->key_panel_visible = (g_state.editor.GetOption() & OPTION_EXT_KEYBOARD) == 0 ||
|
||||
(g_state.extended.option & EXT_OPTION_HIDE_KEY_PANEL) == 0;
|
||||
snapshot->posx = g_state.param.posx;
|
||||
snapshot->posy = g_state.param.posy;
|
||||
@@ -766,92 +649,65 @@ bool GetHostSnapshot(HostSnapshot* snapshot) {
|
||||
snapshot->vertical_alignment = g_state.param.vertical_alignment;
|
||||
snapshot->panel_width = g_state.param.type == Type::Number ? 370 : 793;
|
||||
snapshot->panel_height = g_state.param.type == Type::Number ? 402 : 408;
|
||||
if ((g_state.option & OPTION_USE_OVER_2K) != 0) {
|
||||
if ((g_state.editor.GetOption() & OPTION_USE_OVER_2K) != 0) {
|
||||
snapshot->panel_width *= 2;
|
||||
snapshot->panel_height *= 2;
|
||||
}
|
||||
snapshot->text = g_state.text;
|
||||
snapshot->text = g_state.editor.GetText();
|
||||
snapshot->title.clear();
|
||||
snapshot->placeholder.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ApplyInsertText(uint64_t generation, std::u16string_view text) {
|
||||
uint64_t revision = 0;
|
||||
uint32_t cursor = 0;
|
||||
uint32_t max_length = 0;
|
||||
bool multiline = false;
|
||||
TextFilter filter = nullptr;
|
||||
std::u16string old_text;
|
||||
std::u16string candidate;
|
||||
uint64_t revision = 0;
|
||||
bool multiline = false;
|
||||
TextFilter filter = nullptr;
|
||||
std::u16string old_text;
|
||||
ImeCommon::TextEditEngine candidate;
|
||||
{
|
||||
std::scoped_lock lock(g_mutex);
|
||||
if (!g_state.open || g_state.generation != generation || text.empty()) {
|
||||
return false;
|
||||
}
|
||||
uint32_t valid_length = 0;
|
||||
multiline = (g_state.option & OPTION_MULTILINE) != 0;
|
||||
if (!ValidateText(text.data(), static_cast<uint32_t>(text.size()), multiline,
|
||||
&valid_length) ||
|
||||
valid_length != text.size()) {
|
||||
multiline = (g_state.editor.GetOption() & OPTION_MULTILINE) != 0;
|
||||
if (!ImeCommon::IsValidInputText(text, multiline)) {
|
||||
return false;
|
||||
}
|
||||
std::u16string allowed;
|
||||
for (const char16_t value: text) {
|
||||
if (IsAllowedInput(value, g_state.param.type, g_state.option)) {
|
||||
allowed.push_back(value);
|
||||
}
|
||||
}
|
||||
const size_t available = g_state.max_text_length - g_state.text.size();
|
||||
if (allowed.empty() || available == 0) {
|
||||
candidate = g_state.editor;
|
||||
if (!candidate.Insert(text)) {
|
||||
return false;
|
||||
}
|
||||
allowed.resize(std::min(allowed.size(), available));
|
||||
if (!allowed.empty() && allowed.back() >= 0xd800 && allowed.back() <= 0xdbff) {
|
||||
allowed.pop_back();
|
||||
}
|
||||
if (allowed.empty()) {
|
||||
return false;
|
||||
}
|
||||
revision = g_state.revision;
|
||||
max_length = g_state.max_text_length;
|
||||
filter = g_state.param.filter;
|
||||
old_text = g_state.text;
|
||||
candidate = old_text;
|
||||
candidate.insert(g_state.cursor, allowed);
|
||||
cursor = g_state.cursor + static_cast<uint32_t>(allowed.size());
|
||||
revision = g_state.revision;
|
||||
filter = g_state.param.filter;
|
||||
old_text = g_state.editor.GetText();
|
||||
}
|
||||
return CommitFilteredText(generation, revision, std::move(old_text), std::move(candidate),
|
||||
cursor, filter, max_length, multiline);
|
||||
filter, multiline);
|
||||
}
|
||||
|
||||
static bool ApplyBackspace(uint64_t generation) {
|
||||
uint64_t revision = 0;
|
||||
uint32_t cursor = 0;
|
||||
uint32_t max_length = 0;
|
||||
bool multiline = false;
|
||||
TextFilter filter = nullptr;
|
||||
std::u16string old_text;
|
||||
std::u16string candidate;
|
||||
uint64_t revision = 0;
|
||||
bool multiline = false;
|
||||
TextFilter filter = nullptr;
|
||||
std::u16string old_text;
|
||||
ImeCommon::TextEditEngine candidate;
|
||||
{
|
||||
std::scoped_lock lock(g_mutex);
|
||||
if (!g_state.open || g_state.generation != generation || g_state.cursor == 0) {
|
||||
if (!g_state.open || g_state.generation != generation) {
|
||||
return false;
|
||||
}
|
||||
uint32_t first = g_state.cursor - 1;
|
||||
if (first > 0 && g_state.text[first] >= 0xdc00 && g_state.text[first] <= 0xdfff &&
|
||||
g_state.text[first - 1] >= 0xd800 && g_state.text[first - 1] <= 0xdbff) {
|
||||
first--;
|
||||
candidate = g_state.editor;
|
||||
if (!candidate.Backspace()) {
|
||||
return false;
|
||||
}
|
||||
revision = g_state.revision;
|
||||
max_length = g_state.max_text_length;
|
||||
multiline = (g_state.option & OPTION_MULTILINE) != 0;
|
||||
filter = g_state.param.filter;
|
||||
old_text = g_state.text;
|
||||
candidate = old_text;
|
||||
candidate.erase(first, g_state.cursor - first);
|
||||
cursor = first;
|
||||
revision = g_state.revision;
|
||||
multiline = (g_state.editor.GetOption() & OPTION_MULTILINE) != 0;
|
||||
filter = g_state.param.filter;
|
||||
old_text = g_state.editor.GetText();
|
||||
}
|
||||
return CommitFilteredText(generation, revision, std::move(old_text), std::move(candidate),
|
||||
cursor, filter, max_length, multiline);
|
||||
filter, multiline);
|
||||
}
|
||||
|
||||
static bool ApplyMoveCursor(uint64_t generation, int delta) {
|
||||
@@ -859,25 +715,14 @@ static bool ApplyMoveCursor(uint64_t generation, int delta) {
|
||||
if (!g_state.open || g_state.generation != generation || delta == 0) {
|
||||
return false;
|
||||
}
|
||||
const uint32_t old_cursor = g_state.cursor;
|
||||
int next =
|
||||
std::clamp(static_cast<int>(old_cursor) + delta, 0, static_cast<int>(g_state.text.size()));
|
||||
if (delta < 0 && next > 0 && next < static_cast<int>(g_state.text.size()) &&
|
||||
g_state.text[next] >= 0xdc00 && g_state.text[next] <= 0xdfff &&
|
||||
g_state.text[next - 1] >= 0xd800 && g_state.text[next - 1] <= 0xdbff) {
|
||||
next--;
|
||||
} else if (delta > 0 && next > 0 && next < static_cast<int>(g_state.text.size()) &&
|
||||
g_state.text[next - 1] >= 0xd800 && g_state.text[next - 1] <= 0xdbff &&
|
||||
g_state.text[next] >= 0xdc00 && g_state.text[next] <= 0xdfff) {
|
||||
next++;
|
||||
}
|
||||
g_state.cursor = static_cast<uint32_t>(next);
|
||||
if (g_state.cursor == old_cursor) {
|
||||
const uint32_t old_cursor = g_state.editor.GetCursor();
|
||||
if (!g_state.editor.MoveCursor(delta)) {
|
||||
return false;
|
||||
}
|
||||
const uint32_t direction = g_state.cursor > old_cursor ? 2 : 1;
|
||||
const uint32_t steps = static_cast<uint32_t>(
|
||||
std::abs(static_cast<int>(g_state.cursor) - static_cast<int>(old_cursor)));
|
||||
const uint32_t new_cursor = g_state.editor.GetCursor();
|
||||
const uint32_t direction = new_cursor > old_cursor ? 2 : 1;
|
||||
const uint32_t steps = static_cast<uint32_t>(
|
||||
std::abs(static_cast<int>(new_cursor) - static_cast<int>(old_cursor)));
|
||||
for (uint32_t i = 0; i < steps; i++) {
|
||||
QueuedEvent event;
|
||||
event.event.id = 2;
|
||||
@@ -962,7 +807,7 @@ void ApplyExternalInputs() {
|
||||
generation = g_state.generation;
|
||||
filter = g_state.extended.ext_keyboard_filter;
|
||||
user_id = g_state.param.user_id;
|
||||
multiline = (g_state.option & OPTION_MULTILINE) != 0;
|
||||
multiline = (g_state.editor.GetOption() & OPTION_MULTILINE) != 0;
|
||||
inputs.swap(g_state.external_inputs);
|
||||
}
|
||||
for (auto& input: inputs) {
|
||||
@@ -978,7 +823,7 @@ void ApplyExternalInputs() {
|
||||
uint16_t keycode = input.key.keycode;
|
||||
uint32_t status = input.key.status;
|
||||
if (filter(&input.key, &keycode, &status, nullptr) == 0) {
|
||||
accepted = ApplyKeyboardFilterOutput(&input, keycode, status, multiline);
|
||||
accepted = ImeCommon::ApplyKeyboardFilterOutput(&input, keycode, status, multiline);
|
||||
}
|
||||
}
|
||||
if (!accepted) {
|
||||
@@ -999,6 +844,8 @@ void ApplyExternalInputs() {
|
||||
|
||||
} // namespace
|
||||
|
||||
#if !defined(KYTY_IME_TESTS)
|
||||
|
||||
LIB_VERSION("Ime", 1, "Ime", 1, 1);
|
||||
|
||||
LIB_DEFINE(InitPlatform_1_Ime) {
|
||||
@@ -1017,4 +864,6 @@ LIB_DEFINE(InitPlatform_1_Ime) {
|
||||
LIB_FUNC("ua+13Hk9kKs", ImeKeyboardSetMode);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace Libs::Ime
|
||||
+15
-86
@@ -1,7 +1,7 @@
|
||||
#ifndef EMULATOR_INCLUDE_EMULATOR_LIBS_IME_H_
|
||||
#define EMULATOR_INCLUDE_EMULATOR_LIBS_IME_H_
|
||||
|
||||
#include "common/abi.h"
|
||||
#include "libs/imeCommon.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
@@ -11,28 +11,19 @@
|
||||
namespace Libs::Ime {
|
||||
|
||||
constexpr uint32_t WORK_BUFFER_SIZE = 20 * 1024;
|
||||
constexpr uint32_t MAX_TEXT_LENGTH = 2048;
|
||||
constexpr uint32_t MAX_TEXT_LENGTH = ImeCommon::MAX_TEXT_LENGTH;
|
||||
|
||||
enum class Type : uint32_t { Default = 0, BasicLatin = 1, Url = 2, Mail = 3, Number = 4 };
|
||||
enum class EnterLabel : uint32_t { Default = 0, Send = 1, Search = 2, Go = 3 };
|
||||
enum class Alignment : uint32_t { Start = 0, Center = 1, End = 2 };
|
||||
using Type = ImeCommon::Type;
|
||||
using EnterLabel = ImeCommon::EnterLabel;
|
||||
using Alignment = ImeCommon::Alignment;
|
||||
|
||||
struct Event;
|
||||
struct Keycode;
|
||||
|
||||
using TextFilter = int32_t(KYTY_SYSV_ABI*)(char16_t* out_text, uint32_t* out_text_length,
|
||||
const char16_t* source_text,
|
||||
uint32_t source_text_length);
|
||||
using Keycode = ImeCommon::Keycode;
|
||||
using TextFilter = ImeCommon::TextFilter;
|
||||
using EventHandler = void(KYTY_SYSV_ABI*)(void* arg, const Event* event);
|
||||
using ExtKeyboardFilter = int(KYTY_SYSV_ABI*)(const Keycode* source_keycode, uint16_t* out_keycode,
|
||||
uint32_t* out_status, void* reserved);
|
||||
|
||||
struct Color {
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
uint8_t a;
|
||||
};
|
||||
using ExtKeyboardFilter = ImeCommon::ExtKeyboardFilter;
|
||||
using Color = ImeCommon::Color;
|
||||
|
||||
struct Caret {
|
||||
float x;
|
||||
@@ -75,16 +66,6 @@ struct KeyboardResourceIdArray {
|
||||
uint32_t resource_id[5];
|
||||
};
|
||||
|
||||
struct Keycode {
|
||||
uint16_t keycode;
|
||||
char16_t character;
|
||||
uint32_t status;
|
||||
uint32_t type;
|
||||
int32_t user_id;
|
||||
uint32_t resource_id;
|
||||
uint64_t timestamp;
|
||||
};
|
||||
|
||||
union EventParam {
|
||||
Rect rect;
|
||||
EditText text;
|
||||
@@ -119,24 +100,7 @@ struct Param {
|
||||
int8_t reserved[8];
|
||||
};
|
||||
|
||||
struct ExtendedParam {
|
||||
uint32_t option;
|
||||
Color color_base;
|
||||
Color color_line;
|
||||
Color color_text_field;
|
||||
Color color_preedit;
|
||||
Color color_button_default;
|
||||
Color color_button_function;
|
||||
Color color_button_symbol;
|
||||
Color color_text;
|
||||
Color color_special;
|
||||
uint32_t priority;
|
||||
const char* additional_dictionary_path;
|
||||
ExtKeyboardFilter ext_keyboard_filter;
|
||||
uint32_t disable_device;
|
||||
uint32_t ext_keyboard_mode;
|
||||
int8_t reserved[60];
|
||||
};
|
||||
using ExtendedParam = ImeCommon::ExtendedParam;
|
||||
|
||||
struct KeyboardParam {
|
||||
uint32_t option;
|
||||
@@ -156,22 +120,8 @@ struct KeyboardInfo {
|
||||
int8_t reserved[12];
|
||||
};
|
||||
|
||||
enum class ExternalAction : uint8_t {
|
||||
None,
|
||||
Text,
|
||||
Backspace,
|
||||
MoveLeft,
|
||||
MoveRight,
|
||||
Cancel,
|
||||
Accept,
|
||||
Newline,
|
||||
};
|
||||
|
||||
struct ExternalInput {
|
||||
Keycode key;
|
||||
ExternalAction action;
|
||||
std::u16string text;
|
||||
};
|
||||
using ExternalAction = ImeCommon::ExternalAction;
|
||||
using ExternalInput = ImeCommon::ExternalInput;
|
||||
|
||||
static_assert(sizeof(Caret) == 0x10);
|
||||
static_assert(sizeof(TextGeometry) == 0x10);
|
||||
@@ -192,30 +142,9 @@ static_assert(sizeof(KeyboardResourceIdArray) == 0x18);
|
||||
static_assert(sizeof(KeyboardInfo) == 0x24);
|
||||
static_assert(sizeof(Keycode) == 0x20);
|
||||
|
||||
struct VisualState {
|
||||
bool active;
|
||||
uint64_t revision;
|
||||
};
|
||||
|
||||
struct HostSnapshot {
|
||||
uint64_t generation;
|
||||
Type type;
|
||||
EnterLabel enter_label;
|
||||
uint32_t option;
|
||||
uint32_t max_text_length;
|
||||
uint32_t cursor;
|
||||
uint32_t disable_device;
|
||||
bool key_panel_visible;
|
||||
float posx;
|
||||
float posy;
|
||||
Alignment horizontal_alignment;
|
||||
Alignment vertical_alignment;
|
||||
uint32_t panel_width;
|
||||
uint32_t panel_height;
|
||||
std::u16string text;
|
||||
};
|
||||
|
||||
using VisibilityCallback = void (*)(bool visible, uint64_t generation);
|
||||
using VisualState = ImeCommon::VisualState;
|
||||
using HostSnapshot = ImeCommon::HostSnapshot;
|
||||
using VisibilityCallback = ImeCommon::VisibilityCallback;
|
||||
|
||||
void KYTY_SYSV_ABI ImeParamInit(Param* param);
|
||||
int KYTY_SYSV_ABI ImeGetPanelSize(const Param* param, uint32_t* width, uint32_t* height);
|
||||
|
||||
@@ -0,0 +1,259 @@
|
||||
#include "libs/imeCommon.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
namespace Libs::ImeCommon {
|
||||
namespace {
|
||||
|
||||
constexpr bool IsHighSurrogate(char16_t value) {
|
||||
return value >= 0xd800 && value <= 0xdbff;
|
||||
}
|
||||
|
||||
constexpr bool IsLowSurrogate(char16_t value) {
|
||||
return value >= 0xdc00 && value <= 0xdfff;
|
||||
}
|
||||
|
||||
char16_t HidCharacter(uint16_t keycode, uint32_t status) {
|
||||
const bool shift = (status & 0x00002200) != 0;
|
||||
const bool caps = (status & 0x00020000) != 0;
|
||||
if (keycode >= 4 && keycode <= 29) {
|
||||
return static_cast<char16_t>(((shift != caps) ? u'A' : u'a') + keycode - 4);
|
||||
}
|
||||
if (keycode >= 30 && keycode <= 39) {
|
||||
static constexpr char16_t plain[] = u"1234567890";
|
||||
static constexpr char16_t shifted[] = u"!@#$%^&*()";
|
||||
return (shift ? shifted : plain)[keycode - 30];
|
||||
}
|
||||
if (keycode == 44) {
|
||||
return u' ';
|
||||
}
|
||||
if (keycode >= 45 && keycode <= 56) {
|
||||
static constexpr char16_t plain[] = u"-=[]\\#;'`,./";
|
||||
static constexpr char16_t shifted[] = u"_+{}|~:\"~<>?";
|
||||
return (shift ? shifted : plain)[keycode - 45];
|
||||
}
|
||||
if (keycode >= 89 && keycode <= 98) {
|
||||
static constexpr char16_t keypad[] = u"1234567890";
|
||||
return keypad[keycode - 89];
|
||||
}
|
||||
return keycode == 99 ? u'.' : u'\0';
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool IsValidUtf16(std::u16string_view text) {
|
||||
for (size_t i = 0; i < text.size(); i++) {
|
||||
if (IsHighSurrogate(text[i])) {
|
||||
if (++i >= text.size() || !IsLowSurrogate(text[i])) {
|
||||
return false;
|
||||
}
|
||||
} else if (IsLowSurrogate(text[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsValidInputText(std::u16string_view text, bool multiline) {
|
||||
if (!IsValidUtf16(text)) {
|
||||
return false;
|
||||
}
|
||||
return std::none_of(text.begin(), text.end(), [multiline](char16_t value) {
|
||||
return value == u'\0' || (!multiline && (value == u'\n' || value == u'\r'));
|
||||
});
|
||||
}
|
||||
|
||||
bool IsAllowedInput(char16_t value, Type type, uint32_t option) {
|
||||
if (value == u'\r' || value == u'\0') {
|
||||
return false;
|
||||
}
|
||||
if (value == u'\n') {
|
||||
return (option & OPTION_MULTILINE) != 0;
|
||||
}
|
||||
if (type == Type::Number) {
|
||||
return (value >= u'0' && value <= u'9') || value == u',' || value == u'-' || value == u'.';
|
||||
}
|
||||
if (type == Type::BasicLatin) {
|
||||
return value >= u' ' && value <= u'~';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t NormalizeCursor(std::u16string_view text, uint32_t cursor) {
|
||||
cursor = std::min<uint32_t>(cursor, static_cast<uint32_t>(text.size()));
|
||||
if (cursor > 0 && cursor < text.size() && IsHighSurrogate(text[cursor - 1]) &&
|
||||
IsLowSurrogate(text[cursor])) {
|
||||
cursor++;
|
||||
}
|
||||
return cursor;
|
||||
}
|
||||
|
||||
void ClampText(std::u16string* text, uint32_t limit) {
|
||||
if (text->size() <= limit) {
|
||||
return;
|
||||
}
|
||||
text->resize(limit);
|
||||
if (!text->empty() && IsHighSurrogate(text->back())) {
|
||||
text->pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
EditDelta ComputeEditDelta(std::u16string_view before, std::u16string_view after) {
|
||||
size_t prefix = 0;
|
||||
while (prefix < before.size() && prefix < after.size() && before[prefix] == after[prefix]) {
|
||||
prefix++;
|
||||
}
|
||||
size_t before_tail = before.size();
|
||||
size_t after_tail = after.size();
|
||||
while (before_tail > prefix && after_tail > prefix &&
|
||||
before[before_tail - 1] == after[after_tail - 1]) {
|
||||
before_tail--;
|
||||
after_tail--;
|
||||
}
|
||||
return {static_cast<uint32_t>(prefix),
|
||||
static_cast<int32_t>(after_tail - prefix) - static_cast<int32_t>(before_tail - prefix)};
|
||||
}
|
||||
|
||||
bool RunTextFilter(TextFilter filter, const std::u16string& source, uint32_t output_capacity,
|
||||
std::u16string* output) {
|
||||
if (filter == nullptr || output == nullptr) {
|
||||
return false;
|
||||
}
|
||||
std::vector<char16_t> buffer(static_cast<size_t>(output_capacity) + 1, u'\0');
|
||||
uint32_t output_length = output_capacity;
|
||||
if (filter(buffer.data(), &output_length, source.c_str(),
|
||||
static_cast<uint32_t>(source.size())) != 0 ||
|
||||
output_length > output_capacity ||
|
||||
!IsValidUtf16(std::u16string_view(buffer.data(), output_length))) {
|
||||
return false;
|
||||
}
|
||||
output->assign(buffer.data(), buffer.data() + output_length);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ApplyKeyboardFilterOutput(ExternalInput* input, uint16_t keycode, uint32_t status,
|
||||
bool multiline) {
|
||||
constexpr uint32_t KEYCODE_VALID = 0x00000001;
|
||||
constexpr uint32_t CHARACTER_VALID = 0x00000002;
|
||||
if (keycode == input->key.keycode && status == input->key.status) {
|
||||
return true;
|
||||
}
|
||||
if ((status & KEYCODE_VALID) == 0 || keycode == 0) {
|
||||
return input->action == ExternalAction::Text && (status & CHARACTER_VALID) != 0;
|
||||
}
|
||||
input->key.keycode = keycode;
|
||||
input->key.status = status;
|
||||
input->text.clear();
|
||||
switch (keycode) {
|
||||
case 40:
|
||||
case 88:
|
||||
case 158:
|
||||
input->action = multiline ? ExternalAction::Newline : ExternalAction::Accept;
|
||||
break;
|
||||
case 41: input->action = ExternalAction::Cancel; break;
|
||||
case 42:
|
||||
case 187: input->action = ExternalAction::Backspace; break;
|
||||
case 43:
|
||||
case 186: input->action = ExternalAction::None; break;
|
||||
case 79: input->action = ExternalAction::MoveRight; break;
|
||||
case 80: input->action = ExternalAction::MoveLeft; break;
|
||||
default: {
|
||||
const char16_t character = HidCharacter(keycode, status);
|
||||
if (character == u'\0') {
|
||||
return false;
|
||||
}
|
||||
input->action = ExternalAction::Text;
|
||||
input->key.character = character;
|
||||
input->text.push_back(character);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void TextEditEngine::Reset(Type type, uint32_t option, uint32_t max_length, std::u16string text) {
|
||||
m_type = type;
|
||||
m_option = option;
|
||||
m_max_length = max_length;
|
||||
ClampText(&text, max_length);
|
||||
m_text = std::move(text);
|
||||
m_cursor = static_cast<uint32_t>(m_text.size());
|
||||
}
|
||||
|
||||
bool TextEditEngine::Insert(std::u16string_view text, EditDelta* edit) {
|
||||
if (text.empty() || !IsValidUtf16(text)) {
|
||||
return false;
|
||||
}
|
||||
std::u16string allowed;
|
||||
allowed.reserve(text.size());
|
||||
for (const char16_t value: text) {
|
||||
if (IsAllowedInput(value, m_type, m_option)) {
|
||||
allowed.push_back(value);
|
||||
}
|
||||
}
|
||||
const size_t available = m_max_length - m_text.size();
|
||||
if (allowed.empty() || available == 0) {
|
||||
return false;
|
||||
}
|
||||
allowed.resize(std::min(allowed.size(), available));
|
||||
if (!allowed.empty() && IsHighSurrogate(allowed.back())) {
|
||||
allowed.pop_back();
|
||||
}
|
||||
if (allowed.empty()) {
|
||||
return false;
|
||||
}
|
||||
if (edit != nullptr) {
|
||||
*edit = {m_cursor, static_cast<int32_t>(allowed.size())};
|
||||
}
|
||||
m_text.insert(m_cursor, allowed);
|
||||
m_cursor += static_cast<uint32_t>(allowed.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TextEditEngine::Backspace(EditDelta* edit) {
|
||||
if (m_cursor == 0) {
|
||||
return false;
|
||||
}
|
||||
uint32_t first = m_cursor - 1;
|
||||
if (first > 0 && IsLowSurrogate(m_text[first]) && IsHighSurrogate(m_text[first - 1])) {
|
||||
first--;
|
||||
}
|
||||
if (edit != nullptr) {
|
||||
*edit = {first, -static_cast<int32_t>(m_cursor - first)};
|
||||
}
|
||||
m_text.erase(first, m_cursor - first);
|
||||
m_cursor = first;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TextEditEngine::MoveCursor(int delta) {
|
||||
if (delta == 0) {
|
||||
return false;
|
||||
}
|
||||
int next = std::clamp(static_cast<int>(m_cursor) + delta, 0, static_cast<int>(m_text.size()));
|
||||
if (delta < 0 && next > 0 && next < static_cast<int>(m_text.size()) &&
|
||||
IsLowSurrogate(m_text[next]) && IsHighSurrogate(m_text[next - 1])) {
|
||||
next--;
|
||||
} else if (delta > 0 && next > 0 && next < static_cast<int>(m_text.size()) &&
|
||||
IsHighSurrogate(m_text[next - 1]) && IsLowSurrogate(m_text[next])) {
|
||||
next++;
|
||||
}
|
||||
if (next == static_cast<int>(m_cursor)) {
|
||||
return false;
|
||||
}
|
||||
m_cursor = static_cast<uint32_t>(next);
|
||||
return true;
|
||||
}
|
||||
|
||||
void TextEditEngine::ReplaceText(std::u16string text, uint32_t cursor) {
|
||||
ClampText(&text, m_max_length);
|
||||
m_text = std::move(text);
|
||||
m_cursor = NormalizeCursor(m_text, cursor);
|
||||
}
|
||||
|
||||
void TextEditEngine::SetCursor(uint32_t cursor) {
|
||||
m_cursor = NormalizeCursor(m_text, cursor);
|
||||
}
|
||||
|
||||
} // namespace Libs::ImeCommon
|
||||
@@ -0,0 +1,159 @@
|
||||
#ifndef EMULATOR_INCLUDE_EMULATOR_LIBS_IMECOMMON_H_
|
||||
#define EMULATOR_INCLUDE_EMULATOR_LIBS_IMECOMMON_H_
|
||||
|
||||
#include "common/abi.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace Libs::ImeCommon {
|
||||
|
||||
constexpr uint32_t MAX_TEXT_LENGTH = 2048;
|
||||
constexpr uint32_t OPTION_MULTILINE = 0x00000001;
|
||||
constexpr uint32_t OPTION_NO_AUTO_CAPITALIZE = 0x00000002;
|
||||
constexpr uint32_t OPTION_PASSWORD = 0x00000004;
|
||||
constexpr uint32_t OPTION_EXT_KEYBOARD = 0x00000010;
|
||||
constexpr uint32_t OPTION_FIXED_POSITION = 0x00000040;
|
||||
constexpr uint32_t OPTION_DISABLE_POSITION_ADJUST = 0x00000800;
|
||||
constexpr uint32_t OPTION_EXPANDED_PREEDIT = 0x00001000;
|
||||
constexpr uint32_t OPTION_USE_OVER_2K = 0x00004000;
|
||||
constexpr uint32_t EXT_OPTION_HIDE_KEY_PANEL = 0x00000400;
|
||||
constexpr uint32_t DISABLE_DEVICE_CONTROLLER = 0x00000001;
|
||||
constexpr uint32_t DISABLE_DEVICE_EXT_KEYBOARD = 0x00000002;
|
||||
|
||||
enum class Type : uint32_t { Default = 0, BasicLatin = 1, Url = 2, Mail = 3, Number = 4 };
|
||||
enum class EnterLabel : uint32_t { Default = 0, Send = 1, Search = 2, Go = 3 };
|
||||
enum class Alignment : uint32_t { Start = 0, Center = 1, End = 2 };
|
||||
|
||||
struct Color {
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
uint8_t a;
|
||||
};
|
||||
|
||||
struct Keycode {
|
||||
uint16_t keycode;
|
||||
char16_t character;
|
||||
uint32_t status;
|
||||
uint32_t type;
|
||||
int32_t user_id;
|
||||
uint32_t resource_id;
|
||||
uint64_t timestamp;
|
||||
};
|
||||
|
||||
using TextFilter = int32_t(KYTY_SYSV_ABI*)(char16_t* out_text, uint32_t* out_text_length,
|
||||
const char16_t* source_text,
|
||||
uint32_t source_text_length);
|
||||
using ExtKeyboardFilter = int(KYTY_SYSV_ABI*)(const Keycode* source_keycode, uint16_t* out_keycode,
|
||||
uint32_t* out_status, void* reserved);
|
||||
|
||||
struct ExtendedParam {
|
||||
uint32_t option;
|
||||
Color color_base;
|
||||
Color color_line;
|
||||
Color color_text_field;
|
||||
Color color_preedit;
|
||||
Color color_button_default;
|
||||
Color color_button_function;
|
||||
Color color_button_symbol;
|
||||
Color color_text;
|
||||
Color color_special;
|
||||
uint32_t priority;
|
||||
const char* additional_dictionary_path;
|
||||
ExtKeyboardFilter ext_keyboard_filter;
|
||||
uint32_t disable_device;
|
||||
uint32_t ext_keyboard_mode;
|
||||
int8_t reserved[60];
|
||||
};
|
||||
|
||||
enum class ExternalAction : uint8_t {
|
||||
None,
|
||||
Text,
|
||||
Backspace,
|
||||
MoveLeft,
|
||||
MoveRight,
|
||||
Cancel,
|
||||
Accept,
|
||||
Newline,
|
||||
};
|
||||
|
||||
struct ExternalInput {
|
||||
Keycode key {};
|
||||
ExternalAction action = ExternalAction::None;
|
||||
std::u16string text;
|
||||
};
|
||||
|
||||
struct VisualState {
|
||||
bool active;
|
||||
uint64_t revision;
|
||||
};
|
||||
|
||||
struct HostSnapshot {
|
||||
uint64_t generation = 0;
|
||||
Type type = Type::Default;
|
||||
EnterLabel enter_label = EnterLabel::Default;
|
||||
uint32_t option = 0;
|
||||
uint32_t max_text_length = 0;
|
||||
uint32_t cursor = 0;
|
||||
uint32_t disable_device = 0;
|
||||
bool key_panel_visible = true;
|
||||
float posx = 0.0f;
|
||||
float posy = 0.0f;
|
||||
Alignment horizontal_alignment = Alignment::Start;
|
||||
Alignment vertical_alignment = Alignment::Start;
|
||||
uint32_t panel_width = 0;
|
||||
uint32_t panel_height = 0;
|
||||
std::u16string text;
|
||||
std::u16string title;
|
||||
std::u16string placeholder;
|
||||
};
|
||||
|
||||
using VisibilityCallback = void (*)(bool visible, uint64_t generation);
|
||||
|
||||
struct EditDelta {
|
||||
uint32_t index = 0;
|
||||
int32_t length = 0;
|
||||
};
|
||||
|
||||
class TextEditEngine {
|
||||
public:
|
||||
void Reset(Type type, uint32_t option, uint32_t max_length, std::u16string text);
|
||||
|
||||
bool Insert(std::u16string_view text, EditDelta* edit = nullptr);
|
||||
bool Backspace(EditDelta* edit = nullptr);
|
||||
bool MoveCursor(int delta);
|
||||
|
||||
void ReplaceText(std::u16string text, uint32_t cursor);
|
||||
void SetCursor(uint32_t cursor);
|
||||
|
||||
[[nodiscard]] Type GetType() const { return m_type; }
|
||||
[[nodiscard]] uint32_t GetOption() const { return m_option; }
|
||||
[[nodiscard]] uint32_t GetMaxLength() const { return m_max_length; }
|
||||
[[nodiscard]] uint32_t GetCursor() const { return m_cursor; }
|
||||
[[nodiscard]] const std::u16string& GetText() const { return m_text; }
|
||||
|
||||
private:
|
||||
Type m_type = Type::Default;
|
||||
uint32_t m_option = 0;
|
||||
uint32_t m_max_length = 0;
|
||||
uint32_t m_cursor = 0;
|
||||
std::u16string m_text;
|
||||
};
|
||||
|
||||
[[nodiscard]] bool IsValidUtf16(std::u16string_view text);
|
||||
[[nodiscard]] bool IsValidInputText(std::u16string_view text, bool multiline);
|
||||
[[nodiscard]] bool IsAllowedInput(char16_t value, Type type, uint32_t option);
|
||||
[[nodiscard]] uint32_t NormalizeCursor(std::u16string_view text, uint32_t cursor);
|
||||
void ClampText(std::u16string* text, uint32_t limit);
|
||||
[[nodiscard]] EditDelta ComputeEditDelta(std::u16string_view before, std::u16string_view after);
|
||||
[[nodiscard]] bool RunTextFilter(TextFilter filter, const std::u16string& source,
|
||||
uint32_t output_capacity, std::u16string* output);
|
||||
[[nodiscard]] bool ApplyKeyboardFilterOutput(ExternalInput* input, uint16_t keycode,
|
||||
uint32_t status, bool multiline);
|
||||
|
||||
} // namespace Libs::ImeCommon
|
||||
|
||||
#endif // EMULATOR_INCLUDE_EMULATOR_LIBS_IMECOMMON_H_
|
||||
+19
-205
@@ -53,9 +53,8 @@ struct State {
|
||||
ExtendedParam extended {};
|
||||
bool input_changed = false;
|
||||
bool commit_pending = false;
|
||||
uint32_t cursor = 0;
|
||||
std::u16string original_text;
|
||||
std::u16string current_text;
|
||||
ImeCommon::TextEditEngine editor;
|
||||
std::u16string title;
|
||||
std::u16string placeholder;
|
||||
std::vector<ExternalInput> external_inputs;
|
||||
@@ -71,8 +70,6 @@ bool AllZero(const int8_t* data, size_t size) {
|
||||
return std::all_of(data, data + size, [](int8_t value) { return value == 0; });
|
||||
}
|
||||
|
||||
bool IsValidUtf16(std::u16string_view text);
|
||||
|
||||
bool ReadBounded(const char16_t* text, uint32_t limit, std::u16string* out) {
|
||||
out->clear();
|
||||
if (text == nullptr) {
|
||||
@@ -82,7 +79,7 @@ bool ReadBounded(const char16_t* text, uint32_t limit, std::u16string* out) {
|
||||
for (uint32_t i = 0; i <= limit; ++i) {
|
||||
const char16_t value = text[i];
|
||||
if (value == u'\0') {
|
||||
return IsValidUtf16(*out);
|
||||
return ImeCommon::IsValidUtf16(*out);
|
||||
}
|
||||
if (i == limit) {
|
||||
return false;
|
||||
@@ -92,128 +89,6 @@ bool ReadBounded(const char16_t* text, uint32_t limit, std::u16string* out) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsValidUtf16(std::u16string_view text) {
|
||||
for (size_t i = 0; i < text.size(); i++) {
|
||||
const char16_t current = text[i];
|
||||
if (current >= 0xd800 && current <= 0xdbff) {
|
||||
if (++i >= text.size() || text[i] < 0xdc00 || text[i] > 0xdfff) {
|
||||
return false;
|
||||
}
|
||||
} else if (current >= 0xdc00 && current <= 0xdfff) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsAllowedInput(char16_t value, Type type, uint32_t option) {
|
||||
if (value == u'\r') {
|
||||
return false;
|
||||
}
|
||||
if (value == u'\n') {
|
||||
return (option & OPTION_MULTILINE) != 0;
|
||||
}
|
||||
if (value == u'\0') {
|
||||
return false;
|
||||
}
|
||||
if (type == Type::Number) {
|
||||
return (value >= u'0' && value <= u'9') || value == u',' || value == u'-' || value == u'.';
|
||||
}
|
||||
if (type == Type::BasicLatin) {
|
||||
return value >= u' ' && value <= u'~';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
char16_t HidCharacter(uint16_t keycode, uint32_t status) {
|
||||
const bool shift = (status & 0x00002200) != 0;
|
||||
const bool caps = (status & 0x00020000) != 0;
|
||||
if (keycode >= 4 && keycode <= 29) {
|
||||
const bool upper = shift != caps;
|
||||
return static_cast<char16_t>((upper ? u'A' : u'a') + keycode - 4);
|
||||
}
|
||||
if (keycode >= 30 && keycode <= 39) {
|
||||
static constexpr char16_t plain[] = u"1234567890";
|
||||
static constexpr char16_t shifted[] = u"!@#$%^&*()";
|
||||
return (shift ? shifted : plain)[keycode - 30];
|
||||
}
|
||||
if (keycode == 44) {
|
||||
return u' ';
|
||||
}
|
||||
if (keycode >= 45 && keycode <= 56) {
|
||||
static constexpr char16_t plain[] = u"-=[]\\#;'`,./";
|
||||
static constexpr char16_t shifted[] = u"_+{}|~:\"~<>?";
|
||||
return (shift ? shifted : plain)[keycode - 45];
|
||||
}
|
||||
if (keycode >= 89 && keycode <= 98) {
|
||||
static constexpr char16_t keypad[] = u"1234567890";
|
||||
return keypad[keycode - 89];
|
||||
}
|
||||
if (keycode == 99) {
|
||||
return u'.';
|
||||
}
|
||||
return u'\0';
|
||||
}
|
||||
|
||||
bool ApplyKeyboardFilterOutput(ExternalInput* input, uint16_t keycode, uint32_t status,
|
||||
bool multiline) {
|
||||
constexpr uint32_t KEYCODE_VALID = 0x00000001;
|
||||
constexpr uint32_t CHARACTER_VALID = 0x00000002;
|
||||
if (keycode == input->key.keycode && status == input->key.status) {
|
||||
return true;
|
||||
}
|
||||
if ((status & KEYCODE_VALID) == 0 || keycode == 0) {
|
||||
return input->action == ExternalAction::Text && (status & CHARACTER_VALID) != 0;
|
||||
}
|
||||
input->key.keycode = keycode;
|
||||
input->key.status = status;
|
||||
input->text.clear();
|
||||
switch (keycode) {
|
||||
case 40:
|
||||
case 88:
|
||||
case 158:
|
||||
input->action = multiline ? ExternalAction::Newline : ExternalAction::Accept;
|
||||
break;
|
||||
case 41: input->action = ExternalAction::Cancel; break;
|
||||
case 42:
|
||||
case 187: input->action = ExternalAction::Backspace; break;
|
||||
case 43:
|
||||
case 186: input->action = ExternalAction::None; break;
|
||||
case 79: input->action = ExternalAction::MoveRight; break;
|
||||
case 80: input->action = ExternalAction::MoveLeft; break;
|
||||
default: {
|
||||
const char16_t character = HidCharacter(keycode, status);
|
||||
if (character == u'\0') {
|
||||
return false;
|
||||
}
|
||||
input->action = ExternalAction::Text;
|
||||
input->key.character = character;
|
||||
input->text.push_back(character);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ClampText(std::u16string* text, uint32_t limit) {
|
||||
if (text->size() <= limit) {
|
||||
return;
|
||||
}
|
||||
text->resize(limit);
|
||||
if (!text->empty() && text->back() >= 0xd800 && text->back() <= 0xdbff) {
|
||||
text->pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t NormalizeCursor(std::u16string_view text, uint32_t cursor) {
|
||||
cursor = std::min<uint32_t>(cursor, static_cast<uint32_t>(text.size()));
|
||||
if (cursor > 0 && cursor < text.size() && text[cursor - 1] >= 0xd800 &&
|
||||
text[cursor - 1] <= 0xdbff && text[cursor] >= 0xdc00 && text[cursor] <= 0xdfff) {
|
||||
cursor++;
|
||||
}
|
||||
return cursor;
|
||||
}
|
||||
|
||||
void WriteGuestText(const State& state, const std::u16string& text) {
|
||||
if (state.param.input_text_buffer == nullptr) {
|
||||
return;
|
||||
@@ -355,7 +230,7 @@ void ApplyFilterAndCommit() {
|
||||
return;
|
||||
}
|
||||
filter = g_state.input_changed ? g_state.param.filter : nullptr;
|
||||
source = g_state.current_text;
|
||||
source = g_state.editor.GetText();
|
||||
max_length = g_state.param.max_text_length;
|
||||
generation = g_state.generation;
|
||||
revision = g_state.revision;
|
||||
@@ -363,14 +238,10 @@ void ApplyFilterAndCommit() {
|
||||
}
|
||||
|
||||
if (filter != nullptr) {
|
||||
std::vector<char16_t> output(IME_DIALOG_MAX_TEXT_LENGTH + 1, u'\0');
|
||||
uint32_t output_length = IME_DIALOG_MAX_TEXT_LENGTH;
|
||||
if (filter(output.data(), &output_length, source.c_str(),
|
||||
static_cast<uint32_t>(source.size())) == 0 &&
|
||||
output_length <= IME_DIALOG_MAX_TEXT_LENGTH &&
|
||||
IsValidUtf16(std::u16string_view(output.data(), output_length))) {
|
||||
source.assign(output.data(), output.data() + output_length);
|
||||
ClampText(&source, max_length);
|
||||
std::u16string filtered;
|
||||
if (ImeCommon::RunTextFilter(filter, source, IME_DIALOG_MAX_TEXT_LENGTH, &filtered)) {
|
||||
source = std::move(filtered);
|
||||
ImeCommon::ClampText(&source, max_length);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -386,13 +257,12 @@ void ApplyFilterAndCommit() {
|
||||
return;
|
||||
}
|
||||
if (!g_state.input_changed) {
|
||||
g_state.current_text = std::move(source);
|
||||
g_state.cursor = NormalizeCursor(g_state.current_text, g_state.cursor);
|
||||
g_state.editor.ReplaceText(std::move(source), g_state.editor.GetCursor());
|
||||
}
|
||||
const auto& committed =
|
||||
g_state.status == Status::Finished && g_state.end_status != EndStatus::Ok
|
||||
? g_state.original_text
|
||||
: g_state.current_text;
|
||||
: g_state.editor.GetText();
|
||||
WriteGuestText(g_state, committed);
|
||||
g_state.commit_pending = false;
|
||||
}
|
||||
@@ -451,8 +321,8 @@ void ApplyExternalInputs() {
|
||||
uint16_t output_keycode = input.key.keycode;
|
||||
uint32_t output_status = input.key.status;
|
||||
if (filter(&input.key, &output_keycode, &output_status, nullptr) == 0) {
|
||||
accepted =
|
||||
ApplyKeyboardFilterOutput(&input, output_keycode, output_status, multiline);
|
||||
accepted = ImeCommon::ApplyKeyboardFilterOutput(&input, output_keycode,
|
||||
output_status, multiline);
|
||||
}
|
||||
}
|
||||
if (!accepted) {
|
||||
@@ -528,9 +398,9 @@ int KYTY_SYSV_ABI ImeDialogInit(const Param* param, const ExtendedParam* extende
|
||||
if (extended != nullptr) {
|
||||
g_state.extended = *extended;
|
||||
}
|
||||
g_state.original_text = initial;
|
||||
g_state.current_text = std::move(initial);
|
||||
g_state.cursor = static_cast<uint32_t>(g_state.current_text.size());
|
||||
g_state.original_text = initial;
|
||||
g_state.editor.Reset(param->type, param->option, param->max_text_length,
|
||||
std::move(initial));
|
||||
g_state.title = std::move(title);
|
||||
g_state.placeholder = std::move(placeholder);
|
||||
g_state.commit_pending = true;
|
||||
@@ -664,7 +534,7 @@ bool GetHostSnapshot(HostSnapshot* snapshot) {
|
||||
snapshot->enter_label = g_state.param.enter_label;
|
||||
snapshot->option = g_state.param.option;
|
||||
snapshot->max_text_length = g_state.param.max_text_length;
|
||||
snapshot->cursor = g_state.cursor;
|
||||
snapshot->cursor = g_state.editor.GetCursor();
|
||||
snapshot->disable_device = g_state.extended.disable_device;
|
||||
snapshot->key_panel_visible = (g_state.param.option & OPTION_EXT_KEYBOARD) == 0 ||
|
||||
(g_state.extended.option & 0x00000400) == 0;
|
||||
@@ -674,7 +544,7 @@ bool GetHostSnapshot(HostSnapshot* snapshot) {
|
||||
snapshot->vertical_alignment = g_state.param.vertical_alignment;
|
||||
ComputePanelSize(g_state.param, &g_state.extended, &snapshot->panel_width,
|
||||
&snapshot->panel_height);
|
||||
snapshot->text = g_state.current_text;
|
||||
snapshot->text = g_state.editor.GetText();
|
||||
snapshot->title = g_state.title;
|
||||
snapshot->placeholder = g_state.placeholder;
|
||||
return true;
|
||||
@@ -682,38 +552,9 @@ bool GetHostSnapshot(HostSnapshot* snapshot) {
|
||||
|
||||
bool HostInsertText(uint64_t generation, std::u16string_view text) {
|
||||
std::scoped_lock lock(g_mutex);
|
||||
if (!MatchRunningGeneration(generation) || text.empty()) {
|
||||
if (!MatchRunningGeneration(generation) || !g_state.editor.Insert(text)) {
|
||||
return false;
|
||||
}
|
||||
if (!IsValidUtf16(text)) {
|
||||
return false;
|
||||
}
|
||||
std::u16string allowed;
|
||||
allowed.reserve(text.size());
|
||||
for (const char16_t value: text) {
|
||||
if (IsAllowedInput(value, g_state.param.type, g_state.param.option)) {
|
||||
allowed.push_back(value);
|
||||
}
|
||||
}
|
||||
if (allowed.empty()) {
|
||||
return false;
|
||||
}
|
||||
const size_t available = g_state.param.max_text_length - g_state.current_text.size();
|
||||
if (available == 0) {
|
||||
return false;
|
||||
}
|
||||
std::u16string insertion(std::u16string_view(allowed).substr(0, available));
|
||||
if (insertion.size() < allowed.size() && !insertion.empty() && insertion.back() >= 0xd800 &&
|
||||
insertion.back() <= 0xdbff) {
|
||||
insertion.pop_back();
|
||||
}
|
||||
if (insertion.empty()) {
|
||||
return false;
|
||||
}
|
||||
std::u16string candidate = g_state.current_text;
|
||||
candidate.insert(g_state.cursor, insertion);
|
||||
g_state.current_text = std::move(candidate);
|
||||
g_state.cursor += static_cast<uint32_t>(insertion.size());
|
||||
g_state.input_changed = true;
|
||||
g_state.commit_pending = true;
|
||||
return true;
|
||||
@@ -721,17 +562,9 @@ bool HostInsertText(uint64_t generation, std::u16string_view text) {
|
||||
|
||||
bool HostBackspace(uint64_t generation) {
|
||||
std::scoped_lock lock(g_mutex);
|
||||
if (!MatchRunningGeneration(generation) || g_state.cursor == 0) {
|
||||
if (!MatchRunningGeneration(generation) || !g_state.editor.Backspace()) {
|
||||
return false;
|
||||
}
|
||||
uint32_t first = g_state.cursor - 1;
|
||||
if (first > 0 && g_state.current_text[first] >= 0xdc00 &&
|
||||
g_state.current_text[first] <= 0xdfff && g_state.current_text[first - 1] >= 0xd800 &&
|
||||
g_state.current_text[first - 1] <= 0xdbff) {
|
||||
first--;
|
||||
}
|
||||
g_state.current_text.erase(first, g_state.cursor - first);
|
||||
g_state.cursor = first;
|
||||
g_state.input_changed = true;
|
||||
g_state.commit_pending = true;
|
||||
return true;
|
||||
@@ -739,26 +572,7 @@ bool HostBackspace(uint64_t generation) {
|
||||
|
||||
bool HostMoveCursor(uint64_t generation, int delta) {
|
||||
std::scoped_lock lock(g_mutex);
|
||||
if (!MatchRunningGeneration(generation) || delta == 0) {
|
||||
return false;
|
||||
}
|
||||
int next = std::clamp(static_cast<int>(g_state.cursor) + delta, 0,
|
||||
static_cast<int>(g_state.current_text.size()));
|
||||
if (delta < 0 && next > 0 && next < static_cast<int>(g_state.current_text.size()) &&
|
||||
g_state.current_text[next] >= 0xdc00 && g_state.current_text[next] <= 0xdfff &&
|
||||
g_state.current_text[next - 1] >= 0xd800 && g_state.current_text[next - 1] <= 0xdbff) {
|
||||
next--;
|
||||
} else if (delta > 0 && next > 0 && next < static_cast<int>(g_state.current_text.size()) &&
|
||||
g_state.current_text[next - 1] >= 0xd800 &&
|
||||
g_state.current_text[next - 1] <= 0xdbff && g_state.current_text[next] >= 0xdc00 &&
|
||||
g_state.current_text[next] <= 0xdfff) {
|
||||
next++;
|
||||
}
|
||||
if (next == static_cast<int>(g_state.cursor)) {
|
||||
return false;
|
||||
}
|
||||
g_state.cursor = static_cast<uint32_t>(next);
|
||||
return true;
|
||||
return MatchRunningGeneration(generation) && g_state.editor.MoveCursor(delta);
|
||||
}
|
||||
|
||||
bool HostAccept(uint64_t generation) {
|
||||
|
||||
+25
-99
@@ -1,7 +1,7 @@
|
||||
#ifndef EMULATOR_INCLUDE_EMULATOR_LIBS_IMEDIALOG_H_
|
||||
#define EMULATOR_INCLUDE_EMULATOR_LIBS_IMEDIALOG_H_
|
||||
|
||||
#include "common/abi.h"
|
||||
#include "libs/imeCommon.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
@@ -10,53 +10,43 @@
|
||||
|
||||
namespace Libs::Dialog::ImeDialog {
|
||||
|
||||
constexpr uint32_t IME_DIALOG_MAX_TEXT_LENGTH = 2048;
|
||||
constexpr uint32_t IME_DIALOG_MAX_TEXT_LENGTH = ImeCommon::MAX_TEXT_LENGTH;
|
||||
constexpr uint32_t IME_DIALOG_MAX_TITLE_LENGTH = 128;
|
||||
constexpr uint32_t IME_DIALOG_MAX_PLACEHOLDER_LENGTH = 64;
|
||||
|
||||
enum class Status : uint32_t { None = 0, Running = 1, Finished = 2 };
|
||||
enum class EndStatus : uint32_t { Ok = 0, UserCanceled = 1, Aborted = 2 };
|
||||
enum class Type : uint32_t { Default = 0, BasicLatin = 1, Url = 2, Mail = 3, Number = 4 };
|
||||
enum class EnterLabel : uint32_t { Default = 0, Send = 1, Search = 2, Go = 3 };
|
||||
enum class Alignment : uint32_t { Start = 0, Center = 1, End = 2 };
|
||||
using Type = ImeCommon::Type;
|
||||
using EnterLabel = ImeCommon::EnterLabel;
|
||||
using Alignment = ImeCommon::Alignment;
|
||||
|
||||
enum Option : uint32_t {
|
||||
OPTION_MULTILINE = 0x00000001,
|
||||
OPTION_NO_AUTO_CAPITALIZE = 0x00000002,
|
||||
OPTION_PASSWORD = 0x00000004,
|
||||
OPTION_MULTILINE = ImeCommon::OPTION_MULTILINE,
|
||||
OPTION_NO_AUTO_CAPITALIZE = ImeCommon::OPTION_NO_AUTO_CAPITALIZE,
|
||||
OPTION_PASSWORD = ImeCommon::OPTION_PASSWORD,
|
||||
OPTION_LANGUAGES_FORCED = 0x00000008,
|
||||
OPTION_EXT_KEYBOARD = 0x00000010,
|
||||
OPTION_EXT_KEYBOARD = ImeCommon::OPTION_EXT_KEYBOARD,
|
||||
OPTION_NO_LEARNING = 0x00000020,
|
||||
OPTION_FIXED_POSITION = 0x00000040,
|
||||
OPTION_FIXED_POSITION = ImeCommon::OPTION_FIXED_POSITION,
|
||||
OPTION_DISABLE_COPY_PASTE = 0x00000080,
|
||||
OPTION_DISABLE_RESUME = 0x00000100,
|
||||
OPTION_DISABLE_AUTO_SPACE = 0x00000200,
|
||||
OPTION_DISABLE_POSITION_ADJ = 0x00000800,
|
||||
OPTION_EXPANDED_PREEDIT = 0x00001000,
|
||||
OPTION_DISABLE_POSITION_ADJ = ImeCommon::OPTION_DISABLE_POSITION_ADJUST,
|
||||
OPTION_EXPANDED_PREEDIT = ImeCommon::OPTION_EXPANDED_PREEDIT,
|
||||
OPTION_JAPANESE_CAPS_LOCK = 0x00002000,
|
||||
OPTION_USE_OVER_2K = 0x00004000,
|
||||
OPTION_USE_OVER_2K = ImeCommon::OPTION_USE_OVER_2K,
|
||||
};
|
||||
|
||||
enum DisableDevice : uint32_t {
|
||||
DISABLE_DEVICE_CONTROLLER = 0x00000001,
|
||||
DISABLE_DEVICE_EXT_KEYBOARD = 0x00000002,
|
||||
DISABLE_DEVICE_CONTROLLER = ImeCommon::DISABLE_DEVICE_CONTROLLER,
|
||||
DISABLE_DEVICE_EXT_KEYBOARD = ImeCommon::DISABLE_DEVICE_EXT_KEYBOARD,
|
||||
DISABLE_DEVICE_REMOTE_OSK = 0x00000004,
|
||||
};
|
||||
|
||||
struct Color {
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
uint8_t a;
|
||||
};
|
||||
|
||||
struct Keycode;
|
||||
|
||||
using TextFilter = int32_t(KYTY_SYSV_ABI*)(char16_t* out_text, uint32_t* out_text_length,
|
||||
const char16_t* source_text,
|
||||
uint32_t source_text_length);
|
||||
using ExtKeyboardFilter = int(KYTY_SYSV_ABI*)(const Keycode* source_keycode, uint16_t* out_keycode,
|
||||
uint32_t* out_status, void* reserved);
|
||||
using Color = ImeCommon::Color;
|
||||
using Keycode = ImeCommon::Keycode;
|
||||
using TextFilter = ImeCommon::TextFilter;
|
||||
using ExtKeyboardFilter = ImeCommon::ExtKeyboardFilter;
|
||||
|
||||
struct Param {
|
||||
int32_t user_id;
|
||||
@@ -82,24 +72,7 @@ struct Result {
|
||||
int8_t reserved[12];
|
||||
};
|
||||
|
||||
struct ExtendedParam {
|
||||
uint32_t option;
|
||||
Color color_base;
|
||||
Color color_line;
|
||||
Color color_text_field;
|
||||
Color color_preedit;
|
||||
Color color_button_default;
|
||||
Color color_button_function;
|
||||
Color color_button_symbol;
|
||||
Color color_text;
|
||||
Color color_special;
|
||||
uint32_t priority;
|
||||
const char* additional_dictionary_path;
|
||||
ExtKeyboardFilter ext_keyboard_filter;
|
||||
uint32_t disable_device;
|
||||
uint32_t ext_keyboard_mode;
|
||||
int8_t reserved[60];
|
||||
};
|
||||
using ExtendedParam = ImeCommon::ExtendedParam;
|
||||
|
||||
struct PositionAndForm {
|
||||
uint32_t type;
|
||||
@@ -111,32 +84,8 @@ struct PositionAndForm {
|
||||
uint32_t height;
|
||||
};
|
||||
|
||||
struct Keycode {
|
||||
uint16_t keycode;
|
||||
char16_t character;
|
||||
uint32_t status;
|
||||
uint32_t type;
|
||||
int32_t user_id;
|
||||
uint32_t resource_id;
|
||||
uint64_t timestamp;
|
||||
};
|
||||
|
||||
enum class ExternalAction : uint8_t {
|
||||
None,
|
||||
Text,
|
||||
Backspace,
|
||||
MoveLeft,
|
||||
MoveRight,
|
||||
Cancel,
|
||||
Accept,
|
||||
Newline,
|
||||
};
|
||||
|
||||
struct ExternalInput {
|
||||
Keycode key;
|
||||
ExternalAction action;
|
||||
std::u16string text;
|
||||
};
|
||||
using ExternalAction = ImeCommon::ExternalAction;
|
||||
using ExternalInput = ImeCommon::ExternalInput;
|
||||
|
||||
static_assert(sizeof(Param) == 0x60);
|
||||
static_assert(offsetof(Param, input_text_buffer) == 0x28);
|
||||
@@ -147,32 +96,9 @@ static_assert(offsetof(ExtendedParam, additional_dictionary_path) == 0x30);
|
||||
static_assert(sizeof(PositionAndForm) == 0x1c);
|
||||
static_assert(sizeof(Keycode) == 0x20);
|
||||
|
||||
struct VisualState {
|
||||
bool active;
|
||||
uint64_t revision;
|
||||
};
|
||||
|
||||
struct HostSnapshot {
|
||||
uint64_t generation;
|
||||
Type type;
|
||||
EnterLabel enter_label;
|
||||
uint32_t option;
|
||||
uint32_t max_text_length;
|
||||
uint32_t cursor;
|
||||
uint32_t disable_device;
|
||||
bool key_panel_visible;
|
||||
float posx;
|
||||
float posy;
|
||||
Alignment horizontal_alignment;
|
||||
Alignment vertical_alignment;
|
||||
uint32_t panel_width;
|
||||
uint32_t panel_height;
|
||||
std::u16string text;
|
||||
std::u16string title;
|
||||
std::u16string placeholder;
|
||||
};
|
||||
|
||||
using VisibilityCallback = void (*)(bool visible, uint64_t generation);
|
||||
using VisualState = ImeCommon::VisualState;
|
||||
using HostSnapshot = ImeCommon::HostSnapshot;
|
||||
using VisibilityCallback = ImeCommon::VisibilityCallback;
|
||||
|
||||
int KYTY_SYSV_ABI ImeDialogGetPanelSize(const Param* param, uint32_t* width, uint32_t* height);
|
||||
int KYTY_SYSV_ABI ImeDialogGetPanelSizeExtended(const Param* param, const ExtendedParam* extended,
|
||||
|
||||
@@ -2517,12 +2517,6 @@ static void KYTY_SYSV_ABI AmmGetVirtualAddressRanges(uint64_t* va_start, uint64_
|
||||
uint64_t* multimap_va_end) {
|
||||
PRINT_NAME();
|
||||
|
||||
void* reserve_addr = reinterpret_cast<void*>(AMM_VA_START);
|
||||
if (LibKernel::Memory::KernelReserveVirtualRange(&reserve_addr, AMM_VA_SIZE, AMM_MAP_FIXED,
|
||||
0x10000) == OK) {
|
||||
(void)LibKernel::Memory::KernelSetVirtualRangeName(reserve_addr, AMM_VA_SIZE, "AMM");
|
||||
}
|
||||
|
||||
if (va_start != nullptr) {
|
||||
AprShared::WriteGuest(reinterpret_cast<uint64_t>(va_start), AMM_VA_START);
|
||||
}
|
||||
|
||||
+1
-1
@@ -226,7 +226,7 @@ static void PrintAbortPointerArrayCandidate(const char* name, uint64_t addr) {
|
||||
PrintAbortPointerArrayCandidate("arg5", arg5);
|
||||
|
||||
if (rbp != 0) {
|
||||
Common::Singleton<Loader::RuntimeLinker>::Instance()->StackTrace(rbp);
|
||||
Common::Singleton<Loader::RuntimeLinker>::Instance()->StackTrace(rbp, rsp);
|
||||
}
|
||||
|
||||
if (rsp != 0) {
|
||||
|
||||
@@ -237,15 +237,16 @@ private:
|
||||
|
||||
static Network* g_net = nullptr;
|
||||
|
||||
KYTY_SUBSYSTEM_INIT(Network) {
|
||||
void Initialize() {
|
||||
EXIT_IF(g_net != nullptr);
|
||||
|
||||
g_net = new Network;
|
||||
}
|
||||
|
||||
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Network) {}
|
||||
|
||||
KYTY_SUBSYSTEM_DESTROY(Network) {}
|
||||
void Shutdown() {
|
||||
delete g_net;
|
||||
g_net = nullptr;
|
||||
}
|
||||
|
||||
int Network::PoolCreate(const char* name, int size) {
|
||||
Common::LockGuard lock(m_mutex);
|
||||
|
||||
+8
-3
@@ -3,11 +3,16 @@
|
||||
|
||||
#include "common/abi.h"
|
||||
#include "common/common.h"
|
||||
#include "common/subsystems.h"
|
||||
|
||||
namespace Libs::Network {
|
||||
|
||||
KYTY_SUBSYSTEM_DEFINE(Network);
|
||||
void Initialize();
|
||||
void Shutdown();
|
||||
|
||||
struct Lifecycle {
|
||||
static constexpr const char* name = "Network";
|
||||
static constexpr auto initialize = Libs::Network::Initialize;
|
||||
static constexpr auto shutdown = Libs::Network::Shutdown;
|
||||
};
|
||||
|
||||
namespace Net {
|
||||
|
||||
|
||||
@@ -672,48 +672,39 @@ static Common::VirtualMemory::Mode GetMode(Elf64_Word flags) {
|
||||
}
|
||||
}
|
||||
|
||||
struct FrameS {
|
||||
FrameS* next;
|
||||
uintptr_t ret_addr;
|
||||
struct GuestStackFrame {
|
||||
GuestStackFrame* next;
|
||||
uintptr_t return_address;
|
||||
};
|
||||
|
||||
static void KYTY_SYSV_ABI StackwalkX86(uint64_t rbp, void** stack, int* depth, uintptr_t stack_addr,
|
||||
size_t stack_size, uintptr_t code_addr, size_t code_size) {
|
||||
auto* frame = reinterpret_cast<FrameS*>(rbp);
|
||||
static bool IsReadableRange(uint64_t addr, uint64_t size);
|
||||
|
||||
int d = *depth;
|
||||
int i = 0;
|
||||
static int WalkGuestStack(uint64_t rbp, uint64_t rsp, void** stack, int capacity) {
|
||||
constexpr uintptr_t STACK_SIZE = 1024u * 1024u;
|
||||
const uintptr_t code_start = SYSTEM_RESERVED + CODE_BASE_OFFSET;
|
||||
const uintptr_t stack_end = rsp + STACK_SIZE;
|
||||
if (stack == nullptr || capacity <= 0 || rsp == 0 || rbp < rsp || stack_end < rsp ||
|
||||
g_desired_base_addr <= code_start) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (; i < d; i++) {
|
||||
if (!(reinterpret_cast<uintptr_t>(frame) >= stack_addr &&
|
||||
reinterpret_cast<uintptr_t>(frame) < stack_addr + stack_size)) {
|
||||
auto* frame = reinterpret_cast<GuestStackFrame*>(rbp);
|
||||
|
||||
int depth = 0;
|
||||
while (depth < capacity) {
|
||||
const auto frame_addr = reinterpret_cast<uintptr_t>(frame);
|
||||
if (frame_addr < rsp || frame_addr > stack_end - sizeof(GuestStackFrame) ||
|
||||
!IsReadableRange(frame_addr, sizeof(GuestStackFrame)) ||
|
||||
frame->return_address < code_start || frame->return_address >= g_desired_base_addr) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(frame->ret_addr >= code_addr && frame->ret_addr < code_addr + code_size)) {
|
||||
stack[depth++] = reinterpret_cast<void*>(frame->return_address);
|
||||
if (reinterpret_cast<uintptr_t>(frame->next) <= frame_addr) {
|
||||
break;
|
||||
}
|
||||
|
||||
stack[i] = reinterpret_cast<void*>(frame->ret_addr);
|
||||
|
||||
frame = frame->next;
|
||||
}
|
||||
|
||||
*depth = i;
|
||||
}
|
||||
|
||||
static void KYTY_SYSV_ABI SysStackWalkX86(uint64_t rbp, uint64_t rsp, void** stack, int* depth) {
|
||||
if (rsp == 0 || rbp < rsp) {
|
||||
*depth = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
StackwalkX86(rbp, stack, depth, rsp, 1024u * 1024u, SYSTEM_RESERVED + CODE_BASE_OFFSET,
|
||||
g_desired_base_addr - (SYSTEM_RESERVED + CODE_BASE_OFFSET));
|
||||
}
|
||||
|
||||
void KYTY_SYSV_ABI SysStackWalkX86(uint64_t rbp, void** stack, int* depth) {
|
||||
SysStackWalkX86(rbp, rbp, stack, depth);
|
||||
return depth;
|
||||
}
|
||||
|
||||
// Probe diagnostic ranges without raising another fault.
|
||||
@@ -961,22 +952,7 @@ static bool KytyExceptionHandler(const Common::HostException::ExceptionInfo& exc
|
||||
|
||||
if (info->type == Common::HostException::ExceptionType::AccessViolation) {
|
||||
if (info->rbp != 0) {
|
||||
void* stack[20];
|
||||
int depth = 20;
|
||||
SysStackWalkX86(info->rbp, info->rsp, stack, &depth);
|
||||
|
||||
LOGF("Stack trace [thread = %d]:\n", Common::Thread::GetThreadIdUnique());
|
||||
for (int i = 0; i < depth; i++) {
|
||||
auto vaddr = reinterpret_cast<uint64_t>(stack[i]);
|
||||
auto* p =
|
||||
Common::Singleton<Loader::RuntimeLinker>::Instance()->FindProgramByAddr(vaddr);
|
||||
LOGF("[%d] %016" PRIx64 ", off=%016" PRIx64 ", %s\n", i, vaddr,
|
||||
(p == nullptr ? 0 : vaddr - p->base_vaddr),
|
||||
(p == nullptr ? "???"
|
||||
: Common::FilenameWithoutDirectory(
|
||||
Common::PathToGenericString(p->file_name))
|
||||
.c_str()));
|
||||
}
|
||||
Common::Singleton<Loader::RuntimeLinker>::Instance()->StackTrace(info->rbp, info->rsp);
|
||||
}
|
||||
|
||||
auto dump_guest_qwords = [](const char* name, uint64_t addr) {
|
||||
@@ -1896,11 +1872,9 @@ Program* RuntimeLinker::FindProgramByAddr(uint64_t vaddr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void RuntimeLinker::StackTrace(uint64_t frame_ptr) {
|
||||
void RuntimeLinker::StackTrace(uint64_t frame_ptr, uint64_t stack_ptr) {
|
||||
void* stack[20];
|
||||
int depth = 20;
|
||||
|
||||
SysStackWalkX86(frame_ptr, stack, &depth);
|
||||
int depth = WalkGuestStack(frame_ptr, stack_ptr, stack, static_cast<int>(std::size(stack)));
|
||||
|
||||
LOGF("Stack trace [thread = %d]:\n", Common::Thread::GetThreadIdUnique());
|
||||
|
||||
|
||||
@@ -183,7 +183,7 @@ public:
|
||||
static uint8_t* TlsGetAddr(Program* program);
|
||||
static void DeleteTls(Program* program, int thread_id);
|
||||
|
||||
void StackTrace(uint64_t frame_ptr);
|
||||
void StackTrace(uint64_t frame_ptr, uint64_t stack_ptr);
|
||||
|
||||
private:
|
||||
static void LoadProgramToMemory(Program* program);
|
||||
|
||||
@@ -2,21 +2,12 @@
|
||||
|
||||
#include "common/abi.h"
|
||||
#include "common/dateTime.h"
|
||||
#include "common/subsystems.h"
|
||||
#include "loader/timer.h"
|
||||
|
||||
namespace Loader::Timer {
|
||||
|
||||
static Common::Timer g_timer;
|
||||
|
||||
KYTY_SUBSYSTEM_INIT(Timer) {
|
||||
Start();
|
||||
}
|
||||
|
||||
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Timer) {}
|
||||
|
||||
KYTY_SUBSYSTEM_DESTROY(Timer) {}
|
||||
|
||||
void Start() {
|
||||
g_timer.Start();
|
||||
}
|
||||
|
||||
+5
-4
@@ -4,18 +4,19 @@
|
||||
#include "common/abi.h"
|
||||
#include "common/common.h"
|
||||
#include "common/dateTime.h"
|
||||
#include "common/subsystems.h"
|
||||
|
||||
namespace Loader::Timer {
|
||||
|
||||
KYTY_SUBSYSTEM_DEFINE(Timer);
|
||||
|
||||
void Start();
|
||||
double GetTimeMs();
|
||||
Common::Time GetTime();
|
||||
uint64_t GetCounter();
|
||||
uint64_t GetFrequency();
|
||||
|
||||
struct Lifecycle {
|
||||
static constexpr const char* name = "Timer";
|
||||
static constexpr auto initialize = Loader::Timer::Start;
|
||||
};
|
||||
|
||||
} // namespace Loader::Timer
|
||||
|
||||
#endif /* EMULATOR_INCLUDE_EMULATOR_LOADER_TIMER_H_ */
|
||||
+3
-21
@@ -1,5 +1,4 @@
|
||||
#include "common/common.h"
|
||||
#include "common/commonSubsystem.h"
|
||||
#include "common/dateTime.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/file.h"
|
||||
@@ -7,6 +6,7 @@
|
||||
#include "common/platform/sysDbg.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/threads.h"
|
||||
#include "common/virtualMemory.h"
|
||||
#include "emulator.h"
|
||||
#include "kytyGitVersion.h"
|
||||
|
||||
@@ -275,46 +275,28 @@ static bool ParseArgs(int argc, char* argv[], RunOptions& options, bool& show_he
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
auto& slist = *SubsystemsList::Instance();
|
||||
|
||||
slist.SetArgs(argc, argv);
|
||||
|
||||
auto* core = CommonSubsystem::Instance();
|
||||
auto* threads = ThreadsSubsystem::Instance();
|
||||
|
||||
slist.Add(core, {});
|
||||
slist.Add(threads, {core});
|
||||
|
||||
if (!slist.InitAll(false)) {
|
||||
::printf("Failed to initialize '%s' subsystem: %s\n", slist.GetFailName(),
|
||||
slist.GetFailMsg());
|
||||
return 1;
|
||||
}
|
||||
VirtualMemory::Init();
|
||||
InitializeThreads();
|
||||
|
||||
RunOptions options;
|
||||
bool show_help = false;
|
||||
|
||||
if (argc < 2) {
|
||||
PrintUsage();
|
||||
slist.DestroyAll(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!ParseArgs(argc, argv, options, show_help)) {
|
||||
PrintUsage();
|
||||
slist.DestroyAll(false);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (show_help) {
|
||||
PrintUsage();
|
||||
slist.DestroyAll(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Run(options);
|
||||
|
||||
slist.DestroyAll(false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -870,8 +870,8 @@ void TestMaterializationSharesReadConstEvaluation() {
|
||||
for (uint32_t i = 0; i < memory.words.size(); i++) {
|
||||
memory.words[i] = 0x100 + i;
|
||||
}
|
||||
memory.words[1] |= Prospero::GpuEnumValue(Prospero::BufferFormat::k8UNorm) << 20u;
|
||||
memory.words[3] |= Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) << 28u;
|
||||
memory.words[1] |= static_cast<uint32_t>(Prospero::BufferFormat::k8UNorm) << 20u;
|
||||
memory.words[3] |= static_cast<uint32_t>(Prospero::ImageType::kColor2D) << 28u;
|
||||
std::array<uint32_t, 32> user_data {};
|
||||
user_data[16] = static_cast<uint32_t>(memory.base);
|
||||
user_data[17] = static_cast<uint32_t>(memory.base >> 32u);
|
||||
@@ -911,7 +911,7 @@ void TestInvalidImagesMaterializeAsNull() {
|
||||
std::string error;
|
||||
for (uint32_t type = 0; type < 8; type++) {
|
||||
auto descriptor = stale;
|
||||
descriptor[1] |= Prospero::GpuEnumValue(Prospero::BufferFormat::k8UNorm) << 20u;
|
||||
descriptor[1] |= static_cast<uint32_t>(Prospero::BufferFormat::k8UNorm) << 20u;
|
||||
descriptor[3] = (descriptor[3] & 0x0fffffffu) | (type << 28u);
|
||||
ResourceSnapshot snapshot;
|
||||
Check(MaterializeResources(sampled, {descriptor}, snapshot, &error) &&
|
||||
@@ -951,7 +951,7 @@ void TestInvalidImagesMaterializeAsNull() {
|
||||
std::array<uint32_t, 8> msaa {};
|
||||
msaa[0] = 1;
|
||||
msaa[1] = 36u << 20u;
|
||||
msaa[3] = (Prospero::GpuEnumValue(type) << 28u) | (test.base_level << 12u) |
|
||||
msaa[3] = (static_cast<uint32_t>(type) << 28u) | (test.base_level << 12u) |
|
||||
(test.fragments << 16u);
|
||||
msaa[5] = test.max_mip << 4u;
|
||||
ResourceSnapshot msaa_snapshot;
|
||||
@@ -970,7 +970,7 @@ void TestInvalidImagesMaterializeAsNull() {
|
||||
|
||||
std::array<uint32_t, 8> invalid_format {};
|
||||
invalid_format[0] = 1;
|
||||
invalid_format[3] = Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) << 28u;
|
||||
invalid_format[3] = static_cast<uint32_t>(Prospero::ImageType::kColor2D) << 28u;
|
||||
ResourceSnapshot invalid_format_snapshot;
|
||||
Check(MaterializeResources(sampled, {invalid_format}, invalid_format_snapshot, &error) &&
|
||||
std::all_of(invalid_format_snapshot.images[0].dwords.begin(),
|
||||
@@ -979,9 +979,9 @@ void TestInvalidImagesMaterializeAsNull() {
|
||||
"invalid-format image descriptor was not normalized to null");
|
||||
|
||||
auto valid = stale;
|
||||
valid[1] |= Prospero::GpuEnumValue(Prospero::BufferFormat::k8UNorm) << 20u;
|
||||
valid[1] |= static_cast<uint32_t>(Prospero::BufferFormat::k8UNorm) << 20u;
|
||||
valid[3] =
|
||||
(valid[3] & 0x0fffffffu) | (Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) << 28u);
|
||||
(valid[3] & 0x0fffffffu) | (static_cast<uint32_t>(Prospero::ImageType::kColor2D) << 28u);
|
||||
ResourceSnapshot valid_snapshot;
|
||||
Check(MaterializeResources(sampled, {valid}, valid_snapshot, &error) &&
|
||||
std::equal(valid.begin(), valid.end(), valid_snapshot.images[0].dwords.begin()),
|
||||
@@ -1099,7 +1099,7 @@ void TestResourceSpecializationIsTypedAndTransactional() {
|
||||
array_snapshot.images.resize(1);
|
||||
array_snapshot.images[0].dword_count = 8;
|
||||
array_snapshot.images[0].dwords[0] = 0x1000;
|
||||
array_snapshot.images[0].dwords[3] = Prospero::GpuEnumValue(Prospero::ImageType::kColor1DArray)
|
||||
array_snapshot.images[0].dwords[3] = static_cast<uint32_t>(Prospero::ImageType::kColor1DArray)
|
||||
<< 28u;
|
||||
Check(SpecializeResources(array_view, array_snapshot, &error) &&
|
||||
array_view.info.images[0].dimension == Decoder::ImageDimension::Dim1D &&
|
||||
@@ -1132,7 +1132,7 @@ void TestResourceSpecializationIsTypedAndTransactional() {
|
||||
Prepare(cross_family_2d_array);
|
||||
auto array_2d_snapshot = array_snapshot;
|
||||
array_2d_snapshot.images[0].dwords[3] =
|
||||
Prospero::GpuEnumValue(Prospero::ImageType::kColor2DArray) << 28u;
|
||||
static_cast<uint32_t>(Prospero::ImageType::kColor2DArray) << 28u;
|
||||
Check(SpecializeResources(cross_family_2d_array, array_2d_snapshot, &error) &&
|
||||
cross_family_2d_array.info.images[0].dimension == Decoder::ImageDimension::Dim2DArray,
|
||||
"array MIMG intent did not produce a 2D-array view");
|
||||
@@ -1144,7 +1144,7 @@ void TestResourceSpecializationIsTypedAndTransactional() {
|
||||
Decoder::ImageDimension::Dim2DArray)};
|
||||
Prepare(cube_view);
|
||||
auto cube_snapshot = array_2d_snapshot;
|
||||
cube_snapshot.images[0].dwords[3] = Prospero::GpuEnumValue(Prospero::ImageType::kCube) << 28u;
|
||||
cube_snapshot.images[0].dwords[3] = static_cast<uint32_t>(Prospero::ImageType::kCube) << 28u;
|
||||
Check(SpecializeResources(cube_view, cube_snapshot, &error) &&
|
||||
ValidateResourceSpecialization(cube_view, cube_snapshot, &error) &&
|
||||
cube_view.info.images[0].cube &&
|
||||
@@ -1152,7 +1152,7 @@ void TestResourceSpecializationIsTypedAndTransactional() {
|
||||
"cube descriptor identity did not reach the specialized image and IR");
|
||||
auto array_after_cube = cube_snapshot;
|
||||
array_after_cube.images[0].dwords[3] =
|
||||
Prospero::GpuEnumValue(Prospero::ImageType::kColor2DArray) << 28u;
|
||||
static_cast<uint32_t>(Prospero::ImageType::kColor2DArray) << 28u;
|
||||
Check(!ValidateResourceSpecialization(cube_view, array_after_cube, &error),
|
||||
"2D-array descriptor reused a cube-coordinate specialization");
|
||||
auto null_after_cube = cube_snapshot;
|
||||
@@ -1185,9 +1185,9 @@ void TestResourceSpecializationIsTypedAndTransactional() {
|
||||
|
||||
snapshot.images[0].dword_count = 8;
|
||||
snapshot.images[0].dwords[0] = 0x1000;
|
||||
snapshot.images[0].dwords[1] = Prospero::GpuEnumValue(Prospero::BufferFormat::k32UInt) << 20u;
|
||||
snapshot.images[0].dwords[1] = static_cast<uint32_t>(Prospero::BufferFormat::k32UInt) << 20u;
|
||||
snapshot.images[0].dwords[3] =
|
||||
(Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) << 28u) | 0x3acu;
|
||||
(static_cast<uint32_t>(Prospero::ImageType::kColor2D) << 28u) | 0x3acu;
|
||||
Check(SpecializeResources(program, snapshot, &error), error.c_str());
|
||||
const auto& image = program.info.images[0];
|
||||
const auto& inst = program.blocks[0].instructions[0];
|
||||
@@ -1235,7 +1235,7 @@ void TestRuntimeSpecializationCoversBakedBufferAndAddressFields() {
|
||||
buffer_snapshot.buffers[0].dword_count = 4;
|
||||
buffer_snapshot.buffers[0].dwords[1] = (16u << 16u) | (1u << 31u);
|
||||
buffer_snapshot.buffers[0].dwords[3] =
|
||||
(Prospero::GpuEnumValue(Prospero::BufferFormat::k32UInt) << 12u) | (2u << 21u) |
|
||||
(static_cast<uint32_t>(Prospero::BufferFormat::k32UInt) << 12u) | (2u << 21u) |
|
||||
(1u << 23u);
|
||||
std::string error;
|
||||
Check(SpecializeResources(buffer_program, buffer_snapshot, &error) &&
|
||||
@@ -1244,7 +1244,7 @@ void TestRuntimeSpecializationCoversBakedBufferAndAddressFields() {
|
||||
Check(buffer_program.info.buffers[0].packed_stride ==
|
||||
(16u | (1u << 14u) | (2u << 16u) | (1u << 20u)) &&
|
||||
buffer_program.info.buffers[0].descriptor_format ==
|
||||
Prospero::GpuEnumValue(Prospero::BufferFormat::k32UInt),
|
||||
Prospero::BufferFormat::k32UInt,
|
||||
"buffer specialization omitted SPIR-V-baked descriptor fields");
|
||||
auto stale_buffer = buffer_snapshot;
|
||||
stale_buffer.buffers[0].dwords[1] ^= 4u << 16u;
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,4 +1,3 @@
|
||||
#include "common/commonSubsystem.h"
|
||||
#include "common/emulatorConfig.h"
|
||||
#include "common/file.h"
|
||||
#include "common/logging/log.h"
|
||||
@@ -97,28 +96,16 @@ void InitSubsystems() {
|
||||
return;
|
||||
}
|
||||
|
||||
static char arg0[] = "virtual_memory_allocation_tests";
|
||||
static char* argv[] = {arg0};
|
||||
|
||||
auto* slist = Common::SubsystemsList::Instance();
|
||||
auto* core = Common::CommonSubsystem::Instance();
|
||||
auto* config = Config::ConfigSubsystem::Instance();
|
||||
auto* log = Log::LogSubsystem::Instance();
|
||||
auto* memory = Libs::LibKernel::Memory::MemorySubsystem::Instance();
|
||||
auto* thread = Common::ThreadsSubsystem::Instance();
|
||||
|
||||
slist->SetArgs(1, argv);
|
||||
slist->Add(thread, {});
|
||||
slist->Add(core, {});
|
||||
slist->Add(config, {core});
|
||||
Check("InitSubsystems", slist->InitAll(false), "failed to initialize base subsystems");
|
||||
static Common::Subsystems subsystems;
|
||||
Common::VirtualMemory::Init();
|
||||
Common::InitializeThreads();
|
||||
subsystems.Initialize<Config::Lifecycle>();
|
||||
|
||||
Config::ConfigOptions options;
|
||||
options.printf_direction = Config::OutputDirection::Silent;
|
||||
Config::Load(options);
|
||||
|
||||
slist->Add(log, {core, config});
|
||||
Check("InitSubsystems", slist->InitAll(false), "failed to initialize logging subsystem");
|
||||
subsystems.Initialize<Log::Lifecycle>();
|
||||
|
||||
const auto param_json = std::filesystem::temp_directory_path() /
|
||||
("kyty_virtual_memory_" +
|
||||
@@ -140,8 +127,7 @@ void InitSubsystems() {
|
||||
"failed to read flexible memory size from param.json");
|
||||
Libs::LibKernel::Memory::SetFlexibleMemorySize(flexible_memory_size);
|
||||
|
||||
slist->Add(memory, {core, log, thread});
|
||||
Check("InitSubsystems", slist->InitAll(false), "failed to initialize memory subsystem");
|
||||
subsystems.Initialize<Libs::LibKernel::Memory::Lifecycle>();
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
+150
-22
@@ -1,6 +1,7 @@
|
||||
#include "common/emulatorConfig.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/subsystems.h"
|
||||
#include "common/threads.h"
|
||||
#include "graphics/guest_gpu/hardwareContext.h"
|
||||
#include "graphics/guest_gpu/pm4.h"
|
||||
@@ -344,12 +345,13 @@ void SetIdentityInterpolatorSettings(ShaderPixelInputInfo* input_info) {
|
||||
void EnsureConfigInitialized() {
|
||||
static bool config_initialized = false;
|
||||
if (!config_initialized) {
|
||||
Common::ThreadsSubsystem::Instance()->Init(nullptr);
|
||||
Config::ConfigSubsystem::Instance()->Init(nullptr);
|
||||
static Common::Subsystems subsystems;
|
||||
Common::InitializeThreads();
|
||||
subsystems.Initialize<Config::Lifecycle>();
|
||||
Config::ConfigOptions options;
|
||||
options.printf_direction = Config::OutputDirection::Silent;
|
||||
Config::Load(options);
|
||||
Log::LogSubsystem::Instance()->Init(nullptr);
|
||||
subsystems.Initialize<Log::Lifecycle>();
|
||||
ShaderInit();
|
||||
config_initialized = true;
|
||||
}
|
||||
@@ -463,14 +465,14 @@ void TestNormalizedImageContracts() {
|
||||
ImageInfo container {};
|
||||
container.data = {0x10000, 0x15000};
|
||||
container.pixel_format = vk::Format::eR8G8B8A8Unorm;
|
||||
container.guest_format = Prospero::GpuEnumValue(Prospero::BufferFormat::k8_8_8_8UNorm);
|
||||
container.guest_format = Prospero::BufferFormat::k8_8_8_8UNorm;
|
||||
container.type = Prospero::ImageType::kColor2D;
|
||||
container.extent = {64, 64, 1};
|
||||
container.resources = {3, 4};
|
||||
container.pitch = 64;
|
||||
container.bytes_per_block = 4;
|
||||
container.samples = 1;
|
||||
container.tile_mode = Prospero::GpuEnumValue(Prospero::TileMode::kStandard64KB);
|
||||
container.tile_mode = Prospero::TileMode::kStandard64KB;
|
||||
container.mip_layout[0] = {0, 0x10000, 64, 64};
|
||||
container.mip_layout[1] = {0x10000, 0x4000, 32, 32};
|
||||
container.mip_layout[2] = {0x14000, 0x1000, 16, 16};
|
||||
@@ -495,7 +497,7 @@ void TestNormalizedImageContracts() {
|
||||
"sample-count mismatch was accepted as a compatible image");
|
||||
|
||||
auto compressed = container;
|
||||
compressed.guest_format = Prospero::GpuEnumValue(Prospero::BufferFormat::kBc3UNorm);
|
||||
compressed.guest_format = Prospero::BufferFormat::kBc3UNorm;
|
||||
compressed.pitch = 128;
|
||||
compressed.extent.height = 64;
|
||||
Check(compressed.BlockExtent() == vk::Extent2D {32, 16},
|
||||
@@ -623,9 +625,9 @@ ImageTestUserData(Prospero::ImageType type = Prospero::ImageType::kColor2D) {
|
||||
std::array<uint32_t, 64> data {};
|
||||
for (uint32_t start = 0; start + 3u < data.size(); start += 4u) {
|
||||
data[start] = 0x1000u + start * 0x100u;
|
||||
data[start + 1u] = Prospero::GpuEnumValue(Prospero::BufferFormat::k8UNorm) << 20u;
|
||||
data[start + 1u] = static_cast<uint32_t>(Prospero::BufferFormat::k8UNorm) << 20u;
|
||||
data[start + 2u] = UINT32_MAX;
|
||||
data[start + 3u] = Prospero::GpuEnumValue(type) << 28u;
|
||||
data[start + 3u] = static_cast<uint32_t>(type) << 28u;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
@@ -633,14 +635,14 @@ ImageTestUserData(Prospero::ImageType type = Prospero::ImageType::kColor2D) {
|
||||
void SetImageTestType(std::array<uint32_t, 64>* data, uint32_t srsrc, Prospero::ImageType type) {
|
||||
const auto type_dword = srsrc * 4u + 3u;
|
||||
Check(data != nullptr && type_dword < data->size(), "invalid image test descriptor source");
|
||||
(*data)[type_dword] = Prospero::GpuEnumValue(type) << 28u;
|
||||
(*data)[type_dword] = static_cast<uint32_t>(type) << 28u;
|
||||
}
|
||||
|
||||
void SetImageTestFormat(std::array<uint32_t, 64>* data, uint32_t srsrc,
|
||||
Prospero::BufferFormat format) {
|
||||
const auto format_dword = srsrc * 4u + 1u;
|
||||
Check(data != nullptr && format_dword < data->size(), "invalid image test descriptor source");
|
||||
(*data)[format_dword] = Prospero::GpuEnumValue(format) << 20u;
|
||||
(*data)[format_dword] = static_cast<uint32_t>(format) << 20u;
|
||||
}
|
||||
|
||||
bool ReadZeroTestMemory(void*, uint64_t, uint32_t* value) {
|
||||
@@ -4518,7 +4520,7 @@ void TestNewShaderRecompilerFormattedStoreUsesRuntimeArrayLengthOnly() {
|
||||
std::array<uint32_t, 64> user_data {};
|
||||
user_data[1] = 4u << 16u;
|
||||
user_data[2] = 5u;
|
||||
user_data[3] = Prospero::GpuEnumValue(Prospero::BufferFormat::k32UInt) << 12u;
|
||||
user_data[3] = static_cast<uint32_t>(Prospero::BufferFormat::k32UInt) << 12u;
|
||||
|
||||
ShaderRecompiler::CompileOptions options;
|
||||
options.stage = ShaderType::Compute;
|
||||
@@ -6484,11 +6486,11 @@ void TestNewShaderRecompilerExpPixelOutputs() {
|
||||
CheckSpirvBinaryValidates(uint16_result.spirv);
|
||||
}
|
||||
|
||||
void TestRenderTargetReverseFloat16ExportMapping() {
|
||||
void TestRenderTargetReverseExportMapping() {
|
||||
const auto format =
|
||||
TextureGetRenderTargetFormat(Prospero::GpuEnumValue(Prospero::ChannelLayout::k16_16_16_16),
|
||||
Prospero::GpuEnumValue(Prospero::ChannelType::kFloat),
|
||||
Prospero::GpuEnumValue(Prospero::ChannelOrder::kReversed));
|
||||
TextureGetRenderTargetFormat(Prospero::ChannelLayout::k16_16_16_16,
|
||||
Prospero::ChannelType::kFloat,
|
||||
Prospero::ChannelOrder::kReversed);
|
||||
Check(format.format == vk::Format::eR16G16B16A16Sfloat && format.bytes_per_element == 8u,
|
||||
"reverse RGBA16F render target did not retain its native host format "
|
||||
"and size");
|
||||
@@ -6501,11 +6503,121 @@ void TestRenderTargetReverseFloat16ExportMapping() {
|
||||
"reverse RGBA16F render-target export or write-mask mapping is "
|
||||
"incorrect");
|
||||
const auto legacy_alt =
|
||||
TextureGetRenderTargetFormat(Prospero::GpuEnumValue(Prospero::ChannelLayout::k8_8_8_8),
|
||||
Prospero::GpuEnumValue(Prospero::ChannelType::kUNorm),
|
||||
Prospero::GpuEnumValue(Prospero::ChannelOrder::kAlt));
|
||||
TextureGetRenderTargetFormat(Prospero::ChannelLayout::k8_8_8_8,
|
||||
Prospero::ChannelType::kUNorm,
|
||||
Prospero::ChannelOrder::kAlt);
|
||||
Check(legacy_alt.format == vk::Format::eB8G8R8A8Unorm && legacy_alt.export_mapping.IsIdentity(),
|
||||
"legacy BGRA render target acquired a duplicate shader export mapping");
|
||||
const auto gr32 =
|
||||
TextureGetRenderTargetFormat(Prospero::ChannelLayout::k32_32,
|
||||
Prospero::ChannelType::kFloat,
|
||||
Prospero::ChannelOrder::kReversed);
|
||||
Check(gr32.format == vk::Format::eR32G32Sfloat && gr32.bytes_per_element == 8u &&
|
||||
gr32.export_mapping == Prospero::ColorMappingGr,
|
||||
"reverse GR32F render target did not retain its native host format, "
|
||||
"size, and mapping");
|
||||
|
||||
struct MappingCase {
|
||||
Prospero::ChannelLayout layout;
|
||||
Prospero::ChannelType type;
|
||||
vk::Format format;
|
||||
uint32_t bytes;
|
||||
std::array<Prospero::ColorComponentMapping, 4> mappings;
|
||||
};
|
||||
const MappingCase mapping_cases[] = {
|
||||
{Prospero::ChannelLayout::k8,
|
||||
Prospero::ChannelType::kUInt,
|
||||
vk::Format::eR8Uint,
|
||||
1,
|
||||
{Prospero::ColorMappingRgba, Prospero::ColorMappingGr, Prospero::ColorMappingBgra,
|
||||
Prospero::ColorMappingAgba}},
|
||||
{Prospero::ChannelLayout::k32_32,
|
||||
Prospero::ChannelType::kFloat,
|
||||
vk::Format::eR32G32Sfloat,
|
||||
8,
|
||||
{Prospero::ColorMappingRgba, Prospero::ColorMappingRabg, Prospero::ColorMappingGr,
|
||||
Prospero::ColorMappingArbg}},
|
||||
{Prospero::ChannelLayout::k5_6_5,
|
||||
Prospero::ChannelType::kUNorm,
|
||||
vk::Format::eB5G6R5UnormPack16,
|
||||
2,
|
||||
{Prospero::ColorMappingRgba, Prospero::ColorMappingRgab, Prospero::ColorMappingBgra,
|
||||
Prospero::ColorMappingAgbr}},
|
||||
{Prospero::ChannelLayout::k16_16_16_16,
|
||||
Prospero::ChannelType::kFloat,
|
||||
vk::Format::eR16G16B16A16Sfloat,
|
||||
8,
|
||||
{Prospero::ColorMappingRgba, Prospero::ColorMappingBgra, Prospero::ColorMappingAbgr,
|
||||
Prospero::ColorMappingArgb}},
|
||||
};
|
||||
for (const auto& mapping_case: mapping_cases) {
|
||||
for (uint32_t order = 0; order < 4u; order++) {
|
||||
const auto info = TextureGetRenderTargetFormat(
|
||||
mapping_case.layout, mapping_case.type,
|
||||
static_cast<Prospero::ChannelOrder>(order));
|
||||
Check(info.format == mapping_case.format &&
|
||||
info.bytes_per_element == mapping_case.bytes &&
|
||||
info.export_mapping == mapping_case.mappings[order],
|
||||
"render-target channel order did not use the component-count "
|
||||
"mapping");
|
||||
for (uint32_t physical = 0; physical < 4u; physical++) {
|
||||
const auto logical = info.export_mapping.Map(physical);
|
||||
Check(info.export_mapping.ApplyMask(1u << logical) == (1u << physical),
|
||||
"logical color write mask was not mapped to the inverse physical "
|
||||
"component");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto alt_1010102 =
|
||||
TextureGetRenderTargetFormat(Prospero::ChannelLayout::k10_10_10_2,
|
||||
Prospero::ChannelType::kUNorm,
|
||||
Prospero::ChannelOrder::kAlt);
|
||||
Check(alt_1010102.format == vk::Format::eA2R10G10B10UnormPack32 &&
|
||||
alt_1010102.export_mapping.IsIdentity(),
|
||||
"native alternate 10:10:10:2 render target acquired a shader mapping");
|
||||
const auto reversed_4444 =
|
||||
TextureGetRenderTargetFormat(Prospero::ChannelLayout::k4_4_4_4,
|
||||
Prospero::ChannelType::kUNorm,
|
||||
Prospero::ChannelOrder::kReversed);
|
||||
Check(reversed_4444.format == vk::Format::eR4G4B4A4UnormPack16 &&
|
||||
reversed_4444.export_mapping.IsIdentity(),
|
||||
"reversed 4:4:4:4 render target did not compose storage and channel "
|
||||
"order");
|
||||
const auto standard_4444 =
|
||||
TextureGetRenderTargetFormat(Prospero::ChannelLayout::k4_4_4_4,
|
||||
Prospero::ChannelType::kUNorm,
|
||||
Prospero::ChannelOrder::kStandard);
|
||||
Check(standard_4444.format == vk::Format::eR4G4B4A4UnormPack16 &&
|
||||
standard_4444.export_mapping == Prospero::ColorMappingAbgr,
|
||||
"standard 4:4:4:4 render target did not compensate host packed-bit "
|
||||
"order");
|
||||
const auto standard_5551 =
|
||||
TextureGetRenderTargetFormat(Prospero::ChannelLayout::k5_5_5_1,
|
||||
Prospero::ChannelType::kUNorm,
|
||||
Prospero::ChannelOrder::kStandard);
|
||||
Check(standard_5551.format == vk::Format::eA1R5G5B5UnormPack16 &&
|
||||
standard_5551.export_mapping == Prospero::ColorMappingBgra,
|
||||
"5:5:5:1 render target did not preserve its high one-bit component");
|
||||
const auto standard_1555 =
|
||||
TextureGetRenderTargetFormat(Prospero::ChannelLayout::k1_5_5_5,
|
||||
Prospero::ChannelType::kUNorm,
|
||||
Prospero::ChannelOrder::kStandard);
|
||||
Check(standard_1555.format == vk::Format::eR5G5B5A1UnormPack16 &&
|
||||
standard_1555.export_mapping == Prospero::ColorMappingAbgr,
|
||||
"1:5:5:5 render target did not preserve its low one-bit component");
|
||||
|
||||
const auto argb =
|
||||
TextureGetRenderTargetFormat(Prospero::ChannelLayout::k16_16_16_16,
|
||||
Prospero::ChannelType::kFloat,
|
||||
Prospero::ChannelOrder::kAltReversed);
|
||||
Check(argb.export_mapping == Prospero::ColorMappingArgb &&
|
||||
argb.export_mapping.ApplyMask(0x1u) == 0x2u &&
|
||||
argb.export_mapping.ApplyMask(0x2u) == 0x4u &&
|
||||
argb.export_mapping.ApplyMask(0x4u) == 0x8u &&
|
||||
argb.export_mapping.ApplyMask(0x8u) == 0x1u,
|
||||
"alternate-reversed render-target mapping did not invert its "
|
||||
"non-involutive cycle");
|
||||
|
||||
const uint32_t shader[] = {
|
||||
EncodeExp0(0x00, 0xf),
|
||||
@@ -6532,6 +6644,21 @@ void TestRenderTargetReverseFloat16ExportMapping() {
|
||||
"reverse MRT export did not emit a WZYX component shuffle");
|
||||
CheckSpirvBinaryValidates(reversed_result.spirv);
|
||||
|
||||
reversed_info.target_export_mapping[0] = gr32.export_mapping;
|
||||
ShaderRecompiler::CompileResult gr32_result;
|
||||
Check(ShaderRecompiler::TryRecompile(shader, options, gr32_result, &error), error.c_str());
|
||||
Check(SpirvContainsVectorShuffle(gr32_result.spirv, {1u, 0u, 2u, 3u}),
|
||||
"reverse GR32F MRT export did not emit a YXZW component shuffle");
|
||||
CheckSpirvBinaryValidates(gr32_result.spirv);
|
||||
|
||||
reversed_info.target_export_mapping[0] = argb.export_mapping;
|
||||
ShaderRecompiler::CompileResult argb_result;
|
||||
Check(ShaderRecompiler::TryRecompile(shader, options, argb_result, &error), error.c_str());
|
||||
Check(SpirvContainsVectorShuffle(argb_result.spirv, {3u, 0u, 1u, 2u}),
|
||||
"alternate-reversed MRT export did not emit an ARGB component shuffle");
|
||||
CheckSpirvBinaryValidates(argb_result.spirv);
|
||||
reversed_info.target_export_mapping[0] = gr32.export_mapping;
|
||||
|
||||
HW::PixelShaderInfo regs {};
|
||||
Check(ShaderGetIdPS(regs, identity_info, false) != ShaderGetIdPS(regs, reversed_info, false),
|
||||
"pixel shader cache identity omitted the render-target export mapping");
|
||||
@@ -6545,17 +6672,18 @@ void TestRenderTargetReverseFloat16ExportMapping() {
|
||||
ShaderVertexInputInfo vs_info {};
|
||||
vs_info.stage.program = std::make_shared<ShaderRecompiler::IR::Program>();
|
||||
std::array<Prospero::ColorComponentMapping, 8> mappings {};
|
||||
mappings[0] = format.export_mapping;
|
||||
mappings[0] = gr32.export_mapping;
|
||||
ShaderPixelInputInfo compiled_info {};
|
||||
std::span<const uint32_t> compiled_spirv;
|
||||
Check(ShaderCompileInfoPS(regs, sh, ShaderLaneMaskMode::NativeWave, vs_info, mappings,
|
||||
compiled_info, compiled_spirv) &&
|
||||
compiled_info.target_export_mapping[0].IsIdentity(),
|
||||
"inactive reverse MRT mapping was not normalized out of the shader cache key");
|
||||
"inactive reverse MRT mapping was not normalized out of the shader "
|
||||
"cache key");
|
||||
sh.target_output_mode[0] = 4;
|
||||
Check(ShaderCompileInfoPS(regs, sh, ShaderLaneMaskMode::NativeWave, vs_info, mappings,
|
||||
compiled_info, compiled_spirv) &&
|
||||
compiled_info.target_export_mapping[0] == format.export_mapping,
|
||||
compiled_info.target_export_mapping[0] == gr32.export_mapping,
|
||||
"active reverse MRT mapping was lost before shader specialization");
|
||||
}
|
||||
|
||||
@@ -7625,7 +7753,7 @@ int main() {
|
||||
TestNewShaderRecompilerVertexExportUsesLaneExecMask();
|
||||
TestNewShaderRecompilerPerInvocationMasks();
|
||||
TestNewShaderRecompilerExpPixelOutputs();
|
||||
TestRenderTargetReverseFloat16ExportMapping();
|
||||
TestRenderTargetReverseExportMapping();
|
||||
TestNewShaderRecompilerEarlyZDisabledWhenPixelKillEnabled();
|
||||
TestScalarProvenanceRealWideMoveLowering();
|
||||
TestScalarProvenanceRealCarryAndScalarLoads();
|
||||
|
||||
Reference in new issue
Block a user