600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > android色彩模式 Android Q 色彩(颜色)模式解析(一)

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

时间:2022-02-26 03:18:33

相关推荐

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

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_SATURATION和 SURFACE_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

", mGlobalSaturationFactor);

return NO_ERROR;

}

case 1023: { // Set native mode

mDisplayColorSetting = static_cast(data.readInt32());

invalidateHwcGeometry();

repaintEverything();

ALOGE("xm-gfx: 1023 mDisplayColorSetting:%d

", 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_management

ro.surface_flinger.has_HDR_display

ro.surface_flinger.has_wide_color_display复制代码

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

* frameworks/native/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop

prop {

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<:optional>>("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_BT

// The returned HDR data space is one of

// - Dataspace::UNKNOWN

// - Dataspace::BT_HLG

// - Dataspace::BT_PQ

Dataspace 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::BT:

case Dataspace::BT_ITU:

case Dataspace::BT_LINEAR:

case Dataspace::DISPLAY_BT:

bestDataSpace = Dataspace::DISPLAY_BT;

break;

case Dataspace::DISPLAY_P3:

bestDataSpace = Dataspace::DISPLAY_P3;

break;

case Dataspace::BT_PQ:

case Dataspace::BT_ITU_PQ:

bestDataSpace = Dataspace::DISPLAY_P3;

*outHdrDataSpace = Dataspace::BT_PQ;

break;

case Dataspace::BT_HLG:

case Dataspace::BT_ITU_HLG:

bestDataSpace = Dataspace::DISPLAY_P3;

// When there's mixed PQ content and HLG content, we set the HDR

// data space to be BT_PQ and convert HLG to PQ.

if (*outHdrDataSpace == Dataspace::UNKNOWN) {

*outHdrDataSpace = Dataspace::BT_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

ENHANCEvoid 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.cpp

DisplayColorProfile::DisplayColorProfile(DisplayColorProfileCreationArgs&& args)

: mHasWideColorGamut(args.hasWideColorGamut),

mSupportedPerFrameMetadata(args.supportedPerFrameMetadata) {

populateColorModes(args.hwcColorModes);

std::vector<:hdr> 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<:displaysurface>& 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 intents

const std::array sSdrRenderIntents = {

RenderIntent::ENHANCE,

RenderIntent::COLORIMETRIC,

};

// ordered list of known HDR render intents

const 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和底层驱动的具体实现!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。