[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:
parent
9e797cf943
commit
de2c4cb4ac
4 changed files with 28 additions and 14 deletions
|
@ -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 ®ion, 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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue