diff --git a/composite.cpp b/composite.cpp
index 717c34b699..b78541e37b 100644
--- a/composite.cpp
+++ b/composite.cpp
@@ -207,7 +207,7 @@ void Compositor::slotCompositingOptionsInitialized()
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
case XRenderCompositing:
qDebug() << "Initializing XRender compositing";
- m_scene = new SceneXrender(Workspace::self());
+ m_scene = SceneXrender::createScene();
break;
#endif
default:
diff --git a/scene_xrender.cpp b/scene_xrender.cpp
index e4e7edabdf..7436659773 100644
--- a/scene_xrender.cpp
+++ b/scene_xrender.cpp
@@ -30,6 +30,7 @@ along with this program. If not, see .
#include "effects.h"
#include "overlaywindow.h"
#include "paintredirector.h"
+#include "workspace.h"
#include "xcbutils.h"
#include "kwinxrenderutils.h"
@@ -42,11 +43,6 @@ along with this program. If not, see .
namespace KWin
{
-//****************************************
-// SceneXrender
-//****************************************
-
-xcb_render_picture_t SceneXrender::buffer = XCB_RENDER_PICTURE_NONE;
ScreenPaintData SceneXrender::screen_paint;
#define DOUBLE_TO_FIXED(d) ((xcb_render_fixed_t) ((d) * 65536))
@@ -89,92 +85,187 @@ static xcb_render_pictformat_t findFormatForVisual(xcb_visualid_t visual)
return s_cache.value(visual, 0);
}
-SceneXrender::SceneXrender(Workspace* ws)
- : Scene(ws)
- , format(0)
- , front(XCB_RENDER_PICTURE_NONE)
- , m_overlayWindow(new OverlayWindow())
- , init_ok(false)
+//****************************************
+// XRenderBackend
+//****************************************
+XRenderBackend::XRenderBackend()
+ : m_buffer(XCB_RENDER_PICTURE_NONE)
+ , m_failed(false)
{
if (!Xcb::Extensions::self()->isRenderAvailable()) {
- qCritical() << "No XRender extension available";
+ setFailed("No XRender extension available");
return;
}
if (!Xcb::Extensions::self()->isFixesRegionAvailable()) {
- qCritical() << "No XFixes v3+ extension available";
+ setFailed("No XFixes v3+ extension available");
return;
}
- initXRender(true);
}
-SceneXrender::~SceneXrender()
+XRenderBackend::~XRenderBackend()
{
- if (!init_ok) {
- // TODO this probably needs to clean up whatever has been created until the failure
- m_overlayWindow->destroy();
- return;
+ if (m_buffer) {
+ xcb_render_free_picture(connection(), m_buffer);
+ }
+}
+
+OverlayWindow* XRenderBackend::overlayWindow()
+{
+ return NULL;
+}
+
+void XRenderBackend::showOverlay()
+{
+}
+
+void XRenderBackend::setBuffer(xcb_render_picture_t buffer)
+{
+ if (m_buffer != XCB_RENDER_PICTURE_NONE) {
+ xcb_render_free_picture(connection(), m_buffer);
+ }
+ m_buffer = buffer;
+}
+
+void XRenderBackend::setFailed(const QString& reason)
+{
+ qCritical() << "Creating the XRender backend failed: " << reason;
+ m_failed = true;
+}
+
+void XRenderBackend::screenGeometryChanged(const QSize &size)
+{
+ Q_UNUSED(size)
+}
+
+//****************************************
+// X11XRenderBackend
+//****************************************
+X11XRenderBackend::X11XRenderBackend()
+ : XRenderBackend()
+ , m_overlayWindow(new OverlayWindow())
+ , m_front(XCB_RENDER_PICTURE_NONE)
+ , m_format(0)
+{
+ init(true);
+}
+
+X11XRenderBackend::~X11XRenderBackend()
+{
+ if (m_front) {
+ xcb_render_free_picture(connection(), m_front);
}
- SceneXrender::Window::cleanup();
- SceneXrender::EffectFrame::cleanup();
- xcb_render_free_picture(connection(), front);
- xcb_render_free_picture(connection(), buffer);
- buffer = XCB_RENDER_PICTURE_NONE;
m_overlayWindow->destroy();
- delete m_overlayWindow;
}
-void SceneXrender::initXRender(bool createOverlay)
+OverlayWindow* X11XRenderBackend::overlayWindow()
{
- init_ok = false;
- if (front != XCB_RENDER_PICTURE_NONE)
- xcb_render_free_picture(connection(), front);
+ return m_overlayWindow.data();
+}
+
+void X11XRenderBackend::showOverlay()
+{
+ if (m_overlayWindow->window()) // show the window only after the first pass, since
+ m_overlayWindow->show(); // that pass may take long
+}
+
+void X11XRenderBackend::init(bool createOverlay)
+{
+ if (m_front != XCB_RENDER_PICTURE_NONE)
+ xcb_render_free_picture(connection(), m_front);
bool haveOverlay = createOverlay ? m_overlayWindow->create() : (m_overlayWindow->window() != XCB_WINDOW_NONE);
if (haveOverlay) {
m_overlayWindow->setup(XCB_WINDOW_NONE);
ScopedCPointer attribs(xcb_get_window_attributes_reply(connection(),
xcb_get_window_attributes_unchecked(connection(), m_overlayWindow->window()), NULL));
if (!attribs) {
- qCritical() << "Failed getting window attributes for overlay window";
+ setFailed("Failed getting window attributes for overlay window");
return;
}
- format = findFormatForVisual(attribs->visual);
- if (format == 0) {
- qCritical() << "Failed to find XRender format for overlay window";
+ m_format = findFormatForVisual(attribs->visual);
+ if (m_format == 0) {
+ setFailed("Failed to find XRender format for overlay window");
return;
}
- front = xcb_generate_id(connection());
- xcb_render_create_picture(connection(), front, m_overlayWindow->window(), format, 0, NULL);
+ m_front = xcb_generate_id(connection());
+ xcb_render_create_picture(connection(), m_front, m_overlayWindow->window(), m_format, 0, NULL);
} else {
// create XRender picture for the root window
- format = findFormatForVisual(defaultScreen()->root_visual);
- if (format == 0) {
- qCritical() << "Failed to find XRender format for root window";
+ m_format = findFormatForVisual(defaultScreen()->root_visual);
+ if (m_format == 0) {
+ setFailed("Failed to find XRender format for root window");
return; // error
}
- front = xcb_generate_id(connection());
+ m_front = xcb_generate_id(connection());
const uint32_t values[] = {XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS};
- xcb_render_create_picture(connection(), front, rootWindow(), format, XCB_RENDER_CP_SUBWINDOW_MODE, values);
+ xcb_render_create_picture(connection(), m_front, rootWindow(), m_format, XCB_RENDER_CP_SUBWINDOW_MODE, values);
}
createBuffer();
- init_ok = true;
+}
+
+void X11XRenderBackend::createBuffer()
+{
+ xcb_pixmap_t pixmap = xcb_generate_id(connection());
+ xcb_create_pixmap(connection(), Xcb::defaultDepth(), pixmap, rootWindow(), displayWidth(), displayHeight());
+ xcb_render_picture_t b = xcb_generate_id(connection());
+ xcb_render_create_picture(connection(), b, pixmap, m_format, 0, NULL);
+ xcb_free_pixmap(connection(), pixmap); // The picture owns the pixmap now
+ setBuffer(b);
+}
+
+void X11XRenderBackend::present(int mask, const QRegion &damage)
+{
+ if (mask & Scene::PAINT_SCREEN_REGION) {
+ // Use the damage region as the clip region for the root window
+ XFixesRegion frontRegion(damage);
+ xcb_xfixes_set_picture_clip_region(connection(), m_front, frontRegion, 0, 0);
+ // copy composed buffer to the root window
+ xcb_xfixes_set_picture_clip_region(connection(), buffer(), XCB_XFIXES_REGION_NONE, 0, 0);
+ xcb_render_composite(connection(), XCB_RENDER_PICT_OP_SRC, buffer(), XCB_RENDER_PICTURE_NONE,
+ m_front, 0, 0, 0, 0, 0, 0, displayWidth(), displayHeight());
+ xcb_xfixes_set_picture_clip_region(connection(), m_front, XCB_XFIXES_REGION_NONE, 0, 0);
+ xcb_flush(connection());
+ } else {
+ // copy composed buffer to the root window
+ xcb_render_composite(connection(), XCB_RENDER_PICT_OP_SRC, buffer(), XCB_RENDER_PICTURE_NONE,
+ m_front, 0, 0, 0, 0, 0, 0, displayWidth(), displayHeight());
+ xcb_flush(connection());
+ }
+}
+
+void X11XRenderBackend::screenGeometryChanged(const QSize &size)
+{
+ Q_UNUSED(size)
+ init(false);
+}
+
+//****************************************
+// SceneXrender
+//****************************************
+SceneXrender* SceneXrender::createScene()
+{
+ QScopedPointer backend;
+ backend.reset(new X11XRenderBackend);
+ if (backend->isFailed()) {
+ return NULL;
+ }
+ return new SceneXrender(backend.take());
+}
+
+SceneXrender::SceneXrender(XRenderBackend *backend)
+ : Scene(Workspace::self())
+ , m_backend(backend)
+{
+}
+
+SceneXrender::~SceneXrender()
+{
+ SceneXrender::Window::cleanup();
+ SceneXrender::EffectFrame::cleanup();
}
bool SceneXrender::initFailed() const
{
- return !init_ok;
-}
-
-// Create the compositing buffer. The root window is not double-buffered,
-// so it is done manually using this buffer,
-void SceneXrender::createBuffer()
-{
- if (buffer != XCB_RENDER_PICTURE_NONE)
- xcb_render_free_picture(connection(), buffer);
- xcb_pixmap_t pixmap = xcb_generate_id(connection());
- xcb_create_pixmap(connection(), Xcb::defaultDepth(), pixmap, rootWindow(), displayWidth(), displayHeight());
- buffer = xcb_generate_id(connection());
- xcb_render_create_picture(connection(), buffer, pixmap, format, 0, NULL);
- xcb_free_pixmap(connection(), pixmap); // The picture owns the pixmap now
+ return false;
}
// the entry point for painting
@@ -189,36 +280,15 @@ qint64 SceneXrender::paint(QRegion damage, ToplevelList toplevels)
QRegion updateRegion, validRegion;
paintScreen(&mask, damage, QRegion(), &updateRegion, &validRegion);
- if (m_overlayWindow->window()) // show the window only after the first pass, since
- m_overlayWindow->show(); // that pass may take long
+ m_backend->showOverlay();
- present(mask, updateRegion);
+ m_backend->present(mask, updateRegion);
// do cleanup
clearStackingOrder();
return renderTimer.nsecsElapsed();
}
-void SceneXrender::present(int mask, QRegion damage)
-{
- if (mask & PAINT_SCREEN_REGION) {
- // Use the damage region as the clip region for the root window
- XFixesRegion frontRegion(damage);
- xcb_xfixes_set_picture_clip_region(connection(), front, frontRegion, 0, 0);
- // copy composed buffer to the root window
- xcb_xfixes_set_picture_clip_region(connection(), buffer, XCB_XFIXES_REGION_NONE, 0, 0);
- xcb_render_composite(connection(), XCB_RENDER_PICT_OP_SRC, buffer, XCB_RENDER_PICTURE_NONE,
- front, 0, 0, 0, 0, 0, 0, displayWidth(), displayHeight());
- xcb_xfixes_set_picture_clip_region(connection(), front, XCB_XFIXES_REGION_NONE, 0, 0);
- xcb_flush(connection());
- } else {
- // copy composed buffer to the root window
- xcb_render_composite(connection(), XCB_RENDER_PICT_OP_SRC, buffer, XCB_RENDER_PICTURE_NONE,
- front, 0, 0, 0, 0, 0, 0, displayWidth(), displayHeight());
- xcb_flush(connection());
- }
-}
-
void SceneXrender::paintGenericScreen(int mask, ScreenPaintData data)
{
screen_paint = data; // save, transformations will be done when painting windows
@@ -237,12 +307,12 @@ void SceneXrender::paintBackground(QRegion region)
{
xcb_render_color_t col = { 0, 0, 0, 0xffff }; // black
const QVector &rects = Xcb::regionToRects(region);
- xcb_render_fill_rectangles(connection(), XCB_RENDER_PICT_OP_SRC, buffer, col, rects.count(), rects.data());
+ xcb_render_fill_rectangles(connection(), XCB_RENDER_PICT_OP_SRC, bufferPicture(), col, rects.count(), rects.data());
}
Scene::Window *SceneXrender::createWindow(Toplevel *toplevel)
{
- return new Window(toplevel);
+ return new Window(toplevel, this);
}
Scene::EffectFrame *SceneXrender::createEffectFrame(EffectFrameImpl *frame)
@@ -262,8 +332,9 @@ Shadow *SceneXrender::createShadow(Toplevel *toplevel)
XRenderPicture *SceneXrender::Window::s_tempPicture = 0;
QRect SceneXrender::Window::temp_visibleRect;
-SceneXrender::Window::Window(Toplevel* c)
+SceneXrender::Window::Window(Toplevel* c, SceneXrender *scene)
: Scene::Window(c)
+ , m_scene(scene)
, format(findFormatForVisual(c->visual()->visualid))
, alpha_cached_opacity(0.0)
{
@@ -464,7 +535,7 @@ void SceneXrender::Window::performPaint(int mask, QRegion region, WindowPaintDat
const bool blitInTempPixmap = xRenderOffscreen() || (data.crossFadeProgress() < 1.0 && !opaque) ||
(scaled && (wantShadow || (client && !client->noBorder()) || (deleted && !deleted->noBorder())));
- xcb_render_picture_t renderTarget = buffer;
+ xcb_render_picture_t renderTarget = m_scene->bufferPicture();
if (blitInTempPixmap) {
if (scene_xRenderOffscreenTarget()) {
temp_visibleRect = toplevel->visibleRect().translated(-toplevel->pos());
@@ -675,7 +746,7 @@ xcb_render_composite(connection(), XCB_RENDER_PICT_OP_OVER, _PART_, decorationAl
xcb_render_set_picture_transform(connection(), *s_tempPicture, xform);
setPictureFilter(*s_tempPicture, filter);
xcb_render_composite(connection(), XCB_RENDER_PICT_OP_OVER, *s_tempPicture,
- XCB_RENDER_PICTURE_NONE, buffer,
+ XCB_RENDER_PICTURE_NONE, m_scene->bufferPicture(),
0, 0, 0, 0, r.x(), r.y(), r.width(), r.height());
xcb_render_set_picture_transform(connection(), *s_tempPicture, identity);
}
@@ -715,7 +786,7 @@ WindowPixmap* SceneXrender::Window::createWindowPixmap()
void SceneXrender::screenGeometryChanged(const QSize &size)
{
Scene::screenGeometryChanged(size);
- initXRender(false);
+ m_backend->screenGeometryChanged(size);
}
//****************************************
diff --git a/scene_xrender.h b/scene_xrender.h
index 4c4552f3be..45442f8fa4 100644
--- a/scene_xrender.h
+++ b/scene_xrender.h
@@ -29,6 +29,113 @@ along with this program. If not, see .
namespace KWin
{
+/**
+ * @brief Backend for the SceneXRender to hold the compositing buffer and take care of buffer
+ * swapping.
+ *
+ * This class is intended as a small abstraction to support multiple compositing backends in the
+ * SceneXRender.
+ *
+ */
+class XRenderBackend
+{
+public:
+ virtual ~XRenderBackend();
+ virtual void present(int mask, const QRegion &damage) = 0;
+
+ /**
+ * @brief Returns the OverlayWindow used by the backend.
+ *
+ * A backend does not have to use an OverlayWindow, this is mostly for the X world.
+ * In case the backend does not use an OverlayWindow it is allowed to return @c null.
+ * It's the task of the caller to check whether it is @c null.
+ *
+ * @return :OverlayWindow*
+ **/
+ virtual OverlayWindow *overlayWindow();
+ /**
+ * @brief Shows the Overlay Window
+ *
+ * Default implementation does nothing.
+ */
+ virtual void showOverlay();
+ /**
+ * @brief React on screen geometry changes.
+ *
+ * Default implementation does nothing. Override if specific functionality is required.
+ *
+ * @param size The new screen size
+ */
+ virtual void screenGeometryChanged(const QSize &size);
+ /**
+ * @brief The compositing buffer hold by this backend.
+ *
+ * The Scene composites the new frame into this buffer.
+ *
+ * @return xcb_render_picture_t
+ */
+ xcb_render_picture_t buffer() const {
+ return m_buffer;
+ }
+ /**
+ * @brief Whether the creation of the Backend failed.
+ *
+ * The SceneXRender should test whether the Backend got constructed correctly. If this method
+ * returns @c true, the SceneXRender should not try to start the rendering.
+ *
+ * @return bool @c true if the creation of the Backend failed, @c false otherwise.
+ **/
+ bool isFailed() const {
+ return m_failed;
+ }
+
+protected:
+ XRenderBackend();
+ /**
+ * @brief A subclass needs to call this method once it created the compositing back buffer.
+ *
+ * @param buffer The buffer to use for compositing
+ * @return void
+ */
+ void setBuffer(xcb_render_picture_t buffer);
+ /**
+ * @brief Sets the backend initialization to failed.
+ *
+ * This method should be called by the concrete subclass in case the initialization failed.
+ * The given @p reason is logged as a warning.
+ *
+ * @param reason The reason why the initialization failed.
+ **/
+ void setFailed(const QString &reason);
+
+private:
+ // Create the compositing buffer. The root window is not double-buffered,
+ // so it is done manually using this buffer,
+ xcb_render_picture_t m_buffer;
+ bool m_failed;
+};
+
+/**
+ * @brief XRenderBackend using an X11 Overlay Window as compositing target.
+ *
+ */
+class X11XRenderBackend : public XRenderBackend
+{
+public:
+ X11XRenderBackend();
+ ~X11XRenderBackend();
+
+ virtual void present(int mask, const QRegion &damage);
+ virtual OverlayWindow* overlayWindow();
+ virtual void showOverlay();
+ virtual void screenGeometryChanged(const QSize &size);
+private:
+ void init(bool createOverlay);
+ void createBuffer();
+ QScopedPointer m_overlayWindow;
+ xcb_render_picture_t m_front;
+ xcb_render_pictformat_t m_format;
+};
class SceneXrender
: public Scene
@@ -36,7 +143,6 @@ class SceneXrender
Q_OBJECT
public:
class EffectFrame;
- explicit SceneXrender(Workspace* ws);
virtual ~SceneXrender();
virtual bool initFailed() const;
virtual CompositingType compositingType() const {
@@ -48,31 +154,27 @@ public:
virtual void screenGeometryChanged(const QSize &size);
xcb_render_picture_t bufferPicture();
virtual OverlayWindow *overlayWindow() {
- return m_overlayWindow;
+ return m_backend->overlayWindow();
}
+
+ static SceneXrender *createScene();
protected:
virtual Scene::Window *createWindow(Toplevel *toplevel);
virtual void paintBackground(QRegion region);
virtual void paintGenericScreen(int mask, ScreenPaintData data);
virtual void paintDesktop(int desktop, int mask, const QRegion ®ion, ScreenPaintData &data);
private:
- void createBuffer();
- void present(int mask, QRegion damage);
- void initXRender(bool createOverlay);
- xcb_render_pictformat_t format;
- xcb_render_picture_t front;
- static xcb_render_picture_t buffer;
+ explicit SceneXrender(XRenderBackend *backend);
static ScreenPaintData screen_paint;
class Window;
- OverlayWindow* m_overlayWindow;
- bool init_ok;
+ QScopedPointer m_backend;
};
class SceneXrender::Window
: public Scene::Window
{
public:
- Window(Toplevel* c);
+ Window(Toplevel* c, SceneXrender *scene);
virtual ~Window();
virtual void performPaint(int mask, QRegion region, WindowPaintData data);
QRegion transformedShape() const;
@@ -85,6 +187,7 @@ private:
QPoint mapToScreen(int mask, const WindowPaintData &data, const QPoint &point) const;
void prepareTempPixmap();
void setPictureFilter(xcb_render_picture_t pic, ImageFilterType filter);
+ SceneXrender *m_scene;
xcb_render_pictformat_t format;
double alpha_cached_opacity;
QRegion transformed_shape;
@@ -135,7 +238,7 @@ private:
inline
xcb_render_picture_t SceneXrender::bufferPicture()
{
- return buffer;
+ return m_backend->buffer();
}
inline