1 /*
2 * Copyright 2023 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "include/core/SkCanvas.h"
9 #include "src/core/SkColorSpacePriv.h"
10 #include "tools/ToolUtils.h"
11 #include "tools/testrunners/common/surface_manager/SurfaceManager.h"
12
13 // Based on
14 // https://skia.googlesource.com/skia/+/88d5e1daa3ba3aae65139d4a3ded1e1b7078d59b/dm/DM.cpp#1315.
identify_gamut(SkColorSpace * cs)15 static std::string identify_gamut(SkColorSpace* cs) {
16 if (!cs) {
17 return "untagged";
18 }
19
20 skcms_Matrix3x3 gamut;
21 if (cs->toXYZD50(&gamut)) {
22 auto eq = [](skcms_Matrix3x3 x, skcms_Matrix3x3 y) {
23 for (int i = 0; i < 3; i++) {
24 for (int j = 0; j < 3; j++) {
25 if (x.vals[i][j] != y.vals[i][j]) {
26 return false;
27 }
28 }
29 }
30 return true;
31 };
32
33 if (eq(gamut, SkNamedGamut::kSRGB)) {
34 return "sRGB";
35 }
36 if (eq(gamut, SkNamedGamut::kAdobeRGB)) {
37 return "Adobe";
38 }
39 if (eq(gamut, SkNamedGamut::kDisplayP3)) {
40 return "P3";
41 }
42 if (eq(gamut, SkNamedGamut::kRec2020)) {
43 return "2020";
44 }
45 if (eq(gamut, SkNamedGamut::kXYZ)) {
46 return "XYZ";
47 }
48 if (eq(gamut, gNarrow_toXYZD50)) {
49 return "narrow";
50 }
51 return "other";
52 }
53 return "non-XYZ";
54 }
55
56 // Based on
57 // https://skia.googlesource.com/skia/+/88d5e1daa3ba3aae65139d4a3ded1e1b7078d59b/dm/DM.cpp#1341.
identify_transfer_fn(SkColorSpace * cs)58 static std::string identify_transfer_fn(SkColorSpace* cs) {
59 if (!cs) {
60 return "untagged";
61 }
62
63 auto eq = [](skcms_TransferFunction x, skcms_TransferFunction y) {
64 return x.g == y.g && x.a == y.a && x.b == y.b && x.c == y.c && x.d == y.d && x.e == y.e &&
65 x.f == y.f;
66 };
67
68 skcms_TransferFunction tf;
69 cs->transferFn(&tf);
70 switch (skcms_TransferFunction_getType(&tf)) {
71 case skcms_TFType_sRGBish:
72 if (tf.a == 1 && tf.b == 0 && tf.c == 0 && tf.d == 0 && tf.e == 0 && tf.f == 0) {
73 return SkStringPrintf("gamma %.3g", tf.g).c_str();
74 }
75 if (eq(tf, SkNamedTransferFn::kSRGB)) {
76 return "sRGB";
77 }
78 if (eq(tf, SkNamedTransferFn::kRec2020)) {
79 return "2020";
80 }
81 return SkStringPrintf("%.3g %.3g %.3g %.3g %.3g %.3g %.3g",
82 tf.g,
83 tf.a,
84 tf.b,
85 tf.c,
86 tf.d,
87 tf.e,
88 tf.f)
89 .c_str();
90
91 case skcms_TFType_PQish:
92 if (eq(tf, SkNamedTransferFn::kPQ)) {
93 return "PQ";
94 }
95 return SkStringPrintf("PQish %.3g %.3g %.3g %.3g %.3g %.3g",
96 tf.a,
97 tf.b,
98 tf.c,
99 tf.d,
100 tf.e,
101 tf.f)
102 .c_str();
103
104 case skcms_TFType_HLGish:
105 if (eq(tf, SkNamedTransferFn::kHLG)) {
106 return "HLG";
107 }
108 return SkStringPrintf("HLGish %.3g %.3g %.3g %.3g %.3g (%.3g)",
109 tf.a,
110 tf.b,
111 tf.c,
112 tf.d,
113 tf.e,
114 tf.f + 1)
115 .c_str();
116
117 case skcms_TFType_HLGinvish:
118 break;
119 case skcms_TFType_Invalid:
120 break;
121 }
122 return "non-numeric";
123 }
124
getGoldKeyValuePairs(std::string cpuName,std::string gpuName) const125 std::map<std::string, std::string> SurfaceManager::getGoldKeyValuePairs(std::string cpuName,
126 std::string gpuName) const {
127 std::map<std::string, std::string> kvPairs = {
128 {"surface_config", fConfig},
129 {"gamut", identify_gamut(fColorInfo.colorSpace())},
130 {"transfer_fn", identify_transfer_fn(fColorInfo.colorSpace())},
131 {"color_type", std::string(ToolUtils::colortype_name(fColorInfo.colorType()))},
132 {"alpha_type", std::string(ToolUtils::alphatype_name(fColorInfo.alphaType()))},
133 {"color_depth", std::string(ToolUtils::colortype_depth(fColorInfo.colorType()))},
134 };
135 kvPairs.merge(getCpuOrGpuKeyValuePairs(cpuName, gpuName));
136 return kvPairs;
137 }
138
getPerfKeyValuePairs(std::string cpuName,std::string gpuName) const139 std::map<std::string, std::string> SurfaceManager::getPerfKeyValuePairs(std::string cpuName,
140 std::string gpuName) const {
141 return getCpuOrGpuKeyValuePairs(cpuName, gpuName);
142 }
143
getCpuOrGpuKeyValuePairs(std::string cpuName,std::string gpuName) const144 std::map<std::string, std::string> SurfaceManager::getCpuOrGpuKeyValuePairs(
145 std::string cpuName, std::string gpuName) const {
146 // Leave these keys unset if the CPU or GPU name is not provided and the config is CPU or GPU
147 // bound, respectively. It is up to each test runner to print a warning informing the user of
148 // this behavior.
149 if ((fCpuOrGpu == CpuOrGpu::kCPU && cpuName == "") ||
150 (fCpuOrGpu == CpuOrGpu::kGPU && gpuName == "")) {
151 return std::map<std::string, std::string>();
152 }
153
154 return std::map<std::string, std::string>{
155 {"cpu_or_gpu", fCpuOrGpu == CpuOrGpu::kCPU ? "CPU" : "GPU"},
156 {"cpu_or_gpu_value", fCpuOrGpu == CpuOrGpu::kCPU ? cpuName : gpuName},
157 };
158 }
159
isCpuOrGpuBound() const160 SurfaceManager::CpuOrGpu SurfaceManager::isCpuOrGpuBound() const { return fCpuOrGpu; }
161