Loading services/surfaceflinger/DisplayDevice.cpp +229 −30 Original line number Diff line number Diff line Loading @@ -18,6 +18,9 @@ #undef LOG_TAG #define LOG_TAG "DisplayDevice" #include <array> #include <unordered_set> #include <stdlib.h> #include <stdio.h> #include <string.h> Loading Loading @@ -55,6 +58,7 @@ namespace android { using namespace android::hardware::configstore; using namespace android::hardware::configstore::V1_0; using android::ui::ColorMode; using android::ui::Dataspace; using android::ui::Hdr; using android::ui::RenderIntent; Loading @@ -65,6 +69,147 @@ using android::ui::RenderIntent; uint32_t DisplayDevice::sPrimaryDisplayOrientation = 0; namespace { // ordered list of known SDR color modes const std::array<ColorMode, 2> sSdrColorModes = { ColorMode::DISPLAY_P3, ColorMode::SRGB, }; // ordered list of known HDR color modes const std::array<ColorMode, 2> sHdrColorModes = { ColorMode::BT2100_PQ, ColorMode::BT2100_HLG, }; // ordered list of known SDR render intents const std::array<RenderIntent, 2> sSdrRenderIntents = { RenderIntent::ENHANCE, RenderIntent::COLORIMETRIC, }; // ordered list of known HDR render intents const std::array<RenderIntent, 2> sHdrRenderIntents = { RenderIntent::TONE_MAP_ENHANCE, RenderIntent::TONE_MAP_COLORIMETRIC, }; // map known color mode to dataspace Dataspace colorModeToDataspace(ColorMode mode) { switch (mode) { case ColorMode::SRGB: return Dataspace::SRGB; case ColorMode::DISPLAY_P3: return Dataspace::DISPLAY_P3; case ColorMode::BT2100_HLG: return Dataspace::BT2020_HLG; case ColorMode::BT2100_PQ: return Dataspace::BT2020_PQ; default: return Dataspace::UNKNOWN; } } // Return a list of candidate color modes. std::vector<ColorMode> getColorModeCandidates(ColorMode mode) { std::vector<ColorMode> candidates; // add mode itself candidates.push_back(mode); // check if mode is HDR bool isHdr = false; for (auto hdrMode : sHdrColorModes) { if (hdrMode == mode) { isHdr = true; break; } } // add other HDR candidates when mode is HDR if (isHdr) { for (auto hdrMode : sHdrColorModes) { if (hdrMode != mode) { candidates.push_back(hdrMode); } } } // add other SDR candidates for (auto sdrMode : sSdrColorModes) { if (sdrMode != mode) { candidates.push_back(sdrMode); } } return candidates; } // Return a list of candidate render intents. std::vector<RenderIntent> getRenderIntentCandidates(RenderIntent intent) { std::vector<RenderIntent> candidates; // add intent itself candidates.push_back(intent); // check if intent is HDR bool isHdr = false; for (auto hdrIntent : sHdrRenderIntents) { if (hdrIntent == intent) { isHdr = true; break; } } // add other HDR candidates when intent is HDR if (isHdr) { for (auto hdrIntent : sHdrRenderIntents) { if (hdrIntent != intent) { candidates.push_back(hdrIntent); } } } // add COLORIMETRIC if (intent != RenderIntent::COLORIMETRIC) { candidates.push_back(RenderIntent::COLORIMETRIC); } return candidates; } // Return the best color mode supported by HWC. ColorMode getHwcColorMode( const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes, ColorMode mode) { std::vector<ColorMode> candidates = getColorModeCandidates(mode); for (auto candidate : candidates) { auto iter = hwcColorModes.find(candidate); if (iter != hwcColorModes.end()) { return candidate; } } return ColorMode::NATIVE; } // Return the best render intent supported by HWC. RenderIntent getHwcRenderIntent(const std::vector<RenderIntent>& hwcIntents, RenderIntent intent) { std::vector<RenderIntent> candidates = getRenderIntentCandidates(intent); for (auto candidate : candidates) { for (auto hwcIntent : hwcIntents) { if (candidate == hwcIntent) { return candidate; } } } return RenderIntent::COLORIMETRIC; } } // anonymous namespace // clang-format off DisplayDevice::DisplayDevice( const sp<SurfaceFlinger>& flinger, Loading @@ -80,7 +225,7 @@ DisplayDevice::DisplayDevice( bool hasWideColorGamut, const HdrCapabilities& hdrCapabilities, const int32_t supportedPerFrameMetadata, const std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>& hdrAndRenderIntents, const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes, int initialPowerMode) : lastCompositionHadVisibleLayers(false), mFlinger(flinger), Loading @@ -105,13 +250,11 @@ DisplayDevice::DisplayDevice( mHasHdr10(false), mHasHLG(false), mHasDolbyVision(false), mSupportedPerFrameMetadata(supportedPerFrameMetadata), mHasBT2100PQColorimetric(false), mHasBT2100PQEnhance(false), mHasBT2100HLGColorimetric(false), mHasBT2100HLGEnhance(false) mSupportedPerFrameMetadata(supportedPerFrameMetadata) { // clang-format on populateColorModes(hwcColorModes); std::vector<Hdr> types = hdrCapabilities.getSupportedHdrTypes(); for (Hdr hdrType : types) { switch (hdrType) { Loading Loading @@ -149,18 +292,6 @@ DisplayDevice::DisplayDevice( } mHdrCapabilities = HdrCapabilities(types, maxLuminance, maxAverageLuminance, minLuminance); auto iter = hdrAndRenderIntents.find(ColorMode::BT2100_PQ); if (iter != hdrAndRenderIntents.end()) { hasToneMapping(iter->second, &mHasBT2100PQColorimetric, &mHasBT2100PQEnhance); } iter = hdrAndRenderIntents.find(ColorMode::BT2100_HLG); if (iter != hdrAndRenderIntents.end()) { hasToneMapping(iter->second, &mHasBT2100HLGColorimetric, &mHasBT2100HLGEnhance); } // initialize the display orientation transform. setProjection(DisplayState::eOrientationDefault, mViewport, mFrame); } Loading Loading @@ -544,19 +675,87 @@ void DisplayDevice::dump(String8& result) const { result.append(surfaceDump); } void DisplayDevice::hasToneMapping(const std::vector<RenderIntent>& renderIntents, bool* outColorimetric, bool *outEnhance) { for (auto intent : renderIntents) { switch (intent) { case RenderIntent::TONE_MAP_COLORIMETRIC: *outColorimetric = true; break; case RenderIntent::TONE_MAP_ENHANCE: *outEnhance = true; break; default: break; // Map dataspace/intent to the best matched dataspace/colorMode/renderIntent // supported by HWC. void DisplayDevice::addColorMode( const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes, const ColorMode mode, const RenderIntent intent) { // find the best color mode const ColorMode hwcColorMode = getHwcColorMode(hwcColorModes, mode); // find the best render intent auto iter = hwcColorModes.find(hwcColorMode); const auto& hwcIntents = iter != hwcColorModes.end() ? iter->second : std::vector<RenderIntent>(); const RenderIntent hwcIntent = getHwcRenderIntent(hwcIntents, intent); const Dataspace dataspace = colorModeToDataspace(mode); const Dataspace hwcDataspace = colorModeToDataspace(hwcColorMode); ALOGV("DisplayDevice %d/%d: map (%s, %s) to (%s, %s, %s)", mType, mHwcDisplayId, dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(), decodeRenderIntent(intent).c_str(), dataspaceDetails(static_cast<android_dataspace_t>(hwcDataspace)).c_str(), decodeColorMode(hwcColorMode).c_str(), decodeRenderIntent(hwcIntent).c_str()); mColorModes[getColorModeKey(dataspace, intent)] = {hwcDataspace, hwcColorMode, hwcIntent}; } void DisplayDevice::populateColorModes( const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes) { if (!hasWideColorGamut()) { return; } // add known SDR combinations for (auto intent : sSdrRenderIntents) { for (auto mode : sSdrColorModes) { addColorMode(hwcColorModes, mode, intent); } } // add known HDR combinations for (auto intent : sHdrRenderIntents) { for (auto mode : sHdrColorModes) { addColorMode(hwcColorModes, mode, intent); } } } bool DisplayDevice::hasRenderIntent(RenderIntent intent) const { // assume a render intent is supported when SRGB supports it; we should // get rid of that assumption. auto iter = mColorModes.find(getColorModeKey(Dataspace::SRGB, intent)); return iter != mColorModes.end() && iter->second.renderIntent == intent; } bool DisplayDevice::hasModernHdrSupport(Dataspace dataspace) const { if ((dataspace == Dataspace::BT2020_PQ && hasHDR10Support()) || (dataspace == Dataspace::BT2020_HLG && hasHLGSupport())) { auto iter = mColorModes.find(getColorModeKey(dataspace, RenderIntent::TONE_MAP_COLORIMETRIC)); return iter != mColorModes.end() && iter->second.dataspace == dataspace; } return false; } void DisplayDevice::getBestColorMode(Dataspace dataspace, RenderIntent intent, Dataspace* outDataspace, ColorMode* outMode, RenderIntent* outIntent) const { auto iter = mColorModes.find(getColorModeKey(dataspace, intent)); if (iter != mColorModes.end()) { *outDataspace = iter->second.dataspace; *outMode = iter->second.colorMode; *outIntent = iter->second.renderIntent; } else { ALOGE("map unknown (%s)/(%s) to default color mode", dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(), decodeRenderIntent(intent).c_str()); *outDataspace = Dataspace::UNKNOWN; *outMode = ColorMode::NATIVE; *outIntent = RenderIntent::COLORIMETRIC; } } Loading services/surfaceflinger/DisplayDevice.h +32 −16 Original line number Diff line number Diff line Loading @@ -92,7 +92,7 @@ public: bool hasWideColorGamut, const HdrCapabilities& hdrCapabilities, const int32_t supportedPerFrameMetadata, const std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>& hdrAndRenderIntents, const std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>& hwcColorModes, int initialPowerMode); // clang-format on Loading Loading @@ -145,11 +145,17 @@ public: // machine happy without actually queueing a buffer if nothing has changed status_t beginFrame(bool mustRecompose) const; status_t prepareFrame(HWComposer& hwc); bool hasWideColorGamut() const { return mHasWideColorGamut; } // Whether h/w composer has native support for specific HDR type. bool hasHDR10Support() const { return mHasHdr10; } bool hasHLGSupport() const { return mHasHLG; } bool hasDolbyVisionSupport() const { return mHasDolbyVision; } // Return true if the corresponding color mode for the HDR dataspace is // supported. bool hasModernHdrSupport(ui::Dataspace dataspace) const; // The returned HdrCapabilities is the combination of HDR capabilities from // hardware composer and RenderEngine. When the DisplayDevice supports wide // color gamut, RenderEngine is able to simulate HDR support in Display P3 Loading @@ -158,13 +164,12 @@ public: // respectively if hardware composer doesn't return meaningful values. const HdrCapabilities& getHdrCapabilities() const { return mHdrCapabilities; } // Whether h/w composer has BT2100_PQ color mode. bool hasBT2100PQColorimetricSupport() const { return mHasBT2100PQColorimetric; } bool hasBT2100PQEnhanceSupport() const { return mHasBT2100PQEnhance; } // Return true if intent is supported by the display. bool hasRenderIntent(ui::RenderIntent intent) const; // Whether h/w composer has BT2100_HLG color mode. bool hasBT2100HLGColorimetricSupport() const { return mHasBT2100HLGColorimetric; } bool hasBT2100HLGEnhanceSupport() const { return mHasBT2100HLGEnhance; } void getBestColorMode(ui::Dataspace dataspace, ui::RenderIntent intent, ui::Dataspace* outDataspace, ui::ColorMode* outMode, ui::RenderIntent* outIntent) const; void swapBuffers(HWComposer& hwc) const; Loading Loading @@ -216,9 +221,6 @@ public: void dump(String8& result) const; private: void hasToneMapping(const std::vector<ui::RenderIntent>& renderIntents, bool* outColorimetric, bool *outEnhance); /* * Constants, set during initialization */ Loading Loading @@ -290,12 +292,26 @@ private: bool mHasDolbyVision; HdrCapabilities mHdrCapabilities; const int32_t mSupportedPerFrameMetadata; // Whether h/w composer has BT2100_PQ and BT2100_HLG color mode with // colorimetrical tone mapping or enhanced tone mapping. bool mHasBT2100PQColorimetric; bool mHasBT2100PQEnhance; bool mHasBT2100HLGColorimetric; bool mHasBT2100HLGEnhance; // Mappings from desired Dataspace/RenderIntent to the supported // Dataspace/ColorMode/RenderIntent. using ColorModeKey = uint64_t; struct ColorModeValue { ui::Dataspace dataspace; ui::ColorMode colorMode; ui::RenderIntent renderIntent; }; static ColorModeKey getColorModeKey(ui::Dataspace dataspace, ui::RenderIntent intent) { return (static_cast<uint64_t>(dataspace) << 32) | static_cast<uint32_t>(intent); } void populateColorModes( const std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>& hwcColorModes); void addColorMode( const std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>& hwcColorModes, const ui::ColorMode mode, const ui::RenderIntent intent); std::unordered_map<ColorModeKey, ColorModeValue> mColorModes; }; struct DisplayDeviceState { Loading services/surfaceflinger/SurfaceFlinger.cpp +17 −115 Original line number Diff line number Diff line Loading @@ -1870,7 +1870,6 @@ void SurfaceFlinger::rebuildLayerStacks() { // can only be one of // - Dataspace::SRGB (use legacy dataspace and let HWC saturate when colors are enhanced) // - Dataspace::DISPLAY_P3 // - Dataspace::V0_SCRGB_LINEAR // The returned HDR data space is one of // - Dataspace::UNKNOWN // - Dataspace::BT2020_HLG Loading @@ -1884,12 +1883,8 @@ Dataspace SurfaceFlinger::getBestDataspace( switch (layer->getDataSpace()) { case Dataspace::V0_SCRGB: case Dataspace::V0_SCRGB_LINEAR: bestDataSpace = Dataspace::V0_SCRGB_LINEAR; break; case Dataspace::DISPLAY_P3: if (bestDataSpace == Dataspace::SRGB) { bestDataSpace = Dataspace::DISPLAY_P3; } break; case Dataspace::BT2020_PQ: case Dataspace::BT2020_ITU_PQ: Loading Loading @@ -1925,103 +1920,17 @@ void SurfaceFlinger::pickColorMode(const sp<DisplayDevice>& displayDevice, Dataspace hdrDataSpace; Dataspace bestDataSpace = getBestDataspace(displayDevice, &hdrDataSpace); if (hdrDataSpace == Dataspace::BT2020_PQ) { // Hardware composer can handle BT2100 ColorMode only when // - colorimetrical tone mapping is supported, or // - Auto mode is turned on and enhanced tone mapping is supported. if (displayDevice->hasBT2100PQColorimetricSupport() || (mDisplayColorSetting == DisplayColorSetting::ENHANCED && displayDevice->hasBT2100PQEnhanceSupport())) { *outMode = ColorMode::BT2100_PQ; *outDataSpace = Dataspace::BT2020_PQ; } else if (displayDevice->hasHDR10Support()) { // Legacy HDR support. HDR layers are treated as UNKNOWN layers. hdrDataSpace = Dataspace::UNKNOWN; } else { // Simulate PQ through RenderEngine, pick DISPLAY_P3 color mode. *outMode = ColorMode::DISPLAY_P3; *outDataSpace = Dataspace::DISPLAY_P3; } } else if (hdrDataSpace == Dataspace::BT2020_HLG) { if (displayDevice->hasBT2100HLGColorimetricSupport() || (mDisplayColorSetting == DisplayColorSetting::ENHANCED && displayDevice->hasBT2100HLGEnhanceSupport())) { *outMode = ColorMode::BT2100_HLG; *outDataSpace = Dataspace::BT2020_HLG; } else if (displayDevice->hasHLGSupport()) { // Legacy HDR support. HDR layers are treated as UNKNOWN layers. hdrDataSpace = Dataspace::UNKNOWN; } else { // Simulate HLG through RenderEngine, pick DISPLAY_P3 color mode. *outMode = ColorMode::DISPLAY_P3; *outDataSpace = Dataspace::DISPLAY_P3; } } RenderIntent intent = mDisplayColorSetting == DisplayColorSetting::ENHANCED ? RenderIntent::ENHANCE : RenderIntent::COLORIMETRIC; // At this point, there's no HDR layer. if (hdrDataSpace == Dataspace::UNKNOWN) { switch (bestDataSpace) { case Dataspace::DISPLAY_P3: case Dataspace::V0_SCRGB_LINEAR: *outMode = ColorMode::DISPLAY_P3; *outDataSpace = Dataspace::DISPLAY_P3; break; default: *outMode = ColorMode::SRGB; *outDataSpace = Dataspace::SRGB; break; } } *outRenderIntent = pickRenderIntent(displayDevice, *outMode); } RenderIntent SurfaceFlinger::pickRenderIntent(const sp<DisplayDevice>& displayDevice, ColorMode colorMode) const { // Native Mode means the display is not color managed, and whichever // render intent is picked doesn't matter, thus return // RenderIntent::COLORIMETRIC as default here. if (mDisplayColorSetting == DisplayColorSetting::UNMANAGED) { return RenderIntent::COLORIMETRIC; } // In Auto Color Mode, we want to strech to panel color space, right now // only the built-in display supports it. if (mDisplayColorSetting == DisplayColorSetting::ENHANCED && mBuiltinDisplaySupportsEnhance && displayDevice->isPrimary()) { switch (colorMode) { case ColorMode::DISPLAY_P3: case ColorMode::SRGB: return RenderIntent::ENHANCE; // In Auto Color Mode, BT2100_PQ and BT2100_HLG will only be picked // when TONE_MAP_ENHANCE or TONE_MAP_COLORIMETRIC is supported. // If TONE_MAP_ENHANCE is not supported, fall back to TONE_MAP_COLORIMETRIC. case ColorMode::BT2100_PQ: return displayDevice->hasBT2100PQEnhanceSupport() ? RenderIntent::TONE_MAP_ENHANCE : RenderIntent::TONE_MAP_COLORIMETRIC; case ColorMode::BT2100_HLG: return displayDevice->hasBT2100HLGEnhanceSupport() ? // respect hdrDataSpace only when there is modern HDR support if (hdrDataSpace != Dataspace::UNKNOWN && displayDevice->hasModernHdrSupport(hdrDataSpace)) { bestDataSpace = hdrDataSpace; intent = mDisplayColorSetting == DisplayColorSetting::ENHANCED ? RenderIntent::TONE_MAP_ENHANCE : RenderIntent::TONE_MAP_COLORIMETRIC; // This statement shouldn't be reached, switch cases will always // cover all possible ColorMode returned by pickColorMode. default: return RenderIntent::COLORIMETRIC; } } // Either enhance is not supported or we are in natural mode. // Natural Mode means it's color managed and the color must be right, // thus we pick RenderIntent::COLORIMETRIC as render intent for non-HDR // content and pick RenderIntent::TONE_MAP_COLORIMETRIC for HDR content. switch (colorMode) { // In Natural Color Mode, BT2100_PQ and BT2100_HLG will only be picked // when TONE_MAP_COLORIMETRIC is supported. case ColorMode::BT2100_PQ: case ColorMode::BT2100_HLG: return RenderIntent::TONE_MAP_COLORIMETRIC; default: return RenderIntent::COLORIMETRIC; } displayDevice->getBestColorMode(bestDataSpace, intent, outDataSpace, outMode, outRenderIntent); } void SurfaceFlinger::setUpHWComposer() { Loading Loading @@ -2338,7 +2247,7 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( const wp<IBinder>& display, int hwcId, const DisplayDeviceState& state, const sp<DisplaySurface>& dispSurface, const sp<IGraphicBufferProducer>& producer) { bool hasWideColorGamut = false; std::unordered_map<ColorMode, std::vector<RenderIntent>> hdrAndRenderIntents; std::unordered_map<ColorMode, std::vector<RenderIntent>> hwcColorModes; if (hasWideColorDisplay) { std::vector<ColorMode> modes = getHwComposer().getColorModes(hwcId); Loading @@ -2355,18 +2264,7 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( std::vector<RenderIntent> renderIntents = getHwComposer().getRenderIntents(hwcId, colorMode); if (state.type == DisplayDevice::DISPLAY_PRIMARY) { for (auto intent : renderIntents) { if (intent == RenderIntent::ENHANCE) { mBuiltinDisplaySupportsEnhance = true; break; } } } if (colorMode == ColorMode::BT2100_PQ || colorMode == ColorMode::BT2100_HLG) { hdrAndRenderIntents.emplace(colorMode, renderIntents); } hwcColorModes.emplace(colorMode, renderIntents); } } Loading Loading @@ -2405,17 +2303,21 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( dispSurface, std::move(renderSurface), displayWidth, displayHeight, hasWideColorGamut, hdrCapabilities, getHwComposer().getSupportedPerFrameMetadata(hwcId), hdrAndRenderIntents, initialPowerMode); hwcColorModes, initialPowerMode); if (maxFrameBufferAcquiredBuffers >= 3) { nativeWindowSurface->preallocateBuffers(); } if (hw->isPrimary() && hw->hasRenderIntent(RenderIntent::ENHANCE)) { mBuiltinDisplaySupportsEnhance = true; } ColorMode defaultColorMode = ColorMode::NATIVE; Dataspace defaultDataSpace = Dataspace::UNKNOWN; if (hasWideColorGamut) { defaultColorMode = ColorMode::SRGB; defaultDataSpace = Dataspace::V0_SRGB; defaultDataSpace = Dataspace::SRGB; } setActiveColorModeInternal(hw, defaultColorMode, defaultDataSpace, RenderIntent::COLORIMETRIC); Loading services/surfaceflinger/SurfaceFlinger.h +0 −2 Original line number Diff line number Diff line Loading @@ -666,8 +666,6 @@ private: ui::ColorMode* outMode, ui::Dataspace* outDataSpace, ui::RenderIntent* outRenderIntent) const; ui::RenderIntent pickRenderIntent(const sp<DisplayDevice>& displayDevice, ui::ColorMode colorMode) const; void setUpHWComposer(); void doComposition(); Loading Loading
services/surfaceflinger/DisplayDevice.cpp +229 −30 Original line number Diff line number Diff line Loading @@ -18,6 +18,9 @@ #undef LOG_TAG #define LOG_TAG "DisplayDevice" #include <array> #include <unordered_set> #include <stdlib.h> #include <stdio.h> #include <string.h> Loading Loading @@ -55,6 +58,7 @@ namespace android { using namespace android::hardware::configstore; using namespace android::hardware::configstore::V1_0; using android::ui::ColorMode; using android::ui::Dataspace; using android::ui::Hdr; using android::ui::RenderIntent; Loading @@ -65,6 +69,147 @@ using android::ui::RenderIntent; uint32_t DisplayDevice::sPrimaryDisplayOrientation = 0; namespace { // ordered list of known SDR color modes const std::array<ColorMode, 2> sSdrColorModes = { ColorMode::DISPLAY_P3, ColorMode::SRGB, }; // ordered list of known HDR color modes const std::array<ColorMode, 2> sHdrColorModes = { ColorMode::BT2100_PQ, ColorMode::BT2100_HLG, }; // ordered list of known SDR render intents const std::array<RenderIntent, 2> sSdrRenderIntents = { RenderIntent::ENHANCE, RenderIntent::COLORIMETRIC, }; // ordered list of known HDR render intents const std::array<RenderIntent, 2> sHdrRenderIntents = { RenderIntent::TONE_MAP_ENHANCE, RenderIntent::TONE_MAP_COLORIMETRIC, }; // map known color mode to dataspace Dataspace colorModeToDataspace(ColorMode mode) { switch (mode) { case ColorMode::SRGB: return Dataspace::SRGB; case ColorMode::DISPLAY_P3: return Dataspace::DISPLAY_P3; case ColorMode::BT2100_HLG: return Dataspace::BT2020_HLG; case ColorMode::BT2100_PQ: return Dataspace::BT2020_PQ; default: return Dataspace::UNKNOWN; } } // Return a list of candidate color modes. std::vector<ColorMode> getColorModeCandidates(ColorMode mode) { std::vector<ColorMode> candidates; // add mode itself candidates.push_back(mode); // check if mode is HDR bool isHdr = false; for (auto hdrMode : sHdrColorModes) { if (hdrMode == mode) { isHdr = true; break; } } // add other HDR candidates when mode is HDR if (isHdr) { for (auto hdrMode : sHdrColorModes) { if (hdrMode != mode) { candidates.push_back(hdrMode); } } } // add other SDR candidates for (auto sdrMode : sSdrColorModes) { if (sdrMode != mode) { candidates.push_back(sdrMode); } } return candidates; } // Return a list of candidate render intents. std::vector<RenderIntent> getRenderIntentCandidates(RenderIntent intent) { std::vector<RenderIntent> candidates; // add intent itself candidates.push_back(intent); // check if intent is HDR bool isHdr = false; for (auto hdrIntent : sHdrRenderIntents) { if (hdrIntent == intent) { isHdr = true; break; } } // add other HDR candidates when intent is HDR if (isHdr) { for (auto hdrIntent : sHdrRenderIntents) { if (hdrIntent != intent) { candidates.push_back(hdrIntent); } } } // add COLORIMETRIC if (intent != RenderIntent::COLORIMETRIC) { candidates.push_back(RenderIntent::COLORIMETRIC); } return candidates; } // Return the best color mode supported by HWC. ColorMode getHwcColorMode( const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes, ColorMode mode) { std::vector<ColorMode> candidates = getColorModeCandidates(mode); for (auto candidate : candidates) { auto iter = hwcColorModes.find(candidate); if (iter != hwcColorModes.end()) { return candidate; } } return ColorMode::NATIVE; } // Return the best render intent supported by HWC. RenderIntent getHwcRenderIntent(const std::vector<RenderIntent>& hwcIntents, RenderIntent intent) { std::vector<RenderIntent> candidates = getRenderIntentCandidates(intent); for (auto candidate : candidates) { for (auto hwcIntent : hwcIntents) { if (candidate == hwcIntent) { return candidate; } } } return RenderIntent::COLORIMETRIC; } } // anonymous namespace // clang-format off DisplayDevice::DisplayDevice( const sp<SurfaceFlinger>& flinger, Loading @@ -80,7 +225,7 @@ DisplayDevice::DisplayDevice( bool hasWideColorGamut, const HdrCapabilities& hdrCapabilities, const int32_t supportedPerFrameMetadata, const std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>& hdrAndRenderIntents, const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes, int initialPowerMode) : lastCompositionHadVisibleLayers(false), mFlinger(flinger), Loading @@ -105,13 +250,11 @@ DisplayDevice::DisplayDevice( mHasHdr10(false), mHasHLG(false), mHasDolbyVision(false), mSupportedPerFrameMetadata(supportedPerFrameMetadata), mHasBT2100PQColorimetric(false), mHasBT2100PQEnhance(false), mHasBT2100HLGColorimetric(false), mHasBT2100HLGEnhance(false) mSupportedPerFrameMetadata(supportedPerFrameMetadata) { // clang-format on populateColorModes(hwcColorModes); std::vector<Hdr> types = hdrCapabilities.getSupportedHdrTypes(); for (Hdr hdrType : types) { switch (hdrType) { Loading Loading @@ -149,18 +292,6 @@ DisplayDevice::DisplayDevice( } mHdrCapabilities = HdrCapabilities(types, maxLuminance, maxAverageLuminance, minLuminance); auto iter = hdrAndRenderIntents.find(ColorMode::BT2100_PQ); if (iter != hdrAndRenderIntents.end()) { hasToneMapping(iter->second, &mHasBT2100PQColorimetric, &mHasBT2100PQEnhance); } iter = hdrAndRenderIntents.find(ColorMode::BT2100_HLG); if (iter != hdrAndRenderIntents.end()) { hasToneMapping(iter->second, &mHasBT2100HLGColorimetric, &mHasBT2100HLGEnhance); } // initialize the display orientation transform. setProjection(DisplayState::eOrientationDefault, mViewport, mFrame); } Loading Loading @@ -544,19 +675,87 @@ void DisplayDevice::dump(String8& result) const { result.append(surfaceDump); } void DisplayDevice::hasToneMapping(const std::vector<RenderIntent>& renderIntents, bool* outColorimetric, bool *outEnhance) { for (auto intent : renderIntents) { switch (intent) { case RenderIntent::TONE_MAP_COLORIMETRIC: *outColorimetric = true; break; case RenderIntent::TONE_MAP_ENHANCE: *outEnhance = true; break; default: break; // Map dataspace/intent to the best matched dataspace/colorMode/renderIntent // supported by HWC. void DisplayDevice::addColorMode( const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes, const ColorMode mode, const RenderIntent intent) { // find the best color mode const ColorMode hwcColorMode = getHwcColorMode(hwcColorModes, mode); // find the best render intent auto iter = hwcColorModes.find(hwcColorMode); const auto& hwcIntents = iter != hwcColorModes.end() ? iter->second : std::vector<RenderIntent>(); const RenderIntent hwcIntent = getHwcRenderIntent(hwcIntents, intent); const Dataspace dataspace = colorModeToDataspace(mode); const Dataspace hwcDataspace = colorModeToDataspace(hwcColorMode); ALOGV("DisplayDevice %d/%d: map (%s, %s) to (%s, %s, %s)", mType, mHwcDisplayId, dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(), decodeRenderIntent(intent).c_str(), dataspaceDetails(static_cast<android_dataspace_t>(hwcDataspace)).c_str(), decodeColorMode(hwcColorMode).c_str(), decodeRenderIntent(hwcIntent).c_str()); mColorModes[getColorModeKey(dataspace, intent)] = {hwcDataspace, hwcColorMode, hwcIntent}; } void DisplayDevice::populateColorModes( const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes) { if (!hasWideColorGamut()) { return; } // add known SDR combinations for (auto intent : sSdrRenderIntents) { for (auto mode : sSdrColorModes) { addColorMode(hwcColorModes, mode, intent); } } // add known HDR combinations for (auto intent : sHdrRenderIntents) { for (auto mode : sHdrColorModes) { addColorMode(hwcColorModes, mode, intent); } } } bool DisplayDevice::hasRenderIntent(RenderIntent intent) const { // assume a render intent is supported when SRGB supports it; we should // get rid of that assumption. auto iter = mColorModes.find(getColorModeKey(Dataspace::SRGB, intent)); return iter != mColorModes.end() && iter->second.renderIntent == intent; } bool DisplayDevice::hasModernHdrSupport(Dataspace dataspace) const { if ((dataspace == Dataspace::BT2020_PQ && hasHDR10Support()) || (dataspace == Dataspace::BT2020_HLG && hasHLGSupport())) { auto iter = mColorModes.find(getColorModeKey(dataspace, RenderIntent::TONE_MAP_COLORIMETRIC)); return iter != mColorModes.end() && iter->second.dataspace == dataspace; } return false; } void DisplayDevice::getBestColorMode(Dataspace dataspace, RenderIntent intent, Dataspace* outDataspace, ColorMode* outMode, RenderIntent* outIntent) const { auto iter = mColorModes.find(getColorModeKey(dataspace, intent)); if (iter != mColorModes.end()) { *outDataspace = iter->second.dataspace; *outMode = iter->second.colorMode; *outIntent = iter->second.renderIntent; } else { ALOGE("map unknown (%s)/(%s) to default color mode", dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(), decodeRenderIntent(intent).c_str()); *outDataspace = Dataspace::UNKNOWN; *outMode = ColorMode::NATIVE; *outIntent = RenderIntent::COLORIMETRIC; } } Loading
services/surfaceflinger/DisplayDevice.h +32 −16 Original line number Diff line number Diff line Loading @@ -92,7 +92,7 @@ public: bool hasWideColorGamut, const HdrCapabilities& hdrCapabilities, const int32_t supportedPerFrameMetadata, const std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>& hdrAndRenderIntents, const std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>& hwcColorModes, int initialPowerMode); // clang-format on Loading Loading @@ -145,11 +145,17 @@ public: // machine happy without actually queueing a buffer if nothing has changed status_t beginFrame(bool mustRecompose) const; status_t prepareFrame(HWComposer& hwc); bool hasWideColorGamut() const { return mHasWideColorGamut; } // Whether h/w composer has native support for specific HDR type. bool hasHDR10Support() const { return mHasHdr10; } bool hasHLGSupport() const { return mHasHLG; } bool hasDolbyVisionSupport() const { return mHasDolbyVision; } // Return true if the corresponding color mode for the HDR dataspace is // supported. bool hasModernHdrSupport(ui::Dataspace dataspace) const; // The returned HdrCapabilities is the combination of HDR capabilities from // hardware composer and RenderEngine. When the DisplayDevice supports wide // color gamut, RenderEngine is able to simulate HDR support in Display P3 Loading @@ -158,13 +164,12 @@ public: // respectively if hardware composer doesn't return meaningful values. const HdrCapabilities& getHdrCapabilities() const { return mHdrCapabilities; } // Whether h/w composer has BT2100_PQ color mode. bool hasBT2100PQColorimetricSupport() const { return mHasBT2100PQColorimetric; } bool hasBT2100PQEnhanceSupport() const { return mHasBT2100PQEnhance; } // Return true if intent is supported by the display. bool hasRenderIntent(ui::RenderIntent intent) const; // Whether h/w composer has BT2100_HLG color mode. bool hasBT2100HLGColorimetricSupport() const { return mHasBT2100HLGColorimetric; } bool hasBT2100HLGEnhanceSupport() const { return mHasBT2100HLGEnhance; } void getBestColorMode(ui::Dataspace dataspace, ui::RenderIntent intent, ui::Dataspace* outDataspace, ui::ColorMode* outMode, ui::RenderIntent* outIntent) const; void swapBuffers(HWComposer& hwc) const; Loading Loading @@ -216,9 +221,6 @@ public: void dump(String8& result) const; private: void hasToneMapping(const std::vector<ui::RenderIntent>& renderIntents, bool* outColorimetric, bool *outEnhance); /* * Constants, set during initialization */ Loading Loading @@ -290,12 +292,26 @@ private: bool mHasDolbyVision; HdrCapabilities mHdrCapabilities; const int32_t mSupportedPerFrameMetadata; // Whether h/w composer has BT2100_PQ and BT2100_HLG color mode with // colorimetrical tone mapping or enhanced tone mapping. bool mHasBT2100PQColorimetric; bool mHasBT2100PQEnhance; bool mHasBT2100HLGColorimetric; bool mHasBT2100HLGEnhance; // Mappings from desired Dataspace/RenderIntent to the supported // Dataspace/ColorMode/RenderIntent. using ColorModeKey = uint64_t; struct ColorModeValue { ui::Dataspace dataspace; ui::ColorMode colorMode; ui::RenderIntent renderIntent; }; static ColorModeKey getColorModeKey(ui::Dataspace dataspace, ui::RenderIntent intent) { return (static_cast<uint64_t>(dataspace) << 32) | static_cast<uint32_t>(intent); } void populateColorModes( const std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>& hwcColorModes); void addColorMode( const std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>& hwcColorModes, const ui::ColorMode mode, const ui::RenderIntent intent); std::unordered_map<ColorModeKey, ColorModeValue> mColorModes; }; struct DisplayDeviceState { Loading
services/surfaceflinger/SurfaceFlinger.cpp +17 −115 Original line number Diff line number Diff line Loading @@ -1870,7 +1870,6 @@ void SurfaceFlinger::rebuildLayerStacks() { // can only be one of // - Dataspace::SRGB (use legacy dataspace and let HWC saturate when colors are enhanced) // - Dataspace::DISPLAY_P3 // - Dataspace::V0_SCRGB_LINEAR // The returned HDR data space is one of // - Dataspace::UNKNOWN // - Dataspace::BT2020_HLG Loading @@ -1884,12 +1883,8 @@ Dataspace SurfaceFlinger::getBestDataspace( switch (layer->getDataSpace()) { case Dataspace::V0_SCRGB: case Dataspace::V0_SCRGB_LINEAR: bestDataSpace = Dataspace::V0_SCRGB_LINEAR; break; case Dataspace::DISPLAY_P3: if (bestDataSpace == Dataspace::SRGB) { bestDataSpace = Dataspace::DISPLAY_P3; } break; case Dataspace::BT2020_PQ: case Dataspace::BT2020_ITU_PQ: Loading Loading @@ -1925,103 +1920,17 @@ void SurfaceFlinger::pickColorMode(const sp<DisplayDevice>& displayDevice, Dataspace hdrDataSpace; Dataspace bestDataSpace = getBestDataspace(displayDevice, &hdrDataSpace); if (hdrDataSpace == Dataspace::BT2020_PQ) { // Hardware composer can handle BT2100 ColorMode only when // - colorimetrical tone mapping is supported, or // - Auto mode is turned on and enhanced tone mapping is supported. if (displayDevice->hasBT2100PQColorimetricSupport() || (mDisplayColorSetting == DisplayColorSetting::ENHANCED && displayDevice->hasBT2100PQEnhanceSupport())) { *outMode = ColorMode::BT2100_PQ; *outDataSpace = Dataspace::BT2020_PQ; } else if (displayDevice->hasHDR10Support()) { // Legacy HDR support. HDR layers are treated as UNKNOWN layers. hdrDataSpace = Dataspace::UNKNOWN; } else { // Simulate PQ through RenderEngine, pick DISPLAY_P3 color mode. *outMode = ColorMode::DISPLAY_P3; *outDataSpace = Dataspace::DISPLAY_P3; } } else if (hdrDataSpace == Dataspace::BT2020_HLG) { if (displayDevice->hasBT2100HLGColorimetricSupport() || (mDisplayColorSetting == DisplayColorSetting::ENHANCED && displayDevice->hasBT2100HLGEnhanceSupport())) { *outMode = ColorMode::BT2100_HLG; *outDataSpace = Dataspace::BT2020_HLG; } else if (displayDevice->hasHLGSupport()) { // Legacy HDR support. HDR layers are treated as UNKNOWN layers. hdrDataSpace = Dataspace::UNKNOWN; } else { // Simulate HLG through RenderEngine, pick DISPLAY_P3 color mode. *outMode = ColorMode::DISPLAY_P3; *outDataSpace = Dataspace::DISPLAY_P3; } } RenderIntent intent = mDisplayColorSetting == DisplayColorSetting::ENHANCED ? RenderIntent::ENHANCE : RenderIntent::COLORIMETRIC; // At this point, there's no HDR layer. if (hdrDataSpace == Dataspace::UNKNOWN) { switch (bestDataSpace) { case Dataspace::DISPLAY_P3: case Dataspace::V0_SCRGB_LINEAR: *outMode = ColorMode::DISPLAY_P3; *outDataSpace = Dataspace::DISPLAY_P3; break; default: *outMode = ColorMode::SRGB; *outDataSpace = Dataspace::SRGB; break; } } *outRenderIntent = pickRenderIntent(displayDevice, *outMode); } RenderIntent SurfaceFlinger::pickRenderIntent(const sp<DisplayDevice>& displayDevice, ColorMode colorMode) const { // Native Mode means the display is not color managed, and whichever // render intent is picked doesn't matter, thus return // RenderIntent::COLORIMETRIC as default here. if (mDisplayColorSetting == DisplayColorSetting::UNMANAGED) { return RenderIntent::COLORIMETRIC; } // In Auto Color Mode, we want to strech to panel color space, right now // only the built-in display supports it. if (mDisplayColorSetting == DisplayColorSetting::ENHANCED && mBuiltinDisplaySupportsEnhance && displayDevice->isPrimary()) { switch (colorMode) { case ColorMode::DISPLAY_P3: case ColorMode::SRGB: return RenderIntent::ENHANCE; // In Auto Color Mode, BT2100_PQ and BT2100_HLG will only be picked // when TONE_MAP_ENHANCE or TONE_MAP_COLORIMETRIC is supported. // If TONE_MAP_ENHANCE is not supported, fall back to TONE_MAP_COLORIMETRIC. case ColorMode::BT2100_PQ: return displayDevice->hasBT2100PQEnhanceSupport() ? RenderIntent::TONE_MAP_ENHANCE : RenderIntent::TONE_MAP_COLORIMETRIC; case ColorMode::BT2100_HLG: return displayDevice->hasBT2100HLGEnhanceSupport() ? // respect hdrDataSpace only when there is modern HDR support if (hdrDataSpace != Dataspace::UNKNOWN && displayDevice->hasModernHdrSupport(hdrDataSpace)) { bestDataSpace = hdrDataSpace; intent = mDisplayColorSetting == DisplayColorSetting::ENHANCED ? RenderIntent::TONE_MAP_ENHANCE : RenderIntent::TONE_MAP_COLORIMETRIC; // This statement shouldn't be reached, switch cases will always // cover all possible ColorMode returned by pickColorMode. default: return RenderIntent::COLORIMETRIC; } } // Either enhance is not supported or we are in natural mode. // Natural Mode means it's color managed and the color must be right, // thus we pick RenderIntent::COLORIMETRIC as render intent for non-HDR // content and pick RenderIntent::TONE_MAP_COLORIMETRIC for HDR content. switch (colorMode) { // In Natural Color Mode, BT2100_PQ and BT2100_HLG will only be picked // when TONE_MAP_COLORIMETRIC is supported. case ColorMode::BT2100_PQ: case ColorMode::BT2100_HLG: return RenderIntent::TONE_MAP_COLORIMETRIC; default: return RenderIntent::COLORIMETRIC; } displayDevice->getBestColorMode(bestDataSpace, intent, outDataSpace, outMode, outRenderIntent); } void SurfaceFlinger::setUpHWComposer() { Loading Loading @@ -2338,7 +2247,7 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( const wp<IBinder>& display, int hwcId, const DisplayDeviceState& state, const sp<DisplaySurface>& dispSurface, const sp<IGraphicBufferProducer>& producer) { bool hasWideColorGamut = false; std::unordered_map<ColorMode, std::vector<RenderIntent>> hdrAndRenderIntents; std::unordered_map<ColorMode, std::vector<RenderIntent>> hwcColorModes; if (hasWideColorDisplay) { std::vector<ColorMode> modes = getHwComposer().getColorModes(hwcId); Loading @@ -2355,18 +2264,7 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( std::vector<RenderIntent> renderIntents = getHwComposer().getRenderIntents(hwcId, colorMode); if (state.type == DisplayDevice::DISPLAY_PRIMARY) { for (auto intent : renderIntents) { if (intent == RenderIntent::ENHANCE) { mBuiltinDisplaySupportsEnhance = true; break; } } } if (colorMode == ColorMode::BT2100_PQ || colorMode == ColorMode::BT2100_HLG) { hdrAndRenderIntents.emplace(colorMode, renderIntents); } hwcColorModes.emplace(colorMode, renderIntents); } } Loading Loading @@ -2405,17 +2303,21 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( dispSurface, std::move(renderSurface), displayWidth, displayHeight, hasWideColorGamut, hdrCapabilities, getHwComposer().getSupportedPerFrameMetadata(hwcId), hdrAndRenderIntents, initialPowerMode); hwcColorModes, initialPowerMode); if (maxFrameBufferAcquiredBuffers >= 3) { nativeWindowSurface->preallocateBuffers(); } if (hw->isPrimary() && hw->hasRenderIntent(RenderIntent::ENHANCE)) { mBuiltinDisplaySupportsEnhance = true; } ColorMode defaultColorMode = ColorMode::NATIVE; Dataspace defaultDataSpace = Dataspace::UNKNOWN; if (hasWideColorGamut) { defaultColorMode = ColorMode::SRGB; defaultDataSpace = Dataspace::V0_SRGB; defaultDataSpace = Dataspace::SRGB; } setActiveColorModeInternal(hw, defaultColorMode, defaultDataSpace, RenderIntent::COLORIMETRIC); Loading
services/surfaceflinger/SurfaceFlinger.h +0 −2 Original line number Diff line number Diff line Loading @@ -666,8 +666,6 @@ private: ui::ColorMode* outMode, ui::Dataspace* outDataSpace, ui::RenderIntent* outRenderIntent) const; ui::RenderIntent pickRenderIntent(const sp<DisplayDevice>& displayDevice, ui::ColorMode colorMode) const; void setUpHWComposer(); void doComposition(); Loading