diff --git a/README.md b/README.md index 8c70b31..0b4db90 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,10 @@ By default the game forced a 60Hz refresh rate in full screen mode. With this mo ## Changes to where the memory is allocated on certain vertex buffers This considerably improves the frame rate when 2D elements are being disabled on the screen (i.e. minimap or battle menu HUD). This fix is not new, it is from [OneTweakNG](https://github.com/Nucleoprotein/OneTweakNG). -## Fix the enemy scan text on resolutions over 720p (FF13 only) +## Works around pixelated screen bug that happens when using 2560x1440 resolution +The internal resolution is reduced to 2559x1440 to workaround the issue. + +## Fix the enemy scan text on resolutions over 720p (FFXIII only) The game calls [SetScissorRect](https://docs.microsoft.com/en-us/windows/win32/api/d3d9helper/nf-d3d9helper-idirect3ddevice9-setscissorrect) using a rectangle hardcoded with the 720p coordenates. This correct the coordenates and rectangle size in order to fix it. ## Reporting issues diff --git a/d3d9ex/AutoFix.cpp b/d3d9ex/AutoFix.cpp index be28075..79c3c65 100644 --- a/d3d9ex/AutoFix.cpp +++ b/d3d9ex/AutoFix.cpp @@ -103,11 +103,9 @@ HRESULT APIENTRY MainContext::ApplyVertexBufferFix(IDirect3DDevice9* pIDirect3DD return pIDirect3DDevice9->CreateVertexBuffer(Length, Usage, FVF, Pool, ppVertexBuffer, pSharedHandle); } -void MainContext::FF13_AsyncPatchingLoop() { +void MainContext::FF13_AsyncPatching() { std::this_thread::sleep_for(std::chrono::milliseconds(2000)); - if (*context.ff13_frame_pacer_ptr) { - context.FF13_OneTimeFixes(); - } + context.FF13_OneTimeFixes(); } void MainContext::FF13_InitializeGameAddresses() @@ -128,6 +126,7 @@ void MainContext::FF13_InitializeGameAddresses() } void MainContext::FF13_OneTimeFixes() { + MainContext::FF13_Workaround_2560_1440_Res_Bug(); MainContext::FF13_NOPIngameFrameRateLimitSetter(); MainContext::FF13_RemoveContinuousControllerScan(); MainContext::FF13_FixMissingEnemyScan(); @@ -138,6 +137,17 @@ void MainContext::FF13_OneTimeFixes() { context.didOneTimeFixes = true; } +void MainContext::FF13_Workaround_2560_1440_Res_Bug() +{ + if (*ff13_internal_res_w == 2560 && *ff13_internal_res_h == 1440) { + // We need to reduce one or another. Increasing the internal res causes crashes. + // Decreasing the internal res width by one pixel causes the last pixel column displayed on the screen to stay black. + PrintLog("Applying workaround for resolution 2560x1440 bug."); + *ff13_internal_res_w = 2559; + } +} + + void MainContext::FF13_EnableControllerVibration() { if (!config.GetFFXIIIEnableControllerVibration()) { @@ -257,7 +267,7 @@ void MainContext::FF13_SetFrameRateVariables() { } } -void MainContext::FF13_2_AsyncPatchingLoop() { +void MainContext::FF13_2_AsyncPatching() { std::this_thread::sleep_for(std::chrono::milliseconds(2000)); context.FF13_2_OneTimeFixes(); } @@ -268,6 +278,7 @@ void MainContext::FF13_2_OneTimeFixes() { **ff13_2_frame_pacer_ptr_address = MAX_FRAME_RATE_LIMIT; PrintLog("Frame pacer disabled"); + context.FF13_2_Workaround_2560_1440_Res_Bug(); context.FF13_2_AddHookIngameFrameRateLimitSetter(); context.FF13_2_RemoveContinuousControllerScan(); context.FF13_2_EnableControllerVibration(); @@ -279,6 +290,17 @@ void MainContext::FF13_2_OneTimeFixes() { } } +void MainContext::FF13_2_Workaround_2560_1440_Res_Bug() +{ + if (*ff13_2_internal_res_w == 2560 && *ff13_2_internal_res_h == 1440) { + // We need to reduce one or another. Increasing the internal res causes crashes. + // Decreasing the internal res width by one pixel causes the last pixel column displayed on the screen to stay black. + PrintLog("Applying workaround for resolution 2560x1440 bug."); + *ff13_2_internal_res_w = 2559; + } +} + + void MainContext::FF13_2_EnableControllerVibration() { if (!config.GetFFXIIIEnableControllerVibration()) { @@ -316,6 +338,8 @@ void MainContext::FF13_2_InitializeGameAddresses() ff13_2_base_controller_input_address_ptr = (uint8_t**)(baseAddr + 0x212A164); ff13_2_vibration_low_set_zero_address = baseAddr + 0x2A7221; ff13_2_vibration_high_set_zero_address = baseAddr + 0x2A7226; + ff13_2_internal_res_w = (uint32_t*)(baseAddr + 0x1FA864C); + ff13_2_internal_res_h = ff13_2_internal_res_w + 1; } void MainContext::FF13_2_RemoveContinuousControllerScan() { @@ -404,7 +428,7 @@ void MainContext::ChangeMemoryProtectionToReadWriteExecute(void* address, const } void MainContext::PrintVersionInfo() { - PrintLog("FF13Fix 1.4.3 https://github.com/rebtd7/FF13Fix"); + PrintLog("FF13Fix 1.4.4 https://github.com/rebtd7/FF13Fix"); } bool MainContext::AreAlmostTheSame(float a, float b) { diff --git a/d3d9ex/Context.cpp b/d3d9ex/Context.cpp index 5ab731f..f541fd8 100644 --- a/d3d9ex/Context.cpp +++ b/d3d9ex/Context.cpp @@ -194,16 +194,16 @@ bool MainContext::CheckWindow(HWND hWnd) if (!context.didOneTimeFixes) { if (context.autofix == FINAL_FANTASY_XIII && wcscmp(className.get(), L"SQEX.CDev.Engine.Framework.MainWindow") == 0) { const std::lock_guard lock(context.oneTimeFixesMutex); - if(!context.didOneTimeFixes){ + if(!context.didOneTimeFixes && patchingThread == NULL){ PrintLog("Starting FFXIII one time RAM patches."); - patchingThread = new std::thread(&context.FF13_AsyncPatchingLoop); + patchingThread = new std::thread(&context.FF13_AsyncPatching); } } else if (context.autofix == FINAL_FANTASY_XIII2 && wcscmp(className.get(), L"SQEX.CDev.Engine.Framework.MainWindow") == 0) { const std::lock_guard lock(context.oneTimeFixesMutex); - if (!context.didOneTimeFixes) { + if (!context.didOneTimeFixes && patchingThread == NULL) { PrintLog("Starting FFXIII-2 one time RAM patches."); - patchingThread = new std::thread(&context.FF13_2_AsyncPatchingLoop); + patchingThread = new std::thread(&context.FF13_2_AsyncPatching); } } } diff --git a/d3d9ex/Context.h b/d3d9ex/Context.h index 3abbace..08ee799 100644 --- a/d3d9ex/Context.h +++ b/d3d9ex/Context.h @@ -95,11 +95,13 @@ private: uint8_t** ff13_2_base_controller_input_address_ptr = NULL; uint8_t* ff13_2_vibration_high_set_zero_address = NULL; uint8_t* ff13_2_vibration_low_set_zero_address = NULL; + uint32_t* ff13_2_internal_res_w; + uint32_t* ff13_2_internal_res_h; const float FF13_2_30_FPS = 30.0F; const float FF13_2_MAX_FRAME_CAP = 1000.0F; XInputManager* xinputManager; - std::thread * patchingThread; + std::thread * patchingThread = NULL; void FixBehaviorFlagConflict(const DWORD flags_in, DWORD* flags_out); static const std::map behaviorflags_fixes; @@ -112,21 +114,23 @@ private: void PrintVersionInfo(); - static void FF13_AsyncPatchingLoop(); + static void FF13_AsyncPatching(); void FF13_InitializeGameAddresses(); void FF13_OneTimeFixes(); + void FF13_Workaround_2560_1440_Res_Bug(); void FF13_EnableControllerVibration(); void FF13_NOPIngameFrameRateLimitSetter(); void FF13_SetFrameRateVariables(); void FF13_FixMissingEnemyScan(); void FF13_RemoveContinuousControllerScan(); - static void FF13_2_AsyncPatchingLoop(); + static void FF13_2_AsyncPatching(); void FF13_2_CreateSetFrameRateCodeBlock(); void FF13_2_InitializeGameAddresses(); void FF13_2_RemoveContinuousControllerScan(); void FF13_2_AddHookIngameFrameRateLimitSetter(); void FF13_2_OneTimeFixes(); + void FF13_2_Workaround_2560_1440_Res_Bug(); void FF13_2_EnableControllerVibration(); };