Move graphics reset handling to RenderBackend
This makes the Scene less overloaded and it's needed for things such as render layers. In hindsight, it would be great to merge checkGraphicsReset() and beginFrame(), e.g. make beginFrame() return the status like in QRhi or VkSwapchain. If it's OUT_OF_DATE or something, reinitialize the compositor.
This commit is contained in:
parent
ca7298a325
commit
9e97c06758
8 changed files with 111 additions and 114 deletions
|
@ -307,7 +307,6 @@ bool Compositor::setupStart()
|
|||
QQuickWindow::setSceneGraphBackend(QSGRendererInterface::Software);
|
||||
}
|
||||
|
||||
connect(m_scene, &Scene::resetCompositing, this, &Compositor::reinitialize);
|
||||
Q_EMIT sceneCreated();
|
||||
|
||||
return true;
|
||||
|
@ -619,8 +618,14 @@ QList<Toplevel *> Compositor::windowsToRender() const
|
|||
|
||||
void Compositor::composite(RenderLoop *renderLoop)
|
||||
{
|
||||
const auto &output = m_renderLoops[renderLoop];
|
||||
if (m_backend->checkGraphicsReset()) {
|
||||
qCDebug(KWIN_CORE) << "Graphics reset occurred";
|
||||
KNotification::event(QStringLiteral("graphicsreset"), i18n("Desktop effects were restarted due to a graphics reset"));
|
||||
reinitialize();
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &output = m_renderLoops[renderLoop];
|
||||
fTraceDuration("Paint (", output ? output->name() : QStringLiteral("screens"), ")");
|
||||
|
||||
const auto windows = windowsToRender();
|
||||
|
|
|
@ -13,7 +13,21 @@
|
|||
#include "screens.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <QElapsedTimer>
|
||||
|
||||
#include <epoxy/gl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// HACK: workaround for libepoxy < 1.3
|
||||
#ifndef GL_GUILTY_CONTEXT_RESET
|
||||
#define GL_GUILTY_CONTEXT_RESET 0x8253
|
||||
#endif
|
||||
#ifndef GL_INNOCENT_CONTEXT_RESET
|
||||
#define GL_INNOCENT_CONTEXT_RESET 0x8254
|
||||
#endif
|
||||
#ifndef GL_UNKNOWN_CONTEXT_RESET
|
||||
#define GL_UNKNOWN_CONTEXT_RESET 0x8255
|
||||
#endif
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
@ -97,4 +111,36 @@ SurfaceTexture *OpenGLBackend::createSurfaceTextureWayland(SurfacePixmapWayland
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
bool OpenGLBackend::checkGraphicsReset()
|
||||
{
|
||||
const GLenum status = glGetGraphicsResetStatus();
|
||||
if (Q_LIKELY(status == GL_NO_ERROR)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (status) {
|
||||
case GL_GUILTY_CONTEXT_RESET:
|
||||
qCDebug(KWIN_OPENGL) << "A graphics reset attributable to the current GL context occurred.";
|
||||
break;
|
||||
case GL_INNOCENT_CONTEXT_RESET:
|
||||
qCDebug(KWIN_OPENGL) << "A graphics reset not attributable to the current GL context occurred.";
|
||||
break;
|
||||
case GL_UNKNOWN_CONTEXT_RESET:
|
||||
qCDebug(KWIN_OPENGL) << "A graphics reset of an unknown cause occurred.";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
|
||||
// Wait until the reset is completed or max 10 seconds
|
||||
while (timer.elapsed() < 10000 && glGetGraphicsResetStatus() != GL_NO_ERROR) {
|
||||
usleep(50);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ public:
|
|||
|
||||
virtual void init() = 0;
|
||||
CompositingType compositingType() const override final;
|
||||
bool checkGraphicsReset() override final;
|
||||
|
||||
virtual SurfaceTexture *createSurfaceTextureInternal(SurfacePixmapInternal *pixmap);
|
||||
virtual SurfaceTexture *createSurfaceTextureX11(SurfacePixmapX11 *pixmap);
|
||||
|
|
|
@ -19,4 +19,9 @@ OverlayWindow *RenderBackend::overlayWindow() const
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
bool RenderBackend::checkGraphicsReset()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace KWin
|
||||
|
|
|
@ -29,6 +29,8 @@ public:
|
|||
virtual CompositingType compositingType() const = 0;
|
||||
virtual OverlayWindow *overlayWindow() const;
|
||||
|
||||
virtual bool checkGraphicsReset();
|
||||
|
||||
virtual QRegion beginFrame(AbstractOutput *output) = 0;
|
||||
virtual void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) = 0;
|
||||
};
|
||||
|
|
|
@ -193,7 +193,6 @@ public:
|
|||
|
||||
Q_SIGNALS:
|
||||
void frameRendered();
|
||||
void resetCompositing();
|
||||
|
||||
public Q_SLOTS:
|
||||
// a window has been closed
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <QGraphicsScale>
|
||||
#include <QPainter>
|
||||
|
@ -45,23 +44,8 @@
|
|||
#include <QVector2D>
|
||||
#include <QVector4D>
|
||||
#include <QMatrix4x4>
|
||||
|
||||
#include <KLocalizedString>
|
||||
#include <KNotification>
|
||||
#include <KProcess>
|
||||
#include <QtMath>
|
||||
|
||||
// HACK: workaround for libepoxy < 1.3
|
||||
#ifndef GL_GUILTY_CONTEXT_RESET
|
||||
#define GL_GUILTY_CONTEXT_RESET 0x8253
|
||||
#endif
|
||||
#ifndef GL_INNOCENT_CONTEXT_RESET
|
||||
#define GL_INNOCENT_CONTEXT_RESET 0x8254
|
||||
#endif
|
||||
#ifndef GL_UNKNOWN_CONTEXT_RESET
|
||||
#define GL_UNKNOWN_CONTEXT_RESET 0x8255
|
||||
#endif
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
|
@ -113,40 +97,6 @@ bool SceneOpenGL::initFailed() const
|
|||
return !init_ok;
|
||||
}
|
||||
|
||||
void SceneOpenGL::handleGraphicsReset(GLenum status)
|
||||
{
|
||||
switch (status) {
|
||||
case GL_GUILTY_CONTEXT_RESET:
|
||||
qCDebug(KWIN_OPENGL) << "A graphics reset attributable to the current GL context occurred.";
|
||||
break;
|
||||
|
||||
case GL_INNOCENT_CONTEXT_RESET:
|
||||
qCDebug(KWIN_OPENGL) << "A graphics reset not attributable to the current GL context occurred.";
|
||||
break;
|
||||
|
||||
case GL_UNKNOWN_CONTEXT_RESET:
|
||||
qCDebug(KWIN_OPENGL) << "A graphics reset of an unknown cause occurred.";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
|
||||
// Wait until the reset is completed or max 10 seconds
|
||||
while (timer.elapsed() < 10000 && glGetGraphicsResetStatus() != GL_NO_ERROR)
|
||||
usleep(50);
|
||||
|
||||
qCDebug(KWIN_OPENGL) << "Attempting to reset compositing.";
|
||||
QMetaObject::invokeMethod(this, "resetCompositing", Qt::QueuedConnection);
|
||||
|
||||
KNotification::event(QStringLiteral("graphicsreset"), i18n("Desktop effects were restarted due to a graphics reset"));
|
||||
|
||||
m_resetOccurred = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render cursor texture in case hardware cursor is disabled.
|
||||
* Useful for screen recording apps or backends that can't do planes.
|
||||
|
@ -237,10 +187,6 @@ static SurfaceItem *findTopMostSurface(SurfaceItem *item)
|
|||
void SceneOpenGL::paint(AbstractOutput *output, const QRegion &damage, const QList<Toplevel *> &toplevels,
|
||||
RenderLoop *renderLoop)
|
||||
{
|
||||
if (m_resetOccurred) {
|
||||
return; // A graphics reset has occurred, do nothing.
|
||||
}
|
||||
|
||||
painted_screen = output;
|
||||
// actually paint the frame, flushed with the NEXT frame
|
||||
createStackingOrder(toplevels);
|
||||
|
@ -258,71 +204,66 @@ void SceneOpenGL::paint(AbstractOutput *output, const QRegion &damage, const QLi
|
|||
scaling = 1;
|
||||
}
|
||||
|
||||
const GLenum status = glGetGraphicsResetStatus();
|
||||
if (status != GL_NO_ERROR) {
|
||||
handleGraphicsReset(status);
|
||||
} else {
|
||||
renderLoop->beginFrame();
|
||||
renderLoop->beginFrame();
|
||||
|
||||
SurfaceItem *fullscreenSurface = nullptr;
|
||||
for (int i = stacking_order.count() - 1; i >=0; i--) {
|
||||
Window *window = stacking_order[i];
|
||||
Toplevel *toplevel = window->window();
|
||||
if (output && toplevel->isOnOutput(output) && window->isVisible() && toplevel->opacity() > 0) {
|
||||
AbstractClient *c = dynamic_cast<AbstractClient*>(toplevel);
|
||||
if (!c || !c->isFullScreen()) {
|
||||
break;
|
||||
}
|
||||
if (!window->surfaceItem()) {
|
||||
break;
|
||||
}
|
||||
SurfaceItem *topMost = findTopMostSurface(window->surfaceItem());
|
||||
auto pixmap = topMost->pixmap();
|
||||
if (!pixmap) {
|
||||
break;
|
||||
}
|
||||
pixmap->update();
|
||||
// the subsurface has to be able to cover the whole window
|
||||
if (topMost->position() != QPoint(0, 0)) {
|
||||
break;
|
||||
}
|
||||
// and it has to be completely opaque
|
||||
if (!window->isOpaque() && !topMost->opaque().contains(QRect(0, 0, window->width(), window->height()))) {
|
||||
break;
|
||||
}
|
||||
fullscreenSurface = topMost;
|
||||
SurfaceItem *fullscreenSurface = nullptr;
|
||||
for (int i = stacking_order.count() - 1; i >=0; i--) {
|
||||
Window *window = stacking_order[i];
|
||||
Toplevel *toplevel = window->window();
|
||||
if (output && toplevel->isOnOutput(output) && window->isVisible() && toplevel->opacity() > 0) {
|
||||
AbstractClient *c = dynamic_cast<AbstractClient*>(toplevel);
|
||||
if (!c || !c->isFullScreen()) {
|
||||
break;
|
||||
}
|
||||
if (!window->surfaceItem()) {
|
||||
break;
|
||||
}
|
||||
SurfaceItem *topMost = findTopMostSurface(window->surfaceItem());
|
||||
auto pixmap = topMost->pixmap();
|
||||
if (!pixmap) {
|
||||
break;
|
||||
}
|
||||
pixmap->update();
|
||||
// the subsurface has to be able to cover the whole window
|
||||
if (topMost->position() != QPoint(0, 0)) {
|
||||
break;
|
||||
}
|
||||
// and it has to be completely opaque
|
||||
if (!window->isOpaque() && !topMost->opaque().contains(QRect(0, 0, window->width(), window->height()))) {
|
||||
break;
|
||||
}
|
||||
fullscreenSurface = topMost;
|
||||
break;
|
||||
}
|
||||
renderLoop->setFullscreenSurface(fullscreenSurface);
|
||||
}
|
||||
renderLoop->setFullscreenSurface(fullscreenSurface);
|
||||
|
||||
bool directScanout = false;
|
||||
if (m_backend->directScanoutAllowed(output) && !static_cast<EffectsHandlerImpl*>(effects)->blocksDirectScanout()) {
|
||||
directScanout = m_backend->scanout(output, fullscreenSurface);
|
||||
}
|
||||
if (directScanout) {
|
||||
renderLoop->endFrame();
|
||||
} else {
|
||||
// prepare rendering makescontext current on the output
|
||||
repaint = m_backend->beginFrame(output);
|
||||
GLVertexBuffer::streamingBuffer()->beginFrame();
|
||||
bool directScanout = false;
|
||||
if (m_backend->directScanoutAllowed(output) && !static_cast<EffectsHandlerImpl*>(effects)->blocksDirectScanout()) {
|
||||
directScanout = m_backend->scanout(output, fullscreenSurface);
|
||||
}
|
||||
if (directScanout) {
|
||||
renderLoop->endFrame();
|
||||
} else {
|
||||
// prepare rendering makescontext current on the output
|
||||
repaint = m_backend->beginFrame(output);
|
||||
GLVertexBuffer::streamingBuffer()->beginFrame();
|
||||
|
||||
GLVertexBuffer::setVirtualScreenGeometry(geo);
|
||||
GLRenderTarget::setVirtualScreenGeometry(geo);
|
||||
GLVertexBuffer::setVirtualScreenScale(scaling);
|
||||
GLRenderTarget::setVirtualScreenScale(scaling);
|
||||
GLVertexBuffer::setVirtualScreenGeometry(geo);
|
||||
GLRenderTarget::setVirtualScreenGeometry(geo);
|
||||
GLVertexBuffer::setVirtualScreenScale(scaling);
|
||||
GLRenderTarget::setVirtualScreenScale(scaling);
|
||||
|
||||
updateProjectionMatrix(geo);
|
||||
updateProjectionMatrix(geo);
|
||||
|
||||
paintScreen(damage.intersected(geo), repaint, &update, &valid,
|
||||
renderLoop, projectionMatrix()); // call generic implementation
|
||||
paintCursor(output, valid);
|
||||
paintScreen(damage.intersected(geo), repaint, &update, &valid,
|
||||
renderLoop, projectionMatrix()); // call generic implementation
|
||||
paintCursor(output, valid);
|
||||
|
||||
renderLoop->endFrame();
|
||||
renderLoop->endFrame();
|
||||
|
||||
GLVertexBuffer::streamingBuffer()->endOfFrame();
|
||||
m_backend->endFrame(output, valid, update);
|
||||
}
|
||||
GLVertexBuffer::streamingBuffer()->endOfFrame();
|
||||
m_backend->endFrame(output, valid, update);
|
||||
}
|
||||
|
||||
// do cleanup
|
||||
|
|
|
@ -77,10 +77,8 @@ private:
|
|||
void doPaintBackground(const QVector< float >& vertices);
|
||||
void updateProjectionMatrix(const QRect &geometry);
|
||||
void performPaintWindow(EffectWindowImpl* w, int mask, const QRegion ®ion, WindowPaintData& data);
|
||||
void handleGraphicsReset(GLenum status);
|
||||
|
||||
bool init_ok = true;
|
||||
bool m_resetOccurred = false;
|
||||
OpenGLBackend *m_backend;
|
||||
LanczosFilter *m_lanczosFilter = nullptr;
|
||||
QScopedPointer<GLTexture> m_cursorTexture;
|
||||
|
|
Loading…
Reference in a new issue