• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     if (args.hasWideColorGamut) {
224         // insert HDR10/HLG as we will force client composition for HDR10/HLG
225         // layers
226         if (!hasHDR10Support()) {
227             types.push_back(ui::Hdr::HDR10);
228         }
229 
230         if (!hasHLGSupport()) {
231             types.push_back(ui::Hdr::HLG);
232         }
233     }
234 
235     mHdrCapabilities = HdrCapabilities(types, maxLuminance, maxAverageLuminance, minLuminance);
236 }
237 
238 DisplayColorProfile::~DisplayColorProfile() = default;
239 
isValid() const240 bool DisplayColorProfile::isValid() const {
241     return true;
242 }
243 
hasWideColorGamut() const244 bool DisplayColorProfile::hasWideColorGamut() const {
245     return mHasWideColorGamut;
246 }
247 
getSupportedPerFrameMetadata() const248 int32_t DisplayColorProfile::getSupportedPerFrameMetadata() const {
249     return mSupportedPerFrameMetadata;
250 }
251 
hasHDR10PlusSupport() const252 bool DisplayColorProfile::hasHDR10PlusSupport() const {
253     return mHasHdr10Plus;
254 }
255 
hasHDR10Support() const256 bool DisplayColorProfile::hasHDR10Support() const {
257     return mHasHdr10;
258 }
259 
hasHLGSupport() const260 bool DisplayColorProfile::hasHLGSupport() const {
261     return mHasHLG;
262 }
263 
hasDolbyVisionSupport() const264 bool DisplayColorProfile::hasDolbyVisionSupport() const {
265     return mHasDolbyVision;
266 }
267 
getHdrCapabilities() const268 const HdrCapabilities& DisplayColorProfile::getHdrCapabilities() const {
269     return mHdrCapabilities;
270 }
271 
populateColorModes(const DisplayColorProfileCreationArgs::HwcColorModes & hwcColorModes)272 void DisplayColorProfile::populateColorModes(
273         const DisplayColorProfileCreationArgs::HwcColorModes& hwcColorModes) {
274     if (!hasWideColorGamut()) {
275         return;
276     }
277 
278     // collect all known SDR render intents
279     std::unordered_set<RenderIntent> sdrRenderIntents(sSdrRenderIntents.begin(),
280                                                       sSdrRenderIntents.end());
281     auto iter = hwcColorModes.find(ColorMode::SRGB);
282     if (iter != hwcColorModes.end()) {
283         for (auto intent : iter->second) {
284             sdrRenderIntents.insert(intent);
285         }
286     }
287 
288     // add all known SDR combinations
289     for (auto intent : sdrRenderIntents) {
290         for (auto mode : sSdrColorModes) {
291             addColorMode(hwcColorModes, mode, intent);
292         }
293     }
294 
295     // collect all known HDR render intents
296     std::unordered_set<RenderIntent> hdrRenderIntents(sHdrRenderIntents.begin(),
297                                                       sHdrRenderIntents.end());
298     iter = hwcColorModes.find(ColorMode::BT2100_PQ);
299     if (iter != hwcColorModes.end()) {
300         for (auto intent : iter->second) {
301             hdrRenderIntents.insert(intent);
302         }
303     }
304 
305     // add all known HDR combinations
306     for (auto intent : hdrRenderIntents) {
307         for (auto mode : sHdrColorModes) {
308             addColorMode(hwcColorModes, mode, intent);
309         }
310     }
311 }
312 
313 // Map dataspace/intent to the best matched dataspace/colorMode/renderIntent
314 // supported by HWC.
addColorMode(const DisplayColorProfileCreationArgs::HwcColorModes & hwcColorModes,const ColorMode mode,const RenderIntent intent)315 void DisplayColorProfile::addColorMode(
316         const DisplayColorProfileCreationArgs::HwcColorModes& hwcColorModes, const ColorMode mode,
317         const RenderIntent intent) {
318     // find the best color mode
319     const ColorMode hwcColorMode = getHwcColorMode(hwcColorModes, mode);
320 
321     // find the best render intent
322     auto iter = hwcColorModes.find(hwcColorMode);
323     const auto& hwcIntents =
324             iter != hwcColorModes.end() ? iter->second : std::vector<RenderIntent>();
325     const RenderIntent hwcIntent = getHwcRenderIntent(hwcIntents, intent);
326 
327     const Dataspace dataspace = colorModeToDataspace(mode);
328     const Dataspace hwcDataspace = colorModeToDataspace(hwcColorMode);
329 
330     ALOGV("DisplayColorProfile: map (%s, %s) to (%s, %s, %s)",
331           dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(),
332           decodeRenderIntent(intent).c_str(),
333           dataspaceDetails(static_cast<android_dataspace_t>(hwcDataspace)).c_str(),
334           decodeColorMode(hwcColorMode).c_str(), decodeRenderIntent(hwcIntent).c_str());
335 
336     mColorModes[getColorModeKey(dataspace, intent)] = {hwcDataspace, hwcColorMode, hwcIntent};
337 }
338 
hasRenderIntent(RenderIntent intent) const339 bool DisplayColorProfile::hasRenderIntent(RenderIntent intent) const {
340     // assume a render intent is supported when SRGB supports it; we should
341     // get rid of that assumption.
342     auto iter = mColorModes.find(getColorModeKey(Dataspace::V0_SRGB, intent));
343     return iter != mColorModes.end() && iter->second.renderIntent == intent;
344 }
345 
hasLegacyHdrSupport(Dataspace dataspace) const346 bool DisplayColorProfile::hasLegacyHdrSupport(Dataspace dataspace) const {
347     if ((dataspace == Dataspace::BT2020_PQ && hasHDR10Support()) ||
348         (dataspace == Dataspace::BT2020_HLG && hasHLGSupport())) {
349         auto iter =
350                 mColorModes.find(getColorModeKey(dataspace, RenderIntent::TONE_MAP_COLORIMETRIC));
351         return iter == mColorModes.end() || iter->second.dataspace != dataspace;
352     }
353 
354     return false;
355 }
356 
getBestColorMode(Dataspace dataspace,RenderIntent intent,Dataspace * outDataspace,ColorMode * outMode,RenderIntent * outIntent) const357 void DisplayColorProfile::getBestColorMode(Dataspace dataspace, RenderIntent intent,
358                                            Dataspace* outDataspace, ColorMode* outMode,
359                                            RenderIntent* outIntent) const {
360     auto iter = mColorModes.find(getColorModeKey(dataspace, intent));
361     if (iter != mColorModes.end()) {
362         *outDataspace = iter->second.dataspace;
363         *outMode = iter->second.colorMode;
364         *outIntent = iter->second.renderIntent;
365     } else {
366         // this is unexpected on a WCG display
367         if (hasWideColorGamut()) {
368             ALOGE("map unknown (%s)/(%s) to default color mode",
369                   dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(),
370                   decodeRenderIntent(intent).c_str());
371         }
372 
373         *outDataspace = Dataspace::UNKNOWN;
374         *outMode = ColorMode::NATIVE;
375         *outIntent = RenderIntent::COLORIMETRIC;
376     }
377 }
378 
isDataspaceSupported(Dataspace dataspace) const379 bool DisplayColorProfile::isDataspaceSupported(Dataspace dataspace) const {
380     switch (dataspace) {
381         case Dataspace::BT2020_PQ:
382         case Dataspace::BT2020_ITU_PQ:
383             return hasHDR10Support();
384 
385         case Dataspace::BT2020_HLG:
386         case Dataspace::BT2020_ITU_HLG:
387             return hasHLGSupport();
388 
389         default:
390             return true;
391     }
392 }
393 
getTargetDataspace(ColorMode mode,Dataspace dataspace,Dataspace colorSpaceAgnosticDataspace) const394 ui::Dataspace DisplayColorProfile::getTargetDataspace(ColorMode mode, Dataspace dataspace,
395                                                       Dataspace colorSpaceAgnosticDataspace) const {
396     if (isHdrColorMode(mode)) {
397         return Dataspace::UNKNOWN;
398     }
399     if (colorSpaceAgnosticDataspace != ui::Dataspace::UNKNOWN) {
400         return colorSpaceAgnosticDataspace;
401     }
402     return dataspace;
403 }
404 
dump(std::string & out) const405 void DisplayColorProfile::dump(std::string& out) const {
406     out.append("   Composition Display Color State:");
407 
408     out.append("\n   HWC Support: ");
409 
410     dumpVal(out, "wideColorGamut", hasWideColorGamut());
411     dumpVal(out, "hdr10plus", hasHDR10PlusSupport());
412     dumpVal(out, "hdr10", hasHDR10Support());
413     dumpVal(out, "hlg", hasHLGSupport());
414     dumpVal(out, "dv", hasDolbyVisionSupport());
415     dumpVal(out, "metadata", getSupportedPerFrameMetadata());
416 
417     out.append("\n");
418 }
419 
420 } // namespace impl
421 } // namespace android::compositionengine
422