文章目录

  • Android 色彩(颜色)模式解析(一)
    • FrameWork色彩模式的定义及实现
    • SurfaceFlinger对色彩模式的支持和实现
      • 看屏幕是否支持颜色管理
      • 屏幕的ColorProfile
      • SurfaceFlinger设置ColorMode的流程
    • 小结

Android 色彩(颜色)模式解析(一)

Android Q 在系统设置中提供了可设置的色彩模式,当然这功能很多厂商早就有了~,落后归落后,我们还是看看Android是怎么实现的!

Android Q提供了4种色彩模式:

  • Natural 自然色
  • Boosted 效果增强
  • Saturated 饱和色
  • Adaptive 自动调节

下面我们就结合实际代码,看看具体的实现和流程!

FrameWork色彩模式的定义及实现

为了实现色彩模式的切换,Android Framework设计了ColorDisplayManager及对应的服务,提供可切换的色彩模式和对应的设置接口。四种色彩模式对应的值如下:

    public static final int COLOR_MODE_NATURAL = 0;    public static final int COLOR_MODE_BOOSTED = 1;    public static final int COLOR_MODE_SATURATED = 2;    public static final int COLOR_MODE_AUTOMATIC = 3;

Settings中通过ColorDisplayManager的setColorMode接口进行色彩模式的切换,对应的代码如下:

* packages/apps/Settings/src/com/android/settings/display/ColorModePreferenceFragment.java    @Override    protected boolean setDefaultKey(String key) {        switch (key) {            case KEY_COLOR_MODE_NATURAL:                mColorDisplayManager.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);                break;            case KEY_COLOR_MODE_BOOSTED:                mColorDisplayManager.setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED);                break;            case KEY_COLOR_MODE_SATURATED:                mColorDisplayManager.setColorMode(ColorDisplayManager.COLOR_MODE_SATURATED);                break;            case KEY_COLOR_MODE_AUTOMATIC:                mColorDisplayManager.setColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC);                break;        }        return true;    }

在ColorDisplayManager中,设计了一个内部类ColorDisplayManagerInternal,通过内部类和对应的系统服务COLOR_DISPLAY_SERVICE进行交互。

*  frameworks/base/core/java/android/hardware/display/ColorDisplayManager.java    public void setColorMode(int colorMode) {        mManager.setColorMode(colorMode);    }

对应的服务实现如下:

* frameworks/base/services/core/java/com/android/server/display/color/ColorDisplayService.java    private void setColorModeInternal(@ColorMode int colorMode) {        if (!isColorModeAvailable(colorMode)) {            throw new IllegalArgumentException("Invalid colorMode: " + colorMode);        }        System.putIntForUser(getContext().getContentResolver(), System.DISPLAY_COLOR_MODE,                colorMode,                mCurrentUser);    }

在色彩显示服务中,只是将需要的色彩模式对应的值写到了,系统设置的数据库中,键值DISPLAY_COLOR_MODE。

其实,看多了Framework的代码,我们就会知道,肯定会有一个ContentObserver来监听这个数据的变化的,在ColorDisplayService的setUp函数中:

    private void setUp() {        Slog.d(TAG, "setUp: currentUser=" + mCurrentUser);        // Listen for external changes to any of the settings.        if (mContentObserver == null) {            mContentObserver = new ContentObserver(new Handler(DisplayThread.get().getLooper())) {                @Override                public void onChange(boolean selfChange, Uri uri) {                    super.onChange(selfChange, uri);                    final String setting = uri == null ? null : uri.getLastPathSegment();                    if (setting != null) {                        switch (setting) {                            ... ...                            case System.DISPLAY_COLOR_MODE:                                onDisplayColorModeChanged(getColorModeInternal());

当设置中,切换色彩模式,修改了系统设置中的DISPLAY_COLOR_MODE值后,这个observer就会触发DISPLAY_COLOR_MODE的onChange,最后通过onDisplayColorModeChanged函数来处理。

* frameworks/base/services/core/java/com/android/server/display/color/ColorDisplayService.java    private void onDisplayColorModeChanged(int mode) {        if (mode == NOT_SET) {            return;        }        mNightDisplayTintController.cancelAnimator();        mDisplayWhiteBalanceTintController.cancelAnimator();        if (mNightDisplayTintController.isAvailable(getContext())) {            mNightDisplayTintController                    .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode));            mNightDisplayTintController                    .setMatrix(mNightDisplayTintController.getColorTemperatureSetting());        }        updateDisplayWhiteBalanceStatus();        final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);        dtm.setColorMode(mode, mNightDisplayTintController.getMatrix());    }

这里涉及到夜光屏和白平衡,说白了,这些的实现都是跟色彩和亮度有关。我们先留下夜光屏幕和白平衡,单看色彩模式的流程。色彩模式,通过 DisplayTransformManager 的setColorMode接口继续往下传:

* frameworks/base/services/core/java/com/android/server/display/color/DisplayTransformManager.java    public boolean setColorMode(int colorMode, float[] nightDisplayMatrix) {        if (colorMode == ColorDisplayManager.COLOR_MODE_NATURAL) {            applySaturation(COLOR_SATURATION_NATURAL);            setDisplayColor(DISPLAY_COLOR_MANAGED);        } else if (colorMode == ColorDisplayManager.COLOR_MODE_BOOSTED) {            applySaturation(COLOR_SATURATION_BOOSTED);            setDisplayColor(DISPLAY_COLOR_MANAGED);        } else if (colorMode == ColorDisplayManager.COLOR_MODE_SATURATED) {            applySaturation(COLOR_SATURATION_NATURAL);            setDisplayColor(DISPLAY_COLOR_UNMANAGED);        } else if (colorMode == ColorDisplayManager.COLOR_MODE_AUTOMATIC) {            applySaturation(COLOR_SATURATION_NATURAL);            setDisplayColor(DISPLAY_COLOR_ENHANCED);        }        setColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, nightDisplayMatrix);        updateConfiguration();        return true;    }

重点来了,前面我们说到的4种色彩模式,主要通过两个参数的调节来实现的

  • Saturation饱和度
    饱和度两种可选模式:自然模式和增强模式
    private static final float COLOR_SATURATION_NATURAL = 1.0f;    private static final float COLOR_SATURATION_BOOSTED = 1.1f;
  • DisplayColor显示颜色
    显示颜色有3种模式:Managed,UnManaged以及增强模式
    private static final int DISPLAY_COLOR_MANAGED = 0;    private static final int DISPLAY_COLOR_UNMANAGED = 1;    private static final int DISPLAY_COLOR_ENHANCED = 2;

我们的4中色彩模式:

** COLOR_SATURATION_NATURAL COLOR_SATURATION_BOOSTED
DISPLAY_COLOR_MANAGED 自然色 COLOR_MODE_NATURAL 效果增强 COLOR_MODE_BOOSTED
DISPLAY_COLOR_UNMANAGED 饱和色 COLOR_MODE_SATURATED
DISPLAY_COLOR_ENHANCED 自动调节 COLOR_MODE_AUTOMATIC

这两个参数的设置是通过binder直接设置到SurfaceFlinger的,对应的Binder 命令分别为SURFACE_FLINGER_TRANSACTION_SATURATIONSURFACE_FLINGER_TRANSACTION_DISPLAY_COLOR。相应的代码如下:
饱和度的设置通过applySaturation函数

* frameworks/base/services/core/java/com/android/server/display/color/DisplayTransformManager.java    private void applySaturation(float saturation) {        SystemProperties.set(PERSISTENT_PROPERTY_SATURATION, Float.toString(saturation));        final IBinder flinger = ServiceManager.getService(SURFACE_FLINGER);        if (flinger != null) {            final Parcel data = Parcel.obtain();            data.writeInterfaceToken("android.ui.ISurfaceComposer");            data.writeFloat(saturation);            try {                flinger.transact(SURFACE_FLINGER_TRANSACTION_SATURATION, data, null, 0);            } catch (RemoteException ex) {                Slog.e(TAG, "Failed to set saturation", ex);            } finally {                data.recycle();            }        }    }

显示颜色的设置通过setDisplayColor函数

    private void setDisplayColor(int color) {        SystemProperties.set(PERSISTENT_PROPERTY_DISPLAY_COLOR, Integer.toString(color));        final IBinder flinger = ServiceManager.getService(SURFACE_FLINGER);        if (flinger != null) {            final Parcel data = Parcel.obtain();            data.writeInterfaceToken("android.ui.ISurfaceComposer");            data.writeInt(color);            try {                flinger.transact(SURFACE_FLINGER_TRANSACTION_DISPLAY_COLOR, data, null, 0);            } catch (RemoteException ex) {                Slog.e(TAG, "Failed to set display color", ex);            } finally {                data.recycle();            }        }    }

小结一下,Android提供了4种色彩模式:自然色,效果增强,饱和色和自动调节。而Framework中,是通过两个参数来实现的:饱和度和显示颜色,具体实现,,,往下看!

SurfaceFlinger对色彩模式的支持和实现

通过前面的分析,我们其实只需关心饱和度和显示颜色!SurfaceFlinger中,饱和度用饱和因子mGlobalSaturationFactor来定义,显示颜色用mDisplayColorSetting进行描述。

status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* reply,                                    uint32_t flags) {    ... ...    status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags);    if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) {        ... ...        int n;        switch (code) {            ... ...            case 1022: { // Set saturation boost                Mutex::Autolock _l(mStateLock);                mGlobalSaturationFactor = std::max(0.0f, std::min(data.readFloat(), 2.0f));                updateColorMatrixLocked();                ALOGE("xm-gfx: 1022 mGlobalSaturationFactor:%f\n", mGlobalSaturationFactor);                return NO_ERROR;            }            case 1023: { // Set native mode                mDisplayColorSetting = static_cast(data.readInt32());                invalidateHwcGeometry();                repaintEverything();                ALOGE("xm-gfx: 1023 mDisplayColorSetting:%d\n", mDisplayColorSetting);                return NO_ERROR;            }

饱和因子是一个float值,默认为1.0,系统最初始的值,可以通过属性persist.sys.sf.color_saturation进行设置。饱和因子影响到的是显示的颜色矩阵,具体的算法在这个函数中:

void SurfaceFlinger::updateColorMatrixLocked() {    mat4 colorMatrix;    if (mGlobalSaturationFactor != 1.0f) {        // Rec.709 luma coefficients        float3 luminance{0.213f, 0.715f, 0.072f};        luminance *= 1.0f - mGlobalSaturationFactor;        mat4 saturationMatrix = mat4(            vec4{luminance.r + mGlobalSaturationFactor, luminance.r, luminance.r, 0.0f},            vec4{luminance.g, luminance.g + mGlobalSaturationFactor, luminance.g, 0.0f},            vec4{luminance.b, luminance.b, luminance.b + mGlobalSaturationFactor, 0.0f},            vec4{0.0f, 0.0f, 0.0f, 1.0f}        );        colorMatrix = mClientColorMatrix * saturationMatrix * mDaltonizer();    } else {        colorMatrix = mClientColorMatrix * mDaltonizer();    }    if (mCurrentState.colorMatrix != colorMatrix) {        mCurrentState.colorMatrix = colorMatrix;        mCurrentState.colorMatrixChanged = true;        setTransactionFlags(eTransactionNeeded);    }}

根据饱和因子,生成一个饱和度的矩阵saturationMatrix,再和其他的颜色矩阵相乘,得到需要的矩阵。至于这个矩阵colorMatrix怎么生效的,我们稍后再看!

显示颜色mDisplayColorSetting,最后值可以通过persist.sys.sf.native_mode属性来设置。

看屏幕是否支持颜色管理

SurfaceFlinger定义useColorManagement来描述SurfaceFlinger是否管理颜色。

bool use_color_management(bool defaultValue) {    auto tmpuseColorManagement = SurfaceFlingerProperties::use_color_management();    auto tmpHasHDRDisplay = SurfaceFlingerProperties::has_HDR_display();    auto tmpHasWideColorDisplay = SurfaceFlingerProperties::has_wide_color_display();    auto tmpuseColorManagementVal = tmpuseColorManagement.has_value() ? *tmpuseColorManagement :        defaultValue;    auto tmpHasHDRDisplayVal = tmpHasHDRDisplay.has_value() ? *tmpHasHDRDisplay :        defaultValue;    auto tmpHasWideColorDisplayVal = tmpHasWideColorDisplay.has_value() ? *tmpHasWideColorDisplay :        defaultValue;    return tmpuseColorManagementVal || tmpHasHDRDisplayVal || tmpHasWideColorDisplayVal;}

第一次看这个代码的时候比较奇怪,其实这个就是对属性访问的一个封装,对应的属性访问和接口用sysprop进行描述,定义在SurfaceFlingerProperties.sysprop中,上述3个变量对应的3个属性如下:

ro.surface_flinger.use_color_managementro.surface_flinger.has_HDR_displayro.surface_flinger.has_wide_color_display

我们来看一个属性接口的描述:

* frameworks/native/services/surfaceflinger/sysprop/SurfaceFlingerProperties.syspropprop {    api_name: "has_wide_color_display"    type: Boolean    scope: Internal    access: Readonly    prop_name: "ro.surface_flinger.has_wide_color_display"}

sysprop会被编译成cpp文件!生产的文件在:

out/soong/.intermediates/frameworks/native/services/surfaceflinger/sysprop/libSurfaceFlingerProperties/android_arm64_armv8-a_core_static/gen/sysprop/SurfaceFlingerProperties.sysprop.cpp

has_wide_color_display对应的实现如下:

std::optional has_wide_color_display() {    return GetProp>("ro.surface_flinger.has_wide_color_display");}

屏幕的ColorProfile

颜色管理,是针对屏幕的,不是对单个Layer的!每次一次开始合成时,都会去做屏幕颜色的处理,在calculateWorkingSet函数中。

void SurfaceFlinger::calculateWorkingSet() {    ... ...    // Set the per-frame data    for (const auto& [token, displayDevice] : mDisplays) {        auto display = displayDevice->getCompositionDisplay();        const auto displayId = display->getId();        if (!displayId) {            continue;        }        auto* profile = display->getDisplayColorProfile();        if (mDrawingState.colorMatrixChanged) {            display->setColorTransform(mDrawingState.colorMatrix);        }        Dataspace targetDataspace = Dataspace::UNKNOWN;        if (useColorManagement) {            ColorMode colorMode;            RenderIntent renderIntent;            pickColorMode(displayDevice, &colorMode, &targetDataspace, &renderIntent);            display->setColorMode(colorMode, targetDataspace, renderIntent);        }

SurfaceFlinger中,Profile封装了传输给显示屏幕颜色的所有的状态和功能!ColorMode只是显示屏众多特性中的一个。SurfaceFlinger中用ColorModeValue进行描述:

* frameworks/native/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h    struct ColorModeValue {        ui::Dataspace dataspace;        ui::ColorMode colorMode;        ui::RenderIntent renderIntent;    };

ui的定义在hardware/interfaces/graphics/common中。目前是1.3版本!

我们来看看几个比较常用的:

  • Dataspace
* hardware/interfaces/graphics/common/1.0/types.hal@export(name="android_dataspace_t", value_prefix="HAL_DATASPACE_")enum Dataspace : int32_t {    /**     * Default-assumption data space, when not explicitly specified.     *     * It is safest to assume the buffer is an image with sRGB primaries and     * encoding ranges, but the consumer and/or the producer of the data may     * simply be using defaults. No automatic gamma transform should be     * expected, except for a possible display gamma transform when drawn to a     * screen.     */    UNKNOWN = 0x0,    ... ...    /**     * Transfer characteristic curve:     *  E = L     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry     *      E - corresponding electrical signal     */    TRANSFER_LINEAR = 1 << TRANSFER_SHIFT,    /**     * Transfer characteristic curve:     *     * E = 1.055 * L^(1/2.4) - 0.055  for 0.0031308 <= L <= 1     *   = 12.92 * L                  for 0 <= L < 0.0031308     *     L - luminance of image 0 <= L <= 1 for conventional colorimetry     *     E - corresponding electrical signal     */    TRANSFER_SRGB = 2 << TRANSFER_SHIFT,    ... ...    /**     * sRGB gamma encoding:     *     * The red, green and blue components are stored in sRGB space, and     * converted to linear space when read, using the SRGB transfer function     * for each of the R, G and B components. When written, the inverse     * transformation is performed.     *     * The alpha component, if present, is always stored in linear space and     * is left unmodified when read or written.     *     * Use full range and BT.709 standard.     */    SRGB = 0x201, // deprecated, use V0_SRGB    V0_SRGB = STANDARD_BT709 | TRANSFER_SRGB | RANGE_FULL,    ... ...    /**     * Display P3     *     * Use same primaries and white-point as DCI-P3     * but sRGB transfer function.     */    DISPLAY_P3 = STANDARD_DCI_P3 | TRANSFER_SRGB | RANGE_FULL,};
  • ColorMode
* hardware/interfaces/graphics/common/1.0/types.hal@export(name="android_color_mode_t", value_prefix="HAL_COLOR_MODE_")enum ColorMode : int32_t {    /**     * DEFAULT is the "native" gamut of the display.     * White Point: Vendor/OEM defined     * Panel Gamma: Vendor/OEM defined (typically 2.2)     * Rendering Intent: Vendor/OEM defined (typically 'enhanced')     */    NATIVE = 0,    ... ...    /**     * SRGB corresponds with display settings that implement     * the sRGB color space. Uses the same primaries as ITU-R Recommendation     * BT.709     * Rendering Intent: Colorimetric     * Primaries:     *                  x       y     *  green           0.300   0.600     *  blue            0.150   0.060     *  red             0.640   0.330     *  white (D65)     0.3127  0.3290     *     * PC/Internet (sRGB) Inverse Gamma Correction (IGC):     *     *  if Vnonlinear ≤ 0.03928     *    Vlinear = Vnonlinear / 12.92     *  else     *    Vlinear = ((Vnonlinear + 0.055)/1.055) ^ 2.4     *     * PC/Internet (sRGB) Gamma Correction (GC):     *     *  if Vlinear ≤ 0.0031308     *    Vnonlinear = 12.92 * Vlinear     *  else     *    Vnonlinear = 1.055 * (Vlinear)^(1/2.4) – 0.055     */    SRGB = 7,    ... ...    /**     * DISPLAY_P3 is a color space that uses the DCI_P3 primaries,     * the D65 white point and the SRGB transfer functions.     * Rendering Intent: Colorimetric     * Primaries:     *                  x       y     *  green           0.265   0.690     *  blue            0.150   0.060     *  red             0.680   0.320     *  white (D65)     0.3127  0.3290     *     * PC/Internet (sRGB) Gamma Correction (GC):     *     *  if Vlinear ≤ 0.0030186     *    Vnonlinear = 12.92 * Vlinear     *  else     *    Vnonlinear = 1.055 * (Vlinear)^(1/2.4) – 0.055     *     * Note: In most cases sRGB transfer function will be fine.     */    DISPLAY_P3 = 9};
  • RenderIntent
* hardware/interfaces/graphics/common/1.1/types.hal@export(name="android_render_intent_v1_1_t", value_prefix="HAL_RENDER_INTENT_",        export_parent="false")enum RenderIntent : int32_t {    /**     * Colors in the display gamut are unchanged. Colors out of the display     * gamut are hard-clipped.     *     * This implies that the display must have been calibrated unless     * ColorMode::NATIVE is the only supported color mode.     */    COLORIMETRIC = 0,    /**     * Enhance colors that are in the display gamut. Colors out of the display     * gamut are hard-clipped.     *     * The enhancement typically picks the biggest standard color space (e.g.     * DCI-P3) that is narrower than the display gamut and stretches it to the     * display gamut. The stretching is recommended to preserve skin tones.     */    ENHANCE = 1,    /**     * Tone map high-dynamic-range colors to the display's dynamic range. The     * dynamic range of the colors are communicated separately. After tone     * mapping, the mapping to the display gamut is as defined in     * COLORIMETRIC.     */    TONE_MAP_COLORIMETRIC = 2,    /**     * Tone map high-dynamic-range colors to the display's dynamic range. The     * dynamic range of the colors are communicated separately. After tone     * mapping, the mapping to the display gamut is as defined in ENHANCE.     *     * The tone mapping step and the enhancing step must match     * TONE_MAP_COLORIMETRIC and ENHANCE respectively when they are also     * supported.     */    TONE_MAP_ENHANCE = 3,    /*     * Vendors are recommended to use 0x100 - 0x1FF for their own values, and     * that must be done with subtypes defined by vendor extensions.     */};

SurfaceFlinger设置ColorMode的流程

// Pick the ColorMode / Dataspace for the display device.void SurfaceFlinger::pickColorMode(const sp& display, ColorMode* outMode,                                   Dataspace* outDataSpace, RenderIntent* outRenderIntent) const {    if (mDisplayColorSetting == DisplayColorSetting::UNMANAGED) {        *outMode = ColorMode::NATIVE;        *outDataSpace = Dataspace::UNKNOWN;        *outRenderIntent = RenderIntent::COLORIMETRIC;        return;    }    Dataspace hdrDataSpace;    Dataspace bestDataSpace = getBestDataspace(display, &hdrDataSpace);    auto* profile = display->getCompositionDisplay()->getDisplayColorProfile();    switch (mForceColorMode) {        case ColorMode::SRGB:            bestDataSpace = Dataspace::V0_SRGB;            break;        case ColorMode::DISPLAY_P3:            bestDataSpace = Dataspace::DISPLAY_P3;            break;        default:            break;    }    // respect hdrDataSpace only when there is no legacy HDR support    const bool isHdr =            hdrDataSpace != Dataspace::UNKNOWN && !profile->hasLegacyHdrSupport(hdrDataSpace);    if (isHdr) {        bestDataSpace = hdrDataSpace;    }    RenderIntent intent;    switch (mDisplayColorSetting) {        case DisplayColorSetting::MANAGED:        case DisplayColorSetting::UNMANAGED:            intent = isHdr ? RenderIntent::TONE_MAP_COLORIMETRIC : RenderIntent::COLORIMETRIC;            break;        case DisplayColorSetting::ENHANCED:            intent = isHdr ? RenderIntent::TONE_MAP_ENHANCE : RenderIntent::ENHANCE;            break;        default: // vendor display color setting            intent = static_cast(mDisplayColorSetting);            break;    }    profile->getBestColorMode(bestDataSpace, intent, outDataSpace, outMode, outRenderIntent);}

可见,在选择ColorMode时,获取ColorMode,DataSpace,和RenderIntent。

首先来看,bestDataSpace的获取,实现函数如下:

// Returns a data space that fits all visible layers.  The returned data space// can only be one of//  - Dataspace::SRGB (use legacy dataspace and let HWC saturate when colors are enhanced)//  - Dataspace::DISPLAY_P3//  - Dataspace::DISPLAY_BT2020// The returned HDR data space is one of//  - Dataspace::UNKNOWN//  - Dataspace::BT2020_HLG//  - Dataspace::BT2020_PQDataspace SurfaceFlinger::getBestDataspace(const sp& display,                                           Dataspace* outHdrDataSpace) const {    Dataspace bestDataSpace = Dataspace::V0_SRGB;    *outHdrDataSpace = Dataspace::UNKNOWN;    for (const auto& layer : display->getVisibleLayersSortedByZ()) {        switch (layer->getDataSpace()) {            case Dataspace::V0_SCRGB:            case Dataspace::V0_SCRGB_LINEAR:            case Dataspace::BT2020:            case Dataspace::BT2020_ITU:            case Dataspace::BT2020_LINEAR:            case Dataspace::DISPLAY_BT2020:                bestDataSpace = Dataspace::DISPLAY_BT2020;                break;            case Dataspace::DISPLAY_P3:                bestDataSpace = Dataspace::DISPLAY_P3;                break;            case Dataspace::BT2020_PQ:            case Dataspace::BT2020_ITU_PQ:                bestDataSpace = Dataspace::DISPLAY_P3;                *outHdrDataSpace = Dataspace::BT2020_PQ;                break;            case Dataspace::BT2020_HLG:            case Dataspace::BT2020_ITU_HLG:                bestDataSpace = Dataspace::DISPLAY_P3;                // 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:                break;        }    }    return bestDataSpace;}

说说实话,这个算法没有“看懂”。这里采用一个for循环,检查所有的Layer,也就是说bestDataSpace会被后面的Layer不断的覆盖… …感觉这段法“看不懂”… Anyway,这里将选一个最合适的 bestDataSpace,并且去check有没有HDR的space hdrDataSpace。

再回来看pickColorMode函数:

  • 可以人为的指定dataspace,通过mForceColorMode:
    property_get("persist.sys.sf.color_mode", value, "0");    mForceColorMode = static_cast(atoi(value));
  • 如果是Hdr,将使用HDR的Database。

  • 根据上层给下来的mDisplayColorSetting,确定 RenderIntent。

RenderIntent isHdr Normal
MANAGED TONE_MAP_COLORIMETRIC COLORIMETRIC
UNMANAGED TONE_MAP_COLORIMETRIC COLORIMETRIC
ENHANCED TONE_MAP_ENHANCE ENHANCE
void DisplayColorProfile::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 {        // this is unexpected on a WCG display        if (hasWideColorGamut()) {            ALOGE("map unknown (%s)/(%s) to default color mode",                  dataspaceDetails(static_cast(dataspace)).c_str(),                  decodeRenderIntent(intent).c_str());        }        *outDataspace = Dataspace::UNKNOWN;        *outMode = ColorMode::NATIVE;        *outIntent = RenderIntent::COLORIMETRIC;    }}

也就是从 mColorModes 中选取一个合适的模式!~ mColorModes从哪儿来的?其实,添加屏幕的时候,就会去初始化这些参数,在DisplayColorProfile的初始函数中:

* /frameworks/native/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cppDisplayColorProfile::DisplayColorProfile(DisplayColorProfileCreationArgs&& args)      : mHasWideColorGamut(args.hasWideColorGamut),        mSupportedPerFrameMetadata(args.supportedPerFrameMetadata) {    populateColorModes(args.hwcColorModes);    std::vector types = args.hdrCapabilities.getSupportedHdrTypes();    for (ui::Hdr hdrType : types) {        switch (hdrType) {            case ui::Hdr::HDR10_PLUS:                mHasHdr10Plus = true;                break;            case ui::Hdr::HDR10:                mHasHdr10 = true;                break;            case ui::Hdr::HLG:                mHasHLG = true;                break;            case ui::Hdr::DOLBY_VISION:                mHasDolbyVision = true;                break;            default:                ALOGE("UNKNOWN HDR capability: %d", static_cast(hdrType));        }    }    float minLuminance = args.hdrCapabilities.getDesiredMinLuminance();    float maxLuminance = args.hdrCapabilities.getDesiredMaxLuminance();    float maxAverageLuminance = args.hdrCapabilities.getDesiredMaxAverageLuminance();    minLuminance = minLuminance <= 0.0 ? sDefaultMinLumiance : minLuminance;    maxLuminance = maxLuminance <= 0.0 ? sDefaultMaxLumiance : maxLuminance;    maxAverageLuminance = maxAverageLuminance <= 0.0 ? sDefaultMaxLumiance : maxAverageLuminance;    if (args.hasWideColorGamut) {        // insert HDR10/HLG as we will force client composition for HDR10/HLG        // layers        if (!hasHDR10Support()) {            types.push_back(ui::Hdr::HDR10);        }        if (!hasHLGSupport()) {            types.push_back(ui::Hdr::HLG);        }    }    mHdrCapabilities = HdrCapabilities(types, maxLuminance, maxAverageLuminance, minLuminance);}

注意这个args参数,从哪里来的,在SurfaceFlinger添加DisplayDevice时,给的参数!

sp SurfaceFlinger::setupNewDisplayDeviceInternal(        const wp& displayToken, const std::optional& displayId,        const DisplayDeviceState& state, const sp& dispSurface,        const sp& producer) {    DisplayDeviceCreationArgs creationArgs(this, displayToken, displayId);    creationArgs.sequenceId = state.sequenceId;    creationArgs.isVirtual = state.isVirtual();    creationArgs.isSecure = state.isSecure;    creationArgs.displaySurface = dispSurface;    creationArgs.hasWideColorGamut = false;    creationArgs.supportedPerFrameMetadata = 0;    const bool isInternalDisplay = displayId && displayId == getInternalDisplayIdLocked();    creationArgs.isPrimary = isInternalDisplay;    if (useColorManagement && displayId) {        std::vector modes = getHwComposer().getColorModes(*displayId);        for (ColorMode colorMode : modes) {            if (isWideColorMode(colorMode)) {                creationArgs.hasWideColorGamut = true;            }            std::vector renderIntents =                    getHwComposer().getRenderIntents(*displayId, colorMode);            creationArgs.hwcColorModes.emplace(colorMode, renderIntents);        }    }    if (displayId) {        getHwComposer().getHdrCapabilities(*displayId, &creationArgs.hdrCapabilities);        creationArgs.supportedPerFrameMetadata =                getHwComposer().getSupportedPerFrameMetadata(*displayId);    }    auto nativeWindowSurface = getFactory().createNativeWindowSurface(producer);    auto nativeWindow = nativeWindowSurface->getNativeWindow();    creationArgs.nativeWindow = nativeWindow;    // 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    // here, in case the display is composed entirely by HWC.    if (state.isVirtual()) {        nativeWindow->setSwapInterval(nativeWindow.get(), 0);    }    creationArgs.displayInstallOrientation =            isInternalDisplay ? primaryDisplayOrientation : DisplayState::eOrientationDefault;    // virtual displays are always considered enabled    creationArgs.initialPowerMode = state.isVirtual() ? HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF;    sp display = getFactory().createDisplayDevice(std::move(creationArgs));    if (maxFrameBufferAcquiredBuffers >= 3) {        nativeWindowSurface->preallocateBuffers();    }    ColorMode defaultColorMode = ColorMode::NATIVE;    Dataspace defaultDataSpace = Dataspace::UNKNOWN;    if (display->hasWideColorGamut()) {        defaultColorMode = ColorMode::SRGB;        defaultDataSpace = Dataspace::V0_SRGB;    }    display->getCompositionDisplay()->setColorMode(defaultColorMode, defaultDataSpace,                                                   RenderIntent::COLORIMETRIC);    if (!state.isVirtual()) {        LOG_ALWAYS_FATAL_IF(!displayId);        display->setActiveConfig(getHwComposer().getActiveConfigIndex(*displayId));    }    display->setLayerStack(state.layerStack);    display->setProjection(state.orientation, state.viewport, state.frame);    display->setDisplayName(state.displayName);    return display;}

ColorModes是在populateColorModes函数中添加的:

void DisplayColorProfile::populateColorModes(        const DisplayColorProfileCreationArgs::HwcColorModes& hwcColorModes) {    if (!hasWideColorGamut()) {        return;    }    // collect all known SDR render intents    std::unordered_set 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 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 : hdrRenderIntents) {        for (auto mode : sHdrColorModes) {            addColorMode(hwcColorModes, mode, intent);        }    }}

从这个函数来看,目前主要针对SDR和HDR,系统默认支持的RenderIntent如下:

// ordered list of known SDR render intentsconst std::array sSdrRenderIntents = {        RenderIntent::ENHANCE,        RenderIntent::COLORIMETRIC,};// ordered list of known HDR render intentsconst std::array sHdrRenderIntents = {        RenderIntent::TONE_MAP_ENHANCE,        RenderIntent::TONE_MAP_COLORIMETRIC,};

这块贴的代码有点多,是为了保存完整性,很多细节可以先不看!我们先关注一下,上层设置下来的参数,到哪里去了。!这里AddColorMode时,根据dataspace和renderintent生成key,再将hwc支持的对应的hwcDataspace, hwcColorMode, hwcIntent保存下来。

回到getBestColorMode函数,上层给下的intent,和dataspace。

    static ColorModeKey getColorModeKey(ui::Dataspace dataspace, ui::RenderIntent intent) {        return (static_cast(dataspace) << 32) | static_cast(intent);    }

根据key,去选取hwcDataspace, hwcColorMode, hwcIntent。所以这里的流程梳理下:

  • 屏幕初始化时,获取屏幕支持的hwcDataspace, hwcColorMode, hwcIntent,转换为SurfaceFlinger中的RenderIntenthedataspace的key来保存
  • 上层设置的DisplayColorSetting转换为对应的RenderIntent
  • 根据显示内容,确定最合适的besedataspace
  • 根据RenderIntent和besedataspace,选取对应的hwcDataspace, hwcColorMode, hwcIntent。

小结

我们这里主要讲了上层的颜色管理,接下来看看HAL和底层驱动的具体实现!

更多相关文章

  1. android调试模式的操作技巧,调试BUG极快呀
  2. ANDROID下多种网络模式的联网处理
  3. Android资源文件Res详解——ShapeDrawable
  4. Android学习笔记(九)ListView
  5. Android运行时配置更改
  6. Android四大组件 - Activity的生命周期和启动模式
  7. android中数据库创建操作的模式
  8. 【Android】颜色的透明度
  9. Android与MVC设计模式

随机推荐

  1. Dnsyo-在全球超过1500个DNS服务器上检查
  2. Linux命令行下抓取HTTP流量的工具--httpr
  3. Linux下查看进程IO工具iopp
  4. centos7下配置ntp客户端同步时间服务(包括
  5. CentOS下使用MyTop实时监控MySQL
  6. Linux命令行下交互式HTTP客户端--HTTP Pr
  7. CentOS 7下使用FirewallD构建动态防火墙
  8. Linux压力测试软件Stress使用指南
  9. 批量杀死MySQL连接的几种方法
  10. Java访问数据库之JDBC实现方式