wayland: Keep transaction entries for deleted surfaces

If a transaction entry is removed, the graphics buffer reference will
be dropped and it's possible that the TransactionDmaBufLocker is going
to be destroyed as well.

If that happens, the transaction may remain in the locked state.
This commit is contained in:
Vlad Zahorodnii 2023-09-12 13:30:19 +03:00
parent 693fa8a968
commit df8ddb609b
3 changed files with 23 additions and 26 deletions

View file

@ -407,10 +407,6 @@ SurfaceInterface::~SurfaceInterface()
{
delete d->subsurface.transaction;
d->subsurface.transaction = nullptr;
for (auto transaction = d->firstTransaction; transaction; transaction = transaction->next(this)) {
transaction->remove(this);
}
}
SurfaceRole *SurfaceInterface::role() const

View file

@ -103,6 +103,9 @@ bool Transaction::isReady() const
}
for (const TransactionEntry &entry : m_entries) {
if (!entry.surface) {
continue;
}
if (entry.surface->firstTransaction() != this) {
return false;
}
@ -145,13 +148,6 @@ void Transaction::add(SurfaceInterface *surface)
});
}
void Transaction::remove(SurfaceInterface *surface)
{
std::erase_if(m_entries, [surface](const TransactionEntry &entry) {
return entry.surface == surface;
});
}
void Transaction::amend(SurfaceInterface *surface, std::function<void(SurfaceState *)> mutator)
{
for (TransactionEntry &entry : m_entries) {
@ -211,17 +207,23 @@ void Transaction::apply()
});
for (TransactionEntry &entry : m_entries) {
SurfaceInterfacePrivate::get(entry.surface)->applyState(entry.state.get());
if (entry.surface) {
SurfaceInterfacePrivate::get(entry.surface)->applyState(entry.state.get());
}
}
for (TransactionEntry &entry : m_entries) {
if (entry.surface->lastTransaction() == this) {
entry.surface->setFirstTransaction(nullptr);
entry.surface->setLastTransaction(nullptr);
} else {
Transaction *nextTransaction = entry.nextTransaction;
entry.surface->setFirstTransaction(nextTransaction);
nextTransaction->tryApply();
if (entry.surface) {
if (entry.surface->lastTransaction() == this) {
entry.surface->setFirstTransaction(nullptr);
entry.surface->setLastTransaction(nullptr);
} else {
entry.surface->setFirstTransaction(entry.nextTransaction);
}
}
if (entry.nextTransaction) {
entry.nextTransaction->tryApply();
}
}

View file

@ -8,6 +8,8 @@
#include "core/graphicsbuffer.h"
#include <QPointer>
#include <functional>
#include <memory>
#include <vector>
@ -25,9 +27,11 @@ class Transaction;
struct TransactionEntry
{
/**
* The surface that is going to be affected by the transaction.
* The surface that is going to be affected by the transaction. Might be
* \c null if the surface has been destroyed while the transaction is still
* not ready.
*/
SurfaceInterface *surface = nullptr;
QPointer<SurfaceInterface> surface;
/**
* Next transaction that is going to affect the surface.
@ -81,11 +85,6 @@ public:
*/
void add(SurfaceInterface *surface);
/**
* Removes the specified \a surface from this transaction.
*/
void remove(SurfaceInterface *surface);
/**
* Amends already committed state.
*/