From 8623f5d7788fd2170436da29e97805710ac8a310 Mon Sep 17 00:00:00 2001 From: Hyper <34012267+hyperbx@users.noreply.github.com> Date: Sat, 9 Nov 2024 14:56:17 +0000 Subject: [PATCH] Implemented guest-to-host function pointers (WIP) Co-Authored-By: Skyth (Asilkan) <19259897+blueskythlikesclouds@users.noreply.github.com> --- UnleashedRecomp/gpu/video.cpp | 36 ++++---- UnleashedRecomp/kernel/function.h | 142 ++++++++++++++++++++++++++++-- 2 files changed, 152 insertions(+), 26 deletions(-) diff --git a/UnleashedRecomp/gpu/video.cpp b/UnleashedRecomp/gpu/video.cpp index 17cdfd54..fd6d371a 100644 --- a/UnleashedRecomp/gpu/video.cpp +++ b/UnleashedRecomp/gpu/video.cpp @@ -918,23 +918,23 @@ static void ProcSetRenderState(const RenderCommand& cmd) static const std::pair g_setRenderStateFunctions[] = { - { D3DRS_ZENABLE, GuestFunction> }, - { D3DRS_ZWRITEENABLE, GuestFunction> }, - { D3DRS_ALPHATESTENABLE, GuestFunction> }, - { D3DRS_SRCBLEND, GuestFunction> }, - { D3DRS_DESTBLEND, GuestFunction> }, - { D3DRS_CULLMODE, GuestFunction> }, - { D3DRS_ZFUNC, GuestFunction> }, - { D3DRS_ALPHAREF, GuestFunction> }, - { D3DRS_ALPHABLENDENABLE, GuestFunction> }, - { D3DRS_BLENDOP, GuestFunction> }, - { D3DRS_SCISSORTESTENABLE, GuestFunction> }, - { D3DRS_SLOPESCALEDEPTHBIAS, GuestFunction> }, - { D3DRS_DEPTHBIAS, GuestFunction> }, - { D3DRS_SRCBLENDALPHA, GuestFunction> }, - { D3DRS_DESTBLENDALPHA, GuestFunction> }, - { D3DRS_BLENDOPALPHA, GuestFunction> }, - { D3DRS_COLORWRITEENABLE, GuestFunction> } + { D3DRS_ZENABLE, HostToGuestFunction> }, + { D3DRS_ZWRITEENABLE, HostToGuestFunction> }, + { D3DRS_ALPHATESTENABLE, HostToGuestFunction> }, + { D3DRS_SRCBLEND, HostToGuestFunction> }, + { D3DRS_DESTBLEND, HostToGuestFunction> }, + { D3DRS_CULLMODE, HostToGuestFunction> }, + { D3DRS_ZFUNC, HostToGuestFunction> }, + { D3DRS_ALPHAREF, HostToGuestFunction> }, + { D3DRS_ALPHABLENDENABLE, HostToGuestFunction> }, + { D3DRS_BLENDOP, HostToGuestFunction> }, + { D3DRS_SCISSORTESTENABLE, HostToGuestFunction> }, + { D3DRS_SLOPESCALEDEPTHBIAS, HostToGuestFunction> }, + { D3DRS_DEPTHBIAS, HostToGuestFunction> }, + { D3DRS_SRCBLENDALPHA, HostToGuestFunction> }, + { D3DRS_DESTBLENDALPHA, HostToGuestFunction> }, + { D3DRS_BLENDOPALPHA, HostToGuestFunction> }, + { D3DRS_COLORWRITEENABLE, HostToGuestFunction> } }; static std::unique_ptr g_resolveMsaaDepthPipelines[3]; @@ -1214,7 +1214,7 @@ static uint32_t CreateDevice(uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, memset(device, 0, sizeof(*device)); uint32_t functionOffset = 0x443344; // D3D - g_codeCache.Insert(functionOffset, reinterpret_cast(GuestFunction)); + g_codeCache.Insert(functionOffset, reinterpret_cast(HostToGuestFunction)); for (size_t i = 0; i < _countof(device->setRenderStateFunctions); i++) device->setRenderStateFunctions[i] = functionOffset; diff --git a/UnleashedRecomp/kernel/function.h b/UnleashedRecomp/kernel/function.h index 14eb09cc..4afc7721 100644 --- a/UnleashedRecomp/kernel/function.h +++ b/UnleashedRecomp/kernel/function.h @@ -2,6 +2,7 @@ #include #include #include "xbox.h" +#include "memory.h" template constexpr std::tuple function_args(R(*)(T...)) noexcept @@ -78,10 +79,54 @@ struct ArgTranslator [[unlikely]] default: break; } - // how did you end up here + // TODO: get value from stack. return 0; } + FORCEINLINE constexpr static void SetIntegerArgumentValue(PPCContext& ctx, uint8_t* base, size_t arg, uint64_t value) noexcept + { + if (arg <= 7) + { + switch (arg) + { + case 0: ctx.r3.u64 = value; return; + case 1: ctx.r4.u64 = value; return; + case 2: ctx.r5.u64 = value; return; + case 3: ctx.r6.u64 = value; return; + case 4: ctx.r7.u64 = value; return; + case 5: ctx.r8.u64 = value; return; + case 6: ctx.r9.u64 = value; return; + case 7: ctx.r10.u64 = value; return; + [[unlikely]] default: break; + } + } + + assert(arg < 7 && "Pushing to stack memory is not yet supported."); + } + + FORCEINLINE static void SetPrecisionArgumentValue(PPCContext& ctx, uint8_t* base, size_t arg, double value) noexcept + { + switch (arg) + { + case 0: ctx.f1.f64 = value; return; + case 1: ctx.f2.f64 = value; return; + case 2: ctx.f3.f64 = value; return; + case 3: ctx.f4.f64 = value; return; + case 4: ctx.f5.f64 = value; return; + case 5: ctx.f6.f64 = value; return; + case 6: ctx.f7.f64 = value; return; + case 7: ctx.f8.f64 = value; return; + case 8: ctx.f9.f64 = value; return; + case 9: ctx.f10.f64 = value; return; + case 10: ctx.f11.f64 = value; return; + case 11: ctx.f12.f64 = value; return; + case 12: ctx.f13.f64 = value; return; + [[unlikely]] default: break; + } + + assert(arg < 12 && "Pushing to stack memory is not yet supported."); + } + template FORCEINLINE constexpr static std::enable_if_t, T> GetValue(PPCContext& ctx, uint8_t* base, size_t idx) noexcept { @@ -106,6 +151,31 @@ struct ArgTranslator return reinterpret_cast(base + static_cast(v)); } + + template + FORCEINLINE constexpr static std::enable_if_t, void> SetValue(PPCContext& ctx, uint8_t* base, size_t idx, T value) noexcept + { + if constexpr (is_precise_v) + { + SetPrecisionArgumentValue(ctx, base, idx, value); + } + else + { + SetIntegerArgumentValue(ctx, base, idx, value); + } + } + + template + FORCEINLINE constexpr static std::enable_if_t, void> SetValue(PPCContext& ctx, uint8_t* base, size_t idx, T value) noexcept + { + const auto v = g_memory.MapVirtual(value); + if (!v) + { + return; + } + + SetValue(ctx, base, idx, v); + } }; struct Argument @@ -155,27 +225,42 @@ struct arg_ordinal_t }; template -FORCEINLINE void _translate_args(PPCContext& ctx, uint8_t* base, std::tuple&) noexcept -requires (I >= sizeof...(TArgs)) +FORCEINLINE void _translate_args_to_host(PPCContext& ctx, uint8_t* base, std::tuple&) noexcept + requires (I >= sizeof...(TArgs)) { } template -FORCEINLINE std::enable_if_t<(I < sizeof...(TArgs)), void> _translate_args(PPCContext& ctx, uint8_t* base, std::tuple& tpl) noexcept +FORCEINLINE std::enable_if_t<(I < sizeof...(TArgs)), void> _translate_args_to_host(PPCContext& ctx, uint8_t* base, std::tuple& tpl) noexcept { using T = std::tuple_element_t>; std::get(tpl) = ArgTranslator::GetValue(ctx, base, arg_ordinal_t::value); - _translate_args(ctx, base, tpl); + _translate_args_to_host(ctx, base, tpl); +} + +template +FORCEINLINE void _translate_args_to_guest(PPCContext& ctx, uint8_t* base, std::tuple&) noexcept + requires (I >= sizeof...(TArgs)) +{ +} + +template +FORCEINLINE std::enable_if_t<(I < sizeof...(TArgs)), void> _translate_args_to_guest(PPCContext& ctx, uint8_t* base, std::tuple& tpl) noexcept +{ + using T = std::tuple_element_t>; + ArgTranslator::SetValue(ctx, base, I, std::get(tpl)); + + _translate_args_to_guest(ctx, base, tpl); } template -FORCEINLINE PPC_FUNC(GuestFunction) +FORCEINLINE PPC_FUNC(HostToGuestFunction) { using ret_t = decltype(std::apply(Func, function_args(Func))); auto args = function_args(Func); - _translate_args(ctx, base, args); + _translate_args_to_host(ctx, base, args); if constexpr (std::is_same_v) { @@ -207,8 +292,49 @@ FORCEINLINE PPC_FUNC(GuestFunction) } } +template +FORCEINLINE T GuestToHostFunction(uint32_t addr, TArgs... argv) +{ + auto args = std::make_tuple(argv...); + auto& currentCtx = *GetPPCContext(); + auto newCtx = PPCContext{}; + + newCtx.fn = currentCtx.fn; + newCtx.r1 = currentCtx.r1; + newCtx.r13 = currentCtx.r13; + newCtx.fpscr = currentCtx.fpscr; + + _translate_args_to_guest>(newCtx, (uint8_t*)g_memory.base, args); + + SetPPCContext(newCtx); + (*(PPCFunc**)(newCtx.fn + uint64_t(addr) * 2))(newCtx, (uint8_t*)g_memory.base); + currentCtx.fpscr = newCtx.fpscr; + SetPPCContext(currentCtx); + + if constexpr (std::is_void_v) + { + return; + } + else if constexpr (std::is_pointer_v) + { + return static_cast((uint64_t)g_memory.Translate(newCtx.r3.u32)); + } + else if constexpr (is_precise_v) + { + return static_cast(newCtx.f1.f64); + } + else if constexpr (std::is_integral_v) + { + return static_cast(newCtx.r3.u64); + } + else + { + static_assert(false, "Unsupported return type."); + } +} + #define GUEST_FUNCTION_HOOK(subroutine, function) \ - PPC_FUNC(subroutine) { GuestFunction(ctx, base); } + PPC_FUNC(subroutine) { HostToGuestFunction(ctx, base); } #define GUEST_FUNCTION_STUB(subroutine) \ PPC_FUNC(subroutine) { }