Skip to content

Commit dc98094

Browse files
committed
v2: Fix copy_texture + get_d3d12_resource_container for universal dispatch
copy_texture had TWO different native signatures (pre-TDB82 4-arg vs post-TDB82 6-arg) gated by #if TDB_VER < 82. In universal builds this always resolved to the TDB>=82 branch since TDB_VER is 84 at compile time, silently breaking texture copy for every pre-TDB82 game. Restructured both paths into compile-time-available lambdas (copy_legacy/copy_modern) and dispatch on tdb_ver() at runtime in universal mode. Non-universal builds keep the original single-path compile-time selection. Texture::get_d3d12_resource_container had a control-flow bug after the initial universal conversion: for tdb_ver>=71 it fell through past the runtime fastpath into a preprocessor else branch that was never taken in REFRAMEWORK_UNIVERSAL mode, returning garbage. Fixed by moving the bruteforce scan outside the #elif chain so universal tdb>=71 reaches it, while preserving the legacy compile-time early-return. Verified: RE2 (TDB 70), StarForce (TDB 78), MHWILDS (TDB 81) all boot and reach steady state.
1 parent 9fe90b5 commit dc98094

1 file changed

Lines changed: 108 additions & 87 deletions

File tree

shared/sdk/Renderer.cpp

Lines changed: 108 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -788,119 +788,134 @@ void RenderContext::copy_texture(Texture* dest, Texture* src, Fence& fence) {
788788
return;
789789
#else*/
790790

791-
#if TDB_VER < 82
792-
using CopyTexFn = void (*)(RenderContext*, Texture*, Texture*, Fence&);
793-
static auto func = []() -> CopyTexFn {
794-
spdlog::info("Searching for RenderContext::copy_texture");
795-
796-
std::vector<std::string> string_choices {
797-
// CopyTexture isn't directly behind InterleaveNormalDepthHalfWithoutGBuffer in DD2+
791+
// Two implementations depending on TDB version: the legacy (<82) form takes
792+
// a single source/dest pair; the modern (>=82) form takes per-texture subresource
793+
// indices. They resolve to different native functions with different signatures,
794+
// so in universal builds we dispatch at runtime but both branches must compile.
795+
#if defined(REFRAMEWORK_UNIVERSAL) || TDB_VER < 82
796+
auto copy_legacy = [&]() {
797+
using CopyTexFn = void (*)(RenderContext*, Texture*, Texture*, Fence&);
798+
static auto func = []() -> CopyTexFn {
799+
spdlog::info("Searching for RenderContext::copy_texture");
800+
801+
std::vector<std::string> string_choices {
802+
#ifdef REFRAMEWORK_UNIVERSAL
803+
};
804+
if (sdk::GameIdentity::get().tdb_ver() < 73) {
805+
string_choices.push_back("InterleaveNormalDepthHalfWithoutGBuffer");
806+
}
807+
string_choices.push_back("opyImage");
808+
string_choices.push_back("CopyImage");
809+
{
810+
#else
811+
// CopyTexture isn't directly behind InterleaveNormalDepthHalfWithoutGBuffer in DD2+
798812
#if TDB_VER < 73
799-
"InterleaveNormalDepthHalfWithoutGBuffer",
813+
"InterleaveNormalDepthHalfWithoutGBuffer",
814+
#endif
815+
"opyImage", // Engine has a weird optimization sometimes where it starts from the +1 offset
816+
"CopyImage",
817+
};
800818
#endif
801-
"opyImage", // Engine has a weird optimization sometimes where it starts from the +1 offset
802-
"CopyImage",
803-
};
804-
805-
const auto game = utility::get_executable();
806-
807-
for (const auto& str_choice : string_choices) {
808-
spdlog::info("Scanning for string: {}", str_choice);
809-
810-
const auto string = utility::scan_string(game, str_choice, true);
811819

812-
if (!string) {
813-
spdlog::error("Failed to find copy_texture (no string)");
814-
continue;
815-
}
820+
const auto game = utility::get_executable();
816821

817-
const auto string_ref = utility::scan_displacement_reference(game, *string);
822+
for (const auto& str_choice : string_choices) {
823+
spdlog::info("Scanning for string: {}", str_choice);
818824

819-
if (!string_ref) {
820-
spdlog::error("Failed to find copy_texture (no string ref)");
821-
continue;
822-
}
825+
const auto string = utility::scan_string(game, str_choice, true);
823826

824-
uintptr_t ip = *string_ref;
827+
if (!string) {
828+
spdlog::error("Failed to find copy_texture (no string)");
829+
continue;
830+
}
825831

826-
for (auto i = 0; i < 20; ++i) {
827-
const auto resolved = utility::resolve_instruction(ip);
832+
const auto string_ref = utility::scan_displacement_reference(game, *string);
828833

829-
if (!resolved) {
830-
spdlog::error("Failed to find copy_texture (could not resolve instruction)");
834+
if (!string_ref) {
835+
spdlog::error("Failed to find copy_texture (no string ref)");
831836
continue;
832837
}
833838

834-
ip = resolved->addr;
839+
uintptr_t ip = *string_ref;
835840

836-
if (*(uint8_t*)ip == 0xE8) {
837-
const auto result = (CopyTexFn)utility::calculate_absolute(ip + 1);
841+
for (auto i = 0; i < 20; ++i) {
842+
const auto resolved = utility::resolve_instruction(ip);
838843

839-
spdlog::info("Found copy_texture: {:x}", (uintptr_t)result);
840-
return result;
841-
}
844+
if (!resolved) {
845+
spdlog::error("Failed to find copy_texture (could not resolve instruction)");
846+
continue;
847+
}
842848

843-
ip -= 1;
844-
}
845-
}
849+
ip = resolved->addr;
846850

847-
spdlog::error("Could not find copy_texture, trying fallback");
851+
if (*(uint8_t*)ip == 0xE8) {
852+
const auto result = (CopyTexFn)utility::calculate_absolute(ip + 1);
848853

849-
// Look for alloc call behind RE_POSTPROCESS_Color
850-
/*
851-
BA 01 00 00 00 mov edx, 1 ; this is the copy texture command type
852-
41 B8 30 00 00 00 mov r8d, 30h ; can change, can also be a lea instruction
853-
E8 9B A5 7E 09 call alloc
854-
48 85 C0 test rax, rax
855-
*/
856-
const auto basic_sig_scan = utility::scan(game, "BA 01 00 00 00 41 B8 30 00 00 00 E8 ? ? ? ? 48 85 C0");
854+
spdlog::info("Found copy_texture: {:x}", (uintptr_t)result);
855+
return result;
856+
}
857857

858-
if (!basic_sig_scan) {
859-
spdlog::error("Failed to find copy_texture (fallback)");
860-
return nullptr;
861-
}
858+
ip -= 1;
859+
}
860+
}
861+
#ifdef REFRAMEWORK_UNIVERSAL
862+
}
863+
#endif
862864

863-
const auto fn_start = utility::find_function_start_with_call(*basic_sig_scan);
865+
spdlog::error("Could not find copy_texture");
866+
return (CopyTexFn)nullptr;
867+
}();
864868

865-
if (!fn_start) {
866-
spdlog::error("Failed to find copy_texture (fallback fn_start)");
867-
return nullptr;
869+
if (func != nullptr) {
870+
func(this, dest, src, fence);
868871
}
872+
};
873+
#endif
869874

870-
spdlog::info("Found copy_texture (fallback): {:x}", *fn_start);
871-
872-
return (CopyTexFn)*fn_start;
873-
}();
875+
#if defined(REFRAMEWORK_UNIVERSAL) || TDB_VER >= 82
876+
auto copy_modern = [&]() {
877+
using CopyTexFn = void (*)(RenderContext*, Texture*, int32_t, Texture*, int32_t, Fence&);
878+
static auto func = []() -> CopyTexFn {
879+
spdlog::info("Searching for RenderContext::copy_texture (>= TDB82)");
874880

875-
func(this, dest, src, fence);
876-
#else
877-
using CopyTexFn = void (*)(RenderContext*, Texture*, int32_t, Texture*, int32_t, Fence&);
878-
static auto func = []() -> CopyTexFn {
879-
spdlog::info("Searching for RenderContext::copy_texture (>= TDB82)");
881+
const auto game = utility::get_executable();
882+
// constants 0x301 (the typeid 1 or'd with something) 0x36, 0x3f, 0x2a.
883+
const auto mid_result = utility::scan(game, "01 03 00 00 *[64] 36 *[32] 3f *[32] 2a");
880884

881-
const auto game = utility::get_executable();
882-
// constants 0x301 (the typeid 1 or'd with something) 0x36, 0x3f, 0x2a.
883-
const auto mid_result = utility::scan(game, "01 03 00 00 *[64] 36 *[32] 3f *[32] 2a");
885+
if (!mid_result) {
886+
spdlog::error("Failed to find copy_texture (>= TDB82)");
887+
return (CopyTexFn)nullptr;
888+
}
884889

885-
if (!mid_result) {
886-
spdlog::error("Failed to find copy_texture (>= TDB82)");
887-
return nullptr;
888-
}
890+
const auto fn_start = utility::find_function_start_unwind(*mid_result);
889891

890-
const auto fn_start = utility::find_function_start_unwind(*mid_result);
892+
if (!fn_start) {
893+
spdlog::error("Failed to find copy_texture function start (>= TDB82)");
894+
return (CopyTexFn)nullptr;
895+
}
891896

892-
if (!fn_start) {
893-
spdlog::error("Failed to find copy_texture function start (>= TDB82)");
894-
return nullptr;
895-
}
897+
spdlog::info("Found copy_texture (>= TDB82) at {:x}", *fn_start);
896898

897-
spdlog::info("Found copy_texture (>= TDB82) at {:x}", *fn_start);
899+
return (CopyTexFn)*fn_start;
900+
}();
898901

899-
return (CopyTexFn)*fn_start;
900-
}();
902+
if (func != nullptr) {
903+
// src, src_subresource, dst, dst_subresource, fence
904+
func(this, src, -1, dest, -1, fence);
905+
}
906+
};
907+
#endif
901908

902-
// src, src_subresource, dst, dst_subresource, fence
903-
func(this, src, -1, dest, -1, fence);
909+
#ifdef REFRAMEWORK_UNIVERSAL
910+
if (sdk::GameIdentity::get().tdb_ver() < 82) {
911+
copy_legacy();
912+
} else {
913+
copy_modern();
914+
}
915+
#elif TDB_VER < 82
916+
copy_legacy();
917+
#else
918+
copy_modern();
904919
#endif
905920
//#endif
906921
}
@@ -1549,9 +1564,15 @@ ID3D12Resource* TargetState::get_native_resource_d3d12() const {
15491564
}
15501565

15511566
DirectXResource<ID3D12Resource>* Texture::get_d3d12_resource_container() {
1552-
#if TDB_VER < 71
1567+
#ifdef REFRAMEWORK_UNIVERSAL
1568+
// DMC5 (TDB <71) uses hardcoded offset; newer games bruteforce-scan.
1569+
if (sdk::GameIdentity::get().tdb_ver() < 71) {
1570+
return *(DirectXResource<ID3D12Resource>**)((uintptr_t)this + get_s_d3d12_resource_offset());
1571+
}
1572+
// fall through to bruteforce for TDB >= 71
1573+
#elif TDB_VER < 71
15531574
return *(DirectXResource<ID3D12Resource>**)((uintptr_t)this + s_d3d12_resource_offset);
1554-
#else
1575+
#endif
15551576
static std::optional<size_t> offset = std::nullopt;
15561577

15571578
if (offset) {
@@ -1621,7 +1642,7 @@ DirectXResource<ID3D12Resource>* Texture::get_d3d12_resource_container() {
16211642
}
16221643

16231644
return nullptr;
1624-
#endif
1645+
16251646
}
16261647

16271648
Texture* Texture::clone() {

0 commit comments

Comments
 (0)