Commit f1491e00 authored by David Edmundson's avatar David Edmundson
Browse files

Treat input RGB buffers as premultiplied

Summary:
Currently the server treats incoming buffers as not premultiplied.

KWayland::Client sends data that is ARGB32 and ARGB32_Premultiplied as
the same
WL_SHM_FORMAT_ARGB8888.

According to a post on wayland-devel by Fredrik Höglund, all RGB data
should be treated as premultiplied, which matches what Qt is doing.

Client now performs a conversion rather than sending
mismatched data,

Note: This commit will still breaks a bunch of tests in
kwin as it compares the server output to a fixed
QImage with a format.

Test Plan:
Existing tests pass

Modified surface test to check the pixel data relative to the output
QImage format
not the input format (i.e both input from ARGB32 and
ARGB32_Premultiplied) should
both end up in a QImage with format Premultiplied with premultiplied
values.

The existing test was confirming that data was corrupted, checking that
even though
the output format was not pre-multiplied, the data was.

Reviewers: #plasma, graesslin

Reviewed By: #plasma, graesslin

Subscribers: plasma-devel, #frameworks

Tags: #plasma_on_wayland, #frameworks

Differential Revision: https://phabricator.kde.org/D7460
parent 9b564c40
......@@ -187,7 +187,7 @@ KWayland::Client::Surface *TestDragAndDrop::createSurface()
using namespace KWayland::Client;
auto s = m_compositor->createSurface();
QImage img(QSize(100, 200), QImage::Format_ARGB32);
QImage img(QSize(100, 200), QImage::Format_RGB32);
img.fill(Qt::red);
s->attachBuffer(m_shm->createBuffer(img));
s->damage(QRect(0, 0, 100, 200));
......
......@@ -204,28 +204,28 @@ void ShadowTest::testShadowElements()
// now create the shadow
QScopedPointer<Shadow> shadow(m_shadow->createShadow(surface.data()));
QImage topLeftImage(QSize(10, 10), QImage::Format_ARGB32);
QImage topLeftImage(QSize(10, 10), QImage::Format_ARGB32_Premultiplied);
topLeftImage.fill(Qt::white);
shadow->attachTopLeft(m_shm->createBuffer(topLeftImage));
QImage topImage(QSize(11, 11), QImage::Format_ARGB32);
QImage topImage(QSize(11, 11), QImage::Format_ARGB32_Premultiplied);
topImage.fill(Qt::black);
shadow->attachTop(m_shm->createBuffer(topImage));
QImage topRightImage(QSize(12, 12), QImage::Format_ARGB32);
QImage topRightImage(QSize(12, 12), QImage::Format_ARGB32_Premultiplied);
topRightImage.fill(Qt::red);
shadow->attachTopRight(m_shm->createBuffer(topRightImage));
QImage rightImage(QSize(13, 13), QImage::Format_ARGB32);
QImage rightImage(QSize(13, 13), QImage::Format_ARGB32_Premultiplied);
rightImage.fill(Qt::darkRed);
shadow->attachRight(m_shm->createBuffer(rightImage));
QImage bottomRightImage(QSize(14, 14), QImage::Format_ARGB32);
QImage bottomRightImage(QSize(14, 14), QImage::Format_ARGB32_Premultiplied);
bottomRightImage.fill(Qt::green);
shadow->attachBottomRight(m_shm->createBuffer(bottomRightImage));
QImage bottomImage(QSize(15, 15), QImage::Format_ARGB32);
QImage bottomImage(QSize(15, 15), QImage::Format_ARGB32_Premultiplied);
bottomImage.fill(Qt::darkGreen);
shadow->attachBottom(m_shm->createBuffer(bottomImage));
QImage bottomLeftImage(QSize(16, 16), QImage::Format_ARGB32);
QImage bottomLeftImage(QSize(16, 16), QImage::Format_ARGB32_Premultiplied);
bottomLeftImage.fill(Qt::blue);
shadow->attachBottomLeft(m_shm->createBuffer(bottomLeftImage));
QImage leftImage(QSize(17, 17), QImage::Format_ARGB32);
QImage leftImage(QSize(17, 17), QImage::Format_ARGB32_Premultiplied);
leftImage.fill(Qt::darkBlue);
shadow->attachLeft(m_shm->createBuffer(leftImage));
shadow->setOffsets(QMarginsF(1, 2, 3, 4));
......
......@@ -44,6 +44,7 @@ private Q_SLOTS:
void testCreateBufferNullSize();
void testCreateBufferInvalidSize();
void testCreateBufferFromImage();
void testCreateBufferFromImageWithAlpha();
void testCreateBufferFromData();
void testReuseBuffer();
void testDestroy();
......@@ -154,33 +155,46 @@ void TestShmPool::testCreateBufferInvalidSize()
void TestShmPool::testCreateBufferFromImage()
{
QVERIFY(m_shmPool->isValid());
QImage img(24, 24, QImage::Format_ARGB32);
QImage img(24, 24, QImage::Format_RGB32);
img.fill(Qt::black);
QVERIFY(!img.isNull());
auto buffer = m_shmPool->createBuffer(img).toStrongRef();
QVERIFY(buffer);
QCOMPARE(buffer->size(), img.size());
QImage img2(buffer->address(), img.width(), img.height(), QImage::Format_ARGB32);
QImage img2(buffer->address(), img.width(), img.height(), QImage::Format_RGB32);
QCOMPARE(img2, img);
}
void TestShmPool::testCreateBufferFromImageWithAlpha()
{
QVERIFY(m_shmPool->isValid());
QImage img(24, 24, QImage::Format_ARGB32_Premultiplied);
img.fill(QColor(255,0,0,100)); //red with alpha
QVERIFY(!img.isNull());
auto buffer = m_shmPool->createBuffer(img).toStrongRef();
QVERIFY(buffer);
QCOMPARE(buffer->size(), img.size());
QImage img2(buffer->address(), img.width(), img.height(), QImage::Format_ARGB32_Premultiplied);
QCOMPARE(img2, img);
}
void TestShmPool::testCreateBufferFromData()
{
QVERIFY(m_shmPool->isValid());
QImage img(24, 24, QImage::Format_ARGB32);
QImage img(24, 24, QImage::Format_ARGB32_Premultiplied);
img.fill(Qt::black);
QVERIFY(!img.isNull());
auto buffer = m_shmPool->createBuffer(img.size(), img.bytesPerLine(), img.constBits()).toStrongRef();
QVERIFY(buffer);
QCOMPARE(buffer->size(), img.size());
QImage img2(buffer->address(), img.width(), img.height(), QImage::Format_ARGB32);
QImage img2(buffer->address(), img.width(), img.height(), QImage::Format_ARGB32_Premultiplied);
QCOMPARE(img2, img);
}
void TestShmPool::testReuseBuffer()
{
QVERIFY(m_shmPool->isValid());
QImage img(24, 24, QImage::Format_ARGB32);
QImage img(24, 24, QImage::Format_ARGB32_Premultiplied);
img.fill(Qt::black);
QVERIFY(!img.isNull());
auto buffer = m_shmPool->createBuffer(img).toStrongRef();
......
......@@ -830,7 +830,7 @@ void TestWaylandSeat::testPointerSubSurfaceTree()
// let's map the surfaces
auto render = [this] (Surface *s, const QSize &size) {
QImage image(size, QImage::Format_ARGB32);
QImage image(size, QImage::Format_ARGB32_Premultiplied);
image.fill(Qt::black);
s->attachBuffer(m_shm->createBuffer(image));
s->damage(QRect(QPoint(0, 0), size));
......@@ -1171,7 +1171,7 @@ void TestWaylandSeat::testKeyboardSubSurfaceTreeFromPointer()
// let's map the surfaces
auto render = [this] (Surface *s, const QSize &size) {
QImage image(size, QImage::Format_ARGB32);
QImage image(size, QImage::Format_ARGB32_Premultiplied);
image.fill(Qt::black);
s->attachBuffer(m_shm->createBuffer(image));
s->damage(QRect(QPoint(0, 0), size));
......@@ -1328,7 +1328,7 @@ void TestWaylandSeat::testCursor()
QCOMPARE(cursor->surface()->buffer()->data(), img);
// and add another image to the surface
QImage blue(QSize(10, 20), QImage::Format_ARGB32);
QImage blue(QSize(10, 20), QImage::Format_ARGB32_Premultiplied);
blue.fill(Qt::blue);
cursorSurface->attachBuffer(m_shm->createBuffer(blue));
cursorSurface->damage(QRect(0, 0, 10, 20));
......@@ -1382,7 +1382,7 @@ void TestWaylandSeat::testCursorDamage()
// now let's set the cursor
Surface *cursorSurface = m_compositor->createSurface(m_compositor);
QVERIFY(cursorSurface);
QImage red(QSize(10, 10), QImage::Format_ARGB32);
QImage red(QSize(10, 10), QImage::Format_ARGB32_Premultiplied);
red.fill(Qt::red);
cursorSurface->attachBuffer(m_shm->createBuffer(red));
cursorSurface->damage(QRect(0, 0, 10, 10));
......@@ -1392,7 +1392,7 @@ void TestWaylandSeat::testCursorDamage()
QCOMPARE(pointer->cursor()->surface()->buffer()->data(), red);
// and damage the surface
QImage blue(QSize(10, 10), QImage::Format_ARGB32);
QImage blue(QSize(10, 10), QImage::Format_ARGB32_Premultiplied);
blue.fill(Qt::blue);
cursorSurface->attachBuffer(m_shm->createBuffer(blue));
cursorSurface->damage(QRect(0, 0, 10, 10));
......
......@@ -619,7 +619,7 @@ void TestSubSurface::testSyncMode()
QSignalSpy childDamagedSpy(childSurface, &SurfaceInterface::damaged);
QVERIFY(childDamagedSpy.isValid());
QImage image(QSize(200, 200), QImage::Format_ARGB32);
QImage image(QSize(200, 200), QImage::Format_ARGB32_Premultiplied);
image.fill(Qt::black);
surface->attachBuffer(m_shm->createBuffer(image));
surface->damage(QRect(0, 0, 200, 200));
......@@ -632,7 +632,7 @@ void TestSubSurface::testSyncMode()
QVERIFY(!childSurface->isMapped());
QVERIFY(!parentSurface->isMapped());
QImage image2(QSize(400, 400), QImage::Format_ARGB32);
QImage image2(QSize(400, 400), QImage::Format_ARGB32_Premultiplied);
image2.fill(Qt::red);
parent->attachBuffer(m_shm->createBuffer(image2));
parent->damage(QRect(0, 0, 400, 400));
......@@ -681,7 +681,7 @@ void TestSubSurface::testDeSyncMode()
QSignalSpy childDamagedSpy(childSurface, &SurfaceInterface::damaged);
QVERIFY(childDamagedSpy.isValid());
QImage image(QSize(200, 200), QImage::Format_ARGB32);
QImage image(QSize(200, 200), QImage::Format_ARGB32_Premultiplied);
image.fill(Qt::black);
surface->attachBuffer(m_shm->createBuffer(image));
surface->damage(QRect(0, 0, 200, 200));
......@@ -853,7 +853,7 @@ void TestSubSurface::testMappingOfSurfaceTree()
// first map the child, should not map it
QSignalSpy child3DamageSpy(child3->surface().data(), &SurfaceInterface::damaged);
QVERIFY(child3DamageSpy.isValid());
QImage image(QSize(200, 200), QImage::Format_ARGB32);
QImage image(QSize(200, 200), QImage::Format_ARGB32_Premultiplied);
image.fill(Qt::black);
childLevel3Surface->attachBuffer(m_shm->createBuffer(image));
childLevel3Surface->damage(QRect(0, 0, 200, 200));
......@@ -1025,7 +1025,7 @@ void TestSubSurface::testDestroyAttachedBuffer()
m_subCompositor->createSubSurface(child.data(), parent.data());
// let's damage this surface, will be in sub-surface pending state
QImage image(QSize(100, 100), QImage::Format_ARGB32);
QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied);
image.fill(Qt::red);
child->attachBuffer(m_shm->createBuffer(image));
child->damage(QRect(0, 0, 100, 100));
......
......@@ -261,7 +261,7 @@ void TestWaylandSurface::testDamage()
QVERIFY(damageSpy.isEmpty());
QVERIFY(!serverSurface->isMapped());
QImage img(QSize(10, 10), QImage::Format_ARGB32);
QImage img(QSize(10, 10), QImage::Format_ARGB32_Premultiplied);
img.fill(Qt::black);
auto b = m_shm->createBuffer(img);
s->attachBuffer(b);
......@@ -275,7 +275,7 @@ void TestWaylandSurface::testDamage()
// damage multiple times
QRegion testRegion(5, 8, 3, 6);
testRegion = testRegion.united(QRect(10, 20, 30, 15));
img = QImage(QSize(40, 35), QImage::Format_ARGB32);
img = QImage(QSize(40, 35), QImage::Format_ARGB32_Premultiplied);
img.fill(Qt::black);
b = m_shm->createBuffer(img);
s->attachBuffer(b);
......@@ -302,7 +302,7 @@ void TestWaylandSurface::testFrameCallback()
QSignalSpy frameRenderedSpy(s, SIGNAL(frameRendered()));
QVERIFY(frameRenderedSpy.isValid());
QImage img(QSize(10, 10), QImage::Format_ARGB32);
QImage img(QSize(10, 10), QImage::Format_ARGB32_Premultiplied);
img.fill(Qt::black);
auto b = m_shm->createBuffer(img);
s->attachBuffer(b);
......@@ -325,10 +325,10 @@ void TestWaylandSurface::testAttachBuffer()
KWayland::Server::SurfaceInterface *serverSurface = serverSurfaceCreated.first().first().value<KWayland::Server::SurfaceInterface*>();
QVERIFY(serverSurface);
// create two images
// create three images
QImage black(24, 24, QImage::Format_RGB32);
black.fill(Qt::black);
QImage red(24, 24, QImage::Format_ARGB32);
QImage red(24, 24, QImage::Format_ARGB32); //Note - deliberately not premultiplied
red.fill(QColor(255, 0, 0, 128));
QImage blue(24, 24, QImage::Format_ARGB32_Premultiplied);
blue.fill(QColor(0, 0, 255, 128));
......@@ -371,8 +371,15 @@ void TestWaylandSurface::testAttachBuffer()
KWayland::Server::BufferInterface *buffer2 = serverSurface->buffer();
buffer2->ref();
QVERIFY(buffer2->shmBuffer());
QCOMPARE(buffer2->data(), red);
QCOMPARE(buffer2->data().format(), QImage::Format_ARGB32);
QCOMPARE(buffer2->data().format(), QImage::Format_ARGB32_Premultiplied);
QCOMPARE(buffer2->data().width(), 24);
QCOMPARE(buffer2->data().height(), 24);
for (int i = 0; i < 24; ++i) {
for (int j = 0; j < 24; ++j) {
// it's premultiplied in the format
QCOMPARE(buffer2->data().pixel(i, j), qRgba(128, 0, 0, 128));
}
}
buffer2->unref();
QVERIFY(buffer2->isReferenced());
QVERIFY(!redBuffer.data()->isReleased());
......@@ -400,7 +407,7 @@ void TestWaylandSurface::testAttachBuffer()
KWayland::Server::BufferInterface *buffer3 = serverSurface->buffer();
buffer3->ref();
QVERIFY(buffer3->shmBuffer());
QCOMPARE(buffer3->data().format(), QImage::Format_ARGB32);
QCOMPARE(buffer3->data().format(), QImage::Format_ARGB32_Premultiplied);
QCOMPARE(buffer3->data().width(), 24);
QCOMPARE(buffer3->data().height(), 24);
for (int i = 0; i < 24; ++i) {
......@@ -482,7 +489,7 @@ void TestWaylandSurface::testMultipleSurfaces()
// create two images
QImage black(24, 24, QImage::Format_RGB32);
black.fill(Qt::black);
QImage red(24, 24, QImage::Format_ARGB32);
QImage red(24, 24, QImage::Format_ARGB32_Premultiplied);
red.fill(QColor(255, 0, 0, 128));
auto blackBuffer = pool1.createBuffer(black);
......@@ -707,7 +714,7 @@ void TestWaylandSurface::testScale()
scaleChangedSpy.clear();
//attach a buffer of 100x100, our scale is 4, so this should be a size of 25x25
QImage red(100, 100, QImage::Format_ARGB32);
QImage red(100, 100, QImage::Format_ARGB32_Premultiplied);
red.fill(QColor(255, 0, 0, 128));
auto redBuffer = m_shm->createBuffer(red);
s->attachBuffer(redBuffer.data());
......@@ -731,7 +738,7 @@ void TestWaylandSurface::testScale()
scaleChangedSpy.clear();
//set scale and size in one commit, buffer is 50x50 at scale 2 so size should be 25x25
QImage blue(50, 50, QImage::Format_ARGB32);
QImage blue(50, 50, QImage::Format_ARGB32_Premultiplied);
red.fill(QColor(255, 0, 0, 128));
auto blueBuffer = m_shm->createBuffer(blue);
s->attachBuffer(blueBuffer.data());
......@@ -907,7 +914,7 @@ void TestWaylandSurface::testDestroyAttachedBuffer()
// let's damage this surface
QSignalSpy damagedSpy(serverSurface, &SurfaceInterface::damaged);
QVERIFY(damagedSpy.isValid());
QImage image(QSize(100, 100), QImage::Format_ARGB32);
QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied);
image.fill(Qt::red);
s->attachBuffer(m_shm->createBuffer(image));
s->damage(QRect(0, 0, 100, 100));
......@@ -948,7 +955,7 @@ void TestWaylandSurface::testDestroyWithPendingCallback()
QVERIFY(serverSurface);
// now render to it
QImage img(QSize(10, 10), QImage::Format_ARGB32);
QImage img(QSize(10, 10), QImage::Format_ARGB32_Premultiplied);
img.fill(Qt::black);
auto b = m_shm->createBuffer(img);
s->attachBuffer(b);
......
......@@ -224,7 +224,7 @@ QImage::Format BufferInterface::Private::format() const
}
switch (wl_shm_buffer_get_format(shmBuffer)) {
case WL_SHM_FORMAT_ARGB8888:
return QImage::Format_ARGB32;
return QImage::Format_ARGB32_Premultiplied;
case WL_SHM_FORMAT_XRGB8888:
return QImage::Format_RGB32;
default:
......
Supports Markdown
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