Initial commit

This commit is contained in:
InoriRus
2021-12-01 19:29:27 +10:00
parent b1e7dcdc5d
commit 43f49c8763
1843 changed files with 1111694 additions and 0 deletions
+23
View File
@@ -0,0 +1,23 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_COMMON_H_
#define EMULATOR_INCLUDE_EMULATOR_COMMON_H_
#include "Kyty/Core/Common.h"
#if (KYTY_COMPILER == KYTY_COMPILER_CLANG || KYTY_COMPILER == KYTY_COMPILER_MINGW) && KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS && KYTY_BITNESS == 64 && \
KYTY_ENDIAN == KYTY_ENDIAN_LITTLE && KYTY_ABI == KYTY_ABI_X86_64 && KYTY_PROJECT == KYTY_PROJECT_EMULATOR
#define KYTY_EMU_ENABLED
#endif
#ifdef KYTY_EMU_ENABLED
#include "Emulator/Log.h" // IWYU pragma: export
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define KYTY_MS_ABI __attribute__((ms_abi))
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define KYTY_SYSV_ABI __attribute__((sysv_abi))
#endif
#endif /* EMULATOR_INCLUDE_EMULATOR_COMMON_H_ */
+67
View File
@@ -0,0 +1,67 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_CONFIG_H_
#define EMULATOR_INCLUDE_EMULATOR_CONFIG_H_
#include "Kyty/Core/Common.h"
#include "Kyty/Core/String.h"
#include "Kyty/Core/Subsystems.h"
#include "Emulator/Common.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Scripts {
class ScriptVar;
} // namespace Kyty::Scripts
namespace Kyty::Config {
KYTY_SUBSYSTEM_DEFINE(Config);
enum class ShaderOptimizationType
{
None,
Size,
Performance
};
enum class ShaderLogDirection
{
Silent,
Console,
File
};
enum class ProfilerDirection
{
None,
File,
Network,
FileAndNetwork
};
void Load(const Scripts::ScriptVar& cfg);
uint32_t GetScreenWidth();
uint32_t GetScreenHeight();
bool IsNeo();
bool VulkanValidationEnabled();
bool ShaderValidationEnabled();
ShaderOptimizationType GetShaderOptimizationType();
ShaderLogDirection GetShaderLogDirection();
String GetShaderLogFolder();
bool CommandBufferDumpEnabled();
String GetCommandBufferDumpFolder();
Log::Direction GetPrintfDirection();
String GetPrintfOutputFile();
ProfilerDirection GetProfilerDirection();
String GetProfilerOutputFile();
} // namespace Kyty::Config
#endif
#endif /* EMULATOR_INCLUDE_EMULATOR_CONFIG_H_ */
@@ -0,0 +1,68 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_CONTROLLER_H_
#define EMULATOR_INCLUDE_EMULATOR_CONTROLLER_H_
#include "Kyty/Core/Common.h"
#include "Kyty/Core/Subsystems.h"
#include "Emulator/Common.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Libs::Controller {
KYTY_SUBSYSTEM_DEFINE(Controller);
constexpr uint32_t PAD_BUTTON_L3 = 0x00000002;
constexpr uint32_t PAD_BUTTON_R3 = 0x00000004;
constexpr uint32_t PAD_BUTTON_OPTIONS = 0x00000008;
constexpr uint32_t PAD_BUTTON_UP = 0x00000010;
constexpr uint32_t PAD_BUTTON_RIGHT = 0x00000020;
constexpr uint32_t PAD_BUTTON_DOWN = 0x00000040;
constexpr uint32_t PAD_BUTTON_LEFT = 0x00000080;
constexpr uint32_t PAD_BUTTON_L2 = 0x00000100;
constexpr uint32_t PAD_BUTTON_R2 = 0x00000200;
constexpr uint32_t PAD_BUTTON_L1 = 0x00000400;
constexpr uint32_t PAD_BUTTON_R1 = 0x00000800;
constexpr uint32_t PAD_BUTTON_TRIANGLE = 0x00001000;
constexpr uint32_t PAD_BUTTON_CIRCLE = 0x00002000;
constexpr uint32_t PAD_BUTTON_CROSS = 0x00004000;
constexpr uint32_t PAD_BUTTON_SQUARE = 0x00008000;
constexpr uint32_t PAD_BUTTON_TOUCH_PAD = 0x00100000;
enum class Axis
{
LeftX = 0,
LeftY = 1,
RightX = 2,
RightY = 3,
TriggerLeft = 4,
TriggerRight = 5,
AxisMax
};
struct PadControllerInformation;
struct PadData;
inline int controller_get_axis(int min, int max, int value)
{
int v = (255 * (value - min)) / (max - min);
return (v < 0 ? 0 : (v > 255 ? 255 : v));
}
void ControllerConnect(int id);
void ControllerDisconnect(int id);
void ControllerButton(int id, uint32_t button, bool down);
void ControllerAxis(int id, Axis axis, int value);
int KYTY_SYSV_ABI PadInit();
int KYTY_SYSV_ABI PadOpen(int user_id, int type, int index, const void* param);
int KYTY_SYSV_ABI PadSetMotionSensorState(int handle, bool enable);
int KYTY_SYSV_ABI PadGetControllerInformation(int handle, PadControllerInformation* info);
int KYTY_SYSV_ABI PadReadState(int handle, PadData* data);
} // namespace Kyty::Libs::Controller
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_CONTROLLER_H_ */
+285
View File
@@ -0,0 +1,285 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_ELF_H_
#define EMULATOR_INCLUDE_EMULATOR_ELF_H_
#include "Kyty/Core/Common.h"
#include "Kyty/Core/String.h"
#include "Kyty/Core/Vector.h"
#include "Emulator/Common.h"
namespace Kyty::Core {
class File;
} // namespace Kyty::Core
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Loader {
using Elf64_Addr = uint64_t; // Unsigned program address
using Elf64_Off = uint64_t; // Unsigned file offset
using Elf64_Half = uint16_t; // Unsigned medium integer
using Elf64_Word = uint32_t; // Unsigned integer
using Elf64_Sword = int32_t; // Signed integer
using Elf64_Xword = uint64_t; // Unsigned long integer
using Elf64_Sxword = int64_t; // Signed long integer
constexpr int EI_MAG0 = 0;
constexpr int EI_MAG1 = 1;
constexpr int EI_MAG2 = 2;
constexpr int EI_MAG3 = 3;
constexpr int EI_CLASS = 4;
constexpr int EI_DATA = 5;
constexpr int EI_VERSION = 6;
constexpr int EI_OSABI = 7;
constexpr int EI_ABIVERSION = 8;
constexpr int EI_PAD = 9;
constexpr int EI_NIDENT = 16;
constexpr char ELFCLASS64 = 2; // 64-bit objects
constexpr char ELFDATA2LSB = 1; // Object file data structures are little-endian
constexpr Elf64_Half EM_X86_64 = 62; /* AMD x86-64 architecture */
constexpr int EV_CURRENT = 1;
constexpr char ELFOSABI_FREEBSD = 9; // FreeBSD operating system
constexpr Elf64_Half ET_DYNEXEC = 0xfe10; // Executable file
constexpr Elf64_Half ET_DYNAMIC = 0xfe18; // Shared
//#define SHT_PROGBITS 1
constexpr Elf64_Word PT_LOAD = 1;
constexpr Elf64_Word PT_DYNAMIC = 2;
constexpr Elf64_Word PT_TLS = 7;
constexpr Elf64_Word PT_OS_DYNLIBDATA = 0x61000000;
constexpr Elf64_Word PT_OS_PROCPARAM = 0x61000001;
constexpr Elf64_Word PT_OS_RELRO = 0x61000010;
constexpr Elf64_Word PF_X = 0x1; // Execute
constexpr Elf64_Word PF_W = 0x2; // Write
constexpr Elf64_Word PF_R = 0x4; // Read
constexpr Elf64_Sxword DT_DEBUG = 0x00000015;
constexpr Elf64_Sxword DT_FINI = 0x0000000d;
constexpr Elf64_Sxword DT_FINI_ARRAY = 0x0000001a;
constexpr Elf64_Sxword DT_FINI_ARRAYSZ = 0x0000001c;
constexpr Elf64_Sxword DT_FLAGS = 0x0000001e;
constexpr Elf64_Sxword DT_INIT = 0x0000000c;
constexpr Elf64_Sxword DT_INIT_ARRAY = 0x00000019;
constexpr Elf64_Sxword DT_INIT_ARRAYSZ = 0x0000001b;
constexpr Elf64_Sxword DT_NEEDED = 0x00000001;
constexpr Elf64_Sxword DT_OS_EXPORT_LIB = 0x61000013;
constexpr Elf64_Sxword DT_OS_EXPORT_LIB_1 = 0x61000047;
constexpr Elf64_Sxword DT_OS_EXPORT_LIB_ATTR = 0x61000017;
constexpr Elf64_Sxword DT_OS_FINGERPRINT = 0x61000007;
constexpr Elf64_Sxword DT_OS_HASH = 0x61000025;
constexpr Elf64_Sxword DT_OS_HASHSZ = 0x6100003d;
constexpr Elf64_Sxword DT_OS_IMPORT_LIB = 0x61000015;
constexpr Elf64_Sxword DT_OS_IMPORT_LIB_1 = 0x61000049;
constexpr Elf64_Sxword DT_OS_IMPORT_LIB_ATTR = 0x61000019;
constexpr Elf64_Sxword DT_OS_JMPREL = 0x61000029;
constexpr Elf64_Sxword DT_OS_MODULE_ATTR = 0x61000011;
constexpr Elf64_Sxword DT_OS_MODULE_INFO = 0x6100000d;
constexpr Elf64_Sxword DT_OS_MODULE_INFO_1 = 0x61000043;
constexpr Elf64_Sxword DT_OS_NEEDED_MODULE = 0x6100000f;
constexpr Elf64_Sxword DT_OS_NEEDED_MODULE_1 = 0x61000045;
constexpr Elf64_Sxword DT_OS_ORIGINAL_FILENAME = 0x61000009;
constexpr Elf64_Sxword DT_OS_ORIGINAL_FILENAME_1 = 0x61000041;
constexpr Elf64_Sxword DT_OS_PLTGOT = 0x61000027;
constexpr Elf64_Sxword DT_OS_PLTREL = 0x6100002b;
constexpr Elf64_Sxword DT_OS_PLTRELSZ = 0x6100002d;
constexpr Elf64_Sxword DT_OS_RELA = 0x6100002f;
constexpr Elf64_Sxword DT_OS_RELAENT = 0x61000033;
constexpr Elf64_Sxword DT_OS_RELASZ = 0x61000031;
constexpr Elf64_Sxword DT_OS_STRSZ = 0x61000037;
constexpr Elf64_Sxword DT_OS_STRTAB = 0x61000035;
constexpr Elf64_Sxword DT_OS_SYMENT = 0x6100003b;
constexpr Elf64_Sxword DT_OS_SYMTAB = 0x61000039;
constexpr Elf64_Sxword DT_OS_SYMTABSZ = 0x6100003f;
constexpr Elf64_Sxword DT_PREINIT_ARRAY = 0x00000020;
constexpr Elf64_Sxword DT_PREINIT_ARRAYSZ = 0x00000021;
constexpr Elf64_Sxword DT_REL = 0x00000011;
constexpr Elf64_Sxword DT_RELA = 0x00000007;
constexpr Elf64_Sxword DT_SONAME = 0x0000000e;
constexpr Elf64_Sxword DT_TEXTREL = 0x00000016;
constexpr Elf64_Sxword DT_HASH = 0x00000004;
constexpr Elf64_Sxword DT_STRTAB = 0x00000005;
constexpr Elf64_Sxword DT_STRSZ = 0x0000000a;
constexpr Elf64_Sxword DT_SYMTAB = 0x00000006;
constexpr Elf64_Sxword DT_SYMENT = 0x0000000b;
constexpr Elf64_Sxword DT_PLTGOT = 0x00000003;
constexpr Elf64_Sxword DT_PLTREL = 0x00000014;
constexpr Elf64_Sxword DT_JMPREL = 0x00000017;
constexpr Elf64_Sxword DT_PLTRELSZ = 0x00000002;
constexpr Elf64_Sxword DT_RELASZ = 0x00000008;
constexpr Elf64_Sxword DT_RELAENT = 0x00000009;
constexpr Elf64_Sxword DT_RELACOUNT = 0x6ffffff9;
constexpr Elf64_Sxword DT_NULL = 0;
constexpr Elf64_Word R_X86_64_64 = 1;
constexpr Elf64_Word R_X86_64_GLOB_DAT = 6;
constexpr Elf64_Word R_X86_64_JUMP_SLOT = 7;
constexpr Elf64_Word R_X86_64_RELATIVE = 8;
constexpr Elf64_Word R_X86_64_DTPMOD64 = 16;
constexpr uint8_t STB_LOCAL = 0;
constexpr uint8_t STB_GLOBAL = 1;
constexpr uint8_t STB_WEAK = 2;
constexpr uint8_t STT_OBJECT = 1;
constexpr uint8_t STT_FUNC = 2;
#pragma pack(1)
struct Elf64_Ehdr // NOLINT(readability-identifier-naming)
{
unsigned char e_ident[EI_NIDENT]; /* ELF identification */
Elf64_Half e_type; /* Object file type */
Elf64_Half e_machine; /* Machine type */
Elf64_Word e_version; /* Object file version */
Elf64_Addr e_entry; /* Entry point address */
Elf64_Off e_phoff; /* Program header offset */
Elf64_Off e_shoff; /* Section header offset */
Elf64_Word e_flags; /* Processor-specific flags */
Elf64_Half e_ehsize; /* ELF header size */
Elf64_Half e_phentsize; /* Size of program header entry */
Elf64_Half e_phnum; /* Number of program header entries */
Elf64_Half e_shentsize; /* Size of section header entry */
Elf64_Half e_shnum; /* Number of section header entries */
Elf64_Half e_shstrndx; /* Section name string table index */
};
struct Elf64_Phdr // NOLINT(readability-identifier-naming)
{
Elf64_Word p_type; /* Type of segment */
Elf64_Word p_flags; /* Segment attributes */
Elf64_Off p_offset; /* Offset in file */
Elf64_Addr p_vaddr; /* Virtual address in memory */
Elf64_Addr p_paddr; /* Reserved */
Elf64_Xword p_filesz; /* Size of segment in file */
Elf64_Xword p_memsz; /* Size of segment in memory */
Elf64_Xword p_align; /* Alignment of segment */
};
struct Elf64_Shdr // NOLINT(readability-identifier-naming)
{
Elf64_Word sh_name; /* Section name */
Elf64_Word sh_type; /* Section type */
Elf64_Xword sh_flags; /* Section attributes */
Elf64_Addr sh_addr; /* Virtual address in memory */
Elf64_Off sh_offset; /* Offset in file */
Elf64_Xword sh_size; /* Size of section */
Elf64_Word sh_link; /* Link to other section */
Elf64_Word sh_info; /* Miscellaneous information */
Elf64_Xword sh_addralign; /* Address alignment boundary */
Elf64_Xword sh_entsize; /* Size of entries, if section has table */
};
struct Elf64_Dyn // NOLINT(readability-identifier-naming)
{
Elf64_Sxword d_tag;
union
{
Elf64_Xword d_val;
Elf64_Addr d_ptr;
} d_un;
};
struct Elf64_Sym // NOLINT(readability-identifier-naming)
{
[[nodiscard]] unsigned char GetBind() const { return st_info >> 4u; }
[[nodiscard]] unsigned char GetType() const { return st_info & 0xfu; }
Elf64_Word st_name;
unsigned char st_info;
unsigned char st_other;
Elf64_Half st_shndx;
Elf64_Addr st_value;
Elf64_Xword st_size;
};
// struct Elf64_Rel // NOLINT(readability-identifier-naming)
//{
// Elf64_Addr r_offset;
// Elf64_Xword r_info;
//};
struct Elf64_Rela // NOLINT(readability-identifier-naming)
{
[[nodiscard]] Elf64_Word GetSymbol() const { return static_cast<Elf64_Word>(r_info >> 32u); }
[[nodiscard]] Elf64_Word GetType() const { return static_cast<Elf64_Word>(r_info & 0xffffffff); }
Elf64_Addr r_offset;
Elf64_Xword r_info;
Elf64_Sxword r_addend;
};
struct tls_info_t // NOLINT(readability-identifier-naming)
{
uint64_t addr;
uint64_t filesz;
uint64_t memsz;
};
#pragma pack()
class Elf64
{
public:
Elf64() = default;
virtual ~Elf64();
void Open(const String& file_name);
void DbgDump(const String& folder);
const char* GetSectionName(int index) { return m_str_table + m_shdr[index].sh_name; }
[[nodiscard]] bool IsValid() const;
[[nodiscard]] bool IsShared() const;
[[nodiscard]] bool IsNextGen() const;
void LoadSegment(uint64_t vaddr, uint64_t file_offset, uint64_t size);
uint64_t GetEntry();
[[nodiscard]] const Elf64_Dyn* GetDynValue(Elf64_Sxword tag) const;
[[nodiscard]] Vector<const Elf64_Dyn*> GetDynList(Elf64_Sxword tag) const;
[[nodiscard]] bool HasDynValue(Elf64_Sxword tag) const { return GetDynValue(tag) != nullptr; }
KYTY_CLASS_NO_COPY(Elf64);
[[nodiscard]] const Elf64_Dyn* GetDynamic() const { return static_cast<Elf64_Dyn*>(m_dynamic); }
[[nodiscard]] const Elf64_Ehdr* GetEhdr() const { return m_ehdr; }
[[nodiscard]] const Elf64_Phdr* GetPhdr() const { return m_phdr; }
[[nodiscard]] const Elf64_Shdr* GetShdr() const { return m_shdr; }
[[nodiscard]] char* GetStrTable() const { return m_str_table; }
template <class T>
[[nodiscard]] T GetDynamicData(uint64_t offset) const
{
return (m_dynamic_data == nullptr ? nullptr : reinterpret_cast<T>(static_cast<uint8_t*>(m_dynamic_data) + offset));
}
private:
void Clear();
Core::File* m_f = nullptr;
Elf64_Ehdr* m_ehdr = nullptr;
Elf64_Phdr* m_phdr = nullptr;
Elf64_Shdr* m_shdr = nullptr;
void* m_dynamic = nullptr;
void* m_dynamic_data = nullptr;
char* m_str_table = nullptr;
// uint64_t m_base_vaddr = 0;
};
} // namespace Kyty::Loader
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_ELF_H_ */
@@ -0,0 +1,12 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_EMULATOR_H_
#define EMULATOR_INCLUDE_EMULATOR_EMULATOR_H_
#include "Kyty/Core/Subsystems.h"
namespace Kyty::Emulator {
KYTY_SUBSYSTEM_DEFINE(Emulator);
} // namespace Kyty::Emulator
#endif /* EMULATOR_INCLUDE_EMULATOR_EMULATOR_H_ */
@@ -0,0 +1,94 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_ASYNCJOB_H_
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_ASYNCJOB_H_
#include "Kyty/Core/Common.h"
#include "Kyty/Core/Threads.h"
#include "Emulator/Common.h"
#include "Emulator/Profiler.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Libs::Graphics {
class AsyncJob
{
public:
using func_t = std::function<void(void*)>;
explicit AsyncJob(const char* name): m_name(name) { m_thread = new Core::Thread(ThreadRun, this); }
virtual ~AsyncJob()
{
EXIT_IF(m_thread == nullptr);
Core::LockGuard lock(m_mutex);
m_need_exit = true;
m_cond_var1.Signal();
m_thread->Join();
delete m_thread;
}
KYTY_CLASS_NO_COPY(AsyncJob);
void Execute(func_t func, void* arg = nullptr)
{
Core::LockGuard lock(m_mutex);
while (m_func != nullptr)
{
m_cond_var2.Wait(&m_mutex);
}
m_func = std::move(func);
m_arg = arg;
m_cond_var1.Signal();
}
void Wait()
{
Core::LockGuard lock(m_mutex);
while (m_func != nullptr)
{
m_cond_var2.Wait(&m_mutex);
}
}
private:
Core::Mutex m_mutex;
Core::CondVar m_cond_var1;
Core::CondVar m_cond_var2;
Core::Thread* m_thread = nullptr;
const char* m_name = nullptr;
func_t m_func = nullptr;
void* m_arg = nullptr;
bool m_need_exit = false;
static void ThreadRun(void* data)
{
// printf("Start AsyncJob Thread: 0x%" PRIx64 "\n", static_cast<uint64_t>(GetCurrentThreadId()));
auto* aj = static_cast<AsyncJob*>(data);
if (aj->m_name != nullptr)
{
KYTY_PROFILER_THREAD(aj->m_name);
}
for (;;)
{
Core::LockGuard lock(aj->m_mutex);
while (aj->m_func == nullptr && !aj->m_need_exit)
{
aj->m_cond_var1.Wait(&aj->m_mutex);
}
if (aj->m_need_exit)
{
break;
}
aj->m_func(aj->m_arg);
aj->m_func = nullptr;
aj->m_cond_var2.Signal();
}
}
};
} // namespace Kyty::Libs::Graphics
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_ASYNCJOB_H_ */
@@ -0,0 +1,48 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_DEPTHSTENCILBUFFER_H_
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_DEPTHSTENCILBUFFER_H_
#include "Kyty/Core/Common.h"
#include "Emulator/Common.h"
#include "Emulator/Graphics/GpuMemory.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Libs::Graphics {
struct GraphicContext;
struct VulkanMemory;
class DepthStencilBufferObject: public GpuObject
{
public:
static constexpr int PARAM_FORMAT = 0;
static constexpr int PARAM_WIDTH = 1;
static constexpr int PARAM_HEIGHT = 2;
static constexpr int PARAM_HTILE = 3;
static constexpr int PARAM_NEO = 4;
DepthStencilBufferObject(uint64_t vk_format, uint32_t width, uint32_t height, bool htile, bool neo)
{
params[PARAM_FORMAT] = vk_format;
params[PARAM_WIDTH] = width;
params[PARAM_HEIGHT] = height;
params[PARAM_HTILE] = htile ? 1 : 0;
params[PARAM_NEO] = neo ? 1 : 0;
check_hash = false;
type = Graphics::GpuMemoryObjectType::DepthStencilBuffer;
}
void* Create(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, VulkanMemory* mem) const override;
bool Equal(const uint64_t* other) const override;
[[nodiscard]] write_back_func_t GetWriteBackFunc() const override { return nullptr; };
[[nodiscard]] delete_func_t GetDeleteFunc() const override;
[[nodiscard]] update_func_t GetUpdateFunc() const override;
};
} // namespace Kyty::Libs::Graphics
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_DEPTHSTENCILBUFFER_H_ */
@@ -0,0 +1,99 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GPUMEMORY_H_
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GPUMEMORY_H_
#include "Kyty/Core/Common.h"
#include "Emulator/Common.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Libs::Graphics {
struct GraphicContext;
struct VulkanMemory;
struct VulkanBuffer;
struct TextureVulkanImage;
struct VideoOutVulkanImage;
struct DepthStencilVulkanImage;
enum class GpuMemoryMode
{
NoAccess,
Read,
Write,
ReadWrite
};
enum class GpuMemoryObjectType
{
Invalid,
VideoOutBuffer,
DepthStencilBuffer,
Label,
IndexBuffer,
VertexBuffer,
StorageBuffer,
Texture
};
class GpuObject
{
public:
using write_back_func_t = void (*)(GraphicContext* ctx, void* obj, const uint64_t* vaddr, const uint64_t* size, int vaddr_num);
using delete_func_t = void (*)(GraphicContext* ctx, void* obj, VulkanMemory* mem);
using update_func_t = void (*)(GraphicContext* ctx, const uint64_t* params, void* obj, const uint64_t* vaddr, const uint64_t* size,
int vaddr_num);
static constexpr int PARAMS_MAX = 8;
GpuObject() = default;
virtual ~GpuObject() = default;
KYTY_CLASS_DEFAULT_COPY(GpuObject);
virtual void* Create(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, VulkanMemory* mem) const = 0;
virtual bool Equal(const uint64_t* other) const = 0;
[[nodiscard]] virtual write_back_func_t GetWriteBackFunc() const = 0;
[[nodiscard]] virtual delete_func_t GetDeleteFunc() const = 0;
[[nodiscard]] virtual update_func_t GetUpdateFunc() const = 0;
uint64_t params[PARAMS_MAX] = {};
bool check_hash = false;
bool read_only = false;
GpuMemoryObjectType type = GpuMemoryObjectType::Invalid;
};
void GpuMemoryInit();
void GpuMemorySetAllocatedRange(uint64_t vaddr, uint64_t size);
void GpuMemoryFree(GraphicContext* ctx, uint64_t vaddr, uint64_t size);
void* GpuMemoryGetObject(GraphicContext* ctx, uint64_t vaddr, uint64_t size, const GpuObject& info);
void* GpuMemoryGetObject(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, const GpuObject& info);
void GpuMemoryResetHash(GraphicContext* ctx, uint64_t vaddr, uint64_t size, GpuMemoryObjectType type);
void GpuMemoryDbgDump();
void GpuMemoryFlush();
void GpuMemoryFrameDone();
void GpuMemoryWriteBack(GraphicContext* ctx);
bool VulkanAllocate(GraphicContext* ctx, VulkanMemory* mem);
void VulkanFree(GraphicContext* ctx, VulkanMemory* mem);
void VulkanMapMemory(GraphicContext* ctx, VulkanMemory* mem, void** data);
void VulkanUnmapMemory(GraphicContext* ctx, VulkanMemory* mem);
void VulkanBindImageMemory(GraphicContext* ctx, TextureVulkanImage* image, VulkanMemory* mem);
void VulkanBindImageMemory(GraphicContext* ctx, VideoOutVulkanImage* image, VulkanMemory* mem);
void VulkanBindImageMemory(GraphicContext* ctx, DepthStencilVulkanImage* image, VulkanMemory* mem);
void VulkanBindBufferMemory(GraphicContext* ctx, VulkanBuffer* buffer, VulkanMemory* mem);
void GpuMemoryRegisterOwner(uint32_t* owner_handle, const char* name);
void GpuMemoryRegisterResource(uint32_t* resource_handle, uint32_t owner_handle, const void* memory, size_t size, const char* name,
uint32_t type, uint64_t user_data);
void GpuMemoryUnregisterAllResourcesForOwner(uint32_t owner_handle);
void GpuMemoryUnregisterOwnerAndResources(uint32_t owner_handle);
void GpuMemoryUnregisterResource(uint32_t resource_handle);
} // namespace Kyty::Libs::Graphics
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GPUMEMORY_H_ */
@@ -0,0 +1,106 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GRAPHICCONTEXT_H_
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GRAPHICCONTEXT_H_
#include "Kyty/Core/Common.h"
#include "Kyty/Core/Threads.h"
#include "Emulator/Common.h"
#include <vulkan/vulkan_core.h>
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Libs::Graphics {
struct VulkanSwapchain
{
VkSwapchainKHR swapchain = nullptr;
VkFormat swapchain_format = VK_FORMAT_UNDEFINED;
VkExtent2D swapchain_extent = {};
VkImage* swapchain_images = nullptr;
VkImageView* swapchain_image_views = nullptr;
uint32_t swapchain_images_count = 0;
VkSemaphore present_complete_semaphore = nullptr;
VkFence present_complete_fence = nullptr;
uint32_t current_index = 0;
};
struct VulkanCommandPool
{
Core::Mutex mutex;
VkCommandPool pool = nullptr;
VkCommandBuffer* buffers = nullptr;
VkFence* fences = nullptr;
VkSemaphore* semaphores = nullptr;
bool* busy = nullptr;
uint32_t buffers_count = 0;
};
struct GraphicContext
{
static constexpr int QUEUES_NUM = 11;
static constexpr int QUEUE_GFX = 8;
static constexpr int QUEUE_UTIL = 9;
static constexpr int QUEUE_PRESENT = 10;
static constexpr int QUEUE_COMPUTE_START = 0;
static constexpr int QUEUE_COMPUTE_NUM = 8;
uint32_t screen_width = 0;
uint32_t screen_height = 0;
VkInstance instance = nullptr;
VkDebugUtilsMessengerEXT debug_messenger = nullptr;
VkPhysicalDevice physical_device = nullptr;
VkDevice device = nullptr;
uint32_t queue_family_index = static_cast<uint32_t>(-1);
VkQueue queue[QUEUES_NUM] = {};
};
struct VulkanMemory
{
VkMemoryRequirements requirements = {};
VkMemoryPropertyFlags property = 0;
VkDeviceMemory memory = nullptr;
VkDeviceSize offset = 0;
uint32_t type = 0;
uint64_t unique_id = 0;
};
struct VideoOutVulkanImage
{
VkFormat format = VK_FORMAT_UNDEFINED;
VkExtent2D extent = {};
VkImage image = nullptr;
VkImageView image_view = nullptr;
Graphics::VulkanMemory memory;
};
struct DepthStencilVulkanImage
{
VkFormat format = VK_FORMAT_UNDEFINED;
VkExtent2D extent = {};
VkImage image = nullptr;
VkImageView image_view = nullptr;
Graphics::VulkanMemory memory;
};
struct TextureVulkanImage
{
VkFormat format = VK_FORMAT_UNDEFINED;
VkExtent2D extent = {};
VkImage image = nullptr;
VkImageView image_view = nullptr;
Graphics::VulkanMemory memory;
};
struct VulkanBuffer
{
VkBuffer buffer = nullptr;
VulkanMemory memory;
VkBufferUsageFlags usage = 0;
};
} // namespace Kyty::Libs::Graphics
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GRAPHICCONTEXT_H_ */
@@ -0,0 +1,60 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GRAPHICS_H_
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GRAPHICS_H_
#include "Kyty/Core/Common.h"
#include "Kyty/Core/Subsystems.h"
#include "Emulator/Common.h"
#include "Emulator/Kernel/EventQueue.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Libs::Graphics {
struct VsStageRegisters;
KYTY_SUBSYSTEM_DEFINE(Graphics);
int KYTY_SYSV_ABI GraphicsSetVsShader(uint32_t* cmd, uint64_t size, const VsStageRegisters* vs_regs, uint32_t shader_modifier);
int KYTY_SYSV_ABI GraphicsSetPsShader350(uint32_t* cmd, uint64_t size, const uint32_t* ps_regs);
int KYTY_SYSV_ABI GraphicsSetCsShaderWithModifier(uint32_t* cmd, uint64_t size, const uint32_t* cs_regs, uint32_t shader_modifier);
int KYTY_SYSV_ABI GraphicsSetEmbeddedVsShader(uint32_t* cmd, uint64_t size, uint32_t id, uint32_t shader_modifier);
int KYTY_SYSV_ABI GraphicsDrawIndex(uint32_t* cmd, uint64_t size, uint32_t index_count, const void* index_addr, uint32_t flags,
uint32_t type);
int KYTY_SYSV_ABI GraphicsDrawIndexAuto(uint32_t* cmd, uint64_t size, uint32_t index_count, uint32_t flags);
int KYTY_SYSV_ABI GraphicsSubmitCommandBuffers(uint32_t count, void* dcb_gpu_addrs[], const uint32_t* dcb_sizes_in_bytes,
void* ccb_gpu_addrs[], const uint32_t* ccb_sizes_in_bytes);
int KYTY_SYSV_ABI GraphicsSubmitAndFlipCommandBuffers(uint32_t count, void* dcb_gpu_addrs[], const uint32_t* dcb_sizes_in_bytes,
void* ccb_gpu_addrs[], const uint32_t* ccb_sizes_in_bytes, int handle, int index,
int flip_mode, int64_t flip_arg);
int KYTY_SYSV_ABI GraphicsSubmitDone();
void KYTY_SYSV_ABI GraphicsFlushMemory();
int KYTY_SYSV_ABI GraphicsAddEqEvent(LibKernel::EventQueue::KernelEqueue eq, int id, void* udata);
int KYTY_SYSV_ABI GraphicsDeleteEqEvent(LibKernel::EventQueue::KernelEqueue eq, int id);
uint32_t KYTY_SYSV_ABI GraphicsDrawInitDefaultHardwareState350(uint32_t* cmd, uint64_t size);
uint32_t KYTY_SYSV_ABI GraphicsDispatchInitDefaultHardwareState(uint32_t* cmd, uint64_t size);
int KYTY_SYSV_ABI GraphicsInsertWaitFlipDone(uint32_t* cmd, uint64_t size, uint32_t video_out_handle, uint32_t display_buffer_index);
int KYTY_SYSV_ABI GraphicsDispatchDirect(uint32_t* cmd, uint64_t size, uint32_t thread_group_x, uint32_t thread_group_y,
uint32_t thread_group_z, uint32_t mode);
uint32_t KYTY_SYSV_ABI GraphicsMapComputeQueue(uint32_t pipe_id, uint32_t queue_id, uint32_t* ring_addr, uint32_t ring_size_dw,
uint32_t* read_ptr_addr);
int KYTY_SYSV_ABI GraphicsComputeWaitOnAddress(uint32_t* cmd, uint64_t size, uint32_t* gpu_addr, uint32_t mask, uint32_t func,
uint32_t ref);
void KYTY_SYSV_ABI GraphicsDingDong(uint32_t ring_id, uint32_t offset_dw);
void KYTY_SYSV_ABI GraphicsUnmapComputeQueue(uint32_t id);
int KYTY_SYSV_ABI GraphicsInsertPushMarker(uint32_t* cmd, uint64_t size, const char* str);
int KYTY_SYSV_ABI GraphicsInsertPopMarker(uint32_t* cmd, uint64_t size);
uint64_t KYTY_SYSV_ABI GraphicsGetGpuCoreClockFrequency();
int KYTY_SYSV_ABI GraphicsRegisterOwner(uint32_t* owner_handle, const char* name);
int KYTY_SYSV_ABI GraphicsRegisterResource(uint32_t* resource_handle, uint32_t owner_handle, const void* memory, size_t size,
const char* name, uint32_t type, uint64_t user_data);
int KYTY_SYSV_ABI GraphicsUnregisterAllResourcesForOwner(uint32_t owner_handle);
int KYTY_SYSV_ABI GraphicsUnregisterOwnerAndResources(uint32_t owner_handle);
int KYTY_SYSV_ABI GraphicsUnregisterResource(uint32_t resource_handle);
} // namespace Kyty::Libs::Graphics
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GRAPHICS_H_ */
@@ -0,0 +1,92 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GRAPHICSRENDER_H_
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GRAPHICSRENDER_H_
#include "Kyty/Core/Common.h"
#include "Emulator/Common.h"
#include "Emulator/Kernel/EventQueue.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Libs::Graphics {
class HardwareContext;
class UserConfig;
struct VideoOutVulkanImage;
struct DepthStencilVulkanImage;
struct TextureVulkanImage;
struct VulkanCommandPool;
struct VulkanBuffer;
struct VulkanFramebuffer;
struct RenderDepthInfo;
struct RenderColorInfo;
class CommandBuffer
{
public:
CommandBuffer() { Allocate(); }
virtual ~CommandBuffer() { Free(); }
KYTY_CLASS_NO_COPY(CommandBuffer);
[[nodiscard]] bool IsInvalid() const;
void Allocate();
void Free();
void Begin() const;
void End() const;
void Execute();
void ExecuteWithSemaphore();
VulkanFramebuffer* BeginRenderPass(RenderColorInfo* color, RenderDepthInfo* depth) const;
void EndRenderPass() const;
void WaitForFence();
void WaitForFenceAndReset();
[[nodiscard]] uint32_t GetIndex() const { return m_index; }
VulkanCommandPool* GetPool() { return m_pool; }
[[nodiscard]] bool IsExecute() const { return m_execute; }
void SetQueue(int queue) { m_queue = queue; }
private:
VulkanCommandPool* m_pool = nullptr;
uint32_t m_index = static_cast<uint32_t>(-1);
int m_queue = -1;
bool m_execute = false;
};
void GraphicsRenderInit();
void GraphicsRenderCreateContext();
void GraphicsRenderDrawIndex(CommandBuffer* buffer, HardwareContext* ctx, UserConfig* ucfg, uint32_t index_type_and_size,
uint32_t index_count, const void* index_addr, uint32_t flags, uint32_t type);
void GraphicsRenderDrawIndexAuto(CommandBuffer* buffer, HardwareContext* ctx, UserConfig* ucfg, uint32_t index_count, uint32_t flags);
void GraphicsRenderWriteAtEndOfPipe(CommandBuffer* buffer, uint64_t* dst_gpu_addr, uint64_t value);
void GraphicsRenderWriteAtEndOfPipeClockCounter(CommandBuffer* buffer, uint64_t* dst_gpu_addr);
void GraphicsRenderWriteAtEndOfPipe(CommandBuffer* buffer, uint32_t* dst_gpu_addr, uint32_t value);
void GraphicsRenderWriteAtEndOfPipeGds(CommandBuffer* buffer, uint32_t* dst_gpu_addr, uint32_t dw_offset, uint32_t dw_num);
void GraphicsRenderWriteAtEndOfPipeWithInterruptWriteBackFlip(CommandBuffer* buffer, uint32_t* dst_gpu_addr, uint32_t value, int handle,
int index, int flip_mode, int64_t flip_arg);
void GraphicsRenderWriteAtEndOfPipeWithWriteBack(CommandBuffer* buffer, uint64_t* dst_gpu_addr, uint64_t value);
void GraphicsRenderWriteAtEndOfPipeWithInterrupt(CommandBuffer* buffer, uint64_t* dst_gpu_addr, uint64_t value);
void GraphicsRenderWriteBack();
void GraphicsRenderDispatchDirect(CommandBuffer* buffer, HardwareContext* ctx, uint32_t thread_group_x, uint32_t thread_group_y,
uint32_t thread_group_z, uint32_t mode);
void GraphicsRenderMemoryBarrier(CommandBuffer* buffer);
void DeleteFramebuffer(VideoOutVulkanImage* image);
void DeleteFramebuffer(DepthStencilVulkanImage* image);
void DeleteDescriptor(VulkanBuffer* buffer);
void DeleteDescriptor(TextureVulkanImage* image);
int GraphicsRenderAddEqEvent(LibKernel::EventQueue::KernelEqueue eq, int id, void* udata);
int GraphicsRenderDeleteEqEvent(LibKernel::EventQueue::KernelEqueue eq, int id);
void GraphicsRenderClearGds(uint64_t dw_offset, uint32_t dw_num, uint32_t clear_value);
void GraphicsRenderReadGds(uint32_t* dst, uint32_t dw_offset, uint32_t dw_size);
} // namespace Kyty::Libs::Graphics
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GRAPHICSRENDER_H_ */
@@ -0,0 +1,29 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GRAPHICSRUN_H_
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GRAPHICSRUN_H_
#include "Kyty/Core/Common.h"
#include "Emulator/Common.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Libs::Graphics {
void GraphicsRunInit();
void GraphicsRunSubmit(uint32_t* cmd_draw_buffer, uint32_t num_draw_dw, uint32_t* cmd_const_buffer, uint32_t num_const_dw);
void GraphicsRunSubmitAndFlip(uint32_t* cmd_draw_buffer, uint32_t num_draw_dw, uint32_t* cmd_const_buffer, uint32_t num_const_dw,
int handle, int index, int flip_mode, int64_t flip_arg);
uint32_t GraphicsRunMapComputeQueue(uint32_t pipe_id, uint32_t queue_id, uint32_t* ring_addr, uint32_t ring_size_dw,
uint32_t* read_ptr_addr);
void GraphicsRunUnmapComputeQueue(uint32_t id);
void GraphicsRunWait();
void GraphicsRunDone();
void GraphicsRunDingDong(uint32_t ring_id, uint32_t offset_dw);
int GraphicsRunGetFrameNum();
} // namespace Kyty::Libs::Graphics
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GRAPHICSRUN_H_ */
@@ -0,0 +1,511 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_HARDWARECONTEXT_H_
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_HARDWARECONTEXT_H_
#include "Kyty/Core/Common.h"
#include "Emulator/Common.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Libs::Graphics {
struct RenderTarget
{
uint64_t base_addr = 0;
uint32_t pitch_div8_minus1 = 0;
uint32_t fmask_pitch_div8_minus1 = 0;
uint32_t slice_div64_minus1 = 0;
uint32_t base_array_slice_index = 0;
uint32_t last_array_slice_index = 0;
bool fmask_compression_enable = false;
uint32_t fmask_compression_mode = 0;
bool cmask_fast_clear_enable = false;
bool dcc_compression_enable = false;
bool neo_mode = false;
uint32_t cmask_tile_mode = 0;
uint32_t cmask_tile_mode_neo = 0;
uint32_t format = 0;
uint32_t channel_type = 0;
uint32_t channel_order = 0;
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;
uint32_t dcc_max_uncompressed_block_size = 0;
uint32_t dcc_max_compressed_block_size = 0;
uint32_t dcc_min_compressed_block_size = 0;
uint32_t dcc_color_transform = 0;
bool dcc_enable_overwrite_combiner = false;
bool dcc_force_independent_blocks = false;
uint64_t cmask_addr = 0;
uint32_t cmask_slice_minus1 = 0;
uint64_t fmask_addr = 0;
uint32_t fmask_slice_minus1 = 0;
uint32_t clear_color_word0 = 0;
uint32_t clear_color_word1 = 0;
uint64_t dcc_addr = 0;
uint32_t width = 0;
uint32_t height = 0;
};
struct DepthRenderTargetZInfo
{
uint32_t format = 0;
uint32_t tile_mode_index = 0;
uint32_t num_samples = 0;
bool tile_surface_enable = false;
bool expclear_enabled = false;
uint32_t zrange_precision = 0;
};
struct DepthRenderTargetStencilInfo
{
uint32_t format = 0;
uint32_t tile_mode_index = 0;
uint32_t tile_split = 0;
bool expclear_enabled = false;
bool tile_stencil_disable = false;
};
struct DepthRenderTargetDepthInfo
{
uint32_t addr5_swizzle_mask = 0;
uint32_t array_mode = 0;
uint32_t pipe_config = 0;
uint32_t bank_width = 0;
uint32_t bank_height = 0;
uint32_t macro_tile_aspect = 0;
uint32_t num_banks = 0;
};
struct DepthRenderTargetDepthView
{
uint32_t slice_start = 0;
uint32_t slice_max = 0;
};
struct DepthRenderTargetHTileSurface
{
uint32_t linear = 0;
uint32_t full_cache = 0;
uint32_t htile_uses_preload_win = 0;
uint32_t preload = 0;
uint32_t prefetch_width = 0;
uint32_t prefetch_height = 0;
uint32_t dst_outside_zero_to_one = 0;
};
struct DepthRenderTarget
{
DepthRenderTargetZInfo z_info;
DepthRenderTargetStencilInfo stencil_info;
DepthRenderTargetDepthInfo depth_info;
DepthRenderTargetDepthView depth_view;
DepthRenderTargetHTileSurface htile_surface;
uint64_t z_read_base_addr = 0;
uint64_t stencil_read_base_addr = 0;
uint64_t z_write_base_addr = 0;
uint64_t stencil_write_base_addr = 0;
uint32_t pitch_div8_minus1 = 0;
uint32_t height_div8_minus1 = 0;
uint32_t slice_div64_minus1 = 0;
uint64_t htile_data_base_addr = 0;
uint32_t width = 0;
uint32_t height = 0;
};
struct RenderControl
{
bool depth_clear_enable = false;
bool stencil_clear_enable = false;
bool resummarize_enable = false;
bool stencil_compress_disable = false;
bool depth_compress_disable = false;
bool copy_centroid = false;
uint8_t copy_sample = 0;
};
struct ClipControl
{
uint32_t user_clip_planes = 0;
uint32_t user_clip_plane_mode = 0;
uint32_t clip_space = 0;
uint32_t vertex_kill_mode = 0;
uint32_t min_z_clip_enable = 0;
uint32_t max_z_clip_enable = 0;
bool user_clip_plane_negate_y = false;
bool clip_enable = false;
bool user_clip_plane_cull_only = false;
bool cull_on_clipping_error_disable = false;
bool linear_attribute_clip_enable = false;
bool force_viewport_index_from_vs_enable = false;
};
struct DepthControl
{
bool stencil_enable = false;
bool z_enable = false;
bool z_write_enable = false;
bool depth_bounds_enable = false;
uint8_t zfunc = 0;
bool backface_enable = false;
uint8_t stencilfunc = 0;
uint8_t stencilfunc_bf = 0;
};
struct ModeControl
{
bool cull_front = false;
bool cull_back = false;
bool face = false;
uint8_t poly_mode = 0;
uint8_t polymode_front_ptype = 0;
uint8_t polymode_back_ptype = 0;
bool poly_offset_front_enable = false;
bool poly_offset_back_enable = false;
bool vtx_window_offset_enable = false;
bool provoking_vtx_last = false;
bool persp_corr_dis = false;
};
struct BlendControl
{
uint8_t color_srcblend = 0;
uint8_t color_comb_fcn = 0;
uint8_t color_destblend = 0;
uint8_t alpha_srcblend = 0;
uint8_t alpha_comb_fcn = 0;
uint8_t alpha_destblend = 0;
bool separate_alpha_blend = false;
bool enable = false;
};
struct Viewport
{
float zmin = 0.0f;
float zmax = 0.0f;
float xscale = 0.0f;
float xoffset = 0.0f;
float yscale = 0.0f;
float yoffset = 0.0f;
float zscale = 0.0f;
float zoffset = 0.0f;
};
struct ScreenViewport
{
Viewport viewports[15];
uint32_t transform_control = 0;
int scissor_left = 0;
int scissor_top = 0;
int scissor_right = 0;
int scissor_bottom = 0;
uint32_t hw_offset_x = 0;
uint32_t hw_offset_y = 0;
float guard_band_horz_clip = 0.0f;
float guard_band_vert_clip = 0.0f;
float guard_band_horz_discard = 0.0f;
float guard_band_vert_discard = 0.0f;
};
struct VsStageRegisters
{
uint32_t m_spiShaderPgmLoVs = 0;
uint32_t m_spiShaderPgmHiVs = 0;
uint32_t m_spiShaderPgmRsrc1Vs = 0;
uint32_t m_spiShaderPgmRsrc2Vs = 0;
uint32_t m_spiVsOutConfig = 0;
uint32_t m_spiShaderPosFormat = 0;
uint32_t m_paClVsOutCntl = 0;
[[nodiscard]] uint64_t GetGpuAddress() const;
[[nodiscard]] bool GetStreamoutEnabled() const;
[[nodiscard]] uint32_t GetSgprCount() const;
[[nodiscard]] uint32_t GetInputComponentsCount() const;
[[nodiscard]] uint32_t GetUnknown1() const;
[[nodiscard]] uint32_t GetUnknown2() const;
};
struct PsStageRegisters
{
uint64_t data_addr = 0;
uint8_t vgprs = 0;
uint8_t sgprs = 0;
uint8_t scratch_en = 0;
uint8_t user_sgpr = 0;
uint8_t wave_cnt_en = 0;
uint32_t shader_z_format = 0;
uint8_t target_output_mode[8] = {};
uint32_t ps_input_ena = 0;
uint32_t ps_input_addr = 0;
uint32_t ps_in_control = 0;
uint32_t baryc_cntl = 0;
uint8_t conservative_z_export_value = 0;
uint8_t shader_z_behavior = 0;
bool shader_kill_enable = false;
bool shader_z_export_enable = false;
bool shader_execute_on_noop = false;
uint32_t m_cbShaderMask = 0;
};
struct CsStageRegisters
{
uint64_t data_addr = 0;
uint32_t num_thread_x = 0;
uint32_t num_thread_y = 0;
uint32_t num_thread_z = 0;
uint8_t vgprs = 0;
uint8_t sgprs = 0;
uint8_t bulky = 0;
uint8_t scratch_en = 0;
uint8_t user_sgpr = 0;
uint8_t tgid_x_en = 0;
uint8_t tgid_y_en = 0;
uint8_t tgid_z_en = 0;
uint8_t tg_size_en = 0;
uint8_t tidig_comp_cnt = 0;
uint8_t lds_size = 0;
};
enum class UserSgprType
{
Unknown,
Region,
Vsharp
};
struct UserSgprInfo
{
uint32_t value[16] = {0};
UserSgprType type[16] = {};
uint32_t count = 0;
};
struct VertexShaderInfo
{
VsStageRegisters vs_regs;
uint32_t vs_shader_modifier = 0;
uint32_t vs_embedded_id = 0;
UserSgprInfo vs_user_sgpr;
bool vs_embedded = false;
};
struct PixelShaderInfo
{
PsStageRegisters ps_regs;
uint32_t ps_interpolator_settings[32] = {0};
uint32_t ps_input_num = 0;
UserSgprInfo ps_user_sgpr;
};
struct ComputeShaderInfo
{
CsStageRegisters cs_regs;
uint32_t cs_shader_modifier = 0;
UserSgprInfo cs_user_sgpr;
};
class HardwareContext
{
public:
HardwareContext() = default;
virtual ~HardwareContext() = default;
KYTY_CLASS_DEFAULT_COPY(HardwareContext);
void Reset() { *this = HardwareContext(); }
void SetRenderTarget(uint32_t slot, const RenderTarget& target) { m_render_targets[slot] = target; }
[[nodiscard]] const RenderTarget& GetRenderTargets(uint32_t slot) const { return m_render_targets[slot]; }
void SetBlendControl(uint32_t slot, const BlendControl& control) { m_blend_control[slot] = control; }
[[nodiscard]] const BlendControl& GetBlendControl(uint32_t slot) const { return m_blend_control[slot]; }
void SetRenderTargetMask(uint32_t mask) { m_render_target_mask = mask; }
[[nodiscard]] uint32_t GetRenderTargetMask() const { return m_render_target_mask; }
void SetShaderStages(uint32_t flags) { m_shader_stages = flags; }
[[nodiscard]] uint32_t GetShaderStages() const { return m_shader_stages; }
void SetDepthRenderTarget(const DepthRenderTarget& target) { m_depth_render_target = target; }
[[nodiscard]] const DepthRenderTarget& GetDepthRenderTarget() const { return m_depth_render_target; }
void SetDepthRenderTargetZInfo(const DepthRenderTargetZInfo& info) { m_depth_render_target.z_info = info; }
[[nodiscard]] const DepthRenderTargetZInfo& GetDepthRenderTargetZInfo() const { return m_depth_render_target.z_info; }
void SetDepthRenderTargetStencilInfo(const DepthRenderTargetStencilInfo& info) { m_depth_render_target.stencil_info = info; }
[[nodiscard]] const DepthRenderTargetStencilInfo& GetDepthRenderTargetStencilInfo() const { return m_depth_render_target.stencil_info; }
void SetViewportZ(uint32_t viewport_id, float zmin, float zmax)
{
m_screen_viewport.viewports[viewport_id].zmin = zmin;
m_screen_viewport.viewports[viewport_id].zmax = zmax;
}
void SetViewportScaleOffset(uint32_t viewport_id, float xscale, float xoffset, float yscale, float yoffset, float zscale, float zoffset)
{
m_screen_viewport.viewports[viewport_id].xscale = xscale;
m_screen_viewport.viewports[viewport_id].xoffset = xoffset;
m_screen_viewport.viewports[viewport_id].yscale = yscale;
m_screen_viewport.viewports[viewport_id].yoffset = yoffset;
m_screen_viewport.viewports[viewport_id].zscale = zscale;
m_screen_viewport.viewports[viewport_id].zoffset = zoffset;
}
void SetViewportTransformControl(uint32_t control) { m_screen_viewport.transform_control = control; }
void SetScreenScissor(int left, int top, int right, int bottom)
{
m_screen_viewport.scissor_left = left;
m_screen_viewport.scissor_top = top;
m_screen_viewport.scissor_right = right;
m_screen_viewport.scissor_bottom = bottom;
}
void SetHardwareScreenOffset(uint32_t offset_x, uint32_t offset_y)
{
m_screen_viewport.hw_offset_x = offset_x;
m_screen_viewport.hw_offset_y = offset_y;
}
void SetGuardBands(float horz_clip, float vert_clip, float horz_discard, float vert_discard)
{
m_screen_viewport.guard_band_horz_clip = horz_clip;
m_screen_viewport.guard_band_vert_clip = vert_clip;
m_screen_viewport.guard_band_horz_discard = horz_discard;
m_screen_viewport.guard_band_vert_discard = vert_discard;
}
[[nodiscard]] const ScreenViewport& GetScreenViewport() const { return m_screen_viewport; }
void SetVsShader(const VsStageRegisters* vs_regs, uint32_t shader_modifier)
{
m_vs.vs_regs = *vs_regs;
m_vs.vs_shader_modifier = shader_modifier;
m_vs.vs_embedded = false;
}
void SetVsEmbedded(uint32_t id, uint32_t shader_modifier)
{
m_vs.vs_embedded_id = id;
m_vs.vs_shader_modifier = shader_modifier;
m_vs.vs_embedded = true;
}
void SetPsShader(const PsStageRegisters* ps_regs) { m_ps.ps_regs = *ps_regs; }
void SetCsShader(const CsStageRegisters* cs_regs, uint32_t shader_modifier)
{
m_cs.cs_regs = *cs_regs;
m_cs.cs_shader_modifier = shader_modifier;
}
[[nodiscard]] const ClipControl& GetClipControl() const { return m_clip_control; }
void SetClipControl(const ClipControl& control) { m_clip_control = control; }
[[nodiscard]] const RenderControl& GetRenderControl() const { return m_render_control; }
void SetRenderControl(const RenderControl& control) { m_render_control = control; }
[[nodiscard]] const DepthControl& GetDepthControl() const { return m_depth_control; }
void SetDepthControl(const DepthControl& control) { m_depth_control = control; }
[[nodiscard]] const ModeControl& GetModeControl() const { return m_mode_control; }
void SetModeControl(const ModeControl& control) { m_mode_control = control; }
void SetVsUserSgpr(uint32_t id, uint32_t value, UserSgprType type)
{
m_vs.vs_user_sgpr.value[id] = value;
m_vs.vs_user_sgpr.type[id] = type;
m_vs.vs_user_sgpr.count = ((id + 1) > m_vs.vs_user_sgpr.count ? (id + 1) : m_vs.vs_user_sgpr.count);
}
void SetPsUserSgpr(uint32_t id, uint32_t value, UserSgprType type)
{
m_ps.ps_user_sgpr.value[id] = value;
m_ps.ps_user_sgpr.type[id] = type;
m_ps.ps_user_sgpr.count = ((id + 1) > m_ps.ps_user_sgpr.count ? (id + 1) : m_ps.ps_user_sgpr.count);
}
void SetCsUserSgpr(uint32_t id, uint32_t value, UserSgprType type)
{
m_cs.cs_user_sgpr.value[id] = value;
m_cs.cs_user_sgpr.type[id] = type;
m_cs.cs_user_sgpr.count = ((id + 1) > m_cs.cs_user_sgpr.count ? (id + 1) : m_cs.cs_user_sgpr.count);
}
void SetPsInputSettings(uint32_t id, uint32_t value)
{
m_ps.ps_interpolator_settings[id] = value;
m_ps.ps_input_num = ((id + 1) > m_ps.ps_input_num ? (id + 1) : m_ps.ps_input_num);
}
[[nodiscard]] const PixelShaderInfo& GetPs() const { return m_ps; }
[[nodiscard]] const VertexShaderInfo& GetVs() const { return m_vs; }
[[nodiscard]] const ComputeShaderInfo& GetCs() const { return m_cs; }
[[nodiscard]] float GetDepthClearValue() const { return m_depth_clear_value; }
void SetDepthClearValue(float clear_value) { m_depth_clear_value = clear_value; }
private:
BlendControl m_blend_control[8];
RenderTarget m_render_targets[8];
uint32_t m_render_target_mask = 0;
ScreenViewport m_screen_viewport;
ClipControl m_clip_control;
VertexShaderInfo m_vs;
PixelShaderInfo m_ps;
ComputeShaderInfo m_cs;
uint32_t m_shader_stages = 0;
DepthRenderTarget m_depth_render_target;
RenderControl m_render_control;
DepthControl m_depth_control;
float m_depth_clear_value = 0.0f;
ModeControl m_mode_control;
};
class UserConfig
{
public:
UserConfig() = default;
virtual ~UserConfig() = default;
KYTY_CLASS_DEFAULT_COPY(UserConfig);
void Reset() { *this = UserConfig(); }
void SetPrimitiveType(uint32_t prim_type) { m_prim_type = prim_type; }
[[nodiscard]] uint32_t GetPrimType() const { return m_prim_type; }
private:
uint32_t m_prim_type = 0;
};
inline uint64_t VsStageRegisters::GetGpuAddress() const
{
return (static_cast<uint64_t>(m_spiShaderPgmLoVs) << 8u) | (static_cast<uint64_t>(m_spiShaderPgmHiVs) << 40u);
}
inline bool VsStageRegisters::GetStreamoutEnabled() const
{
return (m_spiShaderPgmRsrc2Vs & 0x00001000u) != 0u;
}
inline uint32_t VsStageRegisters::GetSgprCount() const
{
return (m_spiShaderPgmRsrc1Vs >> 6u) & 0xfu;
}
inline uint32_t VsStageRegisters::GetInputComponentsCount() const
{
return (m_spiShaderPgmRsrc1Vs >> 24u) & 0x3u;
}
inline uint32_t VsStageRegisters::GetUnknown1() const
{
return m_spiShaderPgmRsrc1Vs & 0xfcfffc3fu;
}
inline uint32_t VsStageRegisters::GetUnknown2() const
{
return m_spiShaderPgmRsrc2Vs & 0xFFFFEFFFu;
}
} // namespace Kyty::Libs::Graphics
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_HARDWARECONTEXT_H_ */
@@ -0,0 +1,37 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_INDEXBUFFER_H_
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_INDEXBUFFER_H_
#include "Kyty/Core/Common.h"
#include "Emulator/Common.h"
#include "Emulator/Graphics/GpuMemory.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Libs::Graphics {
struct GraphicContext;
struct VulkanMemory;
class IndexBufferGpuObject: public GpuObject
{
public:
IndexBufferGpuObject()
{
check_hash = true;
type = Graphics::GpuMemoryObjectType::IndexBuffer;
}
void* Create(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, VulkanMemory* mem) const override;
bool Equal(const uint64_t* other) const override;
[[nodiscard]] write_back_func_t GetWriteBackFunc() const override { return nullptr; };
[[nodiscard]] delete_func_t GetDeleteFunc() const override;
[[nodiscard]] update_func_t GetUpdateFunc() const override;
};
} // namespace Kyty::Libs::Graphics
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_INDEXBUFFER_H_ */
@@ -0,0 +1,63 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_LABEL_H_
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_LABEL_H_
#include "Kyty/Core/Common.h"
#include "Emulator/Common.h"
#include "Emulator/Graphics/GpuMemory.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Libs::Graphics {
struct Label;
struct GraphicContext;
class CommandBuffer;
struct VulkanMemory;
void LabelInit();
class LabelGpuObject: public GpuObject
{
public:
using callback_t = bool (*)(const uint64_t* args);
static constexpr int PARAM_VALUE = 0;
static constexpr int PARAM_CALLBACK_1 = 1;
static constexpr int PARAM_CALLBACK_2 = 2;
static constexpr int PARAM_ARG_1 = 3;
static constexpr int PARAM_ARG_2 = 4;
static constexpr int PARAM_ARG_3 = 5;
static constexpr int PARAM_ARG_4 = 6;
explicit LabelGpuObject(uint64_t value, callback_t callback_1, callback_t callback_2, const uint64_t* args = nullptr)
{
params[PARAM_VALUE] = value;
params[PARAM_CALLBACK_1] = reinterpret_cast<uint64_t>(callback_1);
params[PARAM_CALLBACK_2] = reinterpret_cast<uint64_t>(callback_2);
if (args != nullptr)
{
params[PARAM_ARG_1] = args[0];
params[PARAM_ARG_2] = args[1];
params[PARAM_ARG_3] = args[2];
params[PARAM_ARG_4] = args[3];
}
check_hash = false;
type = Graphics::GpuMemoryObjectType::Label;
}
void* Create(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, VulkanMemory* mem) const override;
bool Equal(const uint64_t* other) const override;
[[nodiscard]] write_back_func_t GetWriteBackFunc() const override { return nullptr; };
[[nodiscard]] delete_func_t GetDeleteFunc() const override;
[[nodiscard]] update_func_t GetUpdateFunc() const override;
};
void LabelSet(CommandBuffer* buffer, Label* label);
} // namespace Kyty::Libs::Graphics
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_LABEL_H_ */
@@ -0,0 +1,315 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_PM4_H_
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_PM4_H_
#include "Kyty/Core/Common.h"
#include "Emulator/Common.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Core {
class File;
} // namespace Kyty::Core
#define KYTY_PM4_GET(u, r, f) (((u) >> Pm4::r##_##f##_SHIFT) & Pm4::r##_##f##_MASK)
#define KYTY_PM4(len, op, r) \
(0xC0000000u | (((static_cast<uint16_t>(len) - 2u) & 0x3fffu) << 16u) | (((op)&0xffu) << 8u) | (((r)&0x3fu) << 2u))
namespace Kyty::Libs::Graphics::Pm4 {
constexpr uint32_t IT_NOP = 0x10;
constexpr uint32_t IT_SET_BASE = 0x11;
constexpr uint32_t IT_CLEAR_STATE = 0x12;
constexpr uint32_t IT_INDEX_BUFFER_SIZE = 0x13;
constexpr uint32_t IT_DISPATCH_DIRECT = 0x15;
constexpr uint32_t IT_DISPATCH_INDIRECT = 0x16;
constexpr uint32_t IT_SET_PREDICATION = 0x20;
constexpr uint32_t IT_COND_EXEC = 0x22;
constexpr uint32_t IT_DRAW_INDIRECT = 0x24;
constexpr uint32_t IT_DRAW_INDEX_INDIRECT = 0x25;
constexpr uint32_t IT_INDEX_BASE = 0x26;
constexpr uint32_t IT_DRAW_INDEX_2 = 0x27;
constexpr uint32_t IT_CONTEXT_CONTROL = 0x28;
constexpr uint32_t IT_INDEX_TYPE = 0x2A;
constexpr uint32_t IT_DRAW_INDIRECT_MULTI = 0x2C;
constexpr uint32_t IT_DRAW_INDEX_AUTO = 0x2D;
constexpr uint32_t IT_NUM_INSTANCES = 0x2F;
constexpr uint32_t IT_INDIRECT_BUFFER_CNST = 0x33;
constexpr uint32_t IT_DRAW_INDEX_OFFSET_2 = 0x35;
constexpr uint32_t IT_WRITE_DATA = 0x37;
constexpr uint32_t IT_MEM_SEMAPHORE = 0x39;
constexpr uint32_t IT_DRAW_INDEX_INDIRECT_MULTI = 0x38;
constexpr uint32_t IT_WAIT_REG_MEM = 0x3C;
constexpr uint32_t IT_INDIRECT_BUFFER = 0x3F;
constexpr uint32_t IT_COPY_DATA = 0x40;
constexpr uint32_t IT_CP_DMA = 0x41;
constexpr uint32_t IT_PFP_SYNC_ME = 0x42;
constexpr uint32_t IT_SURFACE_SYNC = 0x43;
constexpr uint32_t IT_EVENT_WRITE = 0x46;
constexpr uint32_t IT_EVENT_WRITE_EOP = 0x47;
constexpr uint32_t IT_EVENT_WRITE_EOS = 0x48;
constexpr uint32_t IT_RELEASE_MEM = 0x49;
constexpr uint32_t IT_DMA_DATA = 0x50;
constexpr uint32_t IT_ACQUIRE_MEM = 0x58;
constexpr uint32_t IT_REWIND = 0x59;
constexpr uint32_t IT_SET_CONFIG_REG = 0x68;
constexpr uint32_t IT_SET_CONTEXT_REG = 0x69;
constexpr uint32_t IT_SET_SH_REG = 0x76;
constexpr uint32_t IT_SET_QUEUE_REG = 0x78;
constexpr uint32_t IT_SET_UCONFIG_REG = 0x79;
constexpr uint32_t IT_WRITE_CONST_RAM = 0x81;
constexpr uint32_t IT_DUMP_CONST_RAM = 0x83;
constexpr uint32_t IT_INCREMENT_CE_COUNTER = 0x84;
constexpr uint32_t IT_INCREMENT_DE_COUNTER = 0x85;
constexpr uint32_t IT_WAIT_ON_CE_COUNTER = 0x86;
constexpr uint32_t IT_WAIT_ON_DE_COUNTER_DIFF = 0x88;
constexpr uint32_t IT_DISPATCH_DRAW_PREAMBLE = 0x8C;
constexpr uint32_t IT_DISPATCH_DRAW = 0x8D;
constexpr uint32_t R_ZERO = 0x00;
constexpr uint32_t R_VS = 0x01;
constexpr uint32_t R_PS = 0x02;
constexpr uint32_t R_DRAW_INDEX = 0x03;
constexpr uint32_t R_DRAW_INDEX_AUTO = 0x04;
constexpr uint32_t R_DRAW_RESET = 0x05;
constexpr uint32_t R_WAIT_FLIP_DONE = 0x06;
constexpr uint32_t R_CS = 0x07;
constexpr uint32_t R_DISPATCH_DIRECT = 0x08;
constexpr uint32_t R_DISPATCH_RESET = 0x09;
constexpr uint32_t R_DISPATCH_WAIT_MEM = 0x0A;
constexpr uint32_t R_PUSH_MARKER = 0x0B;
constexpr uint32_t R_POP_MARKER = 0x0C;
constexpr uint32_t R_VS_EMBEDDED = 0x0D;
constexpr uint32_t DB_RENDER_CONTROL = 0x0;
constexpr uint32_t DB_RENDER_CONTROL_DEPTH_CLEAR_ENABLE_SHIFT = 0;
constexpr uint32_t DB_RENDER_CONTROL_DEPTH_CLEAR_ENABLE_MASK = 0x1;
constexpr uint32_t DB_RENDER_CONTROL_STENCIL_CLEAR_ENABLE_SHIFT = 1;
constexpr uint32_t DB_RENDER_CONTROL_STENCIL_CLEAR_ENABLE_MASK = 0x1;
constexpr uint32_t DB_RENDER_CONTROL_RESUMMARIZE_ENABLE_SHIFT = 4;
constexpr uint32_t DB_RENDER_CONTROL_RESUMMARIZE_ENABLE_MASK = 0x1;
constexpr uint32_t DB_RENDER_CONTROL_STENCIL_COMPRESS_DISABLE_SHIFT = 5;
constexpr uint32_t DB_RENDER_CONTROL_STENCIL_COMPRESS_DISABLE_MASK = 0x1;
constexpr uint32_t DB_RENDER_CONTROL_DEPTH_COMPRESS_DISABLE_SHIFT = 6;
constexpr uint32_t DB_RENDER_CONTROL_DEPTH_COMPRESS_DISABLE_MASK = 0x1;
constexpr uint32_t DB_RENDER_CONTROL_COPY_CENTROID_SHIFT = 7;
constexpr uint32_t DB_RENDER_CONTROL_COPY_CENTROID_MASK = 0x1;
constexpr uint32_t DB_RENDER_CONTROL_COPY_SAMPLE_SHIFT = 8;
constexpr uint32_t DB_RENDER_CONTROL_COPY_SAMPLE_MASK = 0xF;
constexpr uint32_t DB_DEPTH_VIEW = 0x2;
constexpr uint32_t DB_DEPTH_VIEW_SLICE_START_SHIFT = 0;
constexpr uint32_t DB_DEPTH_VIEW_SLICE_START_MASK = 0x7FF;
constexpr uint32_t DB_DEPTH_VIEW_SLICE_MAX_SHIFT = 13;
constexpr uint32_t DB_DEPTH_VIEW_SLICE_MAX_MASK = 0x7FF;
constexpr uint32_t DB_HTILE_DATA_BASE = 0x5;
constexpr uint32_t DB_HTILE_DATA_BASE_BASE_256B_SHIFT = 0;
constexpr uint32_t DB_HTILE_DATA_BASE_BASE_256B_MASK = 0xFFFFFFFF;
constexpr uint32_t DB_DEPTH_CLEAR = 0xB;
constexpr uint32_t DB_DEPTH_CLEAR_DEPTH_CLEAR_SHIFT = 0;
constexpr uint32_t DB_DEPTH_CLEAR_DEPTH_CLEAR_MASK = 0xFFFFFFFF;
constexpr uint32_t DB_DEPTH_INFO = 0xF;
constexpr uint32_t DB_DEPTH_INFO_ADDR5_SWIZZLE_MASK_SHIFT = 0;
constexpr uint32_t DB_DEPTH_INFO_ADDR5_SWIZZLE_MASK_MASK = 0xF;
constexpr uint32_t DB_DEPTH_INFO_ARRAY_MODE_SHIFT = 4;
constexpr uint32_t DB_DEPTH_INFO_ARRAY_MODE_MASK = 0xF;
constexpr uint32_t DB_DEPTH_INFO_PIPE_CONFIG_SHIFT = 8;
constexpr uint32_t DB_DEPTH_INFO_PIPE_CONFIG_MASK = 0x1F;
constexpr uint32_t DB_DEPTH_INFO_BANK_WIDTH_SHIFT = 13;
constexpr uint32_t DB_DEPTH_INFO_BANK_WIDTH_MASK = 0x3;
constexpr uint32_t DB_DEPTH_INFO_BANK_HEIGHT_SHIFT = 15;
constexpr uint32_t DB_DEPTH_INFO_BANK_HEIGHT_MASK = 0x3;
constexpr uint32_t DB_DEPTH_INFO_MACRO_TILE_ASPECT_SHIFT = 17;
constexpr uint32_t DB_DEPTH_INFO_MACRO_TILE_ASPECT_MASK = 0x3;
constexpr uint32_t DB_DEPTH_INFO_NUM_BANKS_SHIFT = 19;
constexpr uint32_t DB_DEPTH_INFO_NUM_BANKS_MASK = 0x3;
constexpr uint32_t DB_Z_INFO = 0x10;
constexpr uint32_t DB_Z_INFO_FORMAT_SHIFT = 0;
constexpr uint32_t DB_Z_INFO_FORMAT_MASK = 0x3;
constexpr uint32_t DB_Z_INFO_NUM_SAMPLES_SHIFT = 2;
constexpr uint32_t DB_Z_INFO_NUM_SAMPLES_MASK = 0x3;
constexpr uint32_t DB_Z_INFO_TILE_MODE_INDEX_SHIFT = 20;
constexpr uint32_t DB_Z_INFO_TILE_MODE_INDEX_MASK = 0x7;
constexpr uint32_t DB_Z_INFO_TILE_SURFACE_ENABLE_SHIFT = 29;
constexpr uint32_t DB_Z_INFO_TILE_SURFACE_ENABLE_MASK = 0x1;
constexpr uint32_t DB_Z_INFO_ZRANGE_PRECISION_SHIFT = 31;
constexpr uint32_t DB_Z_INFO_ZRANGE_PRECISION_MASK = 0x1;
constexpr uint32_t DB_STENCIL_INFO = 0x11;
constexpr uint32_t DB_STENCIL_INFO_FORMAT_SHIFT = 0;
constexpr uint32_t DB_STENCIL_INFO_FORMAT_MASK = 0x1;
constexpr uint32_t DB_STENCIL_INFO_TILE_MODE_INDEX_SHIFT = 20;
constexpr uint32_t DB_STENCIL_INFO_TILE_MODE_INDEX_MASK = 0x7;
constexpr uint32_t DB_STENCIL_INFO_TILE_STENCIL_DISABLE_SHIFT = 29;
constexpr uint32_t DB_STENCIL_INFO_TILE_STENCIL_DISABLE_MASK = 0x1;
constexpr uint32_t DB_Z_READ_BASE = 0x12;
constexpr uint32_t DB_Z_READ_BASE_BASE_256B_SHIFT = 0;
constexpr uint32_t DB_Z_READ_BASE_BASE_256B_MASK = 0xFFFFFFFF;
constexpr uint32_t DB_STENCIL_READ_BASE = 0x13;
constexpr uint32_t DB_STENCIL_READ_BASE_BASE_256B_SHIFT = 0;
constexpr uint32_t DB_STENCIL_READ_BASE_BASE_256B_MASK = 0xFFFFFFFF;
constexpr uint32_t DB_Z_WRITE_BASE = 0x14;
constexpr uint32_t DB_Z_WRITE_BASE_BASE_256B_SHIFT = 0;
constexpr uint32_t DB_Z_WRITE_BASE_BASE_256B_MASK = 0xFFFFFFFF;
constexpr uint32_t DB_STENCIL_WRITE_BASE = 0x15;
constexpr uint32_t DB_STENCIL_WRITE_BASE_BASE_256B_SHIFT = 0;
constexpr uint32_t DB_STENCIL_WRITE_BASE_BASE_256B_MASK = 0xFFFFFFFF;
constexpr uint32_t DB_DEPTH_SIZE = 0x16;
constexpr uint32_t DB_DEPTH_SIZE_PITCH_TILE_MAX_SHIFT = 0;
constexpr uint32_t DB_DEPTH_SIZE_PITCH_TILE_MAX_MASK = 0x7FF;
constexpr uint32_t DB_DEPTH_SIZE_HEIGHT_TILE_MAX_SHIFT = 11;
constexpr uint32_t DB_DEPTH_SIZE_HEIGHT_TILE_MAX_MASK = 0x7FF;
constexpr uint32_t DB_DEPTH_SLICE = 0x17;
constexpr uint32_t DB_DEPTH_SLICE_SLICE_TILE_MAX_SHIFT = 0;
constexpr uint32_t DB_DEPTH_SLICE_SLICE_TILE_MAX_MASK = 0x3FFFFF;
constexpr uint32_t PA_SC_VPORT_ZMIN_0 = 0xB4;
constexpr uint32_t PA_CL_VPORT_XSCALE = 0x10F;
constexpr uint32_t SPI_PS_INPUT_CNTL_0 = 0x191;
constexpr uint32_t CB_BLEND0_CONTROL = 0x1E0;
constexpr uint32_t CB_BLEND0_CONTROL_COLOR_SRCBLEND_SHIFT = 0;
constexpr uint32_t CB_BLEND0_CONTROL_COLOR_SRCBLEND_MASK = 0x1F;
constexpr uint32_t CB_BLEND0_CONTROL_COLOR_COMB_FCN_SHIFT = 5;
constexpr uint32_t CB_BLEND0_CONTROL_COLOR_COMB_FCN_MASK = 0x7;
constexpr uint32_t CB_BLEND0_CONTROL_COLOR_DESTBLEND_SHIFT = 8;
constexpr uint32_t CB_BLEND0_CONTROL_COLOR_DESTBLEND_MASK = 0x1F;
constexpr uint32_t CB_BLEND0_CONTROL_ALPHA_SRCBLEND_SHIFT = 16;
constexpr uint32_t CB_BLEND0_CONTROL_ALPHA_SRCBLEND_MASK = 0x1F;
constexpr uint32_t CB_BLEND0_CONTROL_ALPHA_COMB_FCN_SHIFT = 21;
constexpr uint32_t CB_BLEND0_CONTROL_ALPHA_COMB_FCN_MASK = 0x7;
constexpr uint32_t CB_BLEND0_CONTROL_ALPHA_DESTBLEND_SHIFT = 24;
constexpr uint32_t CB_BLEND0_CONTROL_ALPHA_DESTBLEND_MASK = 0x1F;
constexpr uint32_t CB_BLEND0_CONTROL_SEPARATE_ALPHA_BLEND_SHIFT = 29;
constexpr uint32_t CB_BLEND0_CONTROL_SEPARATE_ALPHA_BLEND_MASK = 0x1;
constexpr uint32_t CB_BLEND0_CONTROL_ENABLE_SHIFT = 30;
constexpr uint32_t CB_BLEND0_CONTROL_ENABLE_MASK = 0x1;
constexpr uint32_t DB_DEPTH_CONTROL = 0x200;
constexpr uint32_t DB_DEPTH_CONTROL_STENCIL_ENABLE_SHIFT = 0;
constexpr uint32_t DB_DEPTH_CONTROL_STENCIL_ENABLE_MASK = 0x1;
constexpr uint32_t DB_DEPTH_CONTROL_Z_ENABLE_SHIFT = 1;
constexpr uint32_t DB_DEPTH_CONTROL_Z_ENABLE_MASK = 0x1;
constexpr uint32_t DB_DEPTH_CONTROL_Z_WRITE_ENABLE_SHIFT = 2;
constexpr uint32_t DB_DEPTH_CONTROL_Z_WRITE_ENABLE_MASK = 0x1;
constexpr uint32_t DB_DEPTH_CONTROL_DEPTH_BOUNDS_ENABLE_SHIFT = 3;
constexpr uint32_t DB_DEPTH_CONTROL_DEPTH_BOUNDS_ENABLE_MASK = 0x1;
constexpr uint32_t DB_DEPTH_CONTROL_ZFUNC_SHIFT = 4;
constexpr uint32_t DB_DEPTH_CONTROL_ZFUNC_MASK = 0x7;
constexpr uint32_t DB_DEPTH_CONTROL_BACKFACE_ENABLE_SHIFT = 7;
constexpr uint32_t DB_DEPTH_CONTROL_BACKFACE_ENABLE_MASK = 0x1;
constexpr uint32_t DB_DEPTH_CONTROL_STENCILFUNC_SHIFT = 8;
constexpr uint32_t DB_DEPTH_CONTROL_STENCILFUNC_MASK = 0x7;
constexpr uint32_t DB_DEPTH_CONTROL_STENCILFUNC_BF_SHIFT = 20;
constexpr uint32_t DB_DEPTH_CONTROL_STENCILFUNC_BF_MASK = 0x7;
constexpr uint32_t PA_SU_SC_MODE_CNTL = 0x205;
constexpr uint32_t PA_SU_SC_MODE_CNTL_CULL_FRONT_SHIFT = 0;
constexpr uint32_t PA_SU_SC_MODE_CNTL_CULL_FRONT_MASK = 0x1;
constexpr uint32_t PA_SU_SC_MODE_CNTL_CULL_BACK_SHIFT = 1;
constexpr uint32_t PA_SU_SC_MODE_CNTL_CULL_BACK_MASK = 0x1;
constexpr uint32_t PA_SU_SC_MODE_CNTL_FACE_SHIFT = 2;
constexpr uint32_t PA_SU_SC_MODE_CNTL_FACE_MASK = 0x1;
constexpr uint32_t PA_SU_SC_MODE_CNTL_POLY_MODE_SHIFT = 3;
constexpr uint32_t PA_SU_SC_MODE_CNTL_POLY_MODE_MASK = 0x3;
constexpr uint32_t PA_SU_SC_MODE_CNTL_POLYMODE_FRONT_PTYPE_SHIFT = 5;
constexpr uint32_t PA_SU_SC_MODE_CNTL_POLYMODE_FRONT_PTYPE_MASK = 0x7;
constexpr uint32_t PA_SU_SC_MODE_CNTL_POLYMODE_BACK_PTYPE_SHIFT = 8;
constexpr uint32_t PA_SU_SC_MODE_CNTL_POLYMODE_BACK_PTYPE_MASK = 0x7;
constexpr uint32_t PA_SU_SC_MODE_CNTL_POLY_OFFSET_FRONT_ENABLE_SHIFT = 11;
constexpr uint32_t PA_SU_SC_MODE_CNTL_POLY_OFFSET_FRONT_ENABLE_MASK = 0x1;
constexpr uint32_t PA_SU_SC_MODE_CNTL_POLY_OFFSET_BACK_ENABLE_SHIFT = 12;
constexpr uint32_t PA_SU_SC_MODE_CNTL_POLY_OFFSET_BACK_ENABLE_MASK = 0x1;
constexpr uint32_t PA_SU_SC_MODE_CNTL_VTX_WINDOW_OFFSET_ENABLE_SHIFT = 16;
constexpr uint32_t PA_SU_SC_MODE_CNTL_VTX_WINDOW_OFFSET_ENABLE_MASK = 0x1;
constexpr uint32_t PA_SU_SC_MODE_CNTL_PROVOKING_VTX_LAST_SHIFT = 19;
constexpr uint32_t PA_SU_SC_MODE_CNTL_PROVOKING_VTX_LAST_MASK = 0x1;
constexpr uint32_t PA_SU_SC_MODE_CNTL_PERSP_CORR_DIS_SHIFT = 20;
constexpr uint32_t PA_SU_SC_MODE_CNTL_PERSP_CORR_DIS_MASK = 0x1;
constexpr uint32_t DB_HTILE_SURFACE = 0x2AF;
constexpr uint32_t DB_HTILE_SURFACE_LINEAR_SHIFT = 0;
constexpr uint32_t DB_HTILE_SURFACE_LINEAR_MASK = 0x1;
constexpr uint32_t DB_HTILE_SURFACE_FULL_CACHE_SHIFT = 1;
constexpr uint32_t DB_HTILE_SURFACE_FULL_CACHE_MASK = 0x1;
constexpr uint32_t DB_HTILE_SURFACE_HTILE_USES_PRELOAD_WIN_SHIFT = 2;
constexpr uint32_t DB_HTILE_SURFACE_HTILE_USES_PRELOAD_WIN_MASK = 0x1;
constexpr uint32_t DB_HTILE_SURFACE_PRELOAD_SHIFT = 3;
constexpr uint32_t DB_HTILE_SURFACE_PRELOAD_MASK = 0x1;
constexpr uint32_t DB_HTILE_SURFACE_PREFETCH_WIDTH_SHIFT = 4;
constexpr uint32_t DB_HTILE_SURFACE_PREFETCH_WIDTH_MASK = 0x3F;
constexpr uint32_t DB_HTILE_SURFACE_PREFETCH_HEIGHT_SHIFT = 10;
constexpr uint32_t DB_HTILE_SURFACE_PREFETCH_HEIGHT_MASK = 0x3F;
constexpr uint32_t DB_HTILE_SURFACE_DST_OUTSIDE_ZERO_TO_ONE_SHIFT = 16;
constexpr uint32_t DB_HTILE_SURFACE_DST_OUTSIDE_ZERO_TO_ONE_MASK = 0x1;
constexpr uint32_t VGT_SHADER_STAGES_EN = 0x2D5;
constexpr uint32_t CB_COLOR0_BASE = 0x318;
constexpr uint32_t SPI_SHADER_PGM_RSRC1_PS = 0xA;
constexpr uint32_t SPI_SHADER_PGM_RSRC1_PS_VGPRS_SHIFT = 0;
constexpr uint32_t SPI_SHADER_PGM_RSRC1_PS_VGPRS_MASK = 0x3F;
constexpr uint32_t SPI_SHADER_PGM_RSRC1_PS_SGPRS_SHIFT = 6;
constexpr uint32_t SPI_SHADER_PGM_RSRC1_PS_SGPRS_MASK = 0xF;
constexpr uint32_t SPI_SHADER_PGM_RSRC2_PS = 0xB;
constexpr uint32_t SPI_SHADER_PGM_RSRC2_PS_SCRATCH_EN_SHIFT = 0;
constexpr uint32_t SPI_SHADER_PGM_RSRC2_PS_SCRATCH_EN_MASK = 0x1;
constexpr uint32_t SPI_SHADER_PGM_RSRC2_PS_USER_SGPR_SHIFT = 1;
constexpr uint32_t SPI_SHADER_PGM_RSRC2_PS_USER_SGPR_MASK = 0x1F;
constexpr uint32_t SPI_SHADER_PGM_RSRC2_PS_WAVE_CNT_EN_SHIFT = 7;
constexpr uint32_t SPI_SHADER_PGM_RSRC2_PS_WAVE_CNT_EN_MASK = 0x0;
constexpr uint32_t SPI_SHADER_USER_DATA_PS_0 = 0xC;
constexpr uint32_t SPI_SHADER_USER_DATA_PS_15 = 0x1B;
constexpr uint32_t SPI_SHADER_USER_DATA_VS_0 = 0x4C;
constexpr uint32_t SPI_SHADER_USER_DATA_VS_15 = 0x5B;
constexpr uint32_t COMPUTE_PGM_RSRC1 = 0x212;
constexpr uint32_t COMPUTE_PGM_RSRC1_VGPRS_SHIFT = 0;
constexpr uint32_t COMPUTE_PGM_RSRC1_VGPRS_MASK = 0x3F;
constexpr uint32_t COMPUTE_PGM_RSRC1_SGPRS_SHIFT = 6;
constexpr uint32_t COMPUTE_PGM_RSRC1_SGPRS_MASK = 0xF;
constexpr uint32_t COMPUTE_PGM_RSRC1_BULKY_SHIFT = 24;
constexpr uint32_t COMPUTE_PGM_RSRC1_BULKY_MASK = 0x1;
constexpr uint32_t COMPUTE_PGM_RSRC2 = 0x213;
constexpr uint32_t COMPUTE_PGM_RSRC2_SCRATCH_EN_SHIFT = 0;
constexpr uint32_t COMPUTE_PGM_RSRC2_SCRATCH_EN_MASK = 0x1;
constexpr uint32_t COMPUTE_PGM_RSRC2_USER_SGPR_SHIFT = 1;
constexpr uint32_t COMPUTE_PGM_RSRC2_USER_SGPR_MASK = 0x1F;
constexpr uint32_t COMPUTE_PGM_RSRC2_TGID_X_EN_SHIFT = 7;
constexpr uint32_t COMPUTE_PGM_RSRC2_TGID_X_EN_MASK = 0x1;
constexpr uint32_t COMPUTE_PGM_RSRC2_TGID_Y_EN_SHIFT = 8;
constexpr uint32_t COMPUTE_PGM_RSRC2_TGID_Y_EN_MASK = 0x1;
constexpr uint32_t COMPUTE_PGM_RSRC2_TGID_Z_EN_SHIFT = 9;
constexpr uint32_t COMPUTE_PGM_RSRC2_TGID_Z_EN_MASK = 0x1;
constexpr uint32_t COMPUTE_PGM_RSRC2_TG_SIZE_EN_SHIFT = 10;
constexpr uint32_t COMPUTE_PGM_RSRC2_TG_SIZE_EN_MASK = 0x1;
constexpr uint32_t COMPUTE_PGM_RSRC2_TIDIG_COMP_CNT_SHIFT = 11;
constexpr uint32_t COMPUTE_PGM_RSRC2_TIDIG_COMP_CNT_MASK = 0x3;
constexpr uint32_t COMPUTE_PGM_RSRC2_LDS_SIZE_SHIFT = 15;
constexpr uint32_t COMPUTE_PGM_RSRC2_LDS_SIZE_MASK = 0x1FF;
constexpr uint32_t COMPUTE_USER_DATA_0 = 0x240;
constexpr uint32_t COMPUTE_USER_DATA_15 = 0x24F;
void DumpPm4PacketStream(Core::File* file, uint32_t* cmd_buffer, uint32_t start_dw, uint32_t num_dw);
} // namespace Kyty::Libs::Graphics::Pm4
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_PM4_H_ */
@@ -0,0 +1,554 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_H_
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_H_
#include "Kyty/Core/Common.h"
#include "Kyty/Core/String.h"
#include "Kyty/Core/Vector.h"
#include "Emulator/Common.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Libs::Graphics {
struct VertexShaderInfo;
struct PixelShaderInfo;
struct ComputeShaderInfo;
enum class ShaderType
{
Unknown,
Vertex,
Pixel,
Fetch,
Compute
};
enum class ShaderInstructionType
{
Unknown,
DsAppend,
DsConsume,
Exp,
BufferLoadDword,
BufferLoadFormatX,
BufferLoadFormatXy,
BufferLoadFormatXyz,
BufferLoadFormatXyzw,
BufferStoreDword,
BufferStoreFormatX,
ImageSample,
TBufferLoadFormatXyzw,
SAndn2B64,
SAndSaveexecB64,
SEndpgm,
SCbranchExecz,
SLshlB32,
SLoadDwordx4,
SLoadDwordx8,
SBufferLoadDword,
SBufferLoadDwordx4,
SBufferLoadDwordx8,
SBufferLoadDwordx16,
SMovB32,
SMovB64,
SSetpcB64,
SSwappcB64,
SWaitcnt,
SWqmB64,
VAddI32,
VAndB32,
VCmpEqF32,
VCmpEqU32,
VCmpLeF32,
VCmpLeU32,
VCmpNeU32,
VCmpNeqF32,
VCmpxEqU32,
VCmpxGtU32,
VCndmaskB32,
VCvtF32U32,
VCvtPkrtzF16F32,
VCvtU32F32,
VMacF32,
VMadakF32,
VMadF32,
VMaxF32,
VMbcntHiU32B32,
VMbcntLoU32B32,
VMinF32,
VMovB32,
VMulF32,
VInterpP1F32,
VInterpP2F32,
VRcpF32,
VRsqF32,
VSadU32,
VSqrtF32,
VSubF32,
VSubI32,
VSubrevF32,
VSubrevI32,
};
namespace ShaderInstructionFormat {
enum FormatByte : uint64_t
{
U = 0,
N,
D, // operand_to_str(inst.dst)
D2, // operand_to_str(inst.dst2)
S0, // operand_to_str(inst.src[0])
S1, // operand_to_str(inst.src[1])
S2, // operand_to_str(inst.src[2])
S3, // operand_to_str(inst.src[3])
DA2, // operand_array_to_str(inst.dst, 2)
DA3, // operand_array_to_str(inst.dst, 3)
DA4, // operand_array_to_str(inst.dst, 4)
DA8, // operand_array_to_str(inst.dst, 8)
DA16, // operand_array_to_str(inst.dst, 16)
D2A2, // operand_array_to_str(inst.dst2, 2)
D2A3, // operand_array_to_str(inst.dst2, 3)
D2A4, // operand_array_to_str(inst.dst2, 4)
S0A2, // operand_array_to_str(inst.src[0], 2)
S0A3, // operand_array_to_str(inst.src[0], 3)
S0A4, // operand_array_to_str(inst.src[0], 4)
S1A2, // operand_array_to_str(inst.src[1], 2)
S1A3, // operand_array_to_str(inst.src[1], 3)
S1A4, // operand_array_to_str(inst.src[1], 4)
S1A8, // operand_array_to_str(inst.src[1], 8)
S2A2, // operand_array_to_str(inst.src[2], 2)
S2A3, // operand_array_to_str(inst.src[2], 3)
S2A4, // operand_array_to_str(inst.src[2], 4)
Attr, // attr%u.%u <- inst.src[1].constant.u, inst.src[2].constant.u
Idxen, // idxen
Float4, // format:float4
Pos0, // pos0
Done, // done
Param0, // param0
Param1, // param1
Param2, // param2
Param3, // param3
Mrt0, // mrt_color0
Compr, // compr
Vm, // vm
L, // label_%u
DmaskF, // dmask:0xf
Dmask7, // dmask:0x7
Gds, // gds
};
constexpr uint64_t FormatDefine(std::initializer_list<uint64_t> f)
{
uint64_t r = 0;
for (auto n: f)
{
r = (r << 8u) | n;
}
return r;
}
enum Format : uint64_t
{
Unknown = FormatDefine({U}),
Empty = FormatDefine({N}),
Imm = FormatDefine({S0}),
Label = FormatDefine({L}),
Mrt0Vsrc0Vsrc1ComprVmDone = FormatDefine({Mrt0, S0, S1, Compr, Vm, Done}),
Mrt0Vsrc0Vsrc1Vsrc2Vsrc3VmDone = FormatDefine({Mrt0, S0, S1, S2, S3, Vm, Done}),
Param0Vsrc0Vsrc1Vsrc2Vsrc3 = FormatDefine({Param0, S0, S1, S2, S3}),
Param1Vsrc0Vsrc1Vsrc2Vsrc3 = FormatDefine({Param1, S0, S1, S2, S3}),
Param2Vsrc0Vsrc1Vsrc2Vsrc3 = FormatDefine({Param2, S0, S1, S2, S3}),
Param3Vsrc0Vsrc1Vsrc2Vsrc3 = FormatDefine({Param3, S0, S1, S2, S3}),
Pos0Vsrc0Vsrc1Vsrc2Vsrc3Done = FormatDefine({Pos0, S0, S1, S2, S3, Done}),
Saddr = FormatDefine({S0A2}),
Sdst4SbaseSoffset = FormatDefine({DA4, S0A2, S1}),
Sdst8SbaseSoffset = FormatDefine({DA8, S0A2, S1}),
SdstSvSoffset = FormatDefine({D, S0A4, S1}),
Sdst4SvSoffset = FormatDefine({DA4, S0A4, S1}),
Sdst8SvSoffset = FormatDefine({DA8, S0A4, S1}),
Sdst16SvSoffset = FormatDefine({DA16, S0A4, S1}),
SVdstSVsrc0 = FormatDefine({D, S0}),
SVdstSVsrc0SVsrc1 = FormatDefine({D, S0, S1}),
Sdst2Ssrc02 = FormatDefine({DA2, S0A2}),
Sdst2Ssrc02Ssrc12 = FormatDefine({DA2, S0A2, S1A2}),
SmaskVsrc0Vsrc1 = FormatDefine({DA2, S0, S1}),
Vdata1VaddrSvSoffsIdxen = FormatDefine({D, S0, S1A4, S2, Idxen}),
Vdata2VaddrSvSoffsIdxen = FormatDefine({DA2, S0, S1A4, S2, Idxen}),
Vdata3VaddrSvSoffsIdxen = FormatDefine({DA3, S0, S1A4, S2, Idxen}),
Vdata4VaddrSvSoffsIdxen = FormatDefine({DA4, S0, S1A4, S2, Idxen}),
Vdata4VaddrSvSoffsIdxenFloat4 = FormatDefine({DA4, S0, S1A4, S2, Idxen, Float4}),
Vdata3Vaddr3StSsDmask7 = FormatDefine({DA3, S0A3, S1A8, S2A4, Dmask7}),
Vdata4Vaddr3StSsDmaskF = FormatDefine({DA4, S0A3, S1A8, S2A4, DmaskF}),
VdstVsrc0Vsrc1Smask2 = FormatDefine({D, S0, S1, S2A2}),
VdstVsrc0Vsrc1Vsrc2 = FormatDefine({D, S0, S1, S2}),
VdstVsrcAttrChan = FormatDefine({D, S0, Attr}),
VdstSdst2Vsrc0Vsrc1 = FormatDefine({D, D2A2, S0, S1}),
VdstGds = FormatDefine({D, Gds})
};
} // namespace ShaderInstructionFormat
enum class ShaderOperandType
{
Unknown,
LiteralConstant,
IntegerInlineConstant,
FloatInlineConstant,
VccLo,
VccHi,
ExecLo,
ExecHi,
ExecZ,
Vgpr,
Sgpr,
M0
};
union ShaderConstant
{
int32_t i;
uint32_t u;
float f;
};
struct ShaderOperand
{
ShaderOperandType type = ShaderOperandType::Unknown;
ShaderConstant constant = {0};
int register_id = 0;
int size = 0;
float multiplier = 1.0f;
bool negate = false;
bool clamp = false;
bool operator==(const ShaderOperand& other) const
{
return type == other.type && constant.u == other.constant.u && register_id == other.register_id && size == other.size;
}
};
struct ShaderInstruction
{
uint32_t pc = 0;
ShaderInstructionType type = ShaderInstructionType::Unknown;
ShaderInstructionFormat::Format format = ShaderInstructionFormat::Unknown;
ShaderOperand src[4];
int src_num = 0;
ShaderOperand dst;
ShaderOperand dst2;
};
class ShaderCode
{
public:
ShaderCode() { m_instructions.Expand(128); };
virtual ~ShaderCode() = default;
KYTY_CLASS_DEFAULT_COPY(ShaderCode);
[[nodiscard]] const Vector<ShaderInstruction>& GetInstructions() const { return m_instructions; }
Vector<ShaderInstruction>& GetInstructions() { return m_instructions; }
[[nodiscard]] const Vector<uint32_t>& GetLabels() const { return m_labels; }
Vector<uint32_t>& GetLabels() { return m_labels; }
[[nodiscard]] String DbgDump() const;
static String DbgInstructionToStr(const ShaderInstruction& inst);
[[nodiscard]] ShaderType GetType() const { return m_type; }
void SetType(ShaderType type) { this->m_type = type; }
private:
Vector<ShaderInstruction> m_instructions;
Vector<uint32_t> m_labels;
ShaderType m_type = ShaderType::Unknown;
};
struct ShaderId
{
Vector<uint32_t> ids;
bool operator==(const ShaderId& other) const { return ids == other.ids; }
bool operator!=(const ShaderId& other) const { return !(*this == other); }
};
struct ShaderBufferResource
{
uint32_t fields[4] = {0};
void UpdateAddress(uint64_t gpu_addr)
{
auto lo = static_cast<uint32_t>(gpu_addr & 0xffffffffu);
auto hi = static_cast<uint32_t>(gpu_addr >> 32u);
fields[0] = lo;
fields[1] = (fields[1] & 0xfffff000u) | (hi & 0xfffu);
}
[[nodiscard]] uint64_t Base() const { return (fields[0] | (static_cast<uint64_t>(fields[1]) << 32u)) & 0xFFFFFFFFFFFu; }
[[nodiscard]] uint16_t Stride() const { return (fields[1] >> 16u) & 0x3FFFu; }
[[nodiscard]] bool SwizzleEnabled() const { return ((fields[1] >> 31u) & 0x1u) == 1; }
[[nodiscard]] uint32_t NumRecords() const { return fields[2]; }
[[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]] uint8_t Nfmt() const { return (fields[3] >> 12u) & 0x7u; }
[[nodiscard]] uint8_t Dfmt() const { return (fields[3] >> 15u) & 0xFu; }
[[nodiscard]] bool AddTid() const { return ((fields[3] >> 23u) & 0x1u) == 1; }
[[nodiscard]] uint8_t MemoryType() const
{
return ((fields[1] >> 7u) & 0x60u) | ((fields[3] >> 25u) & 0x1cu) | ((fields[1] >> 14u) & 0x3u);
}
};
struct ShaderTextureResource
{
uint32_t fields[8] = {0};
void UpdateAddress(uint64_t gpu_addr)
{
auto lo = static_cast<uint32_t>(gpu_addr & 0xffffffffu);
auto hi = static_cast<uint32_t>(gpu_addr >> 32u);
fields[0] = lo;
fields[1] = (fields[1] & 0xffffffc0u) | (hi & 0x3fu);
}
[[nodiscard]] uint64_t Base() const { return ((fields[0] | (static_cast<uint64_t>(fields[1]) << 32u)) & 0x3FFFFFFFFFu) << 8u; }
[[nodiscard]] uint16_t MinLod() const { return (fields[1] >> 8u) & 0xFFFu; }
[[nodiscard]] uint8_t Dfmt() const { return (fields[1] >> 20u) & 0x3Fu; }
[[nodiscard]] uint8_t Nfmt() const { return (fields[1] >> 26u) & 0xFu; }
[[nodiscard]] uint16_t Width() const { return (fields[2] >> 0u) & 0x3FFFu; }
[[nodiscard]] uint16_t Height() const { return (fields[2] >> 14u) & 0x3FFFu; }
[[nodiscard]] uint8_t PerfMod() const { return (fields[2] >> 28u) & 0x7u; }
[[nodiscard]] bool Interlaced() const { return ((fields[2] >> 31u) & 0x1u) == 1; }
[[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]] uint8_t BaseLevel() const { return (fields[3] >> 12u) & 0xFu; }
[[nodiscard]] uint8_t LastLevel() const { return (fields[3] >> 16u) & 0xFu; }
[[nodiscard]] uint8_t TilingIdx() const { return (fields[3] >> 20u) & 0x1Fu; }
[[nodiscard]] bool Pow2Pad() const { return ((fields[3] >> 25u) & 0x1u) == 1; }
[[nodiscard]] uint8_t Type() const { return (fields[3] >> 28u) & 0xFu; }
[[nodiscard]] uint16_t Depth() const { return (fields[4] >> 0u) & 0x1FFFu; }
[[nodiscard]] uint16_t Pitch() const { return (fields[4] >> 13u) & 0x3FFFu; }
[[nodiscard]] uint16_t BaseArray() const { return (fields[5] >> 0u) & 0x1FFFu; }
[[nodiscard]] uint16_t LastArray() const { return (fields[5] >> 13u) & 0x1FFFu; }
[[nodiscard]] uint16_t MinLodWarn() const { return (fields[6] >> 0u) & 0xFFFu; }
[[nodiscard]] uint8_t CounterBankId() const { return (fields[6] >> 12u) & 0xFFu; }
[[nodiscard]] bool LodHdwCntEn() const { return ((fields[6] >> 20u) & 0x1u) == 1; }
[[nodiscard]] uint8_t MemoryType() const
{
return ((fields[1] >> 6u) & 0x3u) | ((fields[1] >> 30u) << 2u) | ((fields[3] & 0x04000000u) == 0 ? 0x60u : 0x10u);
}
};
struct ShaderSamplerResource
{
uint32_t fields[4] = {0};
void UpdateIndex(uint32_t index) { fields[0] = index; }
[[nodiscard]] uint8_t ClampX() const { return (fields[0] >> 0u) & 0x7u; }
[[nodiscard]] uint8_t ClampY() const { return (fields[0] >> 3u) & 0x7u; }
[[nodiscard]] uint8_t ClampZ() const { return (fields[0] >> 6u) & 0x7u; }
[[nodiscard]] uint8_t MaxAnisoRatio() const { return (fields[0] >> 9u) & 0x7u; }
[[nodiscard]] uint8_t DepthCompareFunc() const { return (fields[0] >> 12u) & 0x7u; }
[[nodiscard]] bool ForceUnormCoords() const { return ((fields[0] >> 15u) & 0x1u) == 1; }
[[nodiscard]] uint8_t AnisoThreshold() const { return (fields[0] >> 16u) & 0x7u; }
[[nodiscard]] bool McCoordTrunc() const { return ((fields[0] >> 19u) & 0x1u) == 1; }
[[nodiscard]] bool ForceDegamma() const { return ((fields[0] >> 20u) & 0x1u) == 1; }
[[nodiscard]] uint8_t AnisoBias() const { return (fields[0] >> 21u) & 0x3Fu; }
[[nodiscard]] bool TruncCoord() const { return ((fields[0] >> 27u) & 0x1u) == 1; }
[[nodiscard]] bool DisableCubeWrap() const { return ((fields[0] >> 28u) & 0x1u) == 1; }
[[nodiscard]] uint8_t FilterMode() const { return (fields[0] >> 29u) & 0x3u; }
[[nodiscard]] uint16_t MinLod() const { return (fields[1] >> 0u) & 0xFFFu; }
[[nodiscard]] uint16_t MaxLod() const { return (fields[1] >> 12u) & 0xFFFu; }
[[nodiscard]] uint8_t PerfMip() const { return (fields[1] >> 24u) & 0xFu; }
[[nodiscard]] uint8_t PerfZ() const { return (fields[1] >> 28u) & 0xFu; }
[[nodiscard]] uint16_t LodBias() const { return (fields[2] >> 0u) & 0x3FFFu; }
[[nodiscard]] uint8_t LodBiasSec() const { return (fields[2] >> 14u) & 0x3Fu; }
[[nodiscard]] uint8_t XyMagFilter() const { return (fields[2] >> 20u) & 0x3u; }
[[nodiscard]] uint8_t XyMinFilter() const { return (fields[2] >> 22u) & 0x3u; }
[[nodiscard]] uint8_t ZFilter() const { return (fields[2] >> 24u) & 0x3u; }
[[nodiscard]] uint8_t MipFilter() const { return (fields[2] >> 26u) & 0x3u; }
[[nodiscard]] uint16_t BorderColorPtr() const { return (fields[3] >> 0u) & 0xFFFu; }
[[nodiscard]] uint8_t BorderColorType() const { return (fields[3] >> 30u) & 0x3u; }
};
struct ShaderGdsResource
{
uint32_t field = 0;
[[nodiscard]] uint16_t Base() const { return (field >> 16u) & 0xFFFFu; }
[[nodiscard]] uint16_t Size() const { return field & 0xFFFFu; }
};
struct ShaderExtendedResource
{
uint32_t fields[2] = {0};
void UpdateAddress(uint64_t gpu_addr)
{
auto lo = static_cast<uint32_t>(gpu_addr & 0xffffffffu);
auto hi = static_cast<uint32_t>(gpu_addr >> 32u);
fields[0] = lo;
fields[1] = hi;
}
[[nodiscard]] uint64_t Base() const { return (fields[0] | (static_cast<uint64_t>(fields[1]) << 32u)); }
};
struct ShaderVertexInputBuffer
{
static constexpr int ATTR_MAX = 16;
uint64_t addr = 0;
uint32_t stride = 0;
uint32_t num_records = 0;
int attr_num = 0;
int attr_indices[ATTR_MAX] = {0};
uint32_t attr_offsets[ATTR_MAX] = {0};
};
struct ShaderVertexDestination
{
int register_start = 0;
int registers_num = 0;
};
enum class ShaderStorageUsage
{
Unknown,
Constant,
ReadOnly,
ReadWrite,
};
struct ShaderStorageResources
{
static constexpr int BUFFERS_MAX = 16;
ShaderBufferResource buffers[BUFFERS_MAX];
ShaderStorageUsage usages[BUFFERS_MAX] = {};
int slots[BUFFERS_MAX] = {0};
int start_register[BUFFERS_MAX] = {0};
bool extended[BUFFERS_MAX] = {};
// int extended_index[BUFFERS_MAX] = {0};
int buffers_num = 0;
int binding_index = 0;
};
struct ShaderTextureResources
{
static constexpr int RES_MAX = 16;
ShaderTextureResource textures[RES_MAX];
int start_register[RES_MAX] = {0};
bool extended[RES_MAX] = {};
// int extended_index[RES_MAX] = {0};
int textures_num = 0;
int binding_index = 0;
};
struct ShaderSamplerResources
{
static constexpr int RES_MAX = 16;
ShaderSamplerResource samplers[RES_MAX];
int start_register[RES_MAX] = {0};
bool extended[RES_MAX] = {};
// int extended_index[RES_MAX] = {0};
int samplers_num = 0;
int binding_index = 0;
};
struct ShaderGdsResources
{
static constexpr int POINTERS_MAX = 1;
ShaderGdsResource pointers[POINTERS_MAX];
int slots[POINTERS_MAX] = {0};
int start_register[POINTERS_MAX] = {0};
bool extended[POINTERS_MAX] = {};
// int extended_index[POINTERS_MAX] = {0};
int pointers_num = 0;
int binding_index = 0;
};
struct ShaderExtendedResources
{
bool used = false;
int slot = 0;
// int dw_num = 0;
int start_register = 0;
ShaderExtendedResource data;
};
struct ShaderResources
{
uint32_t push_constant_offset = 0;
uint32_t push_constant_size = 0;
uint32_t descriptor_set_slot = 0;
ShaderStorageResources storage_buffers;
ShaderTextureResources textures2D;
ShaderSamplerResources samplers;
ShaderGdsResources gds_pointers;
ShaderExtendedResources extended;
};
struct ShaderVertexInputInfo
{
static constexpr int RES_MAX = 16;
ShaderBufferResource resources[RES_MAX];
ShaderVertexDestination resources_dst[RES_MAX];
int resources_num = 0;
bool fetch = false;
ShaderVertexInputBuffer buffers[RES_MAX];
int buffers_num = 0;
int export_count = 0;
ShaderResources bind;
};
struct ShaderComputeInputInfo
{
uint32_t threads_num[3] = {};
int workgroup_register = 0;
ShaderResources bind;
};
struct ShaderPixelInputInfo
{
uint32_t interpolator_settings[32] = {0};
uint32_t input_num = 0;
uint8_t target_output_mode[8] = {};
bool ps_pos_xy = false;
bool ps_pixel_kill_enable = false;
ShaderResources bind;
};
void ShaderGetInputInfoVS(const VertexShaderInfo* regs, ShaderVertexInputInfo* info);
void ShaderGetInputInfoPS(const PixelShaderInfo* regs, const ShaderVertexInputInfo* vs_info, ShaderPixelInputInfo* ps_info);
void ShaderGetInputInfoCS(const ComputeShaderInfo* regs, ShaderComputeInputInfo* info);
void ShaderDbgDumpInputInfo(const ShaderVertexInputInfo* info);
void ShaderDbgDumpInputInfo(const ShaderPixelInputInfo* info);
void ShaderDbgDumpInputInfo(const ShaderComputeInputInfo* info);
ShaderId ShaderGetIdVS(const VertexShaderInfo* regs, const ShaderVertexInputInfo* input_info);
ShaderId ShaderGetIdPS(const PixelShaderInfo* regs, const ShaderPixelInputInfo* input_info);
ShaderId ShaderGetIdCS(const ComputeShaderInfo* regs, const ShaderComputeInputInfo* input_info);
Vector<uint32_t> ShaderRecompileVS(const VertexShaderInfo* regs, const ShaderVertexInputInfo* input_info);
Vector<uint32_t> ShaderRecompilePS(const PixelShaderInfo* regs, const ShaderPixelInputInfo* input_info);
Vector<uint32_t> ShaderRecompileCS(const ComputeShaderInfo* regs, const ShaderComputeInputInfo* input_info);
bool ShaderIsDisabled(uint64_t addr);
void ShaderDisable(uint64_t id);
} // namespace Kyty::Libs::Graphics
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_H_ */
@@ -0,0 +1,26 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADERSPIRV_H_
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADERSPIRV_H_
#include "Kyty/Core/Common.h"
#include "Kyty/Core/String.h"
#include "Emulator/Common.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Libs::Graphics {
class ShaderCode;
struct ShaderVertexInputInfo;
struct ShaderPixelInputInfo;
struct ShaderComputeInputInfo;
String SpirvGenerateSource(const ShaderCode& code, const ShaderVertexInputInfo* vs_input_info, const ShaderPixelInputInfo* ps_input_info,
const ShaderComputeInputInfo* cs_input_info);
String SpirvGetEmbeddedVs(uint32_t id);
} // namespace Kyty::Libs::Graphics
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADERSPIRV_H_ */
@@ -0,0 +1,40 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_STORAGEBUFFER_H_
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_STORAGEBUFFER_H_
#include "Kyty/Core/Common.h"
#include "Emulator/Common.h"
#include "Emulator/Graphics/GpuMemory.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Libs::Graphics {
struct GraphicContext;
struct VulkanMemory;
class StorageBufferGpuObject: public GpuObject
{
public:
StorageBufferGpuObject(uint64_t stride, uint64_t num_records, bool ronly)
{
params[0] = stride;
params[1] = num_records;
check_hash = true;
read_only = ronly;
type = Graphics::GpuMemoryObjectType::StorageBuffer;
}
void* Create(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, VulkanMemory* mem) const override;
bool Equal(const uint64_t* other) const override;
[[nodiscard]] write_back_func_t GetWriteBackFunc() const override;
[[nodiscard]] delete_func_t GetDeleteFunc() const override;
[[nodiscard]] update_func_t GetUpdateFunc() const override;
};
} // namespace Kyty::Libs::Graphics
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_STORAGEBUFFER_H_ */
@@ -0,0 +1,54 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_TEXTURE_H_
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_TEXTURE_H_
#include "Kyty/Core/Common.h"
#include "Emulator/Common.h"
#include "Emulator/Graphics/GpuMemory.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Libs::Graphics {
struct GraphicContext;
struct VulkanMemory;
class TextureObject: public GpuObject
{
public:
static constexpr int PARAM_DFMT = 0;
static constexpr int PARAM_NFMT = 1;
static constexpr int PARAM_WIDTH = 2;
static constexpr int PARAM_HEIGHT = 3;
static constexpr int PARAM_LEVELS = 4;
static constexpr int PARAM_TILE = 5;
static constexpr int PARAM_NEO = 6;
static constexpr int PARAM_SWIZZLE = 7;
TextureObject(uint32_t dfmt, uint32_t nfmt, uint32_t width, uint32_t height, uint32_t levels, bool htile, bool neo, uint32_t swizzle)
{
params[PARAM_DFMT] = dfmt;
params[PARAM_NFMT] = nfmt;
params[PARAM_WIDTH] = width;
params[PARAM_HEIGHT] = height;
params[PARAM_LEVELS] = levels;
params[PARAM_TILE] = htile ? 1 : 0;
params[PARAM_NEO] = neo ? 1 : 0;
params[PARAM_SWIZZLE] = swizzle;
check_hash = true;
type = Graphics::GpuMemoryObjectType::Texture;
}
void* Create(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, VulkanMemory* mem) const override;
bool Equal(const uint64_t* other) const override;
[[nodiscard]] write_back_func_t GetWriteBackFunc() const override { return nullptr; };
[[nodiscard]] delete_func_t GetDeleteFunc() const override;
[[nodiscard]] update_func_t GetUpdateFunc() const override;
};
} // namespace Kyty::Libs::Graphics
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_TEXTURE_H_ */
@@ -0,0 +1,35 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_TILE_H_
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_TILE_H_
#include "Kyty/Core/Common.h"
#include "Emulator/Common.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Libs::Graphics {
enum class TileMode
{
VideoOutLinear,
VideoOutTiled,
TextureLinear,
TextureTiled,
};
void TileInit();
void TileConvertTiledToLinear(void* dst, const void* src, TileMode mode, uint32_t width, uint32_t height, bool neo);
void TileConvertTiledToLinear(void* dst, const void* src, TileMode mode, uint32_t dfmt, uint32_t nfmt, uint32_t width, uint32_t height,
uint32_t levels, bool neo);
void TileGetDepthSize(uint32_t width, uint32_t height, uint32_t z_format, uint32_t stencil_format, bool htile, bool neo,
uint32_t* stencil_size, uint32_t* htile_size, uint32_t* depth_size, uint32_t* pitch);
void TileGetVideoOutSize(uint32_t width, uint32_t height, bool tile, bool neo, uint32_t* size);
void TileGetTextureSize(uint32_t dfmt, uint32_t nfmt, uint32_t width, uint32_t height, uint32_t levels, bool tile, bool neo,
uint32_t* total_size, uint32_t* level_sizes, uint32_t* padded_width, uint32_t* padded_height);
} // namespace Kyty::Libs::Graphics
#endif
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_TILE_H_ */
@@ -0,0 +1,50 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_UTILS_H_
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_UTILS_H_
#include "Kyty/Core/Common.h"
#include "Emulator/Common.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty {
template <typename T>
class Vector;
} // namespace Kyty
namespace Kyty::Libs::Graphics {
class CommandBuffer;
struct GraphicContext;
struct VulkanBuffer;
struct VideoOutVulkanImage;
struct TextureVulkanImage;
struct DepthStencilVulkanImage;
struct VulkanSwapchain;
struct BufferImageCopy
{
uint32_t offset;
uint32_t width;
uint32_t height;
};
void UtilBufferToImage(CommandBuffer* buffer, VulkanBuffer* src_buffer, VideoOutVulkanImage* dst_image);
void UtilBufferToImage(CommandBuffer* buffer, VulkanBuffer* src_buffer, TextureVulkanImage* dst_image,
const Vector<BufferImageCopy>& regions);
void UtilBlitImage(CommandBuffer* buffer, VideoOutVulkanImage* src_image, VulkanSwapchain* dst_swapchain);
void UtilFillImage(GraphicContext* ctx, VideoOutVulkanImage* dst_image, const void* src_data, uint64_t size);
void UtilFillImage(GraphicContext* ctx, TextureVulkanImage* dst_image, const void* src_data, uint64_t size,
const Vector<BufferImageCopy>& regions);
void UtilCopyBuffer(VulkanBuffer* src_buffer, VulkanBuffer* dst_buffer, uint64_t size);
void UtilSetImageLayoutOptimal(DepthStencilVulkanImage* image);
void UtilSetImageLayoutOptimal(VideoOutVulkanImage* image);
void VulkanCreateBuffer(GraphicContext* gctx, uint64_t size, VulkanBuffer* buffer);
void VulkanDeleteBuffer(GraphicContext* gctx, VulkanBuffer* buffer);
} // namespace Kyty::Libs::Graphics
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_UTILS_H_ */
@@ -0,0 +1,37 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_VERTEXBUFFER_H_
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_VERTEXBUFFER_H_
#include "Kyty/Core/Common.h"
#include "Emulator/Common.h"
#include "Emulator/Graphics/GpuMemory.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Libs::Graphics {
struct GraphicContext;
struct VulkanMemory;
class VertexBufferGpuObject: public GpuObject
{
public:
VertexBufferGpuObject()
{
check_hash = true;
type = Graphics::GpuMemoryObjectType::VertexBuffer;
}
void* Create(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, VulkanMemory* mem) const override;
bool Equal(const uint64_t* other) const override;
[[nodiscard]] write_back_func_t GetWriteBackFunc() const override { return nullptr; };
[[nodiscard]] delete_func_t GetDeleteFunc() const override;
[[nodiscard]] update_func_t GetUpdateFunc() const override;
};
} // namespace Kyty::Libs::Graphics
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_VERTEXBUFFER_H_ */
@@ -0,0 +1,52 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_VIDEOOUT_H_
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_VIDEOOUT_H_
#include "Kyty/Core/Common.h"
//#include "Kyty/Core/Subsystems.h"
#include "Emulator/Common.h"
#include "Emulator/Kernel/EventQueue.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Libs::Graphics {
// struct VulkanSwapchain;
struct VideoOutVulkanImage;
} // namespace Kyty::Libs::Graphics
namespace Kyty::Libs::VideoOut {
struct VideoOutResolutionStatus;
struct VideoOutBufferAttribute;
struct VideoOutFlipStatus;
struct VideoOutBufferImageInfo
{
Graphics::VideoOutVulkanImage* image = nullptr;
uint32_t index = static_cast<uint32_t>(-1);
uint64_t buffer_size = 0;
};
void VideoOutInit(uint32_t width, uint32_t height);
VideoOutBufferImageInfo VideoOutGetImage(uint64_t addr);
void VideoOutWaitFlipDone(int handle, int index);
KYTY_SYSV_ABI int VideoOutOpen(int user_id, int bus_type, int index, const void* param);
KYTY_SYSV_ABI int VideoOutClose(int handle);
KYTY_SYSV_ABI int VideoOutGetResolutionStatus(int handle, VideoOutResolutionStatus* status);
KYTY_SYSV_ABI void VideoOutSetBufferAttribute(VideoOutBufferAttribute* attribute, uint32_t pixel_format, uint32_t tiling_mode,
uint32_t aspect_ratio, uint32_t width, uint32_t height, uint32_t pitch_in_pixel);
KYTY_SYSV_ABI int VideoOutSetFlipRate(int handle, int rate);
KYTY_SYSV_ABI int VideoOutAddFlipEvent(LibKernel::EventQueue::KernelEqueue eq, int handle, void* udata);
KYTY_SYSV_ABI int VideoOutRegisterBuffers(int handle, int start_index, void* const* addresses, int buffer_num,
const VideoOutBufferAttribute* attribute);
KYTY_SYSV_ABI int VideoOutSubmitFlip(int handle, int index, int flip_mode, int64_t flip_arg);
KYTY_SYSV_ABI int VideoOutGetFlipStatus(int handle, VideoOutFlipStatus* status);
bool FlipWindow(uint32_t micros);
} // namespace Kyty::Libs::VideoOut
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_VIDEOOUT_H_ */
@@ -0,0 +1,48 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_VIDEOOUTBUFFER_H_
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_VIDEOOUTBUFFER_H_
#include "Kyty/Core/Common.h"
#include "Emulator/Common.h"
#include "Emulator/Graphics/GpuMemory.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Libs::Graphics {
struct GraphicContext;
struct VulkanMemory;
class VideoOutBufferObject: public GpuObject
{
public:
static constexpr int PARAM_FORMAT = 0;
static constexpr int PARAM_WIDTH = 1;
static constexpr int PARAM_HEIGHT = 2;
static constexpr int PARAM_TILED = 3;
static constexpr int PARAM_NEO = 4;
explicit VideoOutBufferObject(uint32_t pixel_format, uint32_t width, uint32_t height, bool tiled, bool neo)
{
params[PARAM_FORMAT] = pixel_format;
params[PARAM_WIDTH] = width;
params[PARAM_HEIGHT] = height;
params[PARAM_TILED] = tiled ? 1 : 0;
params[PARAM_NEO] = neo ? 1 : 0;
check_hash = true;
type = Graphics::GpuMemoryObjectType::VideoOutBuffer;
}
void* Create(GraphicContext* ctx, const uint64_t* vaddr, const uint64_t* size, int vaddr_num, VulkanMemory* mem) const override;
bool Equal(const uint64_t* other) const override;
[[nodiscard]] write_back_func_t GetWriteBackFunc() const override { return nullptr; };
[[nodiscard]] delete_func_t GetDeleteFunc() const override;
[[nodiscard]] update_func_t GetUpdateFunc() const override;
};
} // namespace Kyty::Libs::Graphics
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_VIDEOOUTBUFFER_H_ */
@@ -0,0 +1,30 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_WINDOW_H_
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_WINDOW_H_
#include "Kyty/Core/Common.h"
#include "Emulator/Common.h"
#ifdef KYTY_EMU_ENABLED
struct VkSurfaceCapabilitiesKHR;
namespace Kyty::Libs::Graphics {
struct GraphicContext;
struct VideoOutVulkanImage;
VkSurfaceCapabilitiesKHR* VulkanGetSurfaceCapabilities();
GraphicContext* WindowGetGraphicContext();
void WindowInit(uint32_t width, uint32_t height);
void WindowRun();
void WindowWaitForGraphicInitialized();
void WindowDrawBuffer(VideoOutVulkanImage* image);
} // namespace Kyty::Libs::Graphics
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_WINDOW_H_ */
+150
View File
@@ -0,0 +1,150 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_JIT_H_
#define EMULATOR_INCLUDE_EMULATOR_JIT_H_
#include "Emulator/Common.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Loader::Jit {
#pragma pack(1)
struct JmpWithIndex
{
void SetIndex(uint32_t index) { *reinterpret_cast<uint32_t*>(&code[1]) = index; }
void SetFunc(void* handler)
{
auto func_addr = reinterpret_cast<int64_t>(handler);
auto rip_addr = reinterpret_cast<int64_t>(&code[10]);
auto offset64 = func_addr - rip_addr;
auto offset32 = static_cast<uint32_t>(static_cast<uint64_t>(offset64) & 0xffffffffu);
*reinterpret_cast<uint32_t*>(&code[6]) = offset32;
}
static uint64_t GetSize() { return 16; }
// 68 00 00 00 00 push <index>
// E9 E0 FF FF FF jmp <handler>
uint8_t code[16] = {0x68, 0x00, 0x00, 0x00, 0x00, 0xE9, 0x00, 0x00, 0x00, 0x00, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90};
};
struct CallPlt
{
explicit CallPlt(uint32_t table_size)
{
for (uint32_t index = 0; index < table_size; index++)
{
auto* c = new (&code[32] + JmpWithIndex::GetSize() * index) JmpWithIndex;
c->SetIndex(index);
c->SetFunc(this);
}
}
void SetPltGot(uint64_t vaddr) { *reinterpret_cast<uint64_t*>(&code[2]) = vaddr; }
uint64_t GetAddr(uint32_t index) { return reinterpret_cast<uint64_t>(&code[32] + JmpWithIndex::GetSize() * index); }
static uint64_t GetSize(uint32_t table_size) { return 32 + JmpWithIndex::GetSize() * table_size; }
// 0: 49 bb 88 77 66 55 44 movabs r11,0x1122334455667788
// 7: 33 22 11
// a: 41 ff 73 08 push QWORD PTR [r11+0x8]
// e: 41 ff 63 10 jmp QWORD PTR [r11+0x10]
uint8_t code[32] = {0x49, 0xBB, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x41, 0xFF,
0x73, 0x08, 0x41, 0xFF, 0x63, 0x10, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90};
};
struct JmpRax
{
template <class Handler>
void SetFunc(Handler func)
{
*reinterpret_cast<Handler*>(&code[2]) = func;
}
// mov rax, 0x1122334455667788
// jmp rax
uint8_t code[16] = {0x48, 0xB8, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0xFF, 0xE0};
};
struct Call9
{
template <class Handler>
void SetFunc(Handler func)
{
auto func_addr = reinterpret_cast<int64_t>(reinterpret_cast<void*>(func));
auto rip_addr = reinterpret_cast<int64_t>(&code[5]);
auto offset64 = func_addr - rip_addr;
auto offset32 = static_cast<uint32_t>(static_cast<uint64_t>(offset64) & 0xffffffffu);
*reinterpret_cast<uint32_t*>(&code[1]) = offset32;
}
static uint64_t GetSize() { return 9; }
// call func
// mov rax,rax
// nop
uint8_t code[9] = {0xE8, 0x00, 0x00, 0x00, 0x00, 0x48, 0x89, 0xC0, 0x90};
};
struct SafeCall
{
using func_t = KYTY_MS_ABI uint8_t* (*)();
void SetFunc(func_t func) { *reinterpret_cast<func_t*>(&code[0x22]) = func; }
void SetRegSaveArea(uint8_t* area) { *reinterpret_cast<uint8_t**>(&code[0x18]) = area; }
void SetLockVar(uint8_t* lock_var) { *reinterpret_cast<uint8_t**>(&code[0x0e]) = lock_var; }
static uint64_t GetSize() { return 0x1000; }
uint8_t code[0x6c] = {
/*00*/ 0x51, // push rcx /* Save general purpose registers */
/*01*/ 0x52, // push rdx
/*02*/ 0x41, 0x50, // push r8
/*04*/ 0x41, 0x51, // push r9
/*06*/ 0x41, 0x52, // push r10
/*08*/ 0x41, 0x53, // push r11
/*0a*/ 0x57, // push rdi
/*0b*/ 0x56, // push rsi
/*0c*/ 0x48, 0xbf, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, // movabs rdi,0x1122334455667788
/*16*/ 0x48, 0xbe, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, // movabs rsi,0x1122334455667788
/*20*/ 0x48, 0xb9, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, // movabs rcx,0x1122334455667788
/*2a*/ 0xb0, 0x01, // mov al,0x1 /* Lock */
/*2c*/ 0x86, 0x07, // xchg BYTE PTR [rdi],al
/*2e*/ 0x84, 0xc0, // test al,al
/*30*/ 0x75, 0xf8, // jne 2a <LOCK>
/*32*/ 0xb8, 0xff, 0xff, 0xff, 0xff, // mov eax,0xffffffff
/*37*/ 0xba, 0xff, 0xff, 0xff, 0xff, // mov edx,0xffffffff
/*3c*/ 0x0f, 0xae, 0x26, // xsave [rsi] /* Save float registers */
/*3f*/ 0x48, 0x83, 0xec, 0x08, // sub rsp,0x8 /* Align stack */
/*43*/ 0xff, 0xd1, // call rcx
/*45*/ 0x48, 0x83, 0xc4, 0x08, // add rsp,0x8
/*49*/ 0x48, 0x89, 0xc1, // mov rcx,rax
/*4c*/ 0xb8, 0xff, 0xff, 0xff, 0xff, // mov eax,0xffffffff
/*51*/ 0xba, 0xff, 0xff, 0xff, 0xff, // mov edx,0xffffffff
/*56*/ 0x0f, 0xae, 0x2e, // xrstor [rsi] /* Restore float registers */
/*59*/ 0x48, 0x89, 0xc8, // mov rax,rcx
/*5c*/ 0xc6, 0x07, 0x00, // mov BYTE PTR [rdi],0x0 /* Unlock */
/*5f*/ 0x5e, // pop rsi /* Restore general purpose registers */
/*60*/ 0x5f, // pop rdi
/*61*/ 0x41, 0x5b, // pop r11
/*63*/ 0x41, 0x5a, // pop r10
/*65*/ 0x41, 0x59, // pop r9
/*67*/ 0x41, 0x58, // pop r8
/*69*/ 0x5a, // pop rdx
/*6a*/ 0x59, // pop rcx
/*6b*/ 0xc3, // ret
};
};
#pragma pack()
} // namespace Kyty::Loader::Jit
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_JIT_H_ */
@@ -0,0 +1,30 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_KERNEL_EVENTFLAG_H_
#define EMULATOR_INCLUDE_EMULATOR_KERNEL_EVENTFLAG_H_
#include "Kyty/Core/Common.h"
#include "Emulator/Common.h"
#include "Emulator/Kernel/Pthread.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Libs::LibKernel::EventFlag {
class KernelEventFlagPrivate;
using KernelEventFlag = KernelEventFlagPrivate*;
int KYTY_SYSV_ABI KernelCreateEventFlag(KernelEventFlag* ef, const char* name, uint32_t attr, uint64_t init_pattern, const void* param);
int KYTY_SYSV_ABI KernelDeleteEventFlag(KernelEventFlag ef);
int KYTY_SYSV_ABI KernelWaitEventFlag(KernelEventFlag ef, uint64_t bit_pattern, uint32_t wait_mode, uint64_t* result_pat,
KernelUseconds* timeout);
int KYTY_SYSV_ABI KernelPollEventFlag(KernelEventFlag ef, uint64_t bit_pattern, uint32_t wait_mode, uint64_t* result_pat);
int KYTY_SYSV_ABI KernelSetEventFlag(KernelEventFlag ef, uint64_t bit_pattern);
int KYTY_SYSV_ABI KernelClearEventFlag(KernelEventFlag ef, uint64_t bit_pattern);
int KYTY_SYSV_ABI KernelCancelEventFlag(KernelEventFlag ef, uint64_t set_pattern, int* num_wait_threads);
} // namespace Kyty::Libs::LibKernel::EventFlag
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_KERNEL_EVENTFLAG_H_ */
@@ -0,0 +1,75 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_KERNEL_EVENTQUEUE_H_
#define EMULATOR_INCLUDE_EMULATOR_KERNEL_EVENTQUEUE_H_
#include "Kyty/Core/Common.h"
#include "Emulator/Common.h"
#include "Emulator/Kernel/Pthread.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Libs::LibKernel::EventQueue {
constexpr int16_t KERNEL_EVFILT_TIMER = -7;
constexpr int16_t KERNEL_EVFILT_READ = -1;
constexpr int16_t KERNEL_EVFILT_WRITE = -2;
constexpr int16_t KERNEL_EVFILT_USER = -11;
constexpr int16_t KERNEL_EVFILT_FILE = -4;
constexpr int16_t KERNEL_EVFILT_GRAPHICS = -14;
constexpr int16_t KERNEL_EVFILT_VIDEO_OUT = -13;
constexpr int16_t KERNEL_EVFILT_HRTIMER = -15;
class KernelEqueuePrivate;
struct KernelEqueueEvent;
using trigger_func_t = void (*)(KernelEqueueEvent* event, void* trigger_data);
using reset_func_t = void (*)(KernelEqueueEvent* event);
using delete_func_t = void (*)(KernelEqueueEvent* event);
struct KernelEvent
{
uintptr_t ident = 0;
int16_t filter = 0;
uint16_t flags = 0;
uint32_t fflags = 0;
intptr_t data = 0;
void* udata = nullptr;
};
struct KernelFilter
{
void* data = nullptr;
trigger_func_t trigger_func = nullptr;
reset_func_t reset_func = nullptr;
delete_func_t delete_func = nullptr;
};
struct KernelEqueueEvent
{
bool triggered = false;
KernelEvent event;
KernelFilter filter;
};
using KernelEqueue = KernelEqueuePrivate*;
int KYTY_SYSV_ABI KernelAddEvent(KernelEqueue eq, const KernelEqueueEvent& event);
int KYTY_SYSV_ABI KernelTriggerEvent(KernelEqueue eq, uintptr_t ident, int16_t filter, void* trigger_data);
int KYTY_SYSV_ABI KernelDeleteEvent(KernelEqueue eq, uintptr_t ident, int16_t filter);
int KYTY_SYSV_ABI KernelCreateEqueue(KernelEqueue* eq, const char* name);
int KYTY_SYSV_ABI KernelDeleteEqueue(KernelEqueue eq);
int KYTY_SYSV_ABI KernelWaitEqueue(KernelEqueue eq, KernelEvent* ev, int num, int* out, const KernelUseconds* timo);
intptr_t KYTY_SYSV_ABI KernelGetEventData(const KernelEvent* ev);
intptr_t KYTY_SYSV_ABI KernelGetEventFflags(const KernelEvent* ev);
int KYTY_SYSV_ABI KernelGetEventFilter(const KernelEvent* ev);
uintptr_t KYTY_SYSV_ABI KernelGetEventId(const KernelEvent* ev);
void* KYTY_SYSV_ABI KernelGetEventUserData(const KernelEvent* ev);
int KYTY_SYSV_ABI KernelGetEventError(const KernelEvent* ev);
} // namespace Kyty::Libs::LibKernel::EventQueue
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_KERNEL_EVENTQUEUE_H_ */
@@ -0,0 +1,60 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_KERNEL_FILESYSTEM_H_
#define EMULATOR_INCLUDE_EMULATOR_KERNEL_FILESYSTEM_H_
#include "Kyty/Core/Common.h"
#include "Kyty/Core/String.h"
#include "Kyty/Core/Subsystems.h"
#include "Emulator/Common.h"
#include "Emulator/Kernel/Pthread.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Libs::LibKernel::FileSystem {
struct FileStat
{
uint32_t st_dev;
uint32_t st_ino;
uint16_t st_mode;
uint16_t st_nlink;
uint32_t st_uid;
uint32_t st_gid;
uint32_t st_rdev;
KernelTimespec st_atim;
KernelTimespec st_mtim;
KernelTimespec st_ctim;
int64_t st_size;
int64_t st_blocks;
uint32_t st_blksize;
uint32_t st_flags;
uint32_t st_gen;
int32_t st_lspare;
KernelTimespec st_birthtim;
unsigned int: (8 / 2) * (16 - static_cast<int>(sizeof(KernelTimespec)));
unsigned int: (8 / 2) * (16 - static_cast<int>(sizeof(KernelTimespec)));
};
KYTY_SUBSYSTEM_DEFINE(FileSystem);
void Mount(const String& folder, const String& point);
void Umount(const String& folder_or_point);
String GetRealFilename(const String& mounted_file_name);
int KYTY_SYSV_ABI KernelOpen(const char* path, int flags, uint16_t mode);
int KYTY_SYSV_ABI KernelClose(int d);
int64_t KYTY_SYSV_ABI KernelRead(int d, void* buf, size_t nbytes);
int64_t KYTY_SYSV_ABI KernelPread(int d, void* buf, size_t nbytes, int64_t offset);
int64_t KYTY_SYSV_ABI KernelWrite(int d, const void* buf, size_t nbytes);
int64_t KYTY_SYSV_ABI KernelPwrite(int d, const void* buf, size_t nbytes, int64_t offset);
int64_t KYTY_SYSV_ABI KernelLseek(int d, int64_t offset, int whence);
int KYTY_SYSV_ABI KernelStat(const char* path, FileStat* sb);
int KYTY_SYSV_ABI KernelFstat(int d, FileStat* sb);
int KYTY_SYSV_ABI KernelUnlink(const char* path);
int KYTY_SYSV_ABI KernelGetdirentries(int fd, char* buf, int nbytes, int64_t* basep);
} // namespace Kyty::Libs::LibKernel::FileSystem
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_KERNEL_FILESYSTEM_H_ */
@@ -0,0 +1,28 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_KERNEL_MEMORY_H_
#define EMULATOR_INCLUDE_EMULATOR_KERNEL_MEMORY_H_
#include "Kyty/Core/Common.h"
#include "Kyty/Core/Subsystems.h"
#include "Emulator/Common.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Libs::LibKernel::Memory {
KYTY_SUBSYSTEM_DEFINE(Memory);
int KYTY_SYSV_ABI KernelMapNamedFlexibleMemory(void** addr_in_out, size_t len, int prot, int flags, const char* name);
int KYTY_SYSV_ABI KernelMunmap(uint64_t vaddr, size_t len);
size_t KYTY_SYSV_ABI KernelGetDirectMemorySize();
int KYTY_SYSV_ABI KernelAllocateDirectMemory(int64_t search_start, int64_t search_end, size_t len, size_t alignment, int memory_type,
int64_t* phys_addr_out);
int KYTY_SYSV_ABI KernelReleaseDirectMemory(int64_t start, size_t len);
int KYTY_SYSV_ABI KernelMapDirectMemory(void** addr, size_t len, int prot, int flags, int64_t direct_memory_start, size_t alignment);
int KYTY_SYSV_ABI KernelQueryMemoryProtection(void* addr, void** start, void** end, int* prot);
} // namespace Kyty::Libs::LibKernel::Memory
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_KERNEL_MEMORY_H_ */
@@ -0,0 +1,159 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_KERNEL_PTHREAD_H_
#define EMULATOR_INCLUDE_EMULATOR_KERNEL_PTHREAD_H_
#include "Kyty/Core/Common.h"
#include "Kyty/Core/Subsystems.h"
#include "Emulator/Common.h"
// IWYU pragma: no_include <pthread.h>
#ifdef KYTY_EMU_ENABLED
extern "C" {
struct sched_param;
}
namespace Kyty::Loader {
struct Program;
} // namespace Kyty::Loader
namespace Kyty::Libs::LibKernel {
KYTY_SUBSYSTEM_DEFINE(Pthread);
struct PthreadAttrPrivate;
struct PthreadPrivate;
struct PthreadMutexPrivate;
struct PthreadMutexattrPrivate;
struct PthreadRwlockPrivate;
struct PthreadRwlockattrPrivate;
struct PthreadCondattrPrivate;
struct PthreadCondPrivate;
struct KernelTimespec
{
int64_t tv_sec;
int64_t tv_nsec;
};
struct KernelTimeval
{
int64_t tv_sec;
int64_t tv_usec;
};
using PthreadAttr = PthreadAttrPrivate*;
using Pthread = PthreadPrivate*;
using KernelCpumask = uint64_t;
using PthreadMutex = PthreadMutexPrivate*;
using PthreadMutexattr = PthreadMutexattrPrivate*;
using KernelSchedParam = struct sched_param;
using PthreadRwlock = PthreadRwlockPrivate*;
using PthreadRwlockattr = PthreadRwlockattrPrivate*;
using KernelUseconds = unsigned int;
using PthreadCondattr = PthreadCondattrPrivate*;
using PthreadCond = PthreadCondPrivate*;
using KernelClockid = int32_t;
using pthread_entry_func_t = KYTY_SYSV_ABI void* (*)(void*);
using thread_dtors_func_t = KYTY_SYSV_ABI void (*)();
void PthreadInitSelfForMainThread();
void PthreadDeleteStaticObjects(Loader::Program* program);
int KYTY_SYSV_ABI PthreadMutexattrInit(PthreadMutexattr* attr);
int KYTY_SYSV_ABI PthreadMutexattrDestroy(PthreadMutexattr* attr);
int KYTY_SYSV_ABI PthreadMutexattrSettype(PthreadMutexattr* attr, int type);
int KYTY_SYSV_ABI PthreadMutexattrSetprotocol(PthreadMutexattr* attr, int protocol);
int KYTY_SYSV_ABI PthreadMutexInit(PthreadMutex* mutex, const PthreadMutexattr* attr, const char* name);
int KYTY_SYSV_ABI PthreadMutexDestroy(PthreadMutex* mutex);
int KYTY_SYSV_ABI PthreadMutexLock(PthreadMutex* mutex);
int KYTY_SYSV_ABI PthreadMutexTrylock(PthreadMutex* mutex);
int KYTY_SYSV_ABI PthreadMutexUnlock(PthreadMutex* mutex);
Pthread KYTY_SYSV_ABI PthreadSelf();
int KYTY_SYSV_ABI PthreadCreate(Pthread* thread, const PthreadAttr* attr, pthread_entry_func_t entry, void* arg, const char* name);
int KYTY_SYSV_ABI PthreadDetach(Pthread thread);
int KYTY_SYSV_ABI PthreadJoin(Pthread thread, void** value);
int KYTY_SYSV_ABI PthreadCancel(Pthread thread);
int KYTY_SYSV_ABI PthreadSetcancelstate(int state, int* old_state);
int KYTY_SYSV_ABI PthreadSetcanceltype(int type, int* old_type);
void KYTY_SYSV_ABI PthreadTestcancel();
void KYTY_SYSV_ABI PthreadExit(void* value);
int KYTY_SYSV_ABI PthreadEqual(Pthread thread1, Pthread thread2);
int KYTY_SYSV_ABI PthreadGetname(Pthread thread, char* name);
int KYTY_SYSV_ABI KernelUsleep(KernelUseconds microseconds);
unsigned int KYTY_SYSV_ABI KernelSleep(unsigned int seconds);
int KYTY_SYSV_ABI KernelNanosleep(const KernelTimespec* rqtp, KernelTimespec* rmtp);
void KYTY_SYSV_ABI KernelSetThreadDtors(thread_dtors_func_t dtors);
int KYTY_SYSV_ABI PthreadAttrInit(PthreadAttr* attr);
int KYTY_SYSV_ABI PthreadAttrDestroy(PthreadAttr* attr);
int KYTY_SYSV_ABI PthreadAttrGet(Pthread thread, PthreadAttr* attr);
int KYTY_SYSV_ABI PthreadAttrGetaffinity(const PthreadAttr* attr, KernelCpumask* mask);
int KYTY_SYSV_ABI PthreadAttrGetdetachstate(const PthreadAttr* attr, int* state);
int KYTY_SYSV_ABI PthreadAttrGetguardsize(const PthreadAttr* attr, size_t* guard_size);
int KYTY_SYSV_ABI PthreadAttrGetinheritsched(const PthreadAttr* attr, int* inherit_sched);
int KYTY_SYSV_ABI PthreadAttrGetschedparam(const PthreadAttr* attr, KernelSchedParam* param);
int KYTY_SYSV_ABI PthreadAttrGetschedpolicy(const PthreadAttr* attr, int* policy);
int KYTY_SYSV_ABI PthreadAttrGetstack(const PthreadAttr* __restrict attr, void** __restrict stack_addr, size_t* __restrict stack_size);
int KYTY_SYSV_ABI PthreadAttrGetstackaddr(const PthreadAttr* attr, void** stack_addr);
int KYTY_SYSV_ABI PthreadAttrGetstacksize(const PthreadAttr* attr, size_t* stack_size);
int KYTY_SYSV_ABI PthreadAttrSetaffinity(PthreadAttr* attr, KernelCpumask mask);
int KYTY_SYSV_ABI PthreadAttrSetdetachstate(PthreadAttr* attr, int state);
int KYTY_SYSV_ABI PthreadAttrSetguardsize(PthreadAttr* attr, size_t guard_size);
int KYTY_SYSV_ABI PthreadAttrSetinheritsched(PthreadAttr* attr, int inherit_sched);
int KYTY_SYSV_ABI PthreadAttrSetschedparam(PthreadAttr* attr, const KernelSchedParam* param);
int KYTY_SYSV_ABI PthreadAttrSetschedpolicy(PthreadAttr* attr, int policy);
int KYTY_SYSV_ABI PthreadAttrSetstack(PthreadAttr* attr, void* addr, size_t size);
int KYTY_SYSV_ABI PthreadAttrSetstackaddr(PthreadAttr* attr, void* addr);
int KYTY_SYSV_ABI PthreadAttrSetstacksize(PthreadAttr* attr, size_t stack_size);
int KYTY_SYSV_ABI PthreadRwlockDestroy(PthreadRwlock* rwlock);
int KYTY_SYSV_ABI PthreadRwlockInit(PthreadRwlock* rwlock, const PthreadRwlockattr* attr, const char* name);
int KYTY_SYSV_ABI PthreadRwlockRdlock(PthreadRwlock* rwlock);
int KYTY_SYSV_ABI PthreadRwlockTimedrdlock(PthreadRwlock* rwlock, KernelUseconds usec);
int KYTY_SYSV_ABI PthreadRwlockTimedwrlock(PthreadRwlock* rwlock, KernelUseconds usec);
int KYTY_SYSV_ABI PthreadRwlockTryrdlock(PthreadRwlock* rwlock);
int KYTY_SYSV_ABI PthreadRwlockTrywrlock(PthreadRwlock* rwlock);
int KYTY_SYSV_ABI PthreadRwlockUnlock(PthreadRwlock* rwlock);
int KYTY_SYSV_ABI PthreadRwlockWrlock(PthreadRwlock* rwlock);
int KYTY_SYSV_ABI PthreadRwlockattrDestroy(PthreadRwlockattr* attr);
int KYTY_SYSV_ABI PthreadRwlockattrInit(PthreadRwlockattr* attr);
int KYTY_SYSV_ABI PthreadRwlockattrGettype(PthreadRwlockattr* attr, int* type);
int KYTY_SYSV_ABI PthreadRwlockattrSettype(PthreadRwlockattr* attr, int type);
int KYTY_SYSV_ABI PthreadCondattrDestroy(PthreadCondattr* attr);
int KYTY_SYSV_ABI PthreadCondattrInit(PthreadCondattr* attr);
int KYTY_SYSV_ABI PthreadCondBroadcast(PthreadCond* cond);
int KYTY_SYSV_ABI PthreadCondDestroy(PthreadCond* cond);
int KYTY_SYSV_ABI PthreadCondInit(PthreadCond* cond, const PthreadCondattr* attr, const char* name);
int KYTY_SYSV_ABI PthreadCondSignal(PthreadCond* cond);
int KYTY_SYSV_ABI PthreadCondSignalto(PthreadCond* cond, Pthread thread);
int KYTY_SYSV_ABI PthreadCondTimedwait(PthreadCond* cond, PthreadMutex* mutex, KernelUseconds usec);
int KYTY_SYSV_ABI PthreadCondWait(PthreadCond* cond, PthreadMutex* mutex);
int KYTY_SYSV_ABI KernelClockGetres(KernelClockid clock_id, KernelTimespec* tp);
int KYTY_SYSV_ABI KernelClockGettime(KernelClockid clock_id, KernelTimespec* tp);
int KYTY_SYSV_ABI KernelGettimeofday(KernelTimeval* tp);
uint64_t KYTY_SYSV_ABI KernelGetTscFrequency();
uint64_t KYTY_SYSV_ABI KernelReadTsc();
uint64_t KYTY_SYSV_ABI KernelGetProcessTime();
uint64_t KYTY_SYSV_ABI KernelGetProcessTimeCounter();
uint64_t KYTY_SYSV_ABI KernelGetProcessTimeCounterFrequency();
int KYTY_SYSV_ABI pthread_cond_broadcast_s(PthreadCond* cond);
int KYTY_SYSV_ABI pthread_cond_wait_s(PthreadCond* cond, PthreadMutex* mutex);
int KYTY_SYSV_ABI pthread_mutex_lock_s(PthreadMutex* mutex);
int KYTY_SYSV_ABI pthread_mutex_unlock_s(PthreadMutex* mutex);
int KYTY_SYSV_ABI pthread_rwlock_rdlock_s(PthreadRwlock* rwlock);
int KYTY_SYSV_ABI pthread_rwlock_unlock_s(PthreadRwlock* rwlock);
int KYTY_SYSV_ABI pthread_rwlock_wrlock_s(PthreadRwlock* rwlock);
} // namespace Kyty::Libs::LibKernel
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_KERNEL_PTHREAD_H_ */
@@ -0,0 +1,155 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_LIBS_ERRNO_H_
#define EMULATOR_INCLUDE_EMULATOR_LIBS_ERRNO_H_
#include "Emulator/Common.h"
#ifdef KYTY_EMU_ENABLED
constexpr int OK = 0;
namespace Kyty::Libs::LibKernel {
constexpr int KERNEL_ERROR_UNKNOWN = -2147352576; /* 0x80020000 */
constexpr int KERNEL_ERROR_EPERM = -2147352575; /* 0x80020001 */
constexpr int KERNEL_ERROR_ENOENT = -2147352574; /* 0x80020002 */
constexpr int KERNEL_ERROR_ESRCH = -2147352573; /* 0x80020003 */
constexpr int KERNEL_ERROR_EINTR = -2147352572; /* 0x80020004 */
constexpr int KERNEL_ERROR_EIO = -2147352571; /* 0x80020005 */
constexpr int KERNEL_ERROR_ENXIO = -2147352570; /* 0x80020006 */
constexpr int KERNEL_ERROR_E2BIG = -2147352569; /* 0x80020007 */
constexpr int KERNEL_ERROR_ENOEXEC = -2147352568; /* 0x80020008 */
constexpr int KERNEL_ERROR_EBADF = -2147352567; /* 0x80020009 */
constexpr int KERNEL_ERROR_ECHILD = -2147352566; /* 0x8002000A */
constexpr int KERNEL_ERROR_EDEADLK = -2147352565; /* 0x8002000B */
constexpr int KERNEL_ERROR_ENOMEM = -2147352564; /* 0x8002000C */
constexpr int KERNEL_ERROR_EACCES = -2147352563; /* 0x8002000D */
constexpr int KERNEL_ERROR_EFAULT = -2147352562; /* 0x8002000E */
constexpr int KERNEL_ERROR_ENOTBLK = -2147352561; /* 0x8002000F */
constexpr int KERNEL_ERROR_EBUSY = -2147352560; /* 0x80020010 */
constexpr int KERNEL_ERROR_EEXIST = -2147352559; /* 0x80020011 */
constexpr int KERNEL_ERROR_EXDEV = -2147352558; /* 0x80020012 */
constexpr int KERNEL_ERROR_ENODEV = -2147352557; /* 0x80020013 */
constexpr int KERNEL_ERROR_ENOTDIR = -2147352556; /* 0x80020014 */
constexpr int KERNEL_ERROR_EISDIR = -2147352555; /* 0x80020015 */
constexpr int KERNEL_ERROR_EINVAL = -2147352554; /* 0x80020016 */
constexpr int KERNEL_ERROR_ENFILE = -2147352553; /* 0x80020017 */
constexpr int KERNEL_ERROR_EMFILE = -2147352552; /* 0x80020018 */
constexpr int KERNEL_ERROR_ENOTTY = -2147352551; /* 0x80020019 */
constexpr int KERNEL_ERROR_ETXTBSY = -2147352550; /* 0x8002001A */
constexpr int KERNEL_ERROR_EFBIG = -2147352549; /* 0x8002001B */
constexpr int KERNEL_ERROR_ENOSPC = -2147352548; /* 0x8002001C */
constexpr int KERNEL_ERROR_ESPIPE = -2147352547; /* 0x8002001D */
constexpr int KERNEL_ERROR_EROFS = -2147352546; /* 0x8002001E */
constexpr int KERNEL_ERROR_EMLINK = -2147352545; /* 0x8002001F */
constexpr int KERNEL_ERROR_EPIPE = -2147352544; /* 0x80020020 */
constexpr int KERNEL_ERROR_EDOM = -2147352543; /* 0x80020021 */
constexpr int KERNEL_ERROR_ERANGE = -2147352542; /* 0x80020022 */
constexpr int KERNEL_ERROR_EAGAIN = -2147352541; /* 0x80020023 */
constexpr int KERNEL_ERROR_EWOULDBLOCK = -2147352541; /* 0x80020023 */
constexpr int KERNEL_ERROR_EINPROGRESS = -2147352540; /* 0x80020024 */
constexpr int KERNEL_ERROR_EALREADY = -2147352539; /* 0x80020025 */
constexpr int KERNEL_ERROR_ENOTSOCK = -2147352538; /* 0x80020026 */
constexpr int KERNEL_ERROR_EDESTADDRREQ = -2147352537; /* 0x80020027 */
constexpr int KERNEL_ERROR_EMSGSIZE = -2147352536; /* 0x80020028 */
constexpr int KERNEL_ERROR_EPROTOTYPE = -2147352535; /* 0x80020029 */
constexpr int KERNEL_ERROR_ENOPROTOOPT = -2147352534; /* 0x8002002A */
constexpr int KERNEL_ERROR_EPROTONOSUPPORT = -2147352533; /* 0x8002002B */
constexpr int KERNEL_ERROR_ESOCKTNOSUPPORT = -2147352532; /* 0x8002002C */
constexpr int KERNEL_ERROR_EOPNOTSUPP = -2147352531; /* 0x8002002D */
constexpr int KERNEL_ERROR_ENOTSUP = -2147352531; /* 0x8002002D */
constexpr int KERNEL_ERROR_EPFNOSUPPORT = -2147352530; /* 0x8002002E */
constexpr int KERNEL_ERROR_EAFNOSUPPORT = -2147352529; /* 0x8002002F */
constexpr int KERNEL_ERROR_EADDRINUSE = -2147352528; /* 0x80020030 */
constexpr int KERNEL_ERROR_EADDRNOTAVAIL = -2147352527; /* 0x80020031 */
constexpr int KERNEL_ERROR_ENETDOWN = -2147352526; /* 0x80020032 */
constexpr int KERNEL_ERROR_ENETUNREACH = -2147352525; /* 0x80020033 */
constexpr int KERNEL_ERROR_ENETRESET = -2147352524; /* 0x80020034 */
constexpr int KERNEL_ERROR_ECONNABORTED = -2147352523; /* 0x80020035 */
constexpr int KERNEL_ERROR_ECONNRESET = -2147352522; /* 0x80020036 */
constexpr int KERNEL_ERROR_ENOBUFS = -2147352521; /* 0x80020037 */
constexpr int KERNEL_ERROR_EISCONN = -2147352520; /* 0x80020038 */
constexpr int KERNEL_ERROR_ENOTCONN = -2147352519; /* 0x80020039 */
constexpr int KERNEL_ERROR_ESHUTDOWN = -2147352518; /* 0x8002003A */
constexpr int KERNEL_ERROR_ETOOMANYREFS = -2147352517; /* 0x8002003B */
constexpr int KERNEL_ERROR_ETIMEDOUT = -2147352516; /* 0x8002003C */
constexpr int KERNEL_ERROR_ECONNREFUSED = -2147352515; /* 0x8002003D */
constexpr int KERNEL_ERROR_ELOOP = -2147352514; /* 0x8002003E */
constexpr int KERNEL_ERROR_ENAMETOOLONG = -2147352513; /* 0x8002003F */
constexpr int KERNEL_ERROR_EHOSTDOWN = -2147352512; /* 0x80020040 */
constexpr int KERNEL_ERROR_EHOSTUNREACH = -2147352511; /* 0x80020041 */
constexpr int KERNEL_ERROR_ENOTEMPTY = -2147352510; /* 0x80020042 */
constexpr int KERNEL_ERROR_EPROCLIM = -2147352509; /* 0x80020043 */
constexpr int KERNEL_ERROR_EUSERS = -2147352508; /* 0x80020044 */
constexpr int KERNEL_ERROR_EDQUOT = -2147352507; /* 0x80020045 */
constexpr int KERNEL_ERROR_ESTALE = -2147352506; /* 0x80020046 */
constexpr int KERNEL_ERROR_EREMOTE = -2147352505; /* 0x80020047 */
constexpr int KERNEL_ERROR_EBADRPC = -2147352504; /* 0x80020048 */
constexpr int KERNEL_ERROR_ERPCMISMATCH = -2147352503; /* 0x80020049 */
constexpr int KERNEL_ERROR_EPROGUNAVAIL = -2147352502; /* 0x8002004A */
constexpr int KERNEL_ERROR_EPROGMISMATCH = -2147352501; /* 0x8002004B */
constexpr int KERNEL_ERROR_EPROCUNAVAIL = -2147352500; /* 0x8002004C */
constexpr int KERNEL_ERROR_ENOLCK = -2147352499; /* 0x8002004D */
constexpr int KERNEL_ERROR_ENOSYS = -2147352498; /* 0x8002004E */
constexpr int KERNEL_ERROR_EFTYPE = -2147352497; /* 0x8002004F */
constexpr int KERNEL_ERROR_EAUTH = -2147352496; /* 0x80020050 */
constexpr int KERNEL_ERROR_ENEEDAUTH = -2147352495; /* 0x80020051 */
constexpr int KERNEL_ERROR_EIDRM = -2147352494; /* 0x80020052 */
constexpr int KERNEL_ERROR_ENOMSG = -2147352493; /* 0x80020053 */
constexpr int KERNEL_ERROR_EOVERFLOW = -2147352492; /* 0x80020054 */
constexpr int KERNEL_ERROR_ECANCELED = -2147352491; /* 0x80020055 */
constexpr int KERNEL_ERROR_EILSEQ = -2147352490; /* 0x80020056 */
constexpr int KERNEL_ERROR_ENOATTR = -2147352489; /* 0x80020057 */
constexpr int KERNEL_ERROR_EDOOFUS = -2147352488; /* 0x80020058 */
constexpr int KERNEL_ERROR_EBADMSG = -2147352487; /* 0x80020059 */
constexpr int KERNEL_ERROR_EMULTIHOP = -2147352486; /* 0x8002005A */
constexpr int KERNEL_ERROR_ENOLINK = -2147352485; /* 0x8002005B */
constexpr int KERNEL_ERROR_EPROTO = -2147352484; /* 0x8002005C */
constexpr int KERNEL_ERROR_ENOTCAPABLE = -2147352483; /* 0x8002005D */
constexpr int KERNEL_ERROR_ECAPMODE = -2147352482; /* 0x8002005E */
constexpr int KERNEL_ERROR_ENOBLK = -2147352481; /* 0x8002005F */
constexpr int KERNEL_ERROR_EICV = -2147352480; /* 0x80020060 */
constexpr int KERNEL_ERROR_ENOPLAYGOENT = -2147352479; /* 0x80020061 */
constexpr int KERNEL_ERROR_EREVOKE = -2147352478; /* 0x80020062 */
constexpr int KERNEL_ERROR_ESDKVERSION = -2147352477; /* 0x80020063 */
constexpr int KERNEL_ERROR_ESTART = -2147352476; /* 0x80020064 */
constexpr int KERNEL_ERROR_ESTOP = -2147352475; /* 0x80020065 */
} // namespace Kyty::Libs::LibKernel
namespace Kyty::Libs::VideoOut {
constexpr int VIDEO_OUT_ERROR_INVALID_VALUE = -2144796671; /* 0x80290001 */
constexpr int VIDEO_OUT_ERROR_INVALID_ADDRESS = -2144796670; /* 0x80290002 */
constexpr int VIDEO_OUT_ERROR_INVALID_PIXEL_FORMAT = -2144796669; /* 0x80290003 */
constexpr int VIDEO_OUT_ERROR_INVALID_PITCH = -2144796668; /* 0x80290004 */
constexpr int VIDEO_OUT_ERROR_INVALID_RESOLUTION = -2144796667; /* 0x80290005 */
constexpr int VIDEO_OUT_ERROR_INVALID_FLIP_MODE = -2144796666; /* 0x80290006 */
constexpr int VIDEO_OUT_ERROR_INVALID_TILING_MODE = -2144796665; /* 0x80290007 */
constexpr int VIDEO_OUT_ERROR_INVALID_ASPECT_RATIO = -2144796664; /* 0x80290008 */
constexpr int VIDEO_OUT_ERROR_RESOURCE_BUSY = -2144796663; /* 0x80290009 */
constexpr int VIDEO_OUT_ERROR_INVALID_INDEX = -2144796662; /* 0x8029000A */
constexpr int VIDEO_OUT_ERROR_INVALID_HANDLE = -2144796661; /* 0x8029000B */
constexpr int VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE = -2144796660; /* 0x8029000C */
constexpr int VIDEO_OUT_ERROR_INVALID_EVENT = -2144796659; /* 0x8029000D */
constexpr int VIDEO_OUT_ERROR_NO_EMPTY_SLOT = -2144796657; /* 0x8029000F */
constexpr int VIDEO_OUT_ERROR_SLOT_OCCUPIED = -2144796656; /* 0x80290010 */
constexpr int VIDEO_OUT_ERROR_FLIP_QUEUE_FULL = -2144796654; /* 0x80290012 */
constexpr int VIDEO_OUT_ERROR_INVALID_MEMORY = -2144796653; /* 0x80290013 */
constexpr int VIDEO_OUT_ERROR_MEMORY_NOT_PHYSICALLY_CONTIGUOUS = -2144796652; /* 0x80290014 */
constexpr int VIDEO_OUT_ERROR_MEMORY_INVALID_ALIGNMENT = -2144796651; /* 0x80290015 */
constexpr int VIDEO_OUT_ERROR_UNSUPPORTED_OUTPUT_MODE = -2144796650; /* 0x80290016 */
constexpr int VIDEO_OUT_ERROR_OVERFLOW = -2144796649; /* 0x80290017 */
constexpr int VIDEO_OUT_ERROR_NO_DEVICE = -2144796648; /* 0x80290018 */
constexpr int VIDEO_OUT_ERROR_UNAVAILABLE_OUTPUT_MODE = -2144796647; /* 0x80290019 */
constexpr int VIDEO_OUT_ERROR_INVALID_OPTION = -2144796646; /* 0x8029001A */
constexpr int VIDEO_OUT_ERROR_PORT_UNSUPPORTED_FUNCTION = -2144796645; /* 0x8029001B */
constexpr int VIDEO_OUT_ERROR_UNSUPPORTED_OPERATION = -2144796644; /* 0x8029001C */
constexpr int VIDEO_OUT_ERROR_FATAL = -2144796417; /* 0x802900FF */
constexpr int VIDEO_OUT_ERROR_UNKNOWN = -2144796418; /* 0x802900FE */
constexpr int VIDEO_OUT_ERROR_ENOMEM = -2144792564; /* 0x8029100C */
} // namespace Kyty::Libs::VideoOut
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_LIBS_ERRNO_H_ */
@@ -0,0 +1,87 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_LIBS_LIBS_H_
#define EMULATOR_INCLUDE_EMULATOR_LIBS_LIBS_H_
#include "Kyty/Core/String.h"
#include "Emulator/Common.h"
#include "Emulator/Timer.h" // IWYU pragma: keep
#ifdef KYTY_EMU_ENABLED
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define PRINT_NAME_ENABLED g_print_name
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define PRINT_NAME_ENABLE(flag) PRINT_NAME_ENABLED = flag;
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define LIB_DEFINE(name) void name(Loader::SymbolDatabase* s)
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define LIB_NAME(l, m) \
static thread_local bool PRINT_NAME_ENABLED = true; \
static constexpr char g_library[] = l; \
static constexpr char g_module[] = m;
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define LIB_VERSION(l, lv, m, mv1, mv2) \
LIB_NAME(l, m); \
static constexpr int g_library_version = lv; \
static constexpr int g_module_version_major = mv1; \
static constexpr int g_module_version_minor = mv2;
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define LIB_USING(n) \
using n::g_library; \
using n::g_library_version; \
using n::g_module; \
using n::g_module_version_major; \
using n::g_module_version_minor;
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define LIB_CHECK(ids, name) \
if (id == (ids)) \
{ \
name(s); \
return true; \
}
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define LIB_ADD(n, f, t) \
{ \
Loader::SymbolResolve sr {}; \
sr.name = n; \
sr.library = g_library; \
sr.library_version = g_library_version; \
sr.module = g_module; \
sr.module_version_major = g_module_version_major; \
sr.module_version_minor = g_module_version_minor; \
sr.type = t; \
auto func = reinterpret_cast<uint64_t>(f); \
const char32_t* dbg_name = U"" #f; \
s->Add(sr, func, dbg_name); \
}
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define LIB_OBJECT(n, f) LIB_ADD(n, f, Loader::SymbolType::Object)
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define LIB_FUNC(n, f) LIB_ADD(n, f, Loader::SymbolType::Func)
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define PRINT_NAME() \
if (PRINT_NAME_ENABLED) \
{ \
Kyty::printf(FG_CYAN "[%d][%s] %s::%s::%s()" DEFAULT "\n", Core::Thread::GetThreadIdUnique(), \
Loader::Timer::GetTime().ToString("HH24:MI:SS.FFF").C_Str(), g_library, g_module, __func__); \
}
namespace Kyty {
namespace Loader {
class SymbolDatabase;
} // namespace Loader
namespace Libs {
bool Init(const String& id, Loader::SymbolDatabase* s);
} // namespace Libs
} // namespace Kyty
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_LIBS_LIBS_H_ */
@@ -0,0 +1,27 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_LIBS_PRINTF_H_
#define EMULATOR_INCLUDE_EMULATOR_LIBS_PRINTF_H_
#include "Kyty/Core/Common.h"
#include "Emulator/Common.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Libs {
struct VaContext;
struct VaList;
using libc_print_func_t = KYTY_FORMAT_PRINTF(1, 2) KYTY_SYSV_ABI int (*)(const char* str, ...);
using libc_print_v_func_t = int (*)(VaContext* c);
using libc_vprint_func_t = int (*)(const char* str, VaList* c);
libc_print_func_t GetPrintFunc();
libc_print_v_func_t GetPrintFuncV();
libc_vprint_func_t GetVPrintFunc();
} // namespace Kyty::Libs
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_LIBS_PRINTF_H_ */
@@ -0,0 +1,241 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_LIBS_VACONTEXT_H_
#define EMULATOR_INCLUDE_EMULATOR_LIBS_VACONTEXT_H_
#include <cstddef>
#include <xmmintrin.h>
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define VA_ARGS \
uint64_t rdi, uint64_t rsi, uint64_t rdx, uint64_t rcx, uint64_t r8, uint64_t r9, uint64_t overflow_arg_area, __m128 xmm0, \
__m128 xmm1, __m128 xmm2, __m128 xmm3, __m128 xmm4, __m128 xmm5, __m128 xmm6, __m128 xmm7, ...
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define VA_CONTEXT(ctx) \
alignas(16) VaContext ctx; \
(ctx).reg_save_area.gp[0] = rdi; \
(ctx).reg_save_area.gp[1] = rsi; \
(ctx).reg_save_area.gp[2] = rdx; \
(ctx).reg_save_area.gp[3] = rcx; \
(ctx).reg_save_area.gp[4] = r8; \
(ctx).reg_save_area.gp[5] = r9; \
(ctx).reg_save_area.fp[0] = xmm0; \
(ctx).reg_save_area.fp[1] = xmm1; \
(ctx).reg_save_area.fp[2] = xmm2; \
(ctx).reg_save_area.fp[3] = xmm3; \
(ctx).reg_save_area.fp[4] = xmm4; \
(ctx).reg_save_area.fp[5] = xmm5; \
(ctx).reg_save_area.fp[6] = xmm6; \
(ctx).reg_save_area.fp[7] = xmm7; \
(ctx).va_list.reg_save_area = &(ctx).reg_save_area; \
(ctx).va_list.gp_offset = offsetof(VaRegSave, gp); \
(ctx).va_list.fp_offset = offsetof(VaRegSave, fp); \
(ctx).va_list.overflow_arg_area = &overflow_arg_area;
namespace Kyty::Libs {
#pragma pack(1)
struct VaList
{
uint32_t gp_offset;
uint32_t fp_offset;
void* overflow_arg_area;
void* reg_save_area;
};
// typedef float __m128 __attribute__((__vector_size__(16), __aligned__(16)));
struct VaRegSave
{
uint64_t gp[6];
__m128 fp[8];
};
struct VaContext
{
VaRegSave reg_save_area;
VaList va_list;
};
struct VaCharX16
{
char x[16];
};
struct VaShortX8
{
short x[8]; // NOLINT(google-runtime-int)
};
struct VaIntX4
{
int x[4];
};
struct VaFloatX4
{
float x[4];
};
#pragma pack()
template <class T, uint64_t Align, uint64_t Size>
T VaArg_overflow_arg_area(VaList* l)
{
auto ptr = ((reinterpret_cast<uint64_t>(l->overflow_arg_area) + (Align - 1)) & ~(Align - 1));
auto* addr = reinterpret_cast<T*>(ptr);
l->overflow_arg_area = reinterpret_cast<void*>(ptr + Size);
return *addr;
}
template <class T, uint32_t Size>
T VaArg_reg_save_area_gp(VaList* l)
{
auto* addr = reinterpret_cast<T*>(static_cast<uint8_t*>(l->reg_save_area) + l->gp_offset);
l->gp_offset += Size;
return *addr;
}
template <class T, uint32_t Size>
T VaArg_reg_save_area_fp(VaList* l)
{
auto* addr = reinterpret_cast<T*>(static_cast<uint8_t*>(l->reg_save_area) + l->fp_offset);
l->fp_offset += Size;
return *addr;
}
template <>
inline VaFloatX4 VaArg_reg_save_area_fp<VaFloatX4, 32>(VaList* l)
{
auto* addr = reinterpret_cast<VaFloatX4*>(static_cast<uint8_t*>(l->reg_save_area) + l->fp_offset);
l->fp_offset += 32;
VaFloatX4 ret = {{addr[0].x[0], addr[0].x[1], addr[1].x[0], addr[1].x[1]}};
return ret;
}
inline int VaArg_int(VaList* l)
{
if (l->gp_offset <= 40)
{
return VaArg_reg_save_area_gp<int, 8>(l);
}
return VaArg_overflow_arg_area<int, 1, 8>(l);
}
inline double VaArg_double(VaList* l)
{
if (l->fp_offset <= 160)
{
return VaArg_reg_save_area_fp<double, 16>(l);
}
return VaArg_overflow_arg_area<double, 1, 8>(l);
}
inline long double VaArg_long_double(VaList* l)
{
return VaArg_overflow_arg_area<long double, 16, 16>(l);
}
inline wint_t VaArg_wint_t(VaList* l)
{
if (l->gp_offset <= 40)
{
return VaArg_reg_save_area_gp<wint_t, 8>(l);
}
return VaArg_overflow_arg_area<wint_t, 1, 8>(l);
}
inline VaCharX16 VaArg_char_x16(VaList* l)
{
if (l->gp_offset <= 32)
{
return VaArg_reg_save_area_gp<VaCharX16, 16>(l);
}
return VaArg_overflow_arg_area<VaCharX16, 1, 16>(l);
}
inline long VaArg_long(VaList* l) // NOLINT(google-runtime-int)
{
if (l->gp_offset <= 40)
{
return VaArg_reg_save_area_gp<long, 8>(l); // NOLINT(google-runtime-int)
}
return VaArg_overflow_arg_area<long, 1, 8>(l); // NOLINT(google-runtime-int)
}
inline intmax_t VaArg_intmax_t(VaList* l)
{
if (l->gp_offset <= 40)
{
return VaArg_reg_save_area_gp<intmax_t, 8>(l);
}
return VaArg_overflow_arg_area<intmax_t, 1, 8>(l);
}
inline long long VaArg_long_long(VaList* l) // NOLINT(google-runtime-int)
{
if (l->gp_offset <= 40)
{
return VaArg_reg_save_area_gp<long long, 8>(l); // NOLINT(google-runtime-int)
}
return VaArg_overflow_arg_area<long long, 1, 8>(l); // NOLINT(google-runtime-int)
}
inline ptrdiff_t VaArg_ptrdiff_t(VaList* l)
{
if (l->gp_offset <= 40)
{
return VaArg_reg_save_area_gp<ptrdiff_t, 8>(l);
}
return VaArg_overflow_arg_area<ptrdiff_t, 1, 8>(l);
}
inline size_t VaArg_size_t(VaList* l)
{
if (l->gp_offset <= 40)
{
return VaArg_reg_save_area_gp<size_t, 8>(l);
}
return VaArg_overflow_arg_area<size_t, 1, 8>(l);
}
inline VaShortX8 VaArg_ShortX8(VaList* l)
{
if (l->gp_offset <= 32)
{
return VaArg_reg_save_area_gp<VaShortX8, 16>(l);
}
return VaArg_overflow_arg_area<VaShortX8, 1, 16>(l);
}
inline VaIntX4 VaArg_IntX4(VaList* l)
{
if (l->gp_offset <= 32)
{
return VaArg_reg_save_area_gp<VaIntX4, 16>(l);
}
return VaArg_overflow_arg_area<VaIntX4, 1, 16>(l);
}
inline VaFloatX4 VaArg_FloatX4(VaList* l)
{
if (l->fp_offset <= 144)
{
return VaArg_reg_save_area_fp<VaFloatX4, 32>(l);
}
return VaArg_overflow_arg_area<VaFloatX4, 1, 16>(l);
}
template <class T>
T* VaArg_ptr(VaList* l)
{
if (l->gp_offset <= 40)
{
return VaArg_reg_save_area_gp<T*, 8>(l);
}
return VaArg_overflow_arg_area<T*, 1, 8>(l);
}
} // namespace Kyty::Libs
#endif /* EMULATOR_INCLUDE_EMULATOR_LIBS_VACONTEXT_H_ */
+83
View File
@@ -0,0 +1,83 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_LOG_H_
#define EMULATOR_INCLUDE_EMULATOR_LOG_H_
#include "Kyty/Core/Common.h"
#include "Kyty/Core/File.h"
#include "Kyty/Core/String.h"
#include "Kyty/Core/Subsystems.h"
//#include "Emulator/Config.h"
//#define KYTY_LOG_ENABLED
#define CSI "\x1b[" // NOLINT
#define DEFAULT CSI "0m" // NOLINT // Returns all attributes to the default state prior to modification
#define BOLD CSI "1m" // NOLINT // Applies brightness/intensity flag to foreground color
#define NO_BOLD CSI "22m" // NOLINT // Removes brightness/intensity flag from foreground color
#define UNDERLINE CSI "4m" // NOLINT // Adds underline
#define NO_UNDERLINE CSI "24m" // NOLINT // Removes underline
#define NEGATIVE CSI "7m" // NOLINT // Swaps foreground and background colors
#define POSITIVE CSI "27m" // NOLINT // Returns foreground/background to normal
#define FG_BLACK CSI "30m" // NOLINT // Applies non-bold/bright black to foreground
#define FG_RED CSI "31m" // NOLINT // Applies non-bold/bright red to foreground
#define FG_GREEN CSI "32m" // NOLINT // Applies non-bold/bright green to foreground
#define FG_YELLOW CSI "33m" // NOLINT // Applies non-bold/bright yellow to foreground
#define FG_BLUE CSI "34m" // NOLINT // Applies non-bold/bright blue to foreground
#define FG_MAGENTA CSI "35m" // NOLINT // Applies non-bold/bright magenta to foreground
#define FG_CYAN CSI "36m" // NOLINT // Applies non-bold/bright cyan to foreground
#define FG_WHITE CSI "37m" // NOLINT // Applies non-bold/bright white to foreground
#define FG_EXTENDED CSI "38m" // NOLINT // Applies extended color value to the foreground (see details below)
#define FG_DEFAULT CSI "39m" // NOLINT // Applies only the foreground portion of the defaults (see 0)
#define BG_BLACK CSI "40m" // NOLINT // Applies non-bold/bright black to background
#define BG_RED CSI "41m" // NOLINT // Applies non-bold/bright red to background
#define BG_GREEN CSI "42m" // NOLINT // Applies non-bold/bright green to background
#define BG_YELLOW CSI "43m" // NOLINT // Applies non-bold/bright yellow to background
#define BG_BLUE CSI "44m" // NOLINT // Applies non-bold/bright blue to background
#define BG_MAGENTA CSI "45m" // NOLINT // Applies non-bold/bright magenta to background
#define BG_CYAN CSI "46m" // NOLINT // Applies non-bold/bright cyan to background
#define BG_WHITE CSI "47m" // NOLINT // Applies non-bold/bright white to background
#define BG_EXTENDED CSI "48m" // NOLINT // Applies extended color value to the background (see details below)
#define BG_DEFAULT CSI "49m" // NOLINT // Applies only the background portion of the defaults (see 0)
#define FG_BRIGHT_BLACK CSI "90m" // NOLINT // Applies bold/bright black to foreground
#define FG_BRIGHT_RED CSI "91m" // NOLINT // Applies bold/bright red to foreground
#define FG_BRIGHT_GREEN CSI "92m" // NOLINT // Applies bold/bright green to foreground
#define FG_BRIGHT_YELLOW CSI "93m" // NOLINT // Applies bold/bright yellow to foreground
#define FG_BRIGHT_BLUE CSI "94m" // NOLINT // Applies bold/bright blue to foreground
#define FG_BRIGHT_MAGENTA CSI "95m" // NOLINT // Applies bold/bright magenta to foreground
#define FG_BRIGHT_CYAN CSI "96m" // NOLINT // Applies bold/bright cyan to foreground
#define FG_BRIGHT_WHITE CSI "97m" // NOLINT // Applies bold/bright white to foreground
#define BG_BRIGHT_BLACK CSI "100m" // NOLINT // Applies bold/bright black to background
#define BG_BRIGHT_RED CSI "101m" // NOLINT // Applies bold/bright red to background
#define BG_BRIGHT_GREEN CSI "102m" // NOLINT // Applies bold/bright green to background
#define BG_BRIGHT_YELLOW CSI "103m" // NOLINT // Applies bold/bright yellow to background
#define BG_BRIGHT_BLUE CSI "104m" // NOLINT // Applies bold/bright blue to background
#define BG_BRIGHT_MAGENTA CSI "105m" // NOLINT // Applies bold/bright magenta to background
#define BG_BRIGHT_CYAN CSI "106m" // NOLINT // Applies bold/bright cyan to background
#define BG_BRIGHT_WHITE CSI "107m" // NOLINT // Applies bold/bright white to background
namespace Kyty {
namespace Log {
KYTY_SUBSYSTEM_DEFINE(Log);
enum class Direction
{
Silent,
Console,
File
};
void SetDirection(Direction dir);
void SetOutputFile(const String& file_name, Core::File::Encoding enc = Core::File::Encoding::Utf8);
bool IsColoredPrintf();
String RemoveColors(const String& str);
} // namespace Log
void printf(const char* format, ...) KYTY_FORMAT_PRINTF(1, 2);
} // namespace Kyty
#endif /* EMULATOR_INCLUDE_EMULATOR_LOG_H_ */
@@ -0,0 +1,48 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_PROFILER_H_
#define EMULATOR_INCLUDE_EMULATOR_PROFILER_H_
#include "Kyty/Core/Common.h"
#include "Kyty/Core/Subsystems.h"
#include "Emulator/Common.h"
#ifdef KYTY_EMU_ENABLED
#define BUILD_WITH_EASY_PROFILER
#define EASY_PROFILER_STATIC
#include <easy/profiler.h> // IWYU pragma: export
//
#include "easy/details/profiler_aux.h" // IWYU pragma: export
#include "easy/details/profiler_colors.h" // IWYU pragma: export
#include <cwchar> // IWYU pragma: export
// IWYU pragma: no_include "easy/profiler.h"
#if KYTY_COMPILER == KYTY_COMPILER_MSVC
#define KYTY_PROFILER_BLOCK(f, ...) EASY_BLOCK(f, __VA_ARGS__);
#else
#define KYTY_PROFILER_BLOCK(f, s...) EASY_BLOCK(f, ##s);
#endif
#if KYTY_COMPILER == KYTY_COMPILER_MSVC
#define KYTY_PROFILER_FUNCTION(f, ...) EASY_FUNCTION(f, __VA_ARGS__);
#else
#define KYTY_PROFILER_FUNCTION(f, s...) EASY_FUNCTION(f, ##s);
#endif
#define KYTY_PROFILER_END_BLOCK EASY_END_BLOCK
#define KYTY_PROFILER_THREAD(f) EASY_THREAD(f)
namespace Kyty::Profiler {
KYTY_SUBSYSTEM_DEFINE(Profiler);
} // namespace Kyty::Profiler
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_PROFILER_H_ */
@@ -0,0 +1,185 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_RUNTIMELINKER_H_
#define EMULATOR_INCLUDE_EMULATOR_RUNTIMELINKER_H_
#include "Kyty/Core/Common.h"
#include "Kyty/Core/Hashmap.h"
#include "Kyty/Core/String.h"
#include "Kyty/Core/Threads.h"
#include "Kyty/Core/Vector.h"
#include "Emulator/Common.h"
#include "Emulator/SymbolDatabase.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Loader {
class Elf64;
struct Elf64_Sym;
struct Elf64_Rela;
class RuntimeLinker;
namespace VirtualMemory {
class ExceptionHandler;
} // namespace VirtualMemory
using module_func_t = int (*)(size_t args, const void* argp);
struct ModuleId
{
bool operator==(const ModuleId& other) const
{
return version_major == other.version_major && version_minor == other.version_minor && name == other.name;
}
String id;
int version_major;
int version_minor;
String name;
};
struct LibraryId
{
bool operator==(const LibraryId& other) const { return version == other.version && name == other.name; }
String id;
int version;
String name;
};
struct ThreadLocalStorage
{
uint64_t image_vaddr = 0;
uint64_t image_size = 0;
uint64_t handler_vaddr = 0;
Core::Hashmap<int, uint8_t*> tlss;
Core::Mutex mutex;
};
struct DynamicInfo
{
void* hash_table = nullptr;
uint64_t hash_table_size = 0;
char* str_table = nullptr;
uint64_t str_table_size = 0;
Elf64_Sym* symbol_table = nullptr;
uint64_t symbol_table_total_size = 0;
uint64_t symbol_table_entry_size = 0;
uint64_t init_vaddr = 0;
uint64_t fini_vaddr = 0;
uint64_t init_array_vaddr = 0;
uint64_t fini_array_vaddr = 0;
uint64_t preinit_array_vaddr = 0;
uint64_t init_array_size = 0;
uint64_t fini_array_size = 0;
uint64_t preinit_array_size = 0;
uint64_t pltgot_vaddr = 0;
Elf64_Rela* jmprela_table = nullptr;
uint64_t jmprela_table_size = 0;
Elf64_Rela* rela_table = nullptr;
uint64_t rela_table_total_size = 0;
uint64_t rela_table_entry_size = 0;
uint64_t relative_count = 0;
uint64_t debug = 0;
uint64_t textrel = 0;
uint64_t flags = 0;
const char* so_name = nullptr;
Vector<const char*> needed;
Vector<ModuleId> export_modules;
Vector<ModuleId> import_modules;
Vector<LibraryId> export_libs;
Vector<LibraryId> import_libs;
};
struct Program
{
int32_t unique_id = -1;
RuntimeLinker* rt = nullptr;
String file_name;
Elf64* elf = nullptr;
VirtualMemory::ExceptionHandler* exception_handler = nullptr;
DynamicInfo* dynamic_info = nullptr;
uint64_t base_vaddr = 0;
uint64_t base_size = 0;
uint64_t base_size_aligned = 0;
SymbolDatabase* export_symbols = nullptr;
SymbolDatabase* import_symbols = nullptr;
ThreadLocalStorage tls;
bool fail_if_global_not_resolved = true;
bool dbg_print_reloc = false;
uint64_t proc_param_vaddr = 0;
uint64_t custom_call_plt_vaddr = 0;
uint32_t custom_call_plt_num = 0;
};
class RuntimeLinker
{
public:
RuntimeLinker();
virtual ~RuntimeLinker();
void Clear();
KYTY_CLASS_NO_COPY(RuntimeLinker);
void DbgDump(const String& folder);
Program* LoadProgram(const String& elf_name);
void UnloadProgram(Program* program);
[[nodiscard]] uint64_t GetEntry();
[[nodiscard]] uint64_t GetProcParam();
void RelocateAll();
void Execute();
int StartModule(Program* program, size_t args, const void* argp, module_func_t func);
int StopModule(Program* program, size_t args, const void* argp, module_func_t func);
void StartAllModules();
void StopAllModules();
void DeleteTlss(int thread_id);
void Resolve(const String& name, SymbolType type, Program* program, SymbolRecord* out_info, bool* bind_self);
SymbolDatabase* Symbols() { return m_symbols; }
static uint64_t ReadFromElf(Program* program, uint64_t vaddr);
Program* FindProgramByAddr(uint64_t vaddr);
Program* FindProgramById(int32_t id);
static uint8_t* TlsGetAddr(Program* program);
static void DeleteTls(Program* program, int thread_id);
private:
static void LoadProgramToMemory(Program* program);
static void ParseProgramDynamicInfo(Program* program);
static void CreateSymbolDatabase(Program* program);
static void Relocate(Program* program);
static void DeleteProgram(Program* program);
static void SetupTlsHandler(Program* program);
Program* FindProgram(const ModuleId& m, const LibraryId& l);
static const ModuleId* FindModule(const Program& program, const String& id);
static const LibraryId* FindLibrary(const Program& program, const String& id);
Vector<Program*> m_programs;
SymbolDatabase* m_symbols = nullptr;
bool m_relocated = false;
Core::Mutex m_mutex;
};
} // namespace Kyty::Loader
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_RUNTIMELINKER_H_ */
@@ -0,0 +1,67 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_SYMBOLDATABASE_H_
#define EMULATOR_INCLUDE_EMULATOR_SYMBOLDATABASE_H_
#include "Kyty/Core/Common.h"
#include "Kyty/Core/Hashmap.h"
#include "Kyty/Core/String.h"
#include "Kyty/Core/Vector.h"
#include "Emulator/Common.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Loader {
enum class SymbolType
{
Unknown,
Func,
Object,
TlsModule
};
struct SymbolRecord
{
String name;
String dbg_name;
uint64_t vaddr;
};
struct SymbolResolve
{
String name;
String library;
int library_version;
String module;
int module_version_major;
int module_version_minor;
SymbolType type;
};
class SymbolDatabase
{
public:
SymbolDatabase() = default;
virtual ~SymbolDatabase() = default;
void Add(const SymbolResolve& s, uint64_t vaddr);
void Add(const SymbolResolve& s, uint64_t vaddr, const String& dbg_name);
[[nodiscard]] const SymbolRecord* Find(const SymbolResolve& s) const;
void DbgDump(const String& folder, const String& file_name);
KYTY_CLASS_NO_COPY(SymbolDatabase);
static String GenerateName(const SymbolResolve& s);
private:
Vector<SymbolRecord> m_symbols;
Core::Hashmap<String, uint32_t> m_map;
};
} // namespace Kyty::Loader
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_SYMBOLDATABASE_H_ */
+26
View File
@@ -0,0 +1,26 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_TIMER_H_
#define EMULATOR_INCLUDE_EMULATOR_TIMER_H_
#include "Kyty/Core/Common.h"
#include "Kyty/Core/DateTime.h"
#include "Kyty/Core/Subsystems.h"
#include "Emulator/Common.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Loader::Timer {
KYTY_SUBSYSTEM_DEFINE(Timer);
void Start();
double GetTimeMs();
Core::Time GetTime();
uint64_t GetCounter();
uint64_t GetFrequency();
} // namespace Kyty::Loader::Timer
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_TIMER_H_ */
@@ -0,0 +1,107 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_VIRTUALMEMORY_H_
#define EMULATOR_INCLUDE_EMULATOR_VIRTUALMEMORY_H_
#include "Kyty/Core/Common.h"
#include "Emulator/Common.h"
#ifdef KYTY_EMU_ENABLED
namespace Kyty::Loader {
enum class ProcessorArchitecture
{
Unknown,
Amd64, // x64 (AMD or Intel)
};
struct SystemInfo
{
uint32_t PageSize;
uint64_t MinimumApplicationAddress;
uint64_t MaximumApplicationAddress;
uint32_t ActiveProcessorMask;
uint32_t NumberOfProcessors;
ProcessorArchitecture ProcessorArchitecture;
uint32_t AllocationGranularity;
uint16_t ProcessorLevel;
uint16_t ProcessorRevision;
};
SystemInfo GetSystemInfo();
namespace VirtualMemory {
class ExceptionHandlerPrivate;
class ExceptionHandler
{
public:
enum class ExceptionType
{
Unknown,
AccessViolation
};
enum class AccessViolationType
{
Unknown,
Read,
Write,
Execute
};
struct ExceptionInfo
{
ExceptionType type = ExceptionType::Unknown;
AccessViolationType access_violation_type = AccessViolationType::Unknown;
uint64_t access_violation_vaddr = 0;
};
using handler_func_t = void (*)(const ExceptionInfo*);
ExceptionHandler();
virtual ~ExceptionHandler();
KYTY_CLASS_NO_COPY(ExceptionHandler);
static uint64_t GetSize();
bool Install(uint64_t base_address, uint64_t handler_addr, uint64_t image_size, handler_func_t func);
bool Uninstall();
private:
ExceptionHandlerPrivate* m_p = nullptr;
};
enum class Mode : uint32_t
{
NoAccess = 0,
Read = 1,
Write = 2,
ReadWrite = Read | Write,
Execute = 4,
ExecuteRead = Execute | Read,
ExecuteWrite = Execute | Write,
ExecuteReadWrite = Execute | Read | Write,
};
inline bool IsExecute(Mode mode)
{
return (mode == Mode::Execute || mode == Mode::ExecuteRead || mode == Mode::ExecuteWrite || mode == Mode::ExecuteReadWrite);
}
uint64_t Alloc(uint64_t address, uint64_t size, Mode mode);
uint64_t AllocAligned(uint64_t address, uint64_t size, Mode mode, uint64_t alignment);
bool Free(uint64_t address);
bool Protect(uint64_t address, uint64_t size, Mode mode, Mode* old_mode = nullptr);
bool FlushInstructionCache(uint64_t address, uint64_t size);
bool PatchReplace(uint64_t vaddr, uint64_t value);
} // namespace VirtualMemory
} // namespace Kyty::Loader
#endif // KYTY_EMU_ENABLED
#endif /* EMULATOR_INCLUDE_EMULATOR_VIRTUALMEMORY_H_ */