diff --git a/src/backends/drm/egl_gbm_layer_surface.cpp b/src/backends/drm/egl_gbm_layer_surface.cpp index de1ee0180b..d8b3210fcc 100644 --- a/src/backends/drm/egl_gbm_layer_surface.cpp +++ b/src/backends/drm/egl_gbm_layer_surface.cpp @@ -163,37 +163,35 @@ bool EglGbmLayerSurface::createGbmSurface(const QSize &size, uint32_t format, co { static bool modifiersEnvSet = false; static const bool modifiersEnv = qEnvironmentVariableIntValue("KWIN_DRM_USE_MODIFIERS", &modifiersEnvSet) != 0; - const bool allowModifiers = m_eglBackend->gpu()->addFB2ModifiersSupported() && m_gpu->addFB2ModifiersSupported() - && (!modifiersEnvSet || (modifiersEnvSet && modifiersEnv)) && !modifiers.isEmpty(); - - const auto config = m_eglBackend->config(format); - - std::shared_ptr gbmSurface; -#if HAVE_GBM_BO_GET_FD_FOR_PLANE - if (!allowModifiers) { -#else - // modifiers have to be disabled with multi-gpu if gbm_bo_get_fd_for_plane is not available - if (!allowModifiers || m_gpu != m_eglBackend->gpu()) { + bool allowModifiers = m_gpu->addFB2ModifiersSupported() && (!modifiersEnvSet || (modifiersEnvSet && modifiersEnv)) && !modifiers.isEmpty(); +#if !HAVE_GBM_BO_GET_FD_FOR_PLANE + allowModifiers &= m_gpu == m_eglBackend->gpu(); #endif - int gbmFlags = flags | GBM_BO_USE_RENDERING; - if (m_gpu == m_eglBackend->gpu()) { - gbmFlags |= GBM_BO_USE_SCANOUT; - } else { - gbmFlags |= GBM_BO_USE_LINEAR; - } - gbmSurface = std::make_shared(m_eglBackend->gpu(), size, format, gbmFlags, config); - } else { - gbmSurface = std::make_shared(m_eglBackend->gpu(), size, format, modifiers, config); - if (!gbmSurface->isValid()) { - // the egl / gbm implementation may reject the modifier list from another gpu - // as a fallback use linear, to at least make CPU copy more efficient - const QVector linear = {DRM_FORMAT_MOD_LINEAR}; - gbmSurface = std::make_shared(m_eglBackend->gpu(), size, format, linear, config); + const auto config = m_eglBackend->config(format); + if (!config) { + return false; + } + + if (allowModifiers) { + const auto ret = GbmSurface::createSurface(m_eglBackend, size, format, modifiers, config); + if (const auto surface = std::get_if>(&ret)) { + m_oldGbmSurface = m_gbmSurface; + m_gbmSurface = *surface; + return true; + } else if (std::get(ret) != GbmSurface::Error::ModifiersUnsupported) { + return false; } } - if (gbmSurface->isValid()) { + int gbmFlags = flags | GBM_BO_USE_RENDERING; + if (m_gpu == m_eglBackend->gpu()) { + gbmFlags |= GBM_BO_USE_SCANOUT; + } else { + gbmFlags |= GBM_BO_USE_LINEAR; + } + const auto ret = GbmSurface::createSurface(m_eglBackend, size, format, gbmFlags, config); + if (const auto surface = std::get_if>(&ret)) { m_oldGbmSurface = m_gbmSurface; - m_gbmSurface = gbmSurface; + m_gbmSurface = *surface; return true; } else { return false; diff --git a/src/backends/drm/gbm_surface.cpp b/src/backends/drm/gbm_surface.cpp index 309cfa9a8e..784f9ef028 100644 --- a/src/backends/drm/gbm_surface.cpp +++ b/src/backends/drm/gbm_surface.cpp @@ -3,6 +3,7 @@ This file is part of the KDE project. SPDX-FileCopyrightText: 2017 Martin Flöser + SPDX-FileCopyrightText: 2022 Xaver Hugl SPDX-License-Identifier: GPL-2.0-or-later */ @@ -22,41 +23,16 @@ namespace KWin { -GbmSurface::GbmSurface(DrmGpu *gpu, const QSize &size, uint32_t format, uint32_t flags, EGLConfig config) - : m_surface(gbm_surface_create(gpu->gbmDevice(), size.width(), size.height(), format, flags)) - , m_eglBackend(static_cast(gpu->platform()->renderBackend())) - , m_size(size) - , m_format(format) - , m_flags(flags) - , m_fbo(new GLFramebuffer(0, size)) -{ - if (!m_surface) { - qCCritical(KWIN_DRM) << "Could not create gbm surface!" << strerror(errno); - return; - } - m_eglSurface = eglCreatePlatformWindowSurfaceEXT(m_eglBackend->eglDisplay(), config, m_surface, nullptr); - if (m_eglSurface == EGL_NO_SURFACE) { - qCCritical(KWIN_DRM) << "Creating EGL surface failed!" << getEglErrorString(); - } -} - -GbmSurface::GbmSurface(DrmGpu *gpu, const QSize &size, uint32_t format, QVector modifiers, EGLConfig config) - : m_surface(gbm_surface_create_with_modifiers(gpu->gbmDevice(), size.width(), size.height(), format, modifiers.isEmpty() ? nullptr : modifiers.constData(), modifiers.count())) - , m_eglBackend(static_cast(gpu->platform()->renderBackend())) +GbmSurface::GbmSurface(EglGbmBackend *backend, const QSize &size, uint32_t format, const QVector &modifiers, uint32_t flags, gbm_surface *surface, EGLSurface eglSurface) + : m_surface(surface) + , m_eglBackend(backend) + , m_eglSurface(eglSurface) , m_size(size) , m_format(format) , m_modifiers(modifiers) - , m_flags(0) + , m_flags(flags) , m_fbo(new GLFramebuffer(0, size)) { - if (!m_surface) { - qCCritical(KWIN_DRM) << "Could not create gbm surface!" << strerror(errno); - return; - } - m_eglSurface = eglCreatePlatformWindowSurfaceEXT(m_eglBackend->eglDisplay(), config, m_surface, nullptr); - if (m_eglSurface == EGL_NO_SURFACE) { - qCCritical(KWIN_DRM) << "Creating EGL surface failed!" << getEglErrorString(); - } } GbmSurface::~GbmSurface() @@ -120,11 +96,6 @@ QSize GbmSurface::size() const return m_size; } -bool GbmSurface::isValid() const -{ - return m_surface != nullptr && m_eglSurface != EGL_NO_SURFACE; -} - uint32_t GbmSurface::format() const { return m_format; @@ -153,4 +124,38 @@ uint32_t GbmSurface::flags() const { return m_flags; } + +std::variant, GbmSurface::Error> GbmSurface::createSurface(EglGbmBackend *backend, const QSize &size, uint32_t format, uint32_t flags, EGLConfig config) +{ + gbm_surface *surface = gbm_surface_create(backend->gpu()->gbmDevice(), size.width(), size.height(), format, flags); + if (!surface) { + qCWarning(KWIN_DRM) << "Creating gbm surface failed!" << strerror(errno); + return Error::Unknown; + } + EGLSurface eglSurface = eglCreatePlatformWindowSurfaceEXT(backend->eglDisplay(), config, surface, nullptr); + if (eglSurface == EGL_NO_SURFACE) { + qCCritical(KWIN_DRM) << "Creating EGL surface failed!" << getEglErrorString(); + return Error::Unknown; + } + return std::make_shared(backend, size, format, QVector{}, flags, surface, eglSurface); +} + +std::variant, GbmSurface::Error> GbmSurface::createSurface(EglGbmBackend *backend, const QSize &size, uint32_t format, QVector modifiers, EGLConfig config) +{ + gbm_surface *surface = gbm_surface_create_with_modifiers(backend->gpu()->gbmDevice(), size.width(), size.height(), format, modifiers.data(), modifiers.size()); + if (!surface) { + if (errno == ENOSYS) { + return Error::ModifiersUnsupported; + } else { + qCWarning(KWIN_DRM) << "Creating gbm surface failed!" << strerror(errno); + return Error::Unknown; + } + } + EGLSurface eglSurface = eglCreatePlatformWindowSurfaceEXT(backend->eglDisplay(), config, surface, nullptr); + if (eglSurface == EGL_NO_SURFACE) { + qCCritical(KWIN_DRM) << "Creating EGL surface failed!" << getEglErrorString(); + return Error::Unknown; + } + return std::make_shared(backend, size, format, modifiers, 0, surface, eglSurface); +} } diff --git a/src/backends/drm/gbm_surface.h b/src/backends/drm/gbm_surface.h index 7b93315dfb..607b4d12c5 100644 --- a/src/backends/drm/gbm_surface.h +++ b/src/backends/drm/gbm_surface.h @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include "drm_buffer_gbm.h" #include "utils/damagejournal.h" @@ -29,8 +29,7 @@ class EglGbmBackend; class GbmSurface : public std::enable_shared_from_this { public: - explicit GbmSurface(DrmGpu *gpu, const QSize &size, uint32_t format, uint32_t flags, EGLConfig config); - explicit GbmSurface(DrmGpu *gpu, const QSize &size, uint32_t format, QVector modifiers, EGLConfig config); + explicit GbmSurface(EglGbmBackend *backend, const QSize &size, uint32_t format, const QVector &modifiers, uint32_t flags, gbm_surface *surface, EGLSurface eglSurface); ~GbmSurface(); bool makeContextCurrent() const; @@ -49,6 +48,14 @@ public: int bufferAge() const; QRegion repaintRegion() const; + enum class Error { + ModifiersUnsupported, + EglError, + Unknown + }; + static std::variant, Error> createSurface(EglGbmBackend *backend, const QSize &size, uint32_t format, uint32_t flags, EGLConfig config); + static std::variant, Error> createSurface(EglGbmBackend *backend, const QSize &size, uint32_t format, QVector modifiers, EGLConfig config); + private: gbm_surface *m_surface; EglGbmBackend *const m_eglBackend; diff --git a/src/backends/drm/virtual_egl_gbm_layer.cpp b/src/backends/drm/virtual_egl_gbm_layer.cpp index 5f430c2e44..dfcdd02b40 100644 --- a/src/backends/drm/virtual_egl_gbm_layer.cpp +++ b/src/backends/drm/virtual_egl_gbm_layer.cpp @@ -97,27 +97,32 @@ bool VirtualEglGbmLayer::createGbmSurface() { static bool modifiersEnvSet = false; static const bool modifiersEnv = qEnvironmentVariableIntValue("KWIN_DRM_USE_MODIFIERS", &modifiersEnvSet) != 0; + const bool allowModifiers = ((m_eglBackend->gpu()->isNVidia() && !modifiersEnvSet) || (modifiersEnvSet && modifiersEnv)); const auto tranches = m_eglBackend->dmabuf()->tranches(); for (const auto &tranche : tranches) { for (auto it = tranche.formatTable.constBegin(); it != tranche.formatTable.constEnd(); it++) { const auto size = m_output->pixelSize(); const auto config = m_eglBackend->config(it.key()); + const auto format = it.key(); const auto modifiers = it.value(); - const bool allowModifiers = m_eglBackend->gpu()->addFB2ModifiersSupported() && ((m_eglBackend->gpu()->isNVidia() && !modifiersEnvSet) || (modifiersEnvSet && modifiersEnv)); - std::shared_ptr gbmSurface; - if (!allowModifiers) { - gbmSurface = std::make_shared(m_eglBackend->gpu(), size, it.key(), GBM_BO_USE_RENDERING, config); - } else { - gbmSurface = std::make_shared(m_eglBackend->gpu(), size, it.key(), it.value(), config); + if (allowModifiers && !modifiers.isEmpty()) { + const auto ret = GbmSurface::createSurface(m_eglBackend, size, format, modifiers, config); + if (const auto surface = std::get_if>(&ret)) { + m_oldGbmSurface = m_gbmSurface; + m_gbmSurface = *surface; + return true; + } else if (std::get(ret) != GbmSurface::Error::ModifiersUnsupported) { + continue; + } } - if (!gbmSurface->isValid()) { - continue; + const auto ret = GbmSurface::createSurface(m_eglBackend, size, format, GBM_BO_USE_RENDERING, config); + if (const auto surface = std::get_if>(&ret)) { + m_oldGbmSurface = m_gbmSurface; + m_gbmSurface = *surface; + return true; } - m_oldGbmSurface = m_gbmSurface; - m_gbmSurface = gbmSurface; - return true; } } return false;