scene: Decouple Item from Workspace and Output
Currently, Item schedules repaints taking output geometry into account, but that's going to work poorly for cases other than workspace scene. Moving from Output to SceneDelegate also allows us to unify some X11 and Wayland specific code paths in Item. Furthermore, it ensures that effects->paintScreen() won't remove pending repaints for the output.
This commit is contained in:
parent
b95c93517b
commit
2819a3cb4f
6 changed files with 60 additions and 52 deletions
|
@ -1859,7 +1859,12 @@ void EffectsHandlerImpl::renderScreen(EffectScreen *screen)
|
|||
renderTarget.setDevicePixelRatio(screen->devicePixelRatio());
|
||||
|
||||
auto output = static_cast<EffectScreenImpl *>(screen)->platformOutput();
|
||||
m_scene->prePaint(output);
|
||||
|
||||
RenderLayer layer(output->renderLoop());
|
||||
SceneDelegate delegate(m_scene, output);
|
||||
delegate.setLayer(&layer);
|
||||
|
||||
m_scene->prePaint(&delegate);
|
||||
m_scene->paint(&renderTarget, output->geometry());
|
||||
m_scene->postPaint();
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ namespace KWin
|
|||
|
||||
class Window;
|
||||
class Deleted;
|
||||
class Output;
|
||||
|
||||
namespace Decoration
|
||||
{
|
||||
|
|
|
@ -6,20 +6,19 @@
|
|||
|
||||
#include "scene/item.h"
|
||||
#include "composite.h"
|
||||
#include "core/output.h"
|
||||
#include "core/renderlayer.h"
|
||||
#include "core/renderloop.h"
|
||||
#include "main.h"
|
||||
#include "scene/scene.h"
|
||||
#include "utils/common.h"
|
||||
#include "workspace.h"
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
Item::Item(Item *parent)
|
||||
: m_scene(Compositor::self()->scene())
|
||||
{
|
||||
setParentItem(parent);
|
||||
connect(workspace(), &Workspace::outputRemoved, this, &Item::removeRepaints);
|
||||
connect(m_scene, &Scene::delegateRemoved, this, &Item::removeRepaints);
|
||||
}
|
||||
|
||||
Item::~Item()
|
||||
|
@ -27,7 +26,7 @@ Item::~Item()
|
|||
setParentItem(nullptr);
|
||||
for (const auto &dirty : std::as_const(m_repaints)) {
|
||||
if (!dirty.isEmpty()) {
|
||||
Compositor::self()->scene()->addRepaint(dirty);
|
||||
m_scene->addRepaint(dirty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -293,19 +292,14 @@ void Item::scheduleRepaint(const QRegion ®ion)
|
|||
|
||||
void Item::scheduleRepaintInternal(const QRegion ®ion)
|
||||
{
|
||||
const QList<Output *> outputs = workspace()->outputs();
|
||||
const QRegion globalRegion = mapToGlobal(region);
|
||||
if (kwinApp()->operationMode() != Application::OperationModeX11) {
|
||||
for (const auto &output : outputs) {
|
||||
const QRegion dirtyRegion = globalRegion & output->geometry();
|
||||
if (!dirtyRegion.isEmpty()) {
|
||||
m_repaints[output] += dirtyRegion;
|
||||
output->renderLoop()->scheduleRepaint(this);
|
||||
}
|
||||
const QList<SceneDelegate *> delegates = m_scene->delegates();
|
||||
for (SceneDelegate *delegate : delegates) {
|
||||
const QRegion dirtyRegion = globalRegion & delegate->viewport();
|
||||
if (!dirtyRegion.isEmpty()) {
|
||||
m_repaints[delegate] += dirtyRegion;
|
||||
delegate->layer()->loop()->scheduleRepaint(this);
|
||||
}
|
||||
} else {
|
||||
m_repaints[outputs.constFirst()] += globalRegion;
|
||||
outputs.constFirst()->renderLoop()->scheduleRepaint(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -314,16 +308,12 @@ void Item::scheduleFrame()
|
|||
if (!isVisible()) {
|
||||
return;
|
||||
}
|
||||
const QList<Output *> outputs = workspace()->outputs();
|
||||
if (kwinApp()->operationMode() != Application::OperationModeX11) {
|
||||
const QRect geometry = mapToGlobal(rect()).toAlignedRect();
|
||||
for (const Output *output : outputs) {
|
||||
if (output->geometry().intersects(geometry)) {
|
||||
output->renderLoop()->scheduleRepaint(this);
|
||||
}
|
||||
const QRect geometry = mapToGlobal(rect()).toRect();
|
||||
const QList<SceneDelegate *> delegates = m_scene->delegates();
|
||||
for (SceneDelegate *delegate : delegates) {
|
||||
if (delegate->viewport().intersects(geometry)) {
|
||||
delegate->layer()->loop()->scheduleRepaint(this);
|
||||
}
|
||||
} else {
|
||||
outputs.constFirst()->renderLoop()->scheduleRepaint(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -349,19 +339,19 @@ WindowQuadList Item::quads() const
|
|||
return m_quads.value();
|
||||
}
|
||||
|
||||
QRegion Item::repaints(Output *output) const
|
||||
QRegion Item::repaints(SceneDelegate *delegate) const
|
||||
{
|
||||
return m_repaints.value(output);
|
||||
return m_repaints.value(delegate);
|
||||
}
|
||||
|
||||
void Item::resetRepaints(Output *output)
|
||||
void Item::resetRepaints(SceneDelegate *delegate)
|
||||
{
|
||||
m_repaints.insert(output, QRegion());
|
||||
m_repaints.insert(delegate, QRegion());
|
||||
}
|
||||
|
||||
void Item::removeRepaints(Output *output)
|
||||
void Item::removeRepaints(SceneDelegate *delegate)
|
||||
{
|
||||
m_repaints.remove(output);
|
||||
m_repaints.remove(delegate);
|
||||
}
|
||||
|
||||
bool Item::explicitVisible() const
|
||||
|
@ -401,7 +391,7 @@ void Item::updateEffectiveVisibility()
|
|||
|
||||
m_effectiveVisible = effectiveVisible;
|
||||
if (!m_effectiveVisible) {
|
||||
Compositor::self()->scene()->addRepaint(mapToGlobal(boundingRect()).toAlignedRect());
|
||||
m_scene->addRepaint(mapToGlobal(boundingRect()).toAlignedRect());
|
||||
} else {
|
||||
scheduleRepaintInternal(boundingRect().toAlignedRect());
|
||||
}
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
namespace KWin
|
||||
{
|
||||
|
||||
class Output;
|
||||
class SceneDelegate;
|
||||
class Scene;
|
||||
|
||||
/**
|
||||
* The Item class is the base class for items in the scene.
|
||||
|
@ -101,8 +102,8 @@ public:
|
|||
void scheduleRepaint(const QRectF ®ion);
|
||||
void scheduleRepaint(const QRegion ®ion);
|
||||
void scheduleFrame();
|
||||
QRegion repaints(Output *output) const;
|
||||
void resetRepaints(Output *output);
|
||||
QRegion repaints(SceneDelegate *delegate) const;
|
||||
void resetRepaints(SceneDelegate *delegate);
|
||||
|
||||
WindowQuadList quads() const;
|
||||
virtual void preprocess();
|
||||
|
@ -137,8 +138,9 @@ private:
|
|||
|
||||
bool computeEffectiveVisibility() const;
|
||||
void updateEffectiveVisibility();
|
||||
void removeRepaints(Output *output);
|
||||
void removeRepaints(SceneDelegate *delegate);
|
||||
|
||||
Scene *m_scene;
|
||||
QPointer<Item> m_parentItem;
|
||||
QList<Item *> m_childItems;
|
||||
QMatrix4x4 m_transform;
|
||||
|
@ -149,7 +151,7 @@ private:
|
|||
int m_z = 0;
|
||||
bool m_explicitVisible = true;
|
||||
bool m_effectiveVisible = true;
|
||||
QMap<Output *, QRegion> m_repaints;
|
||||
QMap<SceneDelegate *, QRegion> m_repaints;
|
||||
mutable std::optional<WindowQuadList> m_quads;
|
||||
mutable std::optional<QList<Item *>> m_sortedChildItems;
|
||||
};
|
||||
|
|
|
@ -111,7 +111,7 @@ SurfaceItem *SceneDelegate::scanoutCandidate() const
|
|||
|
||||
void SceneDelegate::prePaint()
|
||||
{
|
||||
m_scene->prePaint(m_output);
|
||||
m_scene->prePaint(this);
|
||||
}
|
||||
|
||||
void SceneDelegate::postPaint()
|
||||
|
@ -124,6 +124,11 @@ void SceneDelegate::paint(RenderTarget *renderTarget, const QRegion ®ion)
|
|||
m_scene->paint(renderTarget, region.translated(viewport().topLeft()));
|
||||
}
|
||||
|
||||
Output *SceneDelegate::output() const
|
||||
{
|
||||
return m_output;
|
||||
}
|
||||
|
||||
QRect SceneDelegate::viewport() const
|
||||
{
|
||||
return m_output ? m_output->geometry() : m_scene->geometry();
|
||||
|
@ -235,6 +240,7 @@ void Scene::addDelegate(SceneDelegate *delegate)
|
|||
void Scene::removeDelegate(SceneDelegate *delegate)
|
||||
{
|
||||
m_delegates.removeOne(delegate);
|
||||
Q_EMIT delegateRemoved(delegate);
|
||||
}
|
||||
|
||||
static SurfaceItem *findTopMostSurface(SurfaceItem *item)
|
||||
|
@ -286,16 +292,17 @@ SurfaceItem *Scene::scanoutCandidate() const
|
|||
return candidate;
|
||||
}
|
||||
|
||||
void Scene::prePaint(Output *output)
|
||||
void Scene::prePaint(SceneDelegate *delegate)
|
||||
{
|
||||
createStackingOrder();
|
||||
|
||||
painted_delegate = delegate;
|
||||
if (kwinApp()->operationMode() == Application::OperationModeX11) {
|
||||
painted_screen = workspace()->outputs().constFirst();
|
||||
m_renderer->setRenderTargetRect(geometry());
|
||||
m_renderer->setRenderTargetScale(1);
|
||||
} else {
|
||||
painted_screen = output;
|
||||
painted_screen = painted_delegate->output();
|
||||
m_renderer->setRenderTargetRect(painted_screen->fractionalGeometry());
|
||||
m_renderer->setRenderTargetScale(painted_screen->scale());
|
||||
}
|
||||
|
@ -336,31 +343,31 @@ void Scene::prePaint(Output *output)
|
|||
}
|
||||
}
|
||||
|
||||
static void resetRepaintsHelper(Item *item, Output *output)
|
||||
static void resetRepaintsHelper(Item *item, SceneDelegate *delegate)
|
||||
{
|
||||
item->resetRepaints(output);
|
||||
item->resetRepaints(delegate);
|
||||
|
||||
const auto childItems = item->childItems();
|
||||
for (Item *childItem : childItems) {
|
||||
resetRepaintsHelper(childItem, output);
|
||||
resetRepaintsHelper(childItem, delegate);
|
||||
}
|
||||
}
|
||||
|
||||
static void accumulateRepaints(Item *item, Output *output, QRegion *repaints)
|
||||
static void accumulateRepaints(Item *item, SceneDelegate *delegate, QRegion *repaints)
|
||||
{
|
||||
*repaints += item->repaints(output);
|
||||
item->resetRepaints(output);
|
||||
*repaints += item->repaints(delegate);
|
||||
item->resetRepaints(delegate);
|
||||
|
||||
const auto childItems = item->childItems();
|
||||
for (Item *childItem : childItems) {
|
||||
accumulateRepaints(childItem, output, repaints);
|
||||
accumulateRepaints(childItem, delegate, repaints);
|
||||
}
|
||||
}
|
||||
|
||||
void Scene::preparePaintGenericScreen()
|
||||
{
|
||||
for (WindowItem *windowItem : std::as_const(stacking_order)) {
|
||||
resetRepaintsHelper(windowItem, painted_screen);
|
||||
resetRepaintsHelper(windowItem, painted_delegate);
|
||||
|
||||
WindowPrePaintData data;
|
||||
data.mask = m_paintContext.mask;
|
||||
|
@ -384,7 +391,7 @@ void Scene::preparePaintSimpleScreen()
|
|||
Window *window = windowItem->window();
|
||||
WindowPrePaintData data;
|
||||
data.mask = m_paintContext.mask;
|
||||
accumulateRepaints(windowItem, painted_screen, &data.paint);
|
||||
accumulateRepaints(windowItem, painted_delegate, &data.paint);
|
||||
|
||||
// Clip out the decoration for opaque windows; the decoration is drawn in the second pass.
|
||||
if (window->opacity() == 1.0) {
|
||||
|
@ -419,7 +426,7 @@ void Scene::preparePaintSimpleScreen()
|
|||
}
|
||||
|
||||
if (m_dndIcon) {
|
||||
accumulateRepaints(m_dndIcon.get(), painted_screen, &m_paintContext.damage);
|
||||
accumulateRepaints(m_dndIcon.get(), painted_delegate, &m_paintContext.damage);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,7 @@ public:
|
|||
explicit SceneDelegate(Scene *scene, Output *output, QObject *parent = nullptr);
|
||||
~SceneDelegate() override;
|
||||
|
||||
Output *output() const;
|
||||
QRect viewport() const;
|
||||
|
||||
QRegion repaints() const override;
|
||||
|
@ -90,7 +91,7 @@ public:
|
|||
void removeDelegate(SceneDelegate *delegate);
|
||||
|
||||
SurfaceItem *scanoutCandidate() const;
|
||||
void prePaint(Output *output);
|
||||
void prePaint(SceneDelegate *delegate);
|
||||
void postPaint();
|
||||
void paint(RenderTarget *renderTarget, const QRegion ®ion);
|
||||
|
||||
|
@ -146,6 +147,7 @@ public:
|
|||
Q_SIGNALS:
|
||||
void preFrameRender();
|
||||
void frameRendered();
|
||||
void delegateRemoved(SceneDelegate *delegate);
|
||||
|
||||
protected:
|
||||
void createStackingOrder();
|
||||
|
@ -185,6 +187,7 @@ protected:
|
|||
|
||||
// The screen that is being currently painted
|
||||
Output *painted_screen = nullptr;
|
||||
SceneDelegate *painted_delegate = nullptr;
|
||||
|
||||
// windows in their stacking order
|
||||
QVector<WindowItem *> stacking_order;
|
||||
|
|
Loading…
Reference in a new issue