Commit 8ae37c42 authored by Martin Flöser's avatar Martin Flöser

Move SceneOpenGL into a dedicated plugin

Summary:
Unfortunately a rather large change which required more refactoring than
initially expected. The main problem was that some parts needed to go
into platformsupport so that the platform plugins can link them. Due to
the rather monolithic nature of scene_opengl.h a few changes were
required:
* SceneOpenGL::Texture -> SceneOpenGLTexture
* SceneOpenGL::TexturePrivate -> SceneOpenGLTexturePrivate
* texture based code into dedicated files
* SwapProfiler code into dedicated files
* SwapProfiler only used in x11 variants
* Safety checks for OpenGL scene moved into the new plugin
* signal declared in SceneOpenGL moved to Scene, so that we don't need
to include SceneOpenGL in composite

Test Plan: Nested OpenGL compositor works

Reviewers: #kwin, #plasma

Subscribers: plasma-devel, kwin

Tags: #kwin

Differential Revision: https://phabricator.kde.org/D7740
parent 343d8c9b
......@@ -423,7 +423,6 @@ set(kwin_KDEINIT_SRCS
toplevel.cpp
unmanaged.cpp
scene.cpp
scene_opengl.cpp
screenlockerwatcher.cpp
thumbnailitem.cpp
lanczosfilter.cpp
......@@ -453,7 +452,6 @@ set(kwin_KDEINIT_SRCS
decorations/settings.cpp
decorations/decorationrenderer.cpp
decorations/decorations_logging.cpp
abstract_egl_backend.cpp
platform.cpp
shell_client.cpp
wayland_server.cpp
......
......@@ -29,7 +29,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "effects.h"
#include "overlaywindow.h"
#include "scene.h"
#include "scene_opengl.h"
#include "screens.h"
#include "shadow.h"
#include "useractions.h"
......@@ -39,6 +38,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "wayland_server.h"
#include "decorations/decoratedclient.h"
#include <kwingltexture.h>
#include <KWayland/Server/surface_interface.h>
#include <stdio.h>
......@@ -220,47 +221,6 @@ void Compositor::slotCompositingOptionsInitialized()
}
}
if (!m_scene) {
switch(options->compositingMode()) {
case OpenGLCompositing: {
qCDebug(KWIN_CORE) << "Initializing OpenGL compositing";
// Some broken drivers crash on glXQuery() so to prevent constant KWin crashes:
if (kwinApp()->platform()->openGLCompositingIsBroken())
qCWarning(KWIN_CORE) << "KWin has detected that your OpenGL library is unsafe to use";
else {
kwinApp()->platform()->createOpenGLSafePoint(Platform::OpenGLSafePoint::PreInit);
m_scene = SceneOpenGL::createScene(this);
kwinApp()->platform()->createOpenGLSafePoint(Platform::OpenGLSafePoint::PostInit);
if (m_scene && !m_scene->initFailed()) {
connect(static_cast<SceneOpenGL*>(m_scene), &SceneOpenGL::resetCompositing, this, &Compositor::restart);
break; // -->
}
delete m_scene;
m_scene = NULL;
}
// Do not Fall back to XRender - it causes problems when selfcheck fails during startup, but works later on
break;
}
default:
qCDebug(KWIN_CORE) << "No compositing enabled";
m_starting = false;
if (cm_selection) {
cm_selection->owning = false;
cm_selection->release();
}
if (kwinApp()->platform()->requiresCompositing()) {
qCCritical(KWIN_CORE) << "The used windowing system requires compositing";
qCCritical(KWIN_CORE) << "We are going to quit KWin now as it is broken";
qApp->quit();
}
return;
}
}
if (m_scene == NULL || m_scene->initFailed()) {
qCCritical(KWIN_CORE) << "Failed to initialize compositing, compositing disabled";
delete m_scene;
......@@ -277,6 +237,7 @@ void Compositor::slotCompositingOptionsInitialized()
}
return;
}
connect(m_scene, &Scene::resetCompositing, this, &Compositor::restart);
emit sceneCreated();
if (Workspace::self()) {
......
......@@ -18,3 +18,4 @@ kwin_xkbcommon KWin xkbcommon integration
kwin_qpa_plugin KWin QtPlatformAbstraction plugin
kwin_scene_xrender KWin XRender based compositor scene plugin
kwin_scene_qpainter KWin QPainter based compositor scene plugin
kwin_scene_opengl KWin OpenGL based compositor scene plugins
......@@ -29,6 +29,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QVector4D>
#include <kwinconfig.h>
#include <kwin_export.h>
namespace KWin
{
......@@ -40,7 +41,7 @@ class GLTexture;
class GLRenderTarget;
class GLShader;
class LanczosFilter
class KWIN_EXPORT LanczosFilter
: public QObject
{
Q_OBJECT
......
......@@ -29,6 +29,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QSize>
#include <QSharedData>
#include <QImage>
#include <QMatrix4x4>
#include <epoxy/gl.h>
namespace KWin
{
......
add_subdirectory(qpainter)
add_subdirectory(opengl)
set(SCENE_OPENGL_BACKEND_SRCS
abstract_egl_backend.cpp
backend.cpp
swap_profiler.cpp
texture.cpp
)
include_directories(${CMAKE_SOURCE_DIR})
include(ECMQtDeclareLoggingCategory)
ecm_qt_declare_logging_category(SCENE_OPENGL_BACKEND_SRCS
HEADER
logging.h
IDENTIFIER
KWIN_OPENGL
CATEGORY_NAME
kwin_scene_opengl
DEFAULT_SEVERITY
Critical
)
add_library(SceneOpenGLBackend STATIC ${SCENE_OPENGL_BACKEND_SRCS})
target_link_libraries(SceneOpenGLBackend Qt5::Core Qt5::Widgets KF5::CoreAddons KF5::ConfigCore KF5::WindowSystem)
......@@ -18,16 +18,20 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "abstract_egl_backend.h"
#include "texture.h"
#include "composite.h"
#include "egl_context_attribute_builder.h"
#include "options.h"
#include "platform.h"
#include "scene.h"
#include "wayland_server.h"
#include <KWayland/Server/buffer_interface.h>
#include <KWayland/Server/display.h>
#include <KWayland/Server/surface_interface.h>
// kwin libs
#include <logging.h>
#include <kwinglplatform.h>
#include <kwinglutils.h>
// Qt
#include <QOpenGLContext>
#include <QOpenGLFramebufferObject>
......@@ -93,25 +97,25 @@ bool AbstractEglBackend::initEglAPI()
{
EGLint major, minor;
if (eglInitialize(m_display, &major, &minor) == EGL_FALSE) {
qCWarning(KWIN_CORE) << "eglInitialize failed";
qCWarning(KWIN_OPENGL) << "eglInitialize failed";
EGLint error = eglGetError();
if (error != EGL_SUCCESS) {
qCWarning(KWIN_CORE) << "Error during eglInitialize " << error;
qCWarning(KWIN_OPENGL) << "Error during eglInitialize " << error;
}
return false;
}
EGLint error = eglGetError();
if (error != EGL_SUCCESS) {
qCWarning(KWIN_CORE) << "Error during eglInitialize " << error;
qCWarning(KWIN_OPENGL) << "Error during eglInitialize " << error;
return false;
}
qCDebug(KWIN_CORE) << "Egl Initialize succeeded";
qCDebug(KWIN_OPENGL) << "Egl Initialize succeeded";
if (eglBindAPI(isOpenGLES() ? EGL_OPENGL_ES_API : EGL_OPENGL_API) == EGL_FALSE) {
qCCritical(KWIN_CORE) << "bind OpenGL API failed";
qCCritical(KWIN_OPENGL) << "bind OpenGL API failed";
return false;
}
qCDebug(KWIN_CORE) << "EGL version: " << major << "." << minor;
qCDebug(KWIN_OPENGL) << "EGL version: " << major << "." << minor;
const QByteArray eglExtensions = eglQueryString(m_display, EGL_EXTENSIONS);
setExtensions(eglExtensions.split(' '));
return true;
......@@ -250,13 +254,13 @@ bool AbstractEglBackend::createContext()
const auto attribs = (*it)->build();
ctx = eglCreateContext(m_display, config(), EGL_NO_CONTEXT, attribs.data());
if (ctx != EGL_NO_CONTEXT) {
qCDebug(KWIN_CORE) << "Created EGL context with attributes:" << (*it).get();
qCDebug(KWIN_OPENGL) << "Created EGL context with attributes:" << (*it).get();
break;
}
}
if (ctx == EGL_NO_CONTEXT) {
qCCritical(KWIN_CORE) << "Create Context failed";
qCCritical(KWIN_OPENGL) << "Create Context failed";
return false;
}
m_context = ctx;
......@@ -281,8 +285,8 @@ void AbstractEglBackend::setSurface(const EGLSurface &surface)
kwinApp()->platform()->setSceneEglSurface(surface);
}
AbstractEglTexture::AbstractEglTexture(SceneOpenGL::Texture *texture, AbstractEglBackend *backend)
: SceneOpenGL::TexturePrivate()
AbstractEglTexture::AbstractEglTexture(SceneOpenGLTexture *texture, AbstractEglBackend *backend)
: SceneOpenGLTexturePrivate()
, q(texture)
, m_backend(backend)
, m_image(EGL_NO_IMAGE_KHR)
......@@ -453,7 +457,7 @@ bool AbstractEglTexture::loadEglTexture(const QPointer< KWayland::Server::Buffer
q->unbind();
if (EGL_NO_IMAGE_KHR == m_image) {
qCDebug(KWIN_CORE) << "failed to create egl image";
qCDebug(KWIN_OPENGL) << "failed to create egl image";
q->discard();
return false;
}
......@@ -466,7 +470,7 @@ EGLImageKHR AbstractEglTexture::attach(const QPointer< KWayland::Server::BufferI
EGLint format, yInverted;
eglQueryWaylandBufferWL(m_backend->eglDisplay(), buffer->resource(), EGL_TEXTURE_FORMAT, &format);
if (format != EGL_TEXTURE_RGB && format != EGL_TEXTURE_RGBA) {
qCDebug(KWIN_CORE) << "Unsupported texture format: " << format;
qCDebug(KWIN_OPENGL) << "Unsupported texture format: " << format;
return EGL_NO_IMAGE_KHR;
}
if (!eglQueryWaylandBufferWL(m_backend->eglDisplay(), buffer->resource(), EGL_WAYLAND_Y_INVERTED_WL, &yInverted)) {
......
......@@ -19,13 +19,23 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#ifndef KWIN_ABSTRACT_EGL_BACKEND_H
#define KWIN_ABSTRACT_EGL_BACKEND_H
#include "scene_opengl.h"
#include "backend.h"
#include "texture.h"
#include <QObject>
#include <epoxy/egl.h>
#include <fixx11h.h>
class QOpenGLFramebufferObject;
namespace KWayland
{
namespace Server
{
class BufferInterface;
}
}
namespace KWin
{
......@@ -77,7 +87,7 @@ private:
QList<QByteArray> m_clientExtensions;
};
class KWIN_EXPORT AbstractEglTexture : public SceneOpenGL::TexturePrivate
class KWIN_EXPORT AbstractEglTexture : public SceneOpenGLTexturePrivate
{
public:
virtual ~AbstractEglTexture();
......@@ -86,14 +96,14 @@ public:
OpenGLBackend *backend() override;
protected:
AbstractEglTexture(SceneOpenGL::Texture *texture, AbstractEglBackend *backend);
AbstractEglTexture(SceneOpenGLTexture *texture, AbstractEglBackend *backend);
EGLImageKHR image() const {
return m_image;
}
void setImage(const EGLImageKHR &img) {
m_image = img;
}
SceneOpenGL::Texture *texture() const {
SceneOpenGLTexture *texture() const {
return q;
}
......@@ -102,7 +112,7 @@ private:
bool loadEglTexture(const QPointer<KWayland::Server::BufferInterface> &buffer);
EGLImageKHR attach(const QPointer<KWayland::Server::BufferInterface> &buffer);
bool updateFromFBO(const QSharedPointer<QOpenGLFramebufferObject> &fbo);
SceneOpenGL::Texture *q;
SceneOpenGLTexture *q;
AbstractEglBackend *m_backend;
EGLImageKHR m_image;
};
......
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org>
Copyright (C) 2009, 2010, 2011 Martin Gräßlin <mgraesslin@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "backend.h"
#include <kwineffects.h>
#include <logging.h>
#include "screens.h"
#include <epoxy/gl.h>
namespace KWin
{
OpenGLBackend::OpenGLBackend()
: m_syncsToVBlank(false)
, m_blocksForRetrace(false)
, m_directRendering(false)
, m_haveBufferAge(false)
, m_failed(false)
{
}
OpenGLBackend::~OpenGLBackend()
{
}
void OpenGLBackend::setFailed(const QString &reason)
{
qCWarning(KWIN_OPENGL) << "Creating the OpenGL rendering failed: " << reason;
m_failed = true;
}
void OpenGLBackend::idle()
{
if (hasPendingFlush()) {
effects->makeOpenGLContextCurrent();
present();
}
}
void OpenGLBackend::addToDamageHistory(const QRegion &region)
{
if (m_damageHistory.count() > 10)
m_damageHistory.removeLast();
m_damageHistory.prepend(region);
}
QRegion OpenGLBackend::accumulatedDamageHistory(int bufferAge) const
{
QRegion region;
// Note: An age of zero means the buffer contents are undefined
if (bufferAge > 0 && bufferAge <= m_damageHistory.count()) {
for (int i = 0; i < bufferAge - 1; i++)
region |= m_damageHistory[i];
} else {
const QSize &s = screens()->size();
region = QRegion(0, 0, s.width(), s.height());
}
return region;
}
OverlayWindow* OpenGLBackend::overlayWindow()
{
return NULL;
}
QRegion OpenGLBackend::prepareRenderingForScreen(int screenId)
{
// fallback to repaint complete screen
return screens()->geometry(screenId);
}
void OpenGLBackend::endRenderingFrameForScreen(int screenId, const QRegion &damage, const QRegion &damagedRegion)
{
Q_UNUSED(screenId)
Q_UNUSED(damage)
Q_UNUSED(damagedRegion)
}
bool OpenGLBackend::perScreenRendering() const
{
return false;
}
void OpenGLBackend::copyPixels(const QRegion &region)
{
const int height = screens()->size().height();
foreach (const QRect &r, region.rects()) {
const int x0 = r.x();
const int y0 = height - r.y() - r.height();
const int x1 = r.x() + r.width();
const int y1 = height - r.y();
glBlitFramebuffer(x0, y0, x1, y1, x0, y0, x1, y1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
}
}
}
......@@ -18,350 +18,22 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#ifndef KWIN_SCENE_OPENGL_BACKEND_H
#define KWIN_SCENE_OPENGL_BACKEND_H
#ifndef KWIN_SCENE_OPENGL_H
#define KWIN_SCENE_OPENGL_H
#include <QElapsedTimer>
#include <QRegion>
#include "scene.h"
#include "shadow.h"
#include "kwinglutils.h"
#include "kwingltexture_p.h"
#include "decorations/decorationrenderer.h"
#include <kwin_export.h>
namespace KWin
{
class LanczosFilter;
class OpenGLBackend;
class SyncManager;
class SyncObject;
class KWIN_EXPORT SceneOpenGL
: public Scene
{
Q_OBJECT
public:
class EffectFrame;
class Texture;
class TexturePrivate;
class Window;
virtual ~SceneOpenGL();
virtual bool initFailed() const;
virtual bool hasPendingFlush() const;
virtual qint64 paint(QRegion damage, ToplevelList windows);
virtual Scene::EffectFrame *createEffectFrame(EffectFrameImpl *frame);
virtual Shadow *createShadow(Toplevel *toplevel);
virtual void screenGeometryChanged(const QSize &size);
virtual OverlayWindow *overlayWindow();
virtual bool usesOverlayWindow() const;
virtual bool blocksForRetrace() const;
virtual bool syncsToVBlank() const;
virtual bool makeOpenGLContextCurrent() override;
virtual void doneOpenGLContextCurrent() override;
Decoration::Renderer *createDecorationRenderer(Decoration::DecoratedClientImpl *impl) override;
virtual void triggerFence() override;
virtual QMatrix4x4 projectionMatrix() const = 0;
bool animationsSupported() const override;
void insertWait();
void idle();
bool debug() const { return m_debug; }
void initDebugOutput();
/**
* @brief Factory method to create a backend specific texture.
*
* @return :SceneOpenGL::Texture*
**/
Texture *createTexture();
OpenGLBackend *backend() const {
return m_backend;
}
QVector<QByteArray> openGLPlatformInterfaceExtensions() const override;
/**
* Copy a region of pixels from the current read to the current draw buffer
*/
static void copyPixels(const QRegion &region);
static SceneOpenGL *createScene(QObject *parent);
protected:
SceneOpenGL(OpenGLBackend *backend, QObject *parent = nullptr);
virtual void paintBackground(QRegion region);
virtual void extendPaintRegion(QRegion &region, bool opaqueFullscreen);
QMatrix4x4 transformation(int mask, const ScreenPaintData &data) const;
virtual void paintDesktop(int desktop, int mask, const QRegion &region, ScreenPaintData &data);
void handleGraphicsReset(GLenum status);
virtual void doPaintBackground(const QVector<float> &vertices) = 0;
virtual void updateProjectionMatrix() = 0;
Q_SIGNALS:
void resetCompositing();
protected:
bool init_ok;
private:
bool viewportLimitsMatched(const QSize &size) const;
private:
bool m_debug;
OpenGLBackend *m_backend;
SyncManager *m_syncManager;
SyncObject *m_currentFence;
};
class SceneOpenGL2 : public SceneOpenGL
{
Q_OBJECT
public:
explicit SceneOpenGL2(OpenGLBackend *backend, QObject *parent = nullptr);
virtual ~SceneOpenGL2();
virtual CompositingType compositingType() const {
return OpenGL2Compositing;
}
static bool supported(OpenGLBackend *backend);
QMatrix4x4 projectionMatrix() const override { return m_projectionMatrix; }
QMatrix4x4 screenProjectionMatrix() const override { return m_screenProjectionMatrix; }
protected:
virtual void paintSimpleScreen(int mask, QRegion region);
virtual void paintGenericScreen(int mask, ScreenPaintData data);
virtual void doPaintBackground(const QVector< float >& vertices);
virtual Scene::Window *createWindow(Toplevel *t);
virtual void finalDrawWindow(EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data);
virtual void updateProjectionMatrix() override;
void paintCursor() override;
private:
void performPaintWindow(EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data);
QMatrix4x4 createProjectionMatrix() const;
private:
LanczosFilter *m_lanczosFilter;
QScopedPointer<GLTexture> m_cursorTexture;
QMatrix4x4 m_projectionMatrix;
QMatrix4x4 m_screenProjectionMatrix;
GLuint vao;
};
class SceneOpenGL::TexturePrivate
: public GLTexturePrivate
{
public:
virtual ~TexturePrivate();
virtual bool loadTexture(WindowPixmap *pixmap) = 0;
virtual void updateTexture(WindowPixmap *pixmap);
virtual OpenGLBackend *backend() = 0;
protected:
TexturePrivate();
private:
Q_DISABLE_COPY(TexturePrivate)
};
class SceneOpenGL::Texture
: public GLTexture
{
public:
Texture(OpenGLBackend *backend);
virtual ~Texture();
Texture & operator = (const Texture& tex);
void discard() override final;
protected:
bool load(WindowPixmap *pixmap);
void updateFromPixmap(WindowPixmap *pixmap);
Texture(TexturePrivate& dd);
private:
Q_DECLARE_PRIVATE(Texture)
friend class OpenGLWindowPixmap;
};