From 5115f1993c7b65b57bddcda095f573a4caa56f41 Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Wed, 24 Jul 2024 23:13:15 +0300 Subject: [PATCH 1/7] add cursor fallback swapchain --- src/helpers/Monitor.cpp | 40 +++++++++++++++++++++++++++++++++ src/helpers/Monitor.hpp | 10 ++++++--- src/managers/PointerManager.cpp | 21 ++--------------- 3 files changed, 49 insertions(+), 22 deletions(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 635427d14a2..b0ac1a1bc5e 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -396,6 +396,30 @@ int CMonitor::findAvailableDefaultWS() { return INT32_MAX; // shouldn't be reachable } +SP CMonitor::resizeSwapchain(SP swapchain, Vector2D size, bool isCursor) { + if (!swapchain || size != swapchain->currentOptions().size) { + + if (!swapchain) + swapchain = Aquamarine::CSwapchain::create(output->getBackend()->preferredAllocator(), output->getBackend()); + + auto options = swapchain->currentOptions(); + options.size = size; + options.length = 2; + options.scanout = true; + options.cursor = isCursor; + options.multigpu = output->getBackend()->preferredAllocator()->drmFD() != g_pCompositor->m_iDRMFD; + // We do not set the format. If it's unset (DRM_FORMAT_INVALID) then the swapchain will pick for us, + // but if it's set, we don't wanna change it. + + if (!swapchain->reconfigure(options)) { + Debug::log(TRACE, "Failed to reconfigure {} swapchain", isCursor ? "cursor" : "cursor fallback"); + return nullptr; + } + } + + return swapchain; +} + void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) { // Workspace std::string newDefaultWorkspaceName = ""; @@ -835,6 +859,22 @@ bool CMonitor::attemptDirectScanout() { return true; } +bool CMonitor::resizeCursorSwapchain(Vector2D size) { + auto swapchain = resizeSwapchain(cursorSwapchain, size, true); + if (!cursorSwapchain) + cursorSwapchain = swapchain; + + return !!swapchain; +} + +bool CMonitor::resizeCursorFallbackSwapchain(Vector2D size) { + auto swapchain = resizeSwapchain(cursorFallbackSwapchain, size, false); + if (!cursorFallbackSwapchain) + cursorFallbackSwapchain = swapchain; + + return !!swapchain; +} + CMonitorState::CMonitorState(CMonitor* owner) { m_pOwner = owner; } diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 32fc768a16f..2898d0a84c1 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -100,6 +100,7 @@ class CMonitor { std::optional forceSize; SP currentMode; SP cursorSwapchain; + SP cursorFallbackSwapchain; bool dpmsStatus = true; bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it. @@ -178,6 +179,8 @@ class CMonitor { CBox logicalBox(); void scheduleDone(); bool attemptDirectScanout(); + bool resizeCursorSwapchain(Vector2D size); + bool resizeCursorFallbackSwapchain(Vector2D size); bool m_bEnabled = false; bool m_bRenderingInitPassed = false; @@ -189,10 +192,11 @@ class CMonitor { } private: - void setupDefaultWS(const SMonitorRule&); - int findAvailableDefaultWS(); + void setupDefaultWS(const SMonitorRule&); + int findAvailableDefaultWS(); + SP resizeSwapchain(SP swapchain, Vector2D size, bool isCursor); - wl_event_source* doneSource = nullptr; + wl_event_source* doneSource = nullptr; struct { CHyprSignalListener frame; diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 3b4256880f4..323a354a2f3 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -374,25 +374,8 @@ SP CPointerManager::renderHWCursorBuffer(SPmonitor->cursorSwapchain || maxSize != state->monitor->cursorSwapchain->currentOptions().size) { - - if (!state->monitor->cursorSwapchain) - state->monitor->cursorSwapchain = Aquamarine::CSwapchain::create(state->monitor->output->getBackend()->preferredAllocator(), state->monitor->output->getBackend()); - - auto options = state->monitor->cursorSwapchain->currentOptions(); - options.size = maxSize; - options.length = 2; - options.scanout = true; - options.cursor = true; - options.multigpu = state->monitor->output->getBackend()->preferredAllocator()->drmFD() != g_pCompositor->m_iDRMFD; - // We do not set the format. If it's unset (DRM_FORMAT_INVALID) then the swapchain will pick for us, - // but if it's set, we don't wanna change it. - - if (!state->monitor->cursorSwapchain->reconfigure(options)) { - Debug::log(TRACE, "Failed to reconfigure cursor swapchain"); - return nullptr; - } - } + if (!state->monitor->resizeCursorSwapchain(maxSize)) + return nullptr; // if we already rendered the cursor, revert the swapchain to avoid rendering the cursor over // the current front buffer From 0a9544013112ae486705bf915adfa34933cfe6be Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Thu, 25 Jul 2024 02:55:34 +0300 Subject: [PATCH 2/7] first attempt --- src/helpers/Monitor.cpp | 8 ++- src/managers/PointerManager.cpp | 100 +++++++++++++++++++++++++------- 2 files changed, 86 insertions(+), 22 deletions(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index b0ac1a1bc5e..812662e9ba7 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -399,8 +399,10 @@ int CMonitor::findAvailableDefaultWS() { SP CMonitor::resizeSwapchain(SP swapchain, Vector2D size, bool isCursor) { if (!swapchain || size != swapchain->currentOptions().size) { - if (!swapchain) + if (!swapchain) { + Debug::log(TRACE, "creating new cursor {} swapchain", isCursor); swapchain = Aquamarine::CSwapchain::create(output->getBackend()->preferredAllocator(), output->getBackend()); + } auto options = swapchain->currentOptions(); options.size = size; @@ -408,6 +410,8 @@ SP CMonitor::resizeSwapchain(SP options.scanout = true; options.cursor = isCursor; options.multigpu = output->getBackend()->preferredAllocator()->drmFD() != g_pCompositor->m_iDRMFD; + if (!isCursor && cursorSwapchain) + options.format = cursorSwapchain->currentOptions().format; // We do not set the format. If it's unset (DRM_FORMAT_INVALID) then the swapchain will pick for us, // but if it's set, we don't wanna change it. @@ -860,6 +864,7 @@ bool CMonitor::attemptDirectScanout() { } bool CMonitor::resizeCursorSwapchain(Vector2D size) { + Debug::log(TRACE, "resizeCursorSwapchain"); auto swapchain = resizeSwapchain(cursorSwapchain, size, true); if (!cursorSwapchain) cursorSwapchain = swapchain; @@ -868,6 +873,7 @@ bool CMonitor::resizeCursorSwapchain(Vector2D size) { } bool CMonitor::resizeCursorFallbackSwapchain(Vector2D size) { + Debug::log(TRACE, "resizeCursorFallbackSwapchain"); auto swapchain = resizeSwapchain(cursorFallbackSwapchain, size, false); if (!cursorFallbackSwapchain) cursorFallbackSwapchain = swapchain; diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 323a354a2f3..f5903eb3fde 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -6,6 +6,10 @@ #include "../protocols/core/Compositor.hpp" #include "eventLoop/EventLoopManager.hpp" #include "SeatManager.hpp" +#include "render/OpenGL.hpp" +#include +#include +#include #include #include @@ -396,35 +400,34 @@ SP CPointerManager::renderHWCursorBuffer(SPmakeEGLCurrent(); g_pHyprOpenGL->m_RenderData.pMonitor = state->monitor.get(); - auto RBO = g_pHyprRenderer->getOrCreateRenderbuffer(buf, state->monitor->cursorSwapchain->currentOptions().format); + bool needsFallback = false; + SP fallback; + + auto RBO = g_pHyprRenderer->getOrCreateRenderbuffer(buf, state->monitor->cursorSwapchain->currentOptions().format); if (!RBO) { Debug::log(TRACE, "Failed to create cursor RB with format {}, mod {}", buf->dmabuf().format, buf->dmabuf().modifier); static auto PDUMB = CConfigValue("cursor:allow_dumb_copy"); if (!*PDUMB) return nullptr; - auto bufData = buf->beginDataPtr(0); - auto bufPtr = std::get<0>(bufData); - - // clear buffer - memset(bufPtr, 0, std::get<2>(bufData)); + needsFallback = true; - auto texBuffer = currentCursorImage.pBuffer ? currentCursorImage.pBuffer : currentCursorImage.surface->resource()->current.buffer; + if (!state->monitor->resizeCursorFallbackSwapchain(maxSize)) + return nullptr; - if (texBuffer) { - auto textAttrs = texBuffer->shm(); - auto texData = texBuffer->beginDataPtr(GBM_BO_TRANSFER_WRITE); - auto texPtr = std::get<0>(texData); - Debug::log(TRACE, "cursor texture {}x{} {} {} {}", textAttrs.size.x, textAttrs.size.y, (void*)texPtr, textAttrs.format, textAttrs.stride); - // copy cursor texture - for (int i = 0; i < texBuffer->shm().size.y; i++) - memcpy(bufPtr + i * buf->dmabuf().strides[0], texPtr + i * textAttrs.stride, textAttrs.stride); + fallback = state->monitor->cursorFallbackSwapchain->next(nullptr); + if (!fallback) { + Debug::log(TRACE, "Failed to acquire a buffer from the cursor fallback swapchain"); + return nullptr; } - - buf->endDataPtr(); - - return buf; - } + RBO = g_pHyprRenderer->getOrCreateRenderbuffer(fallback, state->monitor->cursorFallbackSwapchain->currentOptions().format); + if (!RBO) { + Debug::log(TRACE, "Failed to create cursor RB with format {}, mod {}", fallback->dmabuf().format, fallback->dmabuf().modifier); + return nullptr; + } else + Debug::log(TRACE, "Created cursor RB with format {}, mod {}", fallback->dmabuf().format, fallback->dmabuf().modifier); + } else + Debug::log(TRACE, "Created cursor RB with format {}, mod {}", buf->dmabuf().format, buf->dmabuf().modifier); RBO->bind(); @@ -438,11 +441,66 @@ SP CPointerManager::renderHWCursorBuffer(SPrenderTexture(texture, &xbox, 1.F); g_pHyprOpenGL->end(); - glFlush(); + if (needsFallback) + glFinish(); + else + glFlush(); g_pHyprOpenGL->m_RenderData.pMonitor = nullptr; g_pHyprRenderer->onRenderbufferDestroy(RBO.get()); + if (needsFallback) { + // wlroots tries to blit here but it'll fail the same way we've got here in the first place + auto bufAttrs = buf->dmabuf(); + Debug::log(TRACE, "mapping cursor buffer for writing"); + auto bufData = buf->beginDataPtr(GBM_BO_TRANSFER_WRITE); + auto bufPtr = std::get<0>(bufData); + + auto textAttrs = fallback->dmabuf(); + Debug::log(TRACE, "mapping cursor fallback buffer for reading"); + auto texData = fallback->beginDataPtr(GBM_BO_TRANSFER_WRITE); + auto texPtr = std::get<0>(texData); + Debug::log(TRACE, "cursor buffer {}x{} {} format={}({}) stride={}({})", bufAttrs.size.x, bufAttrs.size.y, (void*)bufPtr, bufAttrs.format, std::get<1>(bufData), + bufAttrs.strides[0], std::get<2>(bufData)); + Debug::log(TRACE, "cursor fallback buffer {}x{} {} format={}({}) stride={}({})", textAttrs.size.x, textAttrs.size.y, (void*)texPtr, textAttrs.format, std::get<1>(texData), + textAttrs.strides[0], std::get<2>(texData)); + + const auto dma = fallback->dmabuf(); + + auto image = g_pHyprOpenGL->createEGLImage(dma); + if (image == EGL_NO_IMAGE_KHR) { + Debug::log(TRACE, "texture fallback failed"); + return nullptr; + } + + GLuint id; + + GLCALL(glGenTextures(1, &id)); + + GLCALL(glBindTexture(GL_TEXTURE_2D, id)); + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); + GLCALL(g_pHyprOpenGL->m_sProc.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image)); + GLCALL(glBindTexture(GL_TEXTURE_2D, 0)); + + Debug::log(TRACE, "texture fallback got {}", image); + if (!texPtr) + texPtr = (uint8_t*)image; + + if (!bufPtr || !texPtr) + return nullptr; + + // copy rendered cursor + for (int i = 0; i < textAttrs.size.y; i++) { + Debug::log(TRACE, "copying {}/{} dst start={}, src start={}, length={}", i + 1, textAttrs.size.y, (void*)(bufPtr + i * bufAttrs.strides[0]), + (void*)(texPtr + i * textAttrs.strides[0]), textAttrs.strides[0]); + memcpy(bufPtr + i * bufAttrs.strides[0], texPtr + i * textAttrs.strides[0], textAttrs.strides[0]); + } + + buf->endDataPtr(); + fallback->endDataPtr(); + } + return buf; } From 19fe56bb12fdb7a776ebc462e7c5a3ddf29756ef Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Thu, 25 Jul 2024 11:04:02 +0300 Subject: [PATCH 3/7] copy from rendered texture --- src/helpers/Monitor.cpp | 6 +-- src/managers/PointerManager.cpp | 73 +++++++++++---------------------- 2 files changed, 26 insertions(+), 53 deletions(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 812662e9ba7..b9f3bf37d7f 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -399,10 +399,8 @@ int CMonitor::findAvailableDefaultWS() { SP CMonitor::resizeSwapchain(SP swapchain, Vector2D size, bool isCursor) { if (!swapchain || size != swapchain->currentOptions().size) { - if (!swapchain) { - Debug::log(TRACE, "creating new cursor {} swapchain", isCursor); + if (!swapchain) swapchain = Aquamarine::CSwapchain::create(output->getBackend()->preferredAllocator(), output->getBackend()); - } auto options = swapchain->currentOptions(); options.size = size; @@ -864,7 +862,6 @@ bool CMonitor::attemptDirectScanout() { } bool CMonitor::resizeCursorSwapchain(Vector2D size) { - Debug::log(TRACE, "resizeCursorSwapchain"); auto swapchain = resizeSwapchain(cursorSwapchain, size, true); if (!cursorSwapchain) cursorSwapchain = swapchain; @@ -873,7 +870,6 @@ bool CMonitor::resizeCursorSwapchain(Vector2D size) { } bool CMonitor::resizeCursorFallbackSwapchain(Vector2D size) { - Debug::log(TRACE, "resizeCursorFallbackSwapchain"); auto swapchain = resizeSwapchain(cursorFallbackSwapchain, size, false); if (!cursorFallbackSwapchain) cursorFallbackSwapchain = swapchain; diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index f5903eb3fde..9f1e4678d9e 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -7,6 +7,7 @@ #include "eventLoop/EventLoopManager.hpp" #include "SeatManager.hpp" #include "render/OpenGL.hpp" +#include "render/Texture.hpp" #include #include #include @@ -420,14 +421,13 @@ SP CPointerManager::renderHWCursorBuffer(SPgetOrCreateRenderbuffer(fallback, state->monitor->cursorFallbackSwapchain->currentOptions().format); if (!RBO) { Debug::log(TRACE, "Failed to create cursor RB with format {}, mod {}", fallback->dmabuf().format, fallback->dmabuf().modifier); return nullptr; - } else - Debug::log(TRACE, "Created cursor RB with format {}, mod {}", fallback->dmabuf().format, fallback->dmabuf().modifier); - } else - Debug::log(TRACE, "Created cursor RB with format {}, mod {}", buf->dmabuf().format, buf->dmabuf().modifier); + } + } RBO->bind(); @@ -441,66 +441,43 @@ SP CPointerManager::renderHWCursorBuffer(SPrenderTexture(texture, &xbox, 1.F); g_pHyprOpenGL->end(); - if (needsFallback) - glFinish(); - else + if (!needsFallback) glFlush(); - g_pHyprOpenGL->m_RenderData.pMonitor = nullptr; - - g_pHyprRenderer->onRenderbufferDestroy(RBO.get()); + else { + glFinish(); - if (needsFallback) { // wlroots tries to blit here but it'll fail the same way we've got here in the first place auto bufAttrs = buf->dmabuf(); - Debug::log(TRACE, "mapping cursor buffer for writing"); + auto texAttrs = fallback->dmabuf(); + auto bufData = buf->beginDataPtr(GBM_BO_TRANSFER_WRITE); auto bufPtr = std::get<0>(bufData); - auto textAttrs = fallback->dmabuf(); - Debug::log(TRACE, "mapping cursor fallback buffer for reading"); - auto texData = fallback->beginDataPtr(GBM_BO_TRANSFER_WRITE); - auto texPtr = std::get<0>(texData); - Debug::log(TRACE, "cursor buffer {}x{} {} format={}({}) stride={}({})", bufAttrs.size.x, bufAttrs.size.y, (void*)bufPtr, bufAttrs.format, std::get<1>(bufData), - bufAttrs.strides[0], std::get<2>(bufData)); - Debug::log(TRACE, "cursor fallback buffer {}x{} {} format={}({}) stride={}({})", textAttrs.size.x, textAttrs.size.y, (void*)texPtr, textAttrs.format, std::get<1>(texData), - textAttrs.strides[0], std::get<2>(texData)); - - const auto dma = fallback->dmabuf(); - - auto image = g_pHyprOpenGL->createEGLImage(dma); - if (image == EGL_NO_IMAGE_KHR) { - Debug::log(TRACE, "texture fallback failed"); - return nullptr; - } + Debug::log(TRACE, "cursor buffer {}x{} {} format={} stride={}", bufAttrs.size.x, bufAttrs.size.y, (void*)bufPtr, bufAttrs.format, bufAttrs.strides[0]); + Debug::log(TRACE, "fallback buffer {}x{} format={} stride={}", texAttrs.size.x, texAttrs.size.y, texAttrs.format, texAttrs.strides[0]); + g_pHyprRenderer->makeEGLCurrent(); + auto fallbackTexture = new CTexture(fallback); GLuint id; + glGenFramebuffers(1, &id); + glBindFramebuffer(GL_FRAMEBUFFER, id); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, fallbackTexture->m_iTarget, fallbackTexture->m_iTexID, 0); - GLCALL(glGenTextures(1, &id)); - - GLCALL(glBindTexture(GL_TEXTURE_2D, id)); - GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); - GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); - GLCALL(g_pHyprOpenGL->m_sProc.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image)); - GLCALL(glBindTexture(GL_TEXTURE_2D, 0)); - - Debug::log(TRACE, "texture fallback got {}", image); - if (!texPtr) - texPtr = (uint8_t*)image; + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + Debug::log(ERR, "cursor dumb copy: glCheckFramebufferStatus failed"); + else { + const auto PFORMAT = FormatUtils::getPixelFormatFromDRM(bufAttrs.format); + glPixelStorei(GL_PACK_ALIGNMENT, 1); - if (!bufPtr || !texPtr) - return nullptr; - - // copy rendered cursor - for (int i = 0; i < textAttrs.size.y; i++) { - Debug::log(TRACE, "copying {}/{} dst start={}, src start={}, length={}", i + 1, textAttrs.size.y, (void*)(bufPtr + i * bufAttrs.strides[0]), - (void*)(texPtr + i * textAttrs.strides[0]), textAttrs.strides[0]); - memcpy(bufPtr + i * bufAttrs.strides[0], texPtr + i * textAttrs.strides[0], textAttrs.strides[0]); + glReadPixels(0, 0, bufAttrs.size.x, bufAttrs.size.y, GL_RGBA, PFORMAT->glType, bufPtr); } buf->endDataPtr(); - fallback->endDataPtr(); } + g_pHyprOpenGL->m_RenderData.pMonitor = nullptr; + g_pHyprRenderer->onRenderbufferDestroy(RBO.get()); + return buf; } From 408148c08e58c559029a403ef1d59a5a79ac5756 Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Thu, 25 Jul 2024 14:55:53 +0300 Subject: [PATCH 4/7] cleanup --- src/managers/PointerManager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 9f1e4678d9e..4b358522c9d 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -472,6 +472,9 @@ SP CPointerManager::renderHWCursorBuffer(SPglType, bufPtr); } + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glDeleteFramebuffers(1, &id); + buf->endDataPtr(); } From ee4015545c70a427ebfe92a00fe2176e383d0745 Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Thu, 25 Jul 2024 22:02:26 +0300 Subject: [PATCH 5/7] support dumb buffers, cursor:allow_slow_copy --- src/config/ConfigManager.cpp | 1 + src/managers/PointerManager.cpp | 62 +++++++++++++++++++++++++-------- 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 5a8f2bd26fc..4d15a5babc9 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -542,6 +542,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("cursor:hide_on_key_press", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:hide_on_touch", Hyprlang::INT{1}); m_pConfig->addConfigValue("cursor:allow_dumb_copy", Hyprlang::INT{0}); + m_pConfig->addConfigValue("cursor:allow_slow_copy", Hyprlang::INT{0}); m_pConfig->addConfigValue("autogenerated", Hyprlang::INT{0}); diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 4b358522c9d..50f4f80c5f8 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -404,28 +404,60 @@ SP CPointerManager::renderHWCursorBuffer(SP fallback; - auto RBO = g_pHyprRenderer->getOrCreateRenderbuffer(buf, state->monitor->cursorSwapchain->currentOptions().format); + auto RBO = + buf->type() == Aquamarine::BUFFER_TYPE_DMABUF_DUMB ? nullptr : g_pHyprRenderer->getOrCreateRenderbuffer(buf, state->monitor->cursorSwapchain->currentOptions().format); if (!RBO) { Debug::log(TRACE, "Failed to create cursor RB with format {}, mod {}", buf->dmabuf().format, buf->dmabuf().modifier); static auto PDUMB = CConfigValue("cursor:allow_dumb_copy"); - if (!*PDUMB) + static auto PSLOW = CConfigValue("cursor:allow_slow_copy"); + + if (!*PDUMB && !*PSLOW) return nullptr; - needsFallback = true; + if (*PSLOW) { + Debug::log(TRACE, "[pointer] performing slow copy"); + needsFallback = true; - if (!state->monitor->resizeCursorFallbackSwapchain(maxSize)) - return nullptr; + if (!state->monitor->resizeCursorFallbackSwapchain(maxSize)) + return nullptr; - fallback = state->monitor->cursorFallbackSwapchain->next(nullptr); - if (!fallback) { - Debug::log(TRACE, "Failed to acquire a buffer from the cursor fallback swapchain"); - return nullptr; - } + fallback = state->monitor->cursorFallbackSwapchain->next(nullptr); + if (!fallback) { + Debug::log(TRACE, "Failed to acquire a buffer from the cursor fallback swapchain"); + return nullptr; + } - RBO = g_pHyprRenderer->getOrCreateRenderbuffer(fallback, state->monitor->cursorFallbackSwapchain->currentOptions().format); - if (!RBO) { - Debug::log(TRACE, "Failed to create cursor RB with format {}, mod {}", fallback->dmabuf().format, fallback->dmabuf().modifier); - return nullptr; + RBO = g_pHyprRenderer->getOrCreateRenderbuffer(fallback, state->monitor->cursorFallbackSwapchain->currentOptions().format); + if (!RBO) { + Debug::log(TRACE, "Failed to create cursor RB with format {}, mod {}", fallback->dmabuf().format, fallback->dmabuf().modifier); + return nullptr; + } + } else { + Debug::log(TRACE, "[pointer] performing dumb copy"); + auto bufData = buf->beginDataPtr(0); + auto bufPtr = std::get<0>(bufData); + + // clear buffer + memset(bufPtr, 0, buf->type() == Aquamarine::BUFFER_TYPE_DMABUF_DUMB ? std::get<2>(bufData) * buf->size.y : std::get<2>(bufData)); + + auto texBuffer = currentCursorImage.pBuffer ? currentCursorImage.pBuffer : currentCursorImage.surface->resource()->current.buffer; + if (texBuffer) { + auto textAttrs = texBuffer->shm(); + auto texData = texBuffer->beginDataPtr(GBM_BO_TRANSFER_WRITE); + auto texPtr = std::get<0>(texData); + Debug::log(TRACE, "cursor texture {}x{} {} {} {}", textAttrs.size.x, textAttrs.size.y, (void*)texPtr, textAttrs.format, textAttrs.stride); + + // copy cursor texture + if (buf->dmabuf().strides[0] == textAttrs.stride && buf->dmabuf().size == textAttrs.size) + memcpy(bufPtr, texPtr, textAttrs.stride * textAttrs.size.y); + else + for (int i = 0; i < texBuffer->shm().size.y; i++) + memcpy(bufPtr + i * buf->dmabuf().strides[0], texPtr + i * textAttrs.stride, textAttrs.stride); + } + + buf->endDataPtr(); + + return buf; } } @@ -464,7 +496,7 @@ SP CPointerManager::renderHWCursorBuffer(SPm_iTarget, fallbackTexture->m_iTexID, 0); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - Debug::log(ERR, "cursor dumb copy: glCheckFramebufferStatus failed"); + Debug::log(ERR, "cursor slow copy: glCheckFramebufferStatus failed"); else { const auto PFORMAT = FormatUtils::getPixelFormatFromDRM(bufAttrs.format); glPixelStorei(GL_PACK_ALIGNMENT, 1); From 7238dd9d3889c80bf9692c31c79acaf28f1d190c Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Thu, 25 Jul 2024 22:55:38 +0300 Subject: [PATCH 6/7] fix buffer clearing --- src/managers/PointerManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 50f4f80c5f8..ae946813146 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -438,7 +438,7 @@ SP CPointerManager::renderHWCursorBuffer(SP(bufData); // clear buffer - memset(bufPtr, 0, buf->type() == Aquamarine::BUFFER_TYPE_DMABUF_DUMB ? std::get<2>(bufData) * buf->size.y : std::get<2>(bufData)); + memset(bufPtr, 0, buf->type() == Aquamarine::BUFFER_TYPE_DMABUF_DUMB ? std::get<2>(bufData) * buf->dmabuf().size.y : std::get<2>(bufData)); auto texBuffer = currentCursorImage.pBuffer ? currentCursorImage.pBuffer : currentCursorImage.surface->resource()->current.buffer; if (texBuffer) { From c120740a439db37833115ee5db76bd755004abdf Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Fri, 26 Jul 2024 13:57:22 +0300 Subject: [PATCH 7/7] fix dumb cursor buffers --- src/helpers/Monitor.cpp | 22 ++++++++++++++++------ src/helpers/Monitor.hpp | 6 ++++-- src/managers/PointerManager.cpp | 26 ++++++++++++++++++++++---- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index b9f3bf37d7f..4b835621e9d 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -396,25 +396,27 @@ int CMonitor::findAvailableDefaultWS() { return INT32_MAX; // shouldn't be reachable } -SP CMonitor::resizeSwapchain(SP swapchain, Vector2D size, bool isCursor) { +SP CMonitor::resizeSwapchain(SP swapchain, Vector2D size, bool isCursor, bool isDumb) { if (!swapchain || size != swapchain->currentOptions().size) { - if (!swapchain) - swapchain = Aquamarine::CSwapchain::create(output->getBackend()->preferredAllocator(), output->getBackend()); + if (!swapchain) { + auto allocator = isDumb && output->getBackend()->fallbackAllocator() ? output->getBackend()->fallbackAllocator() : output->getBackend()->preferredAllocator(); + swapchain = Aquamarine::CSwapchain::create(allocator, output->getBackend()); + } auto options = swapchain->currentOptions(); options.size = size; options.length = 2; options.scanout = true; options.cursor = isCursor; - options.multigpu = output->getBackend()->preferredAllocator()->drmFD() != g_pCompositor->m_iDRMFD; + options.multigpu = !isDumb && output->getBackend()->preferredAllocator()->drmFD() != g_pCompositor->m_iDRMFD; if (!isCursor && cursorSwapchain) options.format = cursorSwapchain->currentOptions().format; // We do not set the format. If it's unset (DRM_FORMAT_INVALID) then the swapchain will pick for us, // but if it's set, we don't wanna change it. if (!swapchain->reconfigure(options)) { - Debug::log(TRACE, "Failed to reconfigure {} swapchain", isCursor ? "cursor" : "cursor fallback"); + Debug::log(TRACE, "Failed to reconfigure{} {} swapchain", isCursor ? "cursor" : "cursor fallback", isDumb ? " dumb" : ""); return nullptr; } } @@ -862,13 +864,21 @@ bool CMonitor::attemptDirectScanout() { } bool CMonitor::resizeCursorSwapchain(Vector2D size) { - auto swapchain = resizeSwapchain(cursorSwapchain, size, true); + auto swapchain = resizeSwapchain(cursorSwapchain, size, true, useDumbCursorBuffer); if (!cursorSwapchain) cursorSwapchain = swapchain; return !!swapchain; } +bool CMonitor::resizeCursorSwapchain(Vector2D size, bool useDumb) { + if (useDumbCursorBuffer != useDumb && cursorSwapchain) { + useDumbCursorBuffer = useDumb; + cursorSwapchain = nullptr; // recreate swapchain with a different allocator + } + return resizeCursorSwapchain(size); +} + bool CMonitor::resizeCursorFallbackSwapchain(Vector2D size) { auto swapchain = resizeSwapchain(cursorFallbackSwapchain, size, false); if (!cursorFallbackSwapchain) diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 2898d0a84c1..0d891a654cc 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -180,6 +180,7 @@ class CMonitor { void scheduleDone(); bool attemptDirectScanout(); bool resizeCursorSwapchain(Vector2D size); + bool resizeCursorSwapchain(Vector2D size, bool useDumb); bool resizeCursorFallbackSwapchain(Vector2D size); bool m_bEnabled = false; @@ -194,9 +195,10 @@ class CMonitor { private: void setupDefaultWS(const SMonitorRule&); int findAvailableDefaultWS(); - SP resizeSwapchain(SP swapchain, Vector2D size, bool isCursor); + SP resizeSwapchain(SP swapchain, Vector2D size, bool isCursor, bool isDumb = false); - wl_event_source* doneSource = nullptr; + wl_event_source* doneSource = nullptr; + bool useDumbCursorBuffer = false; struct { CHyprSignalListener frame; diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index ae946813146..d52c0237769 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -411,10 +411,25 @@ SP CPointerManager::renderHWCursorBuffer(SP("cursor:allow_dumb_copy"); static auto PSLOW = CConfigValue("cursor:allow_slow_copy"); + auto isDumb = buf->type() == Aquamarine::BUFFER_TYPE_DMABUF_DUMB; + if (isDumb != *PDUMB) { + Debug::log(TRACE, "[pointer] switching swapchain to {}", *PDUMB ? "dumb" : "gbm"); + if (!state->monitor->resizeCursorSwapchain(maxSize, *PDUMB)) + return nullptr; + + buf = state->monitor->cursorSwapchain->next(nullptr); + if (!buf) { + Debug::log(TRACE, "Failed to acquire a buffer from the cursor swapchain"); + return nullptr; + } + isDumb = buf->type() == Aquamarine::BUFFER_TYPE_DMABUF_DUMB; + } + if (!*PDUMB && !*PSLOW) return nullptr; - if (*PSLOW) { + // slow copy will fail with dumb buffer + if (*PSLOW && !*PDUMB) { Debug::log(TRACE, "[pointer] performing slow copy"); needsFallback = true; @@ -437,8 +452,11 @@ SP CPointerManager::renderHWCursorBuffer(SPbeginDataPtr(0); auto bufPtr = std::get<0>(bufData); + auto bufSize = isDumb ? buf->shm().size : buf->dmabuf().size; + auto bufStride = isDumb ? buf->shm().stride : buf->dmabuf().strides[0]; + // clear buffer - memset(bufPtr, 0, buf->type() == Aquamarine::BUFFER_TYPE_DMABUF_DUMB ? std::get<2>(bufData) * buf->dmabuf().size.y : std::get<2>(bufData)); + memset(bufPtr, 0, bufStride * bufSize.y); auto texBuffer = currentCursorImage.pBuffer ? currentCursorImage.pBuffer : currentCursorImage.surface->resource()->current.buffer; if (texBuffer) { @@ -448,11 +466,11 @@ SP CPointerManager::renderHWCursorBuffer(SPdmabuf().strides[0] == textAttrs.stride && buf->dmabuf().size == textAttrs.size) + if (bufStride == textAttrs.stride && bufSize == textAttrs.size) memcpy(bufPtr, texPtr, textAttrs.stride * textAttrs.size.y); else for (int i = 0; i < texBuffer->shm().size.y; i++) - memcpy(bufPtr + i * buf->dmabuf().strides[0], texPtr + i * textAttrs.stride, textAttrs.stride); + memcpy(bufPtr + i * bufStride, texPtr + i * textAttrs.stride, textAttrs.stride); } buf->endDataPtr();