From bbbc9c62de2ec47ed344598b2ec293bbb0d4d12f Mon Sep 17 00:00:00 2001 From: Kaldaien Date: Tue, 21 Feb 2017 23:47:19 -0500 Subject: [PATCH] Brought over improvements from TBFix --- tzf_dsound/DLL_VERSION.H | 2 +- tzf_dsound/config.cpp | 68 ++- tzf_dsound/config.h | 9 + tzf_dsound/control_panel.cpp | 187 +++++-- tzf_dsound/dllmain.cpp | 2 + tzf_dsound/framerate.cpp | 1 - tzf_dsound/hook.cpp | 8 +- tzf_dsound/keyboard.cpp | 2 - tzf_dsound/mod_tools.cpp | 930 +++++++++++++++++++++++++++++++++-- tzf_dsound/render.cpp | 789 ++++++++++++++++++++++------- tzf_dsound/render.h | 551 +++++++++++++++++++++ tzf_dsound/textures.cpp | 419 +++++++++++++--- tzf_dsound/textures.h | 59 ++- version.ini | Bin 3868 -> 3960 bytes 14 files changed, 2677 insertions(+), 350 deletions(-) diff --git a/tzf_dsound/DLL_VERSION.H b/tzf_dsound/DLL_VERSION.H index 9d47ddf..68d5bb2 100644 --- a/tzf_dsound/DLL_VERSION.H +++ b/tzf_dsound/DLL_VERSION.H @@ -3,7 +3,7 @@ #define TZF_MAJOR 1 #define TZF_MINOR 8 -#define TZF_BUILD 2 +#define TZF_BUILD 3 #define TZF_REV 0 diff --git a/tzf_dsound/config.cpp b/tzf_dsound/config.cpp index 817bc8c..d29e0a8 100644 --- a/tzf_dsound/config.cpp +++ b/tzf_dsound/config.cpp @@ -72,6 +72,7 @@ struct { tzf::ParameterInt* rescale_env_shadows; tzf::ParameterFloat* postproc_ratio; tzf::ParameterBool* clear_blackbars; + tzf::ParameterBool* auto_apply_changes; } render; struct { @@ -99,6 +100,12 @@ struct { tzf::ParameterStringW* texture_set; } gamepad; +struct { + tzf::ParameterFloat* scale; + tzf::ParameterBool* show_osd_message; + tzf::ParameterBool* show_licenses; +} imgui; + struct { tzf::ParameterBool* fix_priest; @@ -410,6 +417,17 @@ TZF_LoadConfig (std::wstring name) L"TZFIX.Render", L"ClearBlackbars" ); + render.auto_apply_changes = + static_cast + (g_ParameterFactory.create_parameter ( + L"Apply Changes Immediately") + ); + render.auto_apply_changes->register_to_ini( + dll_ini, + L"TZFIX.Render", + L"AutoApplyChanges" + ); + textures.cache = static_cast @@ -503,6 +521,37 @@ TZF_LoadConfig (std::wstring name) L"TextureSet" ); + imgui.scale = + static_cast + (g_ParameterFactory.create_parameter ( + L"Font Scale for Config UI") + ); + imgui.scale->register_to_ini( + dll_ini, + L"ImGui.General", + L"Scale" ); + + imgui.show_licenses = + static_cast + (g_ParameterFactory.create_parameter ( + L"Show License Info") + ); + imgui.show_licenses->register_to_ini( + dll_ini, + L"ImGui.General", + L"HasReadLicenses" ); + + imgui.show_osd_message = + static_cast + (g_ParameterFactory.create_parameter ( + L"Show OSD Message") + ); + imgui.show_osd_message->register_to_ini( + dll_ini, + L"ImGui.General", + L"ShowOSDDisclaimer" ); + + keyboard.swap_keys = static_cast (g_ParameterFactory.create_parameter ( @@ -604,6 +653,7 @@ TZF_LoadConfig (std::wstring name) render.aspect_correct_vids->load (config.render.blackbar_videos); render.aspect_correction->load (config.render.aspect_correction); render.clear_blackbars->load (config.render.clear_blackbars); + render.auto_apply_changes->load (config.render.auto_apply_changes); // The video aspect ratio correction option is scheduled for removal anyway, so // this hack is okay... @@ -625,6 +675,10 @@ TZF_LoadConfig (std::wstring name) gamepad.texture_set->load (config.textures.gamepad); + imgui.scale->load (config.input.ui.scale); + imgui.show_licenses->load (config.input.ui.never_show_eula); + imgui.show_osd_message->load (config.render.osd_disclaimer); + steam.allow_broadcasts->load (config.steam.allow_broadcasts); keyboard.swap_keys->load (config.keyboard.swap_keys); @@ -662,13 +716,10 @@ TZF_SaveConfig (std::wstring name, bool close_config) framerate.disable_limiter->store (config.framerate.disable_limiter); framerate.auto_adjust->store (config.framerate.auto_adjust); - // - // Don't store changes to this preference made while the game is running - // - //framerate.target->store (config.framerate.target); - //framerate.battle_target->store (config.framerate.battle_target); + framerate.target->store (config.framerate.target); + framerate.battle_target->store (config.framerate.battle_target); //framerate.battle_adaptive->store (config.framerate.battle_adaptive); - //framerate.cutscene_target->store (config.framerate.cutscene_target); + framerate.cutscene_target->store (config.framerate.cutscene_target); render.aspect_addr->store (config.render.aspect_addr); render.fovy_addr->store (config.render.fovy_addr); @@ -682,6 +733,7 @@ TZF_SaveConfig (std::wstring name, bool close_config) render.postproc_ratio->store (config.render.postproc_ratio); render.rescale_shadows->store (config.render.shadow_rescale); render.rescale_env_shadows->store (config.render.env_shadow_rescale); + render.auto_apply_changes->store (config.render.auto_apply_changes); textures.remaster->store (config.textures.remaster); textures.cache->store (config.textures.cache); @@ -694,6 +746,10 @@ TZF_SaveConfig (std::wstring name, bool close_config) gamepad.texture_set->store (config.textures.gamepad); + imgui.scale->store (config.input.ui.scale); + imgui.show_licenses->store (config.input.ui.never_show_eula); + imgui.show_osd_message->store (config.render.osd_disclaimer); + steam.allow_broadcasts->store (config.steam.allow_broadcasts); lua.fix_priest->store (config.lua.fix_priest); diff --git a/tzf_dsound/config.h b/tzf_dsound/config.h index 1f3b389..ad4328b 100644 --- a/tzf_dsound/config.h +++ b/tzf_dsound/config.h @@ -77,6 +77,8 @@ struct tzf_config_t bool clear_blackbars = true; int32_t env_shadow_rescale = 0; bool dump_shaders = false; + bool auto_apply_changes = false; + bool osd_disclaimer = true; } render; struct { @@ -93,6 +95,13 @@ struct tzf_config_t bool highlight_debug_tex = true; } textures; + struct { + struct { + float scale = 1.0f; + bool never_show_eula = false; + } ui; + } input; + struct { bool visible = false; } control_panel; diff --git a/tzf_dsound/control_panel.cpp b/tzf_dsound/control_panel.cpp index 67db4b7..8bc534d 100644 --- a/tzf_dsound/control_panel.cpp +++ b/tzf_dsound/control_panel.cpp @@ -204,9 +204,45 @@ TZFix_DrawConfigUI (void) ImGuiIO& io = ImGui::GetIO (); - ImGui::SetNextWindowPosCenter (ImGuiSetCond_Always); - ImGui::SetNextWindowSizeConstraints (ImVec2 (500, 50), ImVec2 ( ImGui::GetIO ().DisplaySize.x * 0.95f, - ImGui::GetIO ().DisplaySize.y * 0.95f ) ); + static bool first_frame = true; + + extern HMODULE hInjectorDLL; + + typedef void (__stdcall *SK_ImGui_DrawEULA_pfn)(LPVOID reserved); + + static SK_ImGui_DrawEULA_pfn SK_ImGui_DrawEULA = + (SK_ImGui_DrawEULA_pfn)GetProcAddress ( hInjectorDLL, + "SK_ImGui_DrawEULA" ); + + struct { + bool show = true; + bool never_show_again = config.input.ui.never_show_eula; + } static show_eula; + + if (show_eula.show && (! show_eula.never_show_again)) { + SK_ImGui_DrawEULA (&show_eula); + + if (show_eula.never_show_again) config.input.ui.never_show_eula = true; + } + + static int frame = 0; + + if (frame++ < 10) + ImGui::SetNextWindowPosCenter (ImGuiSetCond_Always); + + if (io.DisplaySize.x != tzf::RenderFix::width || + io.DisplaySize.y != tzf::RenderFix::height) + { + frame = 0; + + io.DisplaySize.x = (float)tzf::RenderFix::width; + io.DisplaySize.y = (float)tzf::RenderFix::height; + + ImGui::SetNextWindowPosCenter (ImGuiSetCond_Always);; + } + + ImGui::SetNextWindowSizeConstraints (ImVec2 (500, 50), ImVec2 ( ImGui::GetIO ().DisplaySize.x * 0.85f, + ImGui::GetIO ().DisplaySize.y * 0.85f ) ); if (was_reset) { ImGui::SetNextWindowSize (ImVec2 (500, 50), ImGuiSetCond_Always); @@ -224,6 +260,20 @@ TZFix_DrawConfigUI (void) ImGui::PushItemWidth (ImGui::GetWindowWidth () * 0.666f); + if (ImGui::CollapsingHeader ("UI Scale")) + { + ImGui::TreePush (""); + + ImGui::SliderFloat ("Scale (only 1.0 is officially supported)", &config.input.ui.scale, 1.0f, 3.0f); + + ImGui::TreePop (); + } + + io.FontGlobalScale = config.input.ui.scale; + const float font_size = ImGui::GetFont ()->FontSize * io.FontGlobalScale; + const float font_size_multiline = font_size + ImGui::GetStyle ().ItemSpacing.y + ImGui::GetStyle ().ItemInnerSpacing.y; + + if (ImGui::CollapsingHeader ("Framerate Control", ImGuiTreeNodeFlags_CollapsingHeader | ImGuiTreeNodeFlags_DefaultOpen)) { #if 0 @@ -284,12 +334,12 @@ TZFix_DrawConfigUI (void) szAvg, 0.0f, 2.0f * tzf::FrameRateFix::GetTargetFrametime (), - ImVec2 ( 600, 82 ) ); + ImVec2 (0, font_size * 7) ); ImGui::SameLine (); ImGui::PushItemWidth (210); - ImGui::BeginChild ( "Sub2", ImVec2 ( 210, 82 ), true ); + ImGui::BeginChild ( "Sub2", ImVec2 ( font_size * 30, font_size * 7 ), true ); int cutscene = 0, battle = 0, world = 0; @@ -378,7 +428,10 @@ TZFix_DrawConfigUI (void) ImGui::PushStyleVar(ImGuiStyleVar_ChildWindowRounding, 15.0f); ImGui::TreePush (""); - ImGui::BeginChild ("Texture Details", ImVec2 (0, 100), true); + + ImGui::BeginChild ("Texture Details", ImVec2 ( font_size * 70, + font_size_multiline * 6.1f ), + true ); ImGui::Columns ( 3 ); ImGui::PushStyleColor (ImGuiCol_Text, ImVec4 (1.0f, 1.0f, 1.0f, 1.0f)); @@ -399,6 +452,8 @@ TZFix_DrawConfigUI (void) ImGui::TextColored (ImVec4 (0.3f, 1.0f, 0.3f, 1.0f), "%#5lu Hits", tzf::RenderFix::tex_mgr.getHitCount () ); ImGui::NextColumn (); + ImGui::Text ( "Budget: %#7zu MiB ", tzf::RenderFix::pDevice-> + GetAvailableTextureMem () / 1048576UL ); ImGui::Columns ( 1 ); ImGui::Separator ( ); @@ -417,7 +472,7 @@ TZFix_DrawConfigUI (void) ImGui::TextColored (ImVec4 (1.0f, 0.3f, 0.3f, 1.0f), "%#5lu Misses", tzf::RenderFix::tex_mgr.getMissCount () ); ImGui::NextColumn (); - ImGui::Text ( "Time: %#7.01lf s ", tzf::RenderFix::tex_mgr.getTimeSaved () / 1000.0f); + ImGui::Text ( "Time: %#6.04lf s ", tzf::RenderFix::tex_mgr.getTimeSaved () / 1000.0f); ImGui::Columns ( 1 ); ImGui::Separator ( ); @@ -434,19 +489,18 @@ TZFix_DrawConfigUI (void) ImGui::TextColored (ImVec4 (0.555f, 0.555f, 1.0f, 1.0f), "%.2f Hit/Miss", (double)tzf::RenderFix::tex_mgr.getHitCount () / - (double)tzf::RenderFix::tex_mgr.getMissCount() ); ImGui::NextColumn (); - ImGui::Text ( "Driver: %#7zu MiB ", tzf::RenderFix::tex_mgr.getByteSaved () >> 20ULL ); + (double)tzf::RenderFix::tex_mgr.getMissCount () ); ImGui::NextColumn (); + ImGui::Text ( "Driver: %#7zu MiB ", tzf::RenderFix::tex_mgr.getByteSaved () >> 20ULL ); ImGui::PopStyleColor ( ); ImGui::Columns ( 1 ); -#if 0 ImGui::Separator ( ); +#if 0 ImGui::TreePush (""); ImGui::Checkbox ("Enable Texture QuickLoad", &config.textures.quick_load); - ImGui::TreePop ( ); if (ImGui::IsItemHovered ()) { @@ -471,24 +525,56 @@ TZFix_DrawConfigUI (void) if (config.textures.quick_load) { ImGui::SameLine (); - if (ImGui::SliderInt("# of Threads", &config.textures.worker_threads, 2, 10)) { + + if (ImGui::SliderInt ("# of Threads", &config.textures.worker_threads, 3, 9)) + { + // Only allow odd numbers of threads + config.textures.worker_threads += 1 - (config.textures.worker_threads & 0x1); + need_restart = true; } if (ImGui::IsItemHovered ()) ImGui::SetTooltip ("Lower is actually better, the only reason to adjust this would be if you have an absurd number of CPU cores and pop-in bothers you ;)"); } + ImGui::TreePop ( ); #endif - ImGui::EndChild ( ); - ImGui::PopStyleVar ( ); - ImGui::TreePop ( ); + ImGui::EndChild ( ); + ImGui::PopStyleVar ( ); + +#if 0 + if (ImGui::CollapsingHeader ("Thread Stats")) + { + std::vector stats = + tzf::RenderFix::tex_mgr.getThreadStats (); + + int thread_id = 0; + + for ( auto it : stats ) { + ImGui::Text ("Thread #%lu - %6lu jobs retired, %5lu MiB loaded - %.6f User / %.6f Kernel / %3.1f Idle", + thread_id++, + it.jobs_retired, it.bytes_loaded >> 20UL, + (double)ULARGE_INTEGER { it.runtime.user.dwLowDateTime, it.runtime.user.dwHighDateTime }.QuadPart / 10000000.0, + (double)ULARGE_INTEGER { it.runtime.kernel.dwLowDateTime, it.runtime.kernel.dwHighDateTime }.QuadPart / 10000000.0, + (double)ULARGE_INTEGER { it.runtime.idle.dwLowDateTime, it.runtime.idle.dwHighDateTime }.QuadPart / 10000000.0 ); + } + } +#endif + ImGui::TreePop ( ); } - if (ImGui::Button ("Texture Modding Tools")) { + if (ImGui::Button (" Texture Modding Tools ")) { show_texture_mod_dlg = (! show_texture_mod_dlg); } + ImGui::SameLine (); + + ImGui::SliderInt ("Texture Cache Size", &config.textures.max_cache_in_mib, 384, 2048, "%.0f MiB"); + + if (ImGui::IsItemHovered ()) + ImGui::SetTooltip ("Lower this if the reported budget (on the Performance tab) ever becomes negative."); + ImGui::TreePop (); } @@ -520,13 +606,6 @@ TZFix_DrawConfigUI (void) if ( ImGui::SliderFloat ("Post-Process Resolution Scale", &config.render.postproc_ratio, 0.0f, 2.0f) ) tzf::RenderFix::need_reset.graphics = true; - - ImGui::Columns (1); - ImGui::PushStyleColor (ImGuiCol_Text, ImColor (0.975f, 0.1f, 0.975f, 1.0f)); - ImGui::Bullet (); ImGui::SameLine (); - ImGui::TextWrapped ("Changes to these settings will produce weird results until you change Screen Mode in-game..." ); - ImGui::PopStyleColor (); - ImGui::TreePop (); } @@ -557,12 +636,6 @@ TZFix_DrawConfigUI (void) ImGui::Combo ("Character Shadow Resolution", &shadows.radio, "Normal\0Enhanced\0High\0Ultra\0\0"); ImGui::Combo ("Environmental Shadow Resolution", &env_shadows.radio, "Normal\0High\0Ultra\0\0"); - ImGui::Columns (1); - ImGui::PushStyleColor (ImGuiCol_Text, ImColor (0.975f, 0.1f, 0.975f, 1.0f)); - ImGui::Bullet (); ImGui::SameLine (); - ImGui::TextWrapped ("Changes to these settings will produce weird results until you change Screen Mode in-game..." ); - ImGui::PopStyleColor (); - if (env_shadows.radio != env_shadows.last_sel) { config.render.env_shadow_rescale = env_shadows.radio; env_shadows.last_sel = env_shadows.radio; @@ -741,6 +814,9 @@ TZFix_DrawConfigUI (void) ImGui::PopItemWidth (); + ImGui::Separator ( ); + ImGui::Columns ( 2 ); + if (ImGui::Button (" Gamepad Config ")) ImGui::OpenPopup ("Gamepad Config"); @@ -756,6 +832,26 @@ TZFix_DrawConfigUI (void) if (ImGui::Selectable ("...", show_test_window)) show_test_window = (! show_test_window); + ImGui::SameLine (0.0f, 60.0f); + + if (ImGui::Selectable (" ... ", show_test_window)) + show_test_window = (! show_test_window); + + ImGui::NextColumn (); + + ImGui::Checkbox ("Apply Changes Immediately ", &config.render.auto_apply_changes); + + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip (); + ImGui::PushStyleColor (ImGuiCol_Text, ImColor (0.95f, 0.75f, 0.25f, 1.0f)); + ImGui::Text ("Third-Party Software May Not Like This\n\n"); + ImGui::PushStyleColor (ImGuiCol_Text, ImColor (0.75f, 0.75f, 0.75f, 1.0f)); + ImGui::BulletText ("You also may not when it takes 5 seconds to change some settings ;)"); + ImGui::PopStyleColor (2); + ImGui::EndTooltip (); + } + bool extra_details = false; if (need_restart || tzf::RenderFix::need_reset.graphics || tzf::RenderFix::need_reset.textures) @@ -770,14 +866,29 @@ TZFix_DrawConfigUI (void) ImGui::BulletText ("Game Restart Required"); ImGui::PopStyleColor (); } - - if (tzf::RenderFix::need_reset.graphics || tzf::RenderFix::need_reset.textures) { - ImGui::PushStyleColor (ImGuiCol_Text, ImVec4 (1.0f, 0.8f, 0.2f, 1.0f)); - ImGui::Bullet ( ); ImGui::SameLine (); - ImGui::TextWrapped ( "You have made changes that will not apply until you change Screen Modes in Graphics Settings, " - "or by performing Alt + Tab with the game set to Fullscreen mode.\n" ); - ImGui::PopStyleColor ( ); - ImGui::PopTextWrapPos ( ); + + if (tzf::RenderFix::need_reset.graphics || tzf::RenderFix::need_reset.textures) + { + if (! config.render.auto_apply_changes) + { + ImGui::PushStyleColor (ImGuiCol_Text, ImVec4 (1.0f, 0.8f, 0.2f, 1.0f)); + ImGui::Bullet ( ); ImGui::SameLine (); + + ImGui::TextWrapped ( "You have made changes to settings that require the game to re-load resources..."); + ImGui::Button ( " Apply Now " ); + + if (ImGui::IsItemHovered ()) ImGui::SetTooltip ("Click this before complaining that things look weird."); + if (ImGui::IsItemClicked ()) tzf::RenderFix::TriggerReset (); + + ImGui::PopStyleColor ( ); + ImGui::PopTextWrapPos ( ); + } + + else + { + ImGui::TextColored (ImVec4 (0.95f, 0.65f, 0.15f, 1.0f), "Applying Changes..."); + tzf::RenderFix::TriggerReset (); + } } } @@ -835,6 +946,4 @@ TZFix_ImGui_Init (void) "SK_ImGui_DrawFrame", TZFix_ImGui_DrawFrame, (LPVOID *)&SK_ImGui_DrawFrame_Original ); - - TZF_ApplyQueuedHooks (); } diff --git a/tzf_dsound/dllmain.cpp b/tzf_dsound/dllmain.cpp index 70db747..e4ab00e 100644 --- a/tzf_dsound/dllmain.cpp +++ b/tzf_dsound/dllmain.cpp @@ -164,6 +164,8 @@ DllThread (LPVOID user) tzf::FrameRateFix::Init (); tzf::KeyboardFix::Init (); + TZF_ApplyQueuedHooks (); + // Uncomment this when spawning a thread //CoUninitialize (); } diff --git a/tzf_dsound/framerate.cpp b/tzf_dsound/framerate.cpp index 830712f..92a1961 100644 --- a/tzf_dsound/framerate.cpp +++ b/tzf_dsound/framerate.cpp @@ -727,7 +727,6 @@ tzf::FrameRateFix::Init (void) (LPVOID *)&Sleep_Original, (LPVOID *)&pfnSleep ); - TZF_ApplyQueuedHooks (); TZF_EnableHook (pfnSleep); pCmdProc->AddVariable ("AllowFakeSleep", TZF_CreateVar (SK_IVariable::Boolean, &config.framerate.allow_fake_sleep)); diff --git a/tzf_dsound/hook.cpp b/tzf_dsound/hook.cpp index d7de0bb..b240857 100644 --- a/tzf_dsound/hook.cpp +++ b/tzf_dsound/hook.cpp @@ -97,7 +97,11 @@ SK_TZF_PluginKeyPress ( BOOL Control, *SK_GetCommandProcessor (); if (Control && Shift) { - if (vkCode == '1') { + if (vkCode == 'O') { + config.render.osd_disclaimer = false; + } + + else if (vkCode == '1') { command.ProcessCommandLine ("AutoAdjust false"); command.ProcessCommandLine ("TargetFPS 60"); command.ProcessCommandLine ("BattleFPS 60"); @@ -325,8 +329,6 @@ class TZF_InputHooker "SK_DetourWindowProc", DetourWindowProc, (LPVOID *)&DetourWindowProc_Original ); - - TZF_ApplyQueuedHooks (); } void End (void) diff --git a/tzf_dsound/keyboard.cpp b/tzf_dsound/keyboard.cpp index fc116ca..8676dad 100644 --- a/tzf_dsound/keyboard.cpp +++ b/tzf_dsound/keyboard.cpp @@ -86,8 +86,6 @@ tzf::KeyboardFix::Init (void) SDL_GetKeyboardState_Detour, (LPVOID *)&SDL_GetKeyboardState_Original ); - TZF_ApplyQueuedHooks (); - // Parse the swap pairs while (remaining > 0 && remaining <= len) { wchar_t* wszSwapPair = pairs; diff --git a/tzf_dsound/mod_tools.cpp b/tzf_dsound/mod_tools.cpp index b17256b..6bb3034 100644 --- a/tzf_dsound/mod_tools.cpp +++ b/tzf_dsound/mod_tools.cpp @@ -1,3 +1,27 @@ +/** + * This file is part of Tales of Berseria "Fix". + * + * Tales of Berseria "Fix" is free software : you can redistribute it + * and/or modify it under the terms of the GNU General Public License + * as published by The Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * Tales of Berseria "Fix" is distributed in the hope that it will be + * useful, + * + * But WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tales of Berseria "Fix". + * + * If not, see . + * +**/ + +#define _CRT_SECURE_NO_WARNINGS + #define NOMINMAX #include "DLL_VERSION.H" @@ -12,9 +36,18 @@ #include "render.h" #include "textures.h" +#include + +extern std::wstring +SK_D3D9_FormatToStr (D3DFORMAT Format, bool include_ordinal = true); + void -TZF_DrawFileList (void) +TZF_DrawFileList (bool& can_scroll) { + const float font_size = ImGui::GetFont ()->FontSize * ImGui::GetIO ().FontGlobalScale; + + ImGui::PushItemWidth (500.0f); + struct enumerated_source_s { std::string name = "invalid"; @@ -41,7 +74,7 @@ TZF_DrawFileList (void) { enumerated_source_s source; - char szFileName [MAX_PATH] = { }; + char szFileName [MAX_PATH] = { '\0' }; if (archive_no != std::numeric_limits ::max ()) { sprintf (szFileName, "%ws", archives [archive_no].c_str ()); @@ -101,14 +134,17 @@ TZF_DrawFileList (void) ImGui::PushStyleVar (ImGuiStyleVar_ChildWindowRounding, 0.0f); ImGui::PushStyleColor (ImGuiCol_Border, ImVec4 (0.4f, 0.6f, 0.9f, 1.0f)); -#define FILE_LIST_WIDTH 250UL -#define FILE_LIST_HEIGHT 100UL +#define FILE_LIST_WIDTH font_size * 20 +#define FILE_LIST_HEIGHT font_size * (sources.size () + 3) ImGui::BeginChild ( "Source List", ImVec2 ( FILE_LIST_WIDTH, FILE_LIST_HEIGHT ), true, ImGuiWindowFlags_AlwaysAutoResize ); + if (ImGui::IsWindowHovered ()) + can_scroll = false; + auto DataSourceTooltip = [](int sel) -> void @@ -185,9 +221,12 @@ TZF_DrawFileList (void) ImGui::PushStyleColor (ImGuiCol_Border, ImVec4 (0.5f, 0.5f, 0.5f, 1.0f)); ImGui::BeginChild ( "Texture Selection", - ImVec2 (-2.0f, list_size.y - 24), + ImVec2 (font_size * 30, list_size.y - font_size * 2), true ); + if (ImGui::IsWindowHovered ()) + can_scroll = false; + for ( auto it : sources [sel].checksums ) { tzf_tex_record_s* injectable = @@ -217,30 +256,547 @@ TZF_DrawFileList (void) ImGui::EndChild ( ); ImGui::PopStyleColor ( 1 ); - if (ImGui::Button ("Refresh Data Sources")) + if (ImGui::Button (" Refresh Data Sources ")) { TZF_RefreshDataSources (); list_dirty = true; } + ImGui::SameLine (); + + if (ImGui::Button (" Reload All Textures ")) + { + tzf::RenderFix::TriggerReset (); + } + ImGui::EndGroup (); } + + ImGui::PopItemWidth (); } + +extern std::unordered_map ps_disassembly; +extern std::unordered_map vs_disassembly; + +enum class tzf_shader_class { + Unknown = 0x00, + Pixel = 0x01, + Vertex = 0x02 +}; + +void +TZF_LiveShaderClassView (tzf_shader_class shader_type, bool& can_scroll) +{ + ImGui::BeginGroup (); + + static float last_width = 256.0f; + const float font_size = ImGui::GetFont ()->FontSize * ImGui::GetIO ().FontGlobalScale; + + struct shader_class_imp_s + { + std::vector contents; + bool dirty = true; + uint32_t last_sel = 0; + int sel = -1; + float last_ht = 256.0f; + ImVec2 last_min = ImVec2 (0.0f, 0.0f); + ImVec2 last_max = ImVec2 (0.0f, 0.0f); + }; + + struct { + shader_class_imp_s vs; + shader_class_imp_s ps; + } static list_base; + + shader_class_imp_s* + list = ( shader_type == tzf_shader_class::Pixel ? &list_base.ps : + &list_base.vs ); + + tzf::RenderFix::shader_tracking_s* + tracker = ( shader_type == tzf_shader_class::Pixel ? &tzf::RenderFix::tracked_ps : + &tzf::RenderFix::tracked_vs ); + + std::vector + shaders ( shader_type == tzf_shader_class::Pixel ? tzf::RenderFix::last_frame.pixel_shaders.begin () : + tzf::RenderFix::last_frame.vertex_shaders.begin (), + shader_type == tzf_shader_class::Pixel ? tzf::RenderFix::last_frame.pixel_shaders.end () : + tzf::RenderFix::last_frame.vertex_shaders.end () ); + + std::unordered_map & + disassembly = ( shader_type == tzf_shader_class::Pixel ? ps_disassembly : + vs_disassembly ); + + const char* + szShaderWord = shader_type == tzf_shader_class::Pixel ? "Pixel" : + "Vertex"; + + if (list->dirty) + { + list->sel = -1; + int idx = 0; + list->contents.clear (); + + // The underlying list is unsorted for speed, but that's not at all + // intuitive to humans, so sort the thing when we have the RT view open. + std::sort ( shaders.begin (), + shaders.end () ); + + + + for ( auto it : shaders ) + { + char szDesc [16] = { }; + + sprintf (szDesc, "%08lx", (uintptr_t)it); + + list->contents.emplace_back (szDesc); + + if ((uint32_t)it == list->last_sel) + { + list->sel = idx; + //tzf::RenderFix::tracked_rt.tracking_tex = render_textures [sel]; + } + + ++idx; + } + } + + if (ImGui::IsMouseHoveringRect (list->last_min, list->last_max)) + { + if (ImGui::GetIO ().KeysDownDuration [VK_OEM_4] == 0.0f) { list->sel--; ImGui::GetIO ().WantCaptureKeyboard = true; } + else if (ImGui::GetIO ().KeysDownDuration [VK_OEM_6] == 0.0f) { list->sel++; ImGui::GetIO ().WantCaptureKeyboard = true; } + } + + ImGui::PushStyleVar (ImGuiStyleVar_ChildWindowRounding, 0.0f); + ImGui::PushStyleColor (ImGuiCol_Border, ImVec4 (0.9f, 0.7f, 0.5f, 1.0f)); + + ImGui::BeginChild ( szShaderWord, + ImVec2 ( font_size * 7.0f, std::max (font_size * 15.0f, list->last_ht)), + true, ImGuiWindowFlags_AlwaysAutoResize ); + + if (ImGui::IsWindowHovered ()) + { + can_scroll = false; + + ImGui::BeginTooltip (); + ImGui::TextColored (ImVec4 (0.9f, 0.6f, 0.2f, 1.0f), "You can cancel all render passes using the selected %s shader to disable an effect", szShaderWord); + ImGui::Separator (); + ImGui::BulletText ("Press [ while the mouse is hovering this list to select the previous shader"); + ImGui::BulletText ("Press ] while the mouse is hovering this list to select the next shader"); + ImGui::EndTooltip (); + + if (ImGui::GetIO ().KeysDownDuration [VK_OEM_4] == 0.0f) { list->sel--; ImGui::GetIO ().WantCaptureKeyboard = true; } + else if (ImGui::GetIO ().KeysDownDuration [VK_OEM_6] == 0.0f) { list->sel++; ImGui::GetIO ().WantCaptureKeyboard = true; } + } + + if (shaders.size ()) + { + struct { + int last_sel = 0; + bool sel_changed = false; + } static shader_state [3]; + + int& last_sel = shader_state [(int)shader_type].last_sel; + bool& sel_changed = shader_state [(int)shader_type].sel_changed; + + if (list->sel != last_sel) + sel_changed = true; + + last_sel = list->sel; + + for ( int line = 0; line < shaders.size (); line++ ) + { + if (line == list->sel) + { + bool selected = true; + + ImGui::Selectable (list->contents [line].c_str (), &selected); + + if (sel_changed) + { + ImGui::SetScrollHere (0.5f); + + sel_changed = false; + list->last_sel = (uint32_t)shaders [list->sel]; + tracker->crc32 = (uint32_t)shaders [list->sel]; + } + } + + else + { + bool selected = false; + + if (ImGui::Selectable (list->contents [line].c_str (), &selected)) + { + sel_changed = true; + list->sel = line; + list->last_sel = (uint32_t)shaders [list->sel]; + tracker->crc32 = (uint32_t)shaders [list->sel]; + } + } + } + } + + ImGui::EndChild (); + ImGui::PopStyleColor (); + + ImGui::SameLine (); + ImGui::BeginGroup (); + + if (ImGui::IsItemHoveredRect ()) { + if (ImGui::GetIO ().KeysDownDuration [VK_OEM_4] == 0.0f) list->sel--; + else if (ImGui::GetIO ().KeysDownDuration [VK_OEM_6] == 0.0f) list->sel++; + } + + if (tracker->crc32 != 0x00) + { + ImGui::BeginGroup (); + ImGui::Checkbox ( shader_type == tzf_shader_class::Pixel ? "Cancel Draws Using Selected Pixel Shader" : + "Cancel Draws Using Selected Vertex Shader", + &tracker->cancel_draws ); ImGui::SameLine (); + + if (tracker->cancel_draws) + ImGui::TextDisabled ("%lu Skipped Draw%c Last Frame (%lu textures)", tracker->num_draws, tracker->num_draws != 1 ? 's' : ' ', tracker->used_textures.size () ); + else + ImGui::TextDisabled ("%lu Draw%c Last Frame (%lu textures)", tracker->num_draws, tracker->num_draws != 1 ? 's' : ' ', tracker->used_textures.size () ); + + ImGui::Checkbox ( shader_type == tzf_shader_class::Pixel ? "Clamp Texture Coordinates For Selected Pixel Shader" : + "Clamp Texture Coordinates For Selected Vertex Shader", + &tracker->clamp_coords ); + + ImGui::Separator (); + ImGui::EndGroup (); + + if (ImGui::IsItemHoveredRect () && tracker->used_textures.size ()) + { + ImGui::BeginTooltip (); + + D3DFORMAT fmt = D3DFMT_UNKNOWN; + + for ( auto it : tracker->used_textures ) + { + ISKTextureD3D9* pTex = tzf::RenderFix::tex_mgr.getTexture (it)->d3d9_tex; + + if (pTex && pTex->pTex) + { + D3DSURFACE_DESC desc; + if (SUCCEEDED (pTex->pTex->GetLevelDesc (0, &desc))) + { + fmt = desc.Format; + ImGui::Image ( pTex->pTex, ImVec2 ( std::max (64.0f, (float)desc.Width / 16.0f), + ((float)desc.Height / (float)desc.Width) * std::max (64.0f, (float)desc.Width / 16.0f) ), + ImVec2 (0,0), ImVec2 (1,1), + ImColor (255,255,255,255), ImColor (242,242,13,255) ); + } + + ImGui::SameLine (); + + ImGui::BeginGroup (); + ImGui::Text ("Texture: %08lx", it); + ImGui::Text ("Format: %ws", SK_D3D9_FormatToStr (fmt).c_str ()); + ImGui::EndGroup (); + } + } + + ImGui::EndTooltip (); + } + + ImGui::PushStyleColor (ImGuiCol_Text, ImVec4 (0.80f, 0.80f, 1.0f, 1.0f)); + ImGui::TextWrapped (disassembly [tracker->crc32].header.c_str ()); + + ImGui::SameLine (); + ImGui::BeginGroup (); + ImGui::TreePush (""); + ImGui::Spacing (); ImGui::Spacing (); + ImGui::PushStyleColor (ImGuiCol_Text, ImVec4 (0.666f, 0.666f, 0.666f, 1.0f)); + + char szName [192] = { '\0' }; + char szOrdinal [64 ] = { '\0' }; + char szOrdEl [ 96] = { '\0' }; + + int el = 0; + + ImGui::PushItemWidth (font_size * 25); + + for ( auto&& it : tracker->constants ) + { + if (it.struct_members.size ()) + { + ImGui::PushStyleColor (ImGuiCol_Text, ImVec4 (0.9f, 0.1f, 0.7f, 1.0f)); + ImGui::Text (it.Name); + ImGui::PopStyleColor (); + + for ( auto&& it2 : it.struct_members ) + { + snprintf ( szOrdinal, 64, " (%c%-3lu) ", + it2.RegisterSet != D3DXRS_SAMPLER ? 'c' : 's', + it2.RegisterIndex ); + snprintf ( szOrdEl, 96, "%s::%lu", // Uniquely identify parameters that share registers + szOrdinal, el++ ); + snprintf ( szName, 192, "%-24s :%s", + it2.Name, szOrdinal ); + + if (it2.Type == D3DXPT_FLOAT && it2.Class == D3DXPC_VECTOR) + { + ImGui::Checkbox (szName, &it2.Override); ImGui::SameLine (); + ImGui::InputFloat4 (szOrdEl, it2.Data); + } + else { + ImGui::TreePush (""); ImGui::TextColored (ImVec4 (0.45f, 0.75f, 0.45f, 1.0f), szName); ImGui::TreePop (); + } + } + + ImGui::Separator (); + } + + else + { + snprintf ( szOrdinal, 64, " (%c%-3lu) ", + it.RegisterSet != D3DXRS_SAMPLER ? 'c' : 's', + it.RegisterIndex ); + snprintf ( szOrdEl, 96, "%s::%lu", // Uniquely identify parameters that share registers + szOrdinal, el++ ); + snprintf ( szName, 192, "%-24s :%s", + it.Name, szOrdinal ); + + if (it.Type == D3DXPT_FLOAT && it.Class == D3DXPC_VECTOR) + { + ImGui::Checkbox (szName, &it.Override); ImGui::SameLine (); + ImGui::InputFloat4 (szOrdEl, it.Data); + } else { + ImGui::TreePush (""); ImGui::TextColored (ImVec4 (0.45f, 0.75f, 0.45f, 1.0f), szName); ImGui::TreePop (); + } + } + } + ImGui::PopItemWidth (); + ImGui::TreePop (); + ImGui::EndGroup (); + + ImGui::Separator (); + + ImGui::PushStyleColor (ImGuiCol_Text, ImVec4 (0.99f, 0.99f, 0.01f, 1.0f)); + ImGui::TextWrapped (disassembly [tracker->crc32].code.c_str ()); + + ImGui::Separator (); + + ImGui::PushStyleColor (ImGuiCol_Text, ImVec4 (0.5f, 0.95f, 0.5f, 1.0f)); + ImGui::TextWrapped (disassembly [tracker->crc32].footer.c_str ()); + + ImGui::PopStyleColor (4); + } + else + tracker->cancel_draws = false; + + ImGui::EndGroup (); + + list->last_ht = ImGui::GetItemRectSize ().y; + + list->last_min = ImGui::GetItemRectMin (); + list->last_max = ImGui::GetItemRectMax (); + + ImGui::PopStyleVar (); + ImGui::EndGroup (); +} + +void +TZF_LiveVertexStreamView (bool& can_scroll) +{ + ImGui::BeginGroup (); + + static float last_width = 256.0f; + const float font_size = ImGui::GetFont ()->FontSize * ImGui::GetIO ().FontGlobalScale; + + struct vertex_stream_s + { + std::vector contents; + bool dirty = true; + uintptr_t last_sel = 0; + int sel = -1; + float last_ht = 256.0f; + ImVec2 last_min = ImVec2 (0.0f, 0.0f); + ImVec2 last_max = ImVec2 (0.0f, 0.0f); + }; + + struct { + vertex_stream_s stream0; + } static list_base; + + vertex_stream_s* + list = &list_base.stream0; + + tzf::RenderFix::vertex_buffer_tracking_s* + tracker = &tzf::RenderFix::tracked_vb; + + std::vector + buffers ( tzf::RenderFix::last_frame.vertex_buffers.begin (), + tzf::RenderFix::last_frame.vertex_buffers.end () ); + + if (list->dirty) + { + list->sel = -1; + int idx = 0; + list->contents.clear (); + + // The underlying list is unsorted for speed, but that's not at all + // intuitive to humans, so sort the thing when we have the RT view open. + std::sort ( buffers.begin (), + buffers.end () ); + + + + for ( auto it : buffers ) + { + char szDesc [16] = { }; + + sprintf (szDesc, "%08lx", (uintptr_t)it); + + list->contents.emplace_back (szDesc); + + if ((uintptr_t)it == list->last_sel) + { + list->sel = idx; + //tzf::RenderFix::tracked_rt.tracking_tex = render_textures [sel]; + } + + ++idx; + } + } + + if (ImGui::IsMouseHoveringRect (list->last_min, list->last_max)) + { + if (ImGui::GetIO ().KeysDownDuration [VK_OEM_4] == 0.0f) { list->sel--; ImGui::GetIO ().WantCaptureKeyboard = true; } + else if (ImGui::GetIO ().KeysDownDuration [VK_OEM_6] == 0.0f) { list->sel++; ImGui::GetIO ().WantCaptureKeyboard = true; } + } + + ImGui::PushStyleVar (ImGuiStyleVar_ChildWindowRounding, 0.0f); + ImGui::PushStyleColor (ImGuiCol_Border, ImVec4 (0.9f, 0.7f, 0.5f, 1.0f)); + + ImGui::BeginChild ( "Stream 0", + ImVec2 ( font_size * 7.0f, std::max (font_size * 15.0f, list->last_ht)), + true, ImGuiWindowFlags_AlwaysAutoResize ); + + if (ImGui::IsWindowHovered ()) + { + can_scroll = false; + + ImGui::BeginTooltip (); + ImGui::TextColored (ImVec4 (0.9f, 0.6f, 0.2f, 1.0f), "You can cancel all render passes using the selected vertex buffer to debug a model"); + ImGui::Separator (); + ImGui::BulletText ("Press [ while the mouse is hovering this list to select the previous shader"); + ImGui::BulletText ("Press ] while the mouse is hovering this list to select the next shader"); + ImGui::EndTooltip (); + + if (ImGui::GetIO ().KeysDownDuration [VK_OEM_4] == 0.0f) { list->sel--; ImGui::GetIO ().WantCaptureKeyboard = true; } + else if (ImGui::GetIO ().KeysDownDuration [VK_OEM_6] == 0.0f) { list->sel++; ImGui::GetIO ().WantCaptureKeyboard = true; } + } + + if (buffers.size ()) + { + struct { + int last_sel = 0; + bool sel_changed = false; + } static stream [3]; + + int& last_sel = stream [0].last_sel; + bool& sel_changed = stream [0].sel_changed; + + if (list->sel != last_sel) + sel_changed = true; + + last_sel = list->sel; + + for ( int line = 0; line < buffers.size (); line++ ) + { + if (line == list->sel) + { + bool selected = true; + + ImGui::Selectable (list->contents [line].c_str (), &selected); + + if (sel_changed) + { + ImGui::SetScrollHere (0.5f); + + sel_changed = false; + list->last_sel = (uintptr_t)buffers [list->sel]; + tracker->vertex_buffer = buffers [list->sel]; + } + } + + else + { + bool selected = false; + + if (ImGui::Selectable (list->contents [line].c_str (), &selected)) + { + sel_changed = true; + list->sel = line; + list->last_sel = (uintptr_t)buffers [list->sel]; + tracker->vertex_buffer = buffers [list->sel]; + } + } + } + } + + ImGui::EndChild (); + ImGui::PopStyleColor (); + + ImGui::SameLine (); + ImGui::BeginGroup (); + + if (ImGui::IsItemHoveredRect ()) { + if (ImGui::GetIO ().KeysDownDuration [VK_OEM_4] == 0.0f) list->sel--; + else if (ImGui::GetIO ().KeysDownDuration [VK_OEM_6] == 0.0f) list->sel++; + } + + if (tracker->vertex_buffer != nullptr) + { + ImGui::Checkbox ("Cancel Draws Using Selected Vertex Buffer", &tracker->cancel_draws); ImGui::SameLine (); + + if (tracker->cancel_draws) + ImGui::TextDisabled ("%lu Skipped Draw%c Last Frame", tracker->num_draws, tracker->num_draws != 1 ? 's' : ' '); + else + ImGui::TextDisabled ("%lu Draw%c Last Frame ", tracker->num_draws, tracker->num_draws != 1 ? 's' : ' '); + + ImGui::Checkbox ("Draw Selected Vertex Buffer In Wireframe", &tracker->wireframe); + } + else + tracker->cancel_draws = false; + + ImGui::EndGroup (); + + list->last_ht = ImGui::GetItemRectSize ().y; + + list->last_min = ImGui::GetItemRectMin (); + list->last_max = ImGui::GetItemRectMax (); + + ImGui::PopStyleVar (); + ImGui::EndGroup (); +} + + bool TZFix_TextureModDlg (void) { + const float font_size = ImGui::GetFont ()->FontSize * ImGui::GetIO ().FontGlobalScale; + bool show_dlg = true; + ImGui::SetNextWindowSizeConstraints ( ImVec2 (256.0f, 384.0f), ImVec2 ( ImGui::GetIO ().DisplaySize.x * 0.75f, ImGui::GetIO ().DisplaySize.y * 0.75f ) ); + ImGui::Begin ( "Tales Engine Texture Mod Toolkit (v " TZF_VERSION_STR_A ")", &show_dlg, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_ShowBorders ); + bool can_scroll = ImGui::IsMouseHoveringRect ( ImVec2 (ImGui::GetWindowPos ().x, ImGui::GetWindowPos ().y), + ImVec2 (ImGui::GetWindowPos ().x + ImGui::GetWindowSize ().x, ImGui::GetWindowPos ().y + ImGui::GetWindowSize ().y) ); + ImGui::PushItemWidth (ImGui::GetWindowWidth () * 0.666f); if (ImGui::CollapsingHeader ("Preliminary Documentation")) { - ImGui::BeginChild ("ModDescription", ImVec2 (750, 325), true); + ImGui::BeginChild ("ModDescription", ImVec2 (font_size * 66.0f, font_size * 25.0f), true); ImGui::TextColored (ImVec4 (0.9f, 0.7f, 0.5f, 1.0f), "Texture Modding Overview"); ImGui::SameLine (); ImGui::Text (" (Full Writeup Pending)"); @@ -277,13 +833,13 @@ TZFix_TextureModDlg (void) if (ImGui::CollapsingHeader("Injectable Data Sources", ImGuiTreeNodeFlags_CollapsingHeader | ImGuiTreeNodeFlags_DefaultOpen)) { - TZF_DrawFileList (); + TZF_DrawFileList (can_scroll); } if (ImGui::CollapsingHeader ("Live Texture View", ImGuiTreeNodeFlags_CollapsingHeader | ImGuiTreeNodeFlags_DefaultOpen)) { - static LONG last_ht = 256L; - static LONG last_width = 256L; + static float last_ht = 256.0f; + static float last_width = 256.0f; static std::vector list_contents; static bool list_dirty = false; @@ -293,9 +849,9 @@ TZFix_TextureModDlg (void) extern uint32_t tex_dbg_idx; extern uint32_t debug_tex_id; - ImGui::BeginChild ("ToolHeadings", ImVec2 (750, 32), false, ImGuiWindowFlags_AlwaysUseWindowPadding); + ImGui::BeginChild ("ToolHeadings", ImVec2 (font_size * 66.0f, font_size * 2.5f), false, ImGuiWindowFlags_AlwaysUseWindowPadding); - if (ImGui::Button ("Refresh Textures")) + if (ImGui::Button (" Refresh Textures ")) { SK_ICommandProcessor& command = *SK_GetCommandProcessor (); @@ -311,7 +867,7 @@ TZFix_TextureModDlg (void) ImGui::SameLine (); - if (ImGui::Button ("Clear Debug")) + if (ImGui::Button (" Clear Debug ")) { sel = -1; debug_tex_id = 0; @@ -337,6 +893,7 @@ TZFix_TextureModDlg (void) } ImGui::SameLine (); + ImGui::Checkbox ("Highlight Selected Texture in Game", &config.textures.highlight_debug_tex); ImGui::Separator (); @@ -347,6 +904,16 @@ TZFix_TextureModDlg (void) list_contents.clear (); sel = tex_dbg_idx; + if (debug_tex_id == 0) + last_ht = 0; + + + // The underlying list is unsorted for speed, but that's not at all + // intuitive to humans, so sort the thing when we have the RT view open. + std::sort ( textures_used_last_dump.begin (), + textures_used_last_dump.end () ); + + for ( auto it : textures_used_last_dump ) { char szDesc [16] = { }; @@ -363,9 +930,12 @@ TZFix_TextureModDlg (void) ImGui::PushStyleColor (ImGuiCol_Border, ImVec4 (0.9f, 0.7f, 0.5f, 1.0f)); ImGui::BeginChild ( "Item List", - ImVec2 ( 90, std::max (512L, last_ht) + 128 ), + ImVec2 ( font_size * 6.0f, std::max (font_size * 15.0f, last_ht)), true, ImGuiWindowFlags_AlwaysAutoResize ); + if (ImGui::IsWindowHovered ()) + can_scroll = false; + if (textures_used_last_dump.size ()) { static int last_sel = 0; @@ -410,44 +980,66 @@ TZFix_TextureModDlg (void) if (ImGui::IsItemHovered ()) { ImGui::BeginTooltip (); - ImGui::TextColored (ImVec4 (0.9f, 0.6f, 0.2f, 1.0f), "The \"debug\" texture will appear black to make identifying textures to modify easier."); - ImGui::Separator (); - ImGui::BulletText ("Press Ctrl + Shift + [ to select the previous texture from this list"); - ImGui::BulletText ("Press Ctrl + Shift + ] to select the next texture from this list"); - ImGui::EndTooltip (); + ImGui::TextColored (ImVec4 (0.9f, 0.6f, 0.2f, 1.0f), "The \"debug\" texture will appear black to make identifying textures to modify easier."); + ImGui::Separator (); + ImGui::BulletText ("Press Ctrl + Shift + [ to select the previous texture from this list"); + ImGui::BulletText ("Press Ctrl + Shift + ] to select the next texture from this list"); + ImGui::EndTooltip (); } - ImGui::SameLine (); + ImGui::SameLine (); ImGui::PushStyleVar (ImGuiStyleVar_ChildWindowRounding, 20.0f); - last_ht = std::max (last_ht, 16L); - last_width = std::max (last_width, 16L); + last_ht = std::max (last_ht, 16.0f); + last_width = std::max (last_width, 16.0f); if (debug_tex_id != 0x00) { tzf::RenderFix::Texture* pTex = tzf::RenderFix::tex_mgr.getTexture (debug_tex_id); + extern bool __remap_textures; + bool has_alternate = (pTex != nullptr && pTex->d3d9_tex->pTexOverride != nullptr); + if (pTex != nullptr) { D3DSURFACE_DESC desc; if (SUCCEEDED (pTex->d3d9_tex->pTex->GetLevelDesc (0, &desc))) { - ImGui::PushStyleColor (ImGuiCol_Border, ImVec4 (0.5f, 0.5f, 0.5f, 1.0f)); - ImGui::BeginChild ( "Item Selection", - ImVec2 (std::max (256L, (LONG)desc.Width + 24), std::max (512L, (LONG)desc.Height) + 128), true, ImGuiWindowFlags_AlwaysAutoResize ); + ImVec4 border_color = config.textures.highlight_debug_tex ? + ImVec4 (0.3f, 0.3f, 0.3f, 1.0f) : + (__remap_textures && has_alternate) ? ImVec4 (0.5f, 0.5f, 0.5f, 1.0f) : + ImVec4 (0.3f, 1.0f, 0.3f, 1.0f); - last_width = desc.Width; - last_ht = desc.Height; + ImGui::PushStyleColor (ImGuiCol_Border, border_color); + + ImGui::BeginGroup (); + ImGui::BeginChild ( "Item Selection", + ImVec2 ( std::max (font_size * 19.0f, (float)desc.Width + 24.0f), + (float)desc.Height + font_size * 10.0f), + true, + ImGuiWindowFlags_AlwaysAutoResize ); + + if ((! config.textures.highlight_debug_tex) && has_alternate) + { + if (ImGui::IsItemHovered ()) + ImGui::SetTooltip ("Click me to make this texture the visible version."); + + // Allow the user to toggle texture override by clicking the frame + if (ImGui::IsItemClicked ()) + __remap_textures = false; + } + + last_width = (float)desc.Width; + last_ht = (float)desc.Height + font_size * 10.0f; - extern std::wstring - SK_D3D9_FormatToStr (D3DFORMAT Format, bool include_ordinal = true); + int num_lods = pTex->d3d9_tex->pTex->GetLevelCount (); - ImGui::Text ( "Dimensions: %lux%lu", - desc.Width, desc.Height/*, - pTex->d3d9_tex->GetLevelCount ()*/ ); + ImGui::Text ( "Dimensions: %lux%lu (%lu %s)", + desc.Width, desc.Height, + num_lods, num_lods > 1 ? "LODs" : "LOD" ); ImGui::Text ( "Format: %ws", SK_D3D9_FormatToStr (desc.Format).c_str () ); ImGui::Text ( "Data Size: %.2f MiB", @@ -459,15 +1051,19 @@ TZFix_TextureModDlg (void) if (! TZF_IsTextureDumped (debug_tex_id)) { - if ( ImGui::Button ("Dump Texture to Disk") ) + if ( ImGui::Button (" Dump Texture to Disk ") ) { - TZF_DumpTexture (desc.Format, debug_tex_id, pTex->d3d9_tex->pTex); + //if (! config.textures.quick_load) + TZF_DumpTexture (desc.Format, debug_tex_id, pTex->d3d9_tex->pTex); } + + //if (config.textures.quick_load && ImGui::IsItemHovered ()) + //ImGui::SetTooltip ("Turn off Texture QuickLoad to use this feature."); } else { - if ( ImGui::Button ("Delete Dumped Texture from Disk") ) + if ( ImGui::Button (" Delete Dumped Texture from Disk ") ) { TZF_DeleteDumpedTexture (desc.Format, debug_tex_id); } @@ -482,11 +1078,12 @@ TZFix_TextureModDlg (void) ); ImGui::EndChildFrame (); ImGui::EndChild (); + ImGui::EndGroup (); ImGui::PopStyleColor (2); } } - if (pTex != nullptr && pTex->d3d9_tex->pTexOverride != nullptr) + if (has_alternate) { ImGui::SameLine (); @@ -494,9 +1091,34 @@ TZFix_TextureModDlg (void) if (SUCCEEDED (pTex->d3d9_tex->pTexOverride->GetLevelDesc (0, &desc))) { - ImGui::PushStyleColor (ImGuiCol_Border, ImVec4 (0.5f, 0.5f, 0.5f, 1.0f)); + ImVec4 border_color = config.textures.highlight_debug_tex ? + ImVec4 (0.3f, 0.3f, 0.3f, 1.0f) : + (__remap_textures) ? ImVec4 (0.3f, 1.0f, 0.3f, 1.0f) : + ImVec4 (0.5f, 0.5f, 0.5f, 1.0f); + + ImGui::PushStyleColor (ImGuiCol_Border, border_color); + + ImGui::BeginGroup (); ImGui::BeginChild ( "Item Selection2", - ImVec2 (std::max (256L, (LONG)desc.Width + 24), std::max (512L, (LONG)desc.Height) + 128), true, ImGuiWindowFlags_AlwaysAutoResize ); + ImVec2 ( std::max (font_size * 19.0f, (float)desc.Width + 24.0f), + (float)desc.Height + font_size * 10.0f), + true, + ImGuiWindowFlags_AlwaysAutoResize ); + + if (! config.textures.highlight_debug_tex) + { + if (ImGui::IsItemHovered ()) + ImGui::SetTooltip ("Click me to make this texture the visible version."); + + // Allow the user to toggle texture override by clicking the frame + if (ImGui::IsItemClicked ()) + __remap_textures = true; + } + + + last_width = std::max (last_width, (float)desc.Width); + last_ht = std::max (last_ht, (float)desc.Height + font_size * 10.0f); + extern std::wstring SK_D3D9_FormatToStr (D3DFORMAT Format, bool include_ordinal = true); @@ -506,10 +1128,11 @@ TZFix_TextureModDlg (void) (TZF_GetInjectableTexture (debug_tex_id) != nullptr), reloading = false;; + int num_lods = pTex->d3d9_tex->pTexOverride->GetLevelCount (); - ImGui::Text ( "Dimensions: %lux%lu", - desc.Width, desc.Height/*, - pTex->d3d9_tex->GetLevelCount ()*/ ); + ImGui::Text ( "Dimensions: %lux%lu (%lu %s)", + desc.Width, desc.Height, + num_lods, num_lods > 1 ? "LODs" : "LOD" ); ImGui::Text ( "Format: %ws", SK_D3D9_FormatToStr (desc.Format).c_str () ); ImGui::Text ( "Data Size: %.2f MiB", @@ -521,7 +1144,7 @@ TZFix_TextureModDlg (void) if (injected) { - if ( ImGui::Button ("Reload This Texture") && tzf::RenderFix::tex_mgr.reloadTexture (debug_tex_id) ) + if ( ImGui::Button (" Reload This Texture ") && tzf::RenderFix::tex_mgr.reloadTexture (debug_tex_id) ) { reloading = true; @@ -530,7 +1153,7 @@ TZFix_TextureModDlg (void) } else { - ImGui::Button ("Resample This Texture"); // NO-OP, but preserves alignment :P + ImGui::Button (" Resample This Texture "); // NO-OP, but preserves alignment :P } if (! reloading) @@ -547,6 +1170,7 @@ TZFix_TextureModDlg (void) } ImGui::EndChild (); + ImGui::EndGroup (); ImGui::PopStyleColor (1); } } @@ -556,10 +1180,224 @@ TZFix_TextureModDlg (void) ImGui::PopStyleVar (2); } + if (ImGui::CollapsingHeader ("Live Render Target View")) + { + static float last_ht = 256.0f; + static float last_width = 256.0f; + + static std::vector list_contents; + static bool list_dirty = true; + static uintptr_t last_sel_ptr = 0; + static int sel = -1; + + std::vector render_textures = + tzf::RenderFix::tex_mgr.getUsedRenderTargets (); + + tzf::RenderFix::tracked_rt.tracking_tex = 0; + + if (list_dirty) + { + sel = -1; + int idx = 0; + list_contents.clear (); + + // The underlying list is unsorted for speed, but that's not at all + // intuitive to humans, so sort the thing when we have the RT view open. + std::sort ( render_textures.begin (), + render_textures.end (), + []( IDirect3DBaseTexture9 *a, + IDirect3DBaseTexture9 *b ) + { + return (uintptr_t)a < (uintptr_t)b; + } + ); + + + for ( auto it : render_textures ) + { + char szDesc [16] = { }; + + sprintf (szDesc, "%lx", (uintptr_t)it); + + list_contents.push_back (szDesc); + + if ((uintptr_t)it == last_sel_ptr) { + sel = idx; + tzf::RenderFix::tracked_rt.tracking_tex = render_textures [sel]; + } + + ++idx; + } + } + + ImGui::PushStyleVar (ImGuiStyleVar_ChildWindowRounding, 0.0f); + ImGui::PushStyleColor (ImGuiCol_Border, ImVec4 (0.9f, 0.7f, 0.5f, 1.0f)); + + ImGui::BeginChild ( "Item List2", + ImVec2 ( font_size * 6.0f, std::max (font_size * 15.0f, last_ht)), + true, ImGuiWindowFlags_AlwaysAutoResize ); + + if (ImGui::IsWindowHovered ()) + can_scroll = false; + + if (render_textures.size ()) + { + static int last_sel = 0; + static bool sel_changed = false; + + if (sel != last_sel) + sel_changed = true; + + last_sel = sel; + + for ( int line = 0; line < render_textures.size (); line++ ) + { + D3DSURFACE_DESC desc; + + CComPtr pTex = nullptr; + + if (SUCCEEDED (render_textures [line]->QueryInterface (IID_PPV_ARGS (&pTex)))) + { + if (SUCCEEDED (pTex->GetLevelDesc (0, &desc))) + { + if (line == sel) + { + bool selected = true; + ImGui::Selectable (list_contents [line].c_str (), &selected); + + if (sel_changed) + { + ImGui::SetScrollHere (0.5f); // 0.0f:top, 0.5f:center, 1.0f:bottom + sel_changed = false; + } + } + + else + { + bool selected = false; + + if (ImGui::Selectable (list_contents [line].c_str (), &selected)) + { + sel_changed = true; + sel = line; + last_sel_ptr = (uintptr_t)render_textures [sel]; + tzf::RenderFix::tracked_rt.tracking_tex = render_textures [sel]; + } + } + } + } + } + } + + ImGui::EndChild (); + + ImGui::BeginGroup (); + + ImGui::PopStyleColor (); + ImGui::PopStyleVar (); + + CComPtr pTex = nullptr; + + if (render_textures.size () && sel >= 0) + render_textures [sel]->QueryInterface (IID_PPV_ARGS (&pTex)); + + if (pTex != nullptr) + { + D3DSURFACE_DESC desc; + + if (SUCCEEDED (pTex->GetLevelDesc (0, &desc))) + { + size_t shaders = std::max ( tzf::RenderFix::tracked_rt.pixel_shaders.size (), + tzf::RenderFix::tracked_rt.vertex_shaders.size () ); + + // Some Render Targets are MASSIVE, let's try to keep the damn things on the screen ;) + float effective_width = std::min (0.75f * ImGui::GetIO ().DisplaySize.x, (float)desc.Width / 2.0f); + float effective_height = std::min (0.75f * ImGui::GetIO ().DisplaySize.y, (float)desc.Height / 2.0f); + + ImGui::SameLine (); + + ImGui::PushStyleColor (ImGuiCol_Border, ImVec4 (0.5f, 0.5f, 0.5f, 1.0f)); + ImGui::BeginChild ( "Item Selection3", + ImVec2 ( std::max (font_size * 30.0f, effective_width + 24.0f), + std::max (256.0f, effective_height + font_size * 4.0f + (float)shaders * font_size) ), + true, + ImGuiWindowFlags_AlwaysAutoResize ); + + last_width = effective_width; + last_ht = effective_height + font_size * 4.0f + (float)shaders * font_size; + + extern std::wstring + SK_D3D9_FormatToStr (D3DFORMAT Format, bool include_ordinal = true); + + + ImGui::Text ( "Dimensions: %lux%lu", + desc.Width, desc.Height/*, + pTex->d3d9_tex->GetLevelCount ()*/ ); + ImGui::Text ( "Format: %ws", + SK_D3D9_FormatToStr (desc.Format).c_str () ); + + ImGui::Separator (); + + ImGui::PushStyleColor (ImGuiCol_Border, ImVec4 (0.95f, 0.95f, 0.05f, 1.0f)); + ImGui::BeginChildFrame (0, ImVec2 (effective_width + 8.0f, effective_height + 8.0f), ImGuiWindowFlags_ShowBorders); + ImGui::Image ( pTex, + ImVec2 (effective_width, effective_height), + ImVec2 (0,0), ImVec2 (1,1), + ImColor (255,255,255,255), ImColor (255,255,255,128) + ); + ImGui::EndChildFrame (); + + if (shaders > 0) + { + ImGui::Columns (2); + + for ( auto it : tzf::RenderFix::tracked_rt.vertex_shaders ) + ImGui::Text ("Vertex Shader: %08x", it); + + ImGui::NextColumn (); + + for ( auto it : tzf::RenderFix::tracked_rt.pixel_shaders ) + ImGui::Text ("Pixel Shader: %08x", it); + + ImGui::Columns (1); + } + + ImGui::EndChild (); + ImGui::PopStyleColor (2); + } + } + + ImGui::EndGroup (); + } + + if (ImGui::CollapsingHeader ("Live Shader View")) + { + ImGui::TreePush (""); + + if (ImGui::CollapsingHeader ("Pixel Shaders")) + TZF_LiveShaderClassView (tzf_shader_class::Pixel, can_scroll); + + if (ImGui::CollapsingHeader ("Vertex Shaders")) + TZF_LiveShaderClassView (tzf_shader_class::Vertex, can_scroll); + + ImGui::TreePop (); + } + + if (ImGui::CollapsingHeader ("Live Vertex Buffer View")) + { + ImGui::TreePush (""); + + if (ImGui::CollapsingHeader ("Stream 0")) + TZF_LiveVertexStreamView (can_scroll); + + ImGui::TreePop (); + } + if (ImGui::CollapsingHeader ("Misc. Settings")) { ImGui::TreePush (""); - if (ImGui::Checkbox ("Dump ALL Textures (TZFix_Res\\dump\\textures\\\\*.dds)", &config.textures.dump)) tzf::RenderFix::need_reset.graphics = true; + if (ImGui::Checkbox ("Dump ALL Shaders (TZFix_Res\\dump\\shaders\\_.html)", &config.render.dump_shaders)) tzf::RenderFix::need_reset.graphics = true; + if (ImGui::Checkbox ("Dump ALL Textures (TZFix_Res\\dump\\textures\\\\*.dds)", &config.textures.dump)) tzf::RenderFix::need_reset.graphics = true; if (ImGui::IsItemHovered ()) { @@ -572,6 +1410,10 @@ TZFix_TextureModDlg (void) } ImGui::PopItemWidth (); + + if (can_scroll) + ImGui::SetScrollY (ImGui::GetScrollY () + 5.0f * ImGui::GetFont ()->FontSize * -ImGui::GetIO ().MouseWheel); + ImGui::End (); return show_dlg; diff --git a/tzf_dsound/render.cpp b/tzf_dsound/render.cpp index 254e4cc..80e0e35 100644 --- a/tzf_dsound/render.cpp +++ b/tzf_dsound/render.cpp @@ -35,9 +35,13 @@ #include #include +#include + tzf::RenderFix::tzf_draw_states_s tzf::RenderFix::draw_state; +extern uint32_t current_tex [256]; + typedef HRESULT (STDMETHODCALLTYPE *SetRenderState_pfn) ( IDirect3DDevice9* This, @@ -45,18 +49,44 @@ typedef HRESULT (STDMETHODCALLTYPE *SetRenderState_pfn) DWORD Value ); -extern SetRenderState_pfn D3D9SetRenderState_Original; +extern SetRenderState_pfn D3D9SetRenderState_Original; + SetSamplerState_pfn D3D9SetSamplerState_Original = nullptr; + +DrawPrimitive_pfn D3D9DrawPrimitive_Original = nullptr; +DrawIndexedPrimitive_pfn D3D9DrawIndexedPrimitive_Original = nullptr; +DrawPrimitiveUP_pfn D3D9DrawPrimitiveUP_Original = nullptr; +DrawIndexedPrimitiveUP_pfn D3D9DrawIndexedPrimitiveUP_Original = nullptr; +SetStreamSource_pfn D3D9SetStreamSource_Original = nullptr; + +SK_BeginBufferSwap_pfn SK_BeginBufferSwap = nullptr; +SK_EndBufferSwap_pfn SK_EndBufferSwap = nullptr; +EndScene_pfn D3D9EndScene_Original = nullptr; +//SK_SetPresentParamsD3D9_pfn SK_SetPresentParamsD3D9_Original = nullptr; +Reset_pfn D3D9Reset_Original = nullptr; +TestCooperativeLevel_pfn D3D9TestCooperativeLevel_Original = nullptr; -DrawPrimitive_pfn D3D9DrawPrimitive_Original = nullptr; -DrawIndexedPrimitive_pfn D3D9DrawIndexedPrimitive_Original = nullptr; -DrawPrimitiveUP_pfn D3D9DrawPrimitiveUP_Original = nullptr; -DrawIndexedPrimitiveUP_pfn D3D9DrawIndexedPrimitiveUP_Original = nullptr; +UpdateSurface_pfn D3D9UpdateSurface_Original = nullptr; +SetScissorRect_pfn D3D9SetScissorRect_Original = nullptr; +SetViewport_pfn D3D9SetViewport_Original = nullptr; + +D3DXDisassembleShader_pfn D3DXDisassembleShader = nullptr; +SetVertexShader_pfn D3D9SetVertexShader_Original = nullptr; +SetPixelShader_pfn D3D9SetPixelShader_Original = nullptr; +SetVertexShaderConstantF_pfn D3D9SetVertexShaderConstantF_Original = nullptr; +SetPixelShaderConstantF_pfn D3D9SetPixelShaderConstantF_Original = nullptr; extern bool pending_loads (void); extern void TZFix_LoadQueuedTextures (void); extern void TZFix_DrawConfigUI (void); +enum reset_stage_s { + Initiate = 0x0, // Fake device loss + Respond = 0x1, // Fake device not reset + Clear = 0x2 // Return status to normal +} trigger_reset; + + bool fullscreen_blit = false; bool needs_aspect = false; @@ -108,16 +138,6 @@ TZF_ComputeAspectCoeffs (float& x, float& y, float& xoff, float& yoff) #include "hook.h" -typedef HRESULT (STDMETHODCALLTYPE *SetSamplerState_pfn) -(IDirect3DDevice9* This, - DWORD Sampler, - D3DSAMPLERSTATETYPE Type, - DWORD Value); - -SetSamplerState_pfn D3D9SetSamplerState_Original = nullptr; - -LPVOID SetSamplerState = nullptr; - COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE @@ -182,8 +202,8 @@ D3D9SetSamplerState_Detour (IDirect3DDevice9* This, return D3D9SetSamplerState_Original (This, Sampler, Type, Value); } -IDirect3DVertexShader9* g_pVS; -IDirect3DPixelShader9* g_pPS; +IDirect3DVertexShader9* g_pVS = nullptr; +IDirect3DPixelShader9* g_pPS = nullptr; static uint32_t crc32_tab[] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, @@ -244,45 +264,25 @@ crc32(uint32_t crc, const void *buf, size_t size) return crc ^ ~0U; } -#include -std::unordered_map vs_checksums; -std::unordered_map ps_checksums; -// Store the CURRENT shader's checksum instead of repeatedly -// looking it up in the above hashmaps. -uint32_t vs_checksum = 0; -uint32_t ps_checksum = 0; +#include -typedef interface ID3DXBuffer ID3DXBuffer; -typedef interface ID3DXBuffer *LPD3DXBUFFER; +// For now, let's just focus on stream0 and pretend nothing else exists... +IDirect3DVertexBuffer9* vb_stream0 = nullptr; -// {8BA5FB08-5195-40e2-AC58-0D989C3A0102} -DEFINE_GUID(IID_ID3DXBuffer, -0x8ba5fb08, 0x5195, 0x40e2, 0xac, 0x58, 0xd, 0x98, 0x9c, 0x3a, 0x1, 0x2); +std::unordered_map vs_disassembly; +std::unordered_map ps_disassembly; -#undef INTERFACE -#define INTERFACE ID3DXBuffer +std::unordered_map vs_checksums; +std::unordered_map ps_checksums; -DECLARE_INTERFACE_(ID3DXBuffer, IUnknown) -{ - // IUnknown - STDMETHOD ( QueryInterface) (THIS_ REFIID iid, LPVOID *ppv) PURE; - STDMETHOD_ (ULONG, AddRef) (THIS) PURE; - STDMETHOD_ (ULONG, Release) (THIS) PURE; - - // ID3DXBuffer - STDMETHOD_ (LPVOID, GetBufferPointer) (THIS) PURE; - STDMETHOD_ (DWORD, GetBufferSize) (THIS) PURE; -}; +tzf::RenderFix::frame_state_s tzf::RenderFix::last_frame; -typedef HRESULT (WINAPI *D3DXDisassembleShader_pfn)( - _In_ const DWORD *pShader, - _In_ BOOL EnableColorCode, - _In_ LPCSTR pComments, - _Out_ LPD3DXBUFFER *ppDisassembly -); +// Store the CURRENT shader's checksum instead of repeatedly +// looking it up in the above hashmaps. +uint32_t vs_checksum = 0; +uint32_t ps_checksum = 0; -D3DXDisassembleShader_pfn D3DXDisassembleShader = nullptr; void SK_D3D9_DumpShader ( const wchar_t* wszPrefix, @@ -291,57 +291,86 @@ SK_D3D9_DumpShader ( const wchar_t* wszPrefix, { static bool dump = config.render.dump_shaders; - if (dump) { - if (GetFileAttributes (L"TBFix_Res\\dump\\shaders") != - FILE_ATTRIBUTE_DIRECTORY) { - CreateDirectoryW (L"TBFix_Res", nullptr); - CreateDirectoryW (L"TBFix_Res\\dump", nullptr); - CreateDirectoryW (L"TBFix_Res\\dump\\shaders", nullptr); + if ( D3DXDisassembleShader != nullptr) + { + if (dump) + { + if (GetFileAttributes (L"TZFix_Res\\dump\\shaders") != + FILE_ATTRIBUTE_DIRECTORY) + { + CreateDirectoryW (L"TZFix_Res", nullptr); + CreateDirectoryW (L"TZFix_Res\\dump", nullptr); + CreateDirectoryW (L"TZFix_Res\\dump\\shaders", nullptr); + } + + wchar_t wszDumpName [MAX_PATH] = { L'\0' }; + + swprintf_s ( wszDumpName, + MAX_PATH, + L"TZFix_Res\\dump\\shaders\\%s_%08x.html", + wszPrefix, crc32 ); + + if ( GetFileAttributes (wszDumpName) == INVALID_FILE_ATTRIBUTES ) + { + CComPtr pDisasm = nullptr; + + HRESULT hr = + D3DXDisassembleShader ((DWORD *)pbFunc, TRUE, "", &pDisasm); + + if (SUCCEEDED (hr)) + { + FILE* fDump = _wfsopen (wszDumpName, L"wb", _SH_DENYWR); + + if (fDump != NULL) + { + fwrite ( pDisasm->GetBufferPointer (), + pDisasm->GetBufferSize (), + 1, + fDump ); + fclose (fDump); + } + } + } } - wchar_t wszDumpName [MAX_PATH]; - _swprintf ( wszDumpName, - L"TBFix_Res\\dump\\shaders\\%s_%08x.html", - wszPrefix, crc32 ); + CComPtr pDisasm = nullptr; - if (D3DXDisassembleShader == nullptr) - D3DXDisassembleShader = - (D3DXDisassembleShader_pfn) - GetProcAddress ( tzf::RenderFix::d3dx9_43_dll, - "D3DXDisassembleShader" ); + HRESULT hr = + D3DXDisassembleShader ((DWORD *)pbFunc, FALSE, "", &pDisasm); - if ( D3DXDisassembleShader != nullptr && - GetFileAttributes (wszDumpName) == INVALID_FILE_ATTRIBUTES ) { - LPD3DXBUFFER pDisasm; + if (SUCCEEDED (hr) && strlen ((const char *)pDisasm->GetBufferPointer ())) + { + char* szDisasm = _strdup ((const char *)pDisasm->GetBufferPointer ()); - HRESULT hr = - D3DXDisassembleShader ((DWORD *)pbFunc, TRUE, "", &pDisasm); + char* comments_end = strstr (szDisasm, "\n "); + char* footer_begins = comments_end ? strstr (comments_end + 1, "\n\n") : nullptr; - if (SUCCEEDED (hr)) { - FILE* fDump = - _wfopen (wszDumpName, L"wb"); + if (comments_end) *comments_end = '\0'; else (comments_end = " "); + if (footer_begins) *footer_begins = '\0'; else (footer_begins = " "); - if (fDump != NULL) { - fwrite ( pDisasm->GetBufferPointer (), - pDisasm->GetBufferSize (), - 1, - fDump ); - fclose (fDump); - } + if (! _wcsicmp (wszPrefix, L"ps")) + { + ps_disassembly.emplace ( crc32, tzf::RenderFix::shader_disasm_s { + szDisasm, + comments_end + 1, + footer_begins + 1 } + ); + } - pDisasm->Release (); + else + { + vs_disassembly.emplace ( crc32, tzf::RenderFix::shader_disasm_s { + szDisasm, + comments_end + 1, + footer_begins + 1 } + ); } + + free (szDisasm); } } } - -typedef HRESULT (STDMETHODCALLTYPE *SetVertexShader_pfn) - (IDirect3DDevice9* This, - IDirect3DVertexShader9* pShader); - -SetVertexShader_pfn D3D9SetVertexShader_Original = nullptr; - COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE @@ -364,8 +393,8 @@ D3D9SetVertexShader_Detour (IDirect3DDevice9* This, } #endif - //if (GetCurrentThreadId () != InterlockedExchangeAdd (&tzf::RenderFix::dwRenderThreadID, 0)) - //return D3D9SetVertexShader_Original (This, pShader); + if (GetCurrentThreadId () != InterlockedExchangeAdd (&tzf::RenderFix::dwRenderThreadID, 0)) + return D3D9SetVertexShader_Original (This, pShader); if (g_pVS != pShader) { @@ -395,15 +424,26 @@ D3D9SetVertexShader_Detour (IDirect3DDevice9* This, vs_checksum = vs_checksums [pShader]; g_pVS = pShader; + if (vs_checksum != 0x00) + { + tzf::RenderFix::last_frame.vertex_shaders.emplace (vs_checksum); + + if (tzf::RenderFix::tracked_rt.active) + tzf::RenderFix::tracked_rt.vertex_shaders.emplace (vs_checksum); + + if (vs_checksum == tzf::RenderFix::tracked_vs.crc32) + { + tzf::RenderFix::tracked_vs.use (pShader); + + for (int i = 0; i < 16; i++) + tzf::RenderFix::tracked_vs.current_textures [i] = 0x0; + } + } + return D3D9SetVertexShader_Original (This, pShader); } -typedef HRESULT (STDMETHODCALLTYPE *SetPixelShader_pfn) - (IDirect3DDevice9* This, - IDirect3DPixelShader9* pShader); - -SetPixelShader_pfn D3D9SetPixelShader_Original = nullptr; COM_DECLSPEC_NOTHROW HRESULT @@ -427,8 +467,8 @@ D3D9SetPixelShader_Detour (IDirect3DDevice9* This, } #endif - //if (GetCurrentThreadId () != InterlockedExchangeAdd (&tzf::RenderFix::dwRenderThreadID, 0)) - //return D3D9SetPixelShader_Original (This, pShader); + if (GetCurrentThreadId () != InterlockedExchangeAdd (&tzf::RenderFix::dwRenderThreadID, 0)) + return D3D9SetPixelShader_Original (This, pShader); if (g_pPS != pShader) { @@ -457,6 +497,22 @@ D3D9SetPixelShader_Detour (IDirect3DDevice9* This, ps_checksum = ps_checksums [pShader]; g_pPS = pShader; + if (ps_checksum != 0x00) + { + tzf::RenderFix::last_frame.pixel_shaders.emplace (ps_checksum); + + if (tzf::RenderFix::tracked_rt.active) + tzf::RenderFix::tracked_rt.pixel_shaders.emplace (ps_checksum); + + if (ps_checksum == tzf::RenderFix::tracked_ps.crc32) + { + tzf::RenderFix::tracked_ps.use (pShader); + + for (int i = 0; i < 16; i++) + tzf::RenderFix::tracked_ps.current_textures [i] = 0x0; + } + } + return D3D9SetPixelShader_Original (This, pShader); } @@ -482,24 +538,138 @@ const uint32_t PS_CHECKSUM_CHAR_SHADOW = 1180797962UL; const uint32_t VS_CHECKSUM_CHAR_SHADOW = 446150694UL; -typedef void (STDMETHODCALLTYPE *SK_BeginBufferSwap_pfn)(void); -SK_BeginBufferSwap_pfn SK_BeginBufferSwap = nullptr; +bool +TZF_ShouldSkipRenderPass (void) +{ + const bool tracked_vs = ( vs_checksum == tzf::RenderFix::tracked_vs.crc32 ); + const bool tracked_ps = ( ps_checksum == tzf::RenderFix::tracked_ps.crc32 ); + const bool tracked_vb = { vb_stream0 == tzf::RenderFix::tracked_vb.vertex_buffer }; + + if (tracked_vs) + { + tzf::RenderFix::tracked_vs.num_draws++; + + for (int i = 0; i < 16; i++) + if (tzf::RenderFix::tracked_vs.current_textures [i] != 0) + tzf::RenderFix::tracked_vs.used_textures.emplace (tzf::RenderFix::tracked_vs.current_textures [i]); + + + // + // TODO: Make generic and move into class -- must pass shader type to function + // + for ( auto&& it : tzf::RenderFix::tracked_vs.constants ) + { + for ( auto&& it2 : it.struct_members ) + { + if ( it2.Override ) + tzf::RenderFix::pDevice->SetVertexShaderConstantF ( it2.RegisterIndex, it2.Data, 1 ); + } + + if ( it.Override ) + tzf::RenderFix::pDevice->SetVertexShaderConstantF ( it.RegisterIndex, it.Data, 1 ); + } + } + + if (tracked_ps) + { + tzf::RenderFix::tracked_ps.num_draws++; + + for (int i = 0; i < 16; i++) + if (tzf::RenderFix::tracked_ps.current_textures [i] != 0) + tzf::RenderFix::tracked_ps.used_textures.emplace (tzf::RenderFix::tracked_ps.current_textures [i]); + + // + // TODO: Make generic and move into class -- must pass shader type to function + // + for ( auto&& it : tzf::RenderFix::tracked_ps.constants ) + { + for ( auto&& it2 : it.struct_members ) + { + if ( it2.Override ) + tzf::RenderFix::pDevice->SetPixelShaderConstantF ( it2.RegisterIndex, it2.Data, 1 ); + } + + if ( it.Override ) + tzf::RenderFix::pDevice->SetPixelShaderConstantF ( it.RegisterIndex, it.Data, 1 ); + } + } + + + bool clamp = false; + bool sharpen = false; + + if (ps_checksum == tzf::RenderFix::tracked_ps.crc32 && tzf::RenderFix::tracked_ps.clamp_coords) + clamp = true; + + if (vs_checksum == tzf::RenderFix::tracked_vs.crc32 && tzf::RenderFix::tracked_vs.clamp_coords) + clamp = true; + +#if 0 + if (config.textures.keep_ui_sharp && ps_checksum == 0x17c397fb) sharpen = true; + + if ( clamp || + ( config.textures.clamp_skit_coords && ps_checksum == 0x872e7c85 ) || + ( config.textures.clamp_map_coords && ps_checksum == 0xc954a649 ) ) + { + sharpen = true; + + D3D9SetSamplerState_Original (tbf::RenderFix::pDevice, 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP ); + D3D9SetSamplerState_Original (tbf::RenderFix::pDevice, 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP ); + D3D9SetSamplerState_Original (tbf::RenderFix::pDevice, 0, D3DSAMP_ADDRESSW, D3DTADDRESS_CLAMP ); + } +#endif + + if (sharpen) + { + float fMin = -3.0f; + D3D9SetSamplerState_Original (tzf::RenderFix::pDevice, 0, D3DSAMP_MIPMAPLODBIAS, *reinterpret_cast (&fMin) ); + } + + + + + if (tracked_vb) + { + tzf::RenderFix::tracked_vb.num_draws++; + + if (tzf::RenderFix::tracked_vb.wireframe) + tzf::RenderFix::pDevice->SetRenderState (D3DRS_FILLMODE, D3DFILL_WIREFRAME); + } + + else + { + if (tzf::RenderFix::tracked_vb.wireframe) + tzf::RenderFix::pDevice->SetRenderState (D3DRS_FILLMODE, D3DFILL_SOLID); + } + + if (tracked_vb && tzf::RenderFix::tracked_vb.cancel_draws) + return true; + -typedef HRESULT (STDMETHODCALLTYPE *SK_EndBufferSwap_pfn) - (HRESULT hr, - IUnknown* device); -SK_EndBufferSwap_pfn SK_EndBufferSwap = nullptr; + // Do these sparate so that we can accurately count used textures even on cancelled passes. + if (tracked_vs && tzf::RenderFix::tracked_vs.cancel_draws) + return true; -typedef HRESULT (STDMETHODCALLTYPE *SetScissorRect_pfn)( - IDirect3DDevice9* This, - const RECT* pRect); + if (tracked_ps && tzf::RenderFix::tracked_ps.cancel_draws) + return true; -SetScissorRect_pfn D3D9SetScissorRect_Original = nullptr; -typedef HRESULT (STDMETHODCALLTYPE *EndScene_pfn) -(IDirect3DDevice9* This); +#if 0 + if (config.render.validation) { + DWORD dwPasses = 0; + HRESULT hr = tbf::RenderFix::pDevice->ValidateDevice (&dwPasses); + + if (hr != S_OK) { + dll_log->Log (L"[D3D9Valid] D3D9 Validation Failure: %x", hr); + dll_log->Log (L"[D3D9Valid] Current vs: %x, Current ps: %x", + vs_checksum, ps_checksum ); + } + } +#endif + -EndScene_pfn D3D9EndScene_Original = nullptr; + return false; +} int draw_count = 0; int next_draw = 0; @@ -606,16 +776,12 @@ D3D9EndScene_Detour (IDirect3DDevice9* This) = (SKX_DrawExternalOSD_pfn)GetProcAddress (hMod, "SKX_DrawExternalOSD"); - static DWORD dwFirstTime = timeGetTime (); - static bool show_disclaimer = true; - - if (show_disclaimer) + if (config.render.osd_disclaimer) { - if (timeGetTime() > dwFirstTime + 10000UL) - show_disclaimer = false; - - SKX_DrawExternalOSD ("ToZFix", "Press Ctrl + Shift + O to toggle In-Game OSD\n" - "Press Ctrl + Shift + Backspace to access In-Game Config Menu"); + SKX_DrawExternalOSD ("ToBFix", "\n" + " Press Ctrl + Shift + O to toggle In-Game OSD\n" + " Press Ctrl + Shift + Backspace to access In-Game Config Menu\n\n" + " * This message will go away the first time you actually read it and successfully toggle the OSD."); } else @@ -677,10 +843,6 @@ D3D9EndFrame_Pre (void) ULONGLONG count = InterlockedIncrement (&frames); - if (count == 1) { - tzf::RenderFix::tex_mgr.Init (); - } - //if (GetCurrentThreadId () != InterlockedExchangeAdd (&tzf::RenderFix::dwRenderThreadID, 0)) //return SK_BeginBufferSwap (); @@ -706,6 +868,19 @@ D3D9EndFrame_Post (HRESULT hr, IUnknown* device) InterlockedExchange (&tzf::RenderFix::dwRenderThreadID, GetCurrentThreadId ()); + if (trigger_reset == reset_stage_s::Clear) + hr = SK_EndBufferSwap (hr, device); + else + hr = D3DERR_DEVICELOST; + + tzf::RenderFix::tex_mgr.resetUsedTextures (); + + tzf::RenderFix::last_frame.clear (); + tzf::RenderFix::tracked_rt.clear (); + tzf::RenderFix::tracked_vs.clear (); + tzf::RenderFix::tracked_ps.clear (); + tzf::RenderFix::tracked_vb.clear (); + hr = SK_EndBufferSwap (hr, device); if (config.framerate.minimize_latency) @@ -713,17 +888,17 @@ D3D9EndFrame_Post (HRESULT hr, IUnknown* device) tzf::RenderFix::draw_state.cegui_active = false; + static bool first = true; + + if (first) { + tzf::RenderFix::tex_mgr.Hook (); + TZF_ApplyQueuedHooks (); + first = false; + } + return hr; } -typedef HRESULT (STDMETHODCALLTYPE *UpdateSurface_pfn) - ( _In_ IDirect3DDevice9 *This, - _In_ IDirect3DSurface9 *pSourceSurface, - _In_ const RECT *pSourceRect, - _In_ IDirect3DSurface9 *pDestinationSurface, - _In_ const POINT *pDestinationPoint ); - -UpdateSurface_pfn D3D9UpdateSurface_Original = nullptr; COM_DECLSPEC_NOTHROW HRESULT @@ -869,12 +1044,6 @@ D3D9SetScissorRect_Detour (IDirect3DDevice9* This, return D3D9SetScissorRect_Original (This, &fixed_scissor); } -typedef HRESULT (STDMETHODCALLTYPE *SetViewport_pfn)( - IDirect3DDevice9* This, - CONST D3DVIEWPORT9* pViewport); - -SetViewport_pfn D3D9SetViewport_Original = nullptr; - COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE @@ -1044,6 +1213,10 @@ D3D9DrawIndexedPrimitive_Detour (IDirect3DDevice9* This, ++tzf::RenderFix::draw_state.draws; ++draw_count; + + if (TZF_ShouldSkipRenderPass ()) + return S_OK; + // Battle Works Well #if 0 if (vs_checksum == 107874419/* && ps_checksum == 3087596655*/) @@ -1108,14 +1281,6 @@ D3D9DrawIndexedPrimitive_Detour (IDirect3DDevice9* This, } -typedef HRESULT (STDMETHODCALLTYPE *SetVertexShaderConstantF_pfn)( - IDirect3DDevice9* This, - UINT StartRegister, - CONST float* pConstantData, - UINT Vector4fCount); - -SetVertexShaderConstantF_pfn D3D9SetVertexShaderConstantF_Original = nullptr; - COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE @@ -1362,14 +1527,6 @@ D3D9SetVertexShaderConstantF_Detour (IDirect3DDevice9* This, -typedef HRESULT (STDMETHODCALLTYPE *SetPixelShaderConstantF_pfn)( - IDirect3DDevice9* This, - UINT StartRegister, - CONST float* pConstantData, - UINT Vector4fCount); - -SetVertexShaderConstantF_pfn D3D9SetPixelShaderConstantF_Original = nullptr; - COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE @@ -1402,6 +1559,9 @@ D3D9DrawPrimitive_Detour (IDirect3DDevice9* This, tzf::RenderFix::draw_state.draws++; + if (TZF_ShouldSkipRenderPass ()) + return S_OK; + #if 0 if (tsf::RenderFix::tracer.log) { dll_log->Log ( L"[FrameTrace] DrawPrimitive - %X, StartVertex: %lu, PrimitiveCount: %lu", @@ -1456,6 +1616,9 @@ D3D9DrawPrimitiveUP_Detour ( IDirect3DDevice9* This, tzf::RenderFix::draw_state.draws++; + if (TZF_ShouldSkipRenderPass ()) + return S_OK; + return D3D9DrawPrimitiveUP_Original ( This, PrimitiveType, @@ -1495,6 +1658,9 @@ D3D9DrawIndexedPrimitiveUP_Detour ( IDirect3DDevice9* This, tzf::RenderFix::draw_state.draws++; + if (TZF_ShouldSkipRenderPass ()) + return S_OK; + return D3D9DrawIndexedPrimitiveUP_Original ( This, @@ -1519,10 +1685,16 @@ tzf::RenderFix::Reset ( IDirect3DDevice9 *This, ULONG count = InterlockedIncrement (&reset_count); - if (pending_loads ()) - TZFix_LoadQueuedTextures (); + { + if (pending_loads ()) + TZFix_LoadQueuedTextures (); + + tex_mgr.reset (); + + need_reset.textures = false; + } - tex_mgr.reset (); + tex_mgr.resetUsedTextures (); need_reset.textures = false; need_reset.graphics = false; @@ -1539,13 +1711,6 @@ tzf::RenderFix::Reset ( IDirect3DDevice9 *This, height = pPresentationParameters->BackBufferHeight; } -typedef HRESULT (__stdcall *Reset_pfn)( - IDirect3DDevice9 *This, - D3DPRESENT_PARAMETERS *pPresentationParameters -); - -Reset_pfn D3D9Reset_Original = nullptr; - COM_DECLSPEC_NOTHROW HRESULT __stdcall @@ -1562,6 +1727,83 @@ D3D9Reset_Detour ( IDirect3DDevice9 *This, HWND hWnd = pPresentationParameters->hDeviceWindow; } + trigger_reset = reset_stage_s::Clear; + + return hr; +} + +COM_DECLSPEC_NOTHROW +HRESULT +STDMETHODCALLTYPE +D3D9TestCooperativeLevel_Detour ( IDirect3DDevice9 *This ) +{ + if (trigger_reset == reset_stage_s::Initiate) + { + trigger_reset = reset_stage_s::Respond; + return D3DERR_DEVICELOST; + } + + else if (trigger_reset == reset_stage_s::Respond) + { + return D3DERR_DEVICENOTRESET; + } + + return D3D9TestCooperativeLevel_Original (This); +} + +#if 0 +COM_DECLSPEC_NOTHROW +HRESULT +STDMETHODCALLTYPE +D3D9CreateVertexBuffer_Detour ( + _In_ IDirect3DDevice9 *This, + _In_ UINT Length, + _In_ DWORD Usage, + _In_ DWORD FVF, + _In_ D3DPOOL Pool, + _Out_ IDirect3DVertexBuffer9 **ppVertexBuffer, + _In_ HANDLE *pSharedHandle ) +{ + +} +#endif + +COM_DECLSPEC_NOTHROW +HRESULT +STDMETHODCALLTYPE +D3D9SetStreamSource_Detour +( + IDirect3DDevice9 *This, + UINT StreamNumber, + IDirect3DVertexBuffer9 *pStreamData, + UINT OffsetInBytes, + UINT Stride ) +{ + // Ignore anything that's not the primary render device. + if (This != tzf::RenderFix::pDevice) { + return + D3D9SetStreamSource_Original ( This, + StreamNumber, + pStreamData, + OffsetInBytes, + Stride ); + } + + HRESULT hr = + D3D9SetStreamSource_Original ( This, + StreamNumber, + pStreamData, + OffsetInBytes, + Stride ); + + if (SUCCEEDED (hr)) + { + tzf::RenderFix::last_frame.vertex_buffers.emplace (pStreamData); + + if (StreamNumber == 0) + vb_stream0 = pStreamData; + } + return hr; } @@ -1569,21 +1811,21 @@ D3D9Reset_Detour ( IDirect3DDevice9 *This, void tzf::RenderFix::Init (void) { + last_frame.vertex_shaders.reserve (256); + last_frame.pixel_shaders.reserve (256); + ps_disassembly.reserve (512); + vs_disassembly.reserve (512); + vs_checksums.reserve (8192); + ps_checksums.reserve (8192); + + trigger_reset = reset_stage_s::Clear; + d3dx9_43_dll = LoadLibrary (L"D3DX9_43.DLL"); TZF_CreateDLLHook2 ( config.system.injector.c_str (), "D3D9SetSamplerState_Override", D3D9SetSamplerState_Detour, - (LPVOID*)&D3D9SetSamplerState_Original, - &SetSamplerState ); - -#if 0 - TZF_CreateDLLHook ( L"d3d9.dll", "D3D9SetPixelShaderConstantF_Override", - D3D9SetPixelShaderConstantF_Detour, - (LPVOID*)&D3D9SetPixelShaderConstantF_Original ); -#endif - + (LPVOID*)&D3D9SetSamplerState_Original ); -#if 1 // Needed for shadow re-scaling TZF_CreateDLLHook2 ( config.system.injector.c_str (), "D3D9SetViewport_Override", D3D9SetViewport_Detour, @@ -1594,6 +1836,10 @@ tzf::RenderFix::Init (void) (LPVOID*)&D3D9SetVertexShaderConstantF_Original ); + TZF_CreateDLLHook2 ( config.system.injector.c_str (), "D3D9SetPixelShaderConstantF_Override", + D3D9SetPixelShaderConstantF_Detour, + (LPVOID*)&D3D9SetPixelShaderConstantF_Original ); + TZF_CreateDLLHook2 ( config.system.injector.c_str (), "D3D9SetVertexShader_Override", D3D9SetVertexShader_Detour, (LPVOID*)&D3D9SetVertexShader_Original ); @@ -1610,7 +1856,6 @@ tzf::RenderFix::Init (void) TZF_CreateDLLHook2 ( config.system.injector.c_str (), "D3D9EndScene_Override", D3D9EndScene_Detour, (LPVOID*)&D3D9EndScene_Original ); -#endif TZF_CreateDLLHook2 ( config.system.injector.c_str (), @@ -1639,6 +1884,16 @@ tzf::RenderFix::Init (void) D3D9EndFrame_Post, (LPVOID*)&SK_EndBufferSwap ); + TZF_CreateDLLHook2 ( config.system.injector.c_str (), + "D3D9TestCooperativeLevel_Override", + D3D9TestCooperativeLevel_Detour, + (LPVOID *)&D3D9TestCooperativeLevel_Original ); + + TZF_CreateDLLHook2 ( config.system.injector.c_str (), + "D3D9SetStreamSource_Override", + D3D9SetStreamSource_Detour, + (LPVOID *)&D3D9SetStreamSource_Original ); + TZF_CreateDLLHook2 ( config.system.injector.c_str (), "D3D9DrawPrimitive_Override", D3D9DrawPrimitive_Detour, @@ -1659,9 +1914,14 @@ tzf::RenderFix::Init (void) D3D9DrawIndexedPrimitiveUP_Detour, (LPVOID*)&D3D9DrawIndexedPrimitiveUP_Original ); + D3DXDisassembleShader = + (D3DXDisassembleShader_pfn) + GetProcAddress ( tzf::RenderFix::d3dx9_43_dll, + "D3DXDisassembleShader" ); + CommandProcessor* comm_proc = CommandProcessor::getInstance (); - TZF_ApplyQueuedHooks (); + tex_mgr.Init (); } void @@ -1771,6 +2031,75 @@ tzf::RenderFix::CommandProcessor::OnVarChange (SK_IVariable* var, void* val) return true; } +void +tzf::RenderFix::TriggerReset (void) +{ + trigger_reset = reset_stage_s::Initiate; +} + +extern HMODULE hInjectorDLL; + +bool +tzf::RenderFix::InstallSGSSAA (void) +{ +#if 0 + ((void (__stdcall *)(const wchar_t * ))GetProcAddress (hInjectorDLL, "SK_NvAPI_SetAppFriendlyName")) ( L"Tales of Zestiria" ); + ((void (__stdcall *)(const wchar_t * ))GetProcAddress (hInjectorDLL, "SK_NvAPI_SetAppName")) ( L"Tales of Zestiria.exe" ); + + wchar_t wszBits [16] = { L'\0' }; + + wcsncpy (wszBits, config.render.nv.compat_bits.c_str (), 16); + + if (config.render.nv.sgssaa_mode == 1) + { + const wchar_t* props [] = { L"CompatibilityBits", wszBits, + L"Method", L"2xMSAA", + L"ReplayMode", L"2xSGSSAA", + L"AntiAliasFix", L"Off", + L"AutoBiasAdjust", L"Off", + L"Override", L"On", + nullptr, nullptr }; + return ((BOOL (__stdcall *)(const wchar_t **))GetProcAddress (hInjectorDLL, "SK_NvAPI_SetAntiAliasingOverride"))( props ); + } + + else if (config.render.nv.sgssaa_mode == 2) + { + const wchar_t* props [] = { L"CompatibilityBits", wszBits, + L"Method", L"4xMSAA", + L"ReplayMode", L"4xSGSSAA", + L"AntiAliasFix", L"Off", + L"AutoBiasAdjust", L"Off", + L"Override", L"On", + nullptr, nullptr }; + return ((BOOL (__stdcall *)(const wchar_t **))GetProcAddress (hInjectorDLL, "SK_NvAPI_SetAntiAliasingOverride"))( props ); + } + + else if (config.render.nv.sgssaa_mode == 3) + { + const wchar_t* props [] = { L"CompatibilityBits", wszBits, + L"Method", L"8xMSAA", + L"ReplayMode", L"8xSGSSAA", + L"AntiAliasFix", L"Off", + L"AutoBiasAdjust", L"Off", + L"Override", L"On", + nullptr, nullptr }; + return ((BOOL (__stdcall *)(const wchar_t **))GetProcAddress (hInjectorDLL, "SK_NvAPI_SetAntiAliasingOverride"))( props ); + } + + else + { + const wchar_t* props [] = { L"Method", L"0x00000000", + L"ReplayMode", L"0x00000000", + L"AutoBiasAdjust", L"On", + L"Override", L"No", + nullptr, nullptr }; + return ((BOOL (__stdcall *)(const wchar_t **))GetProcAddress (hInjectorDLL, "SK_NvAPI_SetAntiAliasingOverride"))( props ); + } +#endif + return FALSE; +} + + tzf::RenderFix::CommandProcessor* tzf::RenderFix::CommandProcessor::pCommProc @@ -1789,4 +2118,114 @@ bool tzf::RenderFix::bink = false; HMODULE tzf::RenderFix::user32_dll = 0; tzf::RenderFix::tzf_reset_state_s - tzf::RenderFix::need_reset; \ No newline at end of file + tzf::RenderFix::need_reset; + +tzf::RenderFix::render_target_tracking_s + tzf::RenderFix::tracked_rt; + +tzf::RenderFix::shader_tracking_s + tzf::RenderFix::tracked_vs; + +tzf::RenderFix::shader_tracking_s + tzf::RenderFix::tracked_ps; + +tzf::RenderFix::vertex_buffer_tracking_s + tzf::RenderFix::tracked_vb; + +void +EnumConstant ( tzf::RenderFix::shader_tracking_s* pShader, + ID3DXConstantTable* pConstantTable, + D3DXHANDLE hConstant, + tzf::RenderFix::shader_tracking_s:: + shader_constant_s& constant, + std::vector < + tzf::RenderFix::shader_tracking_s:: + shader_constant_s >& list ) +{ + UINT one = 1; + + D3DXCONSTANT_DESC constant_desc; + if (SUCCEEDED (pConstantTable->GetConstantDesc (hConstant, &constant_desc, &one))) + { + strncpy (constant.Name, constant_desc.Name, 128); + constant.Class = constant_desc.Class; + constant.Type = constant_desc.Type; + constant.RegisterSet = constant_desc.RegisterSet; + constant.RegisterIndex = constant_desc.RegisterIndex; + constant.RegisterCount = constant_desc.RegisterCount; + constant.Rows = constant_desc.Rows; + constant.Columns = constant_desc.Columns; + //constant.Elements = constant_desc.Elements; + + //if (constant_desc.DefaultValue != nullptr) + //memcpy (constant.Data, constant_desc.DefaultValue, std::min ((size_t)constant_desc.Bytes, sizeof (float) * 4UL)); + + for ( UINT j = 0; j < constant_desc.StructMembers; j++ ) + { + D3DXHANDLE hConstantStruct = + pConstantTable->GetConstant (hConstant, j); + + tzf::RenderFix::shader_tracking_s::shader_constant_s struct_constant = { }; + + EnumConstant (pShader, pConstantTable, hConstantStruct, struct_constant, constant.struct_members ); + } + + list.push_back (constant); + } +}; + + + +void +tzf::RenderFix::shader_tracking_s::use (IUnknown *pShader) +{ + if (shader_obj != pShader) + { + constants.clear (); + + shader_obj = pShader; + + static D3DXGetShaderConstantTable_pfn D3DXGetShaderConstantTable = + (D3DXGetShaderConstantTable_pfn) + GetProcAddress (d3dx9_43_dll, "D3DXGetShaderConstantTable"); + + UINT len; + if (SUCCEEDED (((IDirect3DVertexShader9 *)pShader)->GetFunction (nullptr, &len))) + { + void* pbFunc = malloc (len); + + if (pbFunc != nullptr) + { + if ( SUCCEEDED ( ((IDirect3DVertexShader9 *)pShader)->GetFunction ( pbFunc, + &len ) + ) + ) + { + CComPtr pConstantTable = nullptr; + + if (SUCCEEDED (D3DXGetShaderConstantTable ((DWORD *)pbFunc, &pConstantTable))) + { + D3DXCONSTANTTABLE_DESC ct_desc; + + if (SUCCEEDED (pConstantTable->GetDesc (&ct_desc))) + { + UINT constant_count = ct_desc.Constants; + + for (UINT i = 0; i < constant_count; i++) + { + D3DXHANDLE hConstant = + pConstantTable->GetConstant (nullptr, i); + + shader_constant_s constant = { }; + + EnumConstant (this, pConstantTable, hConstant, constant, constants); + } + } + } + } + + free (pbFunc); + } + } + } +} \ No newline at end of file diff --git a/tzf_dsound/render.h b/tzf_dsound/render.h index 218f742..71d4e53 100644 --- a/tzf_dsound/render.h +++ b/tzf_dsound/render.h @@ -30,6 +30,311 @@ #include +#include + +//--------------------------------------------------------------------------- +// D3DXTX_VERSION: +// -------------- +// Version token used to create a procedural texture filler in effects +// Used by D3DXFill[]TX functions +//--------------------------------------------------------------------------- +#define D3DXTX_VERSION(_Major,_Minor) (('T' << 24) | ('X' << 16) | ((_Major) << 8) | (_Minor)) + + + +//---------------------------------------------------------------------------- +// D3DXSHADER flags: +// ----------------- +// D3DXSHADER_DEBUG +// Insert debug file/line/type/symbol information. +// +// D3DXSHADER_SKIPVALIDATION +// Do not validate the generated code against known capabilities and +// constraints. This option is only recommended when compiling shaders +// you KNOW will work. (ie. have compiled before without this option.) +// Shaders are always validated by D3D before they are set to the device. +// +// D3DXSHADER_SKIPOPTIMIZATION +// Instructs the compiler to skip optimization steps during code generation. +// Unless you are trying to isolate a problem in your code using this option +// is not recommended. +// +// D3DXSHADER_PACKMATRIX_ROWMAJOR +// Unless explicitly specified, matrices will be packed in row-major order +// on input and output from the shader. +// +// D3DXSHADER_PACKMATRIX_COLUMNMAJOR +// Unless explicitly specified, matrices will be packed in column-major +// order on input and output from the shader. This is generally more +// efficient, since it allows vector-matrix multiplication to be performed +// using a series of dot-products. +// +// D3DXSHADER_PARTIALPRECISION +// Force all computations in resulting shader to occur at partial precision. +// This may result in faster evaluation of shaders on some hardware. +// +// D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT +// Force compiler to compile against the next highest available software +// target for vertex shaders. This flag also turns optimizations off, +// and debugging on. +// +// D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT +// Force compiler to compile against the next highest available software +// target for pixel shaders. This flag also turns optimizations off, +// and debugging on. +// +// D3DXSHADER_NO_PRESHADER +// Disables Preshaders. Using this flag will cause the compiler to not +// pull out static expression for evaluation on the host cpu +// +// D3DXSHADER_AVOID_FLOW_CONTROL +// Hint compiler to avoid flow-control constructs where possible. +// +// D3DXSHADER_PREFER_FLOW_CONTROL +// Hint compiler to prefer flow-control constructs where possible. +// +//---------------------------------------------------------------------------- + +#define D3DXSHADER_DEBUG (1 << 0) +#define D3DXSHADER_SKIPVALIDATION (1 << 1) +#define D3DXSHADER_SKIPOPTIMIZATION (1 << 2) +#define D3DXSHADER_PACKMATRIX_ROWMAJOR (1 << 3) +#define D3DXSHADER_PACKMATRIX_COLUMNMAJOR (1 << 4) +#define D3DXSHADER_PARTIALPRECISION (1 << 5) +#define D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT (1 << 6) +#define D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT (1 << 7) +#define D3DXSHADER_NO_PRESHADER (1 << 8) +#define D3DXSHADER_AVOID_FLOW_CONTROL (1 << 9) +#define D3DXSHADER_PREFER_FLOW_CONTROL (1 << 10) +#define D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY (1 << 12) +#define D3DXSHADER_IEEE_STRICTNESS (1 << 13) +#define D3DXSHADER_USE_LEGACY_D3DX9_31_DLL (1 << 16) + + +// optimization level flags +#define D3DXSHADER_OPTIMIZATION_LEVEL0 (1 << 14) +#define D3DXSHADER_OPTIMIZATION_LEVEL1 0 +#define D3DXSHADER_OPTIMIZATION_LEVEL2 ((1 << 14) | (1 << 15)) +#define D3DXSHADER_OPTIMIZATION_LEVEL3 (1 << 15) + + + +//---------------------------------------------------------------------------- +// D3DXCONSTTABLE flags: +// ------------------- + +#define D3DXCONSTTABLE_LARGEADDRESSAWARE (1 << 17) + + + +//---------------------------------------------------------------------------- +// D3DXHANDLE: +// ----------- +// Handle values used to efficiently reference shader and effect parameters. +// Strings can be used as handles. However, handles are not always strings. +//---------------------------------------------------------------------------- + +#ifndef D3DXFX_LARGEADDRESS_HANDLE +typedef LPCSTR D3DXHANDLE; +#else +typedef UINT_PTR D3DXHANDLE; +#endif +typedef D3DXHANDLE *LPD3DXHANDLE; + + +//---------------------------------------------------------------------------- +// D3DXMACRO: +// ---------- +// Preprocessor macro definition. The application pass in a NULL-terminated +// array of this structure to various D3DX APIs. This enables the application +// to #define tokens at runtime, before the file is parsed. +//---------------------------------------------------------------------------- + +typedef struct _D3DXMACRO +{ + LPCSTR Name; + LPCSTR Definition; + +} D3DXMACRO, *LPD3DXMACRO; + + +//---------------------------------------------------------------------------- +// D3DXSEMANTIC: +//---------------------------------------------------------------------------- + +typedef struct _D3DXSEMANTIC +{ + UINT Usage; + UINT UsageIndex; + +} D3DXSEMANTIC, *LPD3DXSEMANTIC; + + + +//---------------------------------------------------------------------------- +// D3DXREGISTER_SET: +//---------------------------------------------------------------------------- + +typedef enum _D3DXREGISTER_SET +{ + D3DXRS_BOOL, + D3DXRS_INT4, + D3DXRS_FLOAT4, + D3DXRS_SAMPLER, + + // force 32-bit size enum + D3DXRS_FORCE_DWORD = 0x7fffffff + +} D3DXREGISTER_SET, *LPD3DXREGISTER_SET; + + +//---------------------------------------------------------------------------- +// D3DXPARAMETER_CLASS: +//---------------------------------------------------------------------------- + +typedef enum _D3DXPARAMETER_CLASS +{ + D3DXPC_SCALAR, + D3DXPC_VECTOR, + D3DXPC_MATRIX_ROWS, + D3DXPC_MATRIX_COLUMNS, + D3DXPC_OBJECT, + D3DXPC_STRUCT, + + // force 32-bit size enum + D3DXPC_FORCE_DWORD = 0x7fffffff + +} D3DXPARAMETER_CLASS, *LPD3DXPARAMETER_CLASS; + + +//---------------------------------------------------------------------------- +// D3DXPARAMETER_TYPE: +//---------------------------------------------------------------------------- + +typedef enum _D3DXPARAMETER_TYPE +{ + D3DXPT_VOID, + D3DXPT_BOOL, + D3DXPT_INT, + D3DXPT_FLOAT, + D3DXPT_STRING, + D3DXPT_TEXTURE, + D3DXPT_TEXTURE1D, + D3DXPT_TEXTURE2D, + D3DXPT_TEXTURE3D, + D3DXPT_TEXTURECUBE, + D3DXPT_SAMPLER, + D3DXPT_SAMPLER1D, + D3DXPT_SAMPLER2D, + D3DXPT_SAMPLER3D, + D3DXPT_SAMPLERCUBE, + D3DXPT_PIXELSHADER, + D3DXPT_VERTEXSHADER, + D3DXPT_PIXELFRAGMENT, + D3DXPT_VERTEXFRAGMENT, + D3DXPT_UNSUPPORTED, + + // force 32-bit size enum + D3DXPT_FORCE_DWORD = 0x7fffffff + +} D3DXPARAMETER_TYPE, *LPD3DXPARAMETER_TYPE; + + +//---------------------------------------------------------------------------- +// D3DXCONSTANTTABLE_DESC: +//---------------------------------------------------------------------------- + +typedef struct _D3DXCONSTANTTABLE_DESC +{ + LPCSTR Creator; // Creator string + DWORD Version; // Shader version + UINT Constants; // Number of constants + +} D3DXCONSTANTTABLE_DESC, *LPD3DXCONSTANTTABLE_DESC; + + +//---------------------------------------------------------------------------- +// D3DXCONSTANT_DESC: +//---------------------------------------------------------------------------- + +typedef struct _D3DXCONSTANT_DESC +{ + LPCSTR Name; // Constant name + + D3DXREGISTER_SET RegisterSet; // Register set + UINT RegisterIndex; // Register index + UINT RegisterCount; // Number of registers occupied + + D3DXPARAMETER_CLASS Class; // Class + D3DXPARAMETER_TYPE Type; // Component type + + UINT Rows; // Number of rows + UINT Columns; // Number of columns + UINT Elements; // Number of array elements + UINT StructMembers; // Number of structure member sub-parameters + + UINT Bytes; // Data size, in bytes + LPCVOID DefaultValue; // Pointer to default value + +} D3DXCONSTANT_DESC, *LPD3DXCONSTANT_DESC; + + + +//---------------------------------------------------------------------------- +// ID3DXConstantTable: +//---------------------------------------------------------------------------- + +typedef interface ID3DXConstantTable ID3DXConstantTable; +typedef interface ID3DXConstantTable *LPD3DXCONSTANTTABLE; + +// {AB3C758F-093E-4356-B762-4DB18F1B3A01} +DEFINE_GUID(IID_ID3DXConstantTable, +0xab3c758f, 0x93e, 0x4356, 0xb7, 0x62, 0x4d, 0xb1, 0x8f, 0x1b, 0x3a, 0x1); + + +#undef INTERFACE +#define INTERFACE ID3DXConstantTable + +DECLARE_INTERFACE_(ID3DXConstantTable, IUnknown) +{ + // IUnknown + STDMETHOD(QueryInterface)(THIS_ REFIID iid, LPVOID *ppv) PURE; + STDMETHOD_(ULONG, AddRef)(THIS) PURE; + STDMETHOD_(ULONG, Release)(THIS) PURE; + + // Buffer + STDMETHOD_(LPVOID, GetBufferPointer)(THIS) PURE; + STDMETHOD_(DWORD, GetBufferSize)(THIS) PURE; + + // Descs + STDMETHOD(GetDesc)(THIS_ D3DXCONSTANTTABLE_DESC *pDesc) PURE; + STDMETHOD(GetConstantDesc)(THIS_ D3DXHANDLE hConstant, D3DXCONSTANT_DESC *pConstantDesc, UINT *pCount) PURE; + STDMETHOD_(UINT, GetSamplerIndex)(THIS_ D3DXHANDLE hConstant) PURE; + + // Handle operation + STDMETHOD_(D3DXHANDLE, GetConstant)(THIS_ D3DXHANDLE hConstant, UINT Index) PURE; + STDMETHOD_(D3DXHANDLE, GetConstantByName)(THIS_ D3DXHANDLE hConstant, LPCSTR pName) PURE; + STDMETHOD_(D3DXHANDLE, GetConstantElement)(THIS_ D3DXHANDLE hConstant, UINT Index) PURE; + + // Set Constants + STDMETHOD(SetDefaults)(THIS_ LPDIRECT3DDEVICE9 pDevice) PURE; + STDMETHOD(SetValue)(THIS_ LPDIRECT3DDEVICE9 pDevice, D3DXHANDLE hConstant, LPCVOID pData, UINT Bytes) PURE; + STDMETHOD(SetBool)(THIS_ LPDIRECT3DDEVICE9 pDevice, D3DXHANDLE hConstant, BOOL b) PURE; + STDMETHOD(SetBoolArray)(THIS_ LPDIRECT3DDEVICE9 pDevice, D3DXHANDLE hConstant, CONST BOOL* pb, UINT Count) PURE; + STDMETHOD(SetInt)(THIS_ LPDIRECT3DDEVICE9 pDevice, D3DXHANDLE hConstant, INT n) PURE; + STDMETHOD(SetIntArray)(THIS_ LPDIRECT3DDEVICE9 pDevice, D3DXHANDLE hConstant, CONST INT* pn, UINT Count) PURE; + STDMETHOD(SetFloat)(THIS_ LPDIRECT3DDEVICE9 pDevice, D3DXHANDLE hConstant, FLOAT f) PURE; + STDMETHOD(SetFloatArray)(THIS_ LPDIRECT3DDEVICE9 pDevice, D3DXHANDLE hConstant, CONST FLOAT* pf, UINT Count) PURE; + STDMETHOD(SetVector)(THIS_ LPDIRECT3DDEVICE9 pDevice, D3DXHANDLE hConstant, CONST LPVOID pVector) PURE; + STDMETHOD(SetVectorArray)(THIS_ LPDIRECT3DDEVICE9 pDevice, D3DXHANDLE hConstant, CONST LPVOID pVector, UINT Count) PURE; + STDMETHOD(SetMatrix)(THIS_ LPDIRECT3DDEVICE9 pDevice, D3DXHANDLE hConstant, CONST LPVOID pMatrix) PURE; + STDMETHOD(SetMatrixArray)(THIS_ LPDIRECT3DDEVICE9 pDevice, D3DXHANDLE hConstant, CONST LPVOID pMatrix, UINT Count) PURE; + STDMETHOD(SetMatrixPointerArray)(THIS_ LPDIRECT3DDEVICE9 pDevice, D3DXHANDLE hConstant, CONST LPVOID* ppMatrix, UINT Count) PURE; + STDMETHOD(SetMatrixTranspose)(THIS_ LPDIRECT3DDEVICE9 pDevice, D3DXHANDLE hConstant, CONST LPVOID pMatrix) PURE; + STDMETHOD(SetMatrixTransposeArray)(THIS_ LPDIRECT3DDEVICE9 pDevice, D3DXHANDLE hConstant, CONST LPVOID pMatrix, UINT Count) PURE; + STDMETHOD(SetMatrixTransposePointerArray)(THIS_ LPDIRECT3DDEVICE9 pDevice, D3DXHANDLE hConstant, CONST LPVOID* ppMatrix, UINT Count) PURE; +}; + namespace tzf { namespace RenderFix @@ -40,6 +345,10 @@ namespace tzf void Reset ( IDirect3DDevice9 *This, D3DPRESENT_PARAMETERS *pPresentationParameters ); + void TriggerReset (void); + + bool InstallSGSSAA (void); + struct tzf_reset_state_s { bool graphics = false; @@ -68,6 +377,116 @@ namespace tzf static CommandProcessor* pCommProc; }; + struct frame_state_s + { + void clear (void) { pixel_shaders.clear (); vertex_shaders.clear (); vertex_buffers.clear (); } + + std::unordered_set pixel_shaders; + std::unordered_set vertex_shaders; + std::unordered_set vertex_buffers; // TODO: Hash the data and assign a more useful identifier + } extern last_frame; + + struct render_target_class_s + { + struct shadow_s + { + struct resolution_s + { + const UINT Low, Med, High; // Low Medium High + } const None { 0, 0, 0 }, //------------------------------ + Character { 64, 128, 256 }, // 64x64, 128x128, 256x256 + Environment { 512, 1024, 2048 }; // 512x512, 1024x1024, 2048x2048 + + const resolution_s* type = &None; + } shadow; + + struct { + enum { + None = 0x0, + DepthOfField = 0x1, + Bloom = 0x2, + Reflection = 0x4, + Map = 0x8 + } type = None; + } postproc; + }; + + struct render_target_tracking_s + { + void clear (void) { pixel_shaders.clear (); vertex_shaders.clear (); active = false; } + + IDirect3DBaseTexture9* tracking_tex = nullptr; + + std::unordered_set pixel_shaders; + std::unordered_set vertex_shaders; + + bool active = false; + } extern tracked_rt; + + struct shader_tracking_s + { + void clear (void) { + active = false; + num_draws = 0; + used_textures.clear (); + + for (int i = 0; i < 16; i++) + current_textures [i] = 0x00; + } + + void use (IUnknown* pShader); + + uint32_t crc32 = 0x00; + bool cancel_draws = false; + bool clamp_coords = false; + bool active = false; + int num_draws = 0; + std::unordered_set used_textures; + uint32_t current_textures [16]; + + //std::vector samplers; + + IUnknown* shader_obj = nullptr; + ID3DXConstantTable* ctable = nullptr; + + struct shader_constant_s + { + char Name [128]; + D3DXREGISTER_SET RegisterSet; + UINT RegisterIndex; + UINT RegisterCount; + D3DXPARAMETER_CLASS Class; + D3DXPARAMETER_TYPE Type; + UINT Rows; + UINT Columns; + UINT Elements; + std::vector + struct_members; + bool Override; + float Data [4]; // TEMP HACK + }; + + std::vector constants; + } extern tracked_vs, tracked_ps; + + struct vertex_buffer_tracking_s + { + void clear (void) { active = false; num_draws = 0; } + + IDirect3DVertexBuffer9* vertex_buffer = nullptr; + //uint32_t crc32 = 0x00; + bool cancel_draws = false; + bool wireframe = false; + bool active = false; + int num_draws = 0; + } extern tracked_vb; + + struct shader_disasm_s { + std::string header; + std::string code; + std::string footer; + }; + extern uint32_t width; extern uint32_t height; @@ -184,6 +603,35 @@ typedef HRESULT (STDMETHODCALLTYPE *EndScene_pfn)( #include +typedef interface ID3DXBuffer ID3DXBuffer; +typedef interface ID3DXBuffer *LPD3DXBUFFER; + +// {8BA5FB08-5195-40e2-AC58-0D989C3A0102} +DEFINE_GUID(IID_ID3DXBuffer, +0x8ba5fb08, 0x5195, 0x40e2, 0xac, 0x58, 0xd, 0x98, 0x9c, 0x3a, 0x1, 0x2); + +#undef INTERFACE +#define INTERFACE ID3DXBuffer + +DECLARE_INTERFACE_(ID3DXBuffer, IUnknown) +{ + // IUnknown + STDMETHOD ( QueryInterface) (THIS_ REFIID iid, LPVOID *ppv) PURE; + STDMETHOD_ (ULONG, AddRef) (THIS) PURE; + STDMETHOD_ (ULONG, Release) (THIS) PURE; + + // ID3DXBuffer + STDMETHOD_ (LPVOID, GetBufferPointer) (THIS) PURE; + STDMETHOD_ (DWORD, GetBufferSize) (THIS) PURE; +}; + + +typedef D3DPRESENT_PARAMETERS* (__stdcall *SK_SetPresentParamsD3D9_pfn) +( + IDirect3DDevice9 *pDevice, + D3DPRESENT_PARAMETERS *pParams +); + typedef HRESULT (STDMETHODCALLTYPE *DrawPrimitive_pfn) ( IDirect3DDevice9 *This, @@ -225,6 +673,109 @@ typedef HRESULT (STDMETHODCALLTYPE *DrawIndexedPrimitiveUP_pfn) UINT VertexStreamZeroStride ); +typedef HRESULT (STDMETHODCALLTYPE *SetStreamSource_pfn) +( + IDirect3DDevice9 *This, + UINT StreamNumber, + IDirect3DVertexBuffer9 *pStreamData, + UINT OffsetInBytes, + UINT Stride +); + +typedef BOOL (__stdcall *SKX_DrawExternalOSD_pfn) +( _In_ const char* szAppName, + _In_ const char* szText +); + +typedef HRESULT (STDMETHODCALLTYPE *SetRenderState_pfn) +( _In_ IDirect3DDevice9* This, + _In_ D3DRENDERSTATETYPE State, + _In_ DWORD Value +); + +typedef HRESULT (STDMETHODCALLTYPE *TestCooperativeLevel_pfn) +( _In_ IDirect3DDevice9* This +); + +typedef void (STDMETHODCALLTYPE *SK_BeginBufferSwap_pfn) +( +); + +typedef HRESULT (STDMETHODCALLTYPE *SK_EndBufferSwap_pfn) +( _In_ HRESULT hr, + _Inout_ IUnknown* device +); + +typedef HRESULT (STDMETHODCALLTYPE *SetScissorRect_pfn) +( _In_ IDirect3DDevice9* This, + _In_ const RECT* pRect +); + +typedef HRESULT (STDMETHODCALLTYPE *EndScene_pfn) +( _In_ IDirect3DDevice9* This +); + +typedef HRESULT (STDMETHODCALLTYPE *SetSamplerState_pfn) +( _In_ IDirect3DDevice9* This, + _In_ DWORD Sampler, + _In_ D3DSAMPLERSTATETYPE Type, + _In_ DWORD Value +); + +typedef HRESULT (STDMETHODCALLTYPE *SetVertexShader_pfn) +( _In_ IDirect3DDevice9* This, + _In_opt_ IDirect3DVertexShader9* pShader +); + +typedef HRESULT (STDMETHODCALLTYPE *SetPixelShader_pfn) +( _In_ IDirect3DDevice9* This, + _In_opt_ IDirect3DPixelShader9* pShader +); + +typedef HRESULT (STDMETHODCALLTYPE *UpdateSurface_pfn) +( _In_ IDirect3DDevice9 *This, + _In_ IDirect3DSurface9 *pSourceSurface, + _In_ const RECT *pSourceRect, + _In_ IDirect3DSurface9 *pDestinationSurface, + _In_ const POINT *pDestinationPoint +); + +typedef HRESULT (STDMETHODCALLTYPE *SetViewport_pfn) +( _In_ IDirect3DDevice9* This, + _In_ CONST D3DVIEWPORT9* pViewport +); + +typedef HRESULT (STDMETHODCALLTYPE *SetVertexShaderConstantF_pfn) +( _In_ IDirect3DDevice9* This, + _In_ UINT StartRegister, + _In_ CONST float* pConstantData, + _In_ UINT Vector4fCount +); + +typedef HRESULT (STDMETHODCALLTYPE *SetPixelShaderConstantF_pfn) +( _In_ IDirect3DDevice9* This, + _In_ UINT StartRegister, + _In_ CONST float* pConstantData, + _In_ UINT Vector4fCount +); + +typedef HRESULT (WINAPI *D3DXGetShaderConstantTable_pfn) +( _In_ const DWORD *pFunction, + _Out_ LPD3DXCONSTANTTABLE *ppConstantTable +); + +typedef HRESULT (WINAPI *D3DXDisassembleShader_pfn) +( _In_ const DWORD *pShader, + _In_ BOOL EnableColorCode, + _In_ LPCSTR pComments, + _Out_ LPD3DXBUFFER *ppDisassembly +); + +typedef HRESULT (__stdcall *Reset_pfn) +( _In_ IDirect3DDevice9 *This, + _Inout_ D3DPRESENT_PARAMETERS *pPresentationParameters +); + #endif /* __TZF__RENDER_H__ */ \ No newline at end of file diff --git a/tzf_dsound/textures.cpp b/tzf_dsound/textures.cpp index 6b1f679..dde970e 100644 --- a/tzf_dsound/textures.cpp +++ b/tzf_dsound/textures.cpp @@ -90,6 +90,9 @@ extern QueryPerformanceCounter_t QueryPerformanceCounter_Original; tzf::RenderFix::TextureManager tzf::RenderFix::tex_mgr; +extern uint32_t vs_checksum; +extern uint32_t ps_checksum; + iSK_Logger* tex_log = nullptr; #include @@ -117,6 +120,76 @@ void TZFix_LoadQueuedTextures (void); #include #include +// Cleanup +std::queue screenshots_to_delete; + +class TBF_AutoCritSection +{ +public: + TBF_AutoCritSection (CRITICAL_SECTION* crit_sec) : cs_ (crit_sec) { + EnterCriticalSection (cs_); + }; + + ~TBF_AutoCritSection (void) { + LeaveCriticalSection (cs_); + } + +private: + CRITICAL_SECTION* cs_; +}; + + +template +class TBF_HashSet +{ +public: + TBF_HashSet (void) { + InitializeCriticalSection (&cs_); + } + + ~TBF_HashSet (void) { + DeleteCriticalSection (&cs_); + } + + void emplace (_T item) + { + TBF_AutoCritSection auto_crit (&cs_); + + container_.emplace (item); + } + + void erase (_T item) + { + TBF_AutoCritSection auto_crit (&cs_); + + container_.erase (item); + } + + bool contains (_T item) + { + TBF_AutoCritSection auto_crit (&cs_); + + return container_.count (item) != 0; + } + + bool empty (void) + { + TBF_AutoCritSection auto_crit (&cs_); + + return container_.empty (); + } + +protected: +private: + std::unordered_set <_T> container_; + CRITICAL_SECTION cs_; +}; + + +TBF_HashSet outstanding_screenshots; // Not excellent screenshots, but screenhots + // that aren't finished yet and we can't reset + // the D3D9 device because of. + std::unordered_map injectable_textures; std::vector archives; std::unordered_set dumped_textures; @@ -151,7 +224,7 @@ TZF_GetInjectableTexture (uint32_t checksum) // The set of textures used during the last frame std::vector textures_last_frame; -std::set textures_used; +std::unordered_set textures_used; std::unordered_set non_power_of_two_textures; // Textures that we will not allow injection for @@ -582,6 +655,53 @@ tzf::RenderFix::TextureManager::cacheSizeTotal (void) return cacheSizeBasic () + cacheSizeInjected (); } +bool +tzf::RenderFix::TextureManager::isRenderTarget (IDirect3DBaseTexture9* pTex) +{ + return known.render_targets.count (pTex) != 0; +} + +void +tzf::RenderFix::TextureManager::trackRenderTarget (IDirect3DBaseTexture9* pTex) +{ + if (! known.render_targets.count (pTex)) + known.render_targets.try_emplace (pTex, (uint32_t)known.render_targets.size ()); +} + +void +tzf::RenderFix::TextureManager::applyTexture (IDirect3DBaseTexture9* pTex) +{ + if (known.render_targets.count (pTex) != 0) + used.render_targets.emplace (pTex); +} + +bool +tzf::RenderFix::TextureManager::isUsedRenderTarget (IDirect3DBaseTexture9* pTex) +{ + return used.render_targets.count (pTex) != 0; +} + +void +tzf::RenderFix::TextureManager::resetUsedTextures (void) +{ + used.render_targets.clear (); +} + +std::vector +tzf::RenderFix::TextureManager::getUsedRenderTargets (void) +{ + return std::vector (used.render_targets.begin (), used.render_targets.end ()); +} + +uint32_t +tzf::RenderFix::TextureManager::getRenderTargetCreationTime (IDirect3DBaseTexture9* pTex) +{ + if (known.render_targets.count (pTex)) + return known.render_targets [pTex]; + + return 0xFFFFFFFFUL; +} + #include "render.h" COM_DECLSPEC_NOTHROW @@ -623,8 +743,10 @@ D3D9SetDepthStencilSurface_Detour ( } -uint32_t debug_tex_id = 0UL; -uint32_t current_tex = 0ui32; +uint32_t debug_tex_id = 0UL; +uint32_t current_tex [256] = { 0ui32 }; + +extern SetSamplerState_pfn D3D9SetSamplerState_Original; COM_DECLSPEC_NOTHROW HRESULT @@ -657,18 +779,36 @@ D3D9SetTexture_Detour ( //Sampler, pTexture ); //} + + tzf::RenderFix::tex_mgr.applyTexture (pTexture); + tzf::RenderFix::tracked_rt.active = (pTexture == tzf::RenderFix::tracked_rt.tracking_tex); + + if (tzf::RenderFix::tracked_rt.active) + { + tzf::RenderFix::tracked_rt.vertex_shaders.emplace (vs_checksum); + tzf::RenderFix::tracked_rt.pixel_shaders.emplace (ps_checksum); + } + + + uint32_t tex_crc32 = 0x0; + void* dontcare; if ( pTexture != nullptr && pTexture->QueryInterface (IID_SKTextureD3D9, &dontcare) == S_OK ) { ISKTextureD3D9* pSKTex = (ISKTextureD3D9 *)pTexture; - current_tex = pSKTex->tex_crc32; + current_tex [std::min (255UL, Sampler)] = pSKTex->tex_crc32; - textures_used.insert (pSKTex->tex_crc32); + if (vs_checksum == tzf::RenderFix::tracked_vs.crc32) tzf::RenderFix::tracked_vs.current_textures [std::min (15UL, Sampler)] = pSKTex->tex_crc32; + if (ps_checksum == tzf::RenderFix::tracked_ps.crc32) tzf::RenderFix::tracked_ps.current_textures [std::min (15UL, Sampler)] = pSKTex->tex_crc32; + + textures_used.emplace (pSKTex->tex_crc32); QueryPerformanceCounter_Original (&pSKTex->last_used); + tex_crc32 = pSKTex->tex_crc32; + // // This is how blocking is implemented -- only do it when a texture that needs // this feature is being applied. @@ -696,6 +836,25 @@ D3D9SetTexture_Detour ( else tsf::RenderFix::active_samplers.erase (Sampler); #endif + bool clamp = false; + + if (ps_checksum == tzf::RenderFix::tracked_ps.crc32 && tzf::RenderFix::tracked_ps.clamp_coords) + clamp = true; + + if (vs_checksum == tzf::RenderFix::tracked_vs.crc32 && tzf::RenderFix::tracked_vs.clamp_coords) + clamp = true; + + if ( clamp ) + { + float fMin = -3.0f; + + D3D9SetSamplerState_Original (This, Sampler, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP ); + D3D9SetSamplerState_Original (This, Sampler, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP ); + D3D9SetSamplerState_Original (This, Sampler, D3DSAMP_ADDRESSW, D3DTADDRESS_CLAMP ); + D3D9SetSamplerState_Original (This, Sampler, D3DSAMP_MIPMAPLODBIAS, *reinterpret_cast (&fMin) ); + } + + return D3D9SetTexture_Original (This, Sampler, pTexture); } @@ -796,6 +955,14 @@ D3D9CreateTexture_Detour (IDirect3DDevice9 *This, D3D9CreateTexture_Original (This, Width, Height, levels, Usage, Format, Pool, ppTexture, pSharedHandle); + if ( SUCCEEDED (result) && + ( ( Usage & D3DUSAGE_RENDERTARGET ) || + ( Usage & D3DUSAGE_DEPTHSTENCIL ) || + ( Usage & D3DUSAGE_DYNAMIC ) ) ) + { + tzf::RenderFix::tex_mgr.trackRenderTarget (*ppTexture); + } + return result; } @@ -1108,6 +1275,39 @@ friend class SK_TextureThreadPool; SetEvent (control_.shutdown); } + size_t bytesLoaded(void) { + return InterlockedExchangeAdd (&bytes_loaded_, 0ULL); + } + + int jobsRetired (void) { + return InterlockedExchangeAdd (&jobs_retired_, 0L); + } + + FILETIME idleTime (void) { + GetThreadTimes ( thread_, + &runtime_.start, &runtime_.end, + &runtime_.kernel, &runtime_.user ); + + FILETIME now; + GetSystemTimeAsFileTime (&now); + + ULONGLONG elapsed = + ULARGE_INTEGER { now.dwLowDateTime, now.dwHighDateTime }.QuadPart - + ULARGE_INTEGER { runtime_.start.dwLowDateTime, runtime_.start.dwHighDateTime }.QuadPart; + + ULONGLONG busy = + ULARGE_INTEGER { runtime_.kernel.dwLowDateTime, runtime_.kernel.dwHighDateTime }.QuadPart + + ULARGE_INTEGER { runtime_.user.dwLowDateTime, runtime_.user.dwHighDateTime }.QuadPart; + + ULARGE_INTEGER idle; + idle.QuadPart = elapsed - busy; + + return FILETIME { idle.LowPart, + idle.HighPart }; + } + FILETIME userTime (void) { return runtime_.user; }; + FILETIME kernelTime (void) { return runtime_.kernel; }; + protected: static CRITICAL_SECTION cs_worker_init; static ULONG num_threads_init; @@ -1121,6 +1321,15 @@ friend class SK_TextureThreadPool; tzf_tex_load_s* job_; + volatile ULONGLONG bytes_loaded_ = 0ULL; + volatile LONG jobs_retired_ = 0L; + + struct { + FILETIME start, end; + FILETIME user, kernel; + FILETIME idle; // Computed: (now - start) - (user + kernel) + } runtime_ { 0, 0, 0, 0, 0 }; + struct { union { struct { @@ -1253,6 +1462,26 @@ friend class SK_TextureWorkerThread; SetEvent (events_.shutdown); } + std::vector getWorkerStats (void) + { + std::vector stats; + + for ( auto it : workers_ ) + { + tzf_tex_thread_stats_s stat; + + stat.bytes_loaded = it->bytesLoaded (); + stat.jobs_retired = it->jobsRetired (); + stat.runtime.idle = it->idleTime (); + stat.runtime.kernel = it->kernelTime (); + stat.runtime.user = it->userTime (); + + stats.push_back (stat); + } + + return stats; + } + protected: static unsigned int __stdcall Spooler (LPVOID user); @@ -1369,7 +1598,7 @@ struct SK_StreamSplitter std::queue textures_to_stream; -std::map +std::unordered_map textures_in_flight; std::queue finished_loads; @@ -1849,7 +2078,7 @@ TZFix_LoadQueuedTextures (void) QueryPerformanceCounter_Original (&load->end); - if (true) + if (false) { tex_log->Log ( L"[%s] Finished %s texture %08x (%5.2f MiB in %9.4f ms)", (load->type == tzf_tex_load_s::Stream) ? L"Inject Tex" : @@ -1916,7 +2145,7 @@ TZFix_LoadQueuedTextures (void) QueryPerformanceCounter_Original (&load->end); - if (true) + if (false) { tex_log->Log ( L"[%s] Finished %s texture %08x (%5.2f MiB in %9.4f ms)", (load->type == tzf_tex_load_s::Stream) ? L"Inject Tex" : @@ -2630,6 +2859,8 @@ tzf::RenderFix::TextureManager::removeTexture (ISKTextureD3D9* pTexD3D9) remove_textures.push_back (pTexD3D9); LeaveCriticalSection (&cs_cache); + + updateOSD (); } void @@ -2730,8 +2961,20 @@ D3D9SetRenderTarget_Detour ( void tzf::RenderFix::TextureManager::Init (void) { - InitializeCriticalSectionAndSpinCount (&cs_cache, 16384UL); - InitializeCriticalSectionAndSpinCount (&osd_cs, 2UL); + textures.reserve (4096); + textures_used.reserve (2048); + textures_last_frame.reserve (1024); + non_power_of_two_textures.reserve (512); + tracked_ps.used_textures.reserve (256); + tracked_vs.used_textures.reserve (256); + known.render_targets.reserve (64); + used.render_targets.reserve (64); + textures_in_flight.reserve (32); + tracked_rt.pixel_shaders.reserve (32); + tracked_rt.vertex_shaders.reserve (32); + + InitializeCriticalSectionAndSpinCount (&cs_cache, 8192UL); + InitializeCriticalSectionAndSpinCount (&osd_cs, 32UL); // Create the directory to store dumped textures if (config.textures.dump) @@ -2797,6 +3040,52 @@ tzf::RenderFix::TextureManager::Init (void) files, (double)liSize.QuadPart / (1024.0 * 1024.0) ); } + InterlockedExchange64 (&bytes_saved, 0LL); + + time_saved = 0.0f; + + InitializeCriticalSectionAndSpinCount (&cs_tex_inject, 10000000); + InitializeCriticalSectionAndSpinCount (&cs_tex_resample, 100000); + InitializeCriticalSectionAndSpinCount (&cs_tex_stream, 100000); + + decomp_semaphore = + CreateSemaphore ( nullptr, + config.textures.worker_threads, + config.textures.worker_threads, + nullptr ); + + resample_pool = new SK_TextureThreadPool (); + + stream_pool.lrg_tex = new SK_TextureThreadPool (); + stream_pool.sm_tex = new SK_TextureThreadPool (); + + SK_ICommandProcessor& command = + *SK_GetCommandProcessor (); + + command.AddVariable ( + "Textures.Remap", + TZF_CreateVar (SK_IVariable::Boolean, &__remap_textures) ); + + command.AddVariable ( + "Textures.Purge", + TZF_CreateVar (SK_IVariable::Boolean, &__need_purge) ); + + command.AddVariable ( + "Textures.Trace", + TZF_CreateVar (SK_IVariable::Boolean, &__log_used) ); + + command.AddVariable ( + "Textures.ShowCache", + TZF_CreateVar (SK_IVariable::Boolean, &__show_cache) ); + + command.AddVariable ( + "Textures.MaxCacheSize", + TZF_CreateVar (SK_IVariable::Int, &config.textures.max_cache_in_mib) ); +} + +void +tzf::RenderFix::TextureManager::Hook (void) +{ TZF_CreateDLLHook2 ( config.system.injector.c_str (), "D3D9SetRenderState_Override", D3D9SetRenderState_Detour, @@ -2812,6 +3101,11 @@ tzf::RenderFix::TextureManager::Init (void) D3D9StretchRect_Detour, (LPVOID*)&D3D9StretchRect_Original ); + TZF_CreateDLLHook2 ( config.system.injector.c_str (), + "D3D9CreateRenderTarget_Override", + D3D9CreateRenderTarget_Detour, + (LPVOID*)&D3D9CreateRenderTarget_Original ); + TZF_CreateDLLHook2 ( config.system.injector.c_str (), "D3D9CreateDepthStencilSurface_Override", D3D9CreateDepthStencilSurface_Detour, @@ -2849,6 +3143,11 @@ tzf::RenderFix::TextureManager::Init (void) GetProcAddress ( tzf::RenderFix::d3dx9_43_dll, "D3DXSaveTextureToFileW" ); + D3DXSaveSurfaceToFileW = + (D3DXSaveSurfaceToFile_pfn) + GetProcAddress ( tzf::RenderFix::d3dx9_43_dll, + "D3DXSaveSurfaceToFileW" ); + D3DXCreateTextureFromFile = (D3DXCreateTextureFromFile_pfn) GetProcAddress ( tzf::RenderFix::d3dx9_43_dll, @@ -2868,66 +3167,6 @@ tzf::RenderFix::TextureManager::Init (void) (D3DXGetImageInfoFromFile_pfn) GetProcAddress ( tzf::RenderFix::d3dx9_43_dll, "D3DXGetImageInfoFromFileW" ); - - // We don't hook this, but we still use it... - if (D3D9CreateRenderTarget_Original == nullptr) { - static HMODULE hModD3D9 = - GetModuleHandle (config.system.injector.c_str ()); - D3D9CreateRenderTarget_Original = - (CreateRenderTarget_pfn) - GetProcAddress (hModD3D9, "D3D9CreateRenderTarget_Override"); - } - - // We don't hook this, but we still use it... - if (D3D9CreateDepthStencilSurface_Original == nullptr) { - static HMODULE hModD3D9 = - GetModuleHandle (config.system.injector.c_str ()); - D3D9CreateDepthStencilSurface_Original = - (CreateDepthStencilSurface_pfn) - GetProcAddress (hModD3D9, "D3D9CreateDepthStencilSurface_Override"); - } - - InterlockedExchange64 (&bytes_saved, 0LL); - - time_saved = 0.0f; - - InitializeCriticalSectionAndSpinCount (&cs_tex_inject, 10000000); - InitializeCriticalSectionAndSpinCount (&cs_tex_resample, 100000); - InitializeCriticalSectionAndSpinCount (&cs_tex_stream, 100000); - - decomp_semaphore = - CreateSemaphore ( nullptr, - config.textures.worker_threads, - config.textures.worker_threads, - nullptr ); - - resample_pool = new SK_TextureThreadPool (); - - stream_pool.lrg_tex = new SK_TextureThreadPool (); - stream_pool.sm_tex = new SK_TextureThreadPool (); - - SK_ICommandProcessor& command = - *SK_GetCommandProcessor (); - - command.AddVariable ( - "Textures.Remap", - TZF_CreateVar (SK_IVariable::Boolean, &__remap_textures) ); - - command.AddVariable ( - "Textures.Purge", - TZF_CreateVar (SK_IVariable::Boolean, &__need_purge) ); - - command.AddVariable ( - "Textures.Trace", - TZF_CreateVar (SK_IVariable::Boolean, &__log_used) ); - - command.AddVariable ( - "Textures.ShowCache", - TZF_CreateVar (SK_IVariable::Boolean, &__show_cache) ); - - command.AddVariable ( - "Textures.MaxCacheSize", - TZF_CreateVar (SK_IVariable::Int, &config.textures.max_cache_in_mib) ); } // Skip the purge step on shutdown @@ -2967,6 +3206,14 @@ tzf::RenderFix::TextureManager::Shutdown (void) time_saved / frame_time ); tex_log->close (); + while (! screenshots_to_delete.empty ()) + { + std::wstring file_to_delete = screenshots_to_delete.front (); + screenshots_to_delete.pop (); + + DeleteFileW (file_to_delete.c_str ()); + } + FreeLibrary (d3dx9_43_dll); } @@ -3088,6 +3335,19 @@ tzf::RenderFix::TextureManager::purge (void) void tzf::RenderFix::TextureManager::reset (void) { + if (! outstanding_screenshots.empty ()) + { + tex_log->LogEx (true, L"[Screenshot] A queued screenshot has not finished, delaying device reset..."); + + while (! outstanding_screenshots.empty ()) + ; + + tex_log->LogEx (false, L"done!\n"); + } + + known.render_targets.clear (); + + int underflows = 0; int ext_refs = 0; @@ -3580,7 +3840,11 @@ SK_TextureThreadPool::Spooler (LPVOID user) void SK_TextureWorkerThread::finishJob (void) { - job_ = nullptr; + InterlockedExchangeAdd (&bytes_loaded_, + ((tzf_tex_load_s *)InterlockedCompareExchangePointer ((PVOID *)&job_, nullptr, nullptr)) + ->SrcDataSize); + InterlockedIncrement (&jobs_retired_); + InterlockedExchangePointer ((PVOID *)&job_, nullptr); } HMODULE tzf::RenderFix::d3dx9_43_dll = 0; @@ -3970,4 +4234,17 @@ tzf::RenderFix::TextureManager::reloadTexture (uint32_t checksum) TZFix_LoadQueuedTextures (); return true; +} + + + +std::vector +tzf::RenderFix::TextureManager::getThreadStats (void) +{ + std::vector stats = + resample_pool->getWorkerStats (); + + // For Inject (Small, Large) -> Push Back + + return stats; } \ No newline at end of file diff --git a/tzf_dsound/textures.h b/tzf_dsound/textures.h index d9b541c..b0848e8 100644 --- a/tzf_dsound/textures.h +++ b/tzf_dsound/textures.h @@ -64,6 +64,18 @@ typedef struct D3DXIMAGE_INFO { } D3DXIMAGE_INFO, *LPD3DXIMAGE_INFO; +struct tzf_tex_thread_stats_s { + ULONGLONG bytes_loaded; + LONG jobs_retired; + + struct { + FILETIME start, end; + FILETIME user, kernel; + FILETIME idle; // Computed: (now - start) - (user + kernel) + } runtime; +}; + + namespace tzf { namespace RenderFix { #if 0 @@ -141,6 +153,7 @@ namespace RenderFix { class TextureManager { public: void Init (void); + void Hook (void); void Shutdown (void); void removeTexture (ISKTextureD3D9* pTexD3D9); @@ -187,6 +200,25 @@ namespace RenderFix { ULONG getMissCount (void) { return InterlockedExchangeAdd (&misses, 0UL); } + void resetUsedTextures (void); + void applyTexture (IDirect3DBaseTexture9* tex); + + std::vector + getUsedRenderTargets (void); + uint32_t getRenderTargetCreationTime + (IDirect3DBaseTexture9* rt); + void trackRenderTarget (IDirect3DBaseTexture9* rt); + bool isRenderTarget (IDirect3DBaseTexture9* rt); + bool isUsedRenderTarget (IDirect3DBaseTexture9* rt); + + void queueScreenshot (wchar_t* wszFileName, bool hudless = true); + bool wantsScreenshot (void); + HRESULT takeScreenshot (IDirect3DSurface9* pSurf); + + std::vector + getThreadStats (void); + + BOOL isTexturePowerOfTwo (UINT sampler) { @@ -203,18 +235,29 @@ namespace RenderFix { private: + struct { + // In lieu of actually wrapping render targets with a COM interface, just add the creation time + // as the mapped parameter + std::unordered_map render_targets; + } known; + + struct { + std::unordered_set render_targets; + } used; + std::unordered_map textures; - float time_saved = 0.0f; - LONG64 bytes_saved = 0LL; + float time_saved = 0.0f; + LONG64 bytes_saved = 0LL; - ULONG hits = 0UL; - ULONG misses = 0UL; + ULONG hits = 0UL; + ULONG misses = 0UL; - LONG64 basic_size = 0LL; - LONG64 injected_size = 0LL; - ULONG injected_count = 0UL; + LONG64 basic_size = 0LL; + LONG64 injected_size = 0LL; + ULONG injected_count = 0UL; - std::string osd_stats = ""; + std::string osd_stats = ""; + bool want_screenshot = false; CRITICAL_SECTION cs_cache; } extern tex_mgr; diff --git a/version.ini b/version.ini index 58b3219a32ee83455ef9f07b827f878cbed104f7..573415c4561152a401b5817e9436fc584e11f1bb 100644 GIT binary patch delta 295 zcmbOu_d{+%0i*H6!kOuw47m&i3`Gq23}p3?V?ef}w<=6eyYs@90zdZv delta 383 zcmZ9I%}T>i5QR^oP#-}MO7^vAT2OG|B7)#Xq*icgnxq%xWKy=EaUX6~6YbI(0#2H)IxL6SbJgm7mE24eQ%z8bG(#bTjk&jLXMQz|$_cZj?m<1`Qg`S~NA_t$1g$`Yu#rmOmOSAR zIaLNq$$j0@pWA*!FT-#O=UFaO-4xEV<2RqqVP}8|UxTLaKACNM&4)XR#&|S4&&bC4 zf6*(Q!G;K%Zb**X$qQT$;r57YHeT=#Lmg