diff --git a/src/backends/x11/common/CMakeLists.txt b/src/backends/x11/common/CMakeLists.txt index eeb630f60a..f97f162a84 100644 --- a/src/backends/x11/common/CMakeLists.txt +++ b/src/backends/x11/common/CMakeLists.txt @@ -6,6 +6,5 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") endif() target_sources(kwin PRIVATE kwinxrenderutils.cpp - x11_common_egl_backend.cpp x11_common_logging.cpp ) diff --git a/src/backends/x11/common/x11_common_egl_backend.cpp b/src/backends/x11/common/x11_common_egl_backend.cpp deleted file mode 100644 index f5ee2f9a50..0000000000 --- a/src/backends/x11/common/x11_common_egl_backend.cpp +++ /dev/null @@ -1,226 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2010, 2012 Martin Gräßlin - - SPDX-License-Identifier: GPL-2.0-or-later -*/ -#include "x11_common_egl_backend.h" -// kwineffects -#include -// kwin -#include "core/outputbackend.h" -#include "main.h" -#include "utils/common.h" -#include "utils/xcbutils.h" -// X11 -#include -#include - -namespace KWin -{ - -EglOnXBackend::EglOnXBackend(xcb_connection_t *connection, Display *display, xcb_window_t rootWindow) - : AbstractEglBackend() - , surfaceHasSubPost(0) - , m_connection(connection) - , m_x11Display(display) - , m_rootWindow(rootWindow) -{ - // Egl is always direct rendering - setIsDirectRendering(true); -} - -void EglOnXBackend::init() -{ - qputenv("EGL_PLATFORM", "x11"); - if (!initRenderingContext()) { - setFailed(QStringLiteral("Could not initialize rendering context")); - return; - } - - initKWinGL(); - if (!hasExtension(QByteArrayLiteral("EGL_KHR_image")) && (!hasExtension(QByteArrayLiteral("EGL_KHR_image_base")) || !hasExtension(QByteArrayLiteral("EGL_KHR_image_pixmap")))) { - setFailed(QStringLiteral("Required support for binding pixmaps to EGLImages not found, disabling compositing")); - return; - } - if (!hasGLExtension(QByteArrayLiteral("GL_OES_EGL_image"))) { - setFailed(QStringLiteral("Required extension GL_OES_EGL_image not found, disabling compositing")); - return; - } - - // check for EGL_NV_post_sub_buffer and whether it can be used on the surface - if (hasExtension(QByteArrayLiteral("EGL_NV_post_sub_buffer"))) { - if (eglQuerySurface(eglDisplay(), surface(), EGL_POST_SUB_BUFFER_SUPPORTED_NV, &surfaceHasSubPost) == EGL_FALSE) { - EGLint error = eglGetError(); - if (error != EGL_SUCCESS && error != EGL_BAD_ATTRIBUTE) { - setFailed(QStringLiteral("query surface failed")); - return; - } else { - surfaceHasSubPost = EGL_FALSE; - } - } - } - - if (surfaceHasSubPost) { - qCDebug(KWIN_CORE) << "EGL implementation and surface support eglPostSubBufferNV, let's use it"; - - // check if swap interval 1 is supported - EGLint val; - eglGetConfigAttrib(eglDisplay(), config(), EGL_MAX_SWAP_INTERVAL, &val); - if (val >= 1) { - if (eglSwapInterval(eglDisplay(), 1)) { - qCDebug(KWIN_CORE) << "Enabled v-sync"; - } - } else { - qCWarning(KWIN_CORE) << "Cannot enable v-sync as max. swap interval is" << val; - } - } else { - /* In the GLX backend, we fall back to using glCopyPixels if we have no extension providing support for partial screen updates. - * However, that does not work in EGL - glCopyPixels with glDrawBuffer(GL_FRONT); does nothing. - * Hence we need EGL to preserve the backbuffer for us, so that we can draw the partial updates on it and call - * eglSwapBuffers() for each frame. eglSwapBuffers() then does the copy (no page flip possible in this mode), - * which means it is slow and not synced to the v-blank. */ - qCWarning(KWIN_CORE) << "eglPostSubBufferNV not supported, have to enable buffer preservation - which breaks v-sync and performance"; - eglSurfaceAttrib(eglDisplay(), surface(), EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED); - } -} - -bool EglOnXBackend::initRenderingContext() -{ - initClientExtensions(); - EGLDisplay dpy = kwinApp()->outputBackend()->sceneEglDisplay(); - - // Use eglGetPlatformDisplayEXT() to get the display pointer - // if the implementation supports it. - if (dpy == EGL_NO_DISPLAY) { - const bool havePlatformBase = hasClientExtension(QByteArrayLiteral("EGL_EXT_platform_base")); - setHavePlatformBase(havePlatformBase); - if (havePlatformBase) { - // Make sure that the X11 platform is supported - if (!hasClientExtension(QByteArrayLiteral("EGL_EXT_platform_x11")) && !hasClientExtension(QByteArrayLiteral("EGL_KHR_platform_x11"))) { - qCWarning(KWIN_CORE) << "EGL_EXT_platform_base is supported, but neither EGL_EXT_platform_x11 nor EGL_KHR_platform_x11 is supported." - << "Cannot create EGLDisplay on X11"; - return false; - } - - dpy = eglGetPlatformDisplayEXT(EGL_PLATFORM_X11_EXT, m_x11Display, nullptr); - } else { - dpy = eglGetDisplay(m_x11Display); - } - } - - if (dpy == EGL_NO_DISPLAY) { - qCWarning(KWIN_CORE) << "Failed to get the EGLDisplay"; - return false; - } - setEglDisplay(dpy); - initEglAPI(); - - initBufferConfigs(); - - if (!createSurfaces()) { - qCCritical(KWIN_CORE) << "Creating egl surface failed"; - return false; - } - - if (!createContext()) { - qCCritical(KWIN_CORE) << "Create OpenGL context failed"; - return false; - } - - if (!makeContextCurrent(surface())) { - qCCritical(KWIN_CORE) << "Make Context Current failed"; - return false; - } - - EGLint error = eglGetError(); - if (error != EGL_SUCCESS) { - qCWarning(KWIN_CORE) << "Error occurred while creating context " << error; - return false; - } - - return true; -} - -EGLSurface EglOnXBackend::createSurface(xcb_window_t window) -{ - if (window == XCB_WINDOW_NONE) { - return EGL_NO_SURFACE; - } - - // Window is 64 bits on a 64-bit architecture whereas xcb_window_t is always 32 bits. - ::Window nativeWindow = window; - - EGLSurface surface = EGL_NO_SURFACE; - if (havePlatformBase()) { - // eglCreatePlatformWindowSurfaceEXT() expects a pointer to the Window. - surface = eglCreatePlatformWindowSurfaceEXT(eglDisplay(), config(), (void *)&nativeWindow, nullptr); - } else { - // eglCreateWindowSurface() expects a Window, not a pointer to the Window. Use - // a c style cast as there are (buggy) platforms where the size of the Window - // type is not the same as the size of EGLNativeWindowType, reinterpret_cast<>() - // may not compile. - surface = eglCreateWindowSurface(eglDisplay(), config(), (EGLNativeWindowType)(uintptr_t)nativeWindow, nullptr); - } - - return surface; -} - -bool EglOnXBackend::initBufferConfigs() -{ - initBufferAge(); - const EGLint config_attribs[] = { - EGL_SURFACE_TYPE, - EGL_WINDOW_BIT | (supportsBufferAge() ? 0 : EGL_SWAP_BEHAVIOR_PRESERVED_BIT), - EGL_RED_SIZE, - 1, - EGL_GREEN_SIZE, - 1, - EGL_BLUE_SIZE, - 1, - EGL_ALPHA_SIZE, - 0, - EGL_RENDERABLE_TYPE, - isOpenGLES() ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_BIT, - EGL_CONFIG_CAVEAT, - EGL_NONE, - EGL_NONE, - }; - - EGLint count; - EGLConfig configs[1024]; - if (eglChooseConfig(eglDisplay(), config_attribs, configs, 1024, &count) == EGL_FALSE) { - qCCritical(KWIN_CORE) << "choose config failed"; - return false; - } - - UniqueCPtr attribs(xcb_get_window_attributes_reply(m_connection, - xcb_get_window_attributes_unchecked(m_connection, m_rootWindow), - nullptr)); - if (!attribs) { - qCCritical(KWIN_CORE) << "Failed to get window attributes of root window"; - return false; - } - - setConfig(configs[0]); - for (int i = 0; i < count; i++) { - EGLint val; - if (eglGetConfigAttrib(eglDisplay(), configs[i], EGL_NATIVE_VISUAL_ID, &val) == EGL_FALSE) { - qCCritical(KWIN_CORE) << "egl get config attrib failed"; - } - if (uint32_t(val) == attribs->visual) { - setConfig(configs[i]); - break; - } - } - return true; -} - -bool EglOnXBackend::makeContextCurrent(const EGLSurface &surface) -{ - return eglMakeCurrent(eglDisplay(), surface, surface, context()) == EGL_TRUE; -} - -} // namespace diff --git a/src/backends/x11/common/x11_common_egl_backend.h b/src/backends/x11/common/x11_common_egl_backend.h deleted file mode 100644 index decc64a523..0000000000 --- a/src/backends/x11/common/x11_common_egl_backend.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2012 Martin Gräßlin - - SPDX-License-Identifier: GPL-2.0-or-later -*/ -#pragma once -#include "abstract_egl_backend.h" - -#include - -struct _XDisplay; -typedef struct _XDisplay Display; -typedef unsigned long XID; -typedef XID Window; - -namespace KWin -{ - -/** - * @brief OpenGL Backend using Egl windowing system over an X overlay window. - */ -class KWIN_EXPORT EglOnXBackend : public AbstractEglBackend -{ - Q_OBJECT - -public: - explicit EglOnXBackend(xcb_connection_t *connection, Display *display, xcb_window_t rootWindow); - - void init() override; - -protected: - virtual bool createSurfaces() = 0; - EGLSurface createSurface(xcb_window_t window); - void setHavePlatformBase(bool have) - { - m_havePlatformBase = have; - } - bool havePlatformBase() const - { - return m_havePlatformBase; - } - bool havePostSubBuffer() const - { - return surfaceHasSubPost; - } - bool makeContextCurrent(const EGLSurface &surface); - -private: - bool initBufferConfigs(); - bool initRenderingContext(); - int surfaceHasSubPost; - xcb_connection_t *m_connection; - Display *m_x11Display; - xcb_window_t m_rootWindow; - bool m_havePlatformBase = false; -}; - -} // namespace diff --git a/src/backends/x11/standalone/x11_standalone_backend.cpp b/src/backends/x11/standalone/x11_standalone_backend.cpp index bcbaddbbd7..da126502a5 100644 --- a/src/backends/x11/standalone/x11_standalone_backend.cpp +++ b/src/backends/x11/standalone/x11_standalone_backend.cpp @@ -125,6 +125,21 @@ X11StandaloneBackend::~X11StandaloneBackend() XRenderUtils::cleanup(); } +Display *X11StandaloneBackend::display() const +{ + return m_x11Display; +} + +xcb_connection_t *X11StandaloneBackend::connection() const +{ + return kwinApp()->x11Connection(); +} + +xcb_window_t X11StandaloneBackend::rootWindow() const +{ + return kwinApp()->x11RootWindow(); +} + bool X11StandaloneBackend::initialize() { if (!QX11Info::isPlatformX11()) { diff --git a/src/backends/x11/standalone/x11_standalone_backend.h b/src/backends/x11/standalone/x11_standalone_backend.h index 0344689762..c06256d299 100644 --- a/src/backends/x11/standalone/x11_standalone_backend.h +++ b/src/backends/x11/standalone/x11_standalone_backend.h @@ -46,6 +46,10 @@ public: ~X11StandaloneBackend() override; bool initialize() override; + Display *display() const; + xcb_connection_t *connection() const; + xcb_window_t rootWindow() const; + std::unique_ptr createOpenGLBackend() override; QVector supportedCompositors() const override; diff --git a/src/backends/x11/standalone/x11_standalone_egl_backend.cpp b/src/backends/x11/standalone/x11_standalone_egl_backend.cpp index e1ad7a1d9b..a7b3e0f492 100644 --- a/src/backends/x11/standalone/x11_standalone_egl_backend.cpp +++ b/src/backends/x11/standalone/x11_standalone_egl_backend.cpp @@ -47,11 +47,12 @@ uint EglLayer::format() const } EglBackend::EglBackend(Display *display, X11StandaloneBackend *backend) - : EglOnXBackend(kwinApp()->x11Connection(), display, kwinApp()->x11RootWindow()) - , m_backend(backend) + : m_backend(backend) , m_overlayWindow(std::make_unique()) , 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? @@ -112,14 +113,92 @@ void EglBackend::init() kwinApp()->outputBackend()->setSceneEglDisplay(shareDisplay); kwinApp()->outputBackend()->setSceneEglGlobalShareContext(shareContext); - EglOnXBackend::init(); + + qputenv("EGL_PLATFORM", "x11"); + if (!initRenderingContext()) { + setFailed(QStringLiteral("Could not initialize rendering context")); + return; + } + + initKWinGL(); + + if (!hasExtension(QByteArrayLiteral("EGL_KHR_image")) && (!hasExtension(QByteArrayLiteral("EGL_KHR_image_base")) || !hasExtension(QByteArrayLiteral("EGL_KHR_image_pixmap")))) { + setFailed(QStringLiteral("Required support for binding pixmaps to EGLImages not found, disabling compositing")); + return; + } + if (!hasGLExtension(QByteArrayLiteral("GL_OES_EGL_image"))) { + setFailed(QStringLiteral("Required extension GL_OES_EGL_image not found, disabling compositing")); + return; + } + + // check for EGL_NV_post_sub_buffer and whether it can be used on the surface + if (hasExtension(QByteArrayLiteral("EGL_NV_post_sub_buffer"))) { + if (eglQuerySurface(eglDisplay(), surface(), EGL_POST_SUB_BUFFER_SUPPORTED_NV, &m_havePostSubBuffer) == EGL_FALSE) { + EGLint error = eglGetError(); + if (error != EGL_SUCCESS && error != EGL_BAD_ATTRIBUTE) { + setFailed(QStringLiteral("query surface failed")); + return; + } else { + m_havePostSubBuffer = EGL_FALSE; + } + } + } + + if (m_havePostSubBuffer) { + qCDebug(KWIN_CORE) << "EGL implementation and surface support eglPostSubBufferNV, let's use it"; + + // check if swap interval 1 is supported + EGLint val; + eglGetConfigAttrib(eglDisplay(), config(), EGL_MAX_SWAP_INTERVAL, &val); + if (val >= 1) { + if (eglSwapInterval(eglDisplay(), 1)) { + qCDebug(KWIN_CORE) << "Enabled v-sync"; + } + } else { + qCWarning(KWIN_CORE) << "Cannot enable v-sync as max. swap interval is" << val; + } + } else { + /* In the GLX backend, we fall back to using glCopyPixels if we have no extension providing support for partial screen updates. + * However, that does not work in EGL - glCopyPixels with glDrawBuffer(GL_FRONT); does nothing. + * Hence we need EGL to preserve the backbuffer for us, so that we can draw the partial updates on it and call + * eglSwapBuffers() for each frame. eglSwapBuffers() then does the copy (no page flip possible in this mode), + * which means it is slow and not synced to the v-blank. */ + qCWarning(KWIN_CORE) << "eglPostSubBufferNV not supported, have to enable buffer preservation - which breaks v-sync and performance"; + eglSurfaceAttrib(eglDisplay(), surface(), EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED); + } } -bool EglBackend::createSurfaces() +bool EglBackend::initRenderingContext() { - if (!m_overlayWindow) { + initClientExtensions(); + EGLDisplay dpy = kwinApp()->outputBackend()->sceneEglDisplay(); + + // Use eglGetPlatformDisplayEXT() to get the display pointer + // if the implementation supports it. + if (dpy == EGL_NO_DISPLAY) { + m_havePlatformBase = hasClientExtension(QByteArrayLiteral("EGL_EXT_platform_base")); + if (m_havePlatformBase) { + // Make sure that the X11 platform is supported + if (!hasClientExtension(QByteArrayLiteral("EGL_EXT_platform_x11")) && !hasClientExtension(QByteArrayLiteral("EGL_KHR_platform_x11"))) { + qCWarning(KWIN_CORE) << "EGL_EXT_platform_base is supported, but neither EGL_EXT_platform_x11 nor EGL_KHR_platform_x11 is supported." + << "Cannot create EGLDisplay on X11"; + return false; + } + + dpy = eglGetPlatformDisplayEXT(EGL_PLATFORM_X11_EXT, m_backend->display(), nullptr); + } else { + dpy = eglGetDisplay(m_backend->display()); + } + } + + if (dpy == EGL_NO_DISPLAY) { + qCWarning(KWIN_CORE) << "Failed to get the EGLDisplay"; return false; } + setEglDisplay(dpy); + initEglAPI(); + + initBufferConfigs(); if (!m_overlayWindow->create()) { qCCritical(KWIN_X11STANDALONE) << "Could not get overlay window"; @@ -130,9 +209,101 @@ bool EglBackend::createSurfaces() EGLSurface surface = createSurface(m_overlayWindow->window()); if (surface == EGL_NO_SURFACE) { + qCCritical(KWIN_CORE) << "Creating egl surface failed"; return false; } setSurface(surface); + + if (!createContext()) { + qCCritical(KWIN_CORE) << "Create OpenGL context failed"; + return false; + } + + if (!makeCurrent()) { + qCCritical(KWIN_CORE) << "Make Context Current failed"; + return false; + } + + EGLint error = eglGetError(); + if (error != EGL_SUCCESS) { + qCWarning(KWIN_CORE) << "Error occurred while creating context " << error; + return false; + } + + return true; +} + +EGLSurface EglBackend::createSurface(xcb_window_t window) +{ + if (window == XCB_WINDOW_NONE) { + return EGL_NO_SURFACE; + } + + // Window is 64 bits on a 64-bit architecture whereas xcb_window_t is always 32 bits. + ::Window nativeWindow = window; + + EGLSurface surface = EGL_NO_SURFACE; + if (m_havePlatformBase) { + // eglCreatePlatformWindowSurfaceEXT() expects a pointer to the Window. + surface = eglCreatePlatformWindowSurfaceEXT(eglDisplay(), config(), (void *)&nativeWindow, nullptr); + } else { + // eglCreateWindowSurface() expects a Window, not a pointer to the Window. Use + // a c style cast as there are (buggy) platforms where the size of the Window + // type is not the same as the size of EGLNativeWindowType, reinterpret_cast<>() + // may not compile. + surface = eglCreateWindowSurface(eglDisplay(), config(), (EGLNativeWindowType)(uintptr_t)nativeWindow, nullptr); + } + + return surface; +} + +bool EglBackend::initBufferConfigs() +{ + initBufferAge(); + const EGLint config_attribs[] = { + EGL_SURFACE_TYPE, + EGL_WINDOW_BIT | (supportsBufferAge() ? 0 : EGL_SWAP_BEHAVIOR_PRESERVED_BIT), + EGL_RED_SIZE, + 1, + EGL_GREEN_SIZE, + 1, + EGL_BLUE_SIZE, + 1, + EGL_ALPHA_SIZE, + 0, + EGL_RENDERABLE_TYPE, + isOpenGLES() ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_BIT, + EGL_CONFIG_CAVEAT, + EGL_NONE, + EGL_NONE, + }; + + EGLint count; + EGLConfig configs[1024]; + if (eglChooseConfig(eglDisplay(), config_attribs, configs, 1024, &count) == EGL_FALSE) { + qCCritical(KWIN_CORE) << "choose config failed"; + return false; + } + + UniqueCPtr attribs(xcb_get_window_attributes_reply(m_backend->connection(), + xcb_get_window_attributes_unchecked(m_backend->connection(), m_backend->rootWindow()), + nullptr)); + if (!attribs) { + qCCritical(KWIN_CORE) << "Failed to get window attributes of root window"; + return false; + } + + setConfig(configs[0]); + for (int i = 0; i < count; i++) { + EGLint val; + if (eglGetConfigAttrib(eglDisplay(), configs[i], EGL_NATIVE_VISUAL_ID, &val) == EGL_FALSE) { + qCCritical(KWIN_CORE) << "egl get config attrib failed"; + } + if (uint32_t(val) == attribs->visual) { + setConfig(configs[i]); + break; + } + } return true; } @@ -198,7 +369,7 @@ void EglBackend::presentSurface(EGLSurface surface, const QRegion &damage, const { const bool fullRepaint = supportsBufferAge() || (damage == screenGeometry); - if (fullRepaint || !havePostSubBuffer()) { + if (fullRepaint || !m_havePostSubBuffer) { // the entire screen changed, or we cannot do partial updates (which implies we enabled surface preservation) eglSwapBuffers(eglDisplay(), surface); if (supportsBufferAge()) { diff --git a/src/backends/x11/standalone/x11_standalone_egl_backend.h b/src/backends/x11/standalone/x11_standalone_egl_backend.h index e336e756e5..a495fd98f3 100644 --- a/src/backends/x11/standalone/x11_standalone_egl_backend.h +++ b/src/backends/x11/standalone/x11_standalone_egl_backend.h @@ -6,9 +6,9 @@ #pragma once -#include "../common/x11_common_egl_backend.h" #include "core/outputlayer.h" -#include "openglsurfacetexture_x11.h" +#include "platformsupport/scenes/opengl/abstract_egl_backend.h" +#include "platformsupport/scenes/opengl/openglsurfacetexture_x11.h" #include "utils/damagejournal.h" #include @@ -35,7 +35,7 @@ private: EglBackend *const m_backend; }; -class EglBackend : public EglOnXBackend +class EglBackend : public AbstractEglBackend { Q_OBJECT @@ -53,12 +53,14 @@ public: OutputLayer *primaryLayer(Output *output) override; protected: - bool createSurfaces() override; + bool initBufferConfigs() override; + bool initRenderingContext(); private: void screenGeometryChanged(); void presentSurface(EGLSurface surface, const QRegion &damage, const QRect &screenGeometry); void vblank(std::chrono::nanoseconds timestamp); + EGLSurface createSurface(xcb_window_t window); X11StandaloneBackend *m_backend; std::unique_ptr m_vsyncMonitor; @@ -68,6 +70,8 @@ private: int m_bufferAge = 0; QRegion m_lastRenderedRegion; std::unique_ptr m_layer; + int m_havePostSubBuffer = false; + bool m_havePlatformBase = false; }; class EglPixmapTexture : public GLTexture diff --git a/src/backends/x11/windowed/x11_windowed_egl_backend.cpp b/src/backends/x11/windowed/x11_windowed_egl_backend.cpp index bdd13b39ed..9edb13f695 100644 --- a/src/backends/x11/windowed/x11_windowed_egl_backend.cpp +++ b/src/backends/x11/windowed/x11_windowed_egl_backend.cpp @@ -259,9 +259,9 @@ quint32 X11WindowedEglCursorLayer::format() const } X11WindowedEglBackend::X11WindowedEglBackend(X11WindowedBackend *backend) - : EglOnXBackend(backend->connection(), backend->display(), backend->rootWindow()) - , m_backend(backend) + : m_backend(backend) { + setIsDirectRendering(true); } X11WindowedEglBackend::~X11WindowedEglBackend() @@ -274,22 +274,64 @@ X11WindowedBackend *X11WindowedEglBackend::backend() const return m_backend; } +bool X11WindowedEglBackend::initializeEgl() +{ + initClientExtensions(); + EGLDisplay dpy = kwinApp()->outputBackend()->sceneEglDisplay(); + + // Use eglGetPlatformDisplayEXT() to get the display pointer + // if the implementation supports it. + if (dpy == EGL_NO_DISPLAY) { + const bool havePlatformBase = hasClientExtension(QByteArrayLiteral("EGL_EXT_platform_base")); + if (havePlatformBase) { + // Make sure that the X11 platform is supported + if (!hasClientExtension(QByteArrayLiteral("EGL_EXT_platform_x11")) && !hasClientExtension(QByteArrayLiteral("EGL_KHR_platform_x11"))) { + qCWarning(KWIN_X11WINDOWED) << "EGL_EXT_platform_base is supported, but neither EGL_EXT_platform_x11 nor EGL_KHR_platform_x11 is supported." + << "Cannot create EGLDisplay on X11"; + return false; + } + + dpy = eglGetPlatformDisplayEXT(EGL_PLATFORM_X11_EXT, m_backend->display(), nullptr); + } else { + dpy = eglGetDisplay(m_backend->display()); + } + } + + if (dpy == EGL_NO_DISPLAY) { + return false; + } + setEglDisplay(dpy); + return initEglAPI(); +} + +bool X11WindowedEglBackend::initRenderingContext() +{ + initBufferConfigs(); + + if (!createContext()) { + return false; + } + + return makeCurrent(); +} + void X11WindowedEglBackend::init() { - EglOnXBackend::init(); + qputenv("EGL_PLATFORM", "x11"); - if (!isFailed()) { - initWayland(); + if (!initializeEgl()) { + setFailed(QStringLiteral("Could not initialize egl")); + return; + } + if (!initRenderingContext()) { + setFailed(QStringLiteral("Could not initialize rendering context")); + return; } -} -void X11WindowedEglBackend::cleanupSurfaces() -{ - m_outputs.clear(); -} + initKWinGL(); + initBufferAge(); + initWayland(); -bool X11WindowedEglBackend::createSurfaces() -{ const auto &outputs = m_backend->outputs(); for (const auto &output : outputs) { X11WindowedOutput *x11Output = static_cast(output); @@ -298,7 +340,11 @@ bool X11WindowedEglBackend::createSurfaces() .cursorLayer = std::make_unique(this, x11Output), }; } - return true; +} + +void X11WindowedEglBackend::cleanupSurfaces() +{ + m_outputs.clear(); } void X11WindowedEglBackend::present(Output *output) diff --git a/src/backends/x11/windowed/x11_windowed_egl_backend.h b/src/backends/x11/windowed/x11_windowed_egl_backend.h index 43b3fa509f..9012174e48 100644 --- a/src/backends/x11/windowed/x11_windowed_egl_backend.h +++ b/src/backends/x11/windowed/x11_windowed_egl_backend.h @@ -8,9 +8,9 @@ */ #pragma once -#include "../common/x11_common_egl_backend.h" #include "core/outputlayer.h" #include "kwinglutils.h" +#include "platformsupport/scenes/opengl/abstract_egl_backend.h" #include @@ -103,7 +103,7 @@ private: /** * @brief OpenGL Backend using Egl windowing system over an X overlay window. */ -class X11WindowedEglBackend : public EglOnXBackend +class X11WindowedEglBackend : public AbstractEglBackend { Q_OBJECT @@ -124,9 +124,11 @@ public: protected: void cleanupSurfaces() override; - bool createSurfaces() override; private: + bool initializeEgl(); + bool initRenderingContext(); + struct Layers { std::unique_ptr primaryLayer;