summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLee Bousfield <ljbousfield@gmail.com>2025-03-22 11:01:14 -0500
committerGitHub <noreply@github.com>2025-03-22 17:01:14 +0100
commit279b06044c583bfaa207d6fbd373c752967a4a2e (patch)
treed4d8757269b9d04d1ebe570ace2cf6fbfdb8e439 /src
parentccbdba7ee2ccb835306de89a6023134fa6b8006f (diff)
screencopy, render: Use explicit sync for screencopy (#9697)
* screencopy, render: Use explicit sync for screencopy * screencopy: Check if explicit sync is enabled * screencopy: Don't require explicit KMS enabled
Diffstat (limited to 'src')
-rw-r--r--src/helpers/Monitor.cpp5
-rw-r--r--src/helpers/Monitor.hpp3
-rw-r--r--src/protocols/Screencopy.cpp59
-rw-r--r--src/protocols/Screencopy.hpp2
-rw-r--r--src/protocols/core/Compositor.cpp2
-rw-r--r--src/render/Renderer.cpp42
6 files changed, 62 insertions, 51 deletions
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<CSyncTimeline> inTimeline;
- SP<CSyncTimeline> outTimeline;
Hyprutils::OS::CFileDescriptor inFence;
SP<CEGLSync> 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 <algorithm>
+#include <functional>
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);
- resource->sendFailed();
+ auto callback = [this, now, weak = self](bool success) {
+ if (weak.expired())
return;
- }
- } else {
- if (!copyShm()) {
- LOGM(ERR, "Shm copy failed in {:x}", (uintptr_t)this);
+
+ if (!success) {
+ LOGM(ERR, "{} copy failed in {:x}", bufferDMA ? "Dmabuf" : "Shm", (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<void(bool)> callback) {
auto TEXTURE = makeShared<CTexture>(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<void(bool)> 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<Hyprlang::INT>("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();
}
}