[wayland] Add support for cropped and scaled surfaces

The wp_viewporter compositor extension allows clients to crop and scale
their surfaces. It can be especially useful for applications wishing to
reduce their power consumption, e.g. video players, etc.

Given that there is no any direct relationship between the surface size
and the buffer size anymore, we have to use specialized helper methods
for converting coordinates from the surface-local space to buffer pixel
space and vice versa.
This commit is contained in:
Vlad Zahorodnii 2020-05-23 21:19:11 +03:00
parent 9e797cf943
commit de2c4cb4ac
4 changed files with 28 additions and 14 deletions

View file

@ -419,11 +419,11 @@ void AbstractEglTexture::updateTexture(WindowPixmap *pixmap)
return;
}
Q_ASSERT(image.size() == m_size);
const QRegion damage = s->trackedDamage();
const QRegion damage = s->mapToBuffer(s->trackedDamage());
s->resetTrackedDamage();
// TODO: this should be shared with GLTexture::update
createTextureSubImage(s->scale(), image, damage);
createTextureSubImage(image, damage);
}
bool AbstractEglTexture::createTextureImage(const QImage &image)
@ -471,31 +471,28 @@ bool AbstractEglTexture::createTextureImage(const QImage &image)
return true;
}
void AbstractEglTexture::createTextureSubImage(int scale, const QImage &image, const QRegion &damage)
void AbstractEglTexture::createTextureSubImage(const QImage &image, const QRegion &damage)
{
q->bind();
if (GLPlatform::instance()->isGLES()) {
if (s_supportsARGB32 && (image.format() == QImage::Format_ARGB32 || image.format() == QImage::Format_ARGB32_Premultiplied)) {
const QImage im = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
for (const QRect &rect : damage) {
auto scaledRect = QRect(rect.x() * scale, rect.y() * scale, rect.width() * scale, rect.height() * scale);
glTexSubImage2D(m_target, 0, scaledRect.x(), scaledRect.y(), scaledRect.width(), scaledRect.height(),
GL_BGRA_EXT, GL_UNSIGNED_BYTE, im.copy(scaledRect).bits());
glTexSubImage2D(m_target, 0, rect.x(), rect.y(), rect.width(), rect.height(),
GL_BGRA_EXT, GL_UNSIGNED_BYTE, im.copy(rect).bits());
}
} else {
const QImage im = image.convertToFormat(QImage::Format_RGBA8888_Premultiplied);
for (const QRect &rect : damage) {
auto scaledRect = QRect(rect.x() * scale, rect.y() * scale, rect.width() * scale, rect.height() * scale);
glTexSubImage2D(m_target, 0, scaledRect.x(), scaledRect.y(), scaledRect.width(), scaledRect.height(),
GL_RGBA, GL_UNSIGNED_BYTE, im.copy(scaledRect).bits());
glTexSubImage2D(m_target, 0, rect.x(), rect.y(), rect.width(), rect.height(),
GL_RGBA, GL_UNSIGNED_BYTE, im.copy(rect).bits());
}
}
} else {
const QImage im = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
for (const QRect &rect : damage) {
auto scaledRect = QRect(rect.x() * scale, rect.y() * scale, rect.width() * scale, rect.height() * scale);
glTexSubImage2D(m_target, 0, scaledRect.x(), scaledRect.y(), scaledRect.width(), scaledRect.height(),
GL_BGRA, GL_UNSIGNED_BYTE, im.copy(scaledRect).bits());
glTexSubImage2D(m_target, 0, rect.x(), rect.y(), rect.width(), rect.height(),
GL_BGRA, GL_UNSIGNED_BYTE, im.copy(rect).bits());
}
}
q->unbind();
@ -602,6 +599,19 @@ bool AbstractEglTexture::updateFromFBO(const QSharedPointer<QOpenGLFramebufferOb
return true;
}
static QRegion scale(const QRegion &region, qreal scaleFactor)
{
if (scaleFactor == 1) {
return region;
}
QRegion scaled;
for (const QRect &rect : region) {
scaled += QRect(rect.topLeft() * scaleFactor, rect.size() * scaleFactor);
}
return scaled;
}
bool AbstractEglTexture::updateFromInternalImageObject(WindowPixmap *pixmap)
{
const QImage image = pixmap->internalImage();
@ -614,7 +624,7 @@ bool AbstractEglTexture::updateFromInternalImageObject(WindowPixmap *pixmap)
return loadInternalImageObject(pixmap);
}
createTextureSubImage(image.devicePixelRatio(), image, pixmap->toplevel()->damage());
createTextureSubImage(image, scale(pixmap->toplevel()->damage(), image.devicePixelRatio()));
return true;
}

View file

@ -108,7 +108,7 @@ protected:
}
private:
void createTextureSubImage(int scale, const QImage &image, const QRegion &damage);
void createTextureSubImage(const QImage &image, const QRegion &damage);
bool createTextureImage(const QImage &image);
bool loadShmTexture(const QPointer<KWaylandServer::BufferInterface> &buffer);
bool loadEglTexture(const QPointer<KWaylandServer::BufferInterface> &buffer);

View file

@ -422,6 +422,7 @@ void Scene::addToplevel(Toplevel *c)
connect(monitor, &SubSurfaceMonitor::subSurfaceUnmapped, this, discardQuads);
connect(c->surface(), &KWaylandServer::SurfaceInterface::scaleChanged, this, discardQuads);
connect(c->surface(), &KWaylandServer::SurfaceInterface::viewportChanged, this, discardQuads);
}
connect(c, &Toplevel::screenScaleChanged, this, discardQuads);
@ -1293,6 +1294,8 @@ QPointF WindowPixmap::mapToWindow(const QPointF &point) const
QPointF WindowPixmap::mapToBuffer(const QPointF &point) const
{
if (surface())
return surface()->mapToBuffer(point);
return point * scale();
}

View file

@ -359,6 +359,7 @@ bool WaylandServer::init(const QByteArray &socketName, InitializationFlags flags
}
);
m_display->createViewporter();
m_display->createShm();
m_seat = m_display->createSeat(m_display);
m_seat->create();