Commit d99e6b5d authored by Vlad Zahorodnii's avatar Vlad Zahorodnii

platforms/x11: Move XRenderBackend to platformsupport directory

This change moves the XRender backend to platformsupport directory,
similar to the OpenGL and the QPainter backend. This allows to put
platform-specific logic in XRenderBackend.
parent b41a1eba
......@@ -90,6 +90,11 @@ QPainterBackend *Platform::createQPainterBackend()
return nullptr;
}
XRenderBackend *Platform::createXRenderBackend()
{
return nullptr;
}
void Platform::prepareShutdown()
{
setOutputsEnabled(false);
......
......@@ -42,6 +42,7 @@ class Scene;
class Screens;
class ScreenEdges;
class Toplevel;
class XRenderBackend;
namespace Decoration
{
......@@ -70,6 +71,7 @@ public:
virtual Screens *createScreens(QObject *parent = nullptr);
virtual OpenGLBackend *createOpenGLBackend();
virtual QPainterBackend *createQPainterBackend();
virtual XRenderBackend *createXRenderBackend();
virtual DmaBufTexture *createDmaBufTexture(const QSize &size) {
Q_UNUSED(size);
return nullptr;
......
add_subdirectory(qpainter)
add_subdirectory(opengl)
add_subdirectory(xrender)
set(xrenderbackend_SOURCES xrenderbackend.cpp)
ecm_qt_declare_logging_category(xrenderbackend_SOURCES
HEADER logging.h
IDENTIFIER KWIN_XRENDER
CATEGORY_NAME kwin_scene_xrender
DEFAULT_SEVERITY Critical
)
add_library(SceneXRenderBackend STATIC ${xrenderbackend_SOURCES})
target_link_libraries(SceneXRenderBackend kwin Qt5::Core Qt5::Gui)
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2006 Lubos Lunak <l.lunak@kde.org>
SPDX-FileCopyrightText: 2009 Fredrik Höglund <fredrik@kde.org>
SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "xrenderbackend.h"
#include "logging.h"
#include "xcbutils.h"
namespace KWin
{
XRenderBackend::XRenderBackend()
: m_buffer(XCB_RENDER_PICTURE_NONE)
, m_failed(false)
{
if (!Xcb::Extensions::self()->isRenderAvailable()) {
setFailed("No XRender extension available");
return;
}
if (!Xcb::Extensions::self()->isFixesRegionAvailable()) {
setFailed("No XFixes v3+ extension available");
return;
}
}
XRenderBackend::~XRenderBackend()
{
if (m_buffer) {
xcb_render_free_picture(connection(), m_buffer);
}
}
OverlayWindow *XRenderBackend::overlayWindow()
{
return nullptr;
}
void XRenderBackend::showOverlay()
{
}
xcb_render_picture_t XRenderBackend::buffer() const
{
return m_buffer;
}
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;
}
bool XRenderBackend::isFailed() const
{
return m_failed;
}
void XRenderBackend::setFailed(const QString &reason)
{
qCCritical(KWIN_XRENDER) << "Creating the XRender backend failed: " << reason;
m_failed = true;
}
void XRenderBackend::screenGeometryChanged(const QSize &size)
{
Q_UNUSED(size)
}
} // namespace KWin
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2006 Lubos Lunak <l.lunak@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <QRegion>
#include <QSize>
#include <xcb/render.h>
namespace KWin
{
class OverlayWindow;
/**
* @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();
virtual bool usesOverlayWindow() const = 0;
/**
* @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;
/**
* @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;
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;
};
} // namespace KWin
......@@ -12,6 +12,7 @@ set(X11PLATFORM_SOURCES
x11_output.cpp
x11_platform.cpp
x11cursor.cpp
x11xrenderbackend.cpp
xfixes_cursor_event_filter.cpp
)
......@@ -24,10 +25,11 @@ if (HAVE_EPOXY_GLX)
endif()
include_directories(${CMAKE_SOURCE_DIR}/platformsupport/scenes/opengl)
include_directories(${CMAKE_SOURCE_DIR}/platformsupport/scenes/xrender)
add_library(KWinX11Platform MODULE ${X11PLATFORM_SOURCES})
set_target_properties(KWinX11Platform PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/org.kde.kwin.platforms/")
target_link_libraries(KWinX11Platform eglx11common kwin kwinxrenderutils SceneOpenGLBackend Qt5::X11Extras XCB::CURSOR KF5::Crash )
target_link_libraries(KWinX11Platform eglx11common kwin kwinxrenderutils SceneOpenGLBackend SceneXRenderBackend Qt5::X11Extras XCB::CURSOR KF5::Crash )
if (X11_Xinput_FOUND)
target_link_libraries(KWinX11Platform ${X11_Xinput_LIB})
endif()
......
......@@ -10,6 +10,7 @@
#include "x11cursor.h"
#include "edge.h"
#include "windowselector.h"
#include "x11xrenderbackend.h"
#include <config-kwin.h>
#include <kwinconfig.h>
#if HAVE_EPOXY_GLX
......@@ -119,6 +120,11 @@ OpenGLBackend *X11StandalonePlatform::createOpenGLBackend()
}
}
XRenderBackend *X11StandalonePlatform::createXRenderBackend()
{
return new X11XRenderBackend(this);
}
Edge *X11StandalonePlatform::createScreenEdge(ScreenEdges *edges)
{
if (m_screenEdgesFilter.isNull()) {
......
......@@ -35,6 +35,7 @@ public:
Screens *createScreens(QObject *parent = nullptr) override;
OpenGLBackend *createOpenGLBackend() override;
XRenderBackend *createXRenderBackend() override;
Edge *createScreenEdge(ScreenEdges *parent) override;
void createPlatformCursor(QObject *parent = nullptr) override;
bool requiresCompositing() const override;
......
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2006 Lubos Lunak <l.lunak@kde.org>
SPDX-FileCopyrightText: 2009 Fredrik Höglund <fredrik@kde.org>
SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "x11xrenderbackend.h"
#include "main.h"
#include "platform.h"
#include "overlaywindow.h"
#include "scene.h"
#include "screens.h"
#include "utils.h"
#include "x11_platform.h"
#include "kwinxrenderutils.h"
namespace KWin
{
X11XRenderBackend::X11XRenderBackend(X11StandalonePlatform *backend)
: XRenderBackend()
, m_backend(backend)
, m_overlayWindow(backend->createOverlayWindow())
, m_front(XCB_RENDER_PICTURE_NONE)
, m_format(0)
{
init(true);
}
X11XRenderBackend::~X11XRenderBackend()
{
if (m_front) {
xcb_render_free_picture(connection(), m_front);
}
m_overlayWindow->destroy();
}
OverlayWindow *X11XRenderBackend::overlayWindow()
{
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<xcb_get_window_attributes_reply_t> attribs(xcb_get_window_attributes_reply(connection(),
xcb_get_window_attributes_unchecked(connection(), m_overlayWindow->window()), nullptr));
if (!attribs) {
setFailed("Failed getting window attributes for overlay window");
return;
}
m_format = XRenderUtils::findPictFormat(attribs->visual);
if (m_format == 0) {
setFailed("Failed to find XRender format for overlay window");
return;
}
m_front = xcb_generate_id(connection());
xcb_render_create_picture(connection(), m_front, m_overlayWindow->window(), m_format, 0, nullptr);
} else {
// create XRender picture for the root window
m_format = XRenderUtils::findPictFormat(kwinApp()->x11DefaultScreen()->root_visual);
if (m_format == 0) {
setFailed("Failed to find XRender format for root window");
return; // error
}
m_front = xcb_generate_id(connection());
const uint32_t values[] = {XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS};
xcb_render_create_picture(connection(), m_front, rootWindow(), m_format, XCB_RENDER_CP_SUBWINDOW_MODE, values);
}
createBuffer();
}
void X11XRenderBackend::createBuffer()
{
xcb_pixmap_t pixmap = xcb_generate_id(connection());
const auto displaySize = screens()->displaySize();
xcb_create_pixmap(connection(), Xcb::defaultDepth(), pixmap, rootWindow(), displaySize.width(), displaySize.height());
xcb_render_picture_t b = xcb_generate_id(connection());
xcb_render_create_picture(connection(), b, pixmap, m_format, 0, nullptr);
xcb_free_pixmap(connection(), pixmap); // The picture owns the pixmap now
setBuffer(b);
}
void X11XRenderBackend::present(int mask, const QRegion &damage)
{
const auto displaySize = screens()->displaySize();
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, displaySize.width(), displaySize.height());
xcb_xfixes_set_picture_clip_region(connection(), m_front, XCB_XFIXES_REGION_NONE, 0, 0);
} 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, displaySize.width(), displaySize.height());
}
xcb_flush(connection());
}
void X11XRenderBackend::screenGeometryChanged(const QSize &size)
{
Q_UNUSED(size)
init(false);
}
bool X11XRenderBackend::usesOverlayWindow() const
{
return true;
}
} // namespace KWin
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2006 Lubos Lunak <l.lunak@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include "xrenderbackend.h"
namespace KWin
{
class X11StandalonePlatform;
/**
* @brief XRenderBackend using an X11 Overlay Window as compositing target.
*/
class X11XRenderBackend : public XRenderBackend
{
public:
explicit X11XRenderBackend(X11StandalonePlatform *backend);
~X11XRenderBackend() override;
void present(int mask, const QRegion &damage) override;
OverlayWindow *overlayWindow() override;
void showOverlay() override;
void screenGeometryChanged(const QSize &size) override;
bool usesOverlayWindow() const override;
private:
void init(bool createOverlay);
void createBuffer();
X11StandalonePlatform *m_backend;
QScopedPointer<OverlayWindow> m_overlayWindow;
xcb_render_picture_t m_front;
xcb_render_pictformat_t m_format;
};
} // namespace KWin
......@@ -12,12 +12,11 @@ ecm_qt_declare_logging_category(
Critical
)
include_directories(${CMAKE_SOURCE_DIR}/platformsupport/scenes/xrender)
add_library(KWinSceneXRender MODULE ${SCENE_XRENDER_SRCS})
set_target_properties(KWinSceneXRender PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/org.kde.kwin.scenes/")
target_link_libraries(KWinSceneXRender
kwin
kwinxrenderutils
)
target_link_libraries(KWinSceneXRender kwin kwinxrenderutils SceneXRenderBackend)
install(
TARGETS
......
......@@ -9,8 +9,8 @@
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "scene_xrender.h"
#include "utils.h"
#include "xrenderbackend.h"
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
......@@ -44,177 +44,14 @@ ScreenPaintData SceneXrender::screen_paint;
#define DOUBLE_TO_FIXED(d) ((xcb_render_fixed_t) ((d) * 65536))
#define FIXED_TO_DOUBLE(f) ((double) ((f) / 65536.0))
//****************************************
// XRenderBackend
//****************************************
XRenderBackend::XRenderBackend()
: m_buffer(XCB_RENDER_PICTURE_NONE)
, m_failed(false)
{
if (!Xcb::Extensions::self()->isRenderAvailable()) {
setFailed("No XRender extension available");
return;
}
if (!Xcb::Extensions::self()->isFixesRegionAvailable()) {
setFailed("No XFixes v3+ extension available");
return;
}
}
XRenderBackend::~XRenderBackend()
{
if (m_buffer) {
xcb_render_free_picture(connection(), m_buffer);
}
}
OverlayWindow* XRenderBackend::overlayWindow()
{
return nullptr;
}
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)
{
qCCritical(KWIN_XRENDER) << "Creating the XRender backend failed: " << reason;
m_failed = true;
}
void XRenderBackend::screenGeometryChanged(const QSize &size)
{
Q_UNUSED(size)
}
//****************************************
// X11XRenderBackend
//****************************************
X11XRenderBackend::X11XRenderBackend()
: XRenderBackend()
, m_overlayWindow(kwinApp()->platform()->createOverlayWindow())
, m_front(XCB_RENDER_PICTURE_NONE)
, m_format(0)
{
init(true);
}
X11XRenderBackend::~X11XRenderBackend()
{
if (m_front) {
xcb_render_free_picture(connection(), m_front);
}
m_overlayWindow->destroy();
}
OverlayWindow* X11XRenderBackend::overlayWindow()
{
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<xcb_get_window_attributes_reply_t> attribs(xcb_get_window_attributes_reply(connection(),
xcb_get_window_attributes_unchecked(connection(), m_overlayWindow->window()), nullptr));
if (!attribs) {
setFailed("Failed getting window attributes for overlay window");
return;
}
m_format = XRenderUtils::findPictFormat(attribs->visual);
if (m_format == 0) {
setFailed("Failed to find XRender format for overlay window");
return;
}
m_front = xcb_generate_id(connection());
xcb_render_create_picture(connection(), m_front, m_overlayWindow->window(), m_format, 0, nullptr);
} else {
// create XRender picture for the root window
m_format = XRenderUtils::findPictFormat(kwinApp()->x11DefaultScreen()->root_visual);
if (m_format == 0) {
setFailed("Failed to find XRender format for root window");
return; // error
}
m_front = xcb_generate_id(connection());
const uint32_t values[] = {XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS};
xcb_render_create_picture(connection(), m_front, rootWindow(), m_format, XCB_RENDER_CP_SUBWINDOW_MODE, values);
}
createBuffer();
}
void X11XRenderBackend::createBuffer()
{