backends/x11: Split EglOnXBackend
The differences between windowed and host flavors of the X11 backend have become too big, so let's split EglOnXBackend to avoid abstracting something that makes little sense.
This commit is contained in:
parent
3bec3abb3f
commit
58ac7888e9
9 changed files with 268 additions and 314 deletions
|
@ -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
|
||||
)
|
||||
|
|
|
@ -1,226 +0,0 @@
|
|||
/*
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
SPDX-FileCopyrightText: 2010, 2012 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
#include "x11_common_egl_backend.h"
|
||||
// kwineffects
|
||||
#include <kwinglutils.h>
|
||||
// kwin
|
||||
#include "core/outputbackend.h"
|
||||
#include "main.h"
|
||||
#include "utils/common.h"
|
||||
#include "utils/xcbutils.h"
|
||||
// X11
|
||||
#include <X11/Xlib-xcb.h>
|
||||
#include <fixx11h.h>
|
||||
|
||||
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<xcb_get_window_attributes_reply_t> 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
|
|
@ -1,61 +0,0 @@
|
|||
/*
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
SPDX-FileCopyrightText: 2012 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
#pragma once
|
||||
#include "abstract_egl_backend.h"
|
||||
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
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
|
|
@ -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()) {
|
||||
|
|
|
@ -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<OpenGLBackend> createOpenGLBackend() override;
|
||||
QVector<CompositingType> supportedCompositors() const override;
|
||||
|
||||
|
|
|
@ -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<OverlayWindowX11>())
|
||||
, m_layer(std::make_unique<EglLayer>(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<xcb_get_window_attributes_reply_t> 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()) {
|
||||
|
|
|
@ -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 <kwingltexture.h>
|
||||
|
@ -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<SoftwareVsyncMonitor> m_vsyncMonitor;
|
||||
|
@ -68,6 +70,8 @@ private:
|
|||
int m_bufferAge = 0;
|
||||
QRegion m_lastRenderedRegion;
|
||||
std::unique_ptr<EglLayer> m_layer;
|
||||
int m_havePostSubBuffer = false;
|
||||
bool m_havePlatformBase = false;
|
||||
};
|
||||
|
||||
class EglPixmapTexture : public GLTexture
|
||||
|
|
|
@ -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<X11WindowedOutput *>(output);
|
||||
|
@ -298,7 +340,11 @@ bool X11WindowedEglBackend::createSurfaces()
|
|||
.cursorLayer = std::make_unique<X11WindowedEglCursorLayer>(this, x11Output),
|
||||
};
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void X11WindowedEglBackend::cleanupSurfaces()
|
||||
{
|
||||
m_outputs.clear();
|
||||
}
|
||||
|
||||
void X11WindowedEglBackend::present(Output *output)
|
||||
|
|
|
@ -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 <QMap>
|
||||
|
||||
|
@ -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<X11WindowedEglPrimaryLayer> primaryLayer;
|
||||
|
|
Loading…
Reference in a new issue