From 805a05438981f7bcb2392e0dc653e5f77b5e0e17 Mon Sep 17 00:00:00 2001 From: UjinT34 <41110182+UjinT34@users.noreply.github.com> Date: Wed, 10 Jul 2024 22:20:00 +0300 Subject: [PATCH] Explicit sync fixes (#6829) * explicit sync fixes * more logging * reremove wlroots * close explicit fds on rollback * limit presentFeedback explicit sync to direct scanout mode only * explicit sync for texture render * cursor explicit sync initial * common wait for explicit sync point code * code style fixes --- src/helpers/sync/SyncTimeline.cpp | 4 +- src/managers/PointerManager.cpp | 2 +- src/managers/PointerManager.hpp | 2 + src/protocols/core/Compositor.cpp | 8 ++-- src/protocols/core/Compositor.hpp | 2 +- src/render/OpenGL.cpp | 58 +++++++++++++++++++----- src/render/OpenGL.hpp | 8 +++- src/render/Renderer.cpp | 73 +++++++++++++++++-------------- 8 files changed, 104 insertions(+), 53 deletions(-) diff --git a/src/helpers/sync/SyncTimeline.cpp b/src/helpers/sync/SyncTimeline.cpp index eee2237f..352120ea 100644 --- a/src/helpers/sync/SyncTimeline.cpp +++ b/src/helpers/sync/SyncTimeline.cpp @@ -162,13 +162,13 @@ bool CSyncTimeline::importFromSyncFileFD(uint64_t dst, int fd) { if (drmSyncobjImportSyncFile(drmFD, syncHandle, fd)) { Debug::log(ERR, "importFromSyncFileFD: drmSyncobjImportSyncFile failed"); drmSyncobjDestroy(drmFD, syncHandle); - return -1; + return false; } if (drmSyncobjTransfer(drmFD, handle, dst, syncHandle, 0, 0)) { Debug::log(ERR, "importFromSyncFileFD: drmSyncobjTransfer failed"); drmSyncobjDestroy(drmFD, syncHandle); - return -1; + return false; } drmSyncobjDestroy(drmFD, syncHandle); diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 99d1412f..868376f1 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -448,7 +448,7 @@ void CPointerManager::renderSoftwareCursorsFor(SP pMonitor, timespec* box.x = std::round(box.x); box.y = std::round(box.y); - g_pHyprOpenGL->renderTextureWithDamage(texture, &box, &damage, 1.F); + g_pHyprOpenGL->renderTextureWithDamage(texture, &box, &damage, 1.F, 0, false, false, currentCursorImage.waitTimeline, currentCursorImage.waitPoint); if (currentCursorImage.surface) currentCursorImage.surface->resource()->frame(now); diff --git a/src/managers/PointerManager.hpp b/src/managers/PointerManager.hpp index 68596ab7..6846c382 100644 --- a/src/managers/PointerManager.hpp +++ b/src/managers/PointerManager.hpp @@ -147,6 +147,8 @@ class CPointerManager { CHyprSignalListener destroySurface; CHyprSignalListener commitSurface; + SP waitTimeline = nullptr; + uint64_t waitPoint = 0; } currentCursorImage; // TODO: support various sizes per-output so we can have pixel-perfect cursors Vector2D pointerPos = {0, 0}; diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index c9095e03..6fad79cc 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -447,21 +447,23 @@ void CWLSurfaceResource::commitPendingState() { } } -void CWLSurfaceResource::presentFeedback(timespec* when, CMonitor* pMonitor) { +void CWLSurfaceResource::presentFeedback(timespec* when, CMonitor* pMonitor, bool needsExplicitSync) { frame(when); auto FEEDBACK = makeShared(self.lock()); FEEDBACK->attachMonitor(pMonitor); FEEDBACK->discarded(); PROTO::presentation->queueData(FEEDBACK); - if (!pMonitor || !pMonitor->outTimeline || !syncobj) + if (!pMonitor || !pMonitor->outTimeline || !syncobj || !needsExplicitSync) return; // attach explicit sync g_pHyprRenderer->explicitPresented.emplace_back(self.lock()); - if (syncobj->acquirePoint > pMonitor->lastWaitPoint) + if (syncobj->acquirePoint > pMonitor->lastWaitPoint) { + Debug::log(TRACE, "presentFeedback lastWaitPoint {} -> {}", pMonitor->lastWaitPoint, syncobj->acquirePoint); pMonitor->lastWaitPoint = syncobj->acquirePoint; + } } CWLCompositorResource::CWLCompositorResource(SP resource_) : resource(resource_) { diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp index 0d85a5c9..5e6413c8 100644 --- a/src/protocols/core/Compositor.hpp +++ b/src/protocols/core/Compositor.hpp @@ -122,7 +122,7 @@ class CWLSurfaceResource { void breadthfirst(std::function, const Vector2D&, void*)> fn, void* data); CRegion accumulateCurrentBufferDamage(); - void presentFeedback(timespec* when, CMonitor* pMonitor); + void presentFeedback(timespec* when, CMonitor* pMonitor, bool needsExplicitSync = false); void lockPendingState(); void unlockPendingState(); diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index a7e0e2aa..6a632e20 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -1255,16 +1255,17 @@ void CHyprOpenGLImpl::renderTexture(SP tex, CBox* pBox, float alpha, i scissor((CBox*)nullptr); } -void CHyprOpenGLImpl::renderTextureWithDamage(SP tex, CBox* pBox, CRegion* damage, float alpha, int round, bool discardActive, bool allowCustomUV) { +void CHyprOpenGLImpl::renderTextureWithDamage(SP tex, CBox* pBox, CRegion* damage, float alpha, int round, bool discardActive, bool allowCustomUV, + SP waitTimeline, uint64_t waitPoint) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - renderTextureInternalWithDamage(tex, pBox, alpha, damage, round, discardActive, false, allowCustomUV, true); + renderTextureInternalWithDamage(tex, pBox, alpha, damage, round, discardActive, false, allowCustomUV, true, waitTimeline, waitPoint); scissor((CBox*)nullptr); } void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pBox, float alpha, CRegion* damage, int round, bool discardActive, bool noAA, bool allowCustomUV, - bool allowDim) { + bool allowDim, SP waitTimeline, uint64_t waitPoint) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); RASSERT((tex->m_iTexID > 0), "Attempted to draw NULL texture!"); @@ -1289,6 +1290,13 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB float glMatrix[9]; matrixMultiply(glMatrix, m_RenderData.projection, matrix); + if (waitTimeline != nullptr) { + if (!waitForTimelinePoint(waitTimeline, waitPoint)) { + Debug::log(ERR, "renderTextureInternalWithDamage: failed to wait for explicit sync point {}", waitPoint); + return; + } + } + CShader* shader = nullptr; bool usingFinalShader = false; @@ -2744,20 +2752,24 @@ std::vector CHyprOpenGLImpl::getDRMFormats() { SP CHyprOpenGLImpl::createEGLSync(int fenceFD) { std::vector attribs; - int dupFd = fcntl(fenceFD, F_DUPFD_CLOEXEC, 0); - if (dupFd < 0) { - Debug::log(ERR, "createEGLSync: dup failed"); - return nullptr; - } + int dupFd = -1; + if (fenceFD > 0) { + int dupFd = fcntl(fenceFD, F_DUPFD_CLOEXEC, 0); + if (dupFd < 0) { + Debug::log(ERR, "createEGLSync: dup failed"); + return nullptr; + } - attribs.push_back(EGL_SYNC_NATIVE_FENCE_FD_ANDROID); - attribs.push_back(dupFd); - attribs.push_back(EGL_NONE); + attribs.push_back(EGL_SYNC_NATIVE_FENCE_FD_ANDROID); + attribs.push_back(dupFd); + attribs.push_back(EGL_NONE); + } EGLSyncKHR sync = m_sProc.eglCreateSyncKHR(m_pEglDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs.data()); if (sync == EGL_NO_SYNC_KHR) { Debug::log(ERR, "eglCreateSyncKHR failed"); - close(dupFd); + if (dupFd >= 0) + close(dupFd); return nullptr; } @@ -2766,6 +2778,28 @@ SP CHyprOpenGLImpl::createEGLSync(int fenceFD) { return eglsync; } +bool CHyprOpenGLImpl::waitForTimelinePoint(SP timeline, uint64_t point) { + int fd = timeline->exportAsSyncFileFD(point); + if (fd < 0) { + Debug::log(ERR, "waitForTimelinePoint: failed to get a fd from explicit timeline"); + return false; + } + + auto sync = g_pHyprOpenGL->createEGLSync(fd); + close(fd); + if (!sync) { + Debug::log(ERR, "waitForTimelinePoint: failed to get an eglsync from explicit timeline"); + return false; + } + + if (!sync->wait()) { + Debug::log(ERR, "waitForTimelinePoint: failed to wait on an eglsync from explicit timeline"); + return false; + } + + return true; +} + void SRenderModifData::applyToBox(CBox& box) { if (!enabled) return; diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 4c972a8f..712b87f3 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -6,6 +6,8 @@ #include "../helpers/Timer.hpp" #include "../helpers/math/Math.hpp" #include "../helpers/Format.hpp" +#include "../helpers/sync/SyncTimeline.hpp" +#include #include #include #include @@ -152,7 +154,8 @@ class CHyprOpenGLImpl { void renderRectWithBlur(CBox*, const CColor&, int round = 0, float blurA = 1.f, bool xray = false); void renderRectWithDamage(CBox*, const CColor&, CRegion* damage, int round = 0); void renderTexture(SP, CBox*, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false); - void renderTextureWithDamage(SP, CBox*, CRegion* damage, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false); + void renderTextureWithDamage(SP, CBox*, CRegion* damage, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false, + SP waitTimeline = nullptr, uint64_t waitPoint = 0); void renderTextureWithBlur(SP, CBox*, float a, SP pSurface, int round = 0, bool blockBlurOptimization = false, float blurA = 1.f); void renderRoundedShadow(CBox*, int round, int range, const CColor& color, float a = 1.0); void renderBorder(CBox*, const CGradientValueData&, int round, int borderSize, float a = 1.0, int outerRound = -1 /* use round */); @@ -203,6 +206,7 @@ class CHyprOpenGLImpl { std::vector getDRMFormats(); EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs); SP createEGLSync(int fenceFD); + bool waitForTimelinePoint(SP timeline, uint64_t point); SCurrentRenderData m_RenderData; @@ -284,7 +288,7 @@ class CHyprOpenGLImpl { CFramebuffer* blurMainFramebufferWithDamage(float a, CRegion* damage); void renderTextureInternalWithDamage(SP, CBox* pBox, float a, CRegion* damage, int round = 0, bool discardOpaque = false, bool noAA = false, - bool allowCustomUV = false, bool allowDim = false); + bool allowCustomUV = false, bool allowDim = false, SP = nullptr, uint64_t waitPoint = 0); void renderTexturePrimitive(SP tex, CBox* pBox); void renderSplash(cairo_t* const, cairo_surface_t* const, double offset, const Vector2D& size); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index fe7cab96..90e3ea65 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -17,6 +17,7 @@ #include "../protocols/DRMSyncobj.hpp" #include "../protocols/LinuxDMABUF.hpp" #include "../helpers/sync/SyncTimeline.hpp" +#include "debug/Log.hpp" extern "C" { #include @@ -114,21 +115,8 @@ static void renderSurface(SP surface, int x, int y, void* da // explicit sync: wait for the timeline, if any if (surface->syncobj && surface->syncobj->acquireTimeline) { - int fd = surface->syncobj->acquireTimeline->timeline->exportAsSyncFileFD(surface->syncobj->acquirePoint); - if (fd < 0) { - Debug::log(ERR, "Renderer: failed to get a fd from explicit timeline"); - return; - } - - auto sync = g_pHyprOpenGL->createEGLSync(fd); - close(fd); - if (!sync) { - Debug::log(ERR, "Renderer: failed to get an eglsync from explicit timeline"); - return; - } - - if (!sync->wait()) { - Debug::log(ERR, "Renderer: failed to wait on an eglsync from explicit timeline"); + if (!g_pHyprOpenGL->waitForTimelinePoint(surface->syncobj->acquireTimeline->timeline, surface->syncobj->acquirePoint)) { + Debug::log(ERR, "Renderer: failed to wait for explicit timeline"); return; } } @@ -191,8 +179,10 @@ static void renderSurface(SP surface, int x, int y, void* da } if (windowBox.width <= 1 || windowBox.height <= 1) { - if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) + if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) { + Debug::log(TRACE, "presentFeedback for invisible surface"); surface->presentFeedback(RDATA->when, RDATA->pMonitor); + } return; // invisible } @@ -245,8 +235,10 @@ static void renderSurface(SP surface, int x, int y, void* da g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding, false, true); } - if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) + if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) { + Debug::log(TRACE, "presentFeedback for visible surface"); surface->presentFeedback(RDATA->when, RDATA->pMonitor); + } g_pHyprOpenGL->blend(true); @@ -1099,8 +1091,10 @@ bool CHyprRenderer::attemptDirectScanout(CMonitor* pMonitor) { if (!pMonitor->mirrors.empty() || pMonitor->isMirror() || m_bDirectScanoutBlocked) return false; // do not DS if this monitor is being mirrored. Will break the functionality. - if (g_pPointerManager->softwareLockedFor(pMonitor->self.lock())) + if (g_pPointerManager->softwareLockedFor(pMonitor->self.lock())) { + Debug::log(TRACE, "Direct scanout failed: soft locked / HW cursors failed"); return false; + } const auto PCANDIDATE = pMonitor->solitaryClient.lock(); @@ -1126,7 +1120,8 @@ bool CHyprRenderer::attemptDirectScanout(CMonitor* pMonitor) { timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - PSURFACE->presentFeedback(&now, pMonitor); + Debug::log(TRACE, "presentFeedback for DS"); + PSURFACE->presentFeedback(&now, pMonitor, true); if (pMonitor->state.commit()) { if (m_pLastScanout.expired()) { @@ -1458,16 +1453,27 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(CMonitor* pMonitor) { // apply timelines for explicit sync bool anyExplicit = !explicitPresented.empty(); if (anyExplicit) { - pMonitor->output->state->setExplicitInFence(pMonitor->inTimeline->exportAsSyncFileFD(pMonitor->lastWaitPoint)); + Debug::log(TRACE, "Explicit sync presented begin"); + auto inFence = pMonitor->inTimeline->exportAsSyncFileFD(pMonitor->lastWaitPoint); + if (inFence < 0) + Debug::log(ERR, "Export lastWaitPoint {} as sync explicitInFence failed", pMonitor->lastWaitPoint); + + pMonitor->output->state->setExplicitInFence(inFence); for (auto& e : explicitPresented) { + Debug::log(TRACE, "Explicit sync presented releasePoint {}", e->syncobj && e->syncobj->releaseTimeline ? e->syncobj->releasePoint : -1); if (!e->syncobj || !e->syncobj->releaseTimeline) continue; e->syncobj->releaseTimeline->timeline->transfer(pMonitor->outTimeline, pMonitor->commitSeq, e->syncobj->releasePoint); } explicitPresented.clear(); - pMonitor->output->state->setExplicitOutFence(pMonitor->outTimeline->exportAsSyncFileFD(pMonitor->commitSeq)); + auto outFence = pMonitor->outTimeline->exportAsSyncFileFD(pMonitor->commitSeq); + if (outFence < 0) + Debug::log(ERR, "Export commitSeq {} as sync explicitOutFence failed", pMonitor->commitSeq); + + pMonitor->output->state->setExplicitOutFence(outFence); + Debug::log(TRACE, "Explicit sync presented end"); } pMonitor->lastWaitPoint = 0; @@ -1475,23 +1481,25 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(CMonitor* pMonitor) { const auto COMMITTED_OUT = pMonitor->output->state->state().explicitOutFence; const auto COMMITTED_IN = pMonitor->output->state->state().explicitInFence; - if (!pMonitor->state.commit()) { + bool commited = pMonitor->state.commit(); + if (!commited) { + Debug::log(TRACE, "Monitor state commit failed"); // rollback the buffer to avoid writing to the front buffer that is being // displayed pMonitor->output->swapchain->rollback(); pMonitor->damage.damageEntire(); - return false; } if (COMMITTED_IN >= 0) close(COMMITTED_IN); if (COMMITTED_OUT >= 0) { - pMonitor->outTimeline->importFromSyncFileFD(pMonitor->commitSeq, COMMITTED_OUT); + if (commited) + pMonitor->outTimeline->importFromSyncFileFD(pMonitor->commitSeq, COMMITTED_OUT); close(COMMITTED_OUT); } - return true; + return commited; } void CHyprRenderer::renderWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const CBox& geometry) { @@ -2687,13 +2695,10 @@ void CHyprRenderer::endRender() { if (m_eRenderMode == RENDER_MODE_FULL_FAKE) return; - if (isNvidia() && *PNVIDIAANTIFLICKER) - glFinish(); - if (m_eRenderMode == RENDER_MODE_NORMAL) { PMONITOR->output->state->setBuffer(m_pCurrentBuffer); - if (PMONITOR->output->state->state().explicitOutFence >= 0) { + if (PMONITOR->inTimeline) { auto sync = g_pHyprOpenGL->createEGLSync(-1); if (!sync) { m_pCurrentRenderbuffer->unbind(); @@ -2713,7 +2718,7 @@ void CHyprRenderer::endRender() { return; } - bool ok = PMONITOR->outTimeline->importFromSyncFileFD(PMONITOR->commitSeq, dupedfd); + bool ok = PMONITOR->inTimeline->importFromSyncFileFD(PMONITOR->commitSeq, dupedfd); close(dupedfd); if (!ok) { m_pCurrentRenderbuffer->unbind(); @@ -2722,8 +2727,12 @@ void CHyprRenderer::endRender() { Debug::log(ERR, "renderer: couldn't import from sync file fd in endRender"); return; } - } else - glFlush(); + } else { + if (isNvidia() && *PNVIDIAANTIFLICKER) + glFinish(); + else + glFlush(); + } } m_pCurrentRenderbuffer->unbind();