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