drm: clear buffer on creation for scanout DRM buffers (#51)

This commit is contained in:
Vaxry 2024-08-17 19:42:51 +01:00 committed by GitHub
parent cd152140fd
commit 71d49670fe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 89 additions and 20 deletions

View file

@ -14,11 +14,16 @@ namespace Aquamarine {
bool scanout = false, cursor = false, multigpu = false;
};
enum eAllocatorType {
AQ_ALLOCATOR_TYPE_GBM = 0,
};
class IAllocator {
public:
virtual ~IAllocator() = default;
virtual Hyprutils::Memory::CSharedPointer<IBuffer> acquire(const SAllocatorBufferParams& params, Hyprutils::Memory::CSharedPointer<CSwapchain> swapchain) = 0;
virtual Hyprutils::Memory::CSharedPointer<CBackend> getBackend() = 0;
virtual int drmFD() = 0;
virtual eAllocatorType type() = 0;
};
};

View file

@ -45,6 +45,7 @@ namespace Aquamarine {
virtual Hyprutils::Memory::CSharedPointer<IBuffer> acquire(const SAllocatorBufferParams& params, Hyprutils::Memory::CSharedPointer<CSwapchain> swapchain_);
virtual Hyprutils::Memory::CSharedPointer<CBackend> getBackend();
virtual int drmFD();
virtual eAllocatorType type();
//
Hyprutils::Memory::CWeakPointer<CGBMAllocator> self;

View file

@ -374,11 +374,10 @@ namespace Aquamarine {
Hyprutils::Memory::CSharedPointer<IDRMImplementation> impl;
Hyprutils::Memory::CWeakPointer<CDRMBackend> primary;
// multigpu state, only present if this backend is not primary, aka if this->primary != nullptr
struct {
Hyprutils::Memory::CSharedPointer<IAllocator> allocator;
Hyprutils::Memory::CSharedPointer<CDRMRenderer> renderer;
} mgpu;
} rendererState;
Hyprutils::Memory::CWeakPointer<CBackend> backend;
@ -415,5 +414,6 @@ namespace Aquamarine {
friend class CDRMAtomicImpl;
friend class CDRMAtomicRequest;
friend class CDRMLease;
friend class CGBMBuffer;
};
};

View file

@ -1,11 +1,13 @@
#include <aquamarine/allocator/GBM.hpp>
#include <aquamarine/backend/Backend.hpp>
#include <aquamarine/backend/DRM.hpp>
#include <aquamarine/allocator/Swapchain.hpp>
#include "FormatUtils.hpp"
#include "Shared.hpp"
#include <xf86drm.h>
#include <gbm.h>
#include <unistd.h>
#include "../backend/drm/Renderer.hpp"
using namespace Aquamarine;
using namespace Hyprutils::Memory;
@ -186,6 +188,12 @@ Aquamarine::CGBMBuffer::CGBMBuffer(const SAllocatorBufferParams& params, Hypruti
modName ? modName : "Unknown"));
free(modName);
if (params.scanout && swapchain->backendImpl->type() == AQ_BACKEND_DRM) {
// clear the buffer using the DRM renderer to avoid uninitialized mem
auto impl = (CDRMBackend*)swapchain->backendImpl.get();
impl->rendererState.renderer->clearBuffer(this);
}
}
Aquamarine::CGBMBuffer::~CGBMBuffer() {
@ -305,3 +313,7 @@ Hyprutils::Memory::CSharedPointer<CBackend> Aquamarine::CGBMAllocator::getBacken
int Aquamarine::CGBMAllocator::drmFD() {
return fd;
}
eAllocatorType Aquamarine::CGBMAllocator::type() {
return AQ_ALLOCATOR_TYPE_GBM;
}

View file

@ -493,27 +493,30 @@ bool Aquamarine::CDRMBackend::shouldBlit() {
}
bool Aquamarine::CDRMBackend::initMgpu() {
if (!primary)
return true;
SP<CGBMAllocator> newAllocator;
if (primary || backend->primaryAllocator->type() != AQ_ALLOCATOR_TYPE_GBM) {
newAllocator = CGBMAllocator::create(backend->reopenDRMNode(gpu->fd), backend);
rendererState.allocator = newAllocator;
} else {
newAllocator = ((CGBMAllocator*)backend->primaryAllocator.get())->self.lock();
rendererState.allocator = newAllocator;
}
auto newAllocator = CGBMAllocator::create(backend->reopenDRMNode(gpu->fd), backend);
mgpu.allocator = newAllocator;
if (!mgpu.allocator) {
if (!rendererState.allocator) {
backend->log(AQ_LOG_ERROR, "drm: initMgpu: no allocator");
return false;
}
mgpu.renderer = CDRMRenderer::attempt(newAllocator, backend.lock());
rendererState.renderer = CDRMRenderer::attempt(newAllocator, backend.lock());
if (!mgpu.renderer) {
if (!rendererState.renderer) {
backend->log(AQ_LOG_ERROR, "drm: initMgpu: no renderer");
return false;
}
mgpu.renderer->self = mgpu.renderer;
rendererState.renderer->self = rendererState.renderer;
buildGlFormats(mgpu.renderer->formats);
buildGlFormats(rendererState.renderer->formats);
return true;
}
@ -1463,7 +1466,7 @@ bool Aquamarine::CDRMOutput::commitState(bool onlyTest) {
if (!mgpu.swapchain) {
TRACE(backend->backend->log(AQ_LOG_TRACE, "drm: No swapchain for blit, creating"));
mgpu.swapchain = CSwapchain::create(backend->mgpu.allocator, backend.lock());
mgpu.swapchain = CSwapchain::create(backend->rendererState.allocator, backend.lock());
}
auto OPTIONS = swapchain->currentOptions();
@ -1480,8 +1483,8 @@ bool Aquamarine::CDRMOutput::commitState(bool onlyTest) {
}
auto NEWAQBUF = mgpu.swapchain->next(nullptr);
auto blitResult = backend->mgpu.renderer->blit(STATE.buffer, NEWAQBUF,
(COMMITTED & COutputState::eOutputStateProperties::AQ_OUTPUT_STATE_EXPLICIT_IN_FENCE) ? STATE.explicitInFence : -1);
auto blitResult = backend->rendererState.renderer->blit(
STATE.buffer, NEWAQBUF, (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;
@ -1623,7 +1626,7 @@ bool Aquamarine::CDRMOutput::setCursor(SP<IBuffer> buffer, const Vector2D& hotsp
if (!mgpu.cursorSwapchain) {
TRACE(backend->backend->log(AQ_LOG_TRACE, "drm: No cursorSwapchain for blit, creating"));
mgpu.cursorSwapchain = CSwapchain::create(backend->mgpu.allocator, backend.lock());
mgpu.cursorSwapchain = CSwapchain::create(backend->rendererState.allocator, backend.lock());
}
auto OPTIONS = mgpu.cursorSwapchain->currentOptions();
@ -1640,7 +1643,7 @@ bool Aquamarine::CDRMOutput::setCursor(SP<IBuffer> buffer, const Vector2D& hotsp
}
auto NEWAQBUF = mgpu.cursorSwapchain->next(nullptr);
if (!backend->mgpu.renderer->blit(buffer, NEWAQBUF).success) {
if (!backend->rendererState.renderer->blit(buffer, NEWAQBUF).success) {
backend->backend->log(AQ_LOG_ERROR, "drm: Backend requires blit, but cursor blit failed");
return false;
}

View file

@ -561,6 +561,52 @@ int CDRMRenderer::recreateBlitSync() {
return fd;
}
void CDRMRenderer::clearBuffer(IBuffer* buf) {
setEGL();
auto dmabuf = buf->dmabuf();
GLuint rboID = 0, fboID = 0;
if (!dmabuf.success) {
backend->log(AQ_LOG_ERROR, "EGL (clear): cannot clear a non-dmabuf");
return;
}
auto rboImage = createEGLImage(dmabuf);
if (rboImage == EGL_NO_IMAGE_KHR) {
backend->log(AQ_LOG_ERROR, std::format("EGL (clear): createEGLImage failed: {}", eglGetError()));
return;
}
GLCALL(glGenRenderbuffers(1, &rboID));
GLCALL(glBindRenderbuffer(GL_RENDERBUFFER, rboID));
GLCALL(egl.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, (GLeglImageOES)rboImage));
GLCALL(glBindRenderbuffer(GL_RENDERBUFFER, 0));
GLCALL(glGenFramebuffers(1, &fboID));
GLCALL(glBindFramebuffer(GL_FRAMEBUFFER, fboID));
GLCALL(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rboID));
GLCALL(glBindRenderbuffer(GL_RENDERBUFFER, rboID));
GLCALL(glBindFramebuffer(GL_FRAMEBUFFER, fboID));
TRACE(backend->log(AQ_LOG_TRACE, std::format("EGL (clear): fbo {} rbo {}", fboID, rboID)));
glClearColor(0.F, 0.F, 0.F, 1.F);
glClear(GL_COLOR_BUFFER_BIT);
glFlush();
GLCALL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
GLCALL(glBindRenderbuffer(GL_RENDERBUFFER, 0));
glDeleteFramebuffers(1, &fboID);
glDeleteRenderbuffers(1, &rboID);
egl.eglDestroyImageKHR(egl.display, rboImage);
restoreEGL();
}
CDRMRenderer::SBlitResult CDRMRenderer::blit(SP<IBuffer> from, SP<IBuffer> to, int waitFD) {
setEGL();

View file

@ -53,11 +53,13 @@ namespace Aquamarine {
};
SBlitResult blit(Hyprutils::Memory::CSharedPointer<IBuffer> from, Hyprutils::Memory::CSharedPointer<IBuffer> to, int waitFD = -1);
// can't be a SP<> because we call it from buf's ctor...
void clearBuffer(IBuffer* buf);
void setEGL();
void restoreEGL();
void setEGL();
void restoreEGL();
void onBufferAttachmentDrop(CDRMRendererBufferAttachment* attachment);
void onBufferAttachmentDrop(CDRMRendererBufferAttachment* attachment);
struct {
struct SShader {