Skip to content

Commit

Permalink
Merge pull request #12659 from unknownbrackets/vsync
Browse files Browse the repository at this point in the history
Support vsync in all hardware backends, support runtime update
  • Loading branch information
hrydgard authored Mar 1, 2020
2 parents 76e0d02 + bc90fae commit 2ec8295
Show file tree
Hide file tree
Showing 23 changed files with 87 additions and 91 deletions.
21 changes: 9 additions & 12 deletions Common/Vulkan/VulkanContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -949,20 +949,17 @@ bool VulkanContext::InitSwapchain() {
ILOG("Supported present mode: %d (%s)", presentModes[i], PresentModeString(presentModes[i]));
}
for (size_t i = 0; i < presentModeCount; i++) {
if (swapchainPresentMode == VK_PRESENT_MODE_MAX_ENUM_KHR) {
// Default to the first present mode from the list.
bool match = false;
match = match || ((flags_ & VULKAN_FLAG_PRESENT_MAILBOX) && presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR);
match = match || ((flags_ & VULKAN_FLAG_PRESENT_FIFO_RELAXED) && presentModes[i] == VK_PRESENT_MODE_FIFO_RELAXED_KHR);
match = match || ((flags_ & VULKAN_FLAG_PRESENT_FIFO) && presentModes[i] == VK_PRESENT_MODE_FIFO_KHR);
match = match || ((flags_ & VULKAN_FLAG_PRESENT_IMMEDIATE) && presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR);

// Default to the first present mode from the list.
if (match || swapchainPresentMode == VK_PRESENT_MODE_MAX_ENUM_KHR) {
swapchainPresentMode = presentModes[i];
}
if ((flags_ & VULKAN_FLAG_PRESENT_MAILBOX) && presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR;
break;
}
if ((flags_ & VULKAN_FLAG_PRESENT_FIFO_RELAXED) && presentModes[i] == VK_PRESENT_MODE_FIFO_RELAXED_KHR) {
swapchainPresentMode = VK_PRESENT_MODE_FIFO_RELAXED_KHR;
break;
}
if ((flags_ & VULKAN_FLAG_PRESENT_IMMEDIATE) && presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) {
swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
if (match) {
break;
}
}
Expand Down
2 changes: 2 additions & 0 deletions Common/Vulkan/VulkanContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ enum {
VULKAN_FLAG_PRESENT_MAILBOX = 2,
VULKAN_FLAG_PRESENT_IMMEDIATE = 4,
VULKAN_FLAG_PRESENT_FIFO_RELAXED = 8,
VULKAN_FLAG_PRESENT_FIFO = 16,
};

enum {
Expand Down Expand Up @@ -136,6 +137,7 @@ class VulkanContext {
VkDevice GetDevice() const { return device_; }
VkInstance GetInstance() const { return instance_; }
uint32_t GetFlags() const { return flags_; }
void UpdateFlags(uint32_t flags) { flags_ = flags; }

VulkanDeleteList &Delete() { return globalDeleteList_; }

Expand Down
7 changes: 6 additions & 1 deletion Core/HLE/sceDisplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -556,7 +556,12 @@ static void DoFrameTiming(bool &throttle, bool &skipFrame, float timestep) {
// we have nothing to do here.
bool doFrameSkip = g_Config.iFrameSkip != 0;

if (!throttle && g_Config.bFrameSkipUnthrottle) {
bool unthrottleNeedsSkip = g_Config.bFrameSkipUnthrottle;
if (g_Config.bVSync && GetGPUBackend() == GPUBackend::VULKAN) {
// Vulkan doesn't support the interval setting, so we force frameskip.
unthrottleNeedsSkip = true;
}
if (!throttle && unthrottleNeedsSkip) {
doFrameSkip = true;
skipFrame = true;
if (numSkippedFrames >= 7) {
Expand Down
1 change: 0 additions & 1 deletion GPU/D3D11/GPU_D3D11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ GPU_D3D11::GPU_D3D11(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
device_ = (ID3D11Device *)draw->GetNativeObject(Draw::NativeObject::DEVICE);
context_ = (ID3D11DeviceContext *)draw->GetNativeObject(Draw::NativeObject::CONTEXT);
D3D_FEATURE_LEVEL featureLevel = (D3D_FEATURE_LEVEL)draw->GetNativeObject(Draw::NativeObject::FEATURE_LEVEL);
lastVsync_ = g_Config.bVSync ? 1 : 0;

stockD3D11.Create(device_);

Expand Down
2 changes: 0 additions & 2 deletions GPU/D3D11/GPU_D3D11.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,4 @@ class GPU_D3D11 : public GPUCommon {
DepalShaderCacheD3D11 *depalShaderCache_;
DrawEngineD3D11 drawEngine_;
ShaderManagerD3D11 *shaderManagerD3D11_;

int lastVsync_;
};
11 changes: 0 additions & 11 deletions GPU/Directx9/GPU_DX9.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,6 @@ GPU_DX9::GPU_DX9(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
drawEngine_(draw) {
device_ = (LPDIRECT3DDEVICE9)draw->GetNativeObject(Draw::NativeObject::DEVICE);
deviceEx_ = (LPDIRECT3DDEVICE9EX)draw->GetNativeObject(Draw::NativeObject::DEVICE_EX);
lastVsync_ = g_Config.bVSync ? 1 : 0;
dxstate.SetVSyncInterval(g_Config.bVSync);

shaderManagerDX9_ = new ShaderManagerDX9(draw, device_);
framebufferManagerDX9_ = new FramebufferManagerDX9(draw);
Expand Down Expand Up @@ -285,15 +283,6 @@ void GPU_DX9::ReapplyGfxState() {
}

void GPU_DX9::BeginFrame() {
// Turn off vsync when unthrottled
int desiredVSyncInterval = g_Config.bVSync ? 1 : 0;
if (PSP_CoreParameter().unthrottle || PSP_CoreParameter().fpsLimit != FPSLimit::NORMAL)
desiredVSyncInterval = 0;
if (desiredVSyncInterval != lastVsync_) {
dxstate.SetVSyncInterval(desiredVSyncInterval);
lastVsync_ = desiredVSyncInterval;
}

textureCacheDX9_->StartFrame();
drawEngine_.DecimateTrackedVertexArrays();
depalShaderCache_.Decimate();
Expand Down
2 changes: 0 additions & 2 deletions GPU/Directx9/GPU_DX9.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,6 @@ class GPU_DX9 : public GPUCommon {
DepalShaderCacheDX9 depalShaderCache_;
DrawEngineDX9 drawEngine_;
ShaderManagerDX9 *shaderManagerDX9_;

int lastVsync_;
};

} // namespace DX9
Expand Down
32 changes: 1 addition & 31 deletions GPU/GLES/GPU_GLES.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ void GPU_GLES::BeginHostFrame() {
drawEngine_.Resized();
shaderManagerGL_->DirtyShader();
textureCacheGL_->NotifyConfigChanged();
resized_ = false;
}

drawEngine_.BeginFrame();
Expand All @@ -369,42 +370,11 @@ void GPU_GLES::EndHostFrame() {
drawEngine_.EndFrame();
}

inline void GPU_GLES::UpdateVsyncInterval(bool force) {
#ifdef _WIN32
int desiredVSyncInterval = g_Config.bVSync ? 1 : 0;
if (PSP_CoreParameter().unthrottle) {
desiredVSyncInterval = 0;
}
if (PSP_CoreParameter().fpsLimit != FPSLimit::NORMAL) {
int limit = PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1 ? g_Config.iFpsLimit1 : g_Config.iFpsLimit2;
// For an alternative speed that is a clean factor of 60, the user probably still wants vsync.
if (limit == 0 || (limit >= 0 && limit != 15 && limit != 30 && limit != 60)) {
desiredVSyncInterval = 0;
}
}

if (desiredVSyncInterval != lastVsync_ || force) {
// Disabled EXT_swap_control_tear for now, it never seems to settle at the correct timing
// so it just keeps tearing. Not what I hoped for...
//if (gl_extensions.EXT_swap_control_tear) {
// // See http://developer.download.nvidia.com/opengl/specs/WGL_EXT_swap_control_tear.txt
// glstate.SetVSyncInterval(-desiredVSyncInterval);
//} else {
gfxCtx_->SwapInterval(desiredVSyncInterval);
//}
lastVsync_ = desiredVSyncInterval;
}
#endif
}

void GPU_GLES::ReapplyGfxState() {
GPUCommon::ReapplyGfxState();
}

void GPU_GLES::BeginFrame() {
UpdateVsyncInterval(resized_);
resized_ = false;

textureCacheGL_->StartFrame();
drawEngine_.DecimateTrackedVertexArrays();
depalShaderCache_.Decimate();
Expand Down
6 changes: 0 additions & 6 deletions GPU/GLES/GPU_GLES.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,6 @@ class GPU_GLES : public GPUCommon {
void CopyDisplayToOutput() override;
void Reinitialize() override;

inline void UpdateVsyncInterval(bool force);

FramebufferManagerGLES *framebufferManagerGL_;
TextureCacheGLES *textureCacheGL_;
DepalShaderCacheGLES depalShaderCache_;
Expand All @@ -89,8 +87,4 @@ class GPU_GLES : public GPUCommon {
ShaderManagerGLES *shaderManagerGL_;

std::string shaderCachePath_;

#ifdef _WIN32
int lastVsync_;
#endif
};
27 changes: 27 additions & 0 deletions GPU/GPUCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "profiler/profiler.h"

#include "Common/ColorConv.h"
#include "Common/GraphicsContext.h"
#include "Core/Reporting.h"
#include "GPU/GeDisasm.h"
#include "GPU/GPU.h"
Expand Down Expand Up @@ -408,6 +409,7 @@ GPUCommon::GPUCommon(GraphicsContext *gfxCtx, Draw::DrawContext *draw) :
}

UpdateCmdInfo();
UpdateVsyncInterval(true);
}

GPUCommon::~GPUCommon() {
Expand All @@ -432,6 +434,7 @@ void GPUCommon::UpdateCmdInfo() {
}

void GPUCommon::BeginHostFrame() {
UpdateVsyncInterval(resized_);
ReapplyGfxState();

// TODO: Assume config may have changed - maybe move to resize.
Expand All @@ -458,6 +461,30 @@ void GPUCommon::Reinitialize() {
interruptsEnabled_ = true;
}

void GPUCommon::UpdateVsyncInterval(bool force) {
#ifdef _WIN32
int desiredVSyncInterval = g_Config.bVSync ? 1 : 0;
if (PSP_CoreParameter().unthrottle) {
desiredVSyncInterval = 0;
}
if (PSP_CoreParameter().fpsLimit != FPSLimit::NORMAL) {
int limit = PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1 ? g_Config.iFpsLimit1 : g_Config.iFpsLimit2;
// For an alternative speed that is a clean factor of 60, the user probably still wants vsync.
if (limit == 0 || (limit >= 0 && limit != 15 && limit != 30 && limit != 60)) {
desiredVSyncInterval = 0;
}
}

if (desiredVSyncInterval != lastVsync_ || force) {
// Disabled EXT_swap_control_tear for now, it never seems to settle at the correct timing
// so it just keeps tearing. Not what I hoped for... (gl_extensions.EXT_swap_control_tear)
// See http://developer.download.nvidia.com/opengl/specs/WGL_EXT_swap_control_tear.txt
gfxCtx_->SwapInterval(desiredVSyncInterval);
lastVsync_ = desiredVSyncInterval;
}
#endif
}

int GPUCommon::EstimatePerVertexCost() {
// TODO: This is transform cost, also account for rasterization cost somehow... although it probably
// runs in parallel with transform.
Expand Down
5 changes: 5 additions & 0 deletions GPU/GPUCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ class GPUCommon : public GPUInterface, public GPUDebugInterface {
}

void BeginFrame() override;
void UpdateVsyncInterval(bool force);

virtual void FastRunLoop(DisplayList &list);

Expand Down Expand Up @@ -362,6 +363,10 @@ class GPUCommon : public GPUInterface, public GPUDebugInterface {
// Debug stats.
double timeSteppingStarted_;
double timeSpentStepping_;

#ifdef _WIN32
int lastVsync_;
#endif
};

struct CommonCommandTableEntry {
Expand Down
5 changes: 0 additions & 5 deletions GPU/Vulkan/GPU_Vulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
drawEngine_(vulkan_, draw),
depalShaderCache_(draw, vulkan_),
vulkan2D_(vulkan_) {
UpdateVsyncInterval(true);
CheckGPUFeatures();

shaderManagerVulkan_ = new ShaderManagerVulkan(draw, vulkan_);
Expand Down Expand Up @@ -419,10 +418,6 @@ void GPU_Vulkan::InitClear() {
}
}

void GPU_Vulkan::UpdateVsyncInterval(bool force) {
// TODO
}

void GPU_Vulkan::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) {
GPUDebug::NotifyDisplay(framebuf, stride, format);
framebufferManager_->SetDisplayFramebuffer(framebuf, stride, format);
Expand Down
1 change: 0 additions & 1 deletion GPU/Vulkan/GPU_Vulkan.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ class GPU_Vulkan : public GPUCommon {
void InitClear() override;
void CopyDisplayToOutput() override;
void Reinitialize() override;
inline void UpdateVsyncInterval(bool force);

void InitDeviceObjects();
void DestroyDeviceObjects();
Expand Down
6 changes: 5 additions & 1 deletion UI/GameSettingsScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,11 @@ void GameSettingsScreen::CreateViews() {
#endif

#ifdef _WIN32
graphicsSettings->Add(new CheckBox(&g_Config.bVSync, gr->T("VSync")));
CheckBox *vSync = graphicsSettings->Add(new CheckBox(&g_Config.bVSync, gr->T("VSync")));
vSync->OnClick.Add([=](EventParams &e) {
NativeResized();
return UI::EVENT_CONTINUE;
});
#endif

CheckBox *hwTransform = graphicsSettings->Add(new CheckBox(&g_Config.bHardwareTransform, gr->T("Hardware Transform")));
Expand Down
4 changes: 2 additions & 2 deletions Windows/GPU/D3D11Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ D3D11Context::~D3D11Context() {
}

void D3D11Context::SwapBuffers() {
swapChain_->Present(0, 0);
swapChain_->Present(swapInterval_, 0);
draw_->HandleEvent(Draw::Event::PRESENTED, 0, 0, nullptr, nullptr);
}

void D3D11Context::SwapInterval(int interval) {
// Dummy
swapInterval_ = interval;
}

HRESULT D3D11Context::CreateTheDevice(IDXGIAdapter *adapter) {
Expand Down
1 change: 1 addition & 0 deletions Windows/GPU/D3D11Context.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,5 @@ class D3D11Context : public WindowsGraphicsContext {
HMODULE hD3D11;
int width;
int height;
int swapInterval_ = 0;
};
11 changes: 7 additions & 4 deletions Windows/GPU/D3D9Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ static void GetRes(HWND hWnd, int &xres, int &yres) {
}

void D3D9Context::SwapInterval(int interval) {
// Dummy
swapInterval_ = interval;
}

bool D3D9Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) {
Expand Down Expand Up @@ -159,7 +159,7 @@ bool D3D9Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) {
presentParams_.hDeviceWindow = wnd;
presentParams_.EnableAutoDepthStencil = true;
presentParams_.AutoDepthStencilFormat = D3DFMT_D24S8;
presentParams_.PresentationInterval = (g_Config.bVSync) ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE;
presentParams_.PresentationInterval = swapInterval_ == 1 ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE;

if (has9Ex_) {
if (windowed && IsWin7OrLater()) {
Expand Down Expand Up @@ -205,16 +205,19 @@ void D3D9Context::Resize() {
// This should only be called from the emu thread.
int xres, yres;
GetRes(hWnd_, xres, yres);
uint32_t newInterval = swapInterval_ == 1 ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE;;
bool w_changed = presentParams_.BackBufferWidth != xres;
bool h_changed = presentParams_.BackBufferHeight != yres;
bool i_changed = presentParams_.PresentationInterval != newInterval;

if (device_ && (w_changed || h_changed)) {
if (device_ && (w_changed || h_changed || i_changed)) {
draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, 0, 0, nullptr);
presentParams_.BackBufferWidth = xres;
presentParams_.BackBufferHeight = yres;
presentParams_.PresentationInterval = newInterval;
HRESULT hr = device_->Reset(&presentParams_);
if (FAILED(hr)) {
// Had to remove DXGetErrorStringA calls here because dxerr.lib is deprecated and will not link with VS 2015.
// Had to remove DXGetErrorStringA calls here because dxerr.lib is deprecated and will not link with VS 2015.
PanicAlert("Unable to reset D3D9 device");
}
draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, 0, 0, nullptr);
Expand Down
1 change: 1 addition & 0 deletions Windows/GPU/D3D9Context.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,6 @@ class D3D9Context : public WindowsGraphicsContext {
HWND hWnd_; // Holds Our Window Handle
HMODULE hD3D9_;
D3DPRESENT_PARAMETERS presentParams_;
int swapInterval_ = 0;
};

15 changes: 11 additions & 4 deletions Windows/GPU/WindowsVulkanContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,15 @@ static VulkanContext *g_Vulkan;

static VulkanLogOptions g_LogOptions;

static uint32_t FlagsFromConfig() {
uint32_t flags = 0;
flags = g_Config.bVSync ? VULKAN_FLAG_PRESENT_FIFO : VULKAN_FLAG_PRESENT_MAILBOX;
if (g_validate_) {
flags |= VULKAN_FLAG_VALIDATE;
}
return flags;
}

bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_message) {
*error_message = "N/A";

Expand All @@ -100,10 +109,7 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m
VulkanContext::CreateInfo info{};
info.app_name = "PPSSPP";
info.app_ver = gitVer.ToInteger();
info.flags = VULKAN_FLAG_PRESENT_MAILBOX;
if (g_validate_) {
info.flags |= VULKAN_FLAG_VALIDATE;
}
info.flags = FlagsFromConfig();
if (VK_SUCCESS != g_Vulkan->CreateInstance(info)) {
*error_message = g_Vulkan->InitError();
delete g_Vulkan;
Expand Down Expand Up @@ -184,6 +190,7 @@ void WindowsVulkanContext::Resize() {
draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight());
g_Vulkan->DestroyObjects();

g_Vulkan->UpdateFlags(FlagsFromConfig());
g_Vulkan->ReinitSurface();

g_Vulkan->InitObjects();
Expand Down
Loading

0 comments on commit 2ec8295

Please sign in to comment.