File indexing completed on 2025-04-20 10:57:34
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2017 Martin Flöser <mgraesslin@kde.org> 0006 SPDX-FileCopyrightText: 2022 Xaver Hugl <xaver.hugl@gmail.com> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 #include "drm_gbm_surface.h" 0011 0012 #include <errno.h> 0013 #include <gbm.h> 0014 0015 #include "drm_backend.h" 0016 #include "drm_egl_backend.h" 0017 #include "drm_gpu.h" 0018 #include "drm_logging.h" 0019 #include "kwineglutils_p.h" 0020 #include "kwinglplatform.h" 0021 0022 namespace KWin 0023 { 0024 0025 GbmSurface::GbmSurface(EglGbmBackend *backend, const QSize &size, uint32_t format, const QVector<uint64_t> &modifiers, uint32_t flags, gbm_surface *surface, EGLSurface eglSurface) 0026 : m_surface(surface) 0027 , m_eglBackend(backend) 0028 , m_eglSurface(eglSurface) 0029 , m_size(size) 0030 , m_format(format) 0031 , m_modifiers(modifiers) 0032 , m_flags(flags) 0033 , m_fbo(std::make_unique<GLFramebuffer>(0, size)) 0034 { 0035 } 0036 0037 GbmSurface::~GbmSurface() 0038 { 0039 if (m_eglSurface != EGL_NO_SURFACE) { 0040 eglDestroySurface(m_eglBackend->eglDisplay(), m_eglSurface); 0041 } 0042 if (m_surface) { 0043 gbm_surface_destroy(m_surface); 0044 } 0045 } 0046 0047 bool GbmSurface::makeContextCurrent() const 0048 { 0049 if (eglMakeCurrent(m_eglBackend->eglDisplay(), m_eglSurface, m_eglSurface, m_eglBackend->context()) == EGL_FALSE) { 0050 qCCritical(KWIN_DRM) << "eglMakeCurrent failed:" << getEglErrorString(); 0051 return false; 0052 } 0053 if (!GLPlatform::instance()->isGLES()) { 0054 glDrawBuffer(GL_BACK); 0055 glReadBuffer(GL_BACK); 0056 } 0057 return true; 0058 } 0059 0060 std::shared_ptr<GbmBuffer> GbmSurface::swapBuffers(const QRegion &dirty) 0061 { 0062 auto error = eglSwapBuffers(m_eglBackend->eglDisplay(), m_eglSurface); 0063 if (error != EGL_TRUE) { 0064 qCCritical(KWIN_DRM) << "an error occurred while swapping buffers" << getEglErrorString(); 0065 return nullptr; 0066 } 0067 auto bo = gbm_surface_lock_front_buffer(m_surface); 0068 if (!bo) { 0069 return nullptr; 0070 } 0071 if (m_eglBackend->supportsBufferAge()) { 0072 eglQuerySurface(m_eglBackend->eglDisplay(), m_eglSurface, EGL_BUFFER_AGE_EXT, &m_bufferAge); 0073 m_damageJournal.add(dirty); 0074 } 0075 return std::make_shared<GbmBuffer>(m_eglBackend->gpu(), bo, shared_from_this()); 0076 } 0077 0078 void GbmSurface::releaseBuffer(GbmBuffer *buffer) 0079 { 0080 gbm_surface_release_buffer(m_surface, buffer->bo()); 0081 } 0082 0083 GLFramebuffer *GbmSurface::fbo() const 0084 { 0085 return m_fbo.get(); 0086 } 0087 0088 EGLSurface GbmSurface::eglSurface() const 0089 { 0090 return m_eglSurface; 0091 } 0092 0093 QSize GbmSurface::size() const 0094 { 0095 return m_size; 0096 } 0097 0098 uint32_t GbmSurface::format() const 0099 { 0100 return m_format; 0101 } 0102 0103 QVector<uint64_t> GbmSurface::modifiers() const 0104 { 0105 return m_modifiers; 0106 } 0107 0108 int GbmSurface::bufferAge() const 0109 { 0110 return m_bufferAge; 0111 } 0112 0113 QRegion GbmSurface::repaintRegion() const 0114 { 0115 if (m_eglBackend->supportsBufferAge()) { 0116 return m_damageJournal.accumulate(m_bufferAge, infiniteRegion()); 0117 } else { 0118 return infiniteRegion(); 0119 } 0120 } 0121 0122 uint32_t GbmSurface::flags() const 0123 { 0124 return m_flags; 0125 } 0126 0127 std::variant<std::shared_ptr<GbmSurface>, GbmSurface::Error> GbmSurface::createSurface(EglGbmBackend *backend, const QSize &size, uint32_t format, uint32_t flags, EGLConfig config) 0128 { 0129 gbm_surface *surface = gbm_surface_create(backend->gpu()->gbmDevice(), size.width(), size.height(), format, flags); 0130 if (!surface) { 0131 qCWarning(KWIN_DRM) << "Creating gbm surface failed!" << strerror(errno); 0132 return Error::Unknown; 0133 } 0134 EGLSurface eglSurface = eglCreatePlatformWindowSurfaceEXT(backend->eglDisplay(), config, surface, nullptr); 0135 if (eglSurface == EGL_NO_SURFACE) { 0136 qCCritical(KWIN_DRM) << "Creating EGL surface failed!" << getEglErrorString(); 0137 gbm_surface_destroy(surface); 0138 return Error::Unknown; 0139 } 0140 return std::make_shared<GbmSurface>(backend, size, format, QVector<uint64_t>{}, flags, surface, eglSurface); 0141 } 0142 0143 std::variant<std::shared_ptr<GbmSurface>, GbmSurface::Error> GbmSurface::createSurface(EglGbmBackend *backend, const QSize &size, uint32_t format, QVector<uint64_t> modifiers, EGLConfig config) 0144 { 0145 gbm_surface *surface = gbm_surface_create_with_modifiers(backend->gpu()->gbmDevice(), size.width(), size.height(), format, modifiers.data(), modifiers.size()); 0146 if (!surface) { 0147 if (errno == ENOSYS) { 0148 return Error::ModifiersUnsupported; 0149 } else { 0150 qCWarning(KWIN_DRM) << "Creating gbm surface failed!" << strerror(errno); 0151 return Error::Unknown; 0152 } 0153 } 0154 EGLSurface eglSurface = eglCreatePlatformWindowSurfaceEXT(backend->eglDisplay(), config, surface, nullptr); 0155 if (eglSurface == EGL_NO_SURFACE) { 0156 qCCritical(KWIN_DRM) << "Creating EGL surface failed!" << getEglErrorString(); 0157 gbm_surface_destroy(surface); 0158 return Error::Unknown; 0159 } 0160 return std::make_shared<GbmSurface>(backend, size, format, modifiers, 0, surface, eglSurface); 0161 } 0162 }