drm dumb buffers for cursors

This commit is contained in:
Vaxry 2024-11-09 19:53:45 +00:00
parent c10739e6e3
commit 80e885f374
4 changed files with 89 additions and 70 deletions

View file

@ -570,7 +570,7 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("cursor:sync_gsettings_theme", Hyprlang::INT{1}); 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_key_press", Hyprlang::INT{0});
m_pConfig->addConfigValue("cursor:hide_on_touch", Hyprlang::INT{1}); 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}); m_pConfig->addConfigValue("autogenerated", Hyprlang::INT{0});

View file

@ -375,6 +375,8 @@ SP<Aquamarine::IBuffer> CPointerManager::renderHWCursorBuffer(SP<CPointerManager
auto maxSize = state->monitor->output->cursorPlaneSize(); auto maxSize = state->monitor->output->cursorPlaneSize();
auto const& cursorSize = currentCursorImage.size; auto const& cursorSize = currentCursorImage.size;
static auto PDUMB = CConfigValue<Hyprlang::INT>("cursor:use_cpu_buffer");
if (maxSize == Vector2D{}) if (maxSize == Vector2D{})
return nullptr; return nullptr;
@ -386,10 +388,23 @@ SP<Aquamarine::IBuffer> CPointerManager::renderHWCursorBuffer(SP<CPointerManager
} else } else
maxSize = cursorSize; 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) if (!state->monitor->cursorSwapchain || *PDUMB != (state->monitor->cursorSwapchain->getAllocator()->type() != Aquamarine::AQ_ALLOCATOR_TYPE_GBM)) {
state->monitor->cursorSwapchain = Aquamarine::CSwapchain::create(state->monitor->output->getBackend()->preferredAllocator(), state->monitor->output->getBackend());
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;
}
}
}
state->monitor->cursorSwapchain = Aquamarine::CSwapchain::create(allocator, state->monitor->output->getBackend());
}
auto options = state->monitor->cursorSwapchain->currentOptions(); auto options = state->monitor->cursorSwapchain->currentOptions();
options.size = maxSize; options.size = maxSize;
@ -397,8 +412,10 @@ SP<Aquamarine::IBuffer> CPointerManager::renderHWCursorBuffer(SP<CPointerManager
options.scanout = true; options.scanout = true;
options.cursor = true; options.cursor = true;
options.multigpu = state->monitor->output->getBackend()->preferredAllocator()->drmFD() != g_pCompositor->m_iDRMFD; 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. // but if it's set, we don't wanna change it.
if (*PDUMB)
options.format = DRM_FORMAT_ARGB8888;
if (!state->monitor->cursorSwapchain->reconfigure(options)) { if (!state->monitor->cursorSwapchain->reconfigure(options)) {
Debug::log(TRACE, "Failed to reconfigure cursor swapchain"); Debug::log(TRACE, "Failed to reconfigure cursor swapchain");
@ -420,60 +437,42 @@ SP<Aquamarine::IBuffer> CPointerManager::renderHWCursorBuffer(SP<CPointerManager
return nullptr; return nullptr;
} }
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);
if (shmBuffer.data())
texData = shmBuffer;
else
texData = {texture->m_vSize.x * 4 * texture->m_vSize.y, 0};
} else {
Debug::log(TRACE, "Cannot use dumb copy on dmabuf cursor buffers");
return nullptr;
}
}
// then, we just yeet it into the dumb buffer
auto [data, fmt, size] = buf->beginDataPtr(0);
memcpy(data, texData.data(), std::min(size, texData.size()));
buf->endDataPtr();
return buf;
}
g_pHyprRenderer->makeEGLCurrent(); g_pHyprRenderer->makeEGLCurrent();
g_pHyprOpenGL->m_RenderData.pMonitor = state->monitor; g_pHyprOpenGL->m_RenderData.pMonitor = state->monitor;
auto RBO = g_pHyprRenderer->getOrCreateRenderbuffer(buf, state->monitor->cursorSwapchain->currentOptions().format); auto RBO = g_pHyprRenderer->getOrCreateRenderbuffer(buf, state->monitor->cursorSwapchain->currentOptions().format);
if (!RBO) { if (!RBO) {
Debug::log(TRACE, "Failed to create cursor RB with format {}, mod {}", buf->dmabuf().format, buf->dmabuf().modifier); 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"); return nullptr;
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) {
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 */);
}
} else {
Debug::log(TRACE, "Unsupported cursor buffer/surface, falling back to sw (can't dumb copy)");
return nullptr;
}
buf->endDataPtr();
return buf;
} }
RBO->bind(); RBO->bind();
@ -775,7 +774,7 @@ SP<CTexture> CPointerManager::getCurrentCursorTexture() {
if (currentCursorImage.pBuffer) { if (currentCursorImage.pBuffer) {
if (!currentCursorImage.bufferTex) if (!currentCursorImage.bufferTex)
currentCursorImage.bufferTex = makeShared<CTexture>(currentCursorImage.pBuffer); currentCursorImage.bufferTex = makeShared<CTexture>(currentCursorImage.pBuffer, true);
return currentCursorImage.bufferTex; return currentCursorImage.bufferTex;
} }

View file

@ -3,6 +3,7 @@
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../protocols/types/Buffer.hpp" #include "../protocols/types/Buffer.hpp"
#include "../helpers/Format.hpp" #include "../helpers/Format.hpp"
#include <cstring>
CTexture::CTexture() { CTexture::CTexture() {
// naffin' // naffin'
@ -16,7 +17,7 @@ CTexture::~CTexture() {
destroyTexture(); 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_bKeepDataCopy(keepDataCopy) {
createFromShm(drmFormat, pixels, stride, size_); createFromShm(drmFormat, pixels, stride, size_);
} }
@ -24,7 +25,7 @@ CTexture::CTexture(const Aquamarine::SDMABUFAttrs& attrs, void* image) {
createFromDma(attrs, 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) if (!buffer)
return; return;
@ -80,6 +81,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(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(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0));
GLCALL(glBindTexture(GL_TEXTURE_2D, 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) { void CTexture::createFromDma(const Aquamarine::SDMABUFAttrs& attrs, void* image) {
@ -135,6 +141,11 @@ void CTexture::update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, cons
GLCALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0)); GLCALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0));
glBindTexture(GL_TEXTURE_2D, 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() { void CTexture::destroyTexture() {
@ -152,3 +163,7 @@ void CTexture::allocate() {
if (!m_iTexID) if (!m_iTexID)
GLCALL(glGenTextures(1, &m_iTexID)); GLCALL(glGenTextures(1, &m_iTexID));
} }
const std::vector<uint8_t>& CTexture::dataCopy() {
return m_vDataCopy;
}

View file

@ -24,26 +24,31 @@ class CTexture {
CTexture(const CTexture&&) = delete; CTexture(const CTexture&&) = delete;
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. // this ctor takes ownership of the eglImage.
CTexture(const Aquamarine::SDMABUFAttrs&, void* image); CTexture(const Aquamarine::SDMABUFAttrs&, void* image);
~CTexture(); ~CTexture();
void destroyTexture(); void destroyTexture();
void allocate(); void allocate();
void update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const CRegion& damage); 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; TEXTURETYPE m_iType = TEXTURE_RGBA;
GLenum m_iTarget = GL_TEXTURE_2D; GLenum m_iTarget = GL_TEXTURE_2D;
GLuint m_iTexID = 0; GLuint m_iTexID = 0;
Vector2D m_vSize = {}; Vector2D m_vSize = {};
void* m_pEglImage = nullptr; void* m_pEglImage = nullptr;
eTransform m_eTransform = HYPRUTILS_TRANSFORM_NORMAL; eTransform m_eTransform = HYPRUTILS_TRANSFORM_NORMAL;
bool m_bOpaque = false; bool m_bOpaque = false;
private: private:
void createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size); void createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size);
void createFromDma(const Aquamarine::SDMABUFAttrs&, void* image); void createFromDma(const Aquamarine::SDMABUFAttrs&, void* image);
bool m_bKeepDataCopy = false;
std::vector<uint8_t> m_vDataCopy;
}; };