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

View file

@ -24,6 +24,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
namespace KWin
{
class X11WindowedBackend;
/**
* @brief OpenGL Backend using Egl windowing system over an X overlay window.
**/
@ -31,6 +33,9 @@ class EglOnXBackend : public OpenGLBackend
{
public:
EglOnXBackend();
#if HAVE_X11_XCB
explicit EglOnXBackend(X11WindowedBackend *backend);
#endif
virtual ~EglOnXBackend();
virtual void screenGeometryChanged(const QSize &size);
virtual SceneOpenGL::TexturePrivate *createBackendTexture(SceneOpenGL::Texture *texture);
@ -58,6 +63,14 @@ private:
EGLContext ctx;
int surfaceHasSubPost;
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;
};

View file

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

View file

@ -294,4 +294,12 @@ void X11WindowedBackend::installCursorFromServer()
// 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 {
return m_display;
}
xcb_window_t rootWindow() const;
bool isValid() const {
return m_connection != nullptr && m_window != XCB_WINDOW_NONE;