aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorVaxry <[email protected]>2024-11-14 20:15:51 +0000
committerGitHub <[email protected]>2024-11-14 20:15:51 +0000
commit20031cea92417a852410827a5cdb4adbcaee4342 (patch)
tree665917c3c02f5de7311c27110ec4e76eb5becd6c /src
parent3fb47372b79265ebdabeeefdad10359d5b18377a (diff)
downloadHyprland-20031cea92417a852410827a5cdb4adbcaee4342.tar.gz
Hyprland-20031cea92417a852410827a5cdb4adbcaee4342.zip
pointer: add drm dumb buffers for cursors (#8399)
--------- Co-authored-by: Mihai Fufezan <[email protected]>
Diffstat (limited to 'src')
-rw-r--r--src/config/ConfigManager.cpp2
-rw-r--r--src/managers/PointerManager.cpp126
-rw-r--r--src/protocols/core/Compositor.cpp26
-rw-r--r--src/protocols/core/Compositor.hpp2
-rw-r--r--src/render/Texture.cpp21
-rw-r--r--src/render/Texture.hpp34
6 files changed, 137 insertions, 74 deletions
diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp
index e3d59874..10299277 100644
--- a/src/config/ConfigManager.cpp
+++ b/src/config/ConfigManager.cpp
@@ -571,7 +571,7 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("cursor:sync_gsettings_theme", Hyprlang::INT{1});
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:use_cpu_buffer", Hyprlang::INT{0});
m_pConfig->addConfigValue("autogenerated", Hyprlang::INT{0});
diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp
index 75be235f..0580c9be 100644
--- a/src/managers/PointerManager.cpp
+++ b/src/managers/PointerManager.cpp
@@ -375,6 +375,8 @@ SP<Aquamarine::IBuffer> CPointerManager::renderHWCursorBuffer(SP<CPointerManager
auto maxSize = state->monitor->output->cursorPlaneSize();
auto const& cursorSize = currentCursorImage.size;
+ static auto PDUMB = CConfigValue<Hyprlang::INT>("cursor:use_cpu_buffer");
+
if (maxSize == Vector2D{})
return nullptr;
@@ -386,10 +388,23 @@ SP<Aquamarine::IBuffer> CPointerManager::renderHWCursorBuffer(SP<CPointerManager
} else
maxSize = cursorSize;
- if (!state->monitor->cursorSwapchain || maxSize != state->monitor->cursorSwapchain->currentOptions().size) {
+ if (!state->monitor->cursorSwapchain || maxSize != state->monitor->cursorSwapchain->currentOptions().size ||
+ *PDUMB != (state->monitor->cursorSwapchain->getAllocator()->type() != Aquamarine::AQ_ALLOCATOR_TYPE_GBM)) {
+
+ if (!state->monitor->cursorSwapchain || *PDUMB != (state->monitor->cursorSwapchain->getAllocator()->type() != Aquamarine::AQ_ALLOCATOR_TYPE_GBM)) {
+
+ auto allocator = state->monitor->output->getBackend()->preferredAllocator();
+ if (*PDUMB) {
+ for (const auto& a : state->monitor->output->getBackend()->getAllocators()) {
+ if (a->type() == Aquamarine::AQ_ALLOCATOR_TYPE_DRM_DUMB) {
+ allocator = a;
+ break;
+ }
+ }
+ }
- if (!state->monitor->cursorSwapchain)
- state->monitor->cursorSwapchain = Aquamarine::CSwapchain::create(state->monitor->output->getBackend()->preferredAllocator(), state->monitor->output->getBackend());
+ state->monitor->cursorSwapchain = Aquamarine::CSwapchain::create(allocator, state->monitor->output->getBackend());
+ }
auto options = state->monitor->cursorSwapchain->currentOptions();
options.size = maxSize;
@@ -397,8 +412,10 @@ SP<Aquamarine::IBuffer> CPointerManager::renderHWCursorBuffer(SP<CPointerManager
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,
+ // We do not set the format (unless shm). 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 (*PDUMB)
+ options.format = DRM_FORMAT_ARGB8888;
if (!state->monitor->cursorSwapchain->reconfigure(options)) {
Debug::log(TRACE, "Failed to reconfigure cursor swapchain");
@@ -420,62 +437,71 @@ SP<Aquamarine::IBuffer> CPointerManager::renderHWCursorBuffer(SP<CPointerManager
return nullptr;
}
- g_pHyprRenderer->makeEGLCurrent();
- g_pHyprOpenGL->m_RenderData.pMonitor = state->monitor;
-
- 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<Hyprlang::INT>("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));
-
- if (currentCursorImage.pBuffer) {
- auto texAttrs = currentCursorImage.pBuffer->shm();
-
- if (!texAttrs.success) {
+ if (*PDUMB) {
+ // get the texture data if available.
+ auto texData = texture->dataCopy();
+ if (texData.empty()) {
+ if (currentCursorImage.surface && currentCursorImage.surface->resource()->role->role() == SURFACE_ROLE_CURSOR) {
+ const auto SURFACE = currentCursorImage.surface->resource();
+ auto& shmBuffer = CCursorSurfaceRole::cursorPixelData(SURFACE);
+
+ bool flipRB = false;
+
+ if (SURFACE->current.texture) {
+ Debug::log(TRACE, "Cursor CPU surface: format {}, expecting AR24", FormatUtils::drmFormatName(SURFACE->current.texture->m_iDrmFormat));
+ if (SURFACE->current.texture->m_iDrmFormat == DRM_FORMAT_ABGR8888) {
+ Debug::log(TRACE, "Cursor CPU surface format AB24, will flip. WARNING: this will break on big endian!");
+ flipRB = true;
+ } else if (SURFACE->current.texture->m_iDrmFormat != DRM_FORMAT_ARGB8888) {
+ Debug::log(TRACE, "Cursor CPU surface format rejected, falling back to sw");
+ return nullptr;
+ }
+ }
+
+ if (shmBuffer.data())
+ texData = shmBuffer;
+ else {
+ texData.resize(texture->m_vSize.x * 4 * texture->m_vSize.y);
+ memset(texData.data(), 0x00, texData.size());
+ }
+
+ if (flipRB) {
+ for (size_t i = 0; i < shmBuffer.size(); i += 4) {
+ std::swap(shmBuffer.at(i), shmBuffer.at(i + 2)); // little-endian!!!!!!
+ }
+ }
+ } else {
Debug::log(TRACE, "Cannot use dumb copy on dmabuf cursor buffers");
return nullptr;
}
+ }
- auto texData = currentCursorImage.pBuffer->beginDataPtr(GBM_BO_TRANSFER_WRITE);
- auto texPtr = std::get<0>(texData);
- Debug::log(TRACE, "cursor texture {}x{} {} {} {}", texAttrs.size.x, texAttrs.size.y, (void*)texPtr, texAttrs.format, texAttrs.stride);
- // copy cursor texture
- for (int i = 0; i < texAttrs.size.y; i++)
- memcpy(bufPtr + i * buf->dmabuf().strides[0], texPtr + i * texAttrs.stride, texAttrs.stride);
- } else if (currentCursorImage.surface && currentCursorImage.surface->resource()->role->role() == SURFACE_ROLE_CURSOR) {
- const auto SURFACE = currentCursorImage.surface->resource();
- auto& shmBuffer = CCursorSurfaceRole::cursorPixelData(SURFACE);
- Debug::log(TRACE, "cursor texture pixel data length: {}B", shmBuffer.size());
-
- if (shmBuffer.data()) {
- // copy cursor texture
- // assume format is 32bpp
- size_t STRIDE = 4 * SURFACE->current.bufferSize.x;
- for (int i = 0; i < SURFACE->current.bufferSize.y; i++)
- memcpy(bufPtr + i * buf->dmabuf().strides[0], shmBuffer.data() + i * STRIDE, STRIDE);
- } else {
- // if there is no data, hide the cursor
- memset(bufPtr, '\0', buf->size.x * buf->size.y * 4 /* assume 32bpp */);
- }
+ // then, we just yeet it into the dumb buffer
- } else {
- Debug::log(TRACE, "Unsupported cursor buffer/surface, falling back to sw (can't dumb copy)");
- return nullptr;
- }
+ auto [data, fmt, size] = buf->beginDataPtr(0);
+
+ memset(data, 0, size);
+ if (buf->dmabuf().size.x > texture->m_vSize.x) {
+ size_t STRIDE = 4 * texture->m_vSize.x;
+ for (int i = 0; i < texture->m_vSize.y; i++)
+ memcpy(data + i * buf->dmabuf().strides[0], texData.data() + i * STRIDE, STRIDE);
+ } else
+ memcpy(data, texData.data(), std::min(size, texData.size()));
buf->endDataPtr();
return buf;
}
+ g_pHyprRenderer->makeEGLCurrent();
+ g_pHyprOpenGL->m_RenderData.pMonitor = state->monitor;
+
+ 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);
+ return nullptr;
+ }
+
RBO->bind();
g_pHyprOpenGL->beginSimple(state->monitor.lock(), {0, 0, INT16_MAX, INT16_MAX}, RBO);
@@ -773,7 +799,7 @@ SP<CTexture> CPointerManager::getCurrentCursorTexture() {
if (currentCursorImage.pBuffer) {
if (!currentCursorImage.bufferTex)
- currentCursorImage.bufferTex = makeShared<CTexture>(currentCursorImage.pBuffer);
+ currentCursorImage.bufferTex = makeShared<CTexture>(currentCursorImage.pBuffer, true);
return currentCursorImage.bufferTex;
}
diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp
index 57f61f87..89f2a4cb 100644
--- a/src/protocols/core/Compositor.cpp
+++ b/src/protocols/core/Compositor.cpp
@@ -438,12 +438,13 @@ void CWLSurfaceResource::commitPendingState() {
current.texture->m_eTransform = wlTransformToHyprutils(current.transform);
if (current.buffer && current.buffer->buffer) {
- current.buffer->buffer->update(accumulateCurrentBufferDamage());
+ const auto DAMAGE = accumulateCurrentBufferDamage();
+ current.buffer->buffer->update(DAMAGE);
// if the surface is a cursor, update the shm buffer
// TODO: don't update the entire texture
- if (role->role() == SURFACE_ROLE_CURSOR)
- updateCursorShm();
+ if (role->role() == SURFACE_ROLE_CURSOR && !DAMAGE.empty())
+ updateCursorShm(DAMAGE);
// release the buffer if it's synchronous as update() has done everything thats needed
// so we can let the app know we're done.
@@ -486,13 +487,12 @@ void CWLSurfaceResource::commitPendingState() {
lastBuffer = current.buffer ? current.buffer->buffer : WP<IHLBuffer>{};
}
-void CWLSurfaceResource::updateCursorShm() {
+void CWLSurfaceResource::updateCursorShm(CRegion damage) {
auto buf = current.buffer ? current.buffer->buffer : lastBuffer;
if (!buf)
return;
- // TODO: actually use damage
auto& shmData = CCursorSurfaceRole::cursorPixelData(self.lock());
auto shmAttrs = buf->shm();
@@ -501,11 +501,25 @@ void CWLSurfaceResource::updateCursorShm() {
return;
}
+ damage.intersect(CBox{0, 0, buf->size.x, buf->size.y});
+
// no need to end, shm.
auto [pixelData, fmt, bufLen] = buf->beginDataPtr(0);
shmData.resize(bufLen);
- memcpy(shmData.data(), pixelData, bufLen);
+
+ if (const auto RECTS = damage.getRects(); RECTS.size() == 1 && RECTS.at(0).x2 == buf->size.x && RECTS.at(0).y2 == buf->size.y)
+ memcpy(shmData.data(), pixelData, bufLen);
+ else {
+ for (auto& box : damage.getRects()) {
+ for (auto y = box.y1; y < box.y2; ++y) {
+ // bpp is 32 INSALLAH
+ auto begin = 4 * box.y1 * (box.x2 - box.x1) + box.x1;
+ auto len = 4 * (box.x2 - box.x1);
+ memcpy((uint8_t*)shmData.data() + begin, (uint8_t*)pixelData + begin, len);
+ }
+ }
+ }
}
void CWLSurfaceResource::presentFeedback(timespec* when, PHLMONITOR pMonitor) {
diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp
index e5bdf082..c036041a 100644
--- a/src/protocols/core/Compositor.hpp
+++ b/src/protocols/core/Compositor.hpp
@@ -148,7 +148,7 @@ class CWLSurfaceResource {
void dropCurrentBuffer();
void commitPendingState();
void bfHelper(std::vector<SP<CWLSurfaceResource>> const& nodes, std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data);
- void updateCursorShm();
+ void updateCursorShm(CRegion damage = CBox{0, 0, INT16_MAX, INT16_MAX});
friend class CWLPointerResource;
};
diff --git a/src/render/Texture.cpp b/src/render/Texture.cpp
index 91e70afa..633f0212 100644
--- a/src/render/Texture.cpp
+++ b/src/render/Texture.cpp
@@ -3,6 +3,7 @@
#include "../Compositor.hpp"
#include "../protocols/types/Buffer.hpp"
#include "../helpers/Format.hpp"
+#include <cstring>
CTexture::CTexture() {
// naffin'
@@ -16,7 +17,7 @@ CTexture::~CTexture() {
destroyTexture();
}
-CTexture::CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size_) {
+CTexture::CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size_, bool keepDataCopy) : m_iDrmFormat(drmFormat), m_bKeepDataCopy(keepDataCopy) {
createFromShm(drmFormat, pixels, stride, size_);
}
@@ -24,7 +25,7 @@ CTexture::CTexture(const Aquamarine::SDMABUFAttrs& attrs, void* image) {
createFromDma(attrs, image);
}
-CTexture::CTexture(const SP<Aquamarine::IBuffer> buffer) {
+CTexture::CTexture(const SP<Aquamarine::IBuffer> buffer, bool keepDataCopy) : m_bKeepDataCopy(keepDataCopy) {
if (!buffer)
return;
@@ -43,6 +44,8 @@ CTexture::CTexture(const SP<Aquamarine::IBuffer> buffer) {
auto [pixelData, fmt, bufLen] = buffer->beginDataPtr(0);
+ m_iDrmFormat = fmt;
+
createFromShm(fmt, pixelData, bufLen, shm.size);
return;
}
@@ -80,6 +83,11 @@ void CTexture::createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t strid
GLCALL(glTexImage2D(GL_TEXTURE_2D, 0, format->glInternalFormat ? format->glInternalFormat : format->glFormat, size_.x, size_.y, 0, format->glFormat, format->glType, pixels));
GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0));
GLCALL(glBindTexture(GL_TEXTURE_2D, 0));
+
+ if (m_bKeepDataCopy) {
+ m_vDataCopy.resize(stride * size_.y);
+ memcpy(m_vDataCopy.data(), pixels, stride * size_.y);
+ }
}
void CTexture::createFromDma(const Aquamarine::SDMABUFAttrs& attrs, void* image) {
@@ -135,6 +143,11 @@ void CTexture::update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, cons
GLCALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0));
glBindTexture(GL_TEXTURE_2D, 0);
+
+ if (m_bKeepDataCopy) {
+ m_vDataCopy.resize(stride * m_vSize.y);
+ memcpy(m_vDataCopy.data(), pixels, stride * m_vSize.y);
+ }
}
void CTexture::destroyTexture() {
@@ -152,3 +165,7 @@ void CTexture::allocate() {
if (!m_iTexID)
GLCALL(glGenTextures(1, &m_iTexID));
}
+
+const std::vector<uint8_t>& CTexture::dataCopy() {
+ return m_vDataCopy;
+}
diff --git a/src/render/Texture.hpp b/src/render/Texture.hpp
index e0ef5503..ae949d5f 100644
--- a/src/render/Texture.hpp
+++ b/src/render/Texture.hpp
@@ -24,26 +24,32 @@ class CTexture {
CTexture(const CTexture&&) = delete;
CTexture(const CTexture&) = delete;
- CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size);
+ CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy = false);
- CTexture(const SP<Aquamarine::IBuffer> buffer);
+ CTexture(const SP<Aquamarine::IBuffer> buffer, bool keepDataCopy = false);
// this ctor takes ownership of the eglImage.
CTexture(const Aquamarine::SDMABUFAttrs&, void* image);
~CTexture();
- void destroyTexture();
- void allocate();
- void update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const CRegion& damage);
+ void destroyTexture();
+ void allocate();
+ void update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const CRegion& damage);
+ const std::vector<uint8_t>& dataCopy();
- TEXTURETYPE m_iType = TEXTURE_RGBA;
- GLenum m_iTarget = GL_TEXTURE_2D;
- GLuint m_iTexID = 0;
- Vector2D m_vSize = {};
- void* m_pEglImage = nullptr;
- eTransform m_eTransform = HYPRUTILS_TRANSFORM_NORMAL;
- bool m_bOpaque = false;
+ TEXTURETYPE m_iType = TEXTURE_RGBA;
+ GLenum m_iTarget = GL_TEXTURE_2D;
+ GLuint m_iTexID = 0;
+ Vector2D m_vSize = {};
+ void* m_pEglImage = nullptr;
+ eTransform m_eTransform = HYPRUTILS_TRANSFORM_NORMAL;
+ bool m_bOpaque = false;
+ uint32_t m_iDrmFormat = 0; // for shm
private:
- void createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size);
- void createFromDma(const Aquamarine::SDMABUFAttrs&, void* image);
+ void createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size);
+ void createFromDma(const Aquamarine::SDMABUFAttrs&, void* image);
+
+ bool m_bKeepDataCopy = false;
+
+ std::vector<uint8_t> m_vDataCopy;
}; \ No newline at end of file