Emit the committed() signal after the state is applied
Currently, the committed signal is emitted after the client has called wl_surface.commit. However, this breaks with synchronized subsurfaces. Notably, Firefox splits a web page in a bunch of smaller layers, which can be backed by wl_subsurface objects. All the subsurfaces are in the sync mode. If a layer needs to be repainted, Firefox will commit the corresponding subsurface with a frame callback. Since the committed signal is emitted when the wl_surface.commit request is invoked, kwin will schedule a new frame immediately. Meaning, that it is quite likely that firefox will have old contents. The right thing to do would be to schedule a frame when all the ancestors of the layer subsurface have been committed. This change re-jitters the commit logic so the committed signal is emitted when a new state is applied to the surface. It also slightly cleans up how SubSurfaceInterface::parentCommit() is called. It will be nice to cleanup the commit logic further by calling the surface role's commit hook unconditionally, i.e. not check whether it's a subsurface. But doing so may result in infinite recursions. How to clean up that is still TBD.
This commit is contained in:
parent
17cccfa233
commit
c55de7b70b
4 changed files with 50 additions and 74 deletions
|
@ -174,37 +174,17 @@ void SubSurfaceInterfacePrivate::subsurface_set_desync(Resource *)
|
||||||
}
|
}
|
||||||
mode = SubSurfaceInterface::Mode::Desynchronized;
|
mode = SubSurfaceInterface::Mode::Desynchronized;
|
||||||
if (!q->isSynchronized()) {
|
if (!q->isSynchronized()) {
|
||||||
synchronizedCommit();
|
auto surfacePrivate = SurfaceInterfacePrivate::get(surface);
|
||||||
|
surfacePrivate->commitFromCache();
|
||||||
}
|
}
|
||||||
Q_EMIT q->modeChanged(SubSurfaceInterface::Mode::Desynchronized);
|
Q_EMIT q->modeChanged(SubSurfaceInterface::Mode::Desynchronized);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SubSurfaceInterfacePrivate::commit()
|
void SubSurfaceInterfacePrivate::commit()
|
||||||
{
|
{
|
||||||
SurfaceInterfacePrivate *surfacePrivate = SurfaceInterfacePrivate::get(surface);
|
|
||||||
|
|
||||||
if (q->isSynchronized()) {
|
|
||||||
commitToCache();
|
|
||||||
} else {
|
|
||||||
if (hasCacheState) {
|
|
||||||
commitToCache();
|
|
||||||
commitFromCache();
|
|
||||||
} else {
|
|
||||||
surfacePrivate->swapStates(&surfacePrivate->pending, &surfacePrivate->current, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (SubSurfaceInterface *subsurface : qAsConst(surfacePrivate->current.below)) {
|
void SubSurfaceInterfacePrivate::parentCommit()
|
||||||
SubSurfaceInterfacePrivate *subsurfacePrivate = SubSurfaceInterfacePrivate::get(subsurface);
|
|
||||||
subsurfacePrivate->parentCommit();
|
|
||||||
}
|
|
||||||
for (SubSurfaceInterface *subsurface : qAsConst(surfacePrivate->current.above)) {
|
|
||||||
SubSurfaceInterfacePrivate *subsurfacePrivate = SubSurfaceInterfacePrivate::get(subsurface);
|
|
||||||
subsurfacePrivate->parentCommit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SubSurfaceInterfacePrivate::parentCommit(bool synchronized)
|
|
||||||
{
|
{
|
||||||
if (hasPendingPosition) {
|
if (hasPendingPosition) {
|
||||||
hasPendingPosition = false;
|
hasPendingPosition = false;
|
||||||
|
@ -212,40 +192,12 @@ void SubSurfaceInterfacePrivate::parentCommit(bool synchronized)
|
||||||
Q_EMIT q->positionChanged(position);
|
Q_EMIT q->positionChanged(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (synchronized || mode == SubSurfaceInterface::Mode::Synchronized) {
|
if (mode == SubSurfaceInterface::Mode::Synchronized) {
|
||||||
synchronizedCommit();
|
auto surfacePrivate = SurfaceInterfacePrivate::get(surface);
|
||||||
|
surfacePrivate->commitFromCache();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SubSurfaceInterfacePrivate::synchronizedCommit()
|
|
||||||
{
|
|
||||||
const SurfaceInterfacePrivate *surfacePrivate = SurfaceInterfacePrivate::get(surface);
|
|
||||||
commitFromCache();
|
|
||||||
|
|
||||||
for (SubSurfaceInterface *subsurface : qAsConst(surfacePrivate->current.below)) {
|
|
||||||
SubSurfaceInterfacePrivate *subsurfacePrivate = SubSurfaceInterfacePrivate::get(subsurface);
|
|
||||||
subsurfacePrivate->parentCommit(true);
|
|
||||||
}
|
|
||||||
for (SubSurfaceInterface *subsurface : qAsConst(surfacePrivate->current.above)) {
|
|
||||||
SubSurfaceInterfacePrivate *subsurfacePrivate = SubSurfaceInterfacePrivate::get(subsurface);
|
|
||||||
subsurfacePrivate->parentCommit(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SubSurfaceInterfacePrivate::commitToCache()
|
|
||||||
{
|
|
||||||
SurfaceInterfacePrivate *surfacePrivate = SurfaceInterfacePrivate::get(surface);
|
|
||||||
surfacePrivate->swapStates(&surfacePrivate->pending, &surfacePrivate->cached, false);
|
|
||||||
hasCacheState = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SubSurfaceInterfacePrivate::commitFromCache()
|
|
||||||
{
|
|
||||||
SurfaceInterfacePrivate *surfacePrivate = SurfaceInterfacePrivate::get(surface);
|
|
||||||
surfacePrivate->swapStates(&surfacePrivate->cached, &surfacePrivate->current, true);
|
|
||||||
hasCacheState = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
SubSurfaceInterface::SubSurfaceInterface(SurfaceInterface *surface, SurfaceInterface *parent,
|
SubSurfaceInterface::SubSurfaceInterface(SurfaceInterface *surface, SurfaceInterface *parent,
|
||||||
wl_resource *resource)
|
wl_resource *resource)
|
||||||
: d(new SubSurfaceInterfacePrivate(this, surface, parent, resource))
|
: d(new SubSurfaceInterfacePrivate(this, surface, parent, resource))
|
||||||
|
|
|
@ -41,12 +41,7 @@ public:
|
||||||
SurfaceInterface *parent, ::wl_resource *resource);
|
SurfaceInterface *parent, ::wl_resource *resource);
|
||||||
|
|
||||||
void commit() override;
|
void commit() override;
|
||||||
|
void parentCommit();
|
||||||
void parentCommit(bool synchronized = false);
|
|
||||||
void synchronizedCommit();
|
|
||||||
|
|
||||||
void commitToCache();
|
|
||||||
void commitFromCache();
|
|
||||||
|
|
||||||
SubSurfaceInterface *q;
|
SubSurfaceInterface *q;
|
||||||
QPoint position = QPoint(0, 0);
|
QPoint position = QPoint(0, 0);
|
||||||
|
@ -54,7 +49,6 @@ public:
|
||||||
SubSurfaceInterface::Mode mode = SubSurfaceInterface::Mode::Synchronized;
|
SubSurfaceInterface::Mode mode = SubSurfaceInterface::Mode::Synchronized;
|
||||||
QPointer<SurfaceInterface> surface;
|
QPointer<SurfaceInterface> surface;
|
||||||
QPointer<SurfaceInterface> parent;
|
QPointer<SurfaceInterface> parent;
|
||||||
bool hasCacheState = false;
|
|
||||||
bool hasPendingPosition = false;
|
bool hasPendingPosition = false;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -649,13 +649,6 @@ void SurfaceInterfacePrivate::swapStates(SurfaceState *source, SurfaceState *tar
|
||||||
if (childrenChanged) {
|
if (childrenChanged) {
|
||||||
Q_EMIT q->childSubSurfacesChanged();
|
Q_EMIT q->childSubSurfacesChanged();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void SurfaceInterfacePrivate::commit()
|
|
||||||
{
|
|
||||||
if (!subSurface) {
|
|
||||||
swapStates(&pending, ¤t, true);
|
|
||||||
|
|
||||||
// The position of a sub-surface is applied when its parent is committed.
|
// The position of a sub-surface is applied when its parent is committed.
|
||||||
for (SubSurfaceInterface *subsurface : qAsConst(current.below)) {
|
for (SubSurfaceInterface *subsurface : qAsConst(current.below)) {
|
||||||
auto subsurfacePrivate = SubSurfaceInterfacePrivate::get(subsurface);
|
auto subsurfacePrivate = SubSurfaceInterfacePrivate::get(subsurface);
|
||||||
|
@ -665,15 +658,47 @@ void SurfaceInterfacePrivate::commit()
|
||||||
auto subsurfacePrivate = SubSurfaceInterfacePrivate::get(subsurface);
|
auto subsurfacePrivate = SubSurfaceInterfacePrivate::get(subsurface);
|
||||||
subsurfacePrivate->parentCommit();
|
subsurfacePrivate->parentCommit();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (role) {
|
if (role) {
|
||||||
role->commit();
|
role->commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_EMIT q->committed();
|
Q_EMIT q->committed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SurfaceInterfacePrivate::commit()
|
||||||
|
{
|
||||||
|
if (subSurface) {
|
||||||
|
commitSubSurface();
|
||||||
|
} else {
|
||||||
|
swapStates(&pending, ¤t, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SurfaceInterfacePrivate::commitSubSurface()
|
||||||
|
{
|
||||||
|
if (subSurface->isSynchronized()) {
|
||||||
|
commitToCache();
|
||||||
|
} else {
|
||||||
|
if (hasCacheState) {
|
||||||
|
commitToCache();
|
||||||
|
commitFromCache();
|
||||||
|
} else {
|
||||||
|
swapStates(&pending, ¤t, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SurfaceInterfacePrivate::commitToCache()
|
||||||
|
{
|
||||||
|
swapStates(&pending, &cached, false);
|
||||||
|
hasCacheState = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SurfaceInterfacePrivate::commitFromCache()
|
||||||
|
{
|
||||||
|
swapStates(&cached, ¤t, true);
|
||||||
|
hasCacheState = false;
|
||||||
|
}
|
||||||
|
|
||||||
QRegion SurfaceInterface::damage() const
|
QRegion SurfaceInterface::damage() const
|
||||||
{
|
{
|
||||||
return d->current.damage;
|
return d->current.damage;
|
||||||
|
|
|
@ -95,7 +95,11 @@ public:
|
||||||
void installPointerConstraint(ConfinedPointerV1Interface *confinement);
|
void installPointerConstraint(ConfinedPointerV1Interface *confinement);
|
||||||
void installIdleInhibitor(IdleInhibitorV1Interface *inhibitor);
|
void installIdleInhibitor(IdleInhibitorV1Interface *inhibitor);
|
||||||
|
|
||||||
|
void commitToCache();
|
||||||
|
void commitFromCache();
|
||||||
|
|
||||||
void commit();
|
void commit();
|
||||||
|
void commitSubSurface();
|
||||||
QMatrix4x4 buildSurfaceToBufferMatrix(const SurfaceState *state);
|
QMatrix4x4 buildSurfaceToBufferMatrix(const SurfaceState *state);
|
||||||
void swapStates(SurfaceState *source, SurfaceState *target, bool emitChanged);
|
void swapStates(SurfaceState *source, SurfaceState *target, bool emitChanged);
|
||||||
|
|
||||||
|
@ -110,6 +114,7 @@ public:
|
||||||
QMatrix4x4 bufferToSurfaceMatrix;
|
QMatrix4x4 bufferToSurfaceMatrix;
|
||||||
QSize bufferSize;
|
QSize bufferSize;
|
||||||
QRegion inputRegion;
|
QRegion inputRegion;
|
||||||
|
bool hasCacheState = false;
|
||||||
|
|
||||||
// workaround for https://bugreports.qt.io/browse/QTBUG-52192
|
// workaround for https://bugreports.qt.io/browse/QTBUG-52192
|
||||||
// A subsurface needs to be considered mapped even if it doesn't have a buffer attached
|
// A subsurface needs to be considered mapped even if it doesn't have a buffer attached
|
||||||
|
|
Loading…
Reference in a new issue