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[] =
|
static const std::pair<GuestRenderState, void*> g_setRenderStateFunctions[] =
|
||||||
{
|
{
|
||||||
{ D3DRS_ZENABLE, GuestFunction<SetRenderState<D3DRS_ZENABLE>> },
|
{ D3DRS_ZENABLE, HostToGuestFunction<SetRenderState<D3DRS_ZENABLE>> },
|
||||||
{ D3DRS_ZWRITEENABLE, GuestFunction<SetRenderState<D3DRS_ZWRITEENABLE>> },
|
{ D3DRS_ZWRITEENABLE, HostToGuestFunction<SetRenderState<D3DRS_ZWRITEENABLE>> },
|
||||||
{ D3DRS_ALPHATESTENABLE, GuestFunction<SetRenderState<D3DRS_ALPHATESTENABLE>> },
|
{ D3DRS_ALPHATESTENABLE, HostToGuestFunction<SetRenderState<D3DRS_ALPHATESTENABLE>> },
|
||||||
{ D3DRS_SRCBLEND, GuestFunction<SetRenderState<D3DRS_SRCBLEND>> },
|
{ D3DRS_SRCBLEND, HostToGuestFunction<SetRenderState<D3DRS_SRCBLEND>> },
|
||||||
{ D3DRS_DESTBLEND, GuestFunction<SetRenderState<D3DRS_DESTBLEND>> },
|
{ D3DRS_DESTBLEND, HostToGuestFunction<SetRenderState<D3DRS_DESTBLEND>> },
|
||||||
{ D3DRS_CULLMODE, GuestFunction<SetRenderState<D3DRS_CULLMODE>> },
|
{ D3DRS_CULLMODE, HostToGuestFunction<SetRenderState<D3DRS_CULLMODE>> },
|
||||||
{ D3DRS_ZFUNC, GuestFunction<SetRenderState<D3DRS_ZFUNC>> },
|
{ D3DRS_ZFUNC, HostToGuestFunction<SetRenderState<D3DRS_ZFUNC>> },
|
||||||
{ D3DRS_ALPHAREF, GuestFunction<SetRenderState<D3DRS_ALPHAREF>> },
|
{ D3DRS_ALPHAREF, HostToGuestFunction<SetRenderState<D3DRS_ALPHAREF>> },
|
||||||
{ D3DRS_ALPHABLENDENABLE, GuestFunction<SetRenderState<D3DRS_ALPHABLENDENABLE>> },
|
{ D3DRS_ALPHABLENDENABLE, HostToGuestFunction<SetRenderState<D3DRS_ALPHABLENDENABLE>> },
|
||||||
{ D3DRS_BLENDOP, GuestFunction<SetRenderState<D3DRS_BLENDOP>> },
|
{ D3DRS_BLENDOP, HostToGuestFunction<SetRenderState<D3DRS_BLENDOP>> },
|
||||||
{ D3DRS_SCISSORTESTENABLE, GuestFunction<SetRenderState<D3DRS_SCISSORTESTENABLE>> },
|
{ D3DRS_SCISSORTESTENABLE, HostToGuestFunction<SetRenderState<D3DRS_SCISSORTESTENABLE>> },
|
||||||
{ D3DRS_SLOPESCALEDEPTHBIAS, GuestFunction<SetRenderState<D3DRS_SLOPESCALEDEPTHBIAS>> },
|
{ D3DRS_SLOPESCALEDEPTHBIAS, HostToGuestFunction<SetRenderState<D3DRS_SLOPESCALEDEPTHBIAS>> },
|
||||||
{ D3DRS_DEPTHBIAS, GuestFunction<SetRenderState<D3DRS_DEPTHBIAS>> },
|
{ D3DRS_DEPTHBIAS, HostToGuestFunction<SetRenderState<D3DRS_DEPTHBIAS>> },
|
||||||
{ D3DRS_SRCBLENDALPHA, GuestFunction<SetRenderState<D3DRS_SRCBLENDALPHA>> },
|
{ D3DRS_SRCBLENDALPHA, HostToGuestFunction<SetRenderState<D3DRS_SRCBLENDALPHA>> },
|
||||||
{ D3DRS_DESTBLENDALPHA, GuestFunction<SetRenderState<D3DRS_DESTBLENDALPHA>> },
|
{ D3DRS_DESTBLENDALPHA, HostToGuestFunction<SetRenderState<D3DRS_DESTBLENDALPHA>> },
|
||||||
{ D3DRS_BLENDOPALPHA, GuestFunction<SetRenderState<D3DRS_BLENDOPALPHA>> },
|
{ D3DRS_BLENDOPALPHA, HostToGuestFunction<SetRenderState<D3DRS_BLENDOPALPHA>> },
|
||||||
{ D3DRS_COLORWRITEENABLE, GuestFunction<SetRenderState<D3DRS_COLORWRITEENABLE>> }
|
{ D3DRS_COLORWRITEENABLE, HostToGuestFunction<SetRenderState<D3DRS_COLORWRITEENABLE>> }
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::unique_ptr<RenderPipeline> g_resolveMsaaDepthPipelines[3];
|
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));
|
memset(device, 0, sizeof(*device));
|
||||||
|
|
||||||
uint32_t functionOffset = 0x443344; // D3D
|
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++)
|
for (size_t i = 0; i < _countof(device->setRenderStateFunctions); i++)
|
||||||
device->setRenderStateFunctions[i] = functionOffset;
|
device->setRenderStateFunctions[i] = functionOffset;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
#include <cpu/ppc_context.h>
|
#include <cpu/ppc_context.h>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include "xbox.h"
|
#include "xbox.h"
|
||||||
|
#include "memory.h"
|
||||||
|
|
||||||
template <typename R, typename... T>
|
template <typename R, typename... T>
|
||||||
constexpr std::tuple<T...> function_args(R(*)(T...)) noexcept
|
constexpr std::tuple<T...> function_args(R(*)(T...)) noexcept
|
||||||
|
|
@ -78,10 +79,54 @@ struct ArgTranslator
|
||||||
[[unlikely]] default: break;
|
[[unlikely]] default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// how did you end up here
|
// TODO: get value from stack.
|
||||||
return 0;
|
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>
|
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
|
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));
|
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
|
struct Argument
|
||||||
|
|
@ -155,27 +225,42 @@ struct arg_ordinal_t
|
||||||
};
|
};
|
||||||
|
|
||||||
template<auto Func, int I = 0, typename ...TArgs>
|
template<auto Func, int I = 0, typename ...TArgs>
|
||||||
FORCEINLINE void _translate_args(PPCContext& ctx, uint8_t* base, std::tuple<TArgs...>&) noexcept
|
FORCEINLINE void _translate_args_to_host(PPCContext& ctx, uint8_t* base, std::tuple<TArgs...>&) noexcept
|
||||||
requires (I >= sizeof...(TArgs))
|
requires (I >= sizeof...(TArgs))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template <auto Func, int I = 0, typename ...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)>>;
|
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);
|
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>
|
template<auto Func>
|
||||||
FORCEINLINE PPC_FUNC(GuestFunction)
|
FORCEINLINE PPC_FUNC(HostToGuestFunction)
|
||||||
{
|
{
|
||||||
using ret_t = decltype(std::apply(Func, function_args(Func)));
|
using ret_t = decltype(std::apply(Func, function_args(Func)));
|
||||||
|
|
||||||
auto args = 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>)
|
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) \
|
#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) \
|
#define GUEST_FUNCTION_STUB(subroutine) \
|
||||||
PPC_FUNC(subroutine) { }
|
PPC_FUNC(subroutine) { }
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue