4#include "dmabufhandler.h"
6#include <QGuiApplication>
9#include <logging_dmabuf.h>
10#include <qpa/qplatformnativeinterface.h>
16 int max_devices = drmGetDevices2(0,
nullptr, 0);
17 if (max_devices <= 0) {
18 qCWarning(PIPEWIREDMABUF_LOGGING) <<
"drmGetDevices2() has not found any devices (errno=" << -max_devices <<
")";
19 return "/dev/dri/renderD128";
22 std::vector<drmDevicePtr> devices(max_devices);
23 int ret = drmGetDevices2(0, devices.data(), max_devices);
25 qCWarning(PIPEWIREDMABUF_LOGGING) <<
"drmGetDevices2() returned an error " << ret;
26 return "/dev/dri/renderD128";
31 for (
const drmDevicePtr &device : devices) {
32 if (device->available_nodes & (1 << DRM_NODE_RENDER)) {
33 render_node = device->nodes[DRM_NODE_RENDER];
38 drmFreeDevices(devices.data(), ret);
42DmaBufHandler::DmaBufHandler()
46DmaBufHandler::~DmaBufHandler()
53void DmaBufHandler::setupEgl()
55 if (m_eglInitialized) {
59 m_egl.display =
static_cast<EGLDisplay
>(QGuiApplication::platformNativeInterface()->nativeResourceForIntegration(
"egldisplay"));
63 if (!epoxy_has_egl_extension(m_egl.display,
"EGL_EXT_platform_base") || !epoxy_has_egl_extension(m_egl.display,
"EGL_MESA_platform_gbm")) {
64 qCWarning(PIPEWIREDMABUF_LOGGING) <<
"One of required EGL extensions is missing";
68 if (m_egl.display == EGL_NO_DISPLAY) {
69 m_egl.display = eglGetPlatformDisplay(EGL_PLATFORM_WAYLAND_KHR, (
void *)EGL_DEFAULT_DISPLAY,
nullptr);
71 if (m_egl.display == EGL_NO_DISPLAY) {
72 const QByteArray renderNode = fetchRenderNode();
76 qCWarning(PIPEWIREDMABUF_LOGGING) <<
"Failed to open drm render node" << renderNode <<
"with error: " << strerror(errno);
80 m_gbmDevice = gbm_create_device(m_drmFd);
83 qCWarning(PIPEWIREDMABUF_LOGGING) <<
"Cannot create GBM device: " << strerror(errno);
86 m_egl.display = eglGetPlatformDisplayEXT(EGL_PLATFORM_GBM_MESA, m_gbmDevice,
nullptr);
89 if (m_egl.display == EGL_NO_DISPLAY) {
90 qCWarning(PIPEWIREDMABUF_LOGGING) <<
"Error during obtaining EGL display: " << GLHelpers::formatGLError(eglGetError());
95 if (eglInitialize(m_egl.display, &major, &minor) == EGL_FALSE) {
96 qCWarning(PIPEWIREDMABUF_LOGGING) <<
"Error during eglInitialize: " << GLHelpers::formatGLError(eglGetError());
100 if (eglBindAPI(EGL_OPENGL_API) == EGL_FALSE) {
101 qCWarning(PIPEWIREDMABUF_LOGGING) <<
"bind OpenGL API failed";
106 auto createConfig = [&] {
107 static const EGLint configAttribs[] = {
124 if (eglChooseConfig(m_egl.display, configAttribs, &configs, 1, &count) == EGL_FALSE) {
125 qCWarning(PIPEWIREDMABUF_LOGGING) <<
"choose config failed";
129 qCWarning(PIPEWIREDMABUF_LOGGING) <<
"eglChooseConfig returned this many configs:" << count;
135 bool b = createConfig();
136 static const EGLint configAttribs[] = {EGL_CONTEXT_OPENGL_DEBUG, EGL_TRUE, EGL_NONE};
138 m_egl.context = eglCreateContext(m_egl.display, b ? configs : EGL_NO_CONFIG_KHR, EGL_NO_CONTEXT, configAttribs);
141 Q_ASSERT(m_egl.context);
142 if (m_egl.context == EGL_NO_CONTEXT) {
143 qCWarning(PIPEWIREDMABUF_LOGGING) <<
"Couldn't create EGL context: " << GLHelpers::formatEGLError(eglGetError());
147 qCDebug(PIPEWIREDMABUF_LOGGING) <<
"Egl initialization succeeded";
148 qCDebug(PIPEWIREDMABUF_LOGGING) << QStringLiteral(
"EGL version: %1.%2").arg(major).arg(minor);
150 m_eglInitialized =
true;
153GLenum closestGLType(
const QImage &image)
166 qDebug() <<
"cannot convert QImage format to GLType" << image.
format();
171bool DmaBufHandler::downloadFrame(
QImage &qimage,
const PipeWireFrame &frame)
173 Q_ASSERT(frame.dmabuf);
174 const QSize streamSize = {frame.dmabuf->width, frame.dmabuf->height};
175 Q_ASSERT(qimage.
size() == streamSize);
177 if (!m_eglInitialized) {
181 if (!eglMakeCurrent(m_egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, m_egl.context)) {
182 qCWarning(PIPEWIREDMABUF_LOGGING) <<
"Failed to make context current" << GLHelpers::formatEGLError(eglGetError());
186 GLHelpers::createImage(m_egl.display, *frame.dmabuf, PipeWireSourceStream::spaVideoFormatToDrmFormat(frame.format), qimage.
size(), m_gbmDevice);
188 if (image == EGL_NO_IMAGE_KHR) {
189 qCWarning(PIPEWIREDMABUF_LOGGING) <<
"Failed to record frame: Error creating EGLImageKHR - " << GLHelpers::formatEGLError(eglGetError());
193 GLHelpers::initDebugOutput();
197 glGenTextures(1, &texture);
198 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
199 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
200 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
201 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
202 glBindTexture(GL_TEXTURE_2D, texture);
204 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
205 glGenFramebuffers(1, &fbo);
206 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
207 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
209 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
210 glDeleteFramebuffers(1, &fbo);
211 glDeleteTextures(1, &texture);
212 eglDestroyImageKHR(m_egl.display, image);
216 glReadPixels(0, 0, frame.dmabuf->width, frame.dmabuf->height, closestGLType(qimage), GL_UNSIGNED_BYTE, qimage.
bits());
218 glDeleteFramebuffers(1, &fbo);
219 glDeleteTextures(1, &texture);
220 eglDestroyImageKHR(m_egl.display, image);
const QList< QKeySequence > & close()
const QList< QKeySequence > & open()
const char * constData() const const