Merge pull request #10 from mitch030504/claude/project-thread-4jegmq

Port three small fixes from the DarthMDev and KartPad forks
This commit is contained in:
mitch030504 authored and GitHub committed 2026-10-05 18:15:11 +02:00
commit 58b6d81ed1
5 files changed
+167 -30

No files matched your search

+12
View File
@@ -221,9 +221,13 @@ void render(const wgpu::RenderPassEncoder& pass) noexcept {
ImGui_ImplSDLRenderer3_RenderDrawData(data, renderer);
SDL_RenderPresent(renderer);
} else {
#ifdef AURORA_GFX_DEBUG_GROUPS
pass.PushDebugGroup("Aurora: Dear Imgui");
#endif
ImGui_ImplWGPU_RenderDrawData(data, pass.Get());
#ifdef AURORA_GFX_DEBUG_GROUPS
pass.PopDebugGroup();
#endif
}
}
@@ -287,9 +291,13 @@ void render(const wgpu::RenderPassEncoder& pass, const ImDrawData* data) noexcep
if (g_useSdlRenderer || data == nullptr) {
return;
}
#ifdef AURORA_GFX_DEBUG_GROUPS
pass.PushDebugGroup("Aurora: Dear Imgui");
#endif
ImGui_ImplWGPU_RenderDrawData(const_cast<ImDrawData*>(data), pass.Get());
#ifdef AURORA_GFX_DEBUG_GROUPS
pass.PopDebugGroup();
#endif
}
StereoOverlay latch_stereo_overlay() noexcept {
@@ -303,9 +311,13 @@ bool render_draw_data(const wgpu::RenderPassEncoder& pass, ImDrawData* data) noe
if (g_useSdlRenderer || data == nullptr || ImGui::GetCurrentContext() == nullptr) {
return false;
}
#ifdef AURORA_GFX_DEBUG_GROUPS
pass.PushDebugGroup("Aurora: Dear Imgui headset panel");
#endif
ImGui_ImplWGPU_RenderDrawData(data, pass.Get());
#ifdef AURORA_GFX_DEBUG_GROUPS
pass.PopDebugGroup();
#endif
return true;
}
+58 -11
View File
@@ -8,6 +8,7 @@
#include <cstdint>
#include <filesystem>
#include <fstream>
#include <iterator>
#include <limits>
#include <map>
#include <memory>
@@ -294,14 +295,57 @@ inline bool ReadExact(const std::filesystem::path& hostPath,
HostReadFailure& failure) {
failure = HostReadFailure::None;
std::ifstream file(hostPath, std::ios::binary);
if (!file.is_open()) {
failure = HostReadFailure::MissingFile;
return false;
// DVD callbacks run on the guest thread, often reading the same stream
// file many times per second. Reuse a bounded set of handles without
// sharing seek positions with another host thread.
struct OpenFile {
std::filesystem::path path;
std::ifstream stream;
std::streamoff size = 0;
std::filesystem::file_time_type modified{};
uint64_t lastUse = 0;
};
static thread_local std::vector<OpenFile> openFiles;
static thread_local uint64_t useCount = 0;
constexpr size_t kMaxOpenFiles = 8;
auto found = std::find_if(openFiles.begin(), openFiles.end(),
[&](const OpenFile& entry) { return entry.path == hostPath; });
if (found != openFiles.end()) {
std::error_code ec;
const auto modified = std::filesystem::last_write_time(hostPath, ec);
if (ec || modified != found->modified) {
openFiles.erase(found);
found = openFiles.end();
}
}
file.seekg(0, std::ios::end);
const std::streamoff fileSize = file.tellg();
if (found == openFiles.end()) {
std::ifstream file(hostPath, std::ios::binary);
if (!file.is_open()) {
failure = HostReadFailure::MissingFile;
return false;
}
file.seekg(0, std::ios::end);
const std::streamoff size = file.tellg();
if (size < 0) {
failure = HostReadFailure::BadOffset;
return false;
}
std::error_code ec;
const auto modified = std::filesystem::last_write_time(hostPath, ec);
if (openFiles.size() == kMaxOpenFiles) {
const auto oldest = std::min_element(openFiles.begin(), openFiles.end(),
[](const OpenFile& a, const OpenFile& b) { return a.lastUse < b.lastUse; });
openFiles.erase(oldest);
}
openFiles.push_back({hostPath, std::move(file), size,
ec ? std::filesystem::file_time_type{} : modified, 0});
found = std::prev(openFiles.end());
}
found->lastUse = ++useCount;
const std::streamoff fileSize = found->size;
if (fileSize < 0 ||
offset > static_cast<uint64_t>(std::numeric_limits<std::streamoff>::max()) ||
offset >= static_cast<uint64_t>(fileSize)) {
@@ -316,17 +360,20 @@ inline bool ReadExact(const std::filesystem::path& hostPath,
}
std::vector<uint8_t> staged(length);
file.seekg(static_cast<std::streamoff>(offset), std::ios::beg);
if (!file) {
found->stream.clear();
found->stream.seekg(static_cast<std::streamoff>(offset), std::ios::beg);
if (!found->stream) {
failure = HostReadFailure::BadOffset;
openFiles.erase(found);
return false;
}
if (length != 0) {
file.read(reinterpret_cast<char*>(staged.data()),
static_cast<std::streamsize>(length));
if (file.gcount() != static_cast<std::streamsize>(length)) {
found->stream.read(reinterpret_cast<char*>(staged.data()),
static_cast<std::streamsize>(length));
if (found->stream.gcount() != static_cast<std::streamsize>(length)) {
failure = HostReadFailure::ShortRead;
openFiles.erase(found);
return false;
}
}
+68 -13
View File
@@ -1,20 +1,19 @@
#include "hle_stubs.h"
#include <cstdint>
#include <limits>
#include "memory.h"
#include "recomp_mod_loader.h"
#include "runtime_log.h"
extern "C" void GxNotifyGuestRamDmaWrite(uint32_t addr, uint32_t size);
// Native because a crafted Yaz0 run writes past the caller's buffer
// (github.com/vabold/szsHaxx)
// https://github.com/vabold/Kinoko/blob/main/source/egg/core/Decomp.cc
extern "C" uint32_t EGG_Decomp_decodeSZS_80218c2c(uint32_t src, uint32_t dst)
{
const uint32_t expandSize = (static_cast<uint32_t>(MemoryInline::FlatRead8(src + 4)) << 24) |
(static_cast<uint32_t>(MemoryInline::FlatRead8(src + 5)) << 16) |
(static_cast<uint32_t>(MemoryInline::FlatRead8(src + 6)) << 8) |
static_cast<uint32_t>(MemoryInline::FlatRead8(src + 7));
template <typename Access>
static uint32_t DecodeSZS(uint32_t src, uint32_t expandSize, Access& access) {
uint32_t srcIdx = 16;
uint32_t dstIdx = 0;
uint32_t mask = 0;
@@ -22,15 +21,15 @@ extern "C" uint32_t EGG_Decomp_decodeSZS_80218c2c(uint32_t src, uint32_t dst)
while (static_cast<int32_t>(dstIdx) < static_cast<int32_t>(expandSize)) {
if (mask == 0) {
flags = MemoryInline::FlatRead8(src + srcIdx++);
flags = access.ReadSource(srcIdx++);
mask = 0x80;
}
if ((flags & mask) != 0) {
MemoryInline::FlatWrite8(dst + dstIdx++, MemoryInline::FlatRead8(src + srcIdx++));
access.WriteOutput(dstIdx++, access.ReadSource(srcIdx++));
} else {
const uint32_t high = MemoryInline::FlatRead8(src + srcIdx);
const uint32_t low = MemoryInline::FlatRead8(src + srcIdx + 1);
const uint32_t high = access.ReadSource(srcIdx);
const uint32_t low = access.ReadSource(srcIdx + 1);
srcIdx += 2;
const uint32_t rep = (high << 8) | low;
@@ -48,7 +47,7 @@ extern "C" uint32_t EGG_Decomp_decodeSZS_80218c2c(uint32_t src, uint32_t dst)
uint32_t count = rep >> 12;
count = count != 0
? count + 2
: static_cast<uint32_t>(MemoryInline::FlatRead8(src + srcIdx++)) + 18;
: static_cast<uint32_t>(access.ReadSource(srcIdx++)) + 18;
for (uint32_t i = 0; i < count; ++i) {
if (dstIdx >= expandSize) {
@@ -59,7 +58,7 @@ extern "C" uint32_t EGG_Decomp_decodeSZS_80218c2c(uint32_t src, uint32_t dst)
"The game stopped decoding a malformed Yaz0 file.");
std::abort();
}
MemoryInline::FlatWrite8(dst + dstIdx++, MemoryInline::FlatRead8(dst + copyIdx++));
access.WriteOutput(dstIdx++, access.ReadOutput(copyIdx++));
}
}
@@ -69,5 +68,61 @@ extern "C" uint32_t EGG_Decomp_decodeSZS_80218c2c(uint32_t src, uint32_t dst)
return expandSize;
}
struct GuestSZSAccess {
uint32_t src;
uint32_t dst;
uint8_t ReadSource(uint32_t offset) const { return MemoryInline::FlatRead8(src + offset); }
uint8_t ReadOutput(uint32_t offset) const { return MemoryInline::FlatRead8(dst + offset); }
void WriteOutput(uint32_t offset, uint8_t value) const {
MemoryInline::FlatWrite8(dst + offset, value);
}
};
struct HostSZSAccess {
const uint8_t* src;
uint8_t* dst;
uint8_t ReadSource(uint32_t offset) const { return src[offset]; }
uint8_t ReadOutput(uint32_t offset) const { return dst[offset]; }
void WriteOutput(uint32_t offset, uint8_t value) const { dst[offset] = value; }
};
static bool HasDeferredReadPages(uint32_t address, size_t length) {
const uint32_t first = address >> MemoryInline::kPageShift;
const uint32_t last = static_cast<uint32_t>(
(static_cast<uint64_t>(address) + length - 1) >> MemoryInline::kPageShift);
for (uint32_t page = first; page <= last; ++page) {
if (MemoryInline::g_deferredReadCoveredPages[page] != 0) return true;
}
return false;
}
extern "C" uint32_t EGG_Decomp_decodeSZS_80218c2c(uint32_t src, uint32_t dst)
{
const uint32_t expandSize = (static_cast<uint32_t>(MemoryInline::FlatRead8(src + 4)) << 24) |
(static_cast<uint32_t>(MemoryInline::FlatRead8(src + 5)) << 16) |
(static_cast<uint32_t>(MemoryInline::FlatRead8(src + 6)) << 8) |
static_cast<uint32_t>(MemoryInline::FlatRead8(src + 7));
// A token produces at least one byte; all-literal data is the largest
// valid input (one flag per eight output bytes). Three extra bytes cover
// the final malformed run before its output-overrun check aborts.
const size_t maxSourceBytes = 16ull + expandSize + (static_cast<uint64_t>(expandSize) + 7) / 8 + 3;
if (expandSize != 0 && expandSize <= static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) &&
!GuestFlat::RequiresCheckedAccess() &&
Memory::Contains(src, maxSourceBytes) && Memory::Contains(dst, expandSize) &&
!HasDeferredReadPages(src, maxSourceBytes) && !HasDeferredReadPages(dst, expandSize) &&
!RecompMod::ExecutableWriteGuardMayHit(dst, expandSize)) {
HostSZSAccess access{Memory::GetPointer(src, maxSourceBytes), Memory::GetPointer(dst, expandSize)};
const uint32_t decoded = DecodeSZS(src, expandSize, access);
GxNotifyGuestRamDmaWrite(dst, decoded);
return decoded;
}
GuestSZSAccess access{src, dst};
return DecodeSZS(src, expandSize, access);
}
PPC_NATIVE_OVERRIDE(80218C2C, EGG_Decomp_decodeSZS_80218c2c, uint32_t,
(uint32_t src, uint32_t dst), (src, dst));
+21 -3
View File
@@ -54,6 +54,9 @@ constexpr int kMaxSslSessions = 4;
struct SslSession {
bool active = false;
bool handshaked = false;
// A failed POSIX TLS write cannot be resumed with a new guest buffer.
// Keep the slot and socket ownership intact until explicit teardown.
bool failed = false;
bool plaintextWfc = false;
uint32_t socketFd = UINT32_MAX;
NativeSocket native = kInvalidSocket;
@@ -761,6 +764,14 @@ static int32_t SslHandshakeImpl(SslSession& ssl) {
return SSL_OK;
}
static int32_t FailSslWrite(SslSession& ssl) {
ssl.failed = true;
// Stop transport I/O without deleting the guest descriptor or freeing a
// session still referenced by the IOCTLV_NET_SSL_WRITE caller.
::shutdown(ssl.native, SHUT_RDWR);
return SSL_ERR_FAILED;
}
static int32_t SslWrite(SslSession& ssl, const uint8_t* data, uint32_t size) {
if (!data || size == 0) {
return SSL_ERR_ZERO;
@@ -795,12 +806,11 @@ static int32_t SslWrite(SslSession& ssl, const uint8_t* data, uint32_t size) {
}
if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
if (std::chrono::steady_clock::now() >= writeDeadline) {
DeleteWiiSocket(ssl.socketFd);
return SSL_ERR_FAILED;
return FailSslWrite(ssl);
}
continue;
}
return SSL_ERR_FAILED;
return FailSslWrite(ssl);
}
return static_cast<int32_t>(totalWritten);
}
@@ -842,6 +852,9 @@ static int32_t SslRead(SslSession& ssl, uint8_t* out, uint32_t size) {
// The handshake runs on every SSL read/write, so a failure repeats for as long
// as the session lives; report only the first one.
static int32_t SslHandshake(SslSession& ssl) {
if (ssl.failed) {
return SSL_ERR_FAILED;
}
const int32_t result = SslHandshakeImpl(ssl);
if (result != SSL_OK && !ssl.loggedHandshakeFail) {
ssl.loggedHandshakeFail = true;
@@ -947,6 +960,11 @@ int32_t HandleSslIoctlv(uint32_t cmd, const std::vector<IoVector>& in, const std
WriteSslReturn(in, SSL_ERR_ID);
return 0;
}
// Reject before NAS buffering can acknowledge data on a failed session.
if (g_sslSessions[sslId].failed) {
WriteSslReturn(in, SSL_ERR_FAILED);
return 0;
}
if (out.size() < 2 || !out[1].address) {
WriteSslReturn(in, SSL_ERR_FAILED);
return 0;
+8 -3
View File
@@ -104,10 +104,15 @@ extern "C" void DVDInit_8015EA1C();
extern "C" uint32_t g_dvdFstReservedBase;
extern "C" uint32_t g_dvdFstReservedSize;
// Byte-wise copy into guest RAM plus the DMA notification the GX caches need.
// DVD DMA normally targets ordinary RAM. Keep scalar writes for executable
// ranges so the translated-code write guard still sees every modified byte.
static void CopyToGuestAsDma(uint32_t dest, const uint8_t* data, size_t size) {
for (size_t i = 0; i < size; ++i) {
Memory::Write8(dest + static_cast<uint32_t>(i), data[i]);
if (size != 0 && !RecompMod::ExecutableWriteGuardMayHit(dest, size)) {
std::memcpy(Memory::GetPointer(dest, size), data, size);
} else {
for (size_t i = 0; i < size; ++i) {
Memory::Write8(dest + static_cast<uint32_t>(i), data[i]);
}
}
GxNotifyGuestRamDmaWrite(dest, static_cast<uint32_t>(size));
}