From 16806b37a4a4d6251b7c8233e41a21a7138c7df0 Mon Sep 17 00:00:00 2001 From: praydog Date: Sat, 2 Nov 2024 14:17:09 -0700 Subject: [PATCH] VR: Initial work on new renderer for Wilds --- CMakeLists.txt | 32 +++++++- shared/sdk/Renderer.cpp | 105 ++++++++++++++++++++++--- shared/sdk/Renderer.hpp | 4 +- shared/sdk/renderer/RenderResource.cpp | 28 ++++++- src/mods/VR.cpp | 22 +++++- 5 files changed, 177 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e2728b3b..adc0c8d05 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13838,8 +13838,10 @@ if(REF_BUILD_MHWILDS_SDK OR REF_BUILD_FRAMEWORK) # build-mhwilds-sdk "shared/sdk/regenny/re3/via/vec4.hpp" "shared/sdk/regenny/re4/BullShit.hpp" "shared/sdk/regenny/re4/DeserializeSequence.hpp" + "shared/sdk/regenny/re4/ID3D12Resource.hpp" "shared/sdk/regenny/re4/ManagedVtable.hpp" "shared/sdk/regenny/re4/RTInternal.hpp" + "shared/sdk/regenny/re4/RTL_CRITICAL_SECTION_DEBUG.hpp" "shared/sdk/regenny/re4/RayTrace.hpp" "shared/sdk/regenny/re4/RenderEntity.hpp" "shared/sdk/regenny/re4/System/String.hpp" @@ -13859,6 +13861,7 @@ if(REF_BUILD_MHWILDS_SDK OR REF_BUILD_FRAMEWORK) # build-mhwilds-sdk "shared/sdk/regenny/re4/tdb71/TypeDefinition.hpp" "shared/sdk/regenny/re4/tdb71/TypeImpl.hpp" "shared/sdk/regenny/re4/via/BasisPlane.hpp" + "shared/sdk/regenny/re4/via/Camera.hpp" "shared/sdk/regenny/re4/via/CameraType.hpp" "shared/sdk/regenny/re4/via/Capsule.hpp" "shared/sdk/regenny/re4/via/Color.hpp" @@ -13936,9 +13939,29 @@ if(REF_BUILD_MHWILDS_SDK OR REF_BUILD_FRAMEWORK) # build-mhwilds-sdk "shared/sdk/regenny/re4/via/motion/SecondaryAnimation.hpp" "shared/sdk/regenny/re4/via/motion/TransitionData.hpp" "shared/sdk/regenny/re4/via/motion/TransitionMap.hpp" + "shared/sdk/regenny/re4/via/render/DXResource.hpp" + "shared/sdk/regenny/re4/via/render/DepthStencilView.hpp" + "shared/sdk/regenny/re4/via/render/DepthStencilViewDX12.hpp" + "shared/sdk/regenny/re4/via/render/LayerArray.hpp" + "shared/sdk/regenny/re4/via/render/Mirror.hpp" + "shared/sdk/regenny/re4/via/render/Poop.hpp" + "shared/sdk/regenny/re4/via/render/RTL_CRITICAL_SECTION.hpp" + "shared/sdk/regenny/re4/via/render/RenderLayer.hpp" "shared/sdk/regenny/re4/via/render/RenderOutput.hpp" + "shared/sdk/regenny/re4/via/render/RenderResource.hpp" + "shared/sdk/regenny/re4/via/render/RenderTargetView.hpp" + "shared/sdk/regenny/re4/via/render/RenderTargetViewDX12.hpp" "shared/sdk/regenny/re4/via/render/SceneArray2.hpp" + "shared/sdk/regenny/re4/via/render/SceneInfo.hpp" + "shared/sdk/regenny/re4/via/render/TargetState.hpp" + "shared/sdk/regenny/re4/via/render/Texture.hpp" + "shared/sdk/regenny/re4/via/render/TextureDX12.hpp" + "shared/sdk/regenny/re4/via/render/TextureDesc.hpp" + "shared/sdk/regenny/re4/via/render/TextureFormat.hpp" + "shared/sdk/regenny/re4/via/render/TextureStreamingType.hpp" + "shared/sdk/regenny/re4/via/render/UsageType.hpp" "shared/sdk/regenny/re4/via/render/layer/PrepareOutput.hpp" + "shared/sdk/regenny/re4/via/render/layer/Scene.hpp" "shared/sdk/regenny/re4/via/typeinfo/TypeInfo.hpp" "shared/sdk/regenny/re4/via/vec3.hpp" "shared/sdk/regenny/re4/via/vec4.hpp" @@ -14285,6 +14308,7 @@ if(REF_BUILD_FRAMEWORK AND CMAKE_SIZEOF_VOID_P EQUAL 8) # build-framework "src/mods/REFrameworkConfig.cpp" "src/mods/Scene.cpp" "src/mods/ScriptRunner.cpp" + "src/mods/TemporalUpscaler.cpp" "src/mods/VR.cpp" "src/mods/bindings/FS.cpp" "src/mods/bindings/ImGui.cpp" @@ -14294,10 +14318,12 @@ if(REF_BUILD_FRAMEWORK AND CMAKE_SIZEOF_VOID_P EQUAL 8) # build-framework "src/mods/tools/GameObjectsDisplay.cpp" "src/mods/tools/ObjectExplorer.cpp" "src/mods/vr/Bindings.cpp" + "src/mods/vr/CameraDuplicator.cpp" "src/mods/vr/D3D11Component.cpp" "src/mods/vr/D3D12Component.cpp" "src/mods/vr/OverlayComponent.cpp" "src/mods/vr/d3d12/CommandContext.cpp" + "src/mods/vr/d3d12/DirectXTK.cpp" "src/mods/vr/d3d12/ResourceCopier.cpp" "src/mods/vr/d3d12/TextureContext.cpp" "src/mods/vr/games/RE8VR.cpp" @@ -14335,6 +14361,7 @@ if(REF_BUILD_FRAMEWORK AND CMAKE_SIZEOF_VOID_P EQUAL 8) # build-framework "src/mods/REFrameworkConfig.hpp" "src/mods/Scene.hpp" "src/mods/ScriptRunner.hpp" + "src/mods/TemporalUpscaler.hpp" "src/mods/VR.hpp" "src/mods/bindings/FS.hpp" "src/mods/bindings/ImGui.hpp" @@ -14343,11 +14370,13 @@ if(REF_BUILD_FRAMEWORK AND CMAKE_SIZEOF_VOID_P EQUAL 8) # build-framework "src/mods/tools/ChainViewer.hpp" "src/mods/tools/GameObjectsDisplay.hpp" "src/mods/tools/ObjectExplorer.hpp" + "src/mods/vr/CameraDuplicator.hpp" "src/mods/vr/D3D11Component.hpp" "src/mods/vr/D3D12Component.hpp" "src/mods/vr/OverlayComponent.hpp" "src/mods/vr/d3d12/ComPtr.hpp" "src/mods/vr/d3d12/CommandContext.hpp" + "src/mods/vr/d3d12/DirectXTK.hpp" "src/mods/vr/d3d12/ResourceCopier.hpp" "src/mods/vr/d3d12/TextureContext.hpp" "src/mods/vr/games/RE8VR.hpp" @@ -14430,13 +14459,14 @@ if(REF_BUILD_FRAMEWORK AND CMAKE_SIZEOF_VOID_P EQUAL 8) # build-framework delayimp DirectXTK DirectXTK12 + pdperfmod ) set_target_properties(MHWILDS PROPERTIES OUTPUT_NAME dinput8 LINK_FLAGS - "/DELAYLOAD:openvr_api.dll /DELAYLOAD:openxr_loader.dll /DELAYLOAD:d3d11.dll /DELAYLOAD:d3d12.dll /DELAYLOAD:D3DCOMPILER_47.dll" + "/DELAYLOAD:openvr_api.dll /DELAYLOAD:openxr_loader.dll /DELAYLOAD:PDPerfPlugin.dll /DELAYLOAD:d3d11.dll /DELAYLOAD:d3d12.dll /DELAYLOAD:D3DCOMPILER_47.dll" RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/bin/${CMKR_TARGET}" RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO diff --git a/shared/sdk/Renderer.cpp b/shared/sdk/Renderer.cpp index 8db620d02..e83efdb14 100644 --- a/shared/sdk/Renderer.cpp +++ b/shared/sdk/Renderer.cpp @@ -663,6 +663,12 @@ sdk::renderer::command::Base* RenderContext::alloc(uint32_t t, uint32_t size) { static auto func = []() -> sdk::renderer::command::Base* (*)(RenderContext*, uint32_t, uint32_t) { spdlog::info("Searching for RenderContext::alloc"); + /* + // In wilds this looks more like this + BA 09 00 00 00 mov edx, 9 + 41 B8 30 00 00 00 mov r8d, 30h + E8 ? ? ? ? call alloc + */ const auto game = utility::get_executable(); const auto scan_result = utility::scan(game, "48 8b ? 44 8d 42 38 e8 ? ? ? ?"); @@ -761,7 +767,9 @@ void RenderContext::copy_texture(Texture* dest, Texture* src, Fence& fence) { return; #else*/ - static auto func = []() -> void (*)(RenderContext*, Texture*, Texture*, Fence&) { + + using CopyTexFn = void (*)(RenderContext*, Texture*, Texture*, Fence&); + static auto func = []() -> CopyTexFn { spdlog::info("Searching for RenderContext::copy_texture"); std::vector string_choices { @@ -773,10 +781,11 @@ void RenderContext::copy_texture(Texture* dest, Texture* src, Fence& fence) { "CopyImage", }; + const auto game = utility::get_executable(); + for (const auto& str_choice : string_choices) { spdlog::info("Scanning for string: {}", str_choice); - const auto game = utility::get_executable(); const auto string = utility::scan_string(game, str_choice, true); if (!string) { @@ -804,7 +813,7 @@ void RenderContext::copy_texture(Texture* dest, Texture* src, Fence& fence) { ip = resolved->addr; if (*(uint8_t*)ip == 0xE8) { - const auto result = (void (*)(RenderContext*, Texture*, Texture*, Fence&))utility::calculate_absolute(ip + 1); + const auto result = (CopyTexFn)utility::calculate_absolute(ip + 1); spdlog::info("Found copy_texture: {:x}", (uintptr_t)result); return result; @@ -814,8 +823,32 @@ void RenderContext::copy_texture(Texture* dest, Texture* src, Fence& fence) { } } - spdlog::error("Could not find copy_texture"); - return nullptr; + spdlog::error("Could not find copy_texture, trying fallback"); + + // Look for alloc call behind RE_POSTPROCESS_Color + /* + BA 01 00 00 00 mov edx, 1 ; this is the copy texture command type + 41 B8 30 00 00 00 mov r8d, 30h ; can change, can also be a lea instruction + E8 9B A5 7E 09 call alloc + 48 85 C0 test rax, rax + */ + const auto basic_sig_scan = utility::scan(game, "BA 01 00 00 00 41 B8 30 00 00 00 E8 ? ? ? ? 48 85 C0"); + + if (!basic_sig_scan) { + spdlog::error("Failed to find copy_texture (fallback)"); + return nullptr; + } + + const auto fn_start = utility::find_function_start_with_call(*basic_sig_scan); + + if (!fn_start) { + spdlog::error("Failed to find copy_texture (fallback fn_start)"); + return nullptr; + } + + spdlog::info("Found copy_texture (fallback): {:x}", *fn_start); + + return (CopyTexFn)*fn_start; }(); func(this, dest, src, fence); @@ -1057,6 +1090,27 @@ sdk::renderer::layer::Output* get_output_layer() { return nullptr; } + static auto get_output_layer_method = renderer_t->get_method("getOutputLayer"); + + if (get_output_layer_method == nullptr) { + auto root = get_root_layer(); + + if (root == nullptr) { + return nullptr; + } + + static auto output_t = sdk::find_type_definition("via.render.layer.Output"); + static auto output_retype = output_t != nullptr ? output_t->get_type() : nullptr; + + auto [parent, found] = root->find_layer_recursive(output_retype); + + if (found == nullptr) { + return nullptr; + } + + return (sdk::renderer::layer::Output*)*found; + } + return sdk::call_native_func(nullptr, renderer_t, "getOutputLayer", sdk::get_thread_context(), nullptr); } @@ -1302,7 +1356,34 @@ Texture* create_texture(Texture::Desc* desc) { ip -= 1; } - return nullptr; + spdlog::error("Failed to find create_texture, trying fallback"); + + const auto fn_start = utility::find_function_start_with_call(*string_ref); + + if (!fn_start) { + spdlog::error("Failed to find create_texture (no fallback)"); + return nullptr; + } + + const auto first_call = utility::scan_mnemonic(*fn_start, 100, "CALL"); + + if (!first_call) { + spdlog::error("Failed to find create_texture (no first call)"); + return nullptr; + } + + const auto second_call = utility::scan_mnemonic(*first_call + 1, 100, "CALL"); + + if (!second_call) { + spdlog::error("Failed to find create_texture (no second call)"); + return nullptr; + } + + auto result = (Texture* (*)(void*, Texture::Desc*))utility::calculate_absolute(*second_call + 1); + + spdlog::info("Found create_texture (fallback): {:x}", (uintptr_t)result); + + return result; }(); static auto renderer = sdk::renderer::get_renderer(); @@ -1441,7 +1522,9 @@ sdk::intrusive_ptr RenderTargetView::clone(uint32_t new_width, } namespace detail { -#if TDB_VER >= 71 +#if TDB_VER >= 74 + constexpr auto rtv_size = 0xA8; +#elif TDB_VER >= 71 #if defined(SF6) || defined(DD2) constexpr auto rtv_size = 0x98; #elif defined(MHRISE) @@ -1468,14 +1551,18 @@ sdk::intrusive_ptr& RenderTargetView::get_texture_d3d12() const { if (rtv_type != nullptr && rtv_type->size > 0 && rtv_type->size < 0x1000) { const auto rtv_size = rtv_type->size; -#if TDB_VER < 73 +#if TDB_VER >= 74 + return *(sdk::intrusive_ptr*)((uintptr_t)this + rtv_size + (sizeof(void*) * 4)); // 0xC8 usually +#elif TDB_VER < 73 return *(sdk::intrusive_ptr*)((uintptr_t)this + rtv_size + sizeof(void*)); #else return *(sdk::intrusive_ptr*)((uintptr_t)this + rtv_size + (sizeof(void*) * 3)); #endif } -#if TDB_VER < 73 +#if TDB_VER >= 74 + return *(sdk::intrusive_ptr*)((uintptr_t)this + detail::rtv_size + (sizeof(void*) * 4)); // 0xC8 usually +#elif TDB_VER < 73 return *(sdk::intrusive_ptr*)((uintptr_t)this + detail::rtv_size + sizeof(void*)); #else return *(sdk::intrusive_ptr*)((uintptr_t)this + detail::rtv_size + (sizeof(void*) * 3)); diff --git a/shared/sdk/Renderer.hpp b/shared/sdk/Renderer.hpp index 6da2afe9f..7c3f1f971 100644 --- a/shared/sdk/Renderer.hpp +++ b/shared/sdk/Renderer.hpp @@ -97,7 +97,7 @@ class Texture : public RenderResource { #endif #if TDB_VER >= 73 - static constexpr inline auto s_d3d12_resource_offset = 0xB8; + static constexpr inline auto s_d3d12_resource_offset = 0xE0; #elif TDB_VER >= 71 #ifdef SF6 // So because this discrepancy in SF6 is > 8 bytes (which is how much was added to RenderResource), trying to automate this @@ -413,7 +413,7 @@ class PrepareOutput : public sdk::renderer::RenderLayer { private: // Man I REALLY need a way of automatically finding this. #if TDB_VER >= 73 - static constexpr inline auto s_output_state_offset = 0x118; + static constexpr inline auto s_output_state_offset = 0x128; #elif TDB_VER >= 71 #ifdef MHRISE static constexpr inline auto s_output_state_offset = 0xF8; diff --git a/shared/sdk/renderer/RenderResource.cpp b/shared/sdk/renderer/RenderResource.cpp index bc1fdcfaa..f86d9acad 100644 --- a/shared/sdk/renderer/RenderResource.cpp +++ b/shared/sdk/renderer/RenderResource.cpp @@ -33,7 +33,33 @@ RenderResource::ReleaseFn RenderResource::get_release_fn() { if (reset_method == nullptr) { spdlog::error("[RenderResource] Failed to find via.render.CapturePlane.reset method!"); - return nullptr; + + const auto game = utility::get_executable(); + std::vector landmark_patterns { + "FF 50 ?", // call qword ptr [rax + ?] + "F0 FF ? 08", // lock dec dword ptr [reg + 8] + "BA 01 00 00 00", // mov edx, 1 + "E8 ? ? ? ?", // call ? + }; + + // Initial scan for a lock cmpxchg [reg + 8], reg instruction + auto landmark = utility::find_landmark_sequence(game, "F0 0F B1 ? 08 75 ?", landmark_patterns, false); + + if (!landmark) { + spdlog::error("[RenderResource] Failed to find landmark sequence!"); + return nullptr; + } + + auto fn_start = utility::find_function_start_with_call(landmark->addr); + + if (!fn_start) { + spdlog::error("[RenderResource] Failed to find function start!"); + return nullptr; + } + + spdlog::info("[RenderResource] Found function start at {:x}", *fn_start); + + return (ReleaseFn)*fn_start; } const auto reset_method_addr = (uintptr_t)reset_method->get_function(); diff --git a/src/mods/VR.cpp b/src/mods/VR.cpp index f7572f820..9b5e2478f 100644 --- a/src/mods/VR.cpp +++ b/src/mods/VR.cpp @@ -2171,7 +2171,11 @@ void VR::disable_bad_effects() { // get_MaxFps on application if (!is_sf6 && m_force_fps_settings->value() && application->get_max_fps() < 600.0f) { application->set_max_fps(600.0f); - spdlog::info("[VR] Max FPS set to {}", 600.0f); + + static bool once = []() { + spdlog::info("[VR] Max FPS set to {}", 600.0f); + return true; + }(); } if (m_force_aa_settings->value() && get_antialiasing_method != nullptr && set_antialiasing_method != nullptr) { @@ -3486,6 +3490,8 @@ void VR::on_end_rendering(void* entry) { } if (g_framework->is_dx12()) { + bool force_reset = false; + if (m_multipass.allocated_size[0] != get_hmd_width() || m_multipass.allocated_size[1] != get_hmd_height()) { const auto rtv0 = output_states[0]->get_rtv(0); const auto rtv1 = output_states[1]->get_rtv(0); @@ -3501,6 +3507,8 @@ void VR::on_end_rendering(void* entry) { m_multipass.allocated_size[0] = get_hmd_width(); m_multipass.allocated_size[1] = get_hmd_height(); + force_reset = true; + spdlog::info("Allocated native res copies"); } else { spdlog::warn("VR: on_end_rendering: texs are null: {:x} {:x}", (uintptr_t)tex0.get(), (uintptr_t)tex1.get()); @@ -3515,6 +3523,10 @@ void VR::on_end_rendering(void* entry) { if (container != nullptr) { m_multipass.eye_textures[0] = container->get_native_resource(); + + if (m_multipass.eye_textures[0] == nullptr) { + spdlog::warn("VR: on_end_rendering: eye texture 0 is null"); + } } } @@ -3523,8 +3535,16 @@ void VR::on_end_rendering(void* entry) { if (container != nullptr) { m_multipass.eye_textures[1] = container->get_native_resource(); + + if (m_multipass.eye_textures[1] == nullptr) { + spdlog::warn("VR: on_end_rendering: eye texture 1 is null"); + } } } + + if (force_reset) { + m_d3d12.force_reset(); + } } else { // TODO! }