From 1f844610d1045a4b3c492c88cf364de1c2466a09 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Fri, 19 Jul 2024 10:56:13 -0500 Subject: [PATCH] [aquamarine] try to fix direct scanout (#6875) * make linux-dmabuf use monitor primary plane formats for ds * add support for monitor connects/disconnects in linux-dmabuf * the weird bug was because ds was global, and disabled on one monitor but enabled on the other * forgot to remove attemptDirectScanout from hyprRenderer * add renderer fallback tranche on ds and a few other improvements * use set when making format table * mitigate ds artifacting and update linux-dmabuf comments with this commit artifacting now only occurs when the client's fps is above the refresh rate of the monitor * use new backend release infra * revert earlier artifacting mitigation that broke stuff ;) * ... i should test before push ;-; --------- Co-authored-by: Vaxry --- src/helpers/Monitor.cpp | 49 +++++ src/helpers/Monitor.hpp | 4 + src/protocols/LinuxDMABUF.cpp | 293 +++++++++++++++++++----------- src/protocols/LinuxDMABUF.hpp | 33 ++-- src/protocols/core/Compositor.cpp | 10 +- src/protocols/types/Buffer.cpp | 3 +- src/protocols/types/Buffer.hpp | 4 + src/render/Renderer.cpp | 56 +----- src/render/Renderer.hpp | 14 +- 9 files changed, 285 insertions(+), 181 deletions(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index b6d2c761..a23b9861 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -10,6 +10,7 @@ #include "../protocols/DRMLease.hpp" #include "../protocols/core/Output.hpp" #include "../managers/PointerManager.hpp" +#include "../protocols/core/Compositor.hpp" #include "sync/SyncTimeline.hpp" #include #include @@ -786,6 +787,54 @@ void CMonitor::scheduleDone() { doneSource = wl_event_loop_add_idle(g_pCompositor->m_sWLEventLoop, ::onDoneSource, this); } +bool CMonitor::attemptDirectScanout() { + if (!mirrors.empty() || isMirror() || g_pHyprRenderer->m_bDirectScanoutBlocked) + return false; // do not DS if this monitor is being mirrored. Will break the functionality. + + if (g_pPointerManager->softwareLockedFor(self.lock())) + return false; + + const auto PCANDIDATE = solitaryClient.lock(); + + if (!PCANDIDATE) + return false; + + const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE); + + if (!PSURFACE || !PSURFACE->current.buffer || PSURFACE->current.buffer->size != vecPixelSize || PSURFACE->current.transform != transform) + return false; + + // we can't scanout shm buffers. + if (!PSURFACE->current.buffer->dmabuf().success) + return false; + + // FIXME: make sure the buffer actually follows the available scanout dmabuf formats + // and comes from the appropriate device. This may implode on multi-gpu!! + + output->state->setBuffer(PSURFACE->current.buffer); + output->state->setPresentationMode(Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC); + + if (!state.test()) + return false; + + timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + Debug::log(TRACE, "presentFeedback for DS"); + PSURFACE->presentFeedback(&now, this, true); + + if (state.commit()) { + if (lastScanout.expired()) { + lastScanout = PCANDIDATE; + Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle); + } + } else { + lastScanout.reset(); + return false; + } + + return true; +} + CMonitorState::CMonitorState(CMonitor* owner) { m_pOwner = owner; } diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 6a56b458..32fc768a 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -133,6 +133,9 @@ class CMonitor { // for tearing PHLWINDOWREF solitaryClient; + // for direct scanout + PHLWINDOWREF lastScanout; + struct { bool canTear = false; bool nextRenderTorn = false; @@ -174,6 +177,7 @@ class CMonitor { int64_t activeSpecialWorkspaceID(); CBox logicalBox(); void scheduleDone(); + bool attemptDirectScanout(); bool m_bEnabled = false; bool m_bRenderingInitPassed = false; diff --git a/src/protocols/LinuxDMABUF.cpp b/src/protocols/LinuxDMABUF.cpp index 1b4391a6..0f9b67a3 100644 --- a/src/protocols/LinuxDMABUF.cpp +++ b/src/protocols/LinuxDMABUF.cpp @@ -23,19 +23,66 @@ static std::optional devIDFromFD(int fd) { return stat.st_rdev; } -CCompiledDMABUFFeedback::CCompiledDMABUFFeedback(dev_t device, std::vector tranches_) { +CDMABUFFormatTable::CDMABUFFormatTable(SDMABUFTranche _rendererTranche, std::vector, SDMABUFTranche>> tranches_) : + rendererTranche(_rendererTranche), monitorTranches(tranches_) { + + std::vector formatsVec; std::set> formats; - for (auto& fmt : tranches_.at(0).formats /* FIXME: multigpu */) { + + // insert formats into vec if they got inserted into set, meaning they're unique + size_t i = 0; + + rendererTranche.indicies.clear(); + for (auto& fmt : rendererTranche.formats) { for (auto& mod : fmt.modifiers) { - formats.insert(std::make_pair<>(fmt.drmFormat, mod)); + auto format = std::make_pair<>(fmt.drmFormat, mod); + auto [_, inserted] = formats.insert(format); + if (inserted) { + // if it was inserted into set, then its unique and will have a new index in vec + rendererTranche.indicies.push_back(i++); + formatsVec.push_back(SDMABUFFormatTableEntry{ + .fmt = fmt.drmFormat, + .modifier = mod, + }); + } else { + // if it wasn't inserted then find its index in vec + auto it = + std::find_if(formatsVec.begin(), formatsVec.end(), [fmt, mod](const SDMABUFFormatTableEntry& oth) { return oth.fmt == fmt.drmFormat && oth.modifier == mod; }); + rendererTranche.indicies.push_back(it - formatsVec.begin()); + } } } - tableLen = formats.size() * sizeof(SDMABUFFeedbackTableEntry); - int fds[2] = {0}; - allocateSHMFilePair(tableLen, &fds[0], &fds[1]); + for (auto& [monitor, tranche] : monitorTranches) { + tranche.indicies.clear(); + for (auto& fmt : tranche.formats) { + for (auto& mod : fmt.modifiers) { + // apparently these can implode on planes, so dont use them + if (mod == DRM_FORMAT_MOD_INVALID || mod == DRM_FORMAT_MOD_LINEAR) + continue; + auto format = std::make_pair<>(fmt.drmFormat, mod); + auto [_, inserted] = formats.insert(format); + if (inserted) { + tranche.indicies.push_back(i++); + formatsVec.push_back(SDMABUFFormatTableEntry{ + .fmt = fmt.drmFormat, + .modifier = mod, + }); + } else { + auto it = std::find_if(formatsVec.begin(), formatsVec.end(), + [fmt, mod](const SDMABUFFormatTableEntry& oth) { return oth.fmt == fmt.drmFormat && oth.modifier == mod; }); + tranche.indicies.push_back(it - formatsVec.begin()); + } + } + } + } - auto arr = (SDMABUFFeedbackTableEntry*)mmap(nullptr, tableLen, PROT_READ | PROT_WRITE, MAP_SHARED, fds[0], 0); + tableSize = formatsVec.size() * sizeof(SDMABUFFormatTableEntry); + + int fds[2] = {0}; + allocateSHMFilePair(tableSize, &fds[0], &fds[1]); + + auto arr = (SDMABUFFormatTableEntry*)mmap(nullptr, tableSize, PROT_READ | PROT_WRITE, MAP_SHARED, fds[0], 0); if (arr == MAP_FAILED) { LOGM(ERR, "mmap failed"); @@ -46,28 +93,14 @@ CCompiledDMABUFFeedback::CCompiledDMABUFFeedback(dev_t device, std::vector> formatsVec; - for (auto& f : formats) { - formatsVec.emplace_back(f); - } + std::copy(formatsVec.begin(), formatsVec.end(), arr); - size_t i = 0; - for (auto& [fmt, mod] : formatsVec) { - LOGM(TRACE, "Feedback: format table index {}: fmt {} mod {}", i, FormatUtils::drmFormatName(fmt), mod); - arr[i++] = SDMABUFFeedbackTableEntry{ - .fmt = fmt, - .modifier = mod, - }; - } + munmap(arr, tableSize); - munmap(arr, tableLen); - - mainDevice = device; - tableFD = fds[1]; - this->formats = formatsVec; + tableFD = fds[1]; } -CCompiledDMABUFFeedback::~CCompiledDMABUFFeedback() { +CDMABUFFormatTable::~CDMABUFFormatTable() { close(tableFD); } @@ -275,12 +308,9 @@ CLinuxDMABUFFeedbackResource::CLinuxDMABUFFeedbackResource(SPsetOnDestroy([this](CZwpLinuxDmabufFeedbackV1* r) { PROTO::linuxDma->destroyResource(this); }); resource->setDestroy([this](CZwpLinuxDmabufFeedbackV1* r) { PROTO::linuxDma->destroyResource(this); }); - auto* feedback = PROTO::linuxDma->defaultFeedback.get(); - - resource->sendFormatTable(feedback->tableFD, feedback->tableLen); - - // send default feedback - sendDefault(); + auto& formatTable = PROTO::linuxDma->formatTable; + resource->sendFormatTable(formatTable->tableFD, formatTable->tableSize); + sendDefaultFeedback(); } CLinuxDMABUFFeedbackResource::~CLinuxDMABUFFeedbackResource() { @@ -291,31 +321,39 @@ bool CLinuxDMABUFFeedbackResource::good() { return resource->resource(); } -void CLinuxDMABUFFeedbackResource::sendDefault() { - auto* feedback = PROTO::linuxDma->defaultFeedback.get(); +void CLinuxDMABUFFeedbackResource::sendTranche(SDMABUFTranche& tranche) { + struct wl_array deviceArr = { + .size = sizeof(tranche.device), + .data = (void*)&tranche.device, + }; + resource->sendTrancheTargetDevice(&deviceArr); + + resource->sendTrancheFlags((zwpLinuxDmabufFeedbackV1TrancheFlags)tranche.flags); + + wl_array indices = { + .size = tranche.indicies.size() * sizeof(tranche.indicies.at(0)), + .data = tranche.indicies.data(), + }; + resource->sendTrancheFormats(&indices); + resource->sendTrancheDone(); +} + +// default tranche is based on renderer (egl) +void CLinuxDMABUFFeedbackResource::sendDefaultFeedback() { + auto mainDevice = PROTO::linuxDma->mainDevice; + auto& formatTable = PROTO::linuxDma->formatTable; struct wl_array deviceArr = { - .size = sizeof(feedback->mainDevice), - .data = (void*)&feedback->mainDevice, + .size = sizeof(mainDevice), + .data = (void*)&mainDevice, }; resource->sendMainDevice(&deviceArr); - // Main tranche - resource->sendTrancheTargetDevice(&deviceArr); - - // Technically, on a single-gpu system, this is correct I believe. - resource->sendTrancheFlags(ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT); - - wl_array indices; - wl_array_init(&indices); - for (size_t i = 0; i < feedback->formats.size(); ++i) { - *((uint16_t*)wl_array_add(&indices, sizeof(uint16_t))) = i; - } - resource->sendTrancheFormats(&indices); - wl_array_release(&indices); - resource->sendTrancheDone(); + sendTranche(formatTable->rendererTranche); resource->sendDone(); + + lastFeedbackWasScanout = false; } CLinuxDMABUFResource::CLinuxDMABUFResource(SP resource_) : resource(resource_) { @@ -366,16 +404,18 @@ bool CLinuxDMABUFResource::good() { } void CLinuxDMABUFResource::sendMods() { - for (auto& [fmt, mod] : PROTO::linuxDma->defaultFeedback->formats) { - if (resource->version() < 3) { - if (mod == DRM_FORMAT_MOD_INVALID || mod == DRM_FORMAT_MOD_LINEAR) - resource->sendFormat(fmt); - continue; + for (auto& fmt : PROTO::linuxDma->formatTable->rendererTranche.formats) { + for (auto& mod : fmt.modifiers) { + if (resource->version() < 3) { + if (mod == DRM_FORMAT_MOD_INVALID || mod == DRM_FORMAT_MOD_LINEAR) + resource->sendFormat(fmt.drmFormat); + continue; + } + + // TODO: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1166 + + resource->sendModifier(fmt.drmFormat, mod >> 32, mod & 0xFFFFFFFF); } - - // TODO: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1166 - - resource->sendModifier(fmt, mod >> 32, mod & 0xFFFFFFFF); } } @@ -392,19 +432,48 @@ CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const mainDevice = *dev; - // FIXME: this will break on multi-gpu - std::vector aqFormats = g_pHyprOpenGL->getDRMFormats(); - - // - SDMABufTranche tranche = { - .device = *dev, - .formats = aqFormats, + SDMABUFTranche eglTranche = { + .device = mainDevice, + .flags = 0, // renderer isnt for ds so dont set flag + .formats = g_pHyprOpenGL->getDRMFormats(), }; - std::vector tches; - tches.push_back(tranche); + std::vector, SDMABUFTranche>> tches; - defaultFeedback = std::make_unique(*dev, tches); + if (g_pCompositor->m_pAqBackend->hasSession()) { + // this assumes there's only 1 device used for both scanout and rendering + // also that each monitor never changes its primary plane + + for (auto& mon : g_pCompositor->m_vMonitors) { + auto tranche = SDMABUFTranche{ + .device = mainDevice, + .flags = ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT, + .formats = mon->output->getRenderFormats(), + }; + tches.push_back(std::make_pair<>(mon, tranche)); + } + + static auto monitorAdded = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any param) { + auto pMonitor = std::any_cast(param); + auto mon = pMonitor->self.lock(); + auto tranche = SDMABUFTranche{ + .device = mainDevice, + .flags = ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT, + .formats = mon->output->getRenderFormats(), + }; + formatTable->monitorTranches.push_back(std::make_pair<>(mon, tranche)); + resetFormatTable(); + }); + + static auto monitorRemoved = g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, SCallbackInfo& info, std::any param) { + auto pMonitor = std::any_cast(param); + auto mon = pMonitor->self.lock(); + std::erase_if(formatTable->monitorTranches, [mon](std::pair, SDMABUFTranche> pair) { return pair.first == mon; }); + resetFormatTable(); + }); + } + + formatTable = std::make_unique(eglTranche, tches); drmDevice* device = nullptr; if (drmGetDeviceFromDevId(mainDevice, 0, &device) != 0) { @@ -429,6 +498,39 @@ CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const }); } +void CLinuxDMABufV1Protocol::resetFormatTable() { + if (!formatTable) + return; + + LOGM(LOG, "Resetting format table"); + + // this might be a big copy + auto newFormatTable = std::make_unique(formatTable->rendererTranche, formatTable->monitorTranches); + + for (auto& feedback : m_vFeedbacks) { + feedback->resource->sendFormatTable(newFormatTable->tableFD, newFormatTable->tableSize); + if (feedback->lastFeedbackWasScanout) { + SP mon; + auto HLSurface = CWLSurface::fromResource(feedback->surface); + if (auto w = HLSurface->getWindow(); w) + if (auto m = g_pCompositor->getMonitorFromID(w->m_iMonitorID); m) + mon = m->self.lock(); + + if (!mon) { + feedback->sendDefaultFeedback(); + return; + } + + updateScanoutTranche(feedback->surface, mon); + } else { + feedback->sendDefaultFeedback(); + } + } + + // delete old table after we sent new one + formatTable = std::move(newFormatTable); +} + CLinuxDMABufV1Protocol::~CLinuxDMABufV1Protocol() { if (mainDeviceFD >= 0) close(mainDeviceFD); @@ -461,8 +563,6 @@ void CLinuxDMABufV1Protocol::destroyResource(CLinuxDMABuffer* resource) { } void CLinuxDMABufV1Protocol::updateScanoutTranche(SP surface, SP pMonitor) { - // TODO: iterating isn't particularly efficient, maybe add a system for addons for surfaces - SP feedbackResource; for (auto& f : m_vFeedbacks) { if (f->surface != surface) @@ -479,49 +579,34 @@ void CLinuxDMABufV1Protocol::updateScanoutTranche(SP surface if (!pMonitor) { LOGM(LOG, "updateScanoutTranche: resetting feedback"); - feedbackResource->sendDefault(); + feedbackResource->sendDefaultFeedback(); return; } - auto* feedback = PROTO::linuxDma->defaultFeedback.get(); + const auto& monitorTranchePair = std::find_if(formatTable->monitorTranches.begin(), formatTable->monitorTranches.end(), + [pMonitor](std::pair, SDMABUFTranche> pair) { return pair.first == pMonitor; }); + + if (monitorTranchePair == formatTable->monitorTranches.end()) { + LOGM(LOG, "updateScanoutTranche: monitor has no tranche"); + return; + } + + auto& monitorTranche = (*monitorTranchePair).second; LOGM(LOG, "updateScanoutTranche: sending a scanout tranche"); - // send a dedicated scanout tranche that contains formats that: - // - match the format of the output - // - are not linear or implicit - struct wl_array deviceArr = { - .size = sizeof(feedback->mainDevice), - .data = (void*)&feedback->mainDevice, + .size = sizeof(mainDevice), + .data = (void*)&mainDevice, }; - feedbackResource->resource->sendTrancheTargetDevice(&deviceArr); - feedbackResource->resource->sendTrancheFlags(ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT); + feedbackResource->resource->sendMainDevice(&deviceArr); - wl_array indices2; - wl_array_init(&indices2); - const auto PRIMARYFORMATS = pMonitor->output->getBackend()->getRenderFormats(); - - for (size_t i = 0; i < feedback->formats.size(); ++i) { - if (feedback->formats.at(i).second == DRM_FORMAT_MOD_LINEAR || feedback->formats.at(i).second == DRM_FORMAT_MOD_INVALID) - continue; - - const auto PRIM_FORMAT = std::find_if(PRIMARYFORMATS.begin(), PRIMARYFORMATS.end(), [&](const auto& e) { return e.drmFormat == feedback->formats.at(i).first; }); - - if (PRIM_FORMAT == PRIMARYFORMATS.end()) - continue; - - if (std::find(PRIM_FORMAT->modifiers.begin(), PRIM_FORMAT->modifiers.end(), feedback->formats.at(i).second) == PRIM_FORMAT->modifiers.end()) - continue; - - LOGM(TRACE, "updateScanoutTranche: index {}: Format {} with modifier {} aka {} passed", i, FormatUtils::drmFormatName(feedback->formats.at(i).first), - feedback->formats.at(i).second, FormatUtils::drmModifierName(feedback->formats.at(i).second)); - *((uint16_t*)wl_array_add(&indices2, sizeof(uint16_t))) = i; - } - - feedbackResource->resource->sendTrancheFormats(&indices2); - wl_array_release(&indices2); - feedbackResource->resource->sendTrancheDone(); + // prioritize scnaout tranche but have renderer fallback tranche + // also yes formats can be duped here because different tranche flags (ds and no ds) + feedbackResource->sendTranche(monitorTranche); + feedbackResource->sendTranche(formatTable->rendererTranche); feedbackResource->resource->sendDone(); + + feedbackResource->lastFeedbackWasScanout = true; } diff --git a/src/protocols/LinuxDMABUF.hpp b/src/protocols/LinuxDMABUF.hpp index 449b4ac9..0e25cdc6 100644 --- a/src/protocols/LinuxDMABUF.hpp +++ b/src/protocols/LinuxDMABUF.hpp @@ -32,34 +32,29 @@ class CLinuxDMABuffer { }; #pragma pack(push, 1) -struct SDMABUFFeedbackTableEntry { +struct SDMABUFFormatTableEntry { uint32_t fmt = 0; char pad[4]; uint64_t modifier = 0; }; #pragma pack(pop) -class SCompiledDMABUFTranche { - dev_t device = 0; - uint32_t flags = 0; - std::vector indices; -}; - -struct SDMABufTranche { +struct SDMABUFTranche { dev_t device = 0; uint32_t flags = 0; std::vector formats; + std::vector indicies; }; -class CCompiledDMABUFFeedback { +class CDMABUFFormatTable { public: - CCompiledDMABUFFeedback(dev_t device, std::vector tranches); - ~CCompiledDMABUFFeedback(); + CDMABUFFormatTable(SDMABUFTranche rendererTranche, std::vector, SDMABUFTranche>> tranches); + ~CDMABUFFormatTable(); - dev_t mainDevice = 0; - int tableFD = -1; - size_t tableLen = 0; - std::vector> formats; + int tableFD = -1; + size_t tableSize = 0; + SDMABUFTranche rendererTranche; + std::vector, SDMABUFTranche>> monitorTranches; }; class CLinuxDMABBUFParamsResource { @@ -87,12 +82,14 @@ class CLinuxDMABUFFeedbackResource { ~CLinuxDMABUFFeedbackResource(); bool good(); - void sendDefault(); + void sendDefaultFeedback(); + void sendTranche(SDMABUFTranche& tranche); SP surface; // optional, for surface feedbacks private: SP resource; + bool lastFeedbackWasScanout = false; friend class CLinuxDMABufV1Protocol; }; @@ -122,13 +119,15 @@ class CLinuxDMABufV1Protocol : public IWaylandProtocol { void destroyResource(CLinuxDMABBUFParamsResource* resource); void destroyResource(CLinuxDMABuffer* resource); + void resetFormatTable(); + // std::vector> m_vManagers; std::vector> m_vFeedbacks; std::vector> m_vParams; std::vector> m_vBuffers; - UP defaultFeedback; + UP formatTable; dev_t mainDevice; int mainDeviceFD = -1; diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index a038bf08..4a5592ae 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -443,7 +443,15 @@ void CWLSurfaceResource::commitPendingState() { // for async buffers, we can only release the buffer once we are unrefing it from current. if (previousBuffer && !previousBuffer->isSynchronous() && !bufferReleased) { - previousBuffer->sendReleaseWithSurface(self.lock()); + if (previousBuffer->lockedByBackend) { + previousBuffer->hlEvents.backendRelease = previousBuffer->events.backendRelease.registerListener([this, previousBuffer](std::any data) { + previousBuffer->sendReleaseWithSurface(self.lock()); + previousBuffer->hlEvents.backendRelease.reset(); + bufferReleased = true; + }); + } else + previousBuffer->sendReleaseWithSurface(self.lock()); + bufferReleased = true; } } diff --git a/src/protocols/types/Buffer.cpp b/src/protocols/types/Buffer.cpp index a347a0fc..0217f7e2 100644 --- a/src/protocols/types/Buffer.cpp +++ b/src/protocols/types/Buffer.cpp @@ -5,5 +5,6 @@ void IHLBuffer::sendRelease() { } void IHLBuffer::sendReleaseWithSurface(SP surf) { - resource->sendReleaseWithSurface(surf); + if (resource && resource->good()) + resource->sendReleaseWithSurface(surf); } diff --git a/src/protocols/types/Buffer.hpp b/src/protocols/types/Buffer.hpp index 2ae542d1..ba8278f3 100644 --- a/src/protocols/types/Buffer.hpp +++ b/src/protocols/types/Buffer.hpp @@ -22,4 +22,8 @@ class IHLBuffer : public Aquamarine::IBuffer { SP texture; bool opaque = false; SP resource; + + struct { + CHyprSignalListener backendRelease; + } hlEvents; }; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 2a2a3da1..2d461227 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1088,53 +1088,6 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SPmirrors.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())) - return false; - - const auto PCANDIDATE = pMonitor->solitaryClient.lock(); - - if (!PCANDIDATE) - return false; - - const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE); - - if (!PSURFACE || !PSURFACE->current.buffer || PSURFACE->current.buffer->size != pMonitor->vecPixelSize || PSURFACE->current.transform != pMonitor->transform) - return false; - - // we can't scanout shm buffers. - if (!PSURFACE->current.buffer->dmabuf().success) - return false; - - // FIXME: make sure the buffer actually follows the available scanout dmabuf formats - // and comes from the appropriate device. This may implode on multi-gpu!! - - pMonitor->output->state->setBuffer(PSURFACE->current.buffer); - - if (!pMonitor->state.test()) - return false; - - timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - Debug::log(TRACE, "presentFeedback for DS"); - PSURFACE->presentFeedback(&now, pMonitor, true); - - if (pMonitor->state.commit()) { - if (m_pLastScanout.expired()) { - m_pLastScanout = PCANDIDATE; - Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle); - } - } else { - m_pLastScanout.reset(); - return false; - } - - return true; -} - void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { static std::chrono::high_resolution_clock::time_point renderStart = std::chrono::high_resolution_clock::now(); static std::chrono::high_resolution_clock::time_point renderStartOverlay = std::chrono::high_resolution_clock::now(); @@ -1214,6 +1167,9 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { g_pLayoutManager->getCurrentLayout()->recalculateMonitor(pMonitor->ID); } + if (!pMonitor->output->needsFrame && pMonitor->forceFullFrames == 0) + return; + // tearing and DS first bool shouldTear = false; if (pMonitor->tearingState.nextRenderTorn) { @@ -1239,11 +1195,11 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { } if (!*PNODIRECTSCANOUT && !shouldTear) { - if (attemptDirectScanout(pMonitor)) { + if (pMonitor->attemptDirectScanout()) { return; - } else if (!m_pLastScanout.expired()) { + } else if (!pMonitor->lastScanout.expired()) { Debug::log(LOG, "Left a direct scanout."); - m_pLastScanout.reset(); + pMonitor->lastScanout.reset(); } } diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 6cabf2d0..72efe8c4 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -76,19 +76,17 @@ class CHyprRenderer { // if RENDER_MODE_NORMAL, provided damage will be written to. // otherwise, it will be the one used. - bool beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, SP buffer = {}, CFramebuffer* fb = nullptr, bool simple = false); - void endRender(); + bool beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, SP buffer = {}, CFramebuffer* fb = nullptr, bool simple = false); + void endRender(); - bool m_bBlockSurfaceFeedback = false; - bool m_bRenderingSnapshot = false; - PHLWINDOWREF m_pLastScanout; - CMonitor* m_pMostHzMonitor = nullptr; - bool m_bDirectScanoutBlocked = false; + bool m_bBlockSurfaceFeedback = false; + bool m_bRenderingSnapshot = false; + CMonitor* m_pMostHzMonitor = nullptr; + bool m_bDirectScanoutBlocked = false; DAMAGETRACKINGMODES damageTrackingModeFromStr(const std::string&); - bool attemptDirectScanout(CMonitor*); void setSurfaceScanoutMode(SP surface, SP monitor); // nullptr monitor resets void initiateManualCrash();