diff --git a/src/backends/drm/drm_egl_backend.cpp b/src/backends/drm/drm_egl_backend.cpp index 3f75765711..041a13a857 100644 --- a/src/backends/drm/drm_egl_backend.cpp +++ b/src/backends/drm/drm_egl_backend.cpp @@ -33,7 +33,6 @@ EglGbmBackend::EglGbmBackend(DrmBackend *drmBackend) , m_backend(drmBackend) { drmBackend->setRenderBackend(this); - setIsDirectRendering(true); connect(m_backend, &DrmBackend::gpuRemoved, this, [this](DrmGpu *gpu) { m_contexts.erase(gpu->eglDisplay()); }); diff --git a/src/backends/virtual/virtual_egl_backend.cpp b/src/backends/virtual/virtual_egl_backend.cpp index 88ce395cf2..4d03f6b5af 100644 --- a/src/backends/virtual/virtual_egl_backend.cpp +++ b/src/backends/virtual/virtual_egl_backend.cpp @@ -89,8 +89,6 @@ VirtualEglBackend::VirtualEglBackend(VirtualBackend *b) , m_backend(b) , m_allocator(std::make_unique(b->gbmDevice())) { - // Egl is always direct rendering - setIsDirectRendering(true); } VirtualEglBackend::~VirtualEglBackend() diff --git a/src/backends/wayland/wayland_egl_backend.cpp b/src/backends/wayland/wayland_egl_backend.cpp index c6d0db3897..ab2c5eaf48 100644 --- a/src/backends/wayland/wayland_egl_backend.cpp +++ b/src/backends/wayland/wayland_egl_backend.cpp @@ -216,9 +216,6 @@ WaylandEglBackend::WaylandEglBackend(WaylandBackend *b) , m_backend(b) , m_allocator(std::make_unique(b->gbmDevice())) { - // Egl is always direct rendering - setIsDirectRendering(true); - connect(m_backend, &WaylandBackend::outputAdded, this, &WaylandEglBackend::createEglWaylandOutput); connect(m_backend, &WaylandBackend::outputRemoved, this, [this](Output *output) { m_outputs.erase(output); diff --git a/src/backends/x11/standalone/CMakeLists.txt b/src/backends/x11/standalone/CMakeLists.txt index 65b0b8bc96..97fa5e44bc 100644 --- a/src/backends/x11/standalone/CMakeLists.txt +++ b/src/backends/x11/standalone/CMakeLists.txt @@ -27,6 +27,7 @@ endif() if (HAVE_GLX) target_sources(KWinX11Platform PRIVATE + glxcontext.cpp x11_standalone_glx_backend.cpp x11_standalone_glx_context_attribute_builder.cpp x11_standalone_glxconvenience.cpp diff --git a/src/backends/x11/standalone/glxcontext.cpp b/src/backends/x11/standalone/glxcontext.cpp new file mode 100644 index 0000000000..c3cce456c8 --- /dev/null +++ b/src/backends/x11/standalone/glxcontext.cpp @@ -0,0 +1,131 @@ +/* + KWin - the KDE window manager + This file is part of the KDE project. + + SPDX-FileCopyrightText: 2023 Xaver Hugl + + SPDX-License-Identifier: GPL-2.0-or-later +*/ +#include "glxcontext.h" +#include "x11_standalone_glx_context_attribute_builder.h" +#include "x11_standalone_logging.h" + +#include +#include + +namespace KWin +{ + +GlxContext::GlxContext(Display *display, GLXWindow window, GLXContext handle) + : m_display(display) + , m_window(window) + , m_handle(handle) +{ +} + +GlxContext::~GlxContext() +{ + glXDestroyContext(m_display, m_handle); +} + +bool GlxContext::makeCurrent() const +{ + if (QOpenGLContext *context = QOpenGLContext::currentContext()) { + // Workaround to tell Qt that no QOpenGLContext is current + context->doneCurrent(); + } + return glXMakeCurrent(m_display, m_window, m_handle); +} + +bool GlxContext::doneCurrent() const +{ + return glXMakeCurrent(m_display, None, nullptr); +} + +std::unique_ptr GlxContext::create(GlxBackend *backend, GLXFBConfig fbconfig, GLXWindow glxWindow) +{ + QOpenGLContext *qtGlobalShareContext = QOpenGLContext::globalShareContext(); + GLXContext globalShareContext = nullptr; + if (qtGlobalShareContext) { + qDebug(KWIN_X11STANDALONE) << "Global share context format:" << qtGlobalShareContext->format(); + const auto nativeHandle = qtGlobalShareContext->nativeInterface(); + if (nativeHandle) { + globalShareContext = nativeHandle->nativeContext(); + } else { + qCDebug(KWIN_X11STANDALONE) << "Invalid QOpenGLContext::globalShareContext()"; + return nullptr; + } + } + if (!globalShareContext) { + qCWarning(KWIN_X11STANDALONE) << "QOpenGLContext::globalShareContext() is required"; + return nullptr; + } + + GLXContext handle = nullptr; + + // Use glXCreateContextAttribsARB() when it's available + if (backend->hasExtension(QByteArrayLiteral("GLX_ARB_create_context"))) { + const bool have_robustness = backend->hasExtension(QByteArrayLiteral("GLX_ARB_create_context_robustness")); + const bool haveVideoMemoryPurge = backend->hasExtension(QByteArrayLiteral("GLX_NV_robustness_video_memory_purge")); + + std::vector candidates; + // core + if (have_robustness) { + if (haveVideoMemoryPurge) { + GlxContextAttributeBuilder purgeMemoryCore; + purgeMemoryCore.setVersion(3, 1); + purgeMemoryCore.setRobust(true); + purgeMemoryCore.setResetOnVideoMemoryPurge(true); + candidates.emplace_back(std::move(purgeMemoryCore)); + } + GlxContextAttributeBuilder robustCore; + robustCore.setVersion(3, 1); + robustCore.setRobust(true); + candidates.emplace_back(std::move(robustCore)); + } + GlxContextAttributeBuilder core; + core.setVersion(3, 1); + candidates.emplace_back(std::move(core)); + // legacy + if (have_robustness) { + if (haveVideoMemoryPurge) { + GlxContextAttributeBuilder purgeMemoryLegacy; + purgeMemoryLegacy.setRobust(true); + purgeMemoryLegacy.setResetOnVideoMemoryPurge(true); + candidates.emplace_back(std::move(purgeMemoryLegacy)); + } + GlxContextAttributeBuilder robustLegacy; + robustLegacy.setRobust(true); + candidates.emplace_back(std::move(robustLegacy)); + } + GlxContextAttributeBuilder legacy; + legacy.setVersion(2, 1); + candidates.emplace_back(std::move(legacy)); + for (auto it = candidates.begin(); it != candidates.end(); it++) { + const auto attribs = it->build(); + handle = glXCreateContextAttribsARB(backend->display(), fbconfig, globalShareContext, true, attribs.data()); + if (handle) { + qCDebug(KWIN_X11STANDALONE) << "Created GLX context with attributes:" << &(*it); + break; + } + } + } + if (!handle) { + handle = glXCreateNewContext(backend->display(), fbconfig, GLX_RGBA_TYPE, globalShareContext, true); + } + if (!handle) { + qCDebug(KWIN_X11STANDALONE) << "Failed to create an OpenGL context."; + return nullptr; + } + // KWin doesn't support indirect rendering + if (!glXIsDirect(backend->display(), handle)) { + return nullptr; + } + if (!glXMakeCurrent(backend->display(), glxWindow, handle)) { + glXDestroyContext(backend->display(), handle); + return nullptr; + } + return std::make_unique(backend->display(), glxWindow, handle); +} + +} diff --git a/src/backends/x11/standalone/glxcontext.h b/src/backends/x11/standalone/glxcontext.h new file mode 100644 index 0000000000..d1b4da31cd --- /dev/null +++ b/src/backends/x11/standalone/glxcontext.h @@ -0,0 +1,35 @@ +/* + KWin - the KDE window manager + This file is part of the KDE project. + + SPDX-FileCopyrightText: 2023 Xaver Hugl + + SPDX-License-Identifier: GPL-2.0-or-later +*/ +#pragma once +#include "libkwineffects/openglcontext.h" +#include "x11_standalone_glx_backend.h" + +#include + +namespace KWin +{ + +class GlxContext : public OpenGlContext +{ +public: + GlxContext(Display *display, GLXWindow window, GLXContext handle); + ~GlxContext() override; + + bool makeCurrent() const; + bool doneCurrent() const; + + static std::unique_ptr create(GlxBackend *backend, GLXFBConfig fbconfig, GLXWindow glxWindow); + +private: + Display *const m_display; + const GLXWindow m_window; + const GLXContext m_handle; +}; + +} diff --git a/src/backends/x11/standalone/x11_standalone_egl_backend.cpp b/src/backends/x11/standalone/x11_standalone_egl_backend.cpp index 1c33cce931..22d32e01d5 100644 --- a/src/backends/x11/standalone/x11_standalone_egl_backend.cpp +++ b/src/backends/x11/standalone/x11_standalone_egl_backend.cpp @@ -59,8 +59,6 @@ EglBackend::EglBackend(Display *display, X11StandaloneBackend *backend) , m_overlayWindow(std::make_unique(backend)) , m_layer(std::make_unique(this)) { - setIsDirectRendering(true); - // There is no any way to determine when a buffer swap completes with EGL. Fallback // to software vblank events. Could we use the Present extension to get notified when // the overlay window is actually presented on the screen? diff --git a/src/backends/x11/standalone/x11_standalone_glx_backend.cpp b/src/backends/x11/standalone/x11_standalone_glx_backend.cpp index dbc778aeec..36609d6ad9 100644 --- a/src/backends/x11/standalone/x11_standalone_glx_backend.cpp +++ b/src/backends/x11/standalone/x11_standalone_glx_backend.cpp @@ -14,6 +14,7 @@ // own #include "x11_standalone_glx_backend.h" #include "../common/kwinxrenderutils.h" +#include "glxcontext.h" #include "utils/softwarevsyncmonitor.h" #include "x11_standalone_backend.h" #include "x11_standalone_glx_context_attribute_builder.h" @@ -130,7 +131,6 @@ GlxBackend::GlxBackend(Display *display, X11StandaloneBackend *backend) , window(None) , fbconfig(nullptr) , glxWindow(None) - , ctx(nullptr) , m_bufferAge(0) , m_x11Display(display) , m_backend(backend) @@ -162,9 +162,7 @@ GlxBackend::~GlxBackend() cleanupGL(); doneCurrent(); - if (ctx) { - glXDestroyContext(display(), ctx); - } + m_context.reset(); if (glxWindow) { glXDestroyWindow(display(), glxWindow); @@ -218,7 +216,8 @@ void GlxBackend::init() return; } - if (!initRenderingContext()) { + m_context = GlxContext::create(this, fbconfig, glxWindow); + if (!m_context) { setFailed(QStringLiteral("Could not initialize rendering context")); return; } @@ -323,10 +322,6 @@ void GlxBackend::init() connect(m_vsyncMonitor.get(), &VsyncMonitor::vblankOccurred, this, &GlxBackend::vblank); } - - setIsDirectRendering(bool(glXIsDirect(display(), ctx))); - - qCDebug(KWIN_X11STANDALONE) << "Direct rendering:" << isDirectRendering(); } bool GlxBackend::checkVersion() @@ -342,94 +337,6 @@ void GlxBackend::initExtensions() setExtensions(string.split(' ')); } -bool GlxBackend::initRenderingContext() -{ - const bool direct = true; - - QOpenGLContext *qtGlobalShareContext = QOpenGLContext::globalShareContext(); - GLXContext globalShareContext = nullptr; - if (qtGlobalShareContext) { - qDebug(KWIN_X11STANDALONE) << "Global share context format:" << qtGlobalShareContext->format(); - const auto nativeHandle = qtGlobalShareContext->nativeInterface(); - if (nativeHandle) { - globalShareContext = nativeHandle->nativeContext(); - } else { - qCDebug(KWIN_X11STANDALONE) << "Invalid QOpenGLContext::globalShareContext()"; - return false; - } - } - if (!globalShareContext) { - qCWarning(KWIN_X11STANDALONE) << "QOpenGLContext::globalShareContext() is required"; - return false; - } - - // Use glXCreateContextAttribsARB() when it's available - if (hasExtension(QByteArrayLiteral("GLX_ARB_create_context"))) { - const bool have_robustness = hasExtension(QByteArrayLiteral("GLX_ARB_create_context_robustness")); - const bool haveVideoMemoryPurge = hasExtension(QByteArrayLiteral("GLX_NV_robustness_video_memory_purge")); - - std::vector candidates; - // core - if (have_robustness) { - if (haveVideoMemoryPurge) { - GlxContextAttributeBuilder purgeMemoryCore; - purgeMemoryCore.setVersion(3, 1); - purgeMemoryCore.setRobust(true); - purgeMemoryCore.setResetOnVideoMemoryPurge(true); - candidates.emplace_back(std::move(purgeMemoryCore)); - } - GlxContextAttributeBuilder robustCore; - robustCore.setVersion(3, 1); - robustCore.setRobust(true); - candidates.emplace_back(std::move(robustCore)); - } - GlxContextAttributeBuilder core; - core.setVersion(3, 1); - candidates.emplace_back(std::move(core)); - // legacy - if (have_robustness) { - if (haveVideoMemoryPurge) { - GlxContextAttributeBuilder purgeMemoryLegacy; - purgeMemoryLegacy.setRobust(true); - purgeMemoryLegacy.setResetOnVideoMemoryPurge(true); - candidates.emplace_back(std::move(purgeMemoryLegacy)); - } - GlxContextAttributeBuilder robustLegacy; - robustLegacy.setRobust(true); - candidates.emplace_back(std::move(robustLegacy)); - } - GlxContextAttributeBuilder legacy; - legacy.setVersion(2, 1); - candidates.emplace_back(std::move(legacy)); - for (auto it = candidates.begin(); it != candidates.end(); it++) { - const auto attribs = it->build(); - ctx = glXCreateContextAttribsARB(display(), fbconfig, globalShareContext, true, attribs.data()); - if (ctx) { - qCDebug(KWIN_X11STANDALONE) << "Created GLX context with attributes:" << &(*it); - break; - } - } - } - - if (!ctx) { - ctx = glXCreateNewContext(display(), fbconfig, GLX_RGBA_TYPE, globalShareContext, direct); - } - - if (!ctx) { - qCDebug(KWIN_X11STANDALONE) << "Failed to create an OpenGL context."; - return false; - } - - if (!glXMakeCurrent(display(), glxWindow, ctx)) { - qCDebug(KWIN_X11STANDALONE) << "Failed to make the OpenGL context current."; - glXDestroyContext(display(), ctx); - ctx = nullptr; - return false; - } - - return true; -} - bool GlxBackend::initBuffer() { if (!initFbConfig()) { @@ -846,17 +753,12 @@ void GlxBackend::vblank(std::chrono::nanoseconds timestamp) bool GlxBackend::makeCurrent() { - if (QOpenGLContext *context = QOpenGLContext::currentContext()) { - // Workaround to tell Qt that no QOpenGLContext is current - context->doneCurrent(); - } - const bool current = glXMakeCurrent(display(), glxWindow, ctx); - return current; + return m_context->makeCurrent(); } void GlxBackend::doneCurrent() { - glXMakeCurrent(display(), None, nullptr); + m_context->doneCurrent(); } OverlayWindow *GlxBackend::overlayWindow() const diff --git a/src/backends/x11/standalone/x11_standalone_glx_backend.h b/src/backends/x11/standalone/x11_standalone_glx_backend.h index b8a58e7c77..6283e261f4 100644 --- a/src/backends/x11/standalone/x11_standalone_glx_backend.h +++ b/src/backends/x11/standalone/x11_standalone_glx_backend.h @@ -31,6 +31,7 @@ class VsyncMonitor; class X11StandaloneBackend; class GlxBackend; class GLRenderTimeQuery; +class GlxContext; // GLX_MESA_swap_interval using glXSwapIntervalMESA_func = int (*)(unsigned int interval); @@ -105,7 +106,6 @@ private: bool initBuffer(); bool checkVersion(); void initExtensions(); - bool initRenderingContext(); bool initFbConfig(); void initVisualDepthHashTable(); void setSwapInterval(int interval); @@ -121,7 +121,7 @@ private: ::Window window; GLXFBConfig fbconfig; GLXWindow glxWindow; - GLXContext ctx; + std::unique_ptr m_context; QHash m_fbconfigHash; QHash m_visualDepthHash; std::unique_ptr m_swapEventFilter; diff --git a/src/backends/x11/windowed/x11_windowed_egl_backend.cpp b/src/backends/x11/windowed/x11_windowed_egl_backend.cpp index 04a2b5c40b..0d1b16dde3 100644 --- a/src/backends/x11/windowed/x11_windowed_egl_backend.cpp +++ b/src/backends/x11/windowed/x11_windowed_egl_backend.cpp @@ -190,7 +190,6 @@ X11WindowedEglBackend::X11WindowedEglBackend(X11WindowedBackend *backend) : m_allocator(std::make_unique(backend->gbmDevice())) , m_backend(backend) { - setIsDirectRendering(true); } X11WindowedEglBackend::~X11WindowedEglBackend() diff --git a/src/composite.cpp b/src/composite.cpp index ac781c6405..d69f90381c 100644 --- a/src/composite.cpp +++ b/src/composite.cpp @@ -189,9 +189,6 @@ bool Compositor::attemptOpenGLCompositing() return false; } } else { - if (!backend->isDirectRendering()) { - return false; - } if (GLPlatform::instance()->recommendedCompositor() < OpenGLCompositing) { qCDebug(KWIN_CORE) << "Driver does not recommend OpenGL compositing"; return false; diff --git a/src/platformsupport/scenes/opengl/openglbackend.cpp b/src/platformsupport/scenes/opengl/openglbackend.cpp index ed3617d40f..f305c2d1db 100644 --- a/src/platformsupport/scenes/opengl/openglbackend.cpp +++ b/src/platformsupport/scenes/opengl/openglbackend.cpp @@ -20,8 +20,7 @@ namespace KWin { OpenGLBackend::OpenGLBackend() - : m_directRendering(false) - , m_haveBufferAge(false) + : m_haveBufferAge(false) , m_failed(false) { } diff --git a/src/platformsupport/scenes/opengl/openglbackend.h b/src/platformsupport/scenes/opengl/openglbackend.h index a582a3d886..3318f4da18 100644 --- a/src/platformsupport/scenes/opengl/openglbackend.h +++ b/src/platformsupport/scenes/opengl/openglbackend.h @@ -61,18 +61,6 @@ public: { return m_failed; } - /** - * @brief Whether the backend uses direct rendering. - * - * Some OpenGLScene modes require direct rendering. E.g. the OpenGL 2 should not be used - * if direct rendering is not supported by the Scene. - * - * @return bool @c true if the GL context is direct, @c false if indirect - */ - bool isDirectRendering() const - { - return m_directRendering; - } bool supportsBufferAge() const { @@ -119,19 +107,6 @@ protected: * @param reason The reason why the initialization failed. */ void setFailed(const QString &reason); - /** - * @brief Sets whether the OpenGL context is direct. - * - * Should be called by the concrete subclass once it is determined whether the OpenGL context is - * direct or indirect. - * If the subclass does not call this method, the backend defaults to @c false. - * - * @param direct @c true if the OpenGL context is direct, @c false if indirect - */ - void setIsDirectRendering(bool direct) - { - m_directRendering = direct; - } void setSupportsBufferAge(bool value) { @@ -154,10 +129,6 @@ protected: } private: - /** - * @brief Whether direct rendering is used, defaults to @c false. - */ - bool m_directRendering; /** * @brief Whether the backend supports GLX_EXT_buffer_age / EGL_EXT_buffer_age. */