@@ -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
15511566DirectXResource<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
16271648Texture* Texture::clone () {
0 commit comments