diff options
Diffstat (limited to 'services/surfaceflinger/DisplayDevice.cpp')
-rw-r--r-- | services/surfaceflinger/DisplayDevice.cpp | 597 |
1 files changed, 377 insertions, 220 deletions
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index b8a0a5a219..db095a51d9 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -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> @@ -28,6 +31,7 @@ #include <utils/RefBase.h> #include <utils/Log.h> +#include <ui/DebugUtils.h> #include <ui/DisplayInfo.h> #include <ui/PixelFormat.h> @@ -37,9 +41,7 @@ #include "DisplayHardware/DisplaySurface.h" #include "DisplayHardware/HWComposer.h" -#ifdef USE_HWC2 #include "DisplayHardware/HWC2.h" -#endif #include "RenderEngine/RenderEngine.h" #include "clz.h" @@ -50,28 +52,15 @@ #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> #include <configstore/Utils.h> -// ---------------------------------------------------------------------------- -using namespace android; -// ---------------------------------------------------------------------------- - -#ifdef EGL_ANDROID_swap_rectangle -static constexpr bool kEGLAndroidSwapRectangle = true; -#else -static constexpr bool kEGLAndroidSwapRectangle = false; -#endif +namespace android { // retrieve triple buffer setting from configstore using namespace android::hardware::configstore; using namespace android::hardware::configstore::V1_0; - -static bool useTripleFramebuffer = getInt64< ISurfaceFlingerConfigs, - &ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2) >= 3; - -#if !defined(EGL_EGLEXT_PROTOTYPES) || !defined(EGL_ANDROID_swap_rectangle) -// Dummy implementation in case it is missing. -inline void eglSetSwapRectangleANDROID (EGLDisplay, EGLSurface, EGLint, EGLint, EGLint, EGLint) { -} -#endif +using android::ui::ColorMode; +using android::ui::Dataspace; +using android::ui::Hdr; +using android::ui::RenderIntent; /* * Initialize the display to the specified values. @@ -80,123 +69,246 @@ inline void eglSetSwapRectangleANDROID (EGLDisplay, EGLSurface, EGLint, EGLint, 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; + } + } + + if (isHdr) { + // add other HDR candidates when intent is HDR + for (auto hdrIntent : sHdrRenderIntents) { + if (hdrIntent != intent) { + candidates.push_back(hdrIntent); + } + } + } else { + // add other SDR candidates when intent is SDR + for (auto sdrIntent : sSdrRenderIntents) { + if (sdrIntent != intent) { + candidates.push_back(sdrIntent); + } + } + } + + 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, DisplayType type, int32_t hwcId, -#ifndef USE_HWC2 - int format, -#endif bool isSecure, const wp<IBinder>& displayToken, + const sp<ANativeWindow>& nativeWindow, const sp<DisplaySurface>& displaySurface, - const sp<IGraphicBufferProducer>& producer, - EGLConfig config, - bool supportWideColor) + std::unique_ptr<RE::Surface> renderSurface, + int displayWidth, + int displayHeight, + bool hasWideColorGamut, + const HdrCapabilities& hdrCapabilities, + const int32_t supportedPerFrameMetadata, + const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes, + int initialPowerMode) : lastCompositionHadVisibleLayers(false), mFlinger(flinger), mType(type), mHwcDisplayId(hwcId), mDisplayToken(displayToken), + mNativeWindow(nativeWindow), mDisplaySurface(displaySurface), - mDisplay(EGL_NO_DISPLAY), - mSurface(EGL_NO_SURFACE), - mDisplayWidth(), - mDisplayHeight(), -#ifndef USE_HWC2 - mFormat(), -#endif - mFlags(), - mPageFlipCount(), + mSurface{std::move(renderSurface)}, + mDisplayWidth(displayWidth), + mDisplayHeight(displayHeight), + mPageFlipCount(0), mIsSecure(isSecure), mLayerStack(NO_LAYER_STACK), mOrientation(), - mPowerMode(HWC_POWER_MODE_OFF), - mActiveConfig(0) + mViewport(Rect::INVALID_RECT), + mFrame(Rect::INVALID_RECT), + mPowerMode(initialPowerMode), + mActiveConfig(0), + mColorTransform(HAL_COLOR_TRANSFORM_IDENTITY), + mHasWideColorGamut(hasWideColorGamut), + mHasHdr10(false), + mHasHLG(false), + mHasDolbyVision(false), + mSupportedPerFrameMetadata(supportedPerFrameMetadata) { // clang-format on - Surface* surface; - mNativeWindow = surface = new Surface(producer, false); - ANativeWindow* const window = mNativeWindow.get(); + populateColorModes(hwcColorModes); + + std::vector<Hdr> types = hdrCapabilities.getSupportedHdrTypes(); + for (Hdr hdrType : types) { + switch (hdrType) { + case Hdr::HDR10: + mHasHdr10 = true; + break; + case Hdr::HLG: + mHasHLG = true; + break; + case Hdr::DOLBY_VISION: + mHasDolbyVision = true; + break; + default: + ALOGE("UNKNOWN HDR capability: %d", static_cast<int32_t>(hdrType)); + } + } -#ifdef USE_HWC2 - mActiveColorMode = HAL_COLOR_MODE_NATIVE; - mDisplayHasWideColor = supportWideColor; -#else - (void) supportWideColor; -#endif - /* - * Create our display's surface - */ - - EGLSurface eglSurface; - EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - if (config == EGL_NO_CONFIG) { -#ifdef USE_HWC2 - config = RenderEngine::chooseEglConfig(display, PIXEL_FORMAT_RGBA_8888, - /*logConfig*/ false); -#else - config = RenderEngine::chooseEglConfig(display, format, - /*logConfig*/ false); -#endif - } - eglSurface = eglCreateWindowSurface(display, config, window, NULL); - eglQuerySurface(display, eglSurface, EGL_WIDTH, &mDisplayWidth); - eglQuerySurface(display, eglSurface, EGL_HEIGHT, &mDisplayHeight); - - // Make sure that composition can never be stalled by a virtual display - // consumer that isn't processing buffers fast enough. We have to do this - // in two places: - // * Here, in case the display is composed entirely by HWC. - // * In makeCurrent(), using eglSwapInterval. Some EGL drivers set the - // window's swap interval in eglMakeCurrent, so they'll override the - // interval we set here. - if (mType >= DisplayDevice::DISPLAY_VIRTUAL) - window->setSwapInterval(window, 0); - - mConfig = config; - mDisplay = display; - mSurface = eglSurface; -#ifndef USE_HWC2 - mFormat = format; -#endif - mPageFlipCount = 0; - mViewport.makeInvalid(); - mFrame.makeInvalid(); - - // virtual displays are always considered enabled - mPowerMode = (mType >= DisplayDevice::DISPLAY_VIRTUAL) ? - HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF; + float minLuminance = hdrCapabilities.getDesiredMinLuminance(); + float maxLuminance = hdrCapabilities.getDesiredMaxLuminance(); + float maxAverageLuminance = hdrCapabilities.getDesiredMaxAverageLuminance(); + + minLuminance = minLuminance <= 0.0 ? sDefaultMinLumiance : minLuminance; + maxLuminance = maxLuminance <= 0.0 ? sDefaultMaxLumiance : maxLuminance; + maxAverageLuminance = maxAverageLuminance <= 0.0 ? sDefaultMaxLumiance : maxAverageLuminance; + if (this->hasWideColorGamut()) { + // insert HDR10/HLG as we will force client composition for HDR10/HLG + // layers + if (!hasHDR10Support()) { + types.push_back(Hdr::HDR10); + } + + if (!hasHLGSupport()) { + types.push_back(Hdr::HLG); + } + } + mHdrCapabilities = HdrCapabilities(types, maxLuminance, maxAverageLuminance, minLuminance); // initialize the display orientation transform. setProjection(DisplayState::eOrientationDefault, mViewport, mFrame); - - if (useTripleFramebuffer) { - surface->allocateBuffers(); - } } -DisplayDevice::~DisplayDevice() { - if (mSurface != EGL_NO_SURFACE) { - eglDestroySurface(mDisplay, mSurface); - mSurface = EGL_NO_SURFACE; - } -} +DisplayDevice::~DisplayDevice() = default; void DisplayDevice::disconnect(HWComposer& hwc) { if (mHwcDisplayId >= 0) { hwc.disconnectDisplay(mHwcDisplayId); -#ifndef USE_HWC2 - if (mHwcDisplayId >= DISPLAY_VIRTUAL) - hwc.freeDisplayId(mHwcDisplayId); -#endif mHwcDisplayId = -1; } } bool DisplayDevice::isValid() const { - return mFlinger != NULL; + return mFlinger != nullptr; } int DisplayDevice::getWidth() const { @@ -207,16 +319,6 @@ int DisplayDevice::getHeight() const { return mDisplayHeight; } -#ifndef USE_HWC2 -PixelFormat DisplayDevice::getFormat() const { - return mFormat; -} -#endif - -EGLSurface DisplayDevice::getEGLSurface() const { - return mSurface; -} - void DisplayDevice::setDisplayName(const String8& displayName) { if (!displayName.isEmpty()) { // never override the name with an empty name @@ -228,25 +330,9 @@ uint32_t DisplayDevice::getPageFlipCount() const { return mPageFlipCount; } -#ifndef USE_HWC2 -status_t DisplayDevice::compositionComplete() const { - return mDisplaySurface->compositionComplete(); -} -#endif - -void DisplayDevice::flip(const Region& dirty) const +void DisplayDevice::flip() const { mFlinger->getRenderEngine().checkErrors(); - - if (kEGLAndroidSwapRectangle) { - if (mFlags & SWAP_RECTANGLE) { - const Region newDirty(dirty.intersect(bounds())); - const Rect b(newDirty.getBounds()); - eglSetSwapRectangleANDROID(mDisplay, mSurface, - b.left, b.top, b.width(), b.height()); - } - } - mPageFlipCount++; } @@ -254,7 +340,6 @@ status_t DisplayDevice::beginFrame(bool mustRecompose) const { return mDisplaySurface->beginFrame(mustRecompose); } -#ifdef USE_HWC2 status_t DisplayDevice::prepareFrame(HWComposer& hwc) { status_t error = hwc.prepare(*this); if (error != NO_ERROR) { @@ -278,53 +363,10 @@ status_t DisplayDevice::prepareFrame(HWComposer& hwc) { } return mDisplaySurface->prepareFrame(compositionType); } -#else -status_t DisplayDevice::prepareFrame(const HWComposer& hwc) const { - DisplaySurface::CompositionType compositionType; - bool haveGles = hwc.hasGlesComposition(mHwcDisplayId); - bool haveHwc = hwc.hasHwcComposition(mHwcDisplayId); - if (haveGles && haveHwc) { - compositionType = DisplaySurface::COMPOSITION_MIXED; - } else if (haveGles) { - compositionType = DisplaySurface::COMPOSITION_GLES; - } else if (haveHwc) { - compositionType = DisplaySurface::COMPOSITION_HWC; - } else { - // Nothing to do -- when turning the screen off we get a frame like - // this. Call it a HWC frame since we won't be doing any GLES work but - // will do a prepare/set cycle. - compositionType = DisplaySurface::COMPOSITION_HWC; - } - return mDisplaySurface->prepareFrame(compositionType); -} -#endif void DisplayDevice::swapBuffers(HWComposer& hwc) const { -#ifdef USE_HWC2 - if (hwc.hasClientComposition(mHwcDisplayId)) { -#else - // We need to call eglSwapBuffers() if: - // (1) we don't have a hardware composer, or - // (2) we did GLES composition this frame, and either - // (a) we have framebuffer target support (not present on legacy - // devices, where HWComposer::commit() handles things); or - // (b) this is a virtual display - if (hwc.initCheck() != NO_ERROR || - (hwc.hasGlesComposition(mHwcDisplayId) && - (hwc.supportsFramebufferTarget() || mType >= DISPLAY_VIRTUAL))) { -#endif - EGLBoolean success = eglSwapBuffers(mDisplay, mSurface); - if (!success) { - EGLint error = eglGetError(); - if (error == EGL_CONTEXT_LOST || - mType == DisplayDevice::DISPLAY_PRIMARY) { - LOG_ALWAYS_FATAL("eglSwapBuffers(%p, %p) failed with 0x%08x", - mDisplay, mSurface, error); - } else { - ALOGE("eglSwapBuffers(%p, %p) failed with 0x%08x", - mDisplay, mSurface, error); - } - } + if (hwc.hasClientComposition(mHwcDisplayId) || hwc.hasFlipClientTargetRequest(mHwcDisplayId)) { + mSurface->swapBuffers(); } status_t result = mDisplaySurface->advanceFrame(); @@ -334,35 +376,14 @@ void DisplayDevice::swapBuffers(HWComposer& hwc) const { } } -#ifdef USE_HWC2 void DisplayDevice::onSwapBuffersCompleted() const { mDisplaySurface->onFrameCommitted(); } -#else -void DisplayDevice::onSwapBuffersCompleted(HWComposer& hwc) const { - if (hwc.initCheck() == NO_ERROR) { - mDisplaySurface->onFrameCommitted(); - } -} -#endif -uint32_t DisplayDevice::getFlags() const -{ - return mFlags; -} - -EGLBoolean DisplayDevice::makeCurrent(EGLDisplay dpy, EGLContext ctx) const { - EGLBoolean result = EGL_TRUE; - EGLSurface sur = eglGetCurrentSurface(EGL_DRAW); - if (sur != mSurface) { - result = eglMakeCurrent(dpy, mSurface, mSurface, ctx); - if (result == EGL_TRUE) { - if (mType >= DisplayDevice::DISPLAY_VIRTUAL) - eglSwapInterval(dpy, 0); - } - } +bool DisplayDevice::makeCurrent() const { + bool success = mFlinger->getRenderEngine().setCurrentSurface(*mSurface); setViewportAndProjection(); - return result; + return success; } void DisplayDevice::setViewportAndProjection() const { @@ -430,20 +451,41 @@ int DisplayDevice::getActiveConfig() const { } // ---------------------------------------------------------------------------- -#ifdef USE_HWC2 -void DisplayDevice::setActiveColorMode(android_color_mode_t mode) { +void DisplayDevice::setActiveColorMode(ColorMode mode) { mActiveColorMode = mode; } -android_color_mode_t DisplayDevice::getActiveColorMode() const { +ColorMode DisplayDevice::getActiveColorMode() const { return mActiveColorMode; } -void DisplayDevice::setCompositionDataSpace(android_dataspace dataspace) { +RenderIntent DisplayDevice::getActiveRenderIntent() const { + return mActiveRenderIntent; +} + +void DisplayDevice::setActiveRenderIntent(RenderIntent renderIntent) { + mActiveRenderIntent = renderIntent; +} + +void DisplayDevice::setColorTransform(const mat4& transform) { + const bool isIdentity = (transform == mat4()); + mColorTransform = + isIdentity ? HAL_COLOR_TRANSFORM_IDENTITY : HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX; +} + +android_color_transform_t DisplayDevice::getColorTransform() const { + return mColorTransform; +} + +void DisplayDevice::setCompositionDataSpace(ui::Dataspace dataspace) { + mCompositionDataSpace = dataspace; ANativeWindow* const window = mNativeWindow.get(); - native_window_set_buffers_data_space(window, dataspace); + native_window_set_buffers_data_space(window, static_cast<android_dataspace>(dataspace)); +} + +ui::Dataspace DisplayDevice::getCompositionDataSpace() const { + return mCompositionDataSpace; } -#endif // ---------------------------------------------------------------------------- @@ -500,17 +542,14 @@ status_t DisplayDevice::orientationToTransfrom( void DisplayDevice::setDisplaySize(const int newWidth, const int newHeight) { dirtyRegion.set(getBounds()); - if (mSurface != EGL_NO_SURFACE) { - eglDestroySurface(mDisplay, mSurface); - mSurface = EGL_NO_SURFACE; - } + mSurface->setNativeWindow(nullptr); mDisplaySurface->resizeBuffers(newWidth, newHeight); ANativeWindow* const window = mNativeWindow.get(); - mSurface = eglCreateWindowSurface(mDisplay, mConfig, window, NULL); - eglQuerySurface(mDisplay, mSurface, EGL_WIDTH, &mDisplayWidth); - eglQuerySurface(mDisplay, mSurface, EGL_HEIGHT, &mDisplayHeight); + mSurface->setNativeWindow(window); + mDisplayWidth = mSurface->queryWidth(); + mDisplayHeight = mSurface->queryHeight(); LOG_FATAL_IF(mDisplayWidth != newWidth, "Unable to set new width to %d", newWidth); @@ -568,6 +607,15 @@ void DisplayDevice::setProjection(int orientation, TL.set(-src_x, -src_y); TP.set(dst_x, dst_y); + // need to take care of primary display rotation for mGlobalTransform + // for case if the panel is not installed aligned with device orientation + if (mType == DisplayType::DISPLAY_PRIMARY) { + int primaryDisplayOrientation = mFlinger->getPrimaryDisplayOrientation(); + DisplayDevice::orientationToTransfrom( + (orientation + primaryDisplayOrientation) % (DisplayState::eOrientation270 + 1), + w, h, &R); + } + // The viewport and frame are both in the logical orientation. // Apply the logical translation, scale to physical size, apply the // physical translation and finally rotate to the physical orientation. @@ -611,17 +659,14 @@ uint32_t DisplayDevice::getPrimaryDisplayOrientationTransform() { void DisplayDevice::dump(String8& result) const { const Transform& tr(mGlobalTransform); - EGLint redSize, greenSize, blueSize, alphaSize; - eglGetConfigAttrib(mDisplay, mConfig, EGL_RED_SIZE, &redSize); - eglGetConfigAttrib(mDisplay, mConfig, EGL_GREEN_SIZE, &greenSize); - eglGetConfigAttrib(mDisplay, mConfig, EGL_BLUE_SIZE, &blueSize); - eglGetConfigAttrib(mDisplay, mConfig, EGL_ALPHA_SIZE, &alphaSize); + ANativeWindow* const window = mNativeWindow.get(); result.appendFormat("+ DisplayDevice: %s\n", mDisplayName.string()); result.appendFormat(" type=%x, hwcId=%d, layerStack=%u, (%4dx%4d), ANativeWindow=%p " "(%d:%d:%d:%d), orient=%2d (type=%08x), " "flips=%u, isSecure=%d, powerMode=%d, activeConfig=%d, numLayers=%zu\n", - mType, mHwcDisplayId, mLayerStack, mDisplayWidth, mDisplayHeight, - mNativeWindow.get(), redSize, greenSize, blueSize, alphaSize, mOrientation, + mType, mHwcDisplayId, mLayerStack, mDisplayWidth, mDisplayHeight, window, + mSurface->queryRedSize(), mSurface->queryGreenSize(), + mSurface->queryBlueSize(), mSurface->queryAlphaSize(), mOrientation, tr.getType(), getPageFlipCount(), mIsSecure, mPowerMode, mActiveConfig, mVisibleLayersSortedByZ.size()); result.appendFormat(" v:[%d,%d,%d,%d], f:[%d,%d,%d,%d], s:[%d,%d,%d,%d]," @@ -630,12 +675,122 @@ void DisplayDevice::dump(String8& result) const { mFrame.left, mFrame.top, mFrame.right, mFrame.bottom, mScissor.left, mScissor.top, mScissor.right, mScissor.bottom, tr[0][0], tr[1][0], tr[2][0], tr[0][1], tr[1][1], tr[2][1], tr[0][2], tr[1][2], tr[2][2]); + auto const surface = static_cast<Surface*>(window); + ui::Dataspace dataspace = surface->getBuffersDataSpace(); + result.appendFormat(" wideColorGamut=%d, hdr10=%d, colorMode=%s, dataspace: %s (%d)\n", + mHasWideColorGamut, mHasHdr10, + decodeColorMode(mActiveColorMode).c_str(), + dataspaceDetails(static_cast<android_dataspace>(dataspace)).c_str(), dataspace); String8 surfaceDump; mDisplaySurface->dumpAsString(surfaceDump); result.append(surfaceDump); } +// 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; + } + + // collect all known SDR render intents + std::unordered_set<RenderIntent> sdrRenderIntents(sSdrRenderIntents.begin(), + sSdrRenderIntents.end()); + auto iter = hwcColorModes.find(ColorMode::SRGB); + if (iter != hwcColorModes.end()) { + for (auto intent : iter->second) { + sdrRenderIntents.insert(intent); + } + } + + // add all known SDR combinations + for (auto intent : sdrRenderIntents) { + for (auto mode : sSdrColorModes) { + addColorMode(hwcColorModes, mode, intent); + } + } + + // collect all known HDR render intents + std::unordered_set<RenderIntent> hdrRenderIntents(sHdrRenderIntents.begin(), + sHdrRenderIntents.end()); + iter = hwcColorModes.find(ColorMode::BT2100_PQ); + if (iter != hwcColorModes.end()) { + for (auto intent : iter->second) { + hdrRenderIntents.insert(intent); + } + } + + // add all 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::hasLegacyHdrSupport(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; + } +} + std::atomic<int32_t> DisplayDeviceState::nextDisplayId(1); DisplayDeviceState::DisplayDeviceState(DisplayDevice::DisplayType type, bool isSecure) @@ -649,3 +804,5 @@ DisplayDeviceState::DisplayDeviceState(DisplayDevice::DisplayType type, bool isS viewport.makeInvalid(); frame.makeInvalid(); } + +} // namespace android |