Commit de2c4cb4 authored by Vlad Zahorodnii's avatar Vlad Zahorodnii
Browse files

[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.
parent 9e797cf9
......@@ -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;
}
......
......@@ -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();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment