diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 30c15e4e..fe8ab9df 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -57,8 +57,7 @@ void CMonitor::onConnect(bool noRule) { g_pEventLoopManager->doLater([] { g_pConfigManager->ensurePersistentWorkspacesPresent(); }); if (output->supportsExplicit) { - inTimeline = CSyncTimeline::create(output->getBackend()->drmFD()); - outTimeline = CSyncTimeline::create(output->getBackend()->drmFD()); + inTimeline = CSyncTimeline::create(output->getBackend()->drmFD()); } listeners.frame = output->events.frame.registerListener([this](std::any d) { onMonitorFrame(); }); @@ -1421,8 +1420,6 @@ bool CMonitor::attemptDirectScanout() { } } - commitSeq++; - bool ok = output->commit(); if (!ok && DOEXPLICIT) { diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index b55f0116..a7d97c8d 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -140,10 +140,9 @@ class CMonitor { // explicit sync SP inTimeline; - SP outTimeline; Hyprutils::OS::CFileDescriptor inFence; SP eglSync; - uint64_t commitSeq = 0; + uint64_t inTimelinePoint = 0; PHLMONITORREF self; diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index aae5caf1..3fd9b9f2 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -12,6 +12,7 @@ #include "../helpers/Format.hpp" #include +#include CScreencopyFrame::~CScreencopyFrame() { if (buffer && buffer->locked()) @@ -174,39 +175,42 @@ void CScreencopyFrame::share() { timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - if (bufferDMA) { - if (!copyDmabuf()) { - LOGM(ERR, "Dmabuf copy failed in {:x}", (uintptr_t)this); + auto callback = [this, now, weak = self](bool success) { + if (weak.expired()) + return; + + if (!success) { + LOGM(ERR, "{} copy failed in {:x}", bufferDMA ? "Dmabuf" : "Shm", (uintptr_t)this); resource->sendFailed(); return; } - } else { - if (!copyShm()) { - LOGM(ERR, "Shm copy failed in {:x}", (uintptr_t)this); - resource->sendFailed(); - return; + + resource->sendFlags((zwlrScreencopyFrameV1Flags)0); + if (withDamage) { + // TODO: add a damage ring for this. + resource->sendDamage(0, 0, buffer->size.x, buffer->size.y); } - } - resource->sendFlags((zwlrScreencopyFrameV1Flags)0); - if (withDamage) { - // TODO: add a damage ring for this. - resource->sendDamage(0, 0, buffer->size.x, buffer->size.y); - } + uint32_t tvSecHi = (sizeof(now.tv_sec) > 4) ? now.tv_sec >> 32 : 0; + uint32_t tvSecLo = now.tv_sec & 0xFFFFFFFF; + resource->sendReady(tvSecHi, tvSecLo, now.tv_nsec); + }; - uint32_t tvSecHi = (sizeof(now.tv_sec) > 4) ? now.tv_sec >> 32 : 0; - uint32_t tvSecLo = now.tv_sec & 0xFFFFFFFF; - resource->sendReady(tvSecHi, tvSecLo, now.tv_nsec); + if (bufferDMA) + copyDmabuf(callback); + else + callback(copyShm()); } -bool CScreencopyFrame::copyDmabuf() { +void CScreencopyFrame::copyDmabuf(std::function callback) { auto TEXTURE = makeShared(pMonitor->output->state->state().buffer); CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX}; if (!g_pHyprRenderer->beginRender(pMonitor.lock(), fakeDamage, RENDER_MODE_TO_BUFFER, buffer.lock(), nullptr, true)) { LOGM(ERR, "Can't copy: failed to begin rendering to dma frame"); - return false; + callback(false); + return; } CBox monbox = CBox{0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y} @@ -221,9 +225,18 @@ bool CScreencopyFrame::copyDmabuf() { g_pHyprOpenGL->m_RenderData.blockScreenShader = true; g_pHyprRenderer->endRender(); - LOGM(TRACE, "Copied frame via dma"); - - return true; + auto explicitOptions = g_pHyprRenderer->getExplicitSyncSettings(pMonitor->output); + if (pMonitor->inTimeline && explicitOptions.explicitEnabled) { + pMonitor->inTimeline->addWaiter( + [callback]() { + LOGM(TRACE, "Copied frame via dma with explicit sync"); + callback(true); + }, + pMonitor->inTimelinePoint, 0); + } else { + LOGM(TRACE, "Copied frame via dma"); + callback(true); + } } bool CScreencopyFrame::copyShm() { @@ -278,6 +291,8 @@ bool CScreencopyFrame::copyShm() { const auto drmFmt = NFormatUtils::getPixelFormatFromDRM(shm.format); uint32_t packStride = NFormatUtils::minStride(drmFmt, box.w); + // This could be optimized by using a pixel buffer object to make this async, + // but really clients should just use a dma buffer anyways. if (packStride == (uint32_t)shm.stride) { glReadPixels(0, 0, box.w, box.h, glFormat, PFORMAT->glType, pixelData); } else { diff --git a/src/protocols/Screencopy.hpp b/src/protocols/Screencopy.hpp index 62c9f8b8..3b46b0b8 100644 --- a/src/protocols/Screencopy.hpp +++ b/src/protocols/Screencopy.hpp @@ -73,7 +73,7 @@ class CScreencopyFrame { CBox box = {}; void copy(CZwlrScreencopyFrameV1* pFrame, wl_resource* buffer); - bool copyDmabuf(); + void copyDmabuf(std::function callback); bool copyShm(); void share(); diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index e922c93e..6b47b503 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -522,7 +522,7 @@ void CWLSurfaceResource::presentFeedback(timespec* when, PHLMONITOR pMonitor, bo FEEDBACK->presented(); PROTO::presentation->queueData(FEEDBACK); - if (!pMonitor || !pMonitor->outTimeline || !syncobj) + if (!pMonitor || !pMonitor->inTimeline || !syncobj) return; // attach explicit sync diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index a89fd329..cf77c000 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1447,8 +1447,6 @@ static hdr_output_metadata createHDRMetadata(SImageDescription settings, A } bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { - pMonitor->commitSeq++; - static auto PPASS = CConfigValue("render:cm_fs_passthrough"); const bool PHDR = pMonitor->imageDescription.transferFunction == CM_TRANSFER_FUNCTION_ST2084_PQ; @@ -2250,37 +2248,39 @@ void CHyprRenderer::endRender() { if (m_eRenderMode == RENDER_MODE_FULL_FAKE) return; - if (m_eRenderMode == RENDER_MODE_NORMAL) { + if (m_eRenderMode == RENDER_MODE_NORMAL) PMONITOR->output->state->setBuffer(m_pCurrentBuffer); - auto explicitOptions = getExplicitSyncSettings(PMONITOR->output); + auto explicitOptions = getExplicitSyncSettings(PMONITOR->output); - if (PMONITOR->inTimeline && explicitOptions.explicitEnabled && explicitOptions.explicitKMSEnabled) { - PMONITOR->eglSync = g_pHyprOpenGL->createEGLSync(); - if (!PMONITOR->eglSync) { - Debug::log(ERR, "renderer: couldn't create an EGLSync for out in endRender"); - return; - } + if (PMONITOR->inTimeline && explicitOptions.explicitEnabled) { + PMONITOR->eglSync = g_pHyprOpenGL->createEGLSync(); + if (!PMONITOR->eglSync) { + Debug::log(ERR, "renderer: couldn't create an EGLSync for out in endRender"); + return; + } - bool ok = PMONITOR->inTimeline->importFromSyncFileFD(PMONITOR->commitSeq, PMONITOR->eglSync->fd()); - if (!ok) { - Debug::log(ERR, "renderer: couldn't import from sync file fd in endRender"); - return; - } + PMONITOR->inTimelinePoint++; + bool ok = PMONITOR->inTimeline->importFromSyncFileFD(PMONITOR->inTimelinePoint, PMONITOR->eglSync->fd()); + if (!ok) { + Debug::log(ERR, "renderer: couldn't import from sync file fd in endRender"); + return; + } - PMONITOR->inFence = CFileDescriptor{PMONITOR->inTimeline->exportAsSyncFileFD(PMONITOR->commitSeq)}; + if (m_eRenderMode == RENDER_MODE_NORMAL && explicitOptions.explicitKMSEnabled) { + PMONITOR->inFence = CFileDescriptor{PMONITOR->inTimeline->exportAsSyncFileFD(PMONITOR->inTimelinePoint)}; if (!PMONITOR->inFence.isValid()) { Debug::log(ERR, "renderer: couldn't export from sync timeline in endRender"); return; } PMONITOR->output->state->setExplicitInFence(PMONITOR->inFence.get()); - } else { - if (isNvidia() && *PNVIDIAANTIFLICKER) - glFinish(); - else - glFlush(); } + } else { + if (isNvidia() && *PNVIDIAANTIFLICKER) + glFinish(); + else + glFlush(); } }