Skip to content

Commit

Permalink
Fix "Ghosting fix" on UE5
Browse files Browse the repository at this point in the history
  • Loading branch information
praydog committed Jun 20, 2023
1 parent 14660bf commit 4349881
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 11 deletions.
37 changes: 36 additions & 1 deletion shared/sdk/FSceneView.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,42 @@
#pragma once

#include "Math.hpp"

namespace sdk {
struct FSceneViewInitOptions;
struct FSceneViewFamily;
struct FSceneViewStateInterface;

template <typename T>
struct FSceneViewProjectionDataT {
glm::vec<3, T> view_origin{};
__declspec(align(16)) glm::mat<4, 4, T, glm::defaultp> view_rotation_matrix{};
__declspec(align(16)) glm::mat<4, 4, T, glm::defaultp> projection_matrix{};

int32_t view_rect[4];
int32_t constrained_view_rect[4];
};

template <typename T>
struct FSceneViewInitOptionsT : public FSceneViewProjectionDataT<T> {
FSceneViewFamily* family{nullptr};
FSceneViewStateInterface* scene_view_state{nullptr};
void* actor{nullptr};
int32_t player_index{};

void* view_element_drawer{};

// FLinearColor
float background_color[4]{};
float overlay_color[4]{};
float color_scale[4]{};

// EStereoscopicPass
uint32_t stereo_pass{};
};

using FSceneViewInitOptions = FSceneViewInitOptionsT<float>;
using FSceneViewInitOptionsUE4 = FSceneViewInitOptionsT<float>;
using FSceneViewInitOptionsUE5 = FSceneViewInitOptionsT<double>;

struct FSceneView {
void constructor(const FSceneViewInitOptions* initOptions);
Expand Down
4 changes: 4 additions & 0 deletions shared/sdk/StereoStuff.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@

#include "FSceneView.hpp"

namespace sdk {
struct FSceneView;
}

enum ETextureCreateFlags : uint64_t { RenderTargetable = 1ull << 0, ResolveTargetable = 1ull << 1, ShaderResource = 1ull << 3, };
enum EStereoscopicPass { eSSP_FULL, eSSP_PRIMARY, eSSP_SECONDARY };

Expand Down
22 changes: 14 additions & 8 deletions src/mods/vr/FFakeStereoRenderingHook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2484,20 +2484,24 @@ constexpr auto INIT_OPTION_SCENE_STATE_INTERFACE_OFFSET = 0xB8;
constexpr auto INIT_OPTIONS_PROJECTION_MATRIX_OFFSET = 0x50;
constexpr auto INIT_OPTIONS_STEREO_PASS_OFFSET = 0x108;

constexpr auto test = offsetof(sdk::FSceneViewInitOptions, scene_view_state);
// FSceneView constructor hook
sdk::FSceneView* FFakeStereoRenderingHook::sceneview_constructor(sdk::FSceneView* view, sdk::FSceneViewInitOptions* init_options) {
sdk::FSceneView* FFakeStereoRenderingHook::sceneview_constructor(sdk::FSceneView* view, sdk::FSceneViewInitOptions* init_options, void* a3, void* a4) {
SPDLOG_INFO_ONCE("Called FSceneView constructor for the first time");

auto& vr = VR::get();

if (!g_hook->is_in_viewport_client_draw() || !vr->is_hmd_active()) {
return g_hook->m_sceneview_data.constructor_hook.call<sdk::FSceneView*>(view, init_options);
return g_hook->m_sceneview_data.constructor_hook.call<sdk::FSceneView*>(view, init_options, a3, a4);
}

auto& known_scene_states = g_hook->m_sceneview_data.known_scene_states;
std::scoped_lock _{g_hook->m_sceneview_data.mtx};

auto init_options_ue5 = (sdk::FSceneViewInitOptionsUE5*)init_options;

static uint32_t last_frame_count = 0;
static uint32_t last_index = 0;
auto& known_scene_states = g_hook->m_sceneview_data.known_scene_states;
auto& last_frame_count = g_hook->m_sceneview_data.last_frame_count;
auto& last_index = g_hook->m_sceneview_data.last_index;

if (last_frame_count != g_frame_count || last_index > 1) {
last_index = 0;
Expand Down Expand Up @@ -2554,8 +2558,10 @@ sdk::FSceneView* FFakeStereoRenderingHook::sceneview_constructor(sdk::FSceneView
//init_options_stereo_pass = 0;
}

auto& init_options_scene_state = *(void**)((uintptr_t)init_options + INIT_OPTION_SCENE_STATE_INTERFACE_OFFSET);
auto& init_options_stereo_pass = *(uint8_t*)((uintptr_t)init_options + INIT_OPTIONS_STEREO_PASS_OFFSET);
const auto is_ue5 = g_hook->has_double_precision();

auto& init_options_scene_state = is_ue5 ? init_options_ue5->scene_view_state : init_options->scene_view_state;
auto& init_options_stereo_pass = is_ue5 ? init_options_ue5->stereo_pass : init_options->stereo_pass;

if (init_options_scene_state != nullptr && !g_hook->m_sceneview_data.known_scene_states.contains(init_options_scene_state)) {
SPDLOG_INFO("Inserting new scene state {:x}", (uintptr_t)init_options_scene_state);
Expand All @@ -2579,7 +2585,7 @@ sdk::FSceneView* FFakeStereoRenderingHook::sceneview_constructor(sdk::FSceneView

last_index++;

return g_hook->m_sceneview_data.constructor_hook.call<sdk::FSceneView*>(view, init_options);
return g_hook->m_sceneview_data.constructor_hook.call<sdk::FSceneView*>(view, init_options, a3, a4);
}

void FFakeStereoRenderingHook::setup_view_family(ISceneViewExtension* extension, FSceneViewFamily& view_family) {
Expand Down
12 changes: 10 additions & 2 deletions src/mods/vr/FFakeStereoRenderingHook.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ struct UCanvas;
struct IStereoLayers;
struct FSceneViewFamily;

namespace sdk {
struct FSceneViewStateInterface;
}

// Injector-specific structure for VRRenderTargetManager that they will all secondarily inherit from
// because different engine versions can have a different IStereoRenderTargetManager virtual table
// so we need a unified way of storing data that can be used for all versions
Expand Down Expand Up @@ -304,7 +308,7 @@ class FFakeStereoRenderingHook : public ModComponent {

// Hooks
// FSceneView
static sdk::FSceneView* sceneview_constructor(sdk::FSceneView* sceneview, sdk::FSceneViewInitOptions* init_options);
static sdk::FSceneView* sceneview_constructor(sdk::FSceneView* sceneview, sdk::FSceneViewInitOptions* init_options, void* a3, void* a4);

// IStereoRendering
static bool is_stereo_enabled(FFakeStereoRendering* stereo);
Expand Down Expand Up @@ -341,9 +345,13 @@ class FFakeStereoRenderingHook : public ModComponent {
std::unique_ptr<ThreadWorker<FRHICommandListImmediate*>> m_slate_thread_worker{std::make_unique<ThreadWorker<FRHICommandListImmediate*>>()};

struct {
std::recursive_mutex mtx{};
safetyhook::InlineHook constructor_hook{};
std::unordered_set<void*> known_scene_states;
std::unordered_set<sdk::FSceneViewStateInterface*> known_scene_states;
bool inside_post_init_properties{false};

uint32_t last_frame_count{};
uint32_t last_index{};
} m_sceneview_data;

safetyhook::InlineHook m_localplayer_get_viewpoint_hook{};
Expand Down

0 comments on commit 4349881

Please sign in to comment.