From 86e36b5b5fc9f161f033671b7452cda69727fe91 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Mon, 24 Feb 2025 14:53:49 -0600 Subject: [PATCH 1/7] allocator: Don't force linear for multigpu if unsupported --- src/allocator/GBM.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/allocator/GBM.cpp b/src/allocator/GBM.cpp index d5f69db..f4ed015 100644 --- a/src/allocator/GBM.cpp +++ b/src/allocator/GBM.cpp @@ -140,10 +140,16 @@ Aquamarine::CGBMBuffer::CGBMBuffer(const SAllocatorBufferParams& params, Hypruti return; } - // FIXME: Nvidia cannot render to linear buffers. What do? if (MULTIGPU) { - allocator->backend->log(AQ_LOG_DEBUG, "GBM: Buffer is marked as multigpu, forcing linear"); - explicitModifiers = {DRM_FORMAT_MOD_LINEAR}; + // Try to use the linear format if available for cross-GPU compatibility. + // However, Nvidia doesn't support linear, so this is a best-effort basis. + for (auto const& f : FORMATS) { + if (f.drmFormat == DRM_FORMAT_MOD_LINEAR) { + allocator->backend->log(AQ_LOG_DEBUG, "GBM: Buffer is marked as multigpu, using linear format"); + explicitModifiers = {DRM_FORMAT_MOD_LINEAR}; + break; + } + } } uint32_t flags = GBM_BO_USE_RENDERING; From 847fe2e1201480e33c90ece173f142068da24783 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Mon, 24 Feb 2025 14:54:35 -0600 Subject: [PATCH 2/7] drm: Use an intermediate CPU buffer for blit if necessary --- src/backend/drm/DRM.cpp | 12 ++++- src/backend/drm/Renderer.cpp | 95 ++++++++++++++++++++++++++++++++---- src/backend/drm/Renderer.hpp | 9 +++- 3 files changed, 102 insertions(+), 14 deletions(-) diff --git a/src/backend/drm/DRM.cpp b/src/backend/drm/DRM.cpp index 508de51..e4cf95b 100644 --- a/src/backend/drm/DRM.cpp +++ b/src/backend/drm/DRM.cpp @@ -1700,8 +1700,12 @@ bool Aquamarine::CDRMOutput::commitState(bool onlyTest) { } auto NEWAQBUF = mgpu.swapchain->next(nullptr); + SP primaryRenderer; + if (backend->primary) { + primaryRenderer = backend->primary->rendererState.renderer; + } auto blitResult = backend->rendererState.renderer->blit( - STATE.buffer, NEWAQBUF, (COMMITTED & COutputState::eOutputStateProperties::AQ_OUTPUT_STATE_EXPLICIT_IN_FENCE) ? STATE.explicitInFence : -1); + STATE.buffer, NEWAQBUF, primaryRenderer, (COMMITTED & COutputState::eOutputStateProperties::AQ_OUTPUT_STATE_EXPLICIT_IN_FENCE) ? STATE.explicitInFence : -1); if (!blitResult.success) { backend->backend->log(AQ_LOG_ERROR, "drm: Backend requires blit, but blit failed"); return false; @@ -1882,7 +1886,11 @@ bool Aquamarine::CDRMOutput::setCursor(SP buffer, const Vector2D& hotsp } auto NEWAQBUF = mgpu.cursorSwapchain->next(nullptr); - if (!backend->rendererState.renderer->blit(buffer, NEWAQBUF).success) { + SP primaryRenderer; + if (backend->primary) { + primaryRenderer = backend->primary->rendererState.renderer; + } + if (!backend->rendererState.renderer->blit(buffer, NEWAQBUF, primaryRenderer).success) { backend->backend->log(AQ_LOG_ERROR, "drm: Backend requires blit, but cursor blit failed"); return false; } diff --git a/src/backend/drm/Renderer.cpp b/src/backend/drm/Renderer.cpp index 3fc70d5..20cc5e4 100644 --- a/src/backend/drm/Renderer.cpp +++ b/src/backend/drm/Renderer.cpp @@ -341,7 +341,7 @@ void CDRMRenderer::loadEGLAPI() { loadGLProc(&proc.eglWaitSyncKHR, "eglWaitSyncKHR"); loadGLProc(&proc.eglCreateSyncKHR, "eglCreateSyncKHR"); loadGLProc(&proc.eglDupNativeFenceFDANDROID, "eglDupNativeFenceFDANDROID"); - loadGLProc(&proc.glEGLImageTargetRenderbufferStorageOES, "glEGLImageTargetRenderbufferStorageOES"); + loadGLProc(&proc.glReadnPixelsEXT, "glReadnPixelsEXT"); if (EGLEXTENSIONS.contains("EGL_EXT_device_base") || EGLEXTENSIONS.contains("EGL_EXT_device_enumeration")) loadGLProc(&proc.eglQueryDevicesEXT, "eglQueryDevicesEXT"); @@ -698,6 +698,52 @@ SGLTex CDRMRenderer::glTex(Hyprutils::Memory::CSharedPointer buffa) { return tex; } +// TODO: Would another format be more efficient than GL_RGBA? +const GLenum PIXEL_BUFFER_FORMAT = GL_RGBA; + +void CDRMRenderer::readBuffer(Hyprutils::Memory::CSharedPointer buf, uint8_t* out, size_t outlen) { + setEGL(); + + auto hadAttachment = buf->attachments.get(AQ_ATTACHMENT_DRM_RENDERER_DATA); + auto att = (CDRMRendererBufferAttachment*)hadAttachment.get(); + if (!hadAttachment) { + // should never remove anything, but JIC. We'll leak an EGLImage if this removes anything. + buf->attachments.removeByType(AQ_ATTACHMENT_DRM_RENDERER_DATA); + auto newAttachment = makeShared(self, buf, nullptr, 0, 0, SGLTex{}, nullptr, 0); + att = newAttachment.get(); + buf->attachments.add(newAttachment); + } + + auto dma = buf->dmabuf(); + if (!att->eglImage) { + att->eglImage = createEGLImage(dma); + if (att->eglImage == EGL_NO_IMAGE_KHR) { + backend->log(AQ_LOG_ERROR, std::format("EGL (readBuffer): createEGLImage failed: {}", eglGetError())); + return; + } + + GLCALL(glGenRenderbuffers(1, &att->rbo)); + GLCALL(glBindRenderbuffer(GL_RENDERBUFFER, att->rbo)); + GLCALL(proc.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, (GLeglImageOES)att->eglImage)); + GLCALL(glBindRenderbuffer(GL_RENDERBUFFER, 0)); + + GLCALL(glGenFramebuffers(1, &att->fbo)); + GLCALL(glBindFramebuffer(GL_FRAMEBUFFER, att->fbo)); + GLCALL(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, att->rbo)); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + backend->log(AQ_LOG_ERROR, std::format("EGL (readBuffer): glCheckFramebufferStatus failed: {}", glGetError())); + return; + } + } + + GLCALL(glBindFramebuffer(GL_FRAMEBUFFER, att->fbo)); + GLCALL(proc.glReadnPixelsEXT(0, 0, dma.size.x, dma.size.y, GL_RGBA, GL_UNSIGNED_BYTE, outlen, out)); + + GLCALL(glBindFramebuffer(GL_FRAMEBUFFER, 0)); + restoreEGL(); +} + inline const float fullVerts[] = { 1, 0, // top right 0, 0, // top left @@ -828,7 +874,7 @@ void CDRMRenderer::clearBuffer(IBuffer* buf) { restoreEGL(); } -CDRMRenderer::SBlitResult CDRMRenderer::blit(SP from, SP to, int waitFD) { +CDRMRenderer::SBlitResult CDRMRenderer::blit(SP from, SP to, SP primaryRenderer, int waitFD) { setEGL(); if (from->dmabuf().size != to->dmabuf().size) { @@ -846,22 +892,45 @@ CDRMRenderer::SBlitResult CDRMRenderer::blit(SP from, SP to, i // both from and to have the same AQ_ATTACHMENT_DRM_RENDERER_DATA. // Those buffers always come from different swapchains, so it's OK. - SGLTex fromTex; + SGLTex fromTex; + auto fromDma = from->dmabuf(); + uint8_t* intermediateBuf = nullptr; + size_t intermediateBufLen = 0; { auto attachment = from->attachments.get(AQ_ATTACHMENT_DRM_RENDERER_DATA); if (attachment) { TRACE(backend->log(AQ_LOG_TRACE, "EGL (blit): From attachment found")); - auto att = (CDRMRendererBufferAttachment*)attachment.get(); - fromTex = att->tex; + auto att = (CDRMRendererBufferAttachment*)attachment.get(); + fromTex = att->tex; + intermediateBuf = att->intermediateBuf; + intermediateBufLen = att->intermediateBufLen; } - if (!fromTex.image) { + if (!fromTex.image && !intermediateBuf) { backend->log(AQ_LOG_DEBUG, "EGL (blit): No attachment in from, creating a new image"); fromTex = glTex(from); + if (!fromTex.image && primaryRenderer) { + backend->log(AQ_LOG_DEBUG, "EGL (blit): Failed to create image from source buffer directly, allocating intermediate buffer"); + static_assert(PIXEL_BUFFER_FORMAT == GL_RGBA); // If the pixel buffer format changes, the below size calculation probably needs to as well. + intermediateBufLen = fromDma.size.x * fromDma.size.y * 4; + intermediateBuf = (uint8_t*)malloc(intermediateBufLen); + if (intermediateBuf == nullptr) { + backend->log(AQ_LOG_ERROR, "EGL (blit): Failed to allocate intermediate buffer"); + return {}; + } + fromTex.target = GL_TEXTURE_2D; + GLCALL(glGenTextures(1, &fromTex.texid)); + } + // should never remove anything, but JIC. We'll leak an EGLImage if this removes anything. from->attachments.removeByType(AQ_ATTACHMENT_DRM_RENDERER_DATA); - from->attachments.add(makeShared(self, from, nullptr, 0, 0, fromTex)); + from->attachments.add(makeShared(self, from, nullptr, 0, 0, fromTex, intermediateBuf, intermediateBufLen)); + } + + if (intermediateBuf) { + // Note: this might modify from's attachments + primaryRenderer->readBuffer(from, intermediateBuf, intermediateBufLen); } } @@ -916,7 +985,7 @@ CDRMRenderer::SBlitResult CDRMRenderer::blit(SP from, SP to, i // should never remove anything, but JIC. We'll leak an RBO and FBO if this removes anything. to->attachments.removeByType(AQ_ATTACHMENT_DRM_RENDERER_DATA); - to->attachments.add(makeShared(self, to, rboImage, fboID, rboID, SGLTex{})); + to->attachments.add(makeShared(self, to, rboImage, fboID, rboID, SGLTex{}, nullptr, 0)); } } @@ -964,6 +1033,10 @@ CDRMRenderer::SBlitResult CDRMRenderer::blit(SP from, SP to, i GLCALL(glTexParameteri(fromTex.target, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); GLCALL(glTexParameteri(fromTex.target, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); + if (intermediateBuf) { + GLCALL(glTexImage2D(fromTex.target, 0, PIXEL_BUFFER_FORMAT, fromDma.size.x, fromDma.size.y, 0, PIXEL_BUFFER_FORMAT, GL_UNSIGNED_BYTE, intermediateBuf)); + } + GLCALL(glUseProgram(SHADER.program)); GLCALL(glDisable(GL_BLEND)); GLCALL(glDisable(GL_SCISSOR_TEST)); @@ -1018,6 +1091,8 @@ void CDRMRenderer::onBufferAttachmentDrop(CDRMRendererBufferAttachment* attachme proc.eglDestroyImageKHR(egl.display, attachment->eglImage); if (attachment->tex.image) proc.eglDestroyImageKHR(egl.display, attachment->tex.image); + if (attachment->intermediateBuf) + free(attachment->intermediateBuf); restoreEGL(); } @@ -1043,7 +1118,7 @@ bool CDRMRenderer::verifyDestinationDMABUF(const SDMABUFAttrs& attrs) { } CDRMRendererBufferAttachment::CDRMRendererBufferAttachment(Hyprutils::Memory::CWeakPointer renderer_, Hyprutils::Memory::CSharedPointer buffer, - EGLImageKHR image, GLuint fbo_, GLuint rbo_, SGLTex tex_) : - eglImage(image), fbo(fbo_), rbo(rbo_), tex(tex_), renderer(renderer_) { + EGLImageKHR image, GLuint fbo_, GLuint rbo_, SGLTex tex_, uint8_t* intermediateBuf_, size_t intermediateBufLen_) : + eglImage(image), fbo(fbo_), rbo(rbo_), tex(tex_), intermediateBuf(intermediateBuf_), intermediateBufLen(intermediateBufLen_), renderer(renderer_) { bufferDestroy = buffer->events.destroy.registerListener([this](std::any d) { renderer->onBufferAttachmentDrop(this); }); } diff --git a/src/backend/drm/Renderer.hpp b/src/backend/drm/Renderer.hpp index af560d9..40261bb 100644 --- a/src/backend/drm/Renderer.hpp +++ b/src/backend/drm/Renderer.hpp @@ -24,7 +24,7 @@ namespace Aquamarine { class CDRMRendererBufferAttachment : public IAttachment { public: CDRMRendererBufferAttachment(Hyprutils::Memory::CWeakPointer renderer_, Hyprutils::Memory::CSharedPointer buffer, EGLImageKHR image, GLuint fbo_, - GLuint rbo_, SGLTex tex); + GLuint rbo_, SGLTex tex, uint8_t* intermediateBuf, size_t intermediateBufLen); virtual ~CDRMRendererBufferAttachment() { ; } @@ -36,6 +36,8 @@ namespace Aquamarine { GLuint fbo = 0, rbo = 0; SGLTex tex; Hyprutils::Signal::CHyprSignalListener bufferDestroy; + uint8_t* intermediateBuf = nullptr; + size_t intermediateBufLen = 0; Hyprutils::Memory::CWeakPointer renderer; }; @@ -55,7 +57,8 @@ namespace Aquamarine { std::optional syncFD; }; - SBlitResult blit(Hyprutils::Memory::CSharedPointer from, Hyprutils::Memory::CSharedPointer to, int waitFD = -1); + SBlitResult blit(Hyprutils::Memory::CSharedPointer from, Hyprutils::Memory::CSharedPointer to, + Hyprutils::Memory::CSharedPointer primaryRenderer, int waitFD = -1); // can't be a SP<> because we call it from buf's ctor... void clearBuffer(IBuffer* buf); @@ -86,6 +89,7 @@ namespace Aquamarine { PFNEGLDEBUGMESSAGECONTROLKHRPROC eglDebugMessageControlKHR = nullptr; PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT = nullptr; PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT = nullptr; + PFNGLREADNPIXELSEXTPROC glReadnPixelsEXT = nullptr; } proc; struct { @@ -114,6 +118,7 @@ namespace Aquamarine { } savedEGLState; SGLTex glTex(Hyprutils::Memory::CSharedPointer buf); + void readBuffer(Hyprutils::Memory::CSharedPointer buf, uint8_t* out, size_t out_len); Hyprutils::Memory::CWeakPointer self; std::vector formats; From 8ce5a7cf0213f300b08aa3bb2cd4c7706c0f37e6 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Mon, 24 Feb 2025 15:21:46 -0600 Subject: [PATCH 3/7] drm: Add comment and cleanup style a bit --- src/backend/drm/Renderer.cpp | 3 +-- src/backend/drm/Renderer.hpp | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/backend/drm/Renderer.cpp b/src/backend/drm/Renderer.cpp index 20cc5e4..f161c75 100644 --- a/src/backend/drm/Renderer.cpp +++ b/src/backend/drm/Renderer.cpp @@ -1033,9 +1033,8 @@ CDRMRenderer::SBlitResult CDRMRenderer::blit(SP from, SP to, S GLCALL(glTexParameteri(fromTex.target, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); GLCALL(glTexParameteri(fromTex.target, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); - if (intermediateBuf) { + if (intermediateBuf) GLCALL(glTexImage2D(fromTex.target, 0, PIXEL_BUFFER_FORMAT, fromDma.size.x, fromDma.size.y, 0, PIXEL_BUFFER_FORMAT, GL_UNSIGNED_BYTE, intermediateBuf)); - } GLCALL(glUseProgram(SHADER.program)); GLCALL(glDisable(GL_BLEND)); diff --git a/src/backend/drm/Renderer.hpp b/src/backend/drm/Renderer.hpp index 40261bb..e8fc28c 100644 --- a/src/backend/drm/Renderer.hpp +++ b/src/backend/drm/Renderer.hpp @@ -36,6 +36,8 @@ namespace Aquamarine { GLuint fbo = 0, rbo = 0; SGLTex tex; Hyprutils::Signal::CHyprSignalListener bufferDestroy; + // This is malloc'd manually instead of using a std::vector to keep lifetime management in line with the rest of the class, + // which e.g. doesn't immediately free the eglImage on drop but instead waits until onBufferAttachmentDrop. uint8_t* intermediateBuf = nullptr; size_t intermediateBufLen = 0; From 96cbe55baee90d2e25dbb6b8bf36d71d17d11849 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Mon, 24 Feb 2025 15:23:40 -0600 Subject: [PATCH 4/7] drm: Fix formatting from comment addition --- src/backend/drm/Renderer.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/backend/drm/Renderer.hpp b/src/backend/drm/Renderer.hpp index e8fc28c..3d086f8 100644 --- a/src/backend/drm/Renderer.hpp +++ b/src/backend/drm/Renderer.hpp @@ -32,10 +32,10 @@ namespace Aquamarine { return AQ_ATTACHMENT_DRM_RENDERER_DATA; } - EGLImageKHR eglImage = nullptr; - GLuint fbo = 0, rbo = 0; - SGLTex tex; - Hyprutils::Signal::CHyprSignalListener bufferDestroy; + EGLImageKHR eglImage = nullptr; + GLuint fbo = 0, rbo = 0; + SGLTex tex; + Hyprutils::Signal::CHyprSignalListener bufferDestroy; // This is malloc'd manually instead of using a std::vector to keep lifetime management in line with the rest of the class, // which e.g. doesn't immediately free the eglImage on drop but instead waits until onBufferAttachmentDrop. uint8_t* intermediateBuf = nullptr; From b7f01bfdda3fbf8538c9484498c237c79144dba6 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Tue, 25 Feb 2025 09:31:07 -0600 Subject: [PATCH 5/7] drm: Use std::vector and std::span for intermediateBuf --- src/backend/drm/Renderer.cpp | 54 ++++++++++++++++-------------------- src/backend/drm/Renderer.hpp | 17 +++++------- 2 files changed, 31 insertions(+), 40 deletions(-) diff --git a/src/backend/drm/Renderer.cpp b/src/backend/drm/Renderer.cpp index f161c75..4e9f241 100644 --- a/src/backend/drm/Renderer.cpp +++ b/src/backend/drm/Renderer.cpp @@ -9,6 +9,7 @@ #include "Shared.hpp" #include "FormatUtils.hpp" #include +#include using namespace Aquamarine; using namespace Hyprutils::Memory; @@ -699,9 +700,9 @@ SGLTex CDRMRenderer::glTex(Hyprutils::Memory::CSharedPointer buffa) { } // TODO: Would another format be more efficient than GL_RGBA? -const GLenum PIXEL_BUFFER_FORMAT = GL_RGBA; +constexpr GLenum PIXEL_BUFFER_FORMAT = GL_RGBA; -void CDRMRenderer::readBuffer(Hyprutils::Memory::CSharedPointer buf, uint8_t* out, size_t outlen) { +void CDRMRenderer::readBuffer(Hyprutils::Memory::CSharedPointer buf, std::span out) { setEGL(); auto hadAttachment = buf->attachments.get(AQ_ATTACHMENT_DRM_RENDERER_DATA); @@ -709,7 +710,7 @@ void CDRMRenderer::readBuffer(Hyprutils::Memory::CSharedPointer if (!hadAttachment) { // should never remove anything, but JIC. We'll leak an EGLImage if this removes anything. buf->attachments.removeByType(AQ_ATTACHMENT_DRM_RENDERER_DATA); - auto newAttachment = makeShared(self, buf, nullptr, 0, 0, SGLTex{}, nullptr, 0); + auto newAttachment = makeShared(self, buf, nullptr, 0, 0, SGLTex{}, std::vector()); att = newAttachment.get(); buf->attachments.add(newAttachment); } @@ -738,7 +739,7 @@ void CDRMRenderer::readBuffer(Hyprutils::Memory::CSharedPointer } GLCALL(glBindFramebuffer(GL_FRAMEBUFFER, att->fbo)); - GLCALL(proc.glReadnPixelsEXT(0, 0, dma.size.x, dma.size.y, GL_RGBA, GL_UNSIGNED_BYTE, outlen, out)); + GLCALL(proc.glReadnPixelsEXT(0, 0, dma.size.x, dma.size.y, GL_RGBA, GL_UNSIGNED_BYTE, out.size(), out.data())); GLCALL(glBindFramebuffer(GL_FRAMEBUFFER, 0)); restoreEGL(); @@ -892,45 +893,40 @@ CDRMRenderer::SBlitResult CDRMRenderer::blit(SP from, SP to, S // both from and to have the same AQ_ATTACHMENT_DRM_RENDERER_DATA. // Those buffers always come from different swapchains, so it's OK. - SGLTex fromTex; - auto fromDma = from->dmabuf(); - uint8_t* intermediateBuf = nullptr; - size_t intermediateBufLen = 0; + SGLTex fromTex; + auto fromDma = from->dmabuf(); + std::span intermediateBuf; { auto attachment = from->attachments.get(AQ_ATTACHMENT_DRM_RENDERER_DATA); if (attachment) { TRACE(backend->log(AQ_LOG_TRACE, "EGL (blit): From attachment found")); - auto att = (CDRMRendererBufferAttachment*)attachment.get(); - fromTex = att->tex; - intermediateBuf = att->intermediateBuf; - intermediateBufLen = att->intermediateBufLen; + auto att = (CDRMRendererBufferAttachment*)attachment.get(); + fromTex = att->tex; + intermediateBuf = att->intermediateBuf; } - if (!fromTex.image && !intermediateBuf) { + if (!fromTex.image && intermediateBuf.empty()) { backend->log(AQ_LOG_DEBUG, "EGL (blit): No attachment in from, creating a new image"); fromTex = glTex(from); + auto newAttachment = makeShared(self, from, nullptr, 0, 0, fromTex, std::vector()); if (!fromTex.image && primaryRenderer) { backend->log(AQ_LOG_DEBUG, "EGL (blit): Failed to create image from source buffer directly, allocating intermediate buffer"); static_assert(PIXEL_BUFFER_FORMAT == GL_RGBA); // If the pixel buffer format changes, the below size calculation probably needs to as well. - intermediateBufLen = fromDma.size.x * fromDma.size.y * 4; - intermediateBuf = (uint8_t*)malloc(intermediateBufLen); - if (intermediateBuf == nullptr) { - backend->log(AQ_LOG_ERROR, "EGL (blit): Failed to allocate intermediate buffer"); - return {}; - } - fromTex.target = GL_TEXTURE_2D; + newAttachment->intermediateBuf.resize(fromDma.size.x * fromDma.size.y * 4); + intermediateBuf = newAttachment->intermediateBuf; + fromTex.target = GL_TEXTURE_2D; GLCALL(glGenTextures(1, &fromTex.texid)); } // should never remove anything, but JIC. We'll leak an EGLImage if this removes anything. from->attachments.removeByType(AQ_ATTACHMENT_DRM_RENDERER_DATA); - from->attachments.add(makeShared(self, from, nullptr, 0, 0, fromTex, intermediateBuf, intermediateBufLen)); + from->attachments.add(newAttachment); } - if (intermediateBuf) { + if (!intermediateBuf.empty()) { // Note: this might modify from's attachments - primaryRenderer->readBuffer(from, intermediateBuf, intermediateBufLen); + primaryRenderer->readBuffer(from, intermediateBuf); } } @@ -985,7 +981,7 @@ CDRMRenderer::SBlitResult CDRMRenderer::blit(SP from, SP to, S // should never remove anything, but JIC. We'll leak an RBO and FBO if this removes anything. to->attachments.removeByType(AQ_ATTACHMENT_DRM_RENDERER_DATA); - to->attachments.add(makeShared(self, to, rboImage, fboID, rboID, SGLTex{}, nullptr, 0)); + to->attachments.add(makeShared(self, to, rboImage, fboID, rboID, SGLTex{}, std::vector())); } } @@ -1033,8 +1029,8 @@ CDRMRenderer::SBlitResult CDRMRenderer::blit(SP from, SP to, S GLCALL(glTexParameteri(fromTex.target, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); GLCALL(glTexParameteri(fromTex.target, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); - if (intermediateBuf) - GLCALL(glTexImage2D(fromTex.target, 0, PIXEL_BUFFER_FORMAT, fromDma.size.x, fromDma.size.y, 0, PIXEL_BUFFER_FORMAT, GL_UNSIGNED_BYTE, intermediateBuf)); + if (!intermediateBuf.empty()) + GLCALL(glTexImage2D(fromTex.target, 0, PIXEL_BUFFER_FORMAT, fromDma.size.x, fromDma.size.y, 0, PIXEL_BUFFER_FORMAT, GL_UNSIGNED_BYTE, intermediateBuf.data())); GLCALL(glUseProgram(SHADER.program)); GLCALL(glDisable(GL_BLEND)); @@ -1090,8 +1086,6 @@ void CDRMRenderer::onBufferAttachmentDrop(CDRMRendererBufferAttachment* attachme proc.eglDestroyImageKHR(egl.display, attachment->eglImage); if (attachment->tex.image) proc.eglDestroyImageKHR(egl.display, attachment->tex.image); - if (attachment->intermediateBuf) - free(attachment->intermediateBuf); restoreEGL(); } @@ -1117,7 +1111,7 @@ bool CDRMRenderer::verifyDestinationDMABUF(const SDMABUFAttrs& attrs) { } CDRMRendererBufferAttachment::CDRMRendererBufferAttachment(Hyprutils::Memory::CWeakPointer renderer_, Hyprutils::Memory::CSharedPointer buffer, - EGLImageKHR image, GLuint fbo_, GLuint rbo_, SGLTex tex_, uint8_t* intermediateBuf_, size_t intermediateBufLen_) : - eglImage(image), fbo(fbo_), rbo(rbo_), tex(tex_), intermediateBuf(intermediateBuf_), intermediateBufLen(intermediateBufLen_), renderer(renderer_) { + EGLImageKHR image, GLuint fbo_, GLuint rbo_, SGLTex tex_, std::vector intermediateBuf_) : + eglImage(image), fbo(fbo_), rbo(rbo_), tex(tex_), intermediateBuf(intermediateBuf_), renderer(renderer_) { bufferDestroy = buffer->events.destroy.registerListener([this](std::any d) { renderer->onBufferAttachmentDrop(this); }); } diff --git a/src/backend/drm/Renderer.hpp b/src/backend/drm/Renderer.hpp index 3d086f8..c3ff004 100644 --- a/src/backend/drm/Renderer.hpp +++ b/src/backend/drm/Renderer.hpp @@ -24,7 +24,7 @@ namespace Aquamarine { class CDRMRendererBufferAttachment : public IAttachment { public: CDRMRendererBufferAttachment(Hyprutils::Memory::CWeakPointer renderer_, Hyprutils::Memory::CSharedPointer buffer, EGLImageKHR image, GLuint fbo_, - GLuint rbo_, SGLTex tex, uint8_t* intermediateBuf, size_t intermediateBufLen); + GLuint rbo_, SGLTex tex, std::vector intermediateBuf_); virtual ~CDRMRendererBufferAttachment() { ; } @@ -32,14 +32,11 @@ namespace Aquamarine { return AQ_ATTACHMENT_DRM_RENDERER_DATA; } - EGLImageKHR eglImage = nullptr; - GLuint fbo = 0, rbo = 0; - SGLTex tex; - Hyprutils::Signal::CHyprSignalListener bufferDestroy; - // This is malloc'd manually instead of using a std::vector to keep lifetime management in line with the rest of the class, - // which e.g. doesn't immediately free the eglImage on drop but instead waits until onBufferAttachmentDrop. - uint8_t* intermediateBuf = nullptr; - size_t intermediateBufLen = 0; + EGLImageKHR eglImage = nullptr; + GLuint fbo = 0, rbo = 0; + SGLTex tex; + Hyprutils::Signal::CHyprSignalListener bufferDestroy; + std::vector intermediateBuf; Hyprutils::Memory::CWeakPointer renderer; }; @@ -120,7 +117,7 @@ namespace Aquamarine { } savedEGLState; SGLTex glTex(Hyprutils::Memory::CSharedPointer buf); - void readBuffer(Hyprutils::Memory::CSharedPointer buf, uint8_t* out, size_t out_len); + void readBuffer(Hyprutils::Memory::CSharedPointer buf, std::span out); Hyprutils::Memory::CWeakPointer self; std::vector formats; From bcbe886c03ba2b3e3154cf6d84b22264636a8735 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Wed, 26 Feb 2025 09:11:30 -0600 Subject: [PATCH 6/7] drm: Fix style and add null check --- src/backend/drm/DRM.cpp | 10 ++++------ src/backend/drm/Renderer.cpp | 3 +-- src/backend/drm/Renderer.hpp | 1 + 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/backend/drm/DRM.cpp b/src/backend/drm/DRM.cpp index e4cf95b..7777d8c 100644 --- a/src/backend/drm/DRM.cpp +++ b/src/backend/drm/DRM.cpp @@ -1699,11 +1699,10 @@ bool Aquamarine::CDRMOutput::commitState(bool onlyTest) { return false; } - auto NEWAQBUF = mgpu.swapchain->next(nullptr); + auto NEWAQBUF = mgpu.swapchain->next(nullptr); SP primaryRenderer; - if (backend->primary) { + if (backend->primary) primaryRenderer = backend->primary->rendererState.renderer; - } auto blitResult = backend->rendererState.renderer->blit( STATE.buffer, NEWAQBUF, primaryRenderer, (COMMITTED & COutputState::eOutputStateProperties::AQ_OUTPUT_STATE_EXPLICIT_IN_FENCE) ? STATE.explicitInFence : -1); if (!blitResult.success) { @@ -1885,11 +1884,10 @@ bool Aquamarine::CDRMOutput::setCursor(SP buffer, const Vector2D& hotsp return false; } - auto NEWAQBUF = mgpu.cursorSwapchain->next(nullptr); + auto NEWAQBUF = mgpu.cursorSwapchain->next(nullptr); SP primaryRenderer; - if (backend->primary) { + if (backend->primary) primaryRenderer = backend->primary->rendererState.renderer; - } if (!backend->rendererState.renderer->blit(buffer, NEWAQBUF, primaryRenderer).success) { backend->backend->log(AQ_LOG_ERROR, "drm: Backend requires blit, but cursor blit failed"); return false; diff --git a/src/backend/drm/Renderer.cpp b/src/backend/drm/Renderer.cpp index 4e9f241..9625ad2 100644 --- a/src/backend/drm/Renderer.cpp +++ b/src/backend/drm/Renderer.cpp @@ -9,7 +9,6 @@ #include "Shared.hpp" #include "FormatUtils.hpp" #include -#include using namespace Aquamarine; using namespace Hyprutils::Memory; @@ -924,7 +923,7 @@ CDRMRenderer::SBlitResult CDRMRenderer::blit(SP from, SP to, S from->attachments.add(newAttachment); } - if (!intermediateBuf.empty()) { + if (!intermediateBuf.empty() && primaryRenderer) { // Note: this might modify from's attachments primaryRenderer->readBuffer(from, intermediateBuf); } diff --git a/src/backend/drm/Renderer.hpp b/src/backend/drm/Renderer.hpp index c3ff004..ef8763e 100644 --- a/src/backend/drm/Renderer.hpp +++ b/src/backend/drm/Renderer.hpp @@ -10,6 +10,7 @@ #include #include #include +#include namespace Aquamarine { From 9347746ecea57ba7c736d651d4731a58b37e38a3 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Wed, 26 Feb 2025 09:12:11 -0600 Subject: [PATCH 7/7] drm: Remove TODO about pixel buf format --- src/backend/drm/Renderer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/backend/drm/Renderer.cpp b/src/backend/drm/Renderer.cpp index 9625ad2..0745f8c 100644 --- a/src/backend/drm/Renderer.cpp +++ b/src/backend/drm/Renderer.cpp @@ -698,7 +698,6 @@ SGLTex CDRMRenderer::glTex(Hyprutils::Memory::CSharedPointer buffa) { return tex; } -// TODO: Would another format be more efficient than GL_RGBA? constexpr GLenum PIXEL_BUFFER_FORMAT = GL_RGBA; void CDRMRenderer::readBuffer(Hyprutils::Memory::CSharedPointer buf, std::span out) {