Skip to content

Commit 86a0ddc

Browse files
author
Your Name
committed
KytyPlus v1.8
1 parent 9f50f52 commit 86a0ddc

18 files changed

Lines changed: 514 additions & 171 deletions

File tree

src/common/singleton.h

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define KYTY_COMMON_SINGLETON_H_
33

44
#include <cstdlib>
5+
#include <mutex>
56
#include <new>
67

78
namespace Common {
@@ -10,27 +11,17 @@ template <class T>
1011
class Singleton {
1112
public:
1213
static T* Instance() {
13-
if (!g_m_instance) {
14-
// NOLINTNEXTLINE(cppcoreguidelines-no-malloc,hicpp-no-malloc)
15-
g_m_instance = static_cast<T*>(std::malloc(sizeof(T)));
16-
new (g_m_instance) T;
17-
}
18-
19-
return g_m_instance;
14+
static T instance;
15+
return &instance;
2016
}
2117

2218
KYTY_CLASS_NO_COPY(Singleton);
2319

2420
protected:
25-
Singleton();
26-
~Singleton();
27-
28-
private:
29-
static inline T* g_m_instance = nullptr;
21+
Singleton() = default;
22+
~Singleton() = default;
3023
};
3124

32-
// template<class T> T* Singleton<T>::instance = 0;
33-
3425
} // namespace Common
3526

3627
#endif /* KYTY_COMMON_SINGLETON_H_ */

src/common/uniqueFunction.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class UniqueFunction {
4141
UniqueFunction(const UniqueFunction&) = delete;
4242
UniqueFunction& operator=(const UniqueFunction&) = delete;
4343

44-
Result operator()(Args... args) const {
44+
Result operator()(Args... args) {
4545
return m_callable->Invoke(std::forward<Args>(args)...);
4646
}
4747

src/core/Avx512Emitter.hpp

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -44,25 +44,30 @@ namespace KytyPS5::JIT {
4444

4545
// Emits SFENCE (Store Fence) for memory consistency
4646
std::expected<void, JitError> EmitStoreFence() {
47-
return AppendBytes({ 0xEF });
47+
// SFENCE = 0x0F 0xAE 0xF8
48+
return AppendBytes({ 0x0F, 0xAE, 0xF8 });
4849
}
4950

5051
// Emits LFENCE (Load Fence)
5152
std::expected<void, JitError> EmitLoadFence() {
52-
return AppendBytes({ 0xEF }); // Simplified; real SFENCE/LFENCE differ in opcode bits
53+
// LFENCE = 0x0F 0xAE 0xE8
54+
return AppendBytes({ 0x0F, 0xAE, 0xE8 });
5355
}
5456

55-
const std::vector<uint8_t>& GetBuffer() const { return code_buffer_; }
57+
// Emits MFENCE (Memory Fence)
58+
std::expected<void, JitError> EmitMemFence() {
59+
// MFENCE = 0x0F 0xAE 0xF0
60+
return AppendBytes({ 0x0F, 0xAE, 0xF0 });
61+
}
5662

57-
// Generic scaffolding entry used by JitDispatcher::EmitAvx512.
58-
std::expected<void, JitError> EmitInstruction(uint32_t opcode, uint8_t zmm_reg) {
59-
std::vector<uint8_t> bytes = {
60-
0x62,
61-
static_cast<uint8_t>(0x00 | ((zmm_reg & 7u) << 3)),
62-
static_cast<uint8_t>(opcode & 0xFFu),
63-
static_cast<uint8_t>(0x00 | ((zmm_reg & 7u) << 3)),
64-
};
65-
return AppendBytes(bytes);
63+
// Raw emission callback for JitDispatcher — appends raw bytes to an external buffer
64+
void EmitRaw(uint32_t opcode, uint8_t zmm_reg, std::vector<uint8_t>& out_buffer) {
65+
// Simplified: emit a placeholder EVEX-encoded NOP-like instruction
66+
// Real implementation would decode opcode and emit proper EVEV-encoded instruction
67+
out_buffer.push_back(0x62);
68+
out_buffer.push_back(static_cast<uint8_t>(0xF0 | (zmm_reg & 0x0F)));
69+
out_buffer.push_back(0x00);
70+
out_buffer.push_back(0x00);
6671
}
6772

6873
private:
@@ -74,18 +79,4 @@ namespace KytyPS5::JIT {
7479
std::vector<uint8_t> code_buffer_;
7580
};
7681

77-
class JitTranslator {
78-
public:
79-
void TranslateSimd(uint8_t op) {
80-
if (op == 0x01) { // Example Op: ADD_SIMD
81-
emitter_.EmitVAddPs(0, 1, 2);
82-
} else if (op == 0x02) { // Example Op: FENCE
83-
emitter_.EmitStoreFence();
84-
}
85-
}
86-
87-
private:
88-
Avx512Emitter emitter_;
89-
};
90-
9182
}

src/core/JitDispatcher.hpp

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313
namespace KytyPS5::Core {
1414

1515
struct alignas(64) ThreadContext {
16-
uint64_t gprs[32];
16+
uint64_t gprs[16]; // x86-64 has 16 GPRs (rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, r8-r15)
1717
uint64_t sp = 0;
1818
uint64_t pc = 0;
19-
uint64_t nzcv = 0;
19+
uint64_t rflags = 0;
2020
};
2121

2222
struct OpMov {
@@ -173,24 +173,10 @@ class JitDispatcher {
173173
if (op.base_reg >= 12) {
174174
EmitFillMove(op.base_reg, 10);
175175
}
176+
// MOV d, [b + offset]
176177
PushByte(0x48);
177-
PushByte(0x89);
178-
PushModRM(0, b);
179-
if (op.offset != 0) {
180-
PushByte(0x48);
181-
PushByte(0x05);
182-
const uint32_t off = static_cast<uint32_t>(op.offset);
183-
for (int i = 0; i < 4; ++i) {
184-
PushByte(static_cast<uint8_t>((off >> (i * 8)) & 0xFF));
185-
}
186-
}
187-
PushByte(0xE8);
188-
for (int i = 0; i < 4; ++i) {
189-
PushByte(0x00);
190-
}
191-
PushByte(0x48);
192-
PushByte(0x89);
193-
PushModRM(d, 0);
178+
PushByte(0x8B);
179+
PushModRM(d, b, static_cast<uint32_t>(op.offset));
194180
if (op.reg_dest >= 12) {
195181
EmitSpillMove(op.reg_dest, d);
196182
}
@@ -205,12 +191,15 @@ class JitDispatcher {
205191
if (op.base_reg >= 12) {
206192
EmitFillMove(op.base_reg, 10);
207193
}
194+
// MOV [b + offset], s
208195
PushByte(0x48);
209196
PushByte(0x89);
210-
PushModRM(b, s, static_cast<uint32_t>(op.offset));
197+
PushModRM(s, b, static_cast<uint32_t>(op.offset));
211198
}
212199

213200
void EmitJmp(const OpJmp& op) {
201+
// JMP rel32 — caller must compute relative offset from end of this instruction
202+
// For scaffolding, emit placeholder that will be patched later
214203
PushByte(0xE9);
215204
const uint32_t rel = static_cast<uint32_t>(op.target_addr);
216205
for (int i = 0; i < 4; ++i) {
@@ -219,22 +208,21 @@ class JitDispatcher {
219208
}
220209

221210
void EmitSyscall(const OpSyscall& op) {
211+
// MOV RAX, call_id
222212
PushByte(0x48);
223213
PushByte(0xB8);
224214
const uint64_t id = op.call_id;
225215
for (int i = 0; i < 8; ++i) {
226216
PushByte(static_cast<uint8_t>((id >> (i * 8)) & 0xFF));
227217
}
218+
// SYSCALL
228219
PushByte(0x0F);
229220
PushByte(0x05);
230221
}
231222

232223
void EmitAvx512(const OpAvx512& op) {
233-
(void)avx_emitter_->EmitInstruction(op.opcode, op.zmm_reg);
234-
PushByte(0x62);
235-
PushByte(0x00);
236-
PushByte(0x00);
237-
PushByte(0x00);
224+
// Delegate to the AVX-512 emitter for proper encoding
225+
avx_emitter_->EmitRaw(op.opcode, op.zmm_reg, code_buffer_);
238226
}
239227

240228
std::vector<uint8_t> code_buffer_;

src/emulator.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,8 @@ static void Execute(const std::filesystem::path& game_patch) {
175175
},
176176
&patch_path);
177177
Libs::Graphics::WindowRun();
178-
std::quick_exit(0);
178+
KytyClose();
179+
std::_Exit(0);
179180
}
180181

181182
void Run(const RunOptions& options) {

src/graphics/host_gpu/graphicContext.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "graphics/host_gpu/vulkanCommon.h" // IWYU pragma: export
77
#include "graphics/host_gpu/vulkanInstance.h"
88

9+
#include <memory>
910
#include <vector>
1011
#include <vk_mem_alloc.h>
1112

@@ -32,7 +33,7 @@ struct GraphicContext: public VulkanInstance {
3233
void AppendHardwareRayTracingDeviceExtensions(
3334
const std::vector<vk::ExtensionProperties>& available_extensions,
3435
std::vector<const char*>& device_extensions);
35-
void LoadHardwareRayTracingFunctions() const;
36+
void LoadHardwareRayTracingFunctions();
3637

3738
uint32_t screen_width = 0;
3839
uint32_t screen_height = 0;

src/graphics/host_gpu/renderer/image/image.cpp

Lines changed: 50 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -590,8 +590,9 @@ void Image::CopyImageWithBuffer(Image& source, Buffer& buffer) {
590590
}
591591

592592
void Image::CopyMip(Image& source, uint32_t mip, uint32_t layer) {
593-
EXIT_IF(m_scheduler == nullptr || source.backing.samples != backing.samples ||
594-
mip >= backing.mip_levels || layer >= backing.layers);
593+
EXIT_IF(m_scheduler == nullptr || m_graphics == nullptr ||
594+
source.backing.samples != backing.samples || mip >= backing.mip_levels ||
595+
layer >= backing.layers);
595596
m_scheduler->EndRendering();
596597
const auto width = std::max(backing.extent.width >> mip, 1u);
597598
const auto height = std::max(backing.extent.height >> mip, 1u);
@@ -600,24 +601,59 @@ void Image::CopyMip(Image& source, uint32_t mip, uint32_t layer) {
600601
const auto [source_layers, destination_layers] = SanitizeCopyLayers(source, *this, depth);
601602
const auto aspects = FullAspectMask(source.backing.format);
602603
EXIT_IF(aspects != FullAspectMask(backing.format));
603-
std::array<vk::ImageCopy, 2> copies {};
604-
uint32_t copy_count = 0;
605-
for (const auto aspect: {vk::ImageAspectFlagBits::eColor, vk::ImageAspectFlagBits::eDepth,
606-
vk::ImageAspectFlagBits::eStencil}) {
607-
if (!static_cast<bool>(aspects & aspect)) {
604+
auto command = m_scheduler->Current().Handle();
605+
Transit(vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits2::eTransferWrite, {}, command);
606+
source.Transit(vk::ImageLayout::eTransferSrcOptimal, vk::AccessFlagBits2::eTransferRead, {},
607+
command);
608+
609+
const auto non_stencil = aspects & ~vk::ImageAspectFlagBits::eStencil;
610+
for (const auto aspect: {vk::ImageAspectFlagBits::eColor, vk::ImageAspectFlagBits::eDepth}) {
611+
if (!static_cast<bool>(non_stencil & aspect)) {
608612
continue;
609613
}
610-
auto& copy = copies[copy_count++];
614+
vk::ImageCopy copy {};
611615
copy.srcSubresource = {aspect, 0, 0, source_layers};
612616
copy.dstSubresource = {aspect, mip, layer, destination_layers};
613617
copy.extent = {width, height, depth};
618+
command.copyImage(source.backing.image, vk::ImageLayout::eTransferSrcOptimal, backing.image,
619+
vk::ImageLayout::eTransferDstOptimal, 1, &copy);
620+
}
621+
622+
// Some AMD hosts drop stencil during image-to-image copies of packed D*S8
623+
// formats. Route the stencil plane through a scratch buffer instead.
624+
if (static_cast<bool>(aspects & vk::ImageAspectFlagBits::eStencil)) {
625+
const auto stencil_bytes =
626+
static_cast<uint64_t>(width) * height * depth * source_layers;
627+
EXIT_IF(stencil_bytes == 0);
628+
Buffer scratch(*m_graphics, *m_scheduler, MemoryUsage::DeviceLocal, 0,
629+
vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst,
630+
stencil_bytes);
631+
vk::BufferImageCopy region {};
632+
region.imageSubresource = {vk::ImageAspectFlagBits::eStencil, 0, 0, source_layers};
633+
region.imageExtent = {width, height, depth};
634+
command.copyImageToBuffer(source.backing.image, vk::ImageLayout::eTransferSrcOptimal,
635+
scratch.Handle(), 1, &region);
636+
637+
vk::BufferMemoryBarrier2 buffer_barrier {};
638+
buffer_barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer;
639+
buffer_barrier.srcAccessMask = vk::AccessFlagBits2::eTransferWrite;
640+
buffer_barrier.dstStageMask = vk::PipelineStageFlagBits2::eTransfer;
641+
buffer_barrier.dstAccessMask = vk::AccessFlagBits2::eTransferRead;
642+
buffer_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
643+
buffer_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
644+
buffer_barrier.buffer = scratch.Handle();
645+
buffer_barrier.size = stencil_bytes;
646+
vk::DependencyInfo dependency {};
647+
dependency.bufferMemoryBarrierCount = 1;
648+
dependency.pBufferMemoryBarriers = &buffer_barrier;
649+
command.pipelineBarrier2(dependency);
650+
651+
region.imageSubresource = {vk::ImageAspectFlagBits::eStencil, mip, layer,
652+
destination_layers};
653+
command.copyBufferToImage(scratch.Handle(), backing.image,
654+
vk::ImageLayout::eTransferDstOptimal, 1, &region);
614655
}
615-
auto command = m_scheduler->Current().Handle();
616-
Transit(vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits2::eTransferWrite, {}, command);
617-
source.Transit(vk::ImageLayout::eTransferSrcOptimal, vk::AccessFlagBits2::eTransferRead, {},
618-
command);
619-
command.copyImage(source.backing.image, vk::ImageLayout::eTransferSrcOptimal, backing.image,
620-
vk::ImageLayout::eTransferDstOptimal, copy_count, copies.data());
656+
621657
Transit(vk::ImageLayout::eGeneral,
622658
vk::AccessFlagBits2::eShaderRead | vk::AccessFlagBits2::eTransferRead, {}, command);
623659
}

0 commit comments

Comments
 (0)