zcr_color_manager.cc 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. // Copyright 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/exo/wayland/zcr_color_manager.h"
  5. #include <chrome-color-management-server-protocol.h>
  6. #include <wayland-server-core.h>
  7. #include <cstdint>
  8. #include <memory>
  9. #include "ash/shell.h"
  10. #include "base/containers/fixed_flat_map.h"
  11. #include "base/notreached.h"
  12. #include "base/strings/stringprintf.h"
  13. #include "components/exo/surface.h"
  14. #include "components/exo/surface_observer.h"
  15. #include "components/exo/wayland/server.h"
  16. #include "components/exo/wayland/server_util.h"
  17. #include "components/exo/wayland/wayland_display_observer.h"
  18. #include "components/exo/wayland/wayland_display_output.h"
  19. #include "components/exo/wm_helper_chromeos.h"
  20. #include "third_party/abseil-cpp/absl/types/optional.h"
  21. #include "third_party/skia/include/core/SkColorSpace.h"
  22. #include "third_party/skia/modules/skcms/skcms.h"
  23. #include "ui/base/wayland/color_manager_util.h"
  24. #include "ui/display/display.h"
  25. #include "ui/display/display_observer.h"
  26. #include "ui/display/manager/display_manager.h"
  27. #include "ui/display/screen.h"
  28. #include "ui/display/types/display_constants.h"
  29. #include "ui/gfx/color_space.h"
  30. #include "ui/gfx/display_color_spaces.h"
  31. #include "ui/gfx/geometry/triangle_f.h"
  32. #include "wayland-server-protocol.h"
  33. namespace exo {
  34. namespace wayland {
  35. namespace {
  36. #define PARAM_TO_FLOAT(x) (x / 10000.f)
  37. #define FLOAT_TO_PARAM(x) (x * 10000)
  38. constexpr auto kDefaultColorSpace = gfx::ColorSpace::CreateSRGB();
  39. // Wrapper around a |gfx::ColorSpace| that tracks additional data useful to
  40. // the protocol. These live as wayland resource data.
  41. class ColorManagerColorSpace {
  42. public:
  43. explicit ColorManagerColorSpace(gfx::ColorSpace color_space)
  44. : color_space(color_space),
  45. eotf(ui::wayland::ToColorManagerEOTF(color_space.GetTransferID())),
  46. primaries(color_space.GetColorSpacePrimaries()) {}
  47. ColorManagerColorSpace(gfx::ColorSpace color_space,
  48. zcr_color_manager_v1_eotf_names eotf,
  49. SkColorSpacePrimaries primaries)
  50. : color_space(color_space), eotf(eotf), primaries(primaries) {}
  51. virtual ~ColorManagerColorSpace() = default;
  52. wl_resource* output_resource;
  53. const gfx::ColorSpace color_space;
  54. const zcr_color_manager_v1_eotf_names eotf;
  55. const SkColorSpacePrimaries primaries;
  56. void SendColorSpaceInfo(wl_resource* color_space_resource) {
  57. SendCustomColorSpaceInfo(color_space_resource);
  58. zcr_color_space_v1_send_params(
  59. color_space_resource, eotf,
  60. static_cast<int>(FLOAT_TO_PARAM(primaries.fRX)),
  61. static_cast<int>(FLOAT_TO_PARAM(primaries.fRY)),
  62. static_cast<int>(FLOAT_TO_PARAM(primaries.fGX)),
  63. static_cast<int>(FLOAT_TO_PARAM(primaries.fGY)),
  64. static_cast<int>(FLOAT_TO_PARAM(primaries.fBX)),
  65. static_cast<int>(FLOAT_TO_PARAM(primaries.fBY)),
  66. static_cast<int>(FLOAT_TO_PARAM(primaries.fWX)),
  67. static_cast<int>(FLOAT_TO_PARAM(primaries.fWY)));
  68. zcr_color_space_v1_send_done(color_space_resource);
  69. if (output_resource)
  70. wl_output_send_done(output_resource);
  71. }
  72. virtual void SendCustomColorSpaceInfo(wl_resource* color_space_resource) {}
  73. };
  74. class NameBasedColorSpace final : public ColorManagerColorSpace {
  75. public:
  76. explicit NameBasedColorSpace(
  77. gfx::ColorSpace color_space,
  78. zcr_color_manager_v1_chromaticity_names chromaticity,
  79. zcr_color_manager_v1_eotf_names eotf,
  80. zcr_color_manager_v1_whitepoint_names whitepoint)
  81. : ColorManagerColorSpace(color_space,
  82. eotf,
  83. color_space.GetColorSpacePrimaries()),
  84. chromaticity(ui::wayland::ToColorManagerChromaticity(
  85. color_space.GetPrimaryID())),
  86. whitepoint(whitepoint) {}
  87. const zcr_color_manager_v1_chromaticity_names chromaticity;
  88. const zcr_color_manager_v1_whitepoint_names whitepoint;
  89. void SendCustomColorSpaceInfo(wl_resource* color_space_resource) override {
  90. zcr_color_space_v1_send_names(color_space_resource, eotf, chromaticity,
  91. whitepoint);
  92. }
  93. };
  94. // Wrap a surface pointer and handle relevant events.
  95. // TODO(b/207031122): This class should also watch for display color space
  96. // changes and update clients.
  97. class ColorManagerSurface final : public SurfaceObserver {
  98. public:
  99. explicit ColorManagerSurface(Server* server,
  100. wl_resource* color_manager_surface_resource,
  101. Surface* surface)
  102. : server_(server),
  103. color_manager_surface_resource_(color_manager_surface_resource),
  104. scoped_surface_(std::make_unique<ScopedSurface>(surface, this)) {}
  105. ColorManagerSurface(ColorManagerSurface&) = delete;
  106. ColorManagerSurface(ColorManagerSurface&&) = delete;
  107. ~ColorManagerSurface() override = default;
  108. // Safely set the color space (doing nothing if the surface was destroyed).
  109. void SetColorSpace(gfx::ColorSpace color_space) {
  110. Surface* surface = scoped_surface_->get();
  111. if (!surface)
  112. return;
  113. surface->SetColorSpace(color_space);
  114. }
  115. private:
  116. // SurfaceObserver:
  117. void OnDisplayChanged(Surface* surface,
  118. int64_t old_display,
  119. int64_t new_display) override {
  120. wl_client* client = wl_resource_get_client(color_manager_surface_resource_);
  121. wl_resource* display_resource =
  122. server_->GetOutputResource(client, new_display);
  123. if (!display_resource)
  124. return;
  125. const auto* wm_helper = WMHelperChromeOS::GetInstance();
  126. if (old_display != display::kInvalidDisplayId) {
  127. const auto& old_display_info = wm_helper->GetDisplayInfo(old_display);
  128. const auto& new_display_info = wm_helper->GetDisplayInfo(new_display);
  129. if (old_display_info.display_color_spaces() ==
  130. new_display_info.display_color_spaces())
  131. return;
  132. }
  133. zcr_color_management_surface_v1_send_preferred_color_space(
  134. color_manager_surface_resource_, display_resource);
  135. }
  136. void OnSurfaceDestroying(Surface* surface) override {
  137. scoped_surface_.reset();
  138. }
  139. Server* server_;
  140. wl_resource* color_manager_surface_resource_;
  141. std::unique_ptr<ScopedSurface> scoped_surface_;
  142. };
  143. class ColorManagerObserver : public WaylandDisplayObserver {
  144. public:
  145. ColorManagerObserver(WaylandDisplayHandler* wayland_display_handler,
  146. wl_resource* color_management_output_resource,
  147. wl_resource* output_resource)
  148. : wayland_display_handler_(wayland_display_handler),
  149. color_management_output_resource_(color_management_output_resource),
  150. output_resource_(output_resource) {}
  151. ColorManagerObserver(const ColorManagerObserver&) = delete;
  152. ColorManagerObserver& operator=(const ColorManagerObserver&) = delete;
  153. ~ColorManagerObserver() = default;
  154. // Overridden from WaylandDisplayObserver:
  155. bool SendDisplayMetrics(const display::Display& display,
  156. uint32_t changed_metrics) override {
  157. if (!(changed_metrics &
  158. display::DisplayObserver::DISPLAY_METRIC_COLOR_SPACE)) {
  159. return false;
  160. }
  161. zcr_color_management_output_v1_send_color_space_changed(
  162. color_management_output_resource_);
  163. return true;
  164. }
  165. gfx::ColorSpace GetColorSpace() const {
  166. #if BUILDFLAG(IS_CHROMEOS_ASH)
  167. // Snapshot ColorSpace is only valid for ScreenAsh.
  168. return ash::Shell::Get()
  169. ->display_manager()
  170. ->GetDisplayInfo(wayland_display_handler_->id())
  171. .GetSnapshotColorSpace();
  172. #else
  173. return gfx::ColorSpace::CreateSRGB();
  174. #endif
  175. }
  176. WaylandDisplayHandler* wayland_display_handler() {
  177. return wayland_display_handler_;
  178. }
  179. wl_resource* GetOutputResource() { return output_resource_; }
  180. private:
  181. WaylandDisplayHandler* wayland_display_handler_;
  182. wl_resource* const color_management_output_resource_;
  183. wl_resource* output_resource_;
  184. };
  185. ////////////////////////////////////////////////////////////////////////////////
  186. // zcr_color_management_color_space_v1_interface:
  187. void color_space_get_information(struct wl_client* client,
  188. struct wl_resource* color_space_resource) {
  189. GetUserDataAs<ColorManagerColorSpace>(color_space_resource)
  190. ->SendColorSpaceInfo(color_space_resource);
  191. }
  192. void color_space_destroy(struct wl_client* client,
  193. struct wl_resource* color_space_resource) {
  194. wl_resource_destroy(color_space_resource);
  195. }
  196. const struct zcr_color_space_v1_interface color_space_v1_implementation = {
  197. color_space_get_information, color_space_destroy};
  198. ////////////////////////////////////////////////////////////////////////////////
  199. // zcr_color_management_output_v1_interface:
  200. void color_management_output_get_color_space(
  201. struct wl_client* client,
  202. struct wl_resource* color_management_output_resource,
  203. uint32_t id) {
  204. auto* color_management_output_observer =
  205. GetUserDataAs<ColorManagerObserver>(color_management_output_resource);
  206. // create new zcr color space for the current color space of the output
  207. auto color_space = std::make_unique<ColorManagerColorSpace>(
  208. color_management_output_observer->GetColorSpace());
  209. color_space->output_resource =
  210. color_management_output_observer->GetOutputResource();
  211. wl_resource* color_space_resource =
  212. wl_resource_create(client, &zcr_color_space_v1_interface, 1, id);
  213. SetImplementation(color_space_resource, &color_space_v1_implementation,
  214. std::move(color_space));
  215. }
  216. void color_management_output_destroy(
  217. struct wl_client* client,
  218. struct wl_resource* color_management_output_resource) {
  219. wl_resource_destroy(color_management_output_resource);
  220. }
  221. const struct zcr_color_management_output_v1_interface
  222. color_management_output_v1_implementation = {
  223. color_management_output_get_color_space,
  224. color_management_output_destroy};
  225. ////////////////////////////////////////////////////////////////////////////////
  226. // zcr_color_management_surface_v1_interface:
  227. void color_management_surface_set_alpha_mode(
  228. struct wl_client* client,
  229. struct wl_resource* color_management_surface_resource,
  230. uint32_t alpha_mode) {
  231. NOTIMPLEMENTED();
  232. }
  233. void color_management_surface_set_extended_dynamic_range(
  234. struct wl_client* client,
  235. struct wl_resource* color_management_surface_resource,
  236. uint32_t value) {
  237. NOTIMPLEMENTED();
  238. }
  239. void color_management_surface_set_color_space(
  240. struct wl_client* client,
  241. struct wl_resource* color_management_surface_resource,
  242. struct wl_resource* color_space_resource,
  243. uint32_t render_intent) {
  244. auto* color_manager_color_space =
  245. GetUserDataAs<ColorManagerColorSpace>(color_space_resource);
  246. GetUserDataAs<ColorManagerSurface>(color_management_surface_resource)
  247. ->SetColorSpace(color_manager_color_space->color_space);
  248. }
  249. void color_management_surface_set_default_color_space(
  250. struct wl_client* client,
  251. struct wl_resource* color_management_surface_resource) {
  252. GetUserDataAs<ColorManagerSurface>(color_management_surface_resource)
  253. ->SetColorSpace(kDefaultColorSpace);
  254. }
  255. void color_management_surface_destroy(
  256. struct wl_client* client,
  257. struct wl_resource* color_management_surface_resource) {
  258. GetUserDataAs<ColorManagerSurface>(color_management_surface_resource)
  259. ->SetColorSpace(kDefaultColorSpace);
  260. wl_resource_destroy(color_management_surface_resource);
  261. }
  262. const struct zcr_color_management_surface_v1_interface
  263. color_management_surface_v1_implementation = {
  264. color_management_surface_set_alpha_mode,
  265. color_management_surface_set_extended_dynamic_range,
  266. color_management_surface_set_color_space,
  267. color_management_surface_set_default_color_space,
  268. color_management_surface_destroy};
  269. ////////////////////////////////////////////////////////////////////////////////
  270. // zcr_color_manager_v1_interface:
  271. void CreateColorSpace(struct wl_client* client,
  272. int32_t color_space_creator_id,
  273. std::unique_ptr<ColorManagerColorSpace> color_space) {
  274. wl_resource* color_space_resource = wl_resource_create(
  275. client, &zcr_color_space_v1_interface, /*version=*/1, /*id=*/0);
  276. SetImplementation(color_space_resource, &color_space_v1_implementation,
  277. std::move(color_space));
  278. wl_resource* color_space_creator_resource =
  279. wl_resource_create(client, &zcr_color_space_creator_v1_interface,
  280. /*version=*/1, color_space_creator_id);
  281. zcr_color_space_creator_v1_send_created(color_space_creator_resource,
  282. color_space_resource);
  283. // The resource should be immediately destroyed once it's sent its event.
  284. wl_resource_destroy(color_space_creator_resource);
  285. }
  286. void SendColorCreationError(struct wl_client* client,
  287. int32_t color_space_creator_id,
  288. int32_t error_flags) {
  289. wl_resource* color_space_creator_resource = wl_resource_create(
  290. client, &zcr_color_space_creator_v1_interface, 1, color_space_creator_id);
  291. zcr_color_space_creator_v1_send_error(color_space_creator_resource,
  292. error_flags);
  293. // The resource should be immediately destroyed once it's sent its event.
  294. wl_resource_destroy(color_space_creator_resource);
  295. }
  296. void color_manager_create_color_space_from_icc(
  297. struct wl_client* client,
  298. struct wl_resource* color_manager_resource,
  299. uint32_t id,
  300. int32_t icc) {
  301. NOTIMPLEMENTED();
  302. }
  303. // TODO(b/206971557): This doesn't handle the user-set white point yet.
  304. void color_manager_create_color_space_from_names(
  305. struct wl_client* client,
  306. struct wl_resource* color_manager_resource,
  307. uint32_t id,
  308. uint32_t eotf,
  309. uint32_t chromaticity,
  310. uint32_t whitepoint) {
  311. uint32_t error_flags = 0;
  312. auto chromaticity_id = gfx::ColorSpace::PrimaryID::INVALID;
  313. const auto* maybe_primary = ui::wayland::kChromaticityMap.find(chromaticity);
  314. if (maybe_primary != std::end(ui::wayland::kChromaticityMap)) {
  315. chromaticity_id = maybe_primary->second;
  316. } else {
  317. DLOG(ERROR) << "Unable to find named chromaticity for id=" << chromaticity;
  318. error_flags |= ZCR_COLOR_SPACE_CREATOR_V1_CREATION_ERROR_BAD_PRIMARIES;
  319. }
  320. auto eotf_id = gfx::ColorSpace::TransferID::INVALID;
  321. const auto* maybe_eotf = ui::wayland::kEotfMap.find(eotf);
  322. if (maybe_eotf != std::end(ui::wayland::kEotfMap)) {
  323. eotf_id = maybe_eotf->second;
  324. } else {
  325. DLOG(ERROR) << "Unable to find named eotf for id=" << eotf;
  326. wl_resource_post_error(color_manager_resource,
  327. ZCR_COLOR_MANAGER_V1_ERROR_BAD_ENUM,
  328. "Unable to find an EOTF matching %d", eotf);
  329. }
  330. if (error_flags)
  331. SendColorCreationError(client, id, error_flags);
  332. CreateColorSpace(
  333. client, id,
  334. std::make_unique<NameBasedColorSpace>(
  335. gfx::ColorSpace(chromaticity_id, eotf_id),
  336. static_cast<zcr_color_manager_v1_chromaticity_names>(chromaticity),
  337. static_cast<zcr_color_manager_v1_eotf_names>(eotf),
  338. static_cast<zcr_color_manager_v1_whitepoint_names>(whitepoint)));
  339. }
  340. void color_manager_create_color_space_from_params(
  341. struct wl_client* client,
  342. struct wl_resource* color_manager_resource,
  343. uint32_t id,
  344. uint32_t eotf,
  345. uint32_t primary_r_x,
  346. uint32_t primary_r_y,
  347. uint32_t primary_g_x,
  348. uint32_t primary_g_y,
  349. uint32_t primary_b_x,
  350. uint32_t primary_b_y,
  351. uint32_t white_point_x,
  352. uint32_t white_point_y) {
  353. SkColorSpacePrimaries primaries = {
  354. PARAM_TO_FLOAT(primary_r_x), PARAM_TO_FLOAT(primary_r_y),
  355. PARAM_TO_FLOAT(primary_g_x), PARAM_TO_FLOAT(primary_g_y),
  356. PARAM_TO_FLOAT(primary_b_x), PARAM_TO_FLOAT(primary_b_y),
  357. PARAM_TO_FLOAT(white_point_x), PARAM_TO_FLOAT(white_point_y)};
  358. gfx::PointF r(primaries.fRX, primaries.fRY);
  359. gfx::PointF g(primaries.fGX, primaries.fGY);
  360. gfx::PointF b(primaries.fBX, primaries.fBY);
  361. gfx::PointF w(primaries.fWX, primaries.fWY);
  362. if (!gfx::PointIsInTriangle(w, r, g, b)) {
  363. auto error_message = base::StringPrintf(
  364. "White point %s must be inside of the triangle r=%s g=%s b=%s",
  365. w.ToString().c_str(), r.ToString().c_str(), g.ToString().c_str(),
  366. b.ToString().c_str());
  367. DLOG(ERROR) << error_message;
  368. wl_resource_post_error(color_manager_resource,
  369. ZCR_COLOR_MANAGER_V1_ERROR_BAD_PARAM, "%s",
  370. error_message.c_str());
  371. return;
  372. }
  373. auto eotf_id = gfx::ColorSpace::TransferID::INVALID;
  374. const auto* maybe_eotf = ui::wayland::kEotfMap.find(eotf);
  375. if (maybe_eotf != std::end(ui::wayland::kEotfMap)) {
  376. eotf_id = maybe_eotf->second;
  377. } else {
  378. DLOG(ERROR) << "Unable to find named transfer function for id=" << eotf;
  379. wl_resource_post_error(color_manager_resource,
  380. ZCR_COLOR_MANAGER_V1_ERROR_BAD_ENUM,
  381. "Unable to find an EOTF matching %d", eotf);
  382. return;
  383. }
  384. skcms_Matrix3x3 xyzd50 = {};
  385. if (!primaries.toXYZD50(&xyzd50)) {
  386. DLOG(ERROR) << base::StringPrintf(
  387. "Unable to translate color space primaries to XYZD50: "
  388. "{%f, %f, %f, %f, %f, %f, %f, %f}",
  389. primaries.fRX, primaries.fRY, primaries.fGX, primaries.fGY,
  390. primaries.fBX, primaries.fBY, primaries.fWX, primaries.fWY);
  391. SendColorCreationError(
  392. client, id, ZCR_COLOR_SPACE_CREATOR_V1_CREATION_ERROR_BAD_PRIMARIES);
  393. return;
  394. }
  395. CreateColorSpace(client, id,
  396. std::make_unique<ColorManagerColorSpace>(
  397. gfx::ColorSpace::CreateCustom(xyzd50, eotf_id)));
  398. }
  399. void color_manager_get_color_management_output(
  400. struct wl_client* client,
  401. struct wl_resource* color_manager_resource,
  402. uint32_t id,
  403. struct wl_resource* output) {
  404. wl_resource* color_management_output_resource = wl_resource_create(
  405. client, &zcr_color_management_output_v1_interface, 1, id);
  406. auto* display_handler = GetUserDataAs<WaylandDisplayHandler>(output);
  407. auto color_management_output_observer =
  408. std::make_unique<ColorManagerObserver>(
  409. display_handler, color_management_output_resource, output);
  410. display_handler->AddObserver(color_management_output_observer.get());
  411. SetImplementation(color_management_output_resource,
  412. &color_management_output_v1_implementation,
  413. std::move(color_management_output_observer));
  414. }
  415. void color_manager_get_color_management_surface(
  416. struct wl_client* client,
  417. struct wl_resource* color_manager_resource,
  418. uint32_t id,
  419. struct wl_resource* surface_resource) {
  420. wl_resource* color_management_surface_resource = wl_resource_create(
  421. client, &zcr_color_management_surface_v1_interface, 1, id);
  422. SetImplementation(color_management_surface_resource,
  423. &color_management_surface_v1_implementation,
  424. std::make_unique<ColorManagerSurface>(
  425. GetUserDataAs<Server>(color_manager_resource),
  426. color_management_surface_resource,
  427. GetUserDataAs<Surface>(surface_resource)));
  428. }
  429. void color_manager_destroy(struct wl_client* client,
  430. struct wl_resource* color_manager_resource) {
  431. wl_resource_destroy(color_manager_resource);
  432. }
  433. const struct zcr_color_manager_v1_interface color_manager_v1_implementation = {
  434. color_manager_create_color_space_from_icc,
  435. color_manager_create_color_space_from_names,
  436. color_manager_create_color_space_from_params,
  437. color_manager_get_color_management_output,
  438. color_manager_get_color_management_surface,
  439. color_manager_destroy};
  440. } // namespace
  441. void bind_zcr_color_manager(wl_client* client,
  442. void* data,
  443. uint32_t version,
  444. uint32_t id) {
  445. wl_resource* color_manager_resource =
  446. wl_resource_create(client, &zcr_color_manager_v1_interface, version, id);
  447. wl_resource_set_implementation(color_manager_resource,
  448. &color_manager_v1_implementation, data,
  449. /*destroy=*/nullptr);
  450. }
  451. } // namespace wayland
  452. } // namespace exo