You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

229 lines
8.7 KiB

/*
SPDX-FileCopyrightText: 2024 Xaver Hugl <xaver.hugl@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "kwin_wayland_test.h"
#include "core/colorpipeline.h"
#include "core/output.h"
#include "core/outputbackend.h"
#include "core/outputconfiguration.h"
#include "outputconfigurationstore.h"
#include "pointer_input.h"
#include "tiles/tilemanager.h"
#include "wayland/surface.h"
#include "wayland_server.h"
#include "window.h"
#include "workspace.h"
#include <KWayland/Client/connection_thread.h>
#include <KWayland/Client/surface.h>
#include <format>
#include "qwayland-xx-color-management-v4.h"
using namespace std::chrono_literals;
namespace KWin
{
static const QString s_socketName = QStringLiteral("wayland_test_color_management-0");
class ImageDescription : public QObject, public QtWayland::xx_image_description_v4
{
Q_OBJECT
public:
explicit ImageDescription(::xx_image_description_v4 *descr)
: QtWayland::xx_image_description_v4(descr)
{
}
~ImageDescription() override
{
xx_image_description_v4_destroy(object());
}
void xx_image_description_v4_ready(uint32_t identity) override
{
Q_EMIT ready();
}
Q_SIGNALS:
void ready();
};
class ColorManagementSurface : public QObject, public QtWayland::xx_color_management_surface_v4
{
Q_OBJECT
public:
explicit ColorManagementSurface(::xx_color_management_surface_v4 *obj)
: QtWayland::xx_color_management_surface_v4(obj)
{
}
~ColorManagementSurface() override
{
xx_color_management_surface_v4_destroy(object());
}
};
class ColorManagementTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void initTestCase();
void init();
void cleanup();
void testSetImageDescription_data();
void testSetImageDescription();
void testUnsupportedPrimaries();
void testNoPrimaries();
void testNoTf();
};
void ColorManagementTest::initTestCase()
{
qRegisterMetaType<Window *>();
QVERIFY(waylandServer()->init(s_socketName));
Test::setOutputConfig({
QRect(0, 0, 1280, 1024),
QRect(1280, 0, 1280, 1024),
});
kwinApp()->start();
const auto outputs = workspace()->outputs();
QCOMPARE(outputs.count(), 2);
QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024));
QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024));
}
void ColorManagementTest::init()
{
Test::setOutputConfig({
QRect(0, 0, 1280, 1024),
QRect(1280, 0, 1280, 1024),
});
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::ColorManagement));
workspace()->setActiveOutput(QPoint(640, 512));
input()->pointer()->warp(QPoint(640, 512));
}
void ColorManagementTest::cleanup()
{
Test::destroyWaylandConnection();
}
void ColorManagementTest::testSetImageDescription_data()
{
QTest::addColumn<ColorDescription>("input");
QTest::addColumn<bool>("protocolError");
QTest::addRow("sRGB") << ColorDescription::sRGB << false;
QTest::addRow("rec.2020 PQ") << ColorDescription(NamedColorimetry::BT2020, TransferFunction(TransferFunction::PerceptualQuantizer), 203, 0, 400, 400) << false;
QTest::addRow("scRGB") << ColorDescription(NamedColorimetry::BT709, TransferFunction(TransferFunction::linear, 0, 80), 80, 0, 80, 80) << false;
QTest::addRow("custom") << ColorDescription(NamedColorimetry::BT2020, TransferFunction(TransferFunction::gamma22, 0.05, 400), 203, 0, 400, 400) << false;
QTest::addRow("invalid tf") << ColorDescription(NamedColorimetry::BT2020, TransferFunction(TransferFunction::gamma22, 204, 205), 203, 0, 400, 400) << true;
// TODO this should fail with the wp protocol version
QTest::addRow("invalid HDR metadata") << ColorDescription(NamedColorimetry::BT2020, TransferFunction(TransferFunction::PerceptualQuantizer), 203, 500, 400, 400) << false;
}
void ColorManagementTest::testSetImageDescription()
{
std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
QVERIFY(window);
auto cmSurf = std::make_unique<ColorManagementSurface>(Test::colorManager()->get_surface(*surface));
QtWayland::xx_image_description_creator_params_v4 creator(Test::colorManager()->new_parametric_creator());
QFETCH(ColorDescription, input);
creator.set_primaries(std::round(10'000 * input.containerColorimetry().red().toxyY().x),
std::round(10'000 * input.containerColorimetry().red().toxyY().y),
std::round(10'000 * input.containerColorimetry().green().toxyY().x),
std::round(10'000 * input.containerColorimetry().green().toxyY().y),
std::round(10'000 * input.containerColorimetry().blue().toxyY().x),
std::round(10'000 * input.containerColorimetry().blue().toxyY().y),
std::round(10'000 * input.containerColorimetry().white().toxyY().x),
std::round(10'000 * input.containerColorimetry().white().toxyY().y));
switch (input.transferFunction().type) {
case TransferFunction::sRGB:
creator.set_tf_named(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB);
creator.set_luminances(std::round(input.transferFunction().minLuminance * 10'000), std::round(input.transferFunction().maxLuminance), std::round(input.referenceLuminance()));
break;
case TransferFunction::gamma22:
creator.set_tf_named(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_GAMMA22);
creator.set_luminances(std::round(input.transferFunction().minLuminance * 10'000), std::round(input.transferFunction().maxLuminance), std::round(input.referenceLuminance()));
break;
case TransferFunction::linear:
creator.set_tf_named(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_LINEAR);
creator.set_luminances(std::round(input.transferFunction().minLuminance * 10'000), std::round(input.transferFunction().maxLuminance), std::round(input.referenceLuminance()));
break;
case TransferFunction::PerceptualQuantizer:
creator.set_tf_named(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ);
creator.set_max_fall(std::round(input.maxAverageLuminance().value_or(0)));
creator.set_max_cll(std::round(input.maxHdrLuminance().value_or(0)));
break;
}
creator.set_mastering_luminance(std::round(input.minLuminance() * 10'000), std::round(input.maxHdrLuminance().value_or(0)));
ImageDescription imageDescr(xx_image_description_creator_params_v4_create(creator.object()));
QFETCH(bool, protocolError);
if (protocolError) {
QSignalSpy error(Test::waylandConnection(), &KWayland::Client::ConnectionThread::errorOccurred);
QVERIFY(error.wait(50ms));
return;
}
QSignalSpy ready(&imageDescr, &ImageDescription::ready);
QVERIFY(ready.wait(50ms));
cmSurf->set_image_description(imageDescr.object(), XX_COLOR_MANAGER_V4_RENDER_INTENT_PERCEPTUAL);
surface->commit(KWayland::Client::Surface::CommitFlag::None);
QSignalSpy colorChange(window->surface(), &SurfaceInterface::colorDescriptionChanged);
QVERIFY(colorChange.wait());
QCOMPARE(window->surface()->colorDescription(), input);
}
void ColorManagementTest::testUnsupportedPrimaries()
{
QtWayland::xx_image_description_creator_params_v4 creator = QtWayland::xx_image_description_creator_params_v4(Test::colorManager()->new_parametric_creator());
creator.set_primaries_named(-1);
xx_image_description_creator_params_v4_create(creator.object());
QSignalSpy error(Test::waylandConnection(), &KWayland::Client::ConnectionThread::errorOccurred);
QVERIFY(error.wait(50ms));
}
void ColorManagementTest::testNoPrimaries()
{
QtWayland::xx_image_description_creator_params_v4 creator = QtWayland::xx_image_description_creator_params_v4(Test::colorManager()->new_parametric_creator());
creator.set_tf_named(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_LINEAR);
xx_image_description_creator_params_v4_create(creator.object());
QSignalSpy error(Test::waylandConnection(), &KWayland::Client::ConnectionThread::errorOccurred);
QVERIFY(error.wait(50ms));
}
void ColorManagementTest::testNoTf()
{
QtWayland::xx_image_description_creator_params_v4 creator = QtWayland::xx_image_description_creator_params_v4(Test::colorManager()->new_parametric_creator());
creator.set_primaries_named(XX_COLOR_MANAGER_V4_PRIMARIES_CIE1931_XYZ);
xx_image_description_creator_params_v4_create(creator.object());
QSignalSpy error(Test::waylandConnection(), &KWayland::Client::ConnectionThread::errorOccurred);
QVERIFY(error.wait(50ms));
}
} // namespace KWin
WAYLANDTEST_MAIN(KWin::ColorManagementTest)
#include "test_colormanagement.moc"