scene/workspacescene: do occlusion testing for direct scanout

Some clients have two or more completely opaque surfaces stacked on top of each other,
optimizing the lower ones out makes direct scanout happen more often and more efficiently
when multiple planes are involved
This commit is contained in:
Xaver Hugl 2024-08-02 20:46:39 +02:00
parent 4ebb8530e6
commit def0bde5e9

View file

@ -151,12 +151,15 @@ Item *WorkspaceScene::overlayItem() const
return m_overlayItem.get();
}
static bool addCandidates(SurfaceItem *item, QList<SurfaceItem *> &candidates, ssize_t maxCount)
static bool addCandidates(SurfaceItem *item, QList<SurfaceItem *> &candidates, ssize_t maxCount, QRegion &occluded)
{
const QList<Item *> children = item->sortedChildItems();
for (const auto &child : children | std::views::reverse) {
if (child->z() >= 0 && child->isVisible()) {
if (!addCandidates(static_cast<SurfaceItem *>(child), candidates, maxCount)) {
if (child->z() < 0) {
break;
}
if (child->isVisible() && !occluded.contains(child->mapToScene(child->boundingRect()).toAlignedRect())) {
if (!addCandidates(static_cast<SurfaceItem *>(child), candidates, maxCount, occluded)) {
return false;
}
}
@ -165,9 +168,13 @@ static bool addCandidates(SurfaceItem *item, QList<SurfaceItem *> &candidates, s
return false;
}
candidates.push_back(item);
occluded += item->mapToScene(item->opaque());
for (const auto &child : children | std::views::reverse) {
if (child->z() < 0 && child->isVisible()) {
if (!addCandidates(static_cast<SurfaceItem *>(child), candidates, maxCount)) {
if (child->z() >= 0) {
continue;
}
if (child->isVisible() && !occluded.contains(child->mapToScene(child->boundingRect()).toAlignedRect())) {
if (!addCandidates(static_cast<SurfaceItem *>(child), candidates, maxCount, occluded)) {
return false;
}
}
@ -192,7 +199,8 @@ QList<SurfaceItem *> WorkspaceScene::scanoutCandidates(ssize_t maxCount) const
if (!windowItem->surfaceItem()) {
continue;
}
if (!addCandidates(windowItem->surfaceItem(), ret, maxCount)) {
QRegion occlusion;
if (!addCandidates(windowItem->surfaceItem(), ret, maxCount, occlusion)) {
return {};
}
return ret;