diff --git a/src/backends/x11/standalone/x11_standalone_backend.cpp b/src/backends/x11/standalone/x11_standalone_backend.cpp index 4f057a4e8f..184038cfbc 100644 --- a/src/backends/x11/standalone/x11_standalone_backend.cpp +++ b/src/backends/x11/standalone/x11_standalone_backend.cpp @@ -24,6 +24,7 @@ #endif #include "core/renderloop.h" #include "keyboard_input.h" +#include "opengl/egldisplay.h" #include "options.h" #include "utils/c_ptr.h" #include "utils/edid.h" diff --git a/src/backends/x11/standalone/x11_standalone_egl_backend.cpp b/src/backends/x11/standalone/x11_standalone_egl_backend.cpp index 3a17786bdd..58d86c86e7 100644 --- a/src/backends/x11/standalone/x11_standalone_egl_backend.cpp +++ b/src/backends/x11/standalone/x11_standalone_egl_backend.cpp @@ -11,6 +11,8 @@ #include "core/outputlayer.h" #include "core/overlaywindow.h" #include "core/renderloop_p.h" +#include "opengl/eglcontext.h" +#include "opengl/egldisplay.h" #include "opengl/glplatform.h" #include "opengl/glrendertimequery.h" #include "options.h" @@ -81,7 +83,10 @@ EglBackend::~EglBackend() if (isFailed() && m_overlayWindow) { m_overlayWindow->destroy(); } - cleanup(); + if (m_surface != EGL_NO_SURFACE) { + eglDestroySurface(eglDisplayObject()->handle(), m_surface); + } + m_context.reset(); if (m_overlayWindow && m_overlayWindow->window()) { m_overlayWindow->destroy(); @@ -117,7 +122,7 @@ void EglBackend::init() m_fbo = std::make_unique(0, workspace()->geometry().size()); m_backend->setEglDisplay(EglDisplay::create(shareDisplay, false)); - kwinApp()->outputBackend()->setSceneEglGlobalShareContext(shareContext); + m_backend->setSceneEglGlobalShareContext(shareContext); qputenv("EGL_PLATFORM", "x11"); if (!initRenderingContext()) { @@ -136,7 +141,7 @@ void EglBackend::init() // 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(eglDisplayObject()->handle(), surface(), EGL_POST_SUB_BUFFER_SUPPORTED_NV, &m_havePostSubBuffer) == EGL_FALSE) { + if (eglQuerySurface(eglDisplayObject()->handle(), m_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")); @@ -152,7 +157,7 @@ void EglBackend::init() // check if swap interval 1 is supported EGLint val; - eglGetConfigAttrib(eglDisplayObject()->handle(), config(), EGL_MAX_SWAP_INTERVAL, &val); + eglGetConfigAttrib(eglDisplayObject()->handle(), m_context->config(), EGL_MAX_SWAP_INTERVAL, &val); if (val >= 1) { if (eglSwapInterval(eglDisplayObject()->handle(), 1)) { qCDebug(KWIN_CORE) << "Enabled v-sync"; @@ -167,7 +172,7 @@ void EglBackend::init() * 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(eglDisplayObject()->handle(), surface(), EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED); + eglSurfaceAttrib(eglDisplayObject()->handle(), m_surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED); } m_swapStrategy = options->glPreferBufferSwap(); @@ -183,6 +188,25 @@ void EglBackend::init() } } +void EglBackend::initClientExtensions() +{ + // Get the list of client extensions + const char *clientExtensionsCString = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); + const QByteArray clientExtensionsString = QByteArray::fromRawData(clientExtensionsCString, qstrlen(clientExtensionsCString)); + if (clientExtensionsString.isEmpty()) { + // If eglQueryString() returned NULL, the implementation doesn't support + // EGL_EXT_client_extensions. Expect an EGL_BAD_DISPLAY error. + (void)eglGetError(); + } + + m_clientExtensions = clientExtensionsString.split(' '); +} + +bool EglBackend::hasClientExtension(const QByteArray &name) +{ + return m_clientExtensions.contains(name); +} + bool EglBackend::initRenderingContext() { initClientExtensions(); @@ -211,9 +235,11 @@ bool EglBackend::initRenderingContext() } } - setEglDisplay(display); - - if (!createContext(chooseBufferConfig())) { + setSupportsBufferAge(display->supportsBufferAge()); + setSupportsNativeFence(display->supportsNativeFence()); + setExtensions(display->extensions()); + m_context = EglContext::create(display, chooseBufferConfig(), m_backend->sceneEglGlobalShareContext()); + if (!m_context) { qCCritical(KWIN_CORE) << "Create OpenGL context failed"; return false; } @@ -225,12 +251,11 @@ bool EglBackend::initRenderingContext() m_overlayWindow->setup(XCB_WINDOW_NONE); } - EGLSurface surface = createSurface(m_overlayWindow->window()); - if (surface == EGL_NO_SURFACE) { + m_surface = createSurface(m_overlayWindow->window()); + if (m_surface == EGL_NO_SURFACE) { qCCritical(KWIN_CORE) << "Creating egl surface failed"; return false; } - setSurface(surface); if (!makeCurrent()) { qCCritical(KWIN_CORE) << "Make Context Current failed"; @@ -258,13 +283,13 @@ EGLSurface EglBackend::createSurface(xcb_window_t window) EGLSurface surface = EGL_NO_SURFACE; if (m_havePlatformBase) { // eglCreatePlatformWindowSurfaceEXT() expects a pointer to the Window. - surface = eglCreatePlatformWindowSurfaceEXT(eglDisplayObject()->handle(), config(), (void *)&nativeWindow, nullptr); + surface = eglCreatePlatformWindowSurfaceEXT(eglDisplayObject()->handle(), m_context->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(eglDisplayObject()->handle(), config(), (EGLNativeWindowType)(uintptr_t)nativeWindow, nullptr); + surface = eglCreateWindowSurface(eglDisplayObject()->handle(), m_context->config(), (EGLNativeWindowType)(uintptr_t)nativeWindow, nullptr); } return surface; @@ -284,7 +309,7 @@ EGLConfig EglBackend::chooseBufferConfig() EGL_ALPHA_SIZE, 0, EGL_RENDERABLE_TYPE, - isOpenGLES() ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_BIT, + EglDisplay::shouldUseOpenGLES() ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_BIT, EGL_CONFIG_CAVEAT, EGL_NONE, EGL_NONE, @@ -374,7 +399,7 @@ void EglBackend::present(Output *output, const std::shared_ptr &fra } } - presentSurface(surface(), effectiveRenderedRegion, workspace()->geometry()); + presentSurface(m_surface, effectiveRenderedRegion, workspace()->geometry()); if (overlayWindow() && overlayWindow()->window()) { // show the window only after the first pass, overlayWindow()->show(); // since that pass may take long @@ -421,6 +446,26 @@ void EglBackend::vblank(std::chrono::nanoseconds timestamp) m_frame.reset(); } +EglDisplay *EglBackend::eglDisplayObject() const +{ + return m_backend->sceneEglDisplayObject(); +} + +OpenGlContext *EglBackend::openglContext() const +{ + return m_context.get(); +} + +bool EglBackend::makeCurrent() +{ + return m_context->makeCurrent(m_surface); +} + +void EglBackend::doneCurrent() +{ + m_context->doneCurrent(); +} + EglSurfaceTextureX11::EglSurfaceTextureX11(EglBackend *backend, SurfacePixmapX11 *texture) : OpenGLSurfaceTextureX11(backend, texture) { diff --git a/src/backends/x11/standalone/x11_standalone_egl_backend.h b/src/backends/x11/standalone/x11_standalone_egl_backend.h index 98d6e12189..fcd9c7244f 100644 --- a/src/backends/x11/standalone/x11_standalone_egl_backend.h +++ b/src/backends/x11/standalone/x11_standalone_egl_backend.h @@ -8,13 +8,15 @@ #include "core/outputlayer.h" #include "options.h" -#include "platformsupport/scenes/opengl/abstract_egl_backend.h" +#include "platformsupport/scenes/opengl/openglbackend.h" #include "platformsupport/scenes/opengl/openglsurfacetexture_x11.h" #include "utils/damagejournal.h" #include "opengl/gltexture.h" #include "opengl/gltexture_p.h" +#include + typedef struct _XDisplay Display; namespace KWin @@ -25,6 +27,8 @@ class SoftwareVsyncMonitor; class X11StandaloneBackend; class EglBackend; class GLRenderTimeQuery; +class EglDisplay; +class EglContext; class EglLayer : public OutputLayer { @@ -39,10 +43,9 @@ private: EglBackend *const m_backend; }; -class EglBackend : public AbstractEglBackend +class EglBackend : public OpenGLBackend { Q_OBJECT - public: EglBackend(::Display *display, X11StandaloneBackend *platform); ~EglBackend() override; @@ -56,16 +59,20 @@ public: OverlayWindow *overlayWindow() const override; OutputLayer *primaryLayer(Output *output) override; std::chrono::nanoseconds queryRenderTime(); + EglDisplay *eglDisplayObject() const; + OpenGlContext *openglContext() const override; + bool makeCurrent() override; + void doneCurrent() override; -protected: +private: EGLConfig chooseBufferConfig(); bool initRenderingContext(); - -private: + void initClientExtensions(); + bool hasClientExtension(const QByteArray &name); void screenGeometryChanged(); - void presentSurface(EGLSurface surface, const QRegion &damage, const QRect &screenGeometry); + void presentSurface(::EGLSurface surface, const QRegion &damage, const QRect &screenGeometry); void vblank(std::chrono::nanoseconds timestamp); - EGLSurface createSurface(xcb_window_t window); + ::EGLSurface createSurface(xcb_window_t window); X11StandaloneBackend *m_backend; std::unique_ptr m_vsyncMonitor; @@ -80,6 +87,10 @@ private: bool m_havePlatformBase = false; Options::GlSwapStrategy m_swapStrategy = Options::AutoSwapStrategy; std::shared_ptr m_frame; + + QList m_clientExtensions; + std::unique_ptr m_context; + ::EGLSurface m_surface = EGL_NO_SURFACE; }; 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 24c7ba3725..770e50b956 100644 --- a/src/backends/x11/windowed/x11_windowed_egl_backend.cpp +++ b/src/backends/x11/windowed/x11_windowed_egl_backend.cpp @@ -185,6 +185,7 @@ X11WindowedEglBackend::X11WindowedEglBackend(X11WindowedBackend *backend) X11WindowedEglBackend::~X11WindowedEglBackend() { + m_outputs.clear(); cleanup(); } @@ -255,11 +256,6 @@ void X11WindowedEglBackend::init() } } -void X11WindowedEglBackend::cleanupSurfaces() -{ - m_outputs.clear(); -} - void X11WindowedEglBackend::present(Output *output, const std::shared_ptr &frame) { m_outputs[output].primaryLayer->present(); diff --git a/src/backends/x11/windowed/x11_windowed_egl_backend.h b/src/backends/x11/windowed/x11_windowed_egl_backend.h index 88e3bd70a2..6065c15529 100644 --- a/src/backends/x11/windowed/x11_windowed_egl_backend.h +++ b/src/backends/x11/windowed/x11_windowed_egl_backend.h @@ -85,9 +85,6 @@ public: OutputLayer *primaryLayer(Output *output) override; OutputLayer *cursorLayer(Output *output) override; -protected: - void cleanupSurfaces() override; - private: bool initializeEgl(); bool initRenderingContext(); diff --git a/src/opengl/egldisplay.cpp b/src/opengl/egldisplay.cpp index 0f3921dca8..fb9dd383ab 100644 --- a/src/opengl/egldisplay.cpp +++ b/src/opengl/egldisplay.cpp @@ -23,7 +23,7 @@ namespace KWin { -static bool shouldUseOpenGLES() +bool EglDisplay::shouldUseOpenGLES() { if (qstrcmp(qgetenv("KWIN_COMPOSE"), "O2ES") == 0) { return true; diff --git a/src/opengl/egldisplay.h b/src/opengl/egldisplay.h index 1de350916f..c439f4ff3f 100644 --- a/src/opengl/egldisplay.h +++ b/src/opengl/egldisplay.h @@ -54,6 +54,7 @@ public: EGLImageKHR importDmaBufAsImage(const DmaBufAttributes &dmabuf) const; EGLImageKHR importDmaBufAsImage(const DmaBufAttributes &dmabuf, int plane, int format, const QSize &size) const; + static bool shouldUseOpenGLES(); static std::unique_ptr create(::EGLDisplay display, bool owning = true); private: diff --git a/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp b/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp index 6a77ac3442..b22dd51a9a 100644 --- a/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp +++ b/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp @@ -33,14 +33,6 @@ namespace KWin static std::unique_ptr s_globalShareContext; -static bool isOpenGLES_helper() -{ - if (qstrcmp(qgetenv("KWIN_COMPOSE"), "O2ES") == 0) { - return true; - } - return QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES; -} - AbstractEglBackend::AbstractEglBackend(dev_t deviceId) : m_deviceId(deviceId) { @@ -91,9 +83,6 @@ void AbstractEglBackend::cleanup() void AbstractEglBackend::cleanupSurfaces() { - if (m_surface != EGL_NO_SURFACE) { - eglDestroySurface(m_display->handle(), m_surface); - } } void AbstractEglBackend::setEglDisplay(EglDisplay *display) @@ -230,7 +219,7 @@ bool AbstractEglBackend::makeCurrent() // Workaround to tell Qt that no QOpenGLContext is current context->doneCurrent(); } - return m_context->makeCurrent(m_surface); + return m_context->makeCurrent(); } void AbstractEglBackend::doneCurrent() @@ -240,7 +229,7 @@ void AbstractEglBackend::doneCurrent() bool AbstractEglBackend::isOpenGLES() const { - return isOpenGLES_helper(); + return EglDisplay::shouldUseOpenGLES(); } bool AbstractEglBackend::createContext(EGLConfig config) @@ -252,11 +241,6 @@ bool AbstractEglBackend::createContext(EGLConfig config) return m_context != nullptr; } -void AbstractEglBackend::setSurface(const EGLSurface &surface) -{ - m_surface = surface; -} - QList AbstractEglBackend::tranches() const { return m_tranches; @@ -336,11 +320,6 @@ QHash> AbstractEglBackend::supportedFormats() const return m_display->nonExternalOnlySupportedDrmFormats(); } -EGLSurface AbstractEglBackend::surface() const -{ - return m_surface; -} - EGLConfig AbstractEglBackend::config() const { return m_context->config(); diff --git a/src/platformsupport/scenes/opengl/abstract_egl_backend.h b/src/platformsupport/scenes/opengl/abstract_egl_backend.h index a086f6b2e8..a5d72e5be7 100644 --- a/src/platformsupport/scenes/opengl/abstract_egl_backend.h +++ b/src/platformsupport/scenes/opengl/abstract_egl_backend.h @@ -32,7 +32,6 @@ public: bool makeCurrent() override; void doneCurrent() override; - EGLSurface surface() const; EGLConfig config() const; EglDisplay *eglDisplayObject() const; EglContext *openglContext() const override; @@ -51,7 +50,6 @@ public: protected: AbstractEglBackend(dev_t deviceId = 0); - void setSurface(const EGLSurface &surface); void cleanup(); virtual void cleanupSurfaces(); void setEglDisplay(EglDisplay *display); @@ -67,7 +65,6 @@ protected: void teardown(); EglDisplay *m_display = nullptr; - EGLSurface m_surface = EGL_NO_SURFACE; std::shared_ptr m_context; QList m_clientExtensions; const dev_t m_deviceId;