Allow using EGLOnXBackend with X11WindowedBackend

Mostly refactoring to not take the global X11 information (connection,
display, etc.). Adds a dedicated ctor overload which takes the
X11WindowedBackend.

SceneOpenGL is adjusted to create an EGLOnXBackend instead of Wayland one
if the X11WindowedBackend is used.
This commit is contained in:
Martin Gräßlin 2015-03-19 11:26:53 +01:00
parent 3cc1032839
commit a1642a85d3
5 changed files with 105 additions and 26 deletions

View file

@ -19,9 +19,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/ *********************************************************************/
#include "eglonxbackend.h" #include "eglonxbackend.h"
// kwin // kwin
#include "main.h"
#include "options.h" #include "options.h"
#include "overlaywindow.h" #include "overlaywindow.h"
#include "screens.h"
#include "xcbutils.h" #include "xcbutils.h"
#if HAVE_X11_XCB
#include "x11windowed_backend.h"
#endif
// kwin libs // kwin libs
#include <kwinglplatform.h> #include <kwinglplatform.h>
// Qt // Qt
@ -33,23 +38,47 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
namespace KWin namespace KWin
{ {
extern int screen_number; // main.cpp
EglOnXBackend::EglOnXBackend() EglOnXBackend::EglOnXBackend()
: OpenGLBackend() : OpenGLBackend()
, m_overlayWindow(new OverlayWindow()) , m_overlayWindow(new OverlayWindow())
, ctx(EGL_NO_CONTEXT) , ctx(EGL_NO_CONTEXT)
, surfaceHasSubPost(0) , surfaceHasSubPost(0)
, m_bufferAge(0) , m_bufferAge(0)
, m_usesOverlayWindow(true)
, m_connection(connection())
, m_x11Display(display())
, m_rootWindow(rootWindow())
, m_x11ScreenNumber(kwinApp()->x11ScreenNumber())
{ {
init(); init();
// Egl is always direct rendering // Egl is always direct rendering
setIsDirectRendering(true); setIsDirectRendering(true);
} }
#if HAVE_X11_XCB
EglOnXBackend::EglOnXBackend(X11WindowedBackend *backend)
: OpenGLBackend()
, m_overlayWindow(nullptr)
, ctx(EGL_NO_CONTEXT)
, surfaceHasSubPost(0)
, m_bufferAge(0)
, m_usesOverlayWindow(false)
, m_x11Backend(backend)
, m_connection(backend->connection())
, m_x11Display(backend->display())
, m_rootWindow(backend->rootWindow())
, m_x11ScreenNumber(backend->screenNumer())
{
init();
// Egl is always direct rendering
setIsDirectRendering(true);
}
#endif
EglOnXBackend::~EglOnXBackend() EglOnXBackend::~EglOnXBackend()
{ {
if (isFailed()) { if (isFailed() && m_overlayWindow) {
m_overlayWindow->destroy(); m_overlayWindow->destroy();
} }
cleanupGL(); cleanupGL();
@ -58,10 +87,12 @@ EglOnXBackend::~EglOnXBackend()
eglDestroySurface(dpy, surface); eglDestroySurface(dpy, surface);
eglTerminate(dpy); eglTerminate(dpy);
eglReleaseThread(); eglReleaseThread();
if (overlayWindow()->window()) { if (m_overlayWindow) {
overlayWindow()->destroy(); if (overlayWindow()->window()) {
overlayWindow()->destroy();
}
delete m_overlayWindow;
} }
delete m_overlayWindow;
} }
static bool gs_tripleBufferUndetected = true; static bool gs_tripleBufferUndetected = true;
@ -178,13 +209,13 @@ bool EglOnXBackend::initRenderingContext()
return false; return false;
const int attribs[] = { const int attribs[] = {
EGL_PLATFORM_X11_SCREEN_EXT, screen_number, EGL_PLATFORM_X11_SCREEN_EXT, m_x11ScreenNumber,
EGL_NONE EGL_NONE
}; };
dpy = eglGetPlatformDisplayEXT(EGL_PLATFORM_X11_EXT, display(), attribs); dpy = eglGetPlatformDisplayEXT(EGL_PLATFORM_X11_EXT, m_x11Display, attribs);
} else { } else {
dpy = eglGetDisplay(display()); dpy = eglGetDisplay(m_x11Display);
} }
if (dpy == EGL_NO_DISPLAY) if (dpy == EGL_NO_DISPLAY)
@ -205,11 +236,26 @@ bool EglOnXBackend::initRenderingContext()
initBufferConfigs(); initBufferConfigs();
if (!overlayWindow()->create()) { if (m_usesOverlayWindow) {
qCCritical(KWIN_CORE) << "Could not get overlay window"; if (!overlayWindow()->create()) {
qCCritical(KWIN_CORE) << "Could not get overlay window";
return false;
} else {
overlayWindow()->setup(None);
}
}
xcb_window_t window = XCB_WINDOW_NONE;
if (m_overlayWindow) {
window = m_overlayWindow->window();
}
#if HAVE_X11_XCB
else if (m_x11Backend) {
window = m_x11Backend->window();
}
#endif
if (window == XCB_WINDOW_NONE) {
return false; return false;
} else {
overlayWindow()->setup(None);
} }
if (havePlatformBase) { if (havePlatformBase) {
@ -217,10 +263,9 @@ bool EglOnXBackend::initRenderingContext()
// always 32 bits. eglCreatePlatformWindowSurfaceEXT() expects the // always 32 bits. eglCreatePlatformWindowSurfaceEXT() expects the
// native_window parameter to be pointer to a Window, so this variable // native_window parameter to be pointer to a Window, so this variable
// cannot be an xcb_window_t. // cannot be an xcb_window_t.
const Window window = overlayWindow()->window();
surface = eglCreatePlatformWindowSurfaceEXT(dpy, config, (void *) &window, nullptr); surface = eglCreatePlatformWindowSurfaceEXT(dpy, config, (void *) &window, nullptr);
} else { } else {
surface = eglCreateWindowSurface(dpy, config, overlayWindow()->window(), nullptr); surface = eglCreateWindowSurface(dpy, config, window, nullptr);
} }
#ifdef KWIN_HAVE_OPENGLES #ifdef KWIN_HAVE_OPENGLES
@ -297,7 +342,9 @@ bool EglOnXBackend::initBufferConfigs()
return false; return false;
} }
Xcb::WindowAttributes attribs(rootWindow()); ScopedCPointer<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) { if (!attribs) {
qCCritical(KWIN_CORE) << "Failed to get window attributes of root window"; qCCritical(KWIN_CORE) << "Failed to get window attributes of root window";
return false; return false;
@ -322,7 +369,8 @@ void EglOnXBackend::present()
if (lastDamage().isEmpty()) if (lastDamage().isEmpty())
return; return;
const QRegion displayRegion(0, 0, displayWidth(), displayHeight()); const QSize screenSize = screens()->size();
const QRegion displayRegion(0, 0, screenSize.width(), screenSize.height());
const bool fullRepaint = supportsBufferAge() || (lastDamage() == displayRegion); const bool fullRepaint = supportsBufferAge() || (lastDamage() == displayRegion);
if (fullRepaint || !surfaceHasSubPost) { if (fullRepaint || !surfaceHasSubPost) {
@ -357,14 +405,14 @@ void EglOnXBackend::present()
} else { } else {
// a part of the screen changed, and we can use eglPostSubBufferNV to copy the updated area // a part of the screen changed, and we can use eglPostSubBufferNV to copy the updated area
foreach (const QRect & r, lastDamage().rects()) { foreach (const QRect & r, lastDamage().rects()) {
eglPostSubBufferNV(dpy, surface, r.left(), displayHeight() - r.bottom() - 1, r.width(), r.height()); eglPostSubBufferNV(dpy, surface, r.left(), screenSize.height() - r.bottom() - 1, r.width(), r.height());
} }
} }
setLastDamage(QRegion()); setLastDamage(QRegion());
if (!supportsBufferAge()) { if (!supportsBufferAge()) {
eglWaitGL(); eglWaitGL();
xcb_flush(connection()); xcb_flush(m_connection);
} }
} }
@ -438,7 +486,7 @@ void EglOnXBackend::endRenderingFrame(const QRegion &renderedRegion, const QRegi
glFlush(); glFlush();
} }
if (overlayWindow()->window()) // show the window only after the first pass, if (m_overlayWindow && overlayWindow()->window()) // show the window only after the first pass,
overlayWindow()->show(); // since that pass may take long overlayWindow()->show(); // since that pass may take long
// Save the damaged region to history // Save the damaged region to history
@ -463,7 +511,7 @@ void EglOnXBackend::doneCurrent()
bool EglOnXBackend::usesOverlayWindow() const bool EglOnXBackend::usesOverlayWindow() const
{ {
return true; return m_usesOverlayWindow;
} }
OverlayWindow* EglOnXBackend::overlayWindow() OverlayWindow* EglOnXBackend::overlayWindow()

View file

@ -24,6 +24,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
namespace KWin namespace KWin
{ {
class X11WindowedBackend;
/** /**
* @brief OpenGL Backend using Egl windowing system over an X overlay window. * @brief OpenGL Backend using Egl windowing system over an X overlay window.
**/ **/
@ -31,6 +33,9 @@ class EglOnXBackend : public OpenGLBackend
{ {
public: public:
EglOnXBackend(); EglOnXBackend();
#if HAVE_X11_XCB
explicit EglOnXBackend(X11WindowedBackend *backend);
#endif
virtual ~EglOnXBackend(); virtual ~EglOnXBackend();
virtual void screenGeometryChanged(const QSize &size); virtual void screenGeometryChanged(const QSize &size);
virtual SceneOpenGL::TexturePrivate *createBackendTexture(SceneOpenGL::Texture *texture); virtual SceneOpenGL::TexturePrivate *createBackendTexture(SceneOpenGL::Texture *texture);
@ -58,6 +63,14 @@ private:
EGLContext ctx; EGLContext ctx;
int surfaceHasSubPost; int surfaceHasSubPost;
int m_bufferAge; int m_bufferAge;
bool m_usesOverlayWindow;
#if HAVE_X11_XCB
X11WindowedBackend *m_x11Backend = nullptr;
#endif
xcb_connection_t *m_connection;
Display *m_x11Display;
xcb_window_t m_rootWindow;
int m_x11ScreenNumber;
friend class EglTexture; friend class EglTexture;
}; };

View file

@ -32,6 +32,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// for Wayland // for Wayland
#if HAVE_WAYLAND_EGL #if HAVE_WAYLAND_EGL
#include "egl_wayland_backend.h" #include "egl_wayland_backend.h"
#include "wayland_backend.h"
#endif
#if HAVE_X11_XCB
#include "x11windowed_backend.h"
#endif #endif
#endif #endif
#ifndef KWIN_HAVE_OPENGLES #ifndef KWIN_HAVE_OPENGLES
@ -483,15 +487,20 @@ SceneOpenGL *SceneOpenGL::createScene(QObject *parent)
break; break;
case EglPlatformInterface: case EglPlatformInterface:
#ifdef KWIN_HAVE_EGL #ifdef KWIN_HAVE_EGL
#if HAVE_WAYLAND_EGL
if (kwinApp()->shouldUseWaylandForCompositing()) { if (kwinApp()->shouldUseWaylandForCompositing()) {
backend = new EglWaylandBackend(); #if HAVE_WAYLAND_EGL
if (Wayland::WaylandBackend::self()) {
backend = new EglWaylandBackend();
}
#endif
#if HAVE_X11_XCB
if (!backend && X11WindowedBackend::self()) {
backend = new EglOnXBackend(X11WindowedBackend::self());
}
#endif
} else { } else {
backend = new EglOnXBackend(); backend = new EglOnXBackend();
} }
#else
backend = new EglOnXBackend();
#endif
#endif #endif
break; break;
default: default:

View file

@ -294,4 +294,12 @@ void X11WindowedBackend::installCursorFromServer()
// TODO: unset cursor // TODO: unset cursor
} }
xcb_window_t X11WindowedBackend::rootWindow() const
{
if (!m_screen) {
return XCB_WINDOW_NONE;
}
return m_screen->root;
}
} }

View file

@ -52,6 +52,7 @@ public:
Display *display() const { Display *display() const {
return m_display; return m_display;
} }
xcb_window_t rootWindow() const;
bool isValid() const { bool isValid() const {
return m_connection != nullptr && m_window != XCB_WINDOW_NONE; return m_connection != nullptr && m_window != XCB_WINDOW_NONE;