Loading services/surfaceflinger/DisplayDevice.cpp +34 −1 Original line number Diff line number Diff line Loading @@ -80,6 +80,7 @@ DisplayDevice::DisplayDevice( bool hasWideColorGamut, const HdrCapabilities& hdrCapabilities, const int32_t supportedPerFrameMetadata, const std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>& hdrAndRenderIntents, int initialPowerMode) : lastCompositionHadVisibleLayers(false), mFlinger(flinger), Loading @@ -105,7 +106,11 @@ DisplayDevice::DisplayDevice( mHasHdr10(false), mHasHLG(false), mHasDolbyVision(false), mSupportedPerFrameMetadata(supportedPerFrameMetadata) mSupportedPerFrameMetadata(supportedPerFrameMetadata), mHasBT2100PQColorimetric(false), mHasBT2100PQEnhance(false), mHasBT2100HLGColorimetric(false), mHasBT2100HLGEnhance(false) { // clang-format on std::vector<Hdr> types = hdrCapabilities.getSupportedHdrTypes(); Loading Loading @@ -145,6 +150,18 @@ 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 @@ -528,6 +545,22 @@ 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; } } } std::atomic<int32_t> DisplayDeviceState::sNextSequenceId(1); } // namespace android services/surfaceflinger/DisplayDevice.h +20 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include "Transform.h" #include <stdlib.h> #include <unordered_map> #include <math/mat4.h> Loading Loading @@ -91,6 +92,7 @@ public: bool hasWideColorGamut, const HdrCapabilities& hdrCapabilities, const int32_t supportedPerFrameMetadata, const std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>& hdrAndRenderIntents, int initialPowerMode); // clang-format on Loading Loading @@ -144,6 +146,7 @@ public: 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; } Loading @@ -155,6 +158,14 @@ 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; } // Whether h/w composer has BT2100_HLG color mode. bool hasBT2100HLGColorimetricSupport() const { return mHasBT2100HLGColorimetric; } bool hasBT2100HLGEnhanceSupport() const { return mHasBT2100HLGEnhance; } void swapBuffers(HWComposer& hwc) const; // called after h/w composer has completed its set() call Loading Loading @@ -205,6 +216,9 @@ 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 @@ -276,6 +290,12 @@ 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; }; struct DisplayDeviceState { Loading services/surfaceflinger/SurfaceFlinger.cpp +138 −48 Original line number Diff line number Diff line Loading @@ -1021,25 +1021,12 @@ ColorMode SurfaceFlinger::getActiveColorMode(const sp<IBinder>& display) { } void SurfaceFlinger::setActiveColorModeInternal(const sp<DisplayDevice>& hw, ColorMode mode, Dataspace dataSpace) { ColorMode mode, Dataspace dataSpace, RenderIntent renderIntent) { ColorMode currentMode = hw->getActiveColorMode(); Dataspace currentDataSpace = hw->getCompositionDataSpace(); RenderIntent currentRenderIntent = hw->getActiveRenderIntent(); // Natural Mode means it's color managed and the color must be right, // thus we pick RenderIntent::COLORIMETRIC as render intent. // 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. RenderIntent renderIntent = 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 && hw->isPrimary()) { renderIntent = RenderIntent::ENHANCE; } if (mode == currentMode && dataSpace == currentDataSpace && renderIntent == currentRenderIntent) { return; Loading Loading @@ -1089,7 +1076,8 @@ status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& display, ALOGW("Attempt to set active color mode %s %d for virtual display", decodeColorMode(mMode).c_str(), mMode); } else { mFlinger.setActiveColorModeInternal(hw, mMode, Dataspace::UNKNOWN); mFlinger.setActiveColorModeInternal(hw, mMode, Dataspace::UNKNOWN, RenderIntent::COLORIMETRIC); } return true; } Loading Loading @@ -1872,36 +1860,39 @@ void SurfaceFlinger::rebuildLayerStacks() { // Returns a data space that fits all visible layers. The returned data space // can only be one of // // - Dataspace::V0_SRGB // - Dataspace::DISPLAY_P3 // - Dataspace::V0_SCRGB_LINEAR // TODO(b/73825729) Add BT2020 data space. ui::Dataspace SurfaceFlinger::getBestDataspace( const sp<const DisplayDevice>& displayDevice) const { Dataspace bestDataspace = Dataspace::V0_SRGB; // The returned HDR data space is one of // - Dataspace::UNKNOWN // - Dataspace::BT2020_HLG // - Dataspace::BT2020_PQ Dataspace SurfaceFlinger::getBestDataspace( const sp<const DisplayDevice>& displayDevice, Dataspace* outHdrDataSpace) const { Dataspace bestDataSpace = Dataspace::V0_SRGB; *outHdrDataSpace = Dataspace::UNKNOWN; for (const auto& layer : displayDevice->getVisibleLayersSortedByZ()) { switch (layer->getDataSpace()) { case Dataspace::V0_SCRGB: case Dataspace::V0_SCRGB_LINEAR: // return immediately return Dataspace::V0_SCRGB_LINEAR; bestDataSpace = Dataspace::V0_SCRGB_LINEAR; break; case Dataspace::DISPLAY_P3: bestDataspace = Dataspace::DISPLAY_P3; if (bestDataSpace == Dataspace::V0_SRGB) { bestDataSpace = Dataspace::DISPLAY_P3; } break; // Historically, HDR dataspaces are ignored by SurfaceFlinger. But // since SurfaceFlinger simulates HDR support now, it should honor // them unless there is also native support. case Dataspace::BT2020_PQ: case Dataspace::BT2020_ITU_PQ: if (!displayDevice->hasHDR10Support()) { return Dataspace::V0_SCRGB_LINEAR; } *outHdrDataSpace = Dataspace::BT2020_PQ; break; case Dataspace::BT2020_HLG: case Dataspace::BT2020_ITU_HLG: if (!displayDevice->hasHLGSupport()) { return Dataspace::V0_SCRGB_LINEAR; // When there's mixed PQ content and HLG content, we set the HDR // data space to be BT2020_PQ and convert HLG to PQ. if (*outHdrDataSpace == Dataspace::UNKNOWN) { *outHdrDataSpace = Dataspace::BT2020_HLG; } break; default: Loading @@ -1909,20 +1900,59 @@ ui::Dataspace SurfaceFlinger::getBestDataspace( } } return bestDataspace; return bestDataSpace; } // Pick the ColorMode / Dataspace for the display device. // TODO(b/73825729) Add BT2020 color mode. void SurfaceFlinger::pickColorMode(const sp<DisplayDevice>& displayDevice, ColorMode* outMode, Dataspace* outDataSpace) const { ColorMode* outMode, Dataspace* outDataSpace, RenderIntent* outRenderIntent) const { if (mDisplayColorSetting == DisplayColorSetting::UNMANAGED) { *outMode = ColorMode::NATIVE; *outDataSpace = Dataspace::UNKNOWN; *outRenderIntent = RenderIntent::COLORIMETRIC; return; } switch (getBestDataspace(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; } } // 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; Loading @@ -1934,6 +1964,57 @@ void SurfaceFlinger::pickColorMode(const sp<DisplayDevice>& displayDevice, 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() ? 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; } } void SurfaceFlinger::setUpHWComposer() { ATRACE_CALL(); Loading Loading @@ -2033,8 +2114,9 @@ void SurfaceFlinger::setUpHWComposer() { if (hasWideColorDisplay) { ColorMode colorMode; Dataspace dataSpace; pickColorMode(displayDevice, &colorMode, &dataSpace); setActiveColorModeInternal(displayDevice, colorMode, dataSpace); RenderIntent renderIntent; pickColorMode(displayDevice, &colorMode, &dataSpace, &renderIntent); setActiveColorModeInternal(displayDevice, colorMode, dataSpace, renderIntent); } } Loading Loading @@ -2248,6 +2330,8 @@ 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; if (hasWideColorDisplay) { std::vector<ColorMode> modes = getHwComposer().getColorModes(hwcId); for (ColorMode colorMode : modes) { Loading @@ -2257,7 +2341,6 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( case ColorMode::DCI_P3: hasWideColorGamut = true; break; // TODO(lpy) Handle BT2020, BT2100_PQ and BT2100_HLG properly. default: break; } Loading @@ -2272,6 +2355,10 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( } } } if (colorMode == ColorMode::BT2100_PQ || colorMode == ColorMode::BT2100_HLG) { hdrAndRenderIntents.emplace(colorMode, renderIntents); } } } Loading Loading @@ -2310,7 +2397,7 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( dispSurface, std::move(renderSurface), displayWidth, displayHeight, hasWideColorGamut, hdrCapabilities, getHwComposer().getSupportedPerFrameMetadata(hwcId), initialPowerMode); hdrAndRenderIntents, initialPowerMode); if (maxFrameBufferAcquiredBuffers >= 3) { nativeWindowSurface->preallocateBuffers(); Loading @@ -2322,7 +2409,8 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( defaultColorMode = ColorMode::SRGB; defaultDataSpace = Dataspace::V0_SRGB; } setActiveColorModeInternal(hw, defaultColorMode, defaultDataSpace); setActiveColorModeInternal(hw, defaultColorMode, defaultDataSpace, RenderIntent::COLORIMETRIC); hw->setLayerStack(state.layerStack); hw->setProjection(state.orientation, state.viewport, state.frame); hw->setDisplayName(state.displayName); Loading Loading @@ -2994,6 +3082,8 @@ bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& displayDev mat4 savedMatrix; if (mDisplayColorSetting == DisplayColorSetting::ENHANCED && layer->isLegacySrgbDataSpace()) { // TODO(b/78891890) Legacy sRGB saturation matrix should be set // separately. savedMatrix = getRenderEngine().setupColorTransform(legacySrgbSaturationMatrix); restore = true; Loading services/surfaceflinger/SurfaceFlinger.h +12 −5 Original line number Diff line number Diff line Loading @@ -483,7 +483,8 @@ private: // Called on the main thread in response to setActiveColorMode() void setActiveColorModeInternal(const sp<DisplayDevice>& hw, ui::ColorMode colorMode, ui::Dataspace dataSpace); ui::Dataspace dataSpace, ui::RenderIntent renderIntent); // Returns whether the transaction actually modified any state bool handleMessageTransaction(); Loading Loading @@ -655,12 +656,18 @@ private: nsecs_t compositeToPresentLatency); void rebuildLayerStacks(); // Given a dataSpace, returns the appropriate color_mode to use // to display that dataSpace. ui::Dataspace getBestDataspace(const sp<const DisplayDevice>& displayDevice) const; ui::Dataspace getBestDataspace(const sp<const DisplayDevice>& displayDevice, ui::Dataspace* outHdrDataSpace) const; // Returns the appropriate ColorMode, Dataspace and RenderIntent for the // DisplayDevice. The function only returns the supported ColorMode, // Dataspace and RenderIntent. void pickColorMode(const sp<DisplayDevice>& displayDevice, ui::ColorMode* outMode, ui::Dataspace* outDataSpace) const; ui::Dataspace* outDataSpace, ui::RenderIntent* outRenderIntent) const; ui::RenderIntent pickRenderIntent(const sp<DisplayDevice>& displayDevice, ui::ColorMode colorMode) const; void setUpHWComposer(); void doComposition(); Loading services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +1 −35 Original line number Diff line number Diff line Loading @@ -47,10 +47,10 @@ using testing::SetArgPointee; using android::hardware::graphics::common::V1_0::Hdr; using android::hardware::graphics::common::V1_1::ColorMode; using android::hardware::graphics::common::V1_1::RenderIntent; using android::Hwc2::Error; using android::Hwc2::IComposer; using android::Hwc2::IComposerClient; using android::Hwc2::RenderIntent; using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector; using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector; Loading Loading @@ -496,33 +496,6 @@ struct WideColorP3ColorimetricSupportedVariant { } }; // For this variant, SurfaceFlinger should configure itself with wide color // display support, and the display should respond with an non-empty list of // supported color modes. template <typename Display> struct WideColorP3EnhanceSupportedVariant { static constexpr bool WIDE_COLOR_SUPPORTED = true; static void injectConfigChange(DisplayTransactionTest* test) { test->mFlinger.mutableHasWideColorDisplay() = true; test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::ENHANCED; } static void setupComposerCallExpectations(DisplayTransactionTest* test) { EXPECT_CALL(*test->mComposer, getColorModes(Display::HWC_DISPLAY_ID, _)) .WillOnce(DoAll(SetArgPointee<1>(std::vector<ColorMode>({ColorMode::DISPLAY_P3})), Return(Error::NONE))); EXPECT_CALL(*test->mComposer, getRenderIntents(Display::HWC_DISPLAY_ID, ColorMode::DISPLAY_P3, _)) .WillOnce( DoAll(SetArgPointee<2>(std::vector<RenderIntent>({RenderIntent::ENHANCE})), Return(Error::NONE))); EXPECT_CALL(*test->mComposer, setColorMode(Display::HWC_DISPLAY_ID, ColorMode::SRGB, RenderIntent::ENHANCE)) .WillOnce(Return(Error::NONE)); } }; // For this variant, SurfaceFlinger should configure itself with wide display // support, but the display should respond with an empty list of supported color // modes. Wide-color support for the display should not be configured. Loading Loading @@ -640,9 +613,6 @@ using HwcVirtualDisplayCase = using WideColorP3ColorimetricDisplayCase = Case<PrimaryDisplayVariant, WideColorP3ColorimetricSupportedVariant<PrimaryDisplayVariant>, HdrNotSupportedVariant<PrimaryDisplayVariant>>; using WideColorP3EnhanceDisplayCase = Case<PrimaryDisplayVariant, WideColorP3EnhanceSupportedVariant<PrimaryDisplayVariant>, HdrNotSupportedVariant<PrimaryDisplayVariant>>; using Hdr10DisplayCase = Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>, Hdr10SupportedVariant<PrimaryDisplayVariant>>; Loading Loading @@ -1048,10 +1018,6 @@ TEST_F(SetupNewDisplayDeviceInternalTest, createWideColorP3Display) { setupNewDisplayDeviceInternalTest<WideColorP3ColorimetricDisplayCase>(); } TEST_F(SetupNewDisplayDeviceInternalTest, createWideColorP3EnhanceDisplay) { setupNewDisplayDeviceInternalTest<WideColorP3EnhanceDisplayCase>(); } TEST_F(SetupNewDisplayDeviceInternalTest, createHdr10Display) { setupNewDisplayDeviceInternalTest<Hdr10DisplayCase>(); } Loading Loading
services/surfaceflinger/DisplayDevice.cpp +34 −1 Original line number Diff line number Diff line Loading @@ -80,6 +80,7 @@ DisplayDevice::DisplayDevice( bool hasWideColorGamut, const HdrCapabilities& hdrCapabilities, const int32_t supportedPerFrameMetadata, const std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>& hdrAndRenderIntents, int initialPowerMode) : lastCompositionHadVisibleLayers(false), mFlinger(flinger), Loading @@ -105,7 +106,11 @@ DisplayDevice::DisplayDevice( mHasHdr10(false), mHasHLG(false), mHasDolbyVision(false), mSupportedPerFrameMetadata(supportedPerFrameMetadata) mSupportedPerFrameMetadata(supportedPerFrameMetadata), mHasBT2100PQColorimetric(false), mHasBT2100PQEnhance(false), mHasBT2100HLGColorimetric(false), mHasBT2100HLGEnhance(false) { // clang-format on std::vector<Hdr> types = hdrCapabilities.getSupportedHdrTypes(); Loading Loading @@ -145,6 +150,18 @@ 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 @@ -528,6 +545,22 @@ 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; } } } std::atomic<int32_t> DisplayDeviceState::sNextSequenceId(1); } // namespace android
services/surfaceflinger/DisplayDevice.h +20 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include "Transform.h" #include <stdlib.h> #include <unordered_map> #include <math/mat4.h> Loading Loading @@ -91,6 +92,7 @@ public: bool hasWideColorGamut, const HdrCapabilities& hdrCapabilities, const int32_t supportedPerFrameMetadata, const std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>& hdrAndRenderIntents, int initialPowerMode); // clang-format on Loading Loading @@ -144,6 +146,7 @@ public: 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; } Loading @@ -155,6 +158,14 @@ 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; } // Whether h/w composer has BT2100_HLG color mode. bool hasBT2100HLGColorimetricSupport() const { return mHasBT2100HLGColorimetric; } bool hasBT2100HLGEnhanceSupport() const { return mHasBT2100HLGEnhance; } void swapBuffers(HWComposer& hwc) const; // called after h/w composer has completed its set() call Loading Loading @@ -205,6 +216,9 @@ 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 @@ -276,6 +290,12 @@ 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; }; struct DisplayDeviceState { Loading
services/surfaceflinger/SurfaceFlinger.cpp +138 −48 Original line number Diff line number Diff line Loading @@ -1021,25 +1021,12 @@ ColorMode SurfaceFlinger::getActiveColorMode(const sp<IBinder>& display) { } void SurfaceFlinger::setActiveColorModeInternal(const sp<DisplayDevice>& hw, ColorMode mode, Dataspace dataSpace) { ColorMode mode, Dataspace dataSpace, RenderIntent renderIntent) { ColorMode currentMode = hw->getActiveColorMode(); Dataspace currentDataSpace = hw->getCompositionDataSpace(); RenderIntent currentRenderIntent = hw->getActiveRenderIntent(); // Natural Mode means it's color managed and the color must be right, // thus we pick RenderIntent::COLORIMETRIC as render intent. // 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. RenderIntent renderIntent = 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 && hw->isPrimary()) { renderIntent = RenderIntent::ENHANCE; } if (mode == currentMode && dataSpace == currentDataSpace && renderIntent == currentRenderIntent) { return; Loading Loading @@ -1089,7 +1076,8 @@ status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& display, ALOGW("Attempt to set active color mode %s %d for virtual display", decodeColorMode(mMode).c_str(), mMode); } else { mFlinger.setActiveColorModeInternal(hw, mMode, Dataspace::UNKNOWN); mFlinger.setActiveColorModeInternal(hw, mMode, Dataspace::UNKNOWN, RenderIntent::COLORIMETRIC); } return true; } Loading Loading @@ -1872,36 +1860,39 @@ void SurfaceFlinger::rebuildLayerStacks() { // Returns a data space that fits all visible layers. The returned data space // can only be one of // // - Dataspace::V0_SRGB // - Dataspace::DISPLAY_P3 // - Dataspace::V0_SCRGB_LINEAR // TODO(b/73825729) Add BT2020 data space. ui::Dataspace SurfaceFlinger::getBestDataspace( const sp<const DisplayDevice>& displayDevice) const { Dataspace bestDataspace = Dataspace::V0_SRGB; // The returned HDR data space is one of // - Dataspace::UNKNOWN // - Dataspace::BT2020_HLG // - Dataspace::BT2020_PQ Dataspace SurfaceFlinger::getBestDataspace( const sp<const DisplayDevice>& displayDevice, Dataspace* outHdrDataSpace) const { Dataspace bestDataSpace = Dataspace::V0_SRGB; *outHdrDataSpace = Dataspace::UNKNOWN; for (const auto& layer : displayDevice->getVisibleLayersSortedByZ()) { switch (layer->getDataSpace()) { case Dataspace::V0_SCRGB: case Dataspace::V0_SCRGB_LINEAR: // return immediately return Dataspace::V0_SCRGB_LINEAR; bestDataSpace = Dataspace::V0_SCRGB_LINEAR; break; case Dataspace::DISPLAY_P3: bestDataspace = Dataspace::DISPLAY_P3; if (bestDataSpace == Dataspace::V0_SRGB) { bestDataSpace = Dataspace::DISPLAY_P3; } break; // Historically, HDR dataspaces are ignored by SurfaceFlinger. But // since SurfaceFlinger simulates HDR support now, it should honor // them unless there is also native support. case Dataspace::BT2020_PQ: case Dataspace::BT2020_ITU_PQ: if (!displayDevice->hasHDR10Support()) { return Dataspace::V0_SCRGB_LINEAR; } *outHdrDataSpace = Dataspace::BT2020_PQ; break; case Dataspace::BT2020_HLG: case Dataspace::BT2020_ITU_HLG: if (!displayDevice->hasHLGSupport()) { return Dataspace::V0_SCRGB_LINEAR; // When there's mixed PQ content and HLG content, we set the HDR // data space to be BT2020_PQ and convert HLG to PQ. if (*outHdrDataSpace == Dataspace::UNKNOWN) { *outHdrDataSpace = Dataspace::BT2020_HLG; } break; default: Loading @@ -1909,20 +1900,59 @@ ui::Dataspace SurfaceFlinger::getBestDataspace( } } return bestDataspace; return bestDataSpace; } // Pick the ColorMode / Dataspace for the display device. // TODO(b/73825729) Add BT2020 color mode. void SurfaceFlinger::pickColorMode(const sp<DisplayDevice>& displayDevice, ColorMode* outMode, Dataspace* outDataSpace) const { ColorMode* outMode, Dataspace* outDataSpace, RenderIntent* outRenderIntent) const { if (mDisplayColorSetting == DisplayColorSetting::UNMANAGED) { *outMode = ColorMode::NATIVE; *outDataSpace = Dataspace::UNKNOWN; *outRenderIntent = RenderIntent::COLORIMETRIC; return; } switch (getBestDataspace(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; } } // 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; Loading @@ -1934,6 +1964,57 @@ void SurfaceFlinger::pickColorMode(const sp<DisplayDevice>& displayDevice, 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() ? 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; } } void SurfaceFlinger::setUpHWComposer() { ATRACE_CALL(); Loading Loading @@ -2033,8 +2114,9 @@ void SurfaceFlinger::setUpHWComposer() { if (hasWideColorDisplay) { ColorMode colorMode; Dataspace dataSpace; pickColorMode(displayDevice, &colorMode, &dataSpace); setActiveColorModeInternal(displayDevice, colorMode, dataSpace); RenderIntent renderIntent; pickColorMode(displayDevice, &colorMode, &dataSpace, &renderIntent); setActiveColorModeInternal(displayDevice, colorMode, dataSpace, renderIntent); } } Loading Loading @@ -2248,6 +2330,8 @@ 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; if (hasWideColorDisplay) { std::vector<ColorMode> modes = getHwComposer().getColorModes(hwcId); for (ColorMode colorMode : modes) { Loading @@ -2257,7 +2341,6 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( case ColorMode::DCI_P3: hasWideColorGamut = true; break; // TODO(lpy) Handle BT2020, BT2100_PQ and BT2100_HLG properly. default: break; } Loading @@ -2272,6 +2355,10 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( } } } if (colorMode == ColorMode::BT2100_PQ || colorMode == ColorMode::BT2100_HLG) { hdrAndRenderIntents.emplace(colorMode, renderIntents); } } } Loading Loading @@ -2310,7 +2397,7 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( dispSurface, std::move(renderSurface), displayWidth, displayHeight, hasWideColorGamut, hdrCapabilities, getHwComposer().getSupportedPerFrameMetadata(hwcId), initialPowerMode); hdrAndRenderIntents, initialPowerMode); if (maxFrameBufferAcquiredBuffers >= 3) { nativeWindowSurface->preallocateBuffers(); Loading @@ -2322,7 +2409,8 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( defaultColorMode = ColorMode::SRGB; defaultDataSpace = Dataspace::V0_SRGB; } setActiveColorModeInternal(hw, defaultColorMode, defaultDataSpace); setActiveColorModeInternal(hw, defaultColorMode, defaultDataSpace, RenderIntent::COLORIMETRIC); hw->setLayerStack(state.layerStack); hw->setProjection(state.orientation, state.viewport, state.frame); hw->setDisplayName(state.displayName); Loading Loading @@ -2994,6 +3082,8 @@ bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& displayDev mat4 savedMatrix; if (mDisplayColorSetting == DisplayColorSetting::ENHANCED && layer->isLegacySrgbDataSpace()) { // TODO(b/78891890) Legacy sRGB saturation matrix should be set // separately. savedMatrix = getRenderEngine().setupColorTransform(legacySrgbSaturationMatrix); restore = true; Loading
services/surfaceflinger/SurfaceFlinger.h +12 −5 Original line number Diff line number Diff line Loading @@ -483,7 +483,8 @@ private: // Called on the main thread in response to setActiveColorMode() void setActiveColorModeInternal(const sp<DisplayDevice>& hw, ui::ColorMode colorMode, ui::Dataspace dataSpace); ui::Dataspace dataSpace, ui::RenderIntent renderIntent); // Returns whether the transaction actually modified any state bool handleMessageTransaction(); Loading Loading @@ -655,12 +656,18 @@ private: nsecs_t compositeToPresentLatency); void rebuildLayerStacks(); // Given a dataSpace, returns the appropriate color_mode to use // to display that dataSpace. ui::Dataspace getBestDataspace(const sp<const DisplayDevice>& displayDevice) const; ui::Dataspace getBestDataspace(const sp<const DisplayDevice>& displayDevice, ui::Dataspace* outHdrDataSpace) const; // Returns the appropriate ColorMode, Dataspace and RenderIntent for the // DisplayDevice. The function only returns the supported ColorMode, // Dataspace and RenderIntent. void pickColorMode(const sp<DisplayDevice>& displayDevice, ui::ColorMode* outMode, ui::Dataspace* outDataSpace) const; ui::Dataspace* outDataSpace, ui::RenderIntent* outRenderIntent) const; ui::RenderIntent pickRenderIntent(const sp<DisplayDevice>& displayDevice, ui::ColorMode colorMode) const; void setUpHWComposer(); void doComposition(); Loading
services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +1 −35 Original line number Diff line number Diff line Loading @@ -47,10 +47,10 @@ using testing::SetArgPointee; using android::hardware::graphics::common::V1_0::Hdr; using android::hardware::graphics::common::V1_1::ColorMode; using android::hardware::graphics::common::V1_1::RenderIntent; using android::Hwc2::Error; using android::Hwc2::IComposer; using android::Hwc2::IComposerClient; using android::Hwc2::RenderIntent; using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector; using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector; Loading Loading @@ -496,33 +496,6 @@ struct WideColorP3ColorimetricSupportedVariant { } }; // For this variant, SurfaceFlinger should configure itself with wide color // display support, and the display should respond with an non-empty list of // supported color modes. template <typename Display> struct WideColorP3EnhanceSupportedVariant { static constexpr bool WIDE_COLOR_SUPPORTED = true; static void injectConfigChange(DisplayTransactionTest* test) { test->mFlinger.mutableHasWideColorDisplay() = true; test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::ENHANCED; } static void setupComposerCallExpectations(DisplayTransactionTest* test) { EXPECT_CALL(*test->mComposer, getColorModes(Display::HWC_DISPLAY_ID, _)) .WillOnce(DoAll(SetArgPointee<1>(std::vector<ColorMode>({ColorMode::DISPLAY_P3})), Return(Error::NONE))); EXPECT_CALL(*test->mComposer, getRenderIntents(Display::HWC_DISPLAY_ID, ColorMode::DISPLAY_P3, _)) .WillOnce( DoAll(SetArgPointee<2>(std::vector<RenderIntent>({RenderIntent::ENHANCE})), Return(Error::NONE))); EXPECT_CALL(*test->mComposer, setColorMode(Display::HWC_DISPLAY_ID, ColorMode::SRGB, RenderIntent::ENHANCE)) .WillOnce(Return(Error::NONE)); } }; // For this variant, SurfaceFlinger should configure itself with wide display // support, but the display should respond with an empty list of supported color // modes. Wide-color support for the display should not be configured. Loading Loading @@ -640,9 +613,6 @@ using HwcVirtualDisplayCase = using WideColorP3ColorimetricDisplayCase = Case<PrimaryDisplayVariant, WideColorP3ColorimetricSupportedVariant<PrimaryDisplayVariant>, HdrNotSupportedVariant<PrimaryDisplayVariant>>; using WideColorP3EnhanceDisplayCase = Case<PrimaryDisplayVariant, WideColorP3EnhanceSupportedVariant<PrimaryDisplayVariant>, HdrNotSupportedVariant<PrimaryDisplayVariant>>; using Hdr10DisplayCase = Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>, Hdr10SupportedVariant<PrimaryDisplayVariant>>; Loading Loading @@ -1048,10 +1018,6 @@ TEST_F(SetupNewDisplayDeviceInternalTest, createWideColorP3Display) { setupNewDisplayDeviceInternalTest<WideColorP3ColorimetricDisplayCase>(); } TEST_F(SetupNewDisplayDeviceInternalTest, createWideColorP3EnhanceDisplay) { setupNewDisplayDeviceInternalTest<WideColorP3EnhanceDisplayCase>(); } TEST_F(SetupNewDisplayDeviceInternalTest, createHdr10Display) { setupNewDisplayDeviceInternalTest<Hdr10DisplayCase>(); } Loading