mirror of
https://github.com/hedge-dev/UnleashedRecomp.git
synced 2026-04-27 04:41:39 +00:00
Implemented guest-to-host function pointers (WIP)
Co-Authored-By: Skyth (Asilkan) <19259897+blueskythlikesclouds@users.noreply.github.com>
This commit is contained in:
parent
0962560ec9
commit
8623f5d778
2 changed files with 152 additions and 26 deletions
|
|
@ -918,23 +918,23 @@ static void ProcSetRenderState(const RenderCommand& cmd)
|
|||
|
||||
static const std::pair<GuestRenderState, void*> g_setRenderStateFunctions[] =
|
||||
{
|
||||
{ D3DRS_ZENABLE, GuestFunction<SetRenderState<D3DRS_ZENABLE>> },
|
||||
{ D3DRS_ZWRITEENABLE, GuestFunction<SetRenderState<D3DRS_ZWRITEENABLE>> },
|
||||
{ D3DRS_ALPHATESTENABLE, GuestFunction<SetRenderState<D3DRS_ALPHATESTENABLE>> },
|
||||
{ D3DRS_SRCBLEND, GuestFunction<SetRenderState<D3DRS_SRCBLEND>> },
|
||||
{ D3DRS_DESTBLEND, GuestFunction<SetRenderState<D3DRS_DESTBLEND>> },
|
||||
{ D3DRS_CULLMODE, GuestFunction<SetRenderState<D3DRS_CULLMODE>> },
|
||||
{ D3DRS_ZFUNC, GuestFunction<SetRenderState<D3DRS_ZFUNC>> },
|
||||
{ D3DRS_ALPHAREF, GuestFunction<SetRenderState<D3DRS_ALPHAREF>> },
|
||||
{ D3DRS_ALPHABLENDENABLE, GuestFunction<SetRenderState<D3DRS_ALPHABLENDENABLE>> },
|
||||
{ D3DRS_BLENDOP, GuestFunction<SetRenderState<D3DRS_BLENDOP>> },
|
||||
{ D3DRS_SCISSORTESTENABLE, GuestFunction<SetRenderState<D3DRS_SCISSORTESTENABLE>> },
|
||||
{ D3DRS_SLOPESCALEDEPTHBIAS, GuestFunction<SetRenderState<D3DRS_SLOPESCALEDEPTHBIAS>> },
|
||||
{ D3DRS_DEPTHBIAS, GuestFunction<SetRenderState<D3DRS_DEPTHBIAS>> },
|
||||
{ D3DRS_SRCBLENDALPHA, GuestFunction<SetRenderState<D3DRS_SRCBLENDALPHA>> },
|
||||
{ D3DRS_DESTBLENDALPHA, GuestFunction<SetRenderState<D3DRS_DESTBLENDALPHA>> },
|
||||
{ D3DRS_BLENDOPALPHA, GuestFunction<SetRenderState<D3DRS_BLENDOPALPHA>> },
|
||||
{ D3DRS_COLORWRITEENABLE, GuestFunction<SetRenderState<D3DRS_COLORWRITEENABLE>> }
|
||||
{ D3DRS_ZENABLE, HostToGuestFunction<SetRenderState<D3DRS_ZENABLE>> },
|
||||
{ D3DRS_ZWRITEENABLE, HostToGuestFunction<SetRenderState<D3DRS_ZWRITEENABLE>> },
|
||||
{ D3DRS_ALPHATESTENABLE, HostToGuestFunction<SetRenderState<D3DRS_ALPHATESTENABLE>> },
|
||||
{ D3DRS_SRCBLEND, HostToGuestFunction<SetRenderState<D3DRS_SRCBLEND>> },
|
||||
{ D3DRS_DESTBLEND, HostToGuestFunction<SetRenderState<D3DRS_DESTBLEND>> },
|
||||
{ D3DRS_CULLMODE, HostToGuestFunction<SetRenderState<D3DRS_CULLMODE>> },
|
||||
{ D3DRS_ZFUNC, HostToGuestFunction<SetRenderState<D3DRS_ZFUNC>> },
|
||||
{ D3DRS_ALPHAREF, HostToGuestFunction<SetRenderState<D3DRS_ALPHAREF>> },
|
||||
{ D3DRS_ALPHABLENDENABLE, HostToGuestFunction<SetRenderState<D3DRS_ALPHABLENDENABLE>> },
|
||||
{ D3DRS_BLENDOP, HostToGuestFunction<SetRenderState<D3DRS_BLENDOP>> },
|
||||
{ D3DRS_SCISSORTESTENABLE, HostToGuestFunction<SetRenderState<D3DRS_SCISSORTESTENABLE>> },
|
||||
{ D3DRS_SLOPESCALEDEPTHBIAS, HostToGuestFunction<SetRenderState<D3DRS_SLOPESCALEDEPTHBIAS>> },
|
||||
{ D3DRS_DEPTHBIAS, HostToGuestFunction<SetRenderState<D3DRS_DEPTHBIAS>> },
|
||||
{ D3DRS_SRCBLENDALPHA, HostToGuestFunction<SetRenderState<D3DRS_SRCBLENDALPHA>> },
|
||||
{ D3DRS_DESTBLENDALPHA, HostToGuestFunction<SetRenderState<D3DRS_DESTBLENDALPHA>> },
|
||||
{ D3DRS_BLENDOPALPHA, HostToGuestFunction<SetRenderState<D3DRS_BLENDOPALPHA>> },
|
||||
{ D3DRS_COLORWRITEENABLE, HostToGuestFunction<SetRenderState<D3DRS_COLORWRITEENABLE>> }
|
||||
};
|
||||
|
||||
static std::unique_ptr<RenderPipeline> 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<void*>(GuestFunction<SetRenderStateUnimplemented>));
|
||||
g_codeCache.Insert(functionOffset, reinterpret_cast<void*>(HostToGuestFunction<SetRenderStateUnimplemented>));
|
||||
|
||||
for (size_t i = 0; i < _countof(device->setRenderStateFunctions); i++)
|
||||
device->setRenderStateFunctions[i] = functionOffset;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include <cpu/ppc_context.h>
|
||||
#include <array>
|
||||
#include "xbox.h"
|
||||
#include "memory.h"
|
||||
|
||||
template <typename R, typename... T>
|
||||
constexpr std::tuple<T...> 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<typename T>
|
||||
FORCEINLINE constexpr static std::enable_if_t<!std::is_pointer_v<T>, T> GetValue(PPCContext& ctx, uint8_t* base, size_t idx) noexcept
|
||||
{
|
||||
|
|
@ -106,6 +151,31 @@ struct ArgTranslator
|
|||
|
||||
return reinterpret_cast<T>(base + static_cast<uint32_t>(v));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
FORCEINLINE constexpr static std::enable_if_t<!std::is_pointer_v<T>, void> SetValue(PPCContext& ctx, uint8_t* base, size_t idx, T value) noexcept
|
||||
{
|
||||
if constexpr (is_precise_v<T>)
|
||||
{
|
||||
SetPrecisionArgumentValue(ctx, base, idx, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetIntegerArgumentValue(ctx, base, idx, value);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
FORCEINLINE constexpr static std::enable_if_t<std::is_pointer_v<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<auto Func, int I = 0, typename ...TArgs>
|
||||
FORCEINLINE void _translate_args(PPCContext& ctx, uint8_t* base, std::tuple<TArgs...>&) noexcept
|
||||
requires (I >= sizeof...(TArgs))
|
||||
FORCEINLINE void _translate_args_to_host(PPCContext& ctx, uint8_t* base, std::tuple<TArgs...>&) noexcept
|
||||
requires (I >= sizeof...(TArgs))
|
||||
{
|
||||
}
|
||||
|
||||
template <auto Func, int I = 0, typename ...TArgs>
|
||||
FORCEINLINE std::enable_if_t<(I < sizeof...(TArgs)), void> _translate_args(PPCContext& ctx, uint8_t* base, std::tuple<TArgs...>& tpl) noexcept
|
||||
FORCEINLINE std::enable_if_t<(I < sizeof...(TArgs)), void> _translate_args_to_host(PPCContext& ctx, uint8_t* base, std::tuple<TArgs...>& tpl) noexcept
|
||||
{
|
||||
using T = std::tuple_element_t<I, std::remove_reference_t<decltype(tpl)>>;
|
||||
std::get<I>(tpl) = ArgTranslator::GetValue<T>(ctx, base, arg_ordinal_t<Func, I>::value);
|
||||
|
||||
_translate_args<Func, I + 1>(ctx, base, tpl);
|
||||
_translate_args_to_host<Func, I + 1>(ctx, base, tpl);
|
||||
}
|
||||
|
||||
template<auto Func, int I = 0, typename ...TArgs>
|
||||
FORCEINLINE void _translate_args_to_guest(PPCContext& ctx, uint8_t* base, std::tuple<TArgs...>&) noexcept
|
||||
requires (I >= sizeof...(TArgs))
|
||||
{
|
||||
}
|
||||
|
||||
template <auto Func, int I = 0, typename ...TArgs>
|
||||
FORCEINLINE std::enable_if_t<(I < sizeof...(TArgs)), void> _translate_args_to_guest(PPCContext& ctx, uint8_t* base, std::tuple<TArgs...>& tpl) noexcept
|
||||
{
|
||||
using T = std::tuple_element_t<I, std::remove_reference_t<decltype(tpl)>>;
|
||||
ArgTranslator::SetValue<T>(ctx, base, I, std::get<I>(tpl));
|
||||
|
||||
_translate_args_to_guest<Func, I + 1>(ctx, base, tpl);
|
||||
}
|
||||
|
||||
template<auto Func>
|
||||
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<Func>(ctx, base, args);
|
||||
_translate_args_to_host<Func>(ctx, base, args);
|
||||
|
||||
if constexpr (std::is_same_v<ret_t, void>)
|
||||
{
|
||||
|
|
@ -207,8 +292,49 @@ FORCEINLINE PPC_FUNC(GuestFunction)
|
|||
}
|
||||
}
|
||||
|
||||
template<typename T, typename... TArgs>
|
||||
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<GuestToHostFunction<T, TArgs...>>(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<T>)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if constexpr (std::is_pointer_v<T>)
|
||||
{
|
||||
return static_cast<T>((uint64_t)g_memory.Translate(newCtx.r3.u32));
|
||||
}
|
||||
else if constexpr (is_precise_v<T>)
|
||||
{
|
||||
return static_cast<T>(newCtx.f1.f64);
|
||||
}
|
||||
else if constexpr (std::is_integral_v<T>)
|
||||
{
|
||||
return static_cast<T>(newCtx.r3.u64);
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert(false, "Unsupported return type.");
|
||||
}
|
||||
}
|
||||
|
||||
#define GUEST_FUNCTION_HOOK(subroutine, function) \
|
||||
PPC_FUNC(subroutine) { GuestFunction<function>(ctx, base); }
|
||||
PPC_FUNC(subroutine) { HostToGuestFunction<function>(ctx, base); }
|
||||
|
||||
#define GUEST_FUNCTION_STUB(subroutine) \
|
||||
PPC_FUNC(subroutine) { }
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue