Improvements for direct scanout

Instead of cancelling direct scanout if the client buffer is not
fitting, adjust the atomic planes. Also ignore all toplevels from
other screens.
This commit is contained in:
Xaver Hugl 2021-02-23 15:25:28 +01:00
parent 4638f2f309
commit 7cc95d931b
3 changed files with 33 additions and 22 deletions

View file

@ -955,14 +955,23 @@ bool DrmOutput::atomicReqModesetPopulate(drmModeAtomicReq *req, bool enable)
{
if (enable) {
const QSize mSize = modeSize();
const QSize sourceSize = hardwareTransforms() ? pixelSize() : mSize;
const QSize bufferSize = m_primaryPlane->next() ? m_primaryPlane->next()->size() : pixelSize();
const QSize sourceSize = hardwareTransforms() ? bufferSize : mSize;
QRect targetRect = QRect(QPoint(0, 0), mSize);
if (mSize != sourceSize) {
targetRect.setSize(sourceSize.scaled(mSize, Qt::AspectRatioMode::KeepAspectRatio));
targetRect.setX((mSize.width() - targetRect.width()) / 2);
targetRect.setY((mSize.height() - targetRect.height()) / 2);
}
m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::SrcX), 0);
m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::SrcY), 0);
m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::SrcW), sourceSize.width() << 16);
m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::SrcH), sourceSize.height() << 16);
m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::CrtcW), mSize.width());
m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::CrtcH), mSize.height());
m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::CrtcX), targetRect.x());
m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::CrtcY), targetRect.y());
m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::CrtcW), targetRect.width());
m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::CrtcH), targetRect.height());
m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::CrtcId), m_crtc->id());
} else {
if (m_gpu->deleteBufferAfterPageFlip()) {
@ -976,6 +985,8 @@ bool DrmOutput::atomicReqModesetPopulate(drmModeAtomicReq *req, bool enable)
m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::SrcY), 0);
m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::SrcW), 0);
m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::SrcH), 0);
m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::CrtcX), 0);
m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::CrtcY), 0);
m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::CrtcW), 0);
m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::CrtcH), 0);
m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::CrtcId), 0);

View file

@ -698,7 +698,8 @@ bool EglGbmBackend::scanout(int screenId, KWaylandServer::SurfaceInterface *surf
}
auto buffer = surface->buffer();
Output output = m_outputs[screenId];
if (buffer->linuxDmabufBuffer()->size() != output.output->modeSize()) {
if (buffer->linuxDmabufBuffer()->size() != output.output->modeSize()
&& output.output->isBeingRecorded()) {
return false;
}
EglDmabufBuffer *dmabuf = static_cast<EglDmabufBuffer*>(buffer->linuxDmabufBuffer());
@ -739,7 +740,7 @@ bool EglGbmBackend::scanout(int screenId, KWaylandServer::SurfaceInterface *surf
}
// damage tracking for screen casting
QRegion damage;
if (output.surfaceInterface == surface) {
if (output.surfaceInterface == surface && buffer->size() == output.output->modeSize()) {
QRegion trackedDamage = surface->trackedDamage();
surface->resetTrackedDamage();
for (const auto &rect : trackedDamage) {

View file

@ -638,24 +638,23 @@ void SceneOpenGL::paint(int screenId, const QRegion &damage, const QList<Topleve
if (!implEffects->blocksDirectScanout()) {
for (int i = stacking_order.count() - 1; i >= 0; i--) {
Window *window = stacking_order[i];
AbstractClient *c = dynamic_cast<AbstractClient*>(window->window());
if (!c) {
break;
}
if (c->isOnScreen(screenId)) {
if (window->isOpaque() && c->isFullScreen()) {
auto pixmap = window->windowPixmap<WindowPixmap>();
if (!pixmap) {
break;
}
pixmap->update();
pixmap = pixmap->topMostSurface();
// the subsurface has to be able to cover the whole window
if (pixmap->position() != QPoint(0, 0)) {
break;
}
directScanout = m_backend->scanout(screenId, pixmap->surface());
Toplevel *toplevel = window->window();
if (toplevel->isOnScreen(screenId)) {
AbstractClient *c = dynamic_cast<AbstractClient*>(toplevel);
if (!c || !c->isFullScreen() || !window->isOpaque()) {
break;
}
auto pixmap = window->windowPixmap<WindowPixmap>();
if (!pixmap) {
break;
}
pixmap->update();
pixmap = pixmap->topMostSurface();
// the subsurface has to be able to cover the whole window
if (pixmap->position() != QPoint(0, 0)) {
break;
}
directScanout = m_backend->scanout(screenId, pixmap->surface());
break;
}
}