From 803125ffe94457e98bb44a5123278010c6d44fb4 Mon Sep 17 00:00:00 2001 From: BearOso Date: Thu, 23 Feb 2023 17:20:35 -0600 Subject: [PATCH] win32: Move frame throttle into drivers for precision. --- vulkan/vulkan_shader_chain.cpp | 19 ++++---- vulkan/vulkan_shader_chain.hpp | 4 +- vulkan/vulkan_simple_output.cpp | 14 ++++-- vulkan/vulkan_simple_output.hpp | 4 +- vulkan/vulkan_swapchain.cpp | 6 +-- win32/CDirect3D.cpp | 3 +- win32/COpenGL.cpp | 3 ++ win32/CVulkan.cpp | 24 +++++++--- win32/snes9xw.vcxproj | 4 +- win32/win32_display.cpp | 43 +++++++++++++++++ win32/win32_display.h | 1 + win32/wsnes9x.cpp | 82 ++++++++------------------------- 12 files changed, 114 insertions(+), 93 deletions(-) diff --git a/vulkan/vulkan_shader_chain.cpp b/vulkan/vulkan_shader_chain.cpp index de5c0e08..a3e580d2 100644 --- a/vulkan/vulkan_shader_chain.cpp +++ b/vulkan/vulkan_shader_chain.cpp @@ -63,10 +63,10 @@ void ShaderChain::construct_buffer_objects() break; } - auto write_size = [&location](float width, float height) { + auto write_size = [&location](int width, int height) { std::array size; - size[0] = width; - size[1] = height; + size[0] = (float)width; + size[1] = (float)height; size[2] = 1.0f / size[0]; size[3] = 1.0f / size[1]; memcpy(location, size.data(), sizeof(float) * 4); @@ -104,7 +104,7 @@ void ShaderChain::construct_buffer_objects() if (uniform.specifier < (int)lookup_textures.size()) write_size(lookup_textures[uniform.specifier]->image_width, lookup_textures[uniform.specifier]->image_height); else - write_size(1.0f, 1.0f); + write_size(1, 1); break; case SlangShader::Uniform::MVP: @@ -389,16 +389,18 @@ void ShaderChain::update_descriptor_set(vk::CommandBuffer cmd, int pipe_num, int } } -void ShaderChain::do_frame(uint8_t *data, int width, int height, int stride, vk::Format format, int viewport_x, int viewport_y, int viewport_width, int viewport_height) +bool ShaderChain::do_frame(uint8_t *data, int width, int height, int stride, vk::Format format, int viewport_x, int viewport_y, int viewport_width, int viewport_height) { - do_frame_without_swap(data, width, height, stride, format, viewport_x, viewport_y, viewport_width, viewport_height); + if (!do_frame_without_swap(data, width, height, stride, format, viewport_x, viewport_y, viewport_width, viewport_height)) + return false; context->swapchain->swap(); + return true; } -void ShaderChain::do_frame_without_swap(uint8_t *data, int width, int height, int stride, vk::Format format, int viewport_x, int viewport_y, int viewport_width, int viewport_height) +bool ShaderChain::do_frame_without_swap(uint8_t *data, int width, int height, int stride, vk::Format format, int viewport_x, int viewport_y, int viewport_width, int viewport_height) { if (!context->swapchain->begin_frame()) - return; + return false; current_frame_index = context->swapchain->get_current_frame(); @@ -518,6 +520,7 @@ void ShaderChain::do_frame_without_swap(uint8_t *data, int width, int height, in last_frame_index = current_frame_index; frame_count++; + return true; } void ShaderChain::upload_original(vk::CommandBuffer cmd, uint8_t *data, int width, int height, int stride, vk::Format format) diff --git a/vulkan/vulkan_shader_chain.hpp b/vulkan/vulkan_shader_chain.hpp index 5311d854..cbcbd3ec 100644 --- a/vulkan/vulkan_shader_chain.hpp +++ b/vulkan/vulkan_shader_chain.hpp @@ -19,8 +19,8 @@ class ShaderChain bool load_shader_preset(std::string filename); void update_and_propagate_sizes(int original_width_, int original_height_, int viewport_width_, int viewport_height_); bool load_lookup_textures(); - void do_frame(uint8_t *data, int width, int height, int stride, vk::Format format, int viewport_x, int viewport_y, int viewport_width, int viewport_height); - void do_frame_without_swap(uint8_t *data, int width, int height, int stride, vk::Format format, int viewport_x, int viewport_y, int viewport_width, int viewport_height); + bool do_frame(uint8_t *data, int width, int height, int stride, vk::Format format, int viewport_x, int viewport_y, int viewport_width, int viewport_height); + bool do_frame_without_swap(uint8_t *data, int width, int height, int stride, vk::Format format, int viewport_x, int viewport_y, int viewport_width, int viewport_height); void upload_original(uint8_t *data, int width, int height, int stride, vk::Format format); void upload_original(vk::CommandBuffer cmd, uint8_t *data, int width, int height, int stride, vk::Format format); void construct_buffer_objects(); diff --git a/vulkan/vulkan_simple_output.cpp b/vulkan/vulkan_simple_output.cpp index 2971cbd0..b8f53c20 100644 --- a/vulkan/vulkan_simple_output.cpp +++ b/vulkan/vulkan_simple_output.cpp @@ -215,13 +215,13 @@ void SimpleOutput::set_filter(bool on) filter = on; } -void SimpleOutput::do_frame_without_swap(uint8_t *buffer, int width, int height, int byte_stride, int viewport_x, int viewport_y, int viewport_width, int viewport_height) +bool SimpleOutput::do_frame_without_swap(uint8_t *buffer, int width, int height, int byte_stride, int viewport_x, int viewport_y, int viewport_width, int viewport_height) { if (!context) - return; + return false; if (!swapchain->begin_frame()) - return; + return false; auto &tex = textures[swapchain->get_current_frame()]; auto &cmd = swapchain->get_cmd(); @@ -253,12 +253,16 @@ void SimpleOutput::do_frame_without_swap(uint8_t *buffer, int width, int height, swapchain->end_render_pass(); swapchain->end_frame_without_swap(); + + return true; } -void SimpleOutput::do_frame(uint8_t *buffer, int width, int height, int byte_stride, int viewport_x, int viewport_y, int viewport_width, int viewport_height) +bool SimpleOutput::do_frame(uint8_t *buffer, int width, int height, int byte_stride, int viewport_x, int viewport_y, int viewport_width, int viewport_height) { - do_frame_without_swap(buffer, width, height, byte_stride, viewport_x, viewport_y, viewport_width, viewport_height); + if (!do_frame_without_swap(buffer, width, height, byte_stride, viewport_x, viewport_y, viewport_width, viewport_height)) + return false; swapchain->swap(); + return true; } } // namespace Vulkan \ No newline at end of file diff --git a/vulkan/vulkan_simple_output.hpp b/vulkan/vulkan_simple_output.hpp index 58993427..c499291c 100644 --- a/vulkan/vulkan_simple_output.hpp +++ b/vulkan/vulkan_simple_output.hpp @@ -10,8 +10,8 @@ class SimpleOutput public: SimpleOutput(Vulkan::Context *context, vk::Format format); ~SimpleOutput(); - void do_frame(uint8_t *buffer, int width, int height, int byte_stride, int viewport_x, int viewport_y, int viewport_width, int viewport_height); - void do_frame_without_swap(uint8_t *buffer, int width, int height, int byte_stride, int viewport_x, int viewport_y, int viewport_width, int viewport_height); + bool do_frame(uint8_t *buffer, int width, int height, int byte_stride, int viewport_x, int viewport_y, int viewport_width, int viewport_height); + bool do_frame_without_swap(uint8_t *buffer, int width, int height, int byte_stride, int viewport_x, int viewport_y, int viewport_width, int viewport_height); void set_filter(bool on); private: diff --git a/vulkan/vulkan_swapchain.cpp b/vulkan/vulkan_swapchain.cpp index 329361b7..54e657e2 100644 --- a/vulkan/vulkan_swapchain.cpp +++ b/vulkan/vulkan_swapchain.cpp @@ -199,14 +199,14 @@ bool Swapchain::begin_frame() auto &frame = frames[current_frame]; - auto result = device.waitForFences(frame.fence.get(), true, 33000000); + auto result = device.waitForFences(frame.fence.get(), true, UINT64_MAX); if (result != vk::Result::eSuccess) { printf("Failed fence\n"); return false; } - auto result_value = device.acquireNextImageKHR(swapchain_object.get(), 33000000, frame.acquire.get()); + auto result_value = device.acquireNextImageKHR(swapchain_object.get(), UINT64_MAX, frame.acquire.get()); if (result_value.result == vk::Result::eErrorOutOfDateKHR || result_value.result == vk::Result::eSuboptimalKHR) { @@ -217,7 +217,7 @@ bool Swapchain::begin_frame() if (result_value.result != vk::Result::eSuccess) { - printf("Timeout waiting for frame. Running too slow.\n"); + printf("Unable to acquire swapchain image: %s\n", vk::to_string(result_value.result).c_str()); return false; } diff --git a/win32/CDirect3D.cpp b/win32/CDirect3D.cpp index 40b7f5a5..f5c803db 100644 --- a/win32/CDirect3D.cpp +++ b/win32/CDirect3D.cpp @@ -334,6 +334,7 @@ void CDirect3D::Render(SSurface Src) pDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,0,2); pDevice->EndScene(); + WinThrottleFramerate(); pDevice->Present(NULL, NULL, NULL, NULL); if (GUI.ReduceInputLag) @@ -569,7 +570,7 @@ bool CDirect3D::ResetDevice() pDevice->SetRenderState(D3DRS_LIGHTING, FALSE); pDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0); - + //recreate the surface CreateDrawSurface(); diff --git a/win32/COpenGL.cpp b/win32/COpenGL.cpp index 9e3ec394..4eb1a3ca 100644 --- a/win32/COpenGL.cpp +++ b/win32/COpenGL.cpp @@ -369,6 +369,9 @@ void COpenGL::Render(SSurface Src) } glFlush(); + + WinThrottleFramerate(); + SwapBuffers(hDC); if (GUI.ReduceInputLag) glFinish(); diff --git a/win32/CVulkan.cpp b/win32/CVulkan.cpp index 4e37ae62..70c3c2ec 100644 --- a/win32/CVulkan.cpp +++ b/win32/CVulkan.cpp @@ -61,9 +61,6 @@ void CVulkan::Render(SSurface Src) if (!context) return; - if (GUI.ReduceInputLag) - context->wait_idle(); - SSurface Dst{}; RECT dstRect = GetFilterOutputSize(Src); @@ -87,14 +84,27 @@ void CVulkan::Render(SSurface Src) //Get maximum rect respecting AR setting displayRect = CalculateDisplayRect(Dst.Width, Dst.Height, windowSize.right, windowSize.bottom); + bool result; + if (shaderchain) { - shaderchain->do_frame(Dst.Surface, Dst.Width, Dst.Height, Dst.Pitch, vk::Format::eR5G6B5UnormPack16, displayRect.left, displayRect.top, displayRect.right - displayRect.left, displayRect.bottom - displayRect.top); - return; + result = shaderchain->do_frame_without_swap(Dst.Surface, Dst.Width, Dst.Height, Dst.Pitch, vk::Format::eR5G6B5UnormPack16, displayRect.left, displayRect.top, displayRect.right - displayRect.left, displayRect.bottom - displayRect.top); + } + else if (simple_output) + { + simple_output->set_filter(Settings.BilinearFilter); + result = simple_output->do_frame_without_swap(Dst.Surface, Dst.Width, Dst.Height, Dst.Pitch, displayRect.left, displayRect.top, displayRect.right - displayRect.left, displayRect.bottom - displayRect.top); } - simple_output->set_filter(Settings.BilinearFilter); - simple_output->do_frame(Dst.Surface, Dst.Width, Dst.Height, Dst.Pitch, displayRect.left, displayRect.top, displayRect.right - displayRect.left, displayRect.bottom - displayRect.top); + WinThrottleFramerate(); + + if (result) + { + context->swapchain->swap(); + + if (GUI.ReduceInputLag) + context->wait_idle(); + } } bool CVulkan::ChangeRenderSize(unsigned int newWidth, unsigned int newHeight) diff --git a/win32/snes9xw.vcxproj b/win32/snes9xw.vcxproj index eba6fe01..31e04fd8 100644 --- a/win32/snes9xw.vcxproj +++ b/win32/snes9xw.vcxproj @@ -449,7 +449,6 @@ - @@ -613,7 +612,6 @@ - @@ -690,4 +688,4 @@ - + \ No newline at end of file diff --git a/win32/win32_display.cpp b/win32/win32_display.cpp index f8b363b0..8aee0df2 100644 --- a/win32/win32_display.cpp +++ b/win32/win32_display.cpp @@ -675,6 +675,49 @@ int WinGetAutomaticInputRate(void) return (int)newInputRate; } +void WinThrottleFramerate() +{ + static HANDLE throttle_timer = nullptr; + static int64_t PCBase, PCFrameTime, PCFrameTimeNTSC, PCFrameTimePAL, PCStart, PCEnd; + + if (Settings.SkipFrames != AUTO_FRAMERATE) + return; + + if (!throttle_timer) + { + QueryPerformanceFrequency((LARGE_INTEGER *)&PCBase); + + PCFrameTimeNTSC = (int64_t)(PCBase / NTSC_PROGRESSIVE_FRAME_RATE); + PCFrameTimePAL = (int64_t)(PCBase / PAL_PROGRESSIVE_FRAME_RATE); + + throttle_timer = CreateWaitableTimer(NULL, true, NULL); + QueryPerformanceCounter((LARGE_INTEGER *)&PCStart); + } + + if (Settings.PAL) + PCFrameTime = PCBase / PAL_PROGRESSIVE_FRAME_RATE; + else + PCFrameTime = PCBase / NTSC_PROGRESSIVE_FRAME_RATE; + + QueryPerformanceCounter((LARGE_INTEGER *)&PCEnd); + int64_t time_left_us = ((PCFrameTime - (PCEnd - PCStart)) * 1000000) / PCBase; + + int64_t PCFrameTime_us = (int64_t)(PCFrameTime * 1000000.0 / PCBase); + if (time_left_us < -PCFrameTime_us / 10) + { + QueryPerformanceCounter((LARGE_INTEGER *)&PCStart); + return; + } + if (time_left_us > 0) + { + LARGE_INTEGER li; + li.QuadPart = -time_left_us * 10; + SetWaitableTimer(throttle_timer, &li, 0, NULL, NULL, false); + WaitForSingleObject(throttle_timer, INFINITE); + } + PCStart += PCFrameTime; +} + std::vector *WinGetShaderParameters() { if (GUI.outputMethod == OPENGL) diff --git a/win32/win32_display.h b/win32/win32_display.h index c3c78479..aaf2c8b0 100644 --- a/win32/win32_display.h +++ b/win32/win32_display.h @@ -42,6 +42,7 @@ char *ReadShaderFileContents(const TCHAR *filename); void ReduceToPath(TCHAR *filename); double WinGetRefreshRate(); int WinGetAutomaticInputRate(); +void WinThrottleFramerate(); std::vector *WinGetShaderParameters(); std::function WinGetShaderSaveFunction(); diff --git a/win32/wsnes9x.cpp b/win32/wsnes9x.cpp index edd03c5d..1806c2dc 100644 --- a/win32/wsnes9x.cpp +++ b/win32/wsnes9x.cpp @@ -2802,35 +2802,6 @@ VOID CALLBACK HotkeyTimer( UINT idEvent, UINT uMsg, DWORD dwUser, DWORD dw1, DWO } } -bool ThrottleTimer() -{ - bool run_frame = false; - do_frame_adjust = false; - QueryPerformanceCounter((LARGE_INTEGER*)&PCEnd); - - if (Settings.TurboMode || Settings.FrameAdvance || Settings.SkipFrames != AUTO_FRAMERATE -#ifdef NETPLAY_SUPPORT - || Settings.NetPlay -#endif - ) - { - PCStart = PCEnd; - return true; - } - - while ((PCEnd - PCStart) >= PCFrameTime) - { - if ((PCEnd - PCStart) >= (PCFrameTime * 2)) - do_frame_adjust = true; - - run_frame = true; - - PCStart += PCFrameTime; - } - - return run_frame; -} - static void EnsureInputDisplayUpdated() { if(GUI.FrameAdvanceJustPressed==1 && Settings.Paused && Settings.DisplayPressedKeys==2 && GUI.ControllerOption != SNES_JOYPAD && GUI.ControllerOption != SNES_MULTIPLAYER5 && GUI.ControllerOption != SNES_MULTIPLAYER8) @@ -3369,8 +3340,6 @@ int WINAPI WinMain( MSG msg; - HANDLE throttle_timer = CreateWaitableTimer(NULL, true, NULL); - while (TRUE) { EnsureInputDisplayUpdated(); @@ -3443,43 +3412,32 @@ int WINAPI WinMain( if(GUI.FrameAdvanceJustPressed) GUI.FrameAdvanceJustPressed--; - if(ThrottleTimer()) - { - ProcessInput(); + ProcessInput(); - if(GUI.rewindBufferSize + if (GUI.rewindBufferSize #ifdef NETPLAY_SUPPORT - &&!Settings.NetPlay + && !Settings.NetPlay #endif - ) { - if(Settings.Rewinding) { - Settings.Rewinding = stateMan.pop(); - } else { - if(IPPU.TotalEmulatedFrames % GUI.rewindGranularity == 0) - stateMan.push(); - } - } - - S9xMainLoop(); - GUI.FrameCount++; - if (GUI.CursorTimer) - { - if (--GUI.CursorTimer == 0) - { - if (GUI.ControllerOption != SNES_SUPERSCOPE && GUI.ControllerOption != SNES_JUSTIFIER && GUI.ControllerOption != SNES_JUSTIFIER_2 && GUI.ControllerOption != SNES_MACSRIFLE) - SetCursor(NULL); - } + ) { + if (Settings.Rewinding) { + Settings.Rewinding = stateMan.pop(); + } + else { + if (IPPU.TotalEmulatedFrames % GUI.rewindGranularity == 0) + stateMan.push(); } } - else - { - auto time_left = ((PCFrameTime - (PCEnd - PCStart)) * 100000 / PCBase); - LARGE_INTEGER li; - li.QuadPart = -time_left; - SetWaitableTimer(throttle_timer, &li, 0, NULL, NULL, false); - WaitForSingleObject(throttle_timer, INFINITE); - } + S9xMainLoop(); + GUI.FrameCount++; + if (GUI.CursorTimer) + { + if (--GUI.CursorTimer == 0) + { + if (GUI.ControllerOption != SNES_SUPERSCOPE && GUI.ControllerOption != SNES_JUSTIFIER && GUI.ControllerOption != SNES_JUSTIFIER_2 && GUI.ControllerOption != SNES_MACSRIFLE) + SetCursor(NULL); + } + } #ifdef NETPLAY_SUPPORT } #endif