mirror of
https://github.com/hyprwm/Hyprland.git
synced 2025-05-19 08:30:22 -07:00
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
This commit is contained in:
parent
ccbdba7ee2
commit
279b06044c
@ -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) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
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<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 {
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user