1 /*
2 * Copyright 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <array>
18 #include <unordered_set>
19
20 #include <compositionengine/CompositionEngine.h>
21 #include <compositionengine/Display.h>
22 #include <compositionengine/DisplayColorProfileCreationArgs.h>
23 #include <compositionengine/RenderSurface.h>
24 #include <compositionengine/impl/DisplayColorProfile.h>
25 #include <compositionengine/impl/DumpHelpers.h>
26 #include <log/log.h>
27 #include <ui/DebugUtils.h>
28
29 #include "DisplayHardware/HWComposer.h"
30
31 namespace android::compositionengine {
32
33 DisplayColorProfile::~DisplayColorProfile() = default;
34
35 namespace impl {
36 namespace {
37
38 using ui::ColorMode;
39 using ui::Dataspace;
40 using ui::RenderIntent;
41
42 // ordered list of known SDR color modes
43 const std::array<ColorMode, 3> sSdrColorModes = {
44 ColorMode::DISPLAY_BT2020,
45 ColorMode::DISPLAY_P3,
46 ColorMode::SRGB,
47 };
48
49 // ordered list of known HDR color modes
50 const std::array<ColorMode, 2> sHdrColorModes = {
51 ColorMode::BT2100_PQ,
52 ColorMode::BT2100_HLG,
53 };
54
55 // ordered list of known SDR render intents
56 const std::array<RenderIntent, 2> sSdrRenderIntents = {
57 RenderIntent::ENHANCE,
58 RenderIntent::COLORIMETRIC,
59 };
60
61 // ordered list of known HDR render intents
62 const std::array<RenderIntent, 2> sHdrRenderIntents = {
63 RenderIntent::TONE_MAP_ENHANCE,
64 RenderIntent::TONE_MAP_COLORIMETRIC,
65 };
66
67 // Returns true if the given colorMode is considered an HDR color mode
isHdrColorMode(const ColorMode colorMode)68 bool isHdrColorMode(const ColorMode colorMode) {
69 return std::any_of(std::begin(sHdrColorModes), std::end(sHdrColorModes),
70 [colorMode](ColorMode hdrColorMode) { return hdrColorMode == colorMode; });
71 }
72
73 // map known color mode to dataspace
colorModeToDataspace(ColorMode mode)74 Dataspace colorModeToDataspace(ColorMode mode) {
75 switch (mode) {
76 case ColorMode::SRGB:
77 return Dataspace::V0_SRGB;
78 case ColorMode::DISPLAY_P3:
79 return Dataspace::DISPLAY_P3;
80 case ColorMode::DISPLAY_BT2020:
81 return Dataspace::DISPLAY_BT2020;
82 case ColorMode::BT2100_HLG:
83 return Dataspace::BT2020_HLG;
84 case ColorMode::BT2100_PQ:
85 return Dataspace::BT2020_PQ;
86 default:
87 return Dataspace::UNKNOWN;
88 }
89 }
90
91 // Return a list of candidate color modes.
getColorModeCandidates(ColorMode mode)92 std::vector<ColorMode> getColorModeCandidates(ColorMode mode) {
93 std::vector<ColorMode> candidates;
94
95 // add mode itself
96 candidates.push_back(mode);
97
98 // check if mode is HDR
99 bool isHdr = isHdrColorMode(mode);
100
101 // add other HDR candidates when mode is HDR
102 if (isHdr) {
103 for (auto hdrMode : sHdrColorModes) {
104 if (hdrMode != mode) {
105 candidates.push_back(hdrMode);
106 }
107 }
108 }
109
110 // add other SDR candidates
111 for (auto sdrMode : sSdrColorModes) {
112 if (sdrMode != mode) {
113 candidates.push_back(sdrMode);
114 }
115 }
116
117 return candidates;
118 }
119
120 // Return a list of candidate render intents.
getRenderIntentCandidates(RenderIntent intent)121 std::vector<RenderIntent> getRenderIntentCandidates(RenderIntent intent) {
122 std::vector<RenderIntent> candidates;
123
124 // add intent itself
125 candidates.push_back(intent);
126
127 // check if intent is HDR
128 bool isHdr = false;
129 for (auto hdrIntent : sHdrRenderIntents) {
130 if (hdrIntent == intent) {
131 isHdr = true;
132 break;
133 }
134 }
135
136 if (isHdr) {
137 // add other HDR candidates when intent is HDR
138 for (auto hdrIntent : sHdrRenderIntents) {
139 if (hdrIntent != intent) {
140 candidates.push_back(hdrIntent);
141 }
142 }
143 } else {
144 // add other SDR candidates when intent is SDR
145 for (auto sdrIntent : sSdrRenderIntents) {
146 if (sdrIntent != intent) {
147 candidates.push_back(sdrIntent);
148 }
149 }
150 }
151
152 return candidates;
153 }
154
155 // Return the best color mode supported by HWC.
getHwcColorMode(const std::unordered_map<ColorMode,std::vector<RenderIntent>> & hwcColorModes,ColorMode mode)156 ColorMode getHwcColorMode(
157 const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes,
158 ColorMode mode) {
159 std::vector<ColorMode> candidates = getColorModeCandidates(mode);
160 for (auto candidate : candidates) {
161 auto iter = hwcColorModes.find(candidate);
162 if (iter != hwcColorModes.end()) {
163 return candidate;
164 }
165 }
166
167 return ColorMode::NATIVE;
168 }
169
170 // Return the best render intent supported by HWC.
getHwcRenderIntent(const std::vector<RenderIntent> & hwcIntents,RenderIntent intent)171 RenderIntent getHwcRenderIntent(const std::vector<RenderIntent>& hwcIntents, RenderIntent intent) {
172 std::vector<RenderIntent> candidates = getRenderIntentCandidates(intent);
173 for (auto candidate : candidates) {
174 for (auto hwcIntent : hwcIntents) {
175 if (candidate == hwcIntent) {
176 return candidate;
177 }
178 }
179 }
180
181 return RenderIntent::COLORIMETRIC;
182 }
183
184 } // anonymous namespace
185
createDisplayColorProfile(const DisplayColorProfileCreationArgs & args)186 std::unique_ptr<compositionengine::DisplayColorProfile> createDisplayColorProfile(
187 const DisplayColorProfileCreationArgs& args) {
188 return std::make_unique<DisplayColorProfile>(args);
189 }
190
DisplayColorProfile(const DisplayColorProfileCreationArgs & args)191 DisplayColorProfile::DisplayColorProfile(const DisplayColorProfileCreationArgs& args)
192 : mHasWideColorGamut(args.hasWideColorGamut),
193 mSupportedPerFrameMetadata(args.supportedPerFrameMetadata) {
194 populateColorModes(args.hwcColorModes);
195
196 std::vector<ui::Hdr> types = args.hdrCapabilities.getSupportedHdrTypes();
197 for (ui::Hdr hdrType : types) {
198 switch (hdrType) {
199 case ui::Hdr::HDR10_PLUS:
200 mHasHdr10Plus = true;
201 break;
202 case ui::Hdr::HDR10:
203 mHasHdr10 = true;
204 break;
205 case ui::Hdr::HLG:
206 mHasHLG = true;
207 break;
208 case ui::Hdr::DOLBY_VISION:
209 mHasDolbyVision = true;
210 break;
211 default:
212 ALOGE("UNKNOWN HDR capability: %d", static_cast<int32_t>(hdrType));
213 }
214 }
215
216 float minLuminance = args.hdrCapabilities.getDesiredMinLuminance();
217 float maxLuminance = args.hdrCapabilities.getDesiredMaxLuminance();
218 float maxAverageLuminance = args.hdrCapabilities.getDesiredMaxAverageLuminance();
219
220 minLuminance = minLuminance <= 0.0 ? sDefaultMinLumiance : minLuminance;
221 maxLuminance = maxLuminance <= 0.0 ? sDefaultMaxLumiance : maxLuminance;
222 maxAverageLuminance = maxAverageLuminance <= 0.0 ? sDefaultMaxLumiance : maxAverageLuminance;
223
224 mHdrCapabilities = HdrCapabilities(types, maxLuminance, maxAverageLuminance, minLuminance);
225 }
226
227 DisplayColorProfile::~DisplayColorProfile() = default;
228
isValid() const229 bool DisplayColorProfile::isValid() const {
230 return true;
231 }
232
hasWideColorGamut() const233 bool DisplayColorProfile::hasWideColorGamut() const {
234 return mHasWideColorGamut;
235 }
236
getSupportedPerFrameMetadata() const237 int32_t DisplayColorProfile::getSupportedPerFrameMetadata() const {
238 return mSupportedPerFrameMetadata;
239 }
240
hasHDR10PlusSupport() const241 bool DisplayColorProfile::hasHDR10PlusSupport() const {
242 return mHasHdr10Plus;
243 }
244
hasHDR10Support() const245 bool DisplayColorProfile::hasHDR10Support() const {
246 return mHasHdr10;
247 }
248
hasHLGSupport() const249 bool DisplayColorProfile::hasHLGSupport() const {
250 return mHasHLG;
251 }
252
hasDolbyVisionSupport() const253 bool DisplayColorProfile::hasDolbyVisionSupport() const {
254 return mHasDolbyVision;
255 }
256
getHdrCapabilities() const257 const HdrCapabilities& DisplayColorProfile::getHdrCapabilities() const {
258 return mHdrCapabilities;
259 }
260
populateColorModes(const DisplayColorProfileCreationArgs::HwcColorModes & hwcColorModes)261 void DisplayColorProfile::populateColorModes(
262 const DisplayColorProfileCreationArgs::HwcColorModes& hwcColorModes) {
263 if (!hasWideColorGamut()) {
264 return;
265 }
266
267 // collect all known SDR render intents
268 std::unordered_set<RenderIntent> sdrRenderIntents(sSdrRenderIntents.begin(),
269 sSdrRenderIntents.end());
270 auto iter = hwcColorModes.find(ColorMode::SRGB);
271 if (iter != hwcColorModes.end()) {
272 for (auto intent : iter->second) {
273 sdrRenderIntents.insert(intent);
274 }
275 }
276
277 // add all known SDR combinations
278 for (auto intent : sdrRenderIntents) {
279 for (auto mode : sSdrColorModes) {
280 addColorMode(hwcColorModes, mode, intent);
281 }
282 }
283
284 // collect all known HDR render intents
285 std::unordered_set<RenderIntent> hdrRenderIntents(sHdrRenderIntents.begin(),
286 sHdrRenderIntents.end());
287 iter = hwcColorModes.find(ColorMode::BT2100_PQ);
288 if (iter != hwcColorModes.end()) {
289 for (auto intent : iter->second) {
290 hdrRenderIntents.insert(intent);
291 }
292 }
293
294 // add all known HDR combinations
295 for (auto intent : hdrRenderIntents) {
296 for (auto mode : sHdrColorModes) {
297 addColorMode(hwcColorModes, mode, intent);
298 }
299 }
300 }
301
302 // Map dataspace/intent to the best matched dataspace/colorMode/renderIntent
303 // supported by HWC.
addColorMode(const DisplayColorProfileCreationArgs::HwcColorModes & hwcColorModes,const ColorMode mode,const RenderIntent intent)304 void DisplayColorProfile::addColorMode(
305 const DisplayColorProfileCreationArgs::HwcColorModes& hwcColorModes, const ColorMode mode,
306 const RenderIntent intent) {
307 // find the best color mode
308 const ColorMode hwcColorMode = getHwcColorMode(hwcColorModes, mode);
309
310 // find the best render intent
311 auto iter = hwcColorModes.find(hwcColorMode);
312 const auto& hwcIntents =
313 iter != hwcColorModes.end() ? iter->second : std::vector<RenderIntent>();
314 const RenderIntent hwcIntent = getHwcRenderIntent(hwcIntents, intent);
315
316 const Dataspace dataspace = colorModeToDataspace(mode);
317 const Dataspace hwcDataspace = colorModeToDataspace(hwcColorMode);
318
319 ALOGV("DisplayColorProfile: map (%s, %s) to (%s, %s, %s)",
320 dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(),
321 decodeRenderIntent(intent).c_str(),
322 dataspaceDetails(static_cast<android_dataspace_t>(hwcDataspace)).c_str(),
323 decodeColorMode(hwcColorMode).c_str(), decodeRenderIntent(hwcIntent).c_str());
324
325 mColorModes[getColorModeKey(dataspace, intent)] = {hwcDataspace, hwcColorMode, hwcIntent};
326 }
327
hasRenderIntent(RenderIntent intent) const328 bool DisplayColorProfile::hasRenderIntent(RenderIntent intent) const {
329 // assume a render intent is supported when SRGB supports it; we should
330 // get rid of that assumption.
331 auto iter = mColorModes.find(getColorModeKey(Dataspace::V0_SRGB, intent));
332 return iter != mColorModes.end() && iter->second.renderIntent == intent;
333 }
334
hasLegacyHdrSupport(Dataspace dataspace) const335 bool DisplayColorProfile::hasLegacyHdrSupport(Dataspace dataspace) const {
336 if ((dataspace == Dataspace::BT2020_PQ && hasHDR10Support()) ||
337 (dataspace == Dataspace::BT2020_HLG && hasHLGSupport())) {
338 auto iter =
339 mColorModes.find(getColorModeKey(dataspace, RenderIntent::TONE_MAP_COLORIMETRIC));
340 return iter == mColorModes.end() || iter->second.dataspace != dataspace;
341 }
342
343 return false;
344 }
345
getBestColorMode(Dataspace dataspace,RenderIntent intent,Dataspace * outDataspace,ColorMode * outMode,RenderIntent * outIntent) const346 void DisplayColorProfile::getBestColorMode(Dataspace dataspace, RenderIntent intent,
347 Dataspace* outDataspace, ColorMode* outMode,
348 RenderIntent* outIntent) const {
349 auto iter = mColorModes.find(getColorModeKey(dataspace, intent));
350 if (iter != mColorModes.end()) {
351 *outDataspace = iter->second.dataspace;
352 *outMode = iter->second.colorMode;
353 *outIntent = iter->second.renderIntent;
354 } else {
355 // this is unexpected on a WCG display
356 if (hasWideColorGamut()) {
357 ALOGE("map unknown (%s)/(%s) to default color mode",
358 dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(),
359 decodeRenderIntent(intent).c_str());
360 }
361
362 *outDataspace = Dataspace::UNKNOWN;
363 *outMode = ColorMode::NATIVE;
364 *outIntent = RenderIntent::COLORIMETRIC;
365 }
366 }
367
isDataspaceSupported(Dataspace dataspace) const368 bool DisplayColorProfile::isDataspaceSupported(Dataspace dataspace) const {
369 switch (dataspace) {
370 case Dataspace::BT2020_PQ:
371 case Dataspace::BT2020_ITU_PQ:
372 return hasHDR10Support();
373
374 case Dataspace::BT2020_HLG:
375 case Dataspace::BT2020_ITU_HLG:
376 return hasHLGSupport();
377
378 default:
379 return true;
380 }
381 }
382
dump(std::string & out) const383 void DisplayColorProfile::dump(std::string& out) const {
384 out.append(" Composition Display Color State:");
385
386 out.append("\n HWC Support: ");
387
388 dumpVal(out, "wideColorGamut", hasWideColorGamut());
389 dumpVal(out, "hdr10plus", hasHDR10PlusSupport());
390 dumpVal(out, "hdr10", hasHDR10Support());
391 dumpVal(out, "hlg", hasHLGSupport());
392 dumpVal(out, "dv", hasDolbyVisionSupport());
393 dumpVal(out, "metadata", getSupportedPerFrameMetadata());
394
395 out.append("\n Hdr Luminance Info:");
396 dumpVal(out, "desiredMinLuminance", mHdrCapabilities.getDesiredMinLuminance());
397 dumpVal(out, "desiredMaxLuminance", mHdrCapabilities.getDesiredMaxLuminance());
398 dumpVal(out, "desiredMaxAverageLuminance", mHdrCapabilities.getDesiredMaxAverageLuminance());
399 out.append("\n");
400 }
401
402 } // namespace impl
403 } // namespace android::compositionengine
404