KWin
Loading...
Searching...
No Matches
xx_colormanagement_v2.cpp
Go to the documentation of this file.
1/*
2 SPDX-FileCopyrightText: 2024 Xaver Hugl <xaver.hugl@gmail.com>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5*/
7#include "display.h"
8#include "surface.h"
9#include "surface_p.h"
10#include "utils/resource.h"
11#include "wayland/output.h"
12
13namespace KWin
14{
15
17 : QObject(parent)
18 , QtWaylandServer::xx_color_manager_v2(*display, 1)
19{
20}
21
22void XXColorManagerV2::xx_color_manager_v2_bind_resource(Resource *resource)
23{
24 send_supported_feature(resource->handle, feature::feature_parametric);
25 send_supported_feature(resource->handle, feature::feature_extended_target_volume);
26 send_supported_feature(resource->handle, feature::feature_set_mastering_display_primaries);
27 send_supported_feature(resource->handle, feature::feature_set_primaries);
28
29 send_supported_primaries_named(resource->handle, primaries::primaries_srgb);
30 send_supported_primaries_named(resource->handle, primaries::primaries_bt2020);
31
32 send_supported_tf_named(resource->handle, transfer_function::transfer_function_bt709);
33 send_supported_tf_named(resource->handle, transfer_function::transfer_function_gamma22);
34 send_supported_tf_named(resource->handle, transfer_function::transfer_function_srgb);
35 send_supported_tf_named(resource->handle, transfer_function::transfer_function_st2084_pq);
36 // TODO scRGB?
37
38 send_supported_intent(resource->handle, render_intent::render_intent_perceptual);
39 send_supported_intent(resource->handle, render_intent::render_intent_relative);
40 // TODO implement the other rendering intents
41}
42
43void XXColorManagerV2::xx_color_manager_v2_destroy(Resource *resource)
44{
45 wl_resource_destroy(resource->handle);
46}
47
48void XXColorManagerV2::xx_color_manager_v2_get_output(Resource *resource, uint32_t id, struct ::wl_resource *output)
49{
50 new XXColorManagementOutputV2(resource->client(), id, resource->version(), OutputInterface::get(output)->handle());
51}
52
53void XXColorManagerV2::xx_color_manager_v2_get_surface(Resource *resource, uint32_t id, struct ::wl_resource *surface)
54{
55 const auto surf = SurfaceInterface::get(surface);
56 const auto priv = SurfaceInterfacePrivate::get(surf);
57 if (priv->frogColorManagement || priv->xxColorSurface) {
58 wl_resource_post_error(resource->handle, 0, "there's already a color management surface for this wl_surface");
59 return;
60 }
61 priv->xxColorSurface = new XXColorSurfaceV2(resource->client(), id, resource->version(), surf);
62}
63
64void XXColorManagerV2::xx_color_manager_v2_new_icc_creator(Resource *resource, uint32_t obj)
65{
66 wl_resource_post_error(resource->handle, error::error_unsupported_feature, "ICC profiles are not supported");
67}
68
69void XXColorManagerV2::xx_color_manager_v2_new_parametric_creator(Resource *resource, uint32_t obj)
70{
71 new XXColorParametricCreatorV2(resource->client(), obj, resource->version());
72}
73
74XXColorSurfaceV2::XXColorSurfaceV2(wl_client *client, uint32_t id, uint32_t version, SurfaceInterface *surface)
75 : QtWaylandServer::xx_color_management_surface_v2(client, id, version)
76 , m_surface(surface)
77 , m_preferred(SurfaceInterfacePrivate::get(surface)->preferredColorDescription.value_or(ColorDescription::sRGB))
78{
79}
80
82{
83 if (m_surface) {
84 const auto priv = SurfaceInterfacePrivate::get(m_surface);
85 priv->pending->colorDescription = ColorDescription::sRGB;
86 priv->pending->colorDescriptionIsSet = true;
87 priv->xxColorSurface = nullptr;
88 }
89}
90
92{
93 if (m_preferred != descr) {
94 m_preferred = descr;
95 send_preferred_changed(resource()->handle);
96 }
97}
98
99void XXColorSurfaceV2::xx_color_management_surface_v2_destroy_resource(Resource *resource)
100{
101 delete this;
102}
103
104void XXColorSurfaceV2::xx_color_management_surface_v2_destroy(Resource *resource)
105{
106 wl_resource_destroy(resource->handle);
107}
108
109void XXColorSurfaceV2::xx_color_management_surface_v2_set_image_description(Resource *resource, struct ::wl_resource *image_description, uint32_t render_intent)
110{
111 if (!m_surface) {
112 return;
113 }
114 const auto priv = SurfaceInterfacePrivate::get(m_surface);
115 priv->pending->colorDescription = XXImageDescriptionV2::get(image_description)->description();
116 priv->pending->colorDescriptionIsSet = true;
117 // TODO render_intent
118}
119
120void XXColorSurfaceV2::xx_color_management_surface_v2_unset_image_description(Resource *resource)
121{
122 if (!m_surface) {
123 return;
124 }
125 const auto priv = SurfaceInterfacePrivate::get(m_surface);
126 priv->pending->colorDescription = ColorDescription::sRGB;
127 priv->pending->colorDescriptionIsSet = true;
128}
129
130void XXColorSurfaceV2::xx_color_management_surface_v2_get_preferred(Resource *resource, uint32_t image_description)
131{
132 new XXImageDescriptionV2(resource->client(), image_description, resource->version(), m_preferred);
133}
134
136 : QtWaylandServer::xx_image_description_creator_params_v2(client, id, version)
137{
138}
139
140void XXColorParametricCreatorV2::xx_image_description_creator_params_v2_destroy_resource(Resource *resource)
141{
142 delete this;
143}
144
145void XXColorParametricCreatorV2::xx_image_description_creator_params_v2_create(Resource *resource, uint32_t image_description)
146{
147 if (!m_colorimetry || !m_transferFunction) {
148 wl_resource_post_error(resource->handle, error::error_incomplete_set, "colorimetry or transfer function missing");
149 return;
150 }
151 if (m_transferFunction != NamedTransferFunction::PerceptualQuantizer && (m_maxFrameAverageBrightness || m_maxPeakBrightness)) {
152 wl_resource_post_error(resource->handle, error::error_inconsistent_set, "max_cll and max_fall must only be set with the PQ transfer function");
153 return;
154 }
155 new XXImageDescriptionV2(resource->client(), image_description, resource->version(), ColorDescription(*m_colorimetry, *m_transferFunction, 100, 0, m_maxFrameAverageBrightness.value_or(100), m_maxPeakBrightness.value_or(100)));
156 wl_resource_destroy(resource->handle);
157}
158
159void XXColorParametricCreatorV2::xx_image_description_creator_params_v2_set_tf_named(Resource *resource, uint32_t tf)
160{
161 if (m_transferFunction) {
162 wl_resource_post_error(resource->handle, error::error_already_set, "transfer function is already set");
163 return;
164 }
165 switch (tf) {
166 case XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_SRGB:
167 case XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_BT709:
168 case XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_GAMMA22:
169 m_transferFunction = NamedTransferFunction::gamma22;
170 return;
171 case XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_ST2084_PQ:
173 return;
174 default:
175 // TODO add more transfer functions
176 wl_resource_post_error(resource->handle, error::error_invalid_tf, "unsupported named transfer function");
177 }
178}
179
180void XXColorParametricCreatorV2::xx_image_description_creator_params_v2_set_tf_power(Resource *resource, uint32_t eexp)
181{
182 wl_resource_post_error(resource->handle, error::error_invalid_tf, "power transfer functions are not supported");
183}
184
185void XXColorParametricCreatorV2::xx_image_description_creator_params_v2_set_primaries_named(Resource *resource, uint32_t primaries)
186{
187 if (m_colorimetry) {
188 wl_resource_post_error(resource->handle, error::error_already_set, "primaries are already set");
189 return;
190 }
191 switch (primaries) {
192 case XX_COLOR_MANAGER_V2_PRIMARIES_SRGB:
194 return;
195 case XX_COLOR_MANAGER_V2_PRIMARIES_BT2020:
197 return;
198 default:
199 // TODO add more named primaries
200 wl_resource_post_error(resource->handle, error::error_invalid_primaries, "unsupported named primaries");
201 }
202}
203
204void XXColorParametricCreatorV2::xx_image_description_creator_params_v2_set_primaries(Resource *resource, uint32_t r_x, uint32_t r_y, uint32_t g_x, uint32_t g_y, uint32_t b_x, uint32_t b_y, uint32_t w_x, uint32_t w_y)
205{
206 if (m_colorimetry) {
207 wl_resource_post_error(resource->handle, error::error_already_set, "primaries are already set");
208 return;
209 }
210 if (w_x == 0 || w_y == 0) {
211 wl_resource_post_error(resource->handle, error::error_invalid_primaries, "whitepoint must not be zero");
212 return;
213 }
214 m_colorimetry = Colorimetry{
215 QVector2D(r_x / 10'000.0, r_y / 10'000.0),
216 QVector2D(g_x / 10'000.0, g_y / 10'000.0),
217 QVector2D(b_x / 10'000.0, b_y / 10'000.0),
218 QVector2D(w_x / 10'000.0, w_y / 10'000.0)};
219}
220
221void XXColorParametricCreatorV2::xx_image_description_creator_params_v2_set_mastering_display_primaries(Resource *resource, uint32_t r_x, uint32_t r_y, uint32_t g_x, uint32_t g_y, uint32_t b_x, uint32_t b_y, uint32_t w_x, uint32_t w_y)
222{
223 // ignored (at least for now)
224}
225
226void XXColorParametricCreatorV2::xx_image_description_creator_params_v2_set_mastering_luminance(Resource *resource, uint32_t min_lum, uint32_t max_lum)
227{
228 // ignored (at least for now)
229}
230
231void XXColorParametricCreatorV2::xx_image_description_creator_params_v2_set_max_cll(Resource *resource, uint32_t max_cll)
232{
233 m_maxPeakBrightness = max_cll;
234}
235
236void XXColorParametricCreatorV2::xx_image_description_creator_params_v2_set_max_fall(Resource *resource, uint32_t max_fall)
237{
238 m_maxFrameAverageBrightness = max_fall;
239}
240
241XXImageDescriptionV2::XXImageDescriptionV2(wl_client *client, uint32_t id, uint32_t version, const ColorDescription &color)
242 : QtWaylandServer::xx_image_description_v2(client, id, version)
243 , m_description(color)
244{
245 // there's no need to track image description identities, as our descriptions are very lightweight
246 static uint32_t s_identity = 1;
247 send_ready(resource()->handle, s_identity++);
248}
249
250void XXImageDescriptionV2::xx_image_description_v2_destroy_resource(Resource *resource)
251{
252 delete this;
253}
254
255void XXImageDescriptionV2::xx_image_description_v2_destroy(Resource *resource)
256{
257 wl_resource_destroy(resource->handle);
258}
259
260static uint32_t kwinTFtoProtoTF(NamedTransferFunction tf)
261{
262 switch (tf) {
264 return xx_color_manager_v2_transfer_function::XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_SRGB;
266 return xx_color_manager_v2_transfer_function::XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_LINEAR;
268 return xx_color_manager_v2_transfer_function::XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_ST2084_PQ;
270 return xx_color_manager_v2_transfer_function::XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_LINEAR;
272 return xx_color_manager_v2_transfer_function::XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_GAMMA22;
273 }
274 Q_UNREACHABLE();
275}
276
277void XXImageDescriptionV2::xx_image_description_v2_get_information(Resource *qtResource, uint32_t information)
278{
279 auto resource = wl_resource_create(qtResource->client(), &xx_image_description_info_v2_interface, qtResource->version(), information);
280 const auto c = m_description.colorimetry();
281 const auto round = [](float f) {
282 return std::clamp(std::round(f * 10'000.0), 0.0, 1.0);
283 };
284 xx_image_description_info_v2_send_primaries(resource,
285 round(c.red().x()), round(c.red().y()),
286 round(c.green().x()), round(c.green().y()),
287 round(c.blue().x()), round(c.blue().y()),
288 round(c.white().x()), round(c.white().y()));
289 xx_image_description_info_v2_send_tf_named(resource, kwinTFtoProtoTF(m_description.transferFunction()));
290 xx_image_description_info_v2_send_done(resource);
291 wl_resource_destroy(resource);
292}
293
295{
296 return m_description;
297}
298
300{
301 if (auto resourceContainer = Resource::fromResource(resource)) {
302 return static_cast<XXImageDescriptionV2 *>(resourceContainer->object());
303 } else {
304 return nullptr;
305 }
306}
307
308XXColorManagementOutputV2::XXColorManagementOutputV2(wl_client *client, uint32_t id, uint32_t version, Output *output)
309 : QtWaylandServer::xx_color_management_output_v2(client, id, version)
310 , m_output(output)
311 , m_colorDescription(output->colorDescription())
312{
313 connect(output, &Output::colorDescriptionChanged, this, &XXColorManagementOutputV2::colorDescriptionChanged);
314}
315
316void XXColorManagementOutputV2::xx_color_management_output_v2_destroy_resource(Resource *resource)
317{
318 delete this;
319}
320
321void XXColorManagementOutputV2::xx_color_management_output_v2_destroy(Resource *resource)
322{
323 wl_resource_destroy(resource->handle);
324}
325
326void XXColorManagementOutputV2::xx_color_management_output_v2_get_image_description(Resource *resource, uint32_t image_description)
327{
328 new XXImageDescriptionV2(resource->client(), image_description, resource->version(), m_colorDescription);
329}
330
331void XXColorManagementOutputV2::colorDescriptionChanged()
332{
333 m_colorDescription = m_output->colorDescription();
334 send_image_description_changed();
335}
336
337}
338
339#include "moc_xx_colormanagement_v2.cpp"
NamedTransferFunction transferFunction() const
static const ColorDescription sRGB
Definition colorspace.h:132
const Colorimetry & colorimetry() const
static const Colorimetry & fromName(NamedColorimetry name)
Class holding the Wayland server display loop.
Definition display.h:34
void colorDescriptionChanged()
const ColorDescription & colorDescription() const
Definition output.cpp:732
Output * handle() const
Definition output.cpp:263
static OutputInterface * get(wl_resource *native)
Definition output.cpp:320
Resource representing a wl_surface.
Definition surface.h:80
static SurfaceInterface * get(wl_resource *native)
Definition surface.cpp:819
static SurfaceInterfacePrivate * get(SurfaceInterface *surface)
Definition surface_p.h:99
XXColorManagementOutputV2(wl_client *client, uint32_t id, uint32_t version, Output *output)
XXColorManagerV2(Display *display, QObject *parent)
XXColorParametricCreatorV2(wl_client *client, uint32_t id, uint32_t version)
XXColorSurfaceV2(wl_client *client, uint32_t id, uint32_t version, SurfaceInterface *surface)
void setPreferredColorDescription(const ColorDescription &descr)
const ColorDescription & description() const
XXImageDescriptionV2(wl_client *client, uint32_t id, uint32_t version, const ColorDescription &color)
static XXImageDescriptionV2 * get(wl_resource *resource)
constexpr int version
NamedTransferFunction
Definition colorspace.h:90