mirror of
https://github.com/bkaradzic/bgfx.git
synced 2026-06-08 03:13:52 +00:00
Fix BGFX_RESET_VSYNC not affecting secondary swap chains on D3D11, Vulkan, OpenGL (#3675)
Toggling BGFX_RESET_VSYNC via bgfx::reset() only updated the main/init swap chain. Secondary swap chains created through createFrameBuffer(nwh, ...) kept their initial vsync state, leaving framerate capped at refresh rate. D3D12 already handled this correctly. D3D11: forward present flags to FrameBufferD3D11::present so it can pass DXGI_PRESENT_ALLOW_TEARING alongside syncInterval=0. Compute presentFlags once in flip() and reuse for both secondary framebuffers and the main swap chain. Vulkan: in updateResolution, iterate m_windows and call FrameBufferVK::update on each valid secondary framebuffer so SwapChainVK::update sees the new BGFX_RESET_VSYNC and recreates the swapchain with the correct present mode. OpenGL (WGL/EGL): wglSwapIntervalEXT is per-context, eglSwapInterval is per-surface. Cache the desired interval in GlContext::m_swapInterval and re-apply it in makeCurrent() whenever a different context/surface becomes current, so secondary SwapChainGL instances pick up the current value. Also honor the initial BGFX_RESET_VSYNC flag in create() instead of hard-coding 0.
This commit is contained in:
@@ -617,7 +617,8 @@ WL_EGL_IMPORT
|
||||
BGFX_FATAL(success, Fatal::UnableToInitialize, "Failed to set context.");
|
||||
m_current = NULL;
|
||||
|
||||
eglSwapInterval(m_display, 0);
|
||||
m_swapInterval = !!(_resolution.reset & BGFX_RESET_VSYNC) ? 1 : 0;
|
||||
eglSwapInterval(m_display, m_swapInterval);
|
||||
}
|
||||
|
||||
import();
|
||||
@@ -703,7 +704,11 @@ WL_EGL_IMPORT
|
||||
if (NULL != m_display)
|
||||
{
|
||||
const bool vsync = !!(_resolution.reset & BGFX_RESET_VSYNC);
|
||||
EGL_CHECK(eglSwapInterval(m_display, vsync ? 1 : 0) );
|
||||
m_swapInterval = vsync ? 1 : 0;
|
||||
// Apply to the currently-bound (main) surface. Secondary SwapChainGL surfaces
|
||||
// get the value applied lazily in makeCurrent() when they become current, since
|
||||
// eglSwapInterval is per-surface.
|
||||
EGL_CHECK(eglSwapInterval(m_display, m_swapInterval) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -763,6 +768,14 @@ WL_EGL_IMPORT
|
||||
{
|
||||
_swapChain->makeCurrent();
|
||||
}
|
||||
|
||||
// eglSwapInterval is per-surface, so re-apply the cached interval every time a
|
||||
// different surface becomes current. Without this, secondary swap chains keep
|
||||
// their driver default (typically vsync ON) even after resize().
|
||||
if (NULL != m_display)
|
||||
{
|
||||
EGL_CHECK(eglSwapInterval(m_display, m_swapInterval) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ namespace bgfx { namespace gl
|
||||
, m_eglWindow(NULL)
|
||||
#endif
|
||||
, m_msaaContext(false)
|
||||
, m_swapInterval(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -81,6 +82,9 @@ namespace bgfx { namespace gl
|
||||
|
||||
// true when MSAA is handled by the context instead of using MSAA FBO
|
||||
bool m_msaaContext;
|
||||
// Desired eglSwapInterval value, cached so it can be re-applied whenever a swap
|
||||
// chain's surface becomes current (eglSwapInterval is per-surface).
|
||||
int m_swapInterval;
|
||||
};
|
||||
} /* namespace gl */ } // namespace bgfx
|
||||
|
||||
|
||||
@@ -295,9 +295,10 @@ namespace bgfx { namespace gl
|
||||
BGFX_FATAL(0 != result, Fatal::UnableToInitialize, "wglMakeCurrent failed!");
|
||||
m_current = NULL;
|
||||
|
||||
m_swapInterval = !!(_resolution.reset & BGFX_RESET_VSYNC) ? 1 : 0;
|
||||
if (NULL != wglSwapIntervalEXT)
|
||||
{
|
||||
wglSwapIntervalEXT(0);
|
||||
wglSwapIntervalEXT(m_swapInterval);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,10 +330,15 @@ namespace bgfx { namespace gl
|
||||
|
||||
void GlContext::resize(const Resolution& _resolution)
|
||||
{
|
||||
const bool vsync = !!(_resolution.reset & BGFX_RESET_VSYNC);
|
||||
m_swapInterval = vsync ? 1 : 0;
|
||||
|
||||
if (NULL != wglSwapIntervalEXT)
|
||||
{
|
||||
const bool vsync = !!(_resolution.reset & BGFX_RESET_VSYNC);
|
||||
wglSwapIntervalEXT(vsync ? 1 : 0);
|
||||
// Apply to the currently-bound (main) context. Secondary SwapChainGL contexts
|
||||
// get the value applied lazily in makeCurrent() when they become current, since
|
||||
// wglSwapIntervalEXT is per-context on Windows.
|
||||
wglSwapIntervalEXT(m_swapInterval);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,6 +399,14 @@ namespace bgfx { namespace gl
|
||||
{
|
||||
_swapChain->makeCurrent();
|
||||
}
|
||||
|
||||
// wglSwapIntervalEXT is per-context on Windows, so re-apply the cached interval
|
||||
// every time a different context becomes current. Without this, secondary swap
|
||||
// chains keep their driver default (typically vsync ON) even after resize().
|
||||
if (NULL != wglSwapIntervalEXT)
|
||||
{
|
||||
wglSwapIntervalEXT(m_swapInterval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ typedef void (APIENTRYP PFNGLSTENCILOPPROC) (GLenum fail, GLenum zfail, GLenum z
|
||||
, m_context(NULL)
|
||||
, m_hdc(NULL)
|
||||
, m_msaaContext(false)
|
||||
, m_swapInterval(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -95,6 +96,9 @@ typedef void (APIENTRYP PFNGLSTENCILOPPROC) (GLenum fail, GLenum zfail, GLenum z
|
||||
HDC m_hdc;
|
||||
// true when MSAA is handled by the context instead of using MSAA FBO
|
||||
bool m_msaaContext;
|
||||
// Desired wglSwapIntervalEXT value, cached so it can be re-applied whenever a swap
|
||||
// chain's context becomes current (wglSwapIntervalEXT is per-context on Windows).
|
||||
int m_swapInterval;
|
||||
};
|
||||
} /* namespace gl */ } // namespace bgfx
|
||||
|
||||
|
||||
@@ -2386,9 +2386,16 @@ namespace bgfx { namespace d3d11
|
||||
: !!(m_resolution.reset & BGFX_RESET_VSYNC)
|
||||
;
|
||||
|
||||
uint32_t presentFlags = 0;
|
||||
if (!syncInterval
|
||||
&& m_dxgi.tearingSupported() )
|
||||
{
|
||||
presentFlags |= DXGI_PRESENT_ALLOW_TEARING;
|
||||
}
|
||||
|
||||
for (uint32_t ii = 1, num = m_numWindows; ii < num && SUCCEEDED(hr); ++ii)
|
||||
{
|
||||
hr = m_frameBuffers[m_windows[ii].idx].present(syncInterval);
|
||||
hr = m_frameBuffers[m_windows[ii].idx].present(syncInterval, presentFlags);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr) )
|
||||
@@ -2396,14 +2403,6 @@ namespace bgfx { namespace d3d11
|
||||
if (NULL != m_swapChain
|
||||
&& m_needPresent)
|
||||
{
|
||||
uint32_t presentFlags = 0;
|
||||
|
||||
if (!syncInterval
|
||||
&& m_dxgi.tearingSupported() )
|
||||
{
|
||||
presentFlags |= DXGI_PRESENT_ALLOW_TEARING;
|
||||
}
|
||||
|
||||
hr = m_swapChain->Present(syncInterval, presentFlags);
|
||||
|
||||
m_needPresent = false;
|
||||
@@ -5286,11 +5285,11 @@ namespace bgfx { namespace d3d11
|
||||
s_renderD3D11->m_currentDepthStencil = m_dsv;
|
||||
}
|
||||
|
||||
HRESULT FrameBufferD3D11::present(uint32_t _syncInterval)
|
||||
HRESULT FrameBufferD3D11::present(uint32_t _syncInterval, uint32_t _flags)
|
||||
{
|
||||
if (m_needPresent)
|
||||
{
|
||||
HRESULT hr = m_swapChain->Present(_syncInterval, 0);
|
||||
HRESULT hr = m_swapChain->Present(_syncInterval, _flags);
|
||||
hr = !isLost(hr) ? S_OK : hr;
|
||||
m_needPresent = false;
|
||||
return hr;
|
||||
|
||||
@@ -345,7 +345,7 @@ namespace bgfx { namespace d3d11
|
||||
void resolve();
|
||||
void clear(const Clear& _clear, const float _palette[][4]);
|
||||
void set();
|
||||
HRESULT present(uint32_t _syncInterval);
|
||||
HRESULT present(uint32_t _syncInterval, uint32_t _flags);
|
||||
|
||||
ID3D11RenderTargetView* m_rtv[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS-1];
|
||||
ID3D11UnorderedAccessView* m_uav[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS-1];
|
||||
|
||||
@@ -3005,6 +3005,22 @@ VK_IMPORT_DEVICE
|
||||
m_resolution.width = m_backBuffer.m_width;
|
||||
m_resolution.height = m_backBuffer.m_height;
|
||||
|
||||
// Propagate reset flags (e.g. BGFX_RESET_VSYNC) to secondary window swapchains,
|
||||
// otherwise they'd keep their original present mode and ignore the reset.
|
||||
for (uint16_t ii = 0; ii < m_numWindows; ++ii)
|
||||
{
|
||||
if (!isValid(m_windows[ii]) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
FrameBufferVK& fb = m_frameBuffers[m_windows[ii].idx];
|
||||
Resolution fbResolution = m_resolution;
|
||||
fbResolution.width = fb.m_width;
|
||||
fbResolution.height = fb.m_height;
|
||||
fb.update(m_commandBuffer, fbResolution);
|
||||
}
|
||||
|
||||
postReset();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user