win32: Move frame throttle into drivers for precision.

This commit is contained in:
BearOso 2023-02-23 17:20:35 -06:00
parent 309f9e650d
commit 803125ffe9
12 changed files with 114 additions and 93 deletions

View File

@ -63,10 +63,10 @@ void ShaderChain::construct_buffer_objects()
break; break;
} }
auto write_size = [&location](float width, float height) { auto write_size = [&location](int width, int height) {
std::array<float, 4> size; std::array<float, 4> size;
size[0] = width; size[0] = (float)width;
size[1] = height; size[1] = (float)height;
size[2] = 1.0f / size[0]; size[2] = 1.0f / size[0];
size[3] = 1.0f / size[1]; size[3] = 1.0f / size[1];
memcpy(location, size.data(), sizeof(float) * 4); memcpy(location, size.data(), sizeof(float) * 4);
@ -104,7 +104,7 @@ void ShaderChain::construct_buffer_objects()
if (uniform.specifier < (int)lookup_textures.size()) if (uniform.specifier < (int)lookup_textures.size())
write_size(lookup_textures[uniform.specifier]->image_width, lookup_textures[uniform.specifier]->image_height); write_size(lookup_textures[uniform.specifier]->image_width, lookup_textures[uniform.specifier]->image_height);
else else
write_size(1.0f, 1.0f); write_size(1, 1);
break; break;
case SlangShader::Uniform::MVP: 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(); 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()) if (!context->swapchain->begin_frame())
return; return false;
current_frame_index = context->swapchain->get_current_frame(); 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; last_frame_index = current_frame_index;
frame_count++; frame_count++;
return true;
} }
void ShaderChain::upload_original(vk::CommandBuffer cmd, uint8_t *data, int width, int height, int stride, vk::Format format) void ShaderChain::upload_original(vk::CommandBuffer cmd, uint8_t *data, int width, int height, int stride, vk::Format format)

View File

@ -19,8 +19,8 @@ class ShaderChain
bool load_shader_preset(std::string filename); bool load_shader_preset(std::string filename);
void update_and_propagate_sizes(int original_width_, int original_height_, int viewport_width_, int viewport_height_); void update_and_propagate_sizes(int original_width_, int original_height_, int viewport_width_, int viewport_height_);
bool load_lookup_textures(); 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); 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);
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_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(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 upload_original(vk::CommandBuffer cmd, uint8_t *data, int width, int height, int stride, vk::Format format);
void construct_buffer_objects(); void construct_buffer_objects();

View File

@ -215,13 +215,13 @@ void SimpleOutput::set_filter(bool on)
filter = 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) if (!context)
return; return false;
if (!swapchain->begin_frame()) if (!swapchain->begin_frame())
return; return false;
auto &tex = textures[swapchain->get_current_frame()]; auto &tex = textures[swapchain->get_current_frame()];
auto &cmd = swapchain->get_cmd(); 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_render_pass();
swapchain->end_frame_without_swap(); 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(); swapchain->swap();
return true;
} }
} // namespace Vulkan } // namespace Vulkan

View File

@ -10,8 +10,8 @@ class SimpleOutput
public: public:
SimpleOutput(Vulkan::Context *context, vk::Format format); SimpleOutput(Vulkan::Context *context, vk::Format format);
~SimpleOutput(); ~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); 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);
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_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); void set_filter(bool on);
private: private:

View File

@ -199,14 +199,14 @@ bool Swapchain::begin_frame()
auto &frame = frames[current_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) if (result != vk::Result::eSuccess)
{ {
printf("Failed fence\n"); printf("Failed fence\n");
return false; 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 || if (result_value.result == vk::Result::eErrorOutOfDateKHR ||
result_value.result == vk::Result::eSuboptimalKHR) result_value.result == vk::Result::eSuboptimalKHR)
{ {
@ -217,7 +217,7 @@ bool Swapchain::begin_frame()
if (result_value.result != vk::Result::eSuccess) 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; return false;
} }

View File

@ -334,6 +334,7 @@ void CDirect3D::Render(SSurface Src)
pDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,0,2); pDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,0,2);
pDevice->EndScene(); pDevice->EndScene();
WinThrottleFramerate();
pDevice->Present(NULL, NULL, NULL, NULL); pDevice->Present(NULL, NULL, NULL, NULL);
if (GUI.ReduceInputLag) if (GUI.ReduceInputLag)
@ -569,7 +570,7 @@ bool CDirect3D::ResetDevice()
pDevice->SetRenderState(D3DRS_LIGHTING, FALSE); pDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
pDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0); pDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
//recreate the surface //recreate the surface
CreateDrawSurface(); CreateDrawSurface();

View File

@ -369,6 +369,9 @@ void COpenGL::Render(SSurface Src)
} }
glFlush(); glFlush();
WinThrottleFramerate();
SwapBuffers(hDC); SwapBuffers(hDC);
if (GUI.ReduceInputLag) if (GUI.ReduceInputLag)
glFinish(); glFinish();

View File

@ -61,9 +61,6 @@ void CVulkan::Render(SSurface Src)
if (!context) if (!context)
return; return;
if (GUI.ReduceInputLag)
context->wait_idle();
SSurface Dst{}; SSurface Dst{};
RECT dstRect = GetFilterOutputSize(Src); RECT dstRect = GetFilterOutputSize(Src);
@ -87,14 +84,27 @@ void CVulkan::Render(SSurface Src)
//Get maximum rect respecting AR setting //Get maximum rect respecting AR setting
displayRect = CalculateDisplayRect(Dst.Width, Dst.Height, windowSize.right, windowSize.bottom); displayRect = CalculateDisplayRect(Dst.Width, Dst.Height, windowSize.right, windowSize.bottom);
bool result;
if (shaderchain) 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); 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);
return; }
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); WinThrottleFramerate();
simple_output->do_frame(Dst.Surface, Dst.Width, Dst.Height, Dst.Pitch, displayRect.left, displayRect.top, displayRect.right - displayRect.left, displayRect.bottom - displayRect.top);
if (result)
{
context->swapchain->swap();
if (GUI.ReduceInputLag)
context->wait_idle();
}
} }
bool CVulkan::ChangeRenderSize(unsigned int newWidth, unsigned int newHeight) bool CVulkan::ChangeRenderSize(unsigned int newWidth, unsigned int newHeight)

View File

@ -449,7 +449,6 @@
<ClInclude Include="..\vulkan\vulkan_slang_pipeline.hpp" /> <ClInclude Include="..\vulkan\vulkan_slang_pipeline.hpp" />
<ClInclude Include="..\vulkan\vulkan_swapchain.hpp" /> <ClInclude Include="..\vulkan\vulkan_swapchain.hpp" />
<ClInclude Include="..\vulkan\vulkan_texture.hpp" /> <ClInclude Include="..\vulkan\vulkan_texture.hpp" />
<ClInclude Include="..\vulkan\std_chrono_throttle.hpp" />
<ClInclude Include="AVIOutput.h" /> <ClInclude Include="AVIOutput.h" />
<ClInclude Include="CCGShader.h" /> <ClInclude Include="CCGShader.h" />
<ClInclude Include="CD3DCG.h" /> <ClInclude Include="CD3DCG.h" />
@ -613,7 +612,6 @@
<ClCompile Include="..\vulkan\vulkan_slang_pipeline.cpp" /> <ClCompile Include="..\vulkan\vulkan_slang_pipeline.cpp" />
<ClCompile Include="..\vulkan\vulkan_swapchain.cpp" /> <ClCompile Include="..\vulkan\vulkan_swapchain.cpp" />
<ClCompile Include="..\vulkan\vulkan_texture.cpp" /> <ClCompile Include="..\vulkan\vulkan_texture.cpp" />
<ClCompile Include="..\vulkan\std_chrono_throttle.cpp" />
<ClCompile Include="AVIOutput.cpp" /> <ClCompile Include="AVIOutput.cpp" />
<ClCompile Include="CCGShader.cpp" /> <ClCompile Include="CCGShader.cpp" />
<ClCompile Include="CD3DCG.cpp" /> <ClCompile Include="CD3DCG.cpp" />
@ -690,4 +688,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>
</Project> </Project>

View File

@ -675,6 +675,49 @@ int WinGetAutomaticInputRate(void)
return (int)newInputRate; 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<GLSLParam> *WinGetShaderParameters() std::vector<GLSLParam> *WinGetShaderParameters()
{ {
if (GUI.outputMethod == OPENGL) if (GUI.outputMethod == OPENGL)

View File

@ -42,6 +42,7 @@ char *ReadShaderFileContents(const TCHAR *filename);
void ReduceToPath(TCHAR *filename); void ReduceToPath(TCHAR *filename);
double WinGetRefreshRate(); double WinGetRefreshRate();
int WinGetAutomaticInputRate(); int WinGetAutomaticInputRate();
void WinThrottleFramerate();
std::vector<GLSLParam> *WinGetShaderParameters(); std::vector<GLSLParam> *WinGetShaderParameters();
std::function<void(const char*)> WinGetShaderSaveFunction(); std::function<void(const char*)> WinGetShaderSaveFunction();

View File

@ -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() static void EnsureInputDisplayUpdated()
{ {
if(GUI.FrameAdvanceJustPressed==1 && Settings.Paused && Settings.DisplayPressedKeys==2 && GUI.ControllerOption != SNES_JOYPAD && GUI.ControllerOption != SNES_MULTIPLAYER5 && GUI.ControllerOption != SNES_MULTIPLAYER8) 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; MSG msg;
HANDLE throttle_timer = CreateWaitableTimer(NULL, true, NULL);
while (TRUE) while (TRUE)
{ {
EnsureInputDisplayUpdated(); EnsureInputDisplayUpdated();
@ -3443,43 +3412,32 @@ int WINAPI WinMain(
if(GUI.FrameAdvanceJustPressed) if(GUI.FrameAdvanceJustPressed)
GUI.FrameAdvanceJustPressed--; GUI.FrameAdvanceJustPressed--;
if(ThrottleTimer()) ProcessInput();
{
ProcessInput();
if(GUI.rewindBufferSize if (GUI.rewindBufferSize
#ifdef NETPLAY_SUPPORT #ifdef NETPLAY_SUPPORT
&&!Settings.NetPlay && !Settings.NetPlay
#endif #endif
) { ) {
if(Settings.Rewinding) { if (Settings.Rewinding) {
Settings.Rewinding = stateMan.pop(); Settings.Rewinding = stateMan.pop();
} else { }
if(IPPU.TotalEmulatedFrames % GUI.rewindGranularity == 0) else {
stateMan.push(); 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);
}
} }
} }
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 #ifdef NETPLAY_SUPPORT
} }
#endif #endif