From d84699d8e5e984422da37595ee41fc0d8d93fef5 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Sat, 19 Jul 2025 12:38:41 +0200 Subject: [PATCH] opengl: detect android fence support and disable explicit if it's missing (#11077) Checks for explicit sync support via the android fences, and falls back to implicit sync if it isn't --- src/helpers/MonitorFrameScheduler.cpp | 17 +++++++++-------- src/helpers/MonitorFrameScheduler.hpp | 1 + src/managers/ProtocolManager.cpp | 2 +- src/render/OpenGL.cpp | 17 ++++++++++++++++- src/render/OpenGL.hpp | 3 +++ src/render/Renderer.cpp | 22 +++++++++++++++++----- 6 files changed, 47 insertions(+), 15 deletions(-) diff --git a/src/helpers/MonitorFrameScheduler.cpp b/src/helpers/MonitorFrameScheduler.cpp index 097824547..1ab4f19bd 100644 --- a/src/helpers/MonitorFrameScheduler.cpp +++ b/src/helpers/MonitorFrameScheduler.cpp @@ -8,10 +8,15 @@ CMonitorFrameScheduler::CMonitorFrameScheduler(PHLMONITOR m) : m_monitor(m) { ; } -void CMonitorFrameScheduler::onSyncFired() { +bool CMonitorFrameScheduler::newSchedulingEnabled() { static auto PENABLENEW = CConfigValue("render:new_render_scheduling"); - if (!*PENABLENEW) + return *PENABLENEW && g_pHyprOpenGL->explicitSyncSupported(); +} + +void CMonitorFrameScheduler::onSyncFired() { + + if (!newSchedulingEnabled()) return; // Sync fired: reset submitted state, set as rendered. Check the last render time. If we are running @@ -36,9 +41,7 @@ void CMonitorFrameScheduler::onSyncFired() { } void CMonitorFrameScheduler::onPresented() { - static auto PENABLENEW = CConfigValue("render:new_render_scheduling"); - - if (!*PENABLENEW) + if (!newSchedulingEnabled()) return; if (!m_pendingThird) @@ -65,8 +68,6 @@ void CMonitorFrameScheduler::onPresented() { } void CMonitorFrameScheduler::onFrame() { - static auto PENABLENEW = CConfigValue("render:new_render_scheduling"); - if (!canRender()) return; @@ -83,7 +84,7 @@ void CMonitorFrameScheduler::onFrame() { m_monitor->m_tearingState.frameScheduledWhileBusy = false; } - if (!*PENABLENEW) { + if (!newSchedulingEnabled()) { m_monitor->m_lastPresentationTimer.reset(); g_pHyprRenderer->renderMonitor(m_monitor.lock()); diff --git a/src/helpers/MonitorFrameScheduler.hpp b/src/helpers/MonitorFrameScheduler.hpp index f26633420..e6eab9c91 100644 --- a/src/helpers/MonitorFrameScheduler.hpp +++ b/src/helpers/MonitorFrameScheduler.hpp @@ -24,6 +24,7 @@ class CMonitorFrameScheduler { private: bool canRender(); void onFinishRender(); + bool newSchedulingEnabled(); bool m_renderAtFrame = true; bool m_pendingThird = false; diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 193b022c1..eac6dee08 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -210,7 +210,7 @@ CProtocolManager::CProtocolManager() { else lease.reset(); - if (!PROTO::sync) + if (g_pHyprOpenGL->m_exts.EGL_ANDROID_native_fence_sync_ext && !PROTO::sync) PROTO::sync = makeUnique(&wp_linux_drm_syncobj_manager_v1_interface, 1, "DRMSyncobj"); } diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 65d0cf388..b1dfc0734 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -257,7 +257,7 @@ EGLDeviceEXT CHyprOpenGLImpl::eglDeviceFromDRMFD(int drmFD) { CHyprOpenGLImpl::CHyprOpenGLImpl() : m_drmFD(g_pCompositor->m_drmFD) { const std::string EGLEXTENSIONS = (const char*)eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); - Debug::log(LOG, "Supported EGL extensions: ({}) {}", std::ranges::count(EGLEXTENSIONS, ' '), EGLEXTENSIONS); + Debug::log(LOG, "Supported EGL global extensions: ({}) {}", std::ranges::count(EGLEXTENSIONS, ' '), EGLEXTENSIONS); m_exts.KHR_display_reference = EGLEXTENSIONS.contains("KHR_display_reference"); @@ -344,6 +344,15 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() : m_drmFD(g_pCompositor->m_drmFD) { if (!m_exts.EXT_image_dma_buf_import || !m_exts.EXT_image_dma_buf_import_modifiers) Debug::log(WARN, "Your GPU does not support DMABUFs, this will possibly cause issues and will take a hit on the performance."); + const std::string EGLEXTENSIONS_DISPLAY = (const char*)eglQueryString(m_eglDisplay, EGL_EXTENSIONS); + + Debug::log(LOG, "Supported EGL display extensions: ({}) {}", std::ranges::count(EGLEXTENSIONS_DISPLAY, ' '), EGLEXTENSIONS_DISPLAY); + + m_exts.EGL_ANDROID_native_fence_sync_ext = EGLEXTENSIONS_DISPLAY.contains("EGL_ANDROID_native_fence_sync"); + + if (!m_exts.EGL_ANDROID_native_fence_sync_ext) + Debug::log(WARN, "Your GPU does not support explicit sync via the EGL_ANDROID_native_fence_sync extension."); + #ifdef USE_TRACY_GPU loadGLProc(&glQueryCounter, "glQueryCounterEXT"); @@ -3054,6 +3063,10 @@ uint32_t CHyprOpenGLImpl::getPreferredReadFormat(PHLMONITOR pMonitor) { return pMonitor->m_output->state->state().drmFormat; } +bool CHyprOpenGLImpl::explicitSyncSupported() { + return m_exts.EGL_ANDROID_native_fence_sync_ext; +} + std::vector CHyprOpenGLImpl::getDRMFormats() { return m_drmFormats; } @@ -3120,6 +3133,8 @@ float SRenderModifData::combinedScale() { } UP CEGLSync::create() { + RASSERT(g_pHyprOpenGL->m_exts.EGL_ANDROID_native_fence_sync_ext, "Tried to create an EGL sync when syncs are not supported on the gpu"); + EGLSyncKHR sync = g_pHyprOpenGL->m_proc.eglCreateSyncKHR(g_pHyprOpenGL->m_eglDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr); if (sync == EGL_NO_SYNC_KHR) { diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 4c6f55f92..c5040e0ea 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -253,6 +253,8 @@ class CHyprOpenGLImpl { void ensureLockTexturesRendered(bool load); + bool explicitSyncSupported(); + bool m_shadersInitialized = false; SP m_shaders; @@ -297,6 +299,7 @@ class CHyprOpenGLImpl { bool KHR_display_reference = false; bool IMG_context_priority = false; bool EXT_create_context_robustness = false; + bool EGL_ANDROID_native_fence_sync_ext = false; } m_exts; SP m_screencopyDeniedTexture; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index e9797fbe4..13f8ff4d4 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -2326,6 +2326,22 @@ void CHyprRenderer::endRender(const std::function& renderingDoneCallback if (m_renderMode == RENDER_MODE_NORMAL) PMONITOR->m_output->state->setBuffer(m_currentBuffer); + if (!g_pHyprOpenGL->explicitSyncSupported()) { + Debug::log(TRACE, "renderer: Explicit sync unsupported, falling back to implicit in endRender"); + + // nvidia doesn't have implicit sync, so we have to explicitly wait here + if (isNvidia() && *PNVIDIAANTIFLICKER) + glFinish(); + else + glFlush(); // mark an implicit sync point + + m_usedAsyncBuffers.clear(); // release all buffer refs and hope implicit sync works + if (renderingDoneCallback) + renderingDoneCallback(); + + return; + } + UP eglSync = CEGLSync::create(); if (eglSync && eglSync->isValid()) { for (auto const& buf : m_usedAsyncBuffers) { @@ -2350,11 +2366,7 @@ void CHyprRenderer::endRender(const std::function& renderingDoneCallback PMONITOR->m_output->state->setExplicitInFence(PMONITOR->m_inFence.get()); } } else { - Debug::log(ERR, "renderer: couldn't use EGLSync for explicit gpu synchronization"); - - // nvidia doesn't have implicit sync, so we have to explicitly wait here - if (isNvidia() && *PNVIDIAANTIFLICKER) - glFinish(); + Debug::log(ERR, "renderer: Explicit sync failed, releasing resources"); m_usedAsyncBuffers.clear(); // release all buffer refs and hope implicit sync works if (renderingDoneCallback)