File indexing completed on 2024-11-10 04:57:38
0001 /* 0002 SPDX-FileCopyrightText: 2024 Xaver Hugl <xaver.hugl@gmail.com> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 #include "xx_colormanagement_v2.h" 0007 #include "display.h" 0008 #include "surface.h" 0009 #include "surface_p.h" 0010 #include "utils/resource.h" 0011 #include "wayland/output.h" 0012 0013 namespace KWin 0014 { 0015 0016 XXColorManagerV2::XXColorManagerV2(Display *display, QObject *parent) 0017 : QObject(parent) 0018 , QtWaylandServer::xx_color_manager_v2(*display, 1) 0019 { 0020 } 0021 0022 void XXColorManagerV2::xx_color_manager_v2_bind_resource(Resource *resource) 0023 { 0024 send_supported_feature(resource->handle, feature::feature_parametric); 0025 send_supported_feature(resource->handle, feature::feature_extended_target_volume); 0026 send_supported_feature(resource->handle, feature::feature_set_mastering_display_primaries); 0027 send_supported_feature(resource->handle, feature::feature_set_primaries); 0028 0029 send_supported_primaries_named(resource->handle, primaries::primaries_srgb); 0030 send_supported_primaries_named(resource->handle, primaries::primaries_bt2020); 0031 0032 send_supported_tf_named(resource->handle, transfer_function::transfer_function_bt709); 0033 send_supported_tf_named(resource->handle, transfer_function::transfer_function_gamma22); 0034 send_supported_tf_named(resource->handle, transfer_function::transfer_function_srgb); 0035 send_supported_tf_named(resource->handle, transfer_function::transfer_function_st2084_pq); 0036 // TODO scRGB? 0037 0038 send_supported_intent(resource->handle, render_intent::render_intent_perceptual); 0039 send_supported_intent(resource->handle, render_intent::render_intent_relative); 0040 // TODO implement the other rendering intents 0041 } 0042 0043 void XXColorManagerV2::xx_color_manager_v2_destroy(Resource *resource) 0044 { 0045 wl_resource_destroy(resource->handle); 0046 } 0047 0048 void XXColorManagerV2::xx_color_manager_v2_get_output(Resource *resource, uint32_t id, struct ::wl_resource *output) 0049 { 0050 new XXColorManagementOutputV2(resource->client(), id, resource->version(), OutputInterface::get(output)->handle()); 0051 } 0052 0053 void XXColorManagerV2::xx_color_manager_v2_get_surface(Resource *resource, uint32_t id, struct ::wl_resource *surface) 0054 { 0055 const auto surf = SurfaceInterface::get(surface); 0056 const auto priv = SurfaceInterfacePrivate::get(surf); 0057 if (priv->frogColorManagement || priv->xxColorSurface) { 0058 wl_resource_post_error(resource->handle, 0, "there's already a color management surface for this wl_surface"); 0059 return; 0060 } 0061 priv->xxColorSurface = new XXColorSurfaceV2(resource->client(), id, resource->version(), surf); 0062 } 0063 0064 void XXColorManagerV2::xx_color_manager_v2_new_icc_creator(Resource *resource, uint32_t obj) 0065 { 0066 wl_resource_post_error(resource->handle, error::error_unsupported_feature, "ICC profiles are not supported"); 0067 } 0068 0069 void XXColorManagerV2::xx_color_manager_v2_new_parametric_creator(Resource *resource, uint32_t obj) 0070 { 0071 new XXColorParametricCreatorV2(resource->client(), obj, resource->version()); 0072 } 0073 0074 XXColorSurfaceV2::XXColorSurfaceV2(wl_client *client, uint32_t id, uint32_t version, SurfaceInterface *surface) 0075 : QtWaylandServer::xx_color_management_surface_v2(client, id, version) 0076 , m_surface(surface) 0077 , m_preferred(SurfaceInterfacePrivate::get(surface)->preferredColorDescription.value_or(ColorDescription::sRGB)) 0078 { 0079 } 0080 0081 XXColorSurfaceV2::~XXColorSurfaceV2() 0082 { 0083 if (m_surface) { 0084 const auto priv = SurfaceInterfacePrivate::get(m_surface); 0085 priv->pending->colorDescription = ColorDescription::sRGB; 0086 priv->pending->colorDescriptionIsSet = true; 0087 priv->xxColorSurface = nullptr; 0088 } 0089 } 0090 0091 void XXColorSurfaceV2::setPreferredColorDescription(const ColorDescription &descr) 0092 { 0093 if (m_preferred != descr) { 0094 m_preferred = descr; 0095 send_preferred_changed(resource()->handle); 0096 } 0097 } 0098 0099 void XXColorSurfaceV2::xx_color_management_surface_v2_destroy_resource(Resource *resource) 0100 { 0101 delete this; 0102 } 0103 0104 void XXColorSurfaceV2::xx_color_management_surface_v2_destroy(Resource *resource) 0105 { 0106 wl_resource_destroy(resource->handle); 0107 } 0108 0109 void XXColorSurfaceV2::xx_color_management_surface_v2_set_image_description(Resource *resource, struct ::wl_resource *image_description, uint32_t render_intent) 0110 { 0111 if (!m_surface) { 0112 return; 0113 } 0114 const auto priv = SurfaceInterfacePrivate::get(m_surface); 0115 priv->pending->colorDescription = XXImageDescriptionV2::get(image_description)->description(); 0116 priv->pending->colorDescriptionIsSet = true; 0117 // TODO render_intent 0118 } 0119 0120 void XXColorSurfaceV2::xx_color_management_surface_v2_unset_image_description(Resource *resource) 0121 { 0122 if (!m_surface) { 0123 return; 0124 } 0125 const auto priv = SurfaceInterfacePrivate::get(m_surface); 0126 priv->pending->colorDescription = ColorDescription::sRGB; 0127 priv->pending->colorDescriptionIsSet = true; 0128 } 0129 0130 void XXColorSurfaceV2::xx_color_management_surface_v2_get_preferred(Resource *resource, uint32_t image_description) 0131 { 0132 new XXImageDescriptionV2(resource->client(), image_description, resource->version(), m_preferred); 0133 } 0134 0135 XXColorParametricCreatorV2::XXColorParametricCreatorV2(wl_client *client, uint32_t id, uint32_t version) 0136 : QtWaylandServer::xx_image_description_creator_params_v2(client, id, version) 0137 { 0138 } 0139 0140 void XXColorParametricCreatorV2::xx_image_description_creator_params_v2_destroy_resource(Resource *resource) 0141 { 0142 delete this; 0143 } 0144 0145 void XXColorParametricCreatorV2::xx_image_description_creator_params_v2_create(Resource *resource, uint32_t image_description) 0146 { 0147 if (!m_colorimetry || !m_transferFunction) { 0148 wl_resource_post_error(resource->handle, error::error_incomplete_set, "colorimetry or transfer function missing"); 0149 return; 0150 } 0151 if (m_transferFunction != NamedTransferFunction::PerceptualQuantizer && (m_maxFrameAverageBrightness || m_maxPeakBrightness)) { 0152 wl_resource_post_error(resource->handle, error::error_inconsistent_set, "max_cll and max_fall must only be set with the PQ transfer function"); 0153 return; 0154 } 0155 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))); 0156 wl_resource_destroy(resource->handle); 0157 } 0158 0159 void XXColorParametricCreatorV2::xx_image_description_creator_params_v2_set_tf_named(Resource *resource, uint32_t tf) 0160 { 0161 if (m_transferFunction) { 0162 wl_resource_post_error(resource->handle, error::error_already_set, "transfer function is already set"); 0163 return; 0164 } 0165 switch (tf) { 0166 case XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_SRGB: 0167 case XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_BT709: 0168 case XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_GAMMA22: 0169 m_transferFunction = NamedTransferFunction::gamma22; 0170 return; 0171 case XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_ST2084_PQ: 0172 m_transferFunction = NamedTransferFunction::PerceptualQuantizer; 0173 return; 0174 default: 0175 // TODO add more transfer functions 0176 wl_resource_post_error(resource->handle, error::error_invalid_tf, "unsupported named transfer function"); 0177 } 0178 } 0179 0180 void XXColorParametricCreatorV2::xx_image_description_creator_params_v2_set_tf_power(Resource *resource, uint32_t eexp) 0181 { 0182 wl_resource_post_error(resource->handle, error::error_invalid_tf, "power transfer functions are not supported"); 0183 } 0184 0185 void XXColorParametricCreatorV2::xx_image_description_creator_params_v2_set_primaries_named(Resource *resource, uint32_t primaries) 0186 { 0187 if (m_colorimetry) { 0188 wl_resource_post_error(resource->handle, error::error_already_set, "primaries are already set"); 0189 return; 0190 } 0191 switch (primaries) { 0192 case XX_COLOR_MANAGER_V2_PRIMARIES_SRGB: 0193 m_colorimetry = Colorimetry::fromName(NamedColorimetry::BT709); 0194 return; 0195 case XX_COLOR_MANAGER_V2_PRIMARIES_BT2020: 0196 m_colorimetry = Colorimetry::fromName(NamedColorimetry::BT2020); 0197 return; 0198 default: 0199 // TODO add more named primaries 0200 wl_resource_post_error(resource->handle, error::error_invalid_primaries, "unsupported named primaries"); 0201 } 0202 } 0203 0204 void 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) 0205 { 0206 if (m_colorimetry) { 0207 wl_resource_post_error(resource->handle, error::error_already_set, "primaries are already set"); 0208 return; 0209 } 0210 if (w_x == 0 || w_y == 0) { 0211 wl_resource_post_error(resource->handle, error::error_invalid_primaries, "whitepoint must not be zero"); 0212 return; 0213 } 0214 m_colorimetry = Colorimetry{ 0215 QVector2D(r_x / 10'000.0, r_y / 10'000.0), 0216 QVector2D(g_x / 10'000.0, g_y / 10'000.0), 0217 QVector2D(b_x / 10'000.0, b_y / 10'000.0), 0218 QVector2D(w_x / 10'000.0, w_y / 10'000.0)}; 0219 } 0220 0221 void 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) 0222 { 0223 // ignored (at least for now) 0224 } 0225 0226 void XXColorParametricCreatorV2::xx_image_description_creator_params_v2_set_mastering_luminance(Resource *resource, uint32_t min_lum, uint32_t max_lum) 0227 { 0228 // ignored (at least for now) 0229 } 0230 0231 void XXColorParametricCreatorV2::xx_image_description_creator_params_v2_set_max_cll(Resource *resource, uint32_t max_cll) 0232 { 0233 m_maxPeakBrightness = max_cll; 0234 } 0235 0236 void XXColorParametricCreatorV2::xx_image_description_creator_params_v2_set_max_fall(Resource *resource, uint32_t max_fall) 0237 { 0238 m_maxFrameAverageBrightness = max_fall; 0239 } 0240 0241 XXImageDescriptionV2::XXImageDescriptionV2(wl_client *client, uint32_t id, uint32_t version, const ColorDescription &color) 0242 : QtWaylandServer::xx_image_description_v2(client, id, version) 0243 , m_description(color) 0244 { 0245 // there's no need to track image description identities, as our descriptions are very lightweight 0246 static uint32_t s_identity = 1; 0247 send_ready(resource()->handle, s_identity++); 0248 } 0249 0250 void XXImageDescriptionV2::xx_image_description_v2_destroy_resource(Resource *resource) 0251 { 0252 delete this; 0253 } 0254 0255 void XXImageDescriptionV2::xx_image_description_v2_destroy(Resource *resource) 0256 { 0257 wl_resource_destroy(resource->handle); 0258 } 0259 0260 static uint32_t kwinTFtoProtoTF(NamedTransferFunction tf) 0261 { 0262 switch (tf) { 0263 case NamedTransferFunction::sRGB: 0264 return xx_color_manager_v2_transfer_function::XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_SRGB; 0265 case NamedTransferFunction::linear: 0266 return xx_color_manager_v2_transfer_function::XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_LINEAR; 0267 case NamedTransferFunction::PerceptualQuantizer: 0268 return xx_color_manager_v2_transfer_function::XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_ST2084_PQ; 0269 case NamedTransferFunction::scRGB: 0270 return xx_color_manager_v2_transfer_function::XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_LINEAR; 0271 case NamedTransferFunction::gamma22: 0272 return xx_color_manager_v2_transfer_function::XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_GAMMA22; 0273 } 0274 Q_UNREACHABLE(); 0275 } 0276 0277 void XXImageDescriptionV2::xx_image_description_v2_get_information(Resource *qtResource, uint32_t information) 0278 { 0279 auto resource = wl_resource_create(qtResource->client(), &xx_image_description_info_v2_interface, qtResource->version(), information); 0280 const auto c = m_description.colorimetry(); 0281 const auto round = [](float f) { 0282 return std::clamp(std::round(f * 10'000.0), 0.0, 1.0); 0283 }; 0284 xx_image_description_info_v2_send_primaries(resource, 0285 round(c.red().x()), round(c.red().y()), 0286 round(c.green().x()), round(c.green().y()), 0287 round(c.blue().x()), round(c.blue().y()), 0288 round(c.white().x()), round(c.white().y())); 0289 xx_image_description_info_v2_send_tf_named(resource, kwinTFtoProtoTF(m_description.transferFunction())); 0290 xx_image_description_info_v2_send_done(resource); 0291 wl_resource_destroy(resource); 0292 } 0293 0294 const ColorDescription &XXImageDescriptionV2::description() const 0295 { 0296 return m_description; 0297 } 0298 0299 XXImageDescriptionV2 *XXImageDescriptionV2::get(wl_resource *resource) 0300 { 0301 if (auto resourceContainer = Resource::fromResource(resource)) { 0302 return static_cast<XXImageDescriptionV2 *>(resourceContainer->object()); 0303 } else { 0304 return nullptr; 0305 } 0306 } 0307 0308 XXColorManagementOutputV2::XXColorManagementOutputV2(wl_client *client, uint32_t id, uint32_t version, Output *output) 0309 : QtWaylandServer::xx_color_management_output_v2(client, id, version) 0310 , m_output(output) 0311 , m_colorDescription(output->colorDescription()) 0312 { 0313 connect(output, &Output::colorDescriptionChanged, this, &XXColorManagementOutputV2::colorDescriptionChanged); 0314 } 0315 0316 void XXColorManagementOutputV2::xx_color_management_output_v2_destroy_resource(Resource *resource) 0317 { 0318 delete this; 0319 } 0320 0321 void XXColorManagementOutputV2::xx_color_management_output_v2_destroy(Resource *resource) 0322 { 0323 wl_resource_destroy(resource->handle); 0324 } 0325 0326 void XXColorManagementOutputV2::xx_color_management_output_v2_get_image_description(Resource *resource, uint32_t image_description) 0327 { 0328 new XXImageDescriptionV2(resource->client(), image_description, resource->version(), m_colorDescription); 0329 } 0330 0331 void XXColorManagementOutputV2::colorDescriptionChanged() 0332 { 0333 m_colorDescription = m_output->colorDescription(); 0334 send_image_description_changed(); 0335 } 0336 0337 } 0338 0339 #include "moc_xx_colormanagement_v2.cpp"