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;
}
auto write_size = [&location](float width, float height) {
auto write_size = [&location](int width, int height) {
std::array<float, 4> 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)

View File

@ -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();

View File

@ -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

View File

@ -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:

View File

@ -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;
}

View File

@ -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)

View File

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

View File

@ -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)

View File

@ -449,7 +449,6 @@
<ClInclude Include="..\vulkan\vulkan_slang_pipeline.hpp" />
<ClInclude Include="..\vulkan\vulkan_swapchain.hpp" />
<ClInclude Include="..\vulkan\vulkan_texture.hpp" />
<ClInclude Include="..\vulkan\std_chrono_throttle.hpp" />
<ClInclude Include="AVIOutput.h" />
<ClInclude Include="CCGShader.h" />
<ClInclude Include="CD3DCG.h" />
@ -613,7 +612,6 @@
<ClCompile Include="..\vulkan\vulkan_slang_pipeline.cpp" />
<ClCompile Include="..\vulkan\vulkan_swapchain.cpp" />
<ClCompile Include="..\vulkan\vulkan_texture.cpp" />
<ClCompile Include="..\vulkan\std_chrono_throttle.cpp" />
<ClCompile Include="AVIOutput.cpp" />
<ClCompile Include="CCGShader.cpp" />
<ClCompile Include="CD3DCG.cpp" />

View File

@ -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<GLSLParam> *WinGetShaderParameters()
{
if (GUI.outputMethod == OPENGL)

View File

@ -42,6 +42,7 @@ char *ReadShaderFileContents(const TCHAR *filename);
void ReduceToPath(TCHAR *filename);
double WinGetRefreshRate();
int WinGetAutomaticInputRate();
void WinThrottleFramerate();
std::vector<GLSLParam> *WinGetShaderParameters();
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()
{
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,19 +3412,18 @@ int WINAPI WinMain(
if(GUI.FrameAdvanceJustPressed)
GUI.FrameAdvanceJustPressed--;
if(ThrottleTimer())
{
ProcessInput();
if(GUI.rewindBufferSize
if (GUI.rewindBufferSize
#ifdef NETPLAY_SUPPORT
&&!Settings.NetPlay
&& !Settings.NetPlay
#endif
) {
if(Settings.Rewinding) {
if (Settings.Rewinding) {
Settings.Rewinding = stateMan.pop();
} else {
if(IPPU.TotalEmulatedFrames % GUI.rewindGranularity == 0)
}
else {
if (IPPU.TotalEmulatedFrames % GUI.rewindGranularity == 0)
stateMan.push();
}
}
@ -3470,16 +3438,6 @@ int WINAPI WinMain(
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);
}
#ifdef NETPLAY_SUPPORT
}
#endif