File indexing completed on 2024-04-14 15:33:28
0001 /* 0002 SPDX-FileCopyrightText: 2022 Aleix Pol Gonzalez <aleixpol@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 0007 #include "glhelpers.h" 0008 #include <QList> 0009 #include <QVersionNumber> 0010 #include <epoxy/gl.h> 0011 #include <libdrm/drm_fourcc.h> 0012 #include <logging.h> 0013 #include <mutex> 0014 0015 #include <gbm.h> 0016 0017 namespace GLHelpers 0018 { 0019 0020 void initDebugOutputOnce() 0021 { 0022 auto callback = [](GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const GLvoid *userParam) { 0023 Q_UNUSED(source) 0024 Q_UNUSED(severity) 0025 Q_UNUSED(userParam) 0026 while (length && std::isspace(message[length - 1])) { 0027 --length; 0028 } 0029 0030 switch (type) { 0031 case GL_DEBUG_TYPE_ERROR: 0032 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: 0033 qCWarning(PIPEWIRE_LOGGING, "%#x: %.*s", id, length, message); 0034 break; 0035 0036 case GL_DEBUG_TYPE_OTHER: 0037 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: 0038 case GL_DEBUG_TYPE_PORTABILITY: 0039 case GL_DEBUG_TYPE_PERFORMANCE: 0040 default: 0041 qCDebug(PIPEWIRE_LOGGING, "%#x: %.*s", id, length, message); 0042 break; 0043 } 0044 }; 0045 glDebugMessageCallback(callback, nullptr); 0046 glEnable(GL_DEBUG_OUTPUT); 0047 } 0048 0049 static std::once_flag initDebugOnce; 0050 void initDebugOutput() 0051 { 0052 if (!PIPEWIRE_LOGGING().isDebugEnabled()) { 0053 return; 0054 } 0055 0056 if (!eglGetCurrentDisplay()) { 0057 // Epoxy gets very confused and it will crash 0058 return; 0059 } 0060 0061 std::call_once(initDebugOnce, initDebugOutputOnce); 0062 } 0063 0064 #define ENUM_STRING(x) case x: return #x; 0065 0066 QByteArray formatGLError(GLenum err) 0067 { 0068 switch (err) { 0069 ENUM_STRING(GL_NO_ERROR) 0070 ENUM_STRING(GL_INVALID_ENUM) 0071 ENUM_STRING(GL_INVALID_VALUE) 0072 ENUM_STRING(GL_INVALID_OPERATION) 0073 ENUM_STRING(GL_STACK_OVERFLOW) 0074 ENUM_STRING(GL_STACK_UNDERFLOW) 0075 ENUM_STRING(GL_OUT_OF_MEMORY) 0076 default: 0077 return QByteArray("0x") + QByteArray::number(err, 16); 0078 } 0079 } 0080 0081 QByteArray formatEGLError(GLenum err) 0082 { 0083 switch (err) { 0084 ENUM_STRING(EGL_SUCCESS) 0085 ENUM_STRING(EGL_BAD_DISPLAY) 0086 ENUM_STRING(EGL_BAD_CONTEXT) 0087 ENUM_STRING(EGL_BAD_PARAMETER) 0088 ENUM_STRING(EGL_BAD_MATCH) 0089 ENUM_STRING(EGL_BAD_ACCESS) 0090 ENUM_STRING(EGL_BAD_ALLOC) 0091 ENUM_STRING(EGL_BAD_CONFIG) 0092 default: 0093 return QByteArray("0x") + QByteArray::number(err, 16); 0094 } 0095 } 0096 0097 EGLImage createImage(EGLDisplay display, const DmaBufAttributes &dmabufAttribs, uint32_t format, const QSize &size, gbm_device *gbmDevice) 0098 { 0099 Q_ASSERT(!size.isEmpty()); 0100 gbm_bo *imported = nullptr; 0101 if (gbmDevice) { 0102 gbm_import_fd_data importInfo = {static_cast<int>(dmabufAttribs.planes[0].fd), 0103 static_cast<uint32_t>(size.width()), 0104 static_cast<uint32_t>(size.height()), 0105 static_cast<uint32_t>(dmabufAttribs.planes[0].stride), 0106 GBM_BO_FORMAT_ARGB8888}; 0107 imported = gbm_bo_import(gbmDevice, GBM_BO_IMPORT_FD, &importInfo, GBM_BO_USE_SCANOUT); 0108 if (!imported) { 0109 qCWarning(PIPEWIRE_LOGGING) << "Failed to process buffer: Cannot import passed GBM fd - " << strerror(errno); 0110 return EGL_NO_IMAGE_KHR; 0111 } 0112 } 0113 0114 const bool hasModifiers = dmabufAttribs.modifier != DRM_FORMAT_MOD_INVALID; 0115 0116 QVector<EGLint> attribs; 0117 attribs << EGL_WIDTH << size.width() << EGL_HEIGHT << size.height() << EGL_LINUX_DRM_FOURCC_EXT << EGLint(format) 0118 0119 << EGL_DMA_BUF_PLANE0_FD_EXT << dmabufAttribs.planes[0].fd << EGL_DMA_BUF_PLANE0_OFFSET_EXT << EGLint(dmabufAttribs.planes[0].offset) 0120 << EGL_DMA_BUF_PLANE0_PITCH_EXT << EGLint(dmabufAttribs.planes[0].stride); 0121 0122 if (hasModifiers) { 0123 attribs << EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT << EGLint(dmabufAttribs.modifier & 0xffffffff) << EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT 0124 << EGLint(dmabufAttribs.modifier >> 32); 0125 } 0126 0127 if (dmabufAttribs.planes.count() > 1) { 0128 attribs << EGL_DMA_BUF_PLANE1_FD_EXT << dmabufAttribs.planes[1].fd << EGL_DMA_BUF_PLANE1_OFFSET_EXT << EGLint(dmabufAttribs.planes[1].offset) 0129 << EGL_DMA_BUF_PLANE1_PITCH_EXT << EGLint(dmabufAttribs.planes[1].stride); 0130 0131 if (hasModifiers) { 0132 attribs << EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT << EGLint(dmabufAttribs.modifier & 0xffffffff) << EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT 0133 << EGLint(dmabufAttribs.modifier >> 32); 0134 } 0135 } 0136 0137 if (dmabufAttribs.planes.count() > 2) { 0138 attribs << EGL_DMA_BUF_PLANE2_FD_EXT << dmabufAttribs.planes[2].fd << EGL_DMA_BUF_PLANE2_OFFSET_EXT << EGLint(dmabufAttribs.planes[2].offset) 0139 << EGL_DMA_BUF_PLANE2_PITCH_EXT << EGLint(dmabufAttribs.planes[2].stride); 0140 0141 if (hasModifiers) { 0142 attribs << EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT << EGLint(dmabufAttribs.modifier & 0xffffffff) << EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT 0143 << EGLint(dmabufAttribs.modifier >> 32); 0144 } 0145 } 0146 0147 if (dmabufAttribs.planes.count() > 3) { 0148 attribs << EGL_DMA_BUF_PLANE3_FD_EXT << dmabufAttribs.planes[3].fd << EGL_DMA_BUF_PLANE3_OFFSET_EXT << EGLint(dmabufAttribs.planes[3].offset) 0149 << EGL_DMA_BUF_PLANE3_PITCH_EXT << EGLint(dmabufAttribs.planes[3].stride); 0150 0151 if (hasModifiers) { 0152 attribs << EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT << EGLint(dmabufAttribs.modifier & 0xffffffff) << EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT 0153 << EGLint(dmabufAttribs.modifier >> 32); 0154 } 0155 } 0156 0157 attribs << EGL_NONE; 0158 0159 static auto eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC)eglGetProcAddress("eglCreateImageKHR"); 0160 0161 /* MESA says: 0162 * "If <target> is EGL_LINUX_DMA_BUF_EXT, <dpy> must be a valid display, 0163 * <ctx> must be EGL_NO_CONTEXT..." 0164 */ 0165 EGLImage ret = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, imported, attribs.data()); 0166 if (ret == EGL_NO_IMAGE_KHR) { 0167 qCWarning(PIPEWIRE_LOGGING) << "invalid image" << GLHelpers::formatEGLError(eglGetError()); 0168 } 0169 if (imported) { 0170 gbm_bo_destroy(imported); 0171 } 0172 return ret; 0173 } 0174 }