mirror of
https://github.com/hyprwm/aquamarine.git
synced 2024-11-17 06:06:00 +01:00
drm: better handle drm blits
This commit is contained in:
parent
46ce868cbb
commit
d619af4971
5 changed files with 142 additions and 46 deletions
|
@ -7,6 +7,7 @@ namespace Aquamarine {
|
||||||
enum eAttachmentType : uint32_t {
|
enum eAttachmentType : uint32_t {
|
||||||
AQ_ATTACHMENT_DRM_BUFFER = 0,
|
AQ_ATTACHMENT_DRM_BUFFER = 0,
|
||||||
AQ_ATTACHMENT_DRM_KMS_UNIMPORTABLE,
|
AQ_ATTACHMENT_DRM_KMS_UNIMPORTABLE,
|
||||||
|
AQ_ATTACHMENT_DRM_RENDERER_DATA,
|
||||||
};
|
};
|
||||||
|
|
||||||
class IAttachment {
|
class IAttachment {
|
||||||
|
|
|
@ -496,6 +496,8 @@ bool Aquamarine::CDRMBackend::initMgpu() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mgpu.renderer->self = mgpu.renderer;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include "Math.hpp"
|
#include "Math.hpp"
|
||||||
#include "Shared.hpp"
|
#include "Shared.hpp"
|
||||||
|
#include "FormatUtils.hpp"
|
||||||
|
|
||||||
using namespace Aquamarine;
|
using namespace Aquamarine;
|
||||||
using namespace Hyprutils::Memory;
|
using namespace Hyprutils::Memory;
|
||||||
|
@ -276,6 +277,8 @@ EGLImageKHR CDRMRenderer::createEGLImage(const SDMABUFAttrs& attrs) {
|
||||||
attribs.push_back(EGL_LINUX_DRM_FOURCC_EXT);
|
attribs.push_back(EGL_LINUX_DRM_FOURCC_EXT);
|
||||||
attribs.push_back(attrs.format);
|
attribs.push_back(attrs.format);
|
||||||
|
|
||||||
|
TRACE(backend->log(AQ_LOG_TRACE, std::format("EGL: createEGLImage: size {} with format {}", attrs.size, fourccToName(attrs.format))));
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
EGLint fd;
|
EGLint fd;
|
||||||
EGLint offset;
|
EGLint offset;
|
||||||
|
@ -364,24 +367,56 @@ bool CDRMRenderer::blit(SP<IBuffer> from, SP<IBuffer> to) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// firstly, get a texture from the from buffer
|
// firstly, get a texture from the from buffer
|
||||||
auto fromTex = glTex(from);
|
// if it has an attachment, use that
|
||||||
|
// both from and to have the same AQ_ATTACHMENT_DRM_RENDERER_DATA.
|
||||||
|
// Those buffers always come from different swapchains, so it's OK.
|
||||||
|
|
||||||
|
GLTex fromTex;
|
||||||
|
{
|
||||||
|
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->eglImage, att->texid};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fromTex.image) {
|
||||||
|
backend->log(AQ_LOG_DEBUG, "EGL (blit): No attachment in from, creating a new image");
|
||||||
|
fromTex = glTex(from);
|
||||||
|
|
||||||
|
// 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<CDRMRendererBufferAttachment>(self, from, fromTex.image, 0, 0, fromTex.texid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TRACE(backend->log(AQ_LOG_TRACE, std::format("EGL (blit): fromTex id {}, image 0x{:x}", fromTex.texid, (uintptr_t)fromTex.image)));
|
TRACE(backend->log(AQ_LOG_TRACE, std::format("EGL (blit): fromTex id {}, image 0x{:x}", fromTex.texid, (uintptr_t)fromTex.image)));
|
||||||
|
|
||||||
// then, get a rbo from our to buffer
|
// then, get a rbo from our to buffer
|
||||||
auto toDma = to->dmabuf();
|
// if it has an attachment, use that
|
||||||
|
|
||||||
auto rboImage = createEGLImage(toDma);
|
EGLImageKHR rboImage = nullptr;
|
||||||
|
GLuint rboID = 0, fboID = 0;
|
||||||
|
auto toDma = to->dmabuf();
|
||||||
|
{
|
||||||
|
auto attachment = to->attachments.get(AQ_ATTACHMENT_DRM_RENDERER_DATA);
|
||||||
|
if (attachment) {
|
||||||
|
TRACE(backend->log(AQ_LOG_TRACE, "EGL (blit): To attachment found"));
|
||||||
|
auto att = (CDRMRendererBufferAttachment*)attachment.get();
|
||||||
|
rboImage = att->eglImage;
|
||||||
|
fboID = att->fbo;
|
||||||
|
rboID = att->rbo;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rboImage) {
|
||||||
|
backend->log(AQ_LOG_DEBUG, "EGL (blit): No attachment in to, creating a new image");
|
||||||
|
|
||||||
|
rboImage = createEGLImage(toDma);
|
||||||
if (rboImage == EGL_NO_IMAGE_KHR) {
|
if (rboImage == EGL_NO_IMAGE_KHR) {
|
||||||
backend->log(AQ_LOG_ERROR, std::format("EGL (blit): createEGLImage failed: {}", eglGetError()));
|
backend->log(AQ_LOG_ERROR, std::format("EGL (blit): createEGLImage failed: {}", eglGetError()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE(backend->log(AQ_LOG_TRACE, std::format("EGL (blit): rboImage 0x{:x}", (uintptr_t)rboImage)));
|
|
||||||
|
|
||||||
GLuint rboID = 0, fboID = 0;
|
|
||||||
|
|
||||||
// TODO: don't spam this?
|
|
||||||
GLCALL(glGenRenderbuffers(1, &rboID));
|
GLCALL(glGenRenderbuffers(1, &rboID));
|
||||||
GLCALL(glBindRenderbuffer(GL_RENDERBUFFER, rboID));
|
GLCALL(glBindRenderbuffer(GL_RENDERBUFFER, rboID));
|
||||||
egl.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, (GLeglImageOES)rboImage);
|
egl.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, (GLeglImageOES)rboImage);
|
||||||
|
@ -396,6 +431,14 @@ bool CDRMRenderer::blit(SP<IBuffer> from, SP<IBuffer> to) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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<CDRMRendererBufferAttachment>(self, to, rboImage, fboID, rboID, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE(backend->log(AQ_LOG_TRACE, std::format("EGL (blit): rboImage 0x{:x}", (uintptr_t)rboImage)));
|
||||||
|
|
||||||
GLCALL(glBindRenderbuffer(GL_RENDERBUFFER, rboID));
|
GLCALL(glBindRenderbuffer(GL_RENDERBUFFER, rboID));
|
||||||
GLCALL(glBindFramebuffer(GL_FRAMEBUFFER, fboID));
|
GLCALL(glBindFramebuffer(GL_FRAMEBUFFER, fboID));
|
||||||
|
|
||||||
|
@ -410,12 +453,18 @@ bool CDRMRenderer::blit(SP<IBuffer> from, SP<IBuffer> to) {
|
||||||
TRACE(backend->log(AQ_LOG_TRACE, std::format("EGL (blit): box size {}", renderBox.size())));
|
TRACE(backend->log(AQ_LOG_TRACE, std::format("EGL (blit): box size {}", renderBox.size())));
|
||||||
|
|
||||||
float mtx[9];
|
float mtx[9];
|
||||||
float identity[9];
|
float base[9];
|
||||||
float monitorProj[9];
|
float monitorProj[9];
|
||||||
matrixIdentity(identity);
|
matrixIdentity(base);
|
||||||
projectBox(mtx, renderBox, HYPRUTILS_TRANSFORM_NORMAL, 0, identity);
|
|
||||||
|
|
||||||
matrixProjection(monitorProj, toDma.size.x, toDma.size.y, HYPRUTILS_TRANSFORM_NORMAL);
|
// KMS uses flipped y, we have to do FLIPPED_180
|
||||||
|
matrixTranslate(base, toDma.size.x / 2.0, toDma.size.y / 2.0);
|
||||||
|
matrixTransform(base, HYPRUTILS_TRANSFORM_FLIPPED_180);
|
||||||
|
matrixTranslate(base, -toDma.size.x / 2.0, -toDma.size.y / 2.0);
|
||||||
|
|
||||||
|
projectBox(mtx, renderBox, HYPRUTILS_TRANSFORM_FLIPPED_180, 0, base);
|
||||||
|
|
||||||
|
matrixProjection(monitorProj, toDma.size.x, toDma.size.y, HYPRUTILS_TRANSFORM_FLIPPED_180);
|
||||||
|
|
||||||
float glMtx[9];
|
float glMtx[9];
|
||||||
matrixMultiply(glMtx, monitorProj, mtx);
|
matrixMultiply(glMtx, monitorProj, mtx);
|
||||||
|
@ -424,6 +473,10 @@ bool CDRMRenderer::blit(SP<IBuffer> from, SP<IBuffer> to) {
|
||||||
|
|
||||||
GLCALL(glActiveTexture(GL_TEXTURE0));
|
GLCALL(glActiveTexture(GL_TEXTURE0));
|
||||||
GLCALL(glBindTexture(GL_TEXTURE_2D, fromTex.texid));
|
GLCALL(glBindTexture(GL_TEXTURE_2D, fromTex.texid));
|
||||||
|
|
||||||
|
GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
|
||||||
|
GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
|
||||||
|
|
||||||
GLCALL(glUseProgram(gl.shader.program));
|
GLCALL(glUseProgram(gl.shader.program));
|
||||||
GLCALL(glDisable(GL_BLEND));
|
GLCALL(glDisable(GL_BLEND));
|
||||||
GLCALL(glDisable(GL_SCISSOR_TEST));
|
GLCALL(glDisable(GL_SCISSOR_TEST));
|
||||||
|
@ -448,18 +501,36 @@ bool CDRMRenderer::blit(SP<IBuffer> from, SP<IBuffer> to) {
|
||||||
|
|
||||||
// rendered, cleanup
|
// rendered, cleanup
|
||||||
|
|
||||||
GLCALL(glBindRenderbuffer(GL_RENDERBUFFER, 0));
|
glFlush();
|
||||||
|
|
||||||
GLCALL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
|
GLCALL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
|
||||||
|
GLCALL(glBindRenderbuffer(GL_RENDERBUFFER, 0));
|
||||||
GLCALL(glDeleteTextures(1, &fromTex.texid));
|
|
||||||
|
|
||||||
GLCALL(glDeleteRenderbuffers(1, &rboID));
|
|
||||||
GLCALL(glDeleteFramebuffers(1, &fboID));
|
|
||||||
|
|
||||||
egl.eglDestroyImageKHR(egl.display, rboImage);
|
|
||||||
egl.eglDestroyImageKHR(egl.display, fromTex.image);
|
|
||||||
|
|
||||||
restoreEGL();
|
restoreEGL();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CDRMRenderer::onBufferAttachmentDrop(CDRMRendererBufferAttachment* attachment) {
|
||||||
|
setEGL();
|
||||||
|
|
||||||
|
TRACE(backend->log(AQ_LOG_TRACE,
|
||||||
|
std::format("EGL (onBufferAttachmentDrop): dropping fbo {} rbo {} image 0x{:x}", attachment->fbo, attachment->rbo, (uintptr_t)attachment->eglImage)));
|
||||||
|
|
||||||
|
if (attachment->texid)
|
||||||
|
GLCALL(glDeleteTextures(1, &attachment->texid));
|
||||||
|
if (attachment->rbo)
|
||||||
|
GLCALL(glDeleteRenderbuffers(1, &attachment->rbo));
|
||||||
|
if (attachment->fbo)
|
||||||
|
GLCALL(glDeleteFramebuffers(1, &attachment->fbo));
|
||||||
|
if (attachment->eglImage)
|
||||||
|
egl.eglDestroyImageKHR(egl.display, attachment->eglImage);
|
||||||
|
|
||||||
|
restoreEGL();
|
||||||
|
}
|
||||||
|
|
||||||
|
CDRMRendererBufferAttachment::CDRMRendererBufferAttachment(Hyprutils::Memory::CWeakPointer<CDRMRenderer> renderer_, Hyprutils::Memory::CSharedPointer<IBuffer> buffer,
|
||||||
|
EGLImageKHR image, GLuint fbo_, GLuint rbo_, GLuint texid_) :
|
||||||
|
eglImage(image), fbo(fbo_), rbo(rbo_), renderer(renderer_), texid(texid_) {
|
||||||
|
bufferDestroy = buffer->events.destroy.registerListener([this](std::any d) { renderer->onBufferAttachmentDrop(this); });
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,24 @@
|
||||||
#include <gbm.h>
|
#include <gbm.h>
|
||||||
|
|
||||||
namespace Aquamarine {
|
namespace Aquamarine {
|
||||||
|
class CDRMRendererBufferAttachment : public IAttachment {
|
||||||
|
public:
|
||||||
|
CDRMRendererBufferAttachment(Hyprutils::Memory::CWeakPointer<CDRMRenderer> renderer_, Hyprutils::Memory::CSharedPointer<IBuffer> buffer, EGLImageKHR image, GLuint fbo_,
|
||||||
|
GLuint rbo_, GLuint texid_);
|
||||||
|
virtual ~CDRMRendererBufferAttachment() {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
virtual eAttachmentType type() {
|
||||||
|
return AQ_ATTACHMENT_DRM_RENDERER_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
EGLImageKHR eglImage = nullptr;
|
||||||
|
GLuint fbo = 0, rbo = 0, texid = 0;
|
||||||
|
Hyprutils::Signal::CHyprSignalListener bufferDestroy;
|
||||||
|
|
||||||
|
Hyprutils::Memory::CWeakPointer<CDRMRenderer> renderer;
|
||||||
|
};
|
||||||
|
|
||||||
class CDRMRenderer {
|
class CDRMRenderer {
|
||||||
public:
|
public:
|
||||||
static Hyprutils::Memory::CSharedPointer<CDRMRenderer> attempt(int drmfd, Hyprutils::Memory::CSharedPointer<CBackend> backend_);
|
static Hyprutils::Memory::CSharedPointer<CDRMRenderer> attempt(int drmfd, Hyprutils::Memory::CSharedPointer<CBackend> backend_);
|
||||||
|
@ -19,6 +37,8 @@ namespace Aquamarine {
|
||||||
void setEGL();
|
void setEGL();
|
||||||
void restoreEGL();
|
void restoreEGL();
|
||||||
|
|
||||||
|
void onBufferAttachmentDrop(CDRMRendererBufferAttachment* attachment);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
struct {
|
struct {
|
||||||
GLuint program = 0;
|
GLuint program = 0;
|
||||||
|
@ -55,6 +75,8 @@ namespace Aquamarine {
|
||||||
|
|
||||||
GLTex glTex(Hyprutils::Memory::CSharedPointer<IBuffer> buf);
|
GLTex glTex(Hyprutils::Memory::CSharedPointer<IBuffer> buf);
|
||||||
|
|
||||||
|
Hyprutils::Memory::CWeakPointer<CDRMRenderer> self;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CDRMRenderer() = default;
|
CDRMRenderer() = default;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue