diff --git a/include/DLL_VERSION.H b/include/DLL_VERSION.H index f6c1138..bf257ba 100644 --- a/include/DLL_VERSION.H +++ b/include/DLL_VERSION.H @@ -3,8 +3,8 @@ #define TBF_MAJOR 0 #define TBF_MINOR 9 -#define TBF_BUILD 4 -#define TBF_REV 1 +#define TBF_BUILD 5 +#define TBF_REV 0 diff --git a/src/ImGui/control_panel.cpp b/src/ImGui/control_panel.cpp index 89cc8c9..b18ceb6 100644 --- a/src/ImGui/control_panel.cpp +++ b/src/ImGui/control_panel.cpp @@ -284,9 +284,9 @@ TBFix_KeybindDialog (keybind_s* keybind) //memcpy (bind_keys, active_keys, keys); } - keybind->ctrl = (GetAsyncKeyState (VK_CONTROL) & 0x8000) != 0; - keybind->shift = (GetAsyncKeyState (VK_SHIFT) & 0x8000) != 0; - keybind->alt = (GetAsyncKeyState (VK_MENU) & 0x8000) != 0; + keybind->ctrl = (GetAsyncKeyState (VK_CONTROL) & 0x8000) != 0; + keybind->shift = (GetAsyncKeyState (VK_SHIFT) & 0x8000) != 0; + keybind->alt = (GetAsyncKeyState (VK_MENU) & 0x8000) != 0; keybind->update (); diff --git a/src/ImGui/mod_tools.cpp b/src/ImGui/mod_tools.cpp index 90e86ba..520d4e7 100644 --- a/src/ImGui/mod_tools.cpp +++ b/src/ImGui/mod_tools.cpp @@ -363,6 +363,13 @@ TBFix_TextureModDlg (void) 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] = { }; @@ -444,19 +451,39 @@ TBFix_TextureModDlg (void) tbf::RenderFix::Texture* pTex = tbf::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)); + 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); + + 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; @@ -464,9 +491,11 @@ TBFix_TextureModDlg (void) SK_D3D9_FormatToStr (D3DFORMAT Format, bool include_ordinal = true); - ImGui::Text ( "Dimensions: %lux%lu", - desc.Width, desc.Height/*, - pTex->d3d9_tex->GetLevelCount ()*/ ); + int num_lods = pTex->d3d9_tex->pTex->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", @@ -480,8 +509,12 @@ TBFix_TextureModDlg (void) { if ( ImGui::Button ("Dump Texture to Disk") ) { - TBF_DumpTexture (desc.Format, debug_tex_id, pTex->d3d9_tex->pTex); + if (! config.textures.quick_load) + TBF_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 @@ -501,11 +534,12 @@ TBFix_TextureModDlg (void) ); ImGui::EndChildFrame (); ImGui::EndChild (); + ImGui::EndGroup (); ImGui::PopStyleColor (2); } } - if (pTex != nullptr && pTex->d3d9_tex->pTexOverride != nullptr) + if (has_alternate) { ImGui::SameLine (); @@ -513,13 +547,35 @@ TBFix_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 (font_size * 19.0f, (float)desc.Width + 24.0f), - (float)desc.Height + font_size * 10.0f), + 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); @@ -528,10 +584,11 @@ TBFix_TextureModDlg (void) (TBF_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", @@ -569,6 +626,7 @@ TBFix_TextureModDlg (void) } ImGui::EndChild (); + ImGui::EndGroup (); ImGui::PopStyleColor (1); } } @@ -586,17 +644,31 @@ TBFix_TextureModDlg (void) static std::vector list_contents; static bool list_dirty = true; static uintptr_t last_sel_ptr = 0; - static int sel = 0; + static int sel = -1; std::vector render_textures = tbf::RenderFix::tex_mgr.getUsedRenderTargets (); + tbf::RenderFix::tracked_rt.tracking_tex = 0; + if (list_dirty) { - sel = 0; - int idx = 0; + 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] = { }; @@ -605,8 +677,10 @@ TBFix_TextureModDlg (void) list_contents.push_back (szDesc); - if ((uintptr_t)it == last_sel_ptr) + if ((uintptr_t)it == last_sel_ptr) { sel = idx; + tbf::RenderFix::tracked_rt.tracking_tex = render_textures [sel]; + } ++idx; } @@ -677,7 +751,7 @@ TBFix_TextureModDlg (void) CComPtr pTex = nullptr; - if (render_textures.size ()) + if (render_textures.size () && sel >= 0) render_textures [sel]->QueryInterface (IID_PPV_ARGS (&pTex)); if (pTex != nullptr) @@ -689,17 +763,21 @@ TBFix_TextureModDlg (void) size_t shaders = std::max ( tbf::RenderFix::tracked_rt.pixel_shaders.size (), tbf::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 (128.0f, (float)desc.Width / 2.0f + 24.0f), - std::max (256.0f, (float)desc.Height / 2.0f) + 64.0f + (float)shaders * 19.0f), + ImVec2 ( std::max (128.0f, effective_width + 24.0f), + std::max (256.0f, effective_height + font_size * 4.0f + (float)shaders * font_size) ), true, ImGuiWindowFlags_AlwaysAutoResize ); - last_width = (float)desc.Width / 2.0f; - last_ht = (float)desc.Height / 2.0f + font_size * 3.0f + (float)shaders * font_size; + 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); @@ -714,9 +792,9 @@ TBFix_TextureModDlg (void) ImGui::Separator (); ImGui::PushStyleColor (ImGuiCol_Border, ImVec4 (0.95f, 0.95f, 0.05f, 1.0f)); - ImGui::BeginChildFrame (0, ImVec2 ((float)desc.Width / 2.0f + 8.0f, (float)desc.Height / 2.0f + 8.0f), ImGuiWindowFlags_ShowBorders); + ImGui::BeginChildFrame (0, ImVec2 (effective_width + 8.0f, effective_height + 8.0f), ImGuiWindowFlags_ShowBorders); ImGui::Image ( pTex, - ImVec2 ((float)desc.Width / 2.0f, (float)desc.Height / 2.0f), + ImVec2 (effective_width, effective_height), ImVec2 (0,0), ImVec2 (1,1), ImColor (255,255,255,255), ImColor (255,255,255,128) ); diff --git a/src/dllmain.cpp b/src/dllmain.cpp index 4550fab..6eae6b9 100644 --- a/src/dllmain.cpp +++ b/src/dllmain.cpp @@ -185,9 +185,7 @@ SKPlugIn_Init (HMODULE hModSpecialK) // // Hacky way to force off options in Special K that are known not to work well with this game // - SK_GetCommandProcessor ()->ProcessCommandLine ("Window.Fullscreen false"); - SK_GetCommandProcessor ()->ProcessCommandLine ("Window.Borderless false"); - SK_GetCommandProcessor ()->ProcessCommandLine ("Window.Center false"); + SK_GetCommandProcessor ()->ProcessCommandLine ("Window.Center false"); CreateThread ( nullptr, 0, diff --git a/src/input.cpp b/src/input.cpp index e1aaff9..fa9f546 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -86,6 +86,13 @@ typedef void (CALLBACK *SK_PluginKeyPress_pfn)( BOOL Control, BYTE vkCode ); SK_PluginKeyPress_pfn SK_PluginKeyPress_Original = nullptr; +#define TBF_MakeKeyMask(vKey,ctrl,shift,alt) \ + (UINT)((vKey) | ((ctrl) != 0) << 9) | \ + ((shift != 0) << 10) | \ + ((alt != 0) << 11) + +#define TBF_ControlShiftKey(vKey) TBF_MakeKeyMask ((vKey), true, true, false) + void CALLBACK SK_TBF_PluginKeyPress ( BOOL Control, @@ -93,6 +100,9 @@ SK_TBF_PluginKeyPress ( BOOL Control, BOOL Alt, BYTE vkCode ) { + UINT uiMaskedKeyCode = + TBF_MakeKeyMask (vkCode, Control, Shift, Alt); + extern DWORD TBFix_Modal; if (timeGetTime () < (TBFix_Modal + 500UL)) { @@ -103,59 +113,59 @@ SK_TBF_PluginKeyPress ( BOOL Control, SK_ICommandProcessor& command = *SK_GetCommandProcessor (); - if ( vkCode == config.keyboard.hudless.vKey && - (Control != 0) == config.keyboard.hudless.ctrl && - (Shift != 0) == config.keyboard.hudless.shift && - (Alt != 0) == config.keyboard.hudless.alt ) - tbf::RenderFix::tex_mgr.queueScreenshot (L"NOT_IMPLEMENTED", true); + const UINT uiHUDlessMask = + TBF_MakeKeyMask ( config.keyboard.hudless.vKey, + config.keyboard.hudless.ctrl, + config.keyboard.hudless.shift, + config.keyboard.hudless.alt ); -#if 0 - else if ( vkCode == config.keyboard.screenshot.vKey && - Control == config.keyboard.screenshot.ctrl && - Shift == config.keyboard.screenshot.shift && - Alt == config.keyboard.screenshot.alt ) - tbf::RenderFix::tex_mgr.queueScreenshot (L"NOT_IMPLEMENTED", false); -#endif + if (uiMaskedKeyCode == uiHUDlessMask) + { + tbf::RenderFix::tex_mgr.queueScreenshot (L"NOT_IMPLEMENTED", true); + return; + } - else if (Control && Shift) + switch (uiMaskedKeyCode) { - if (vkCode == VK_DELETE) { + case TBF_ControlShiftKey (VK_DELETE): config.render.osd_disclaimer = (! config.render.osd_disclaimer); - } + break; + - else if (vkCode == 'U') { + case TBF_ControlShiftKey ('U'): command.ProcessCommandLine ("Textures.Remap toggle"); tbf::RenderFix::tex_mgr.updateOSD (); return; - } - else if (vkCode == 'Z') { + + case TBF_ControlShiftKey ('Z'): command.ProcessCommandLine ("Textures.Purge true"); tbf::RenderFix::tex_mgr.updateOSD (); return; - } - else if (vkCode == 'X') { + + case TBF_ControlShiftKey ('X'): command.ProcessCommandLine ("Textures.Trace true"); tbf::RenderFix::tex_mgr.updateOSD (); return; - } - else if (vkCode == 'V') { + + case TBF_ControlShiftKey ('V'): command.ProcessCommandLine ("Textures.ShowCache toggle"); tbf::RenderFix::tex_mgr.updateOSD (); return; - } - else if (vkCode == VK_OEM_6) { + + + case TBF_ControlShiftKey (VK_OEM_6): extern std::vector textures_used_last_dump; extern uint32_t tex_dbg_idx; ++tex_dbg_idx; @@ -175,9 +185,9 @@ SK_TBF_PluginKeyPress ( BOOL Control, tbf::RenderFix::tex_mgr.updateOSD (); return; - } - else if (vkCode == VK_OEM_4) { + + case TBF_ControlShiftKey (VK_OEM_4): extern std::vector textures_used_last_dump; extern uint32_t tex_dbg_idx; extern uint32_t debug_tex_id; @@ -197,7 +207,6 @@ SK_TBF_PluginKeyPress ( BOOL Control, tbf::RenderFix::tex_mgr.updateOSD (); return; - } } SK_PluginKeyPress_Original (Control, Shift, Alt, vkCode); diff --git a/src/textures.cpp b/src/textures.cpp index 5b0947d..715a8c8 100644 --- a/src/textures.cpp +++ b/src/textures.cpp @@ -109,12 +109,77 @@ iSK_Logger* tex_log = nullptr; #include #include -// Textures that are missing mipmaps -std::set incomplete_textures; - // Cleanup -std::queue screenshots_to_delete; +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 insert (_T item) + { + TBF_AutoCritSection auto_crit (&cs_); + + container_.insert (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. tbf::RenderFix::pad_buttons_t tbf::RenderFix::pad_buttons; @@ -170,7 +235,7 @@ TBF_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 @@ -197,6 +262,143 @@ SK_D3D9_UsageToStr (DWORD dwUsage) return usage; } +INT +__stdcall +SK_D3D9_BytesPerPixel (D3DFORMAT Format) +{ + switch (Format) + { + case D3DFMT_UNKNOWN: + return 0; + + case D3DFMT_R8G8B8: return 3; + case D3DFMT_A8R8G8B8: return 4; + case D3DFMT_X8R8G8B8: return 4; + case D3DFMT_R5G6B5: return 2; + case D3DFMT_X1R5G5B5: return 2; + case D3DFMT_A1R5G5B5: return 2; + case D3DFMT_A4R4G4B4: return 2; + case D3DFMT_R3G3B2: return 8; + case D3DFMT_A8: return 1; + case D3DFMT_A8R3G3B2: return 2; + case D3DFMT_X4R4G4B4: return 2; + case D3DFMT_A2B10G10R10: return 4; + case D3DFMT_A8B8G8R8: return 4; + case D3DFMT_X8B8G8R8: return 4; + case D3DFMT_G16R16: return 4; + case D3DFMT_A2R10G10B10: return 4; + case D3DFMT_A16B16G16R16: return 8; + case D3DFMT_A8P8: return 2; + case D3DFMT_P8: return 1; + case D3DFMT_L8: return 1; + case D3DFMT_A8L8: return 2; + case D3DFMT_A4L4: return 1; + case D3DFMT_V8U8: return 2; + case D3DFMT_L6V5U5: return 2; + case D3DFMT_X8L8V8U8: return 4; + case D3DFMT_Q8W8V8U8: return 4; + case D3DFMT_V16U16: return 4; + case D3DFMT_A2W10V10U10: return 4; + +#if 0 + case D3DFMT_UYVY : + return std::wstring (L"FourCC 'UYVY'"); + case D3DFMT_R8G8_B8G8 : + return std::wstring (L"FourCC 'RGBG'"); + case D3DFMT_YUY2 : + return std::wstring (L"FourCC 'YUY2'"); + case D3DFMT_G8R8_G8B8 : + return std::wstring (L"FourCC 'GRGB'"); +#endif + case D3DFMT_DXT1: return -1; + case D3DFMT_DXT2: return -2; + case D3DFMT_DXT3: return -2; + case D3DFMT_DXT4: return -1; + case D3DFMT_DXT5: return -2; + + case D3DFMT_D16_LOCKABLE: return 2; + case D3DFMT_D32: return 4; + case D3DFMT_D15S1: return 2; + case D3DFMT_D24S8: return 4; + case D3DFMT_D24X8: return 4; + case D3DFMT_D24X4S4: return 4; + case D3DFMT_D16: return 2; + case D3DFMT_D32F_LOCKABLE: return 4; + case D3DFMT_D24FS8: return 4; + +/* D3D9Ex only -- */ +#if !defined(D3D_DISABLE_9EX) + + /* Z-Stencil formats valid for CPU access */ + case D3DFMT_D32_LOCKABLE: return 4; + case D3DFMT_S8_LOCKABLE: return 1; +#endif // !D3D_DISABLE_9EX + + + + case D3DFMT_L16: return 2; + +#if 0 + case D3DFMT_VERTEXDATA : + return std::wstring (L"VERTEXDATA") + + (include_ordinal ? L" (100)" : L""); +#endif + case D3DFMT_INDEX16: return 2; + case D3DFMT_INDEX32: return 4; + + case D3DFMT_Q16W16V16U16: return 8; + +#if 0 + case D3DFMT_MULTI2_ARGB8 : + return std::wstring (L"FourCC 'MET1'"); +#endif + + // Floating point surface formats + + // s10e5 formats (16-bits per channel) + case D3DFMT_R16F: return 2; + case D3DFMT_G16R16F: return 4; + case D3DFMT_A16B16G16R16F: return 8; + + // IEEE s23e8 formats (32-bits per channel) + case D3DFMT_R32F: return 4; + case D3DFMT_G32R32F: return 8; + case D3DFMT_A32B32G32R32F: return 16; + +#if 0 + case D3DFMT_CxV8U8 : + return std::wstring (L"CxV8U8") + + (include_ordinal ? L" (117)" : L""); +#endif + +/* D3D9Ex only -- */ +#if !defined(D3D_DISABLE_9EX) + + // Monochrome 1 bit per pixel format + case D3DFMT_A1: return -8; + +#if 0 + // 2.8 biased fixed point + case D3DFMT_A2B10G10R10_XR_BIAS : + return std::wstring (L"A2B10G10R10_XR_BIAS") + + (include_ordinal ? L" (119)" : L""); +#endif + + +#if 0 + // Binary format indicating that the data has no inherent type + case D3DFMT_BINARYBUFFER : + return std::wstring (L"BINARYBUFFER") + + (include_ordinal ? L" (199)" : L""); +#endif + +#endif // !D3D_DISABLE_9EX +/* -- D3D9Ex only */ + } + + return 0; +} + std::wstring SK_D3D9_FormatToStr (D3DFORMAT Format, bool include_ordinal = true) { @@ -1502,7 +1704,7 @@ struct SK_StreamSplitter std::queue textures_to_stream; -std::map +std::unordered_map textures_in_flight; std::queue finished_loads; @@ -1517,7 +1719,7 @@ CRITICAL_SECTION cs_tex_inject; #define D3DX_FROM_FILE ((UINT) -3) #define D3DFMT_FROM_FILE ((D3DFORMAT) -3) -std::set inject_tids; +std::unordered_set inject_tids; volatile LONG streaming = 0L; volatile ULONG streaming_bytes = 0L; @@ -2027,6 +2229,42 @@ TBFix_LoadQueuedTextures (void) pSKTex->pTexOverride = load->pSrc; pSKTex->override_size = load->SrcDataSize; + // The original size info is completely wrong once we start generating mipmaps ;) + // + if (load->type == tbf_tex_load_s::Resample) + { + pSKTex->override_size = 0; + + for (UINT i = 0; i < pSKTex->pTexOverride->GetLevelCount (); i++) + { + D3DSURFACE_DESC desc = { }; + pSKTex->pTexOverride->GetLevelDesc (i, &desc); + + int bytes_per_pel = SK_D3D9_BytesPerPixel (desc.Format); + + // If bytes_per_pel is < 0, we have to handle DXT alignment craziness to be accurate... + + if (bytes_per_pel >= 0) + pSKTex->override_size += desc.Width * desc.Height * bytes_per_pel; + + else + { + // Assume once this stuff gets into VRAM that it is tightly-packed, + // it would be stupid for the driver to do otherwise. + UINT stride = bytes_per_pel == -1 ? + std::max (1UL, ((desc.Width + 3UL) / 4UL) ) * 8UL : + std::max (1UL, ((desc.Width + 3UL) / 4UL) ) * 16UL; + + size_t lod_size = stride * (desc.Height / 4 + + desc.Height % 4); + + pSKTex->override_size += lod_size; + } + } + + load->SrcDataSize = (UINT)pSKTex->override_size; + } + tbf::RenderFix::tex_mgr.addInjected (load->SrcDataSize); } @@ -2138,8 +2376,8 @@ TBFix_LoadQueuedTextures (void) #include -std::set resample_blacklist; -bool resample_blacklist_init = false; +std::unordered_set resample_blacklist; +bool resample_blacklist_init = false; void TBFix_ReloadPadButtons (void) @@ -3342,6 +3580,17 @@ tbf::RenderFix::TextureManager::purge (void) void tbf::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; @@ -4321,6 +4570,8 @@ tbf::RenderFix::TextureManager::takeScreenshot (IDirect3DSurface9* pSurf) ) ) { + outstanding_screenshots.insert (pSurfScreenshot); + struct screenshot_params_s { D3DSURFACE_DESC desc; IDirect3DSurface9* pSurf; @@ -4366,6 +4617,8 @@ tbf::RenderFix::TextureManager::takeScreenshot (IDirect3DSurface9* pSurf) ) ) { + outstanding_screenshots.insert (pSurfThumb); + // Slightly higher quality filtering than if we just used StretchRect with a linear filter,+ // (200 x ...) pixels still sucks, but we can make it suck just a little bit less. if (SUCCEEDED ( D3DXLoadSurfaceFromSurface ( pSurfThumb, @@ -4389,12 +4642,16 @@ tbf::RenderFix::TextureManager::takeScreenshot (IDirect3DSurface9* pSurf) with_thumbnail = true; } } + + outstanding_screenshots.erase (pSurfThumb); } if (! with_thumbnail) SK_SteamAPI_AddScreenshotToLibrary (params->name.c_str (), nullptr, params->desc.Width, params->desc.Height); } + outstanding_screenshots.erase (params->pSurf); + params->pSurf->Release (); delete params; @@ -4409,6 +4666,11 @@ tbf::RenderFix::TextureManager::takeScreenshot (IDirect3DSurface9* pSurf) nullptr ); } + + else { + pSurfScreenshot->Release (); + return E_FAIL; + } } return S_OK; diff --git a/version.ini b/version.ini index 12c882b..06aaaf6 100644 Binary files a/version.ini and b/version.ini differ