Merge "Wire-up colorMode="hdr""

This commit is contained in:
TreeHugger Robot
2020-07-31 00:02:05 +00:00
committed by Android (Google) Code Review
17 changed files with 211 additions and 100 deletions

View File

@@ -22,6 +22,7 @@ import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.pm.ActivityInfo;
import android.content.res.CompatibilityInfo.Translator;
import android.graphics.Canvas;
import android.graphics.ColorSpace;
@@ -1001,7 +1002,10 @@ public class Surface implements Parcelable {
mHardwareRenderer = new HardwareRenderer();
mHardwareRenderer.setContentRoot(mRenderNode);
mHardwareRenderer.setSurface(Surface.this, true);
mHardwareRenderer.setWideGamut(isWideColorGamut);
mHardwareRenderer.setColorMode(
isWideColorGamut
? ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT
: ActivityInfo.COLOR_MODE_DEFAULT);
mHardwareRenderer.setLightSourceAlpha(0.0f, 0.0f);
mHardwareRenderer.setLightSourceGeometry(0.0f, 0.0f, 0.0f, 0.0f);
}

View File

@@ -1329,13 +1329,9 @@ public final class ViewRootImpl implements ViewParent,
final boolean hasSurfaceInsets = insets.left != 0 || insets.right != 0
|| insets.top != 0 || insets.bottom != 0;
final boolean translucent = attrs.format != PixelFormat.OPAQUE || hasSurfaceInsets;
final boolean wideGamut =
mContext.getResources().getConfiguration().isScreenWideColorGamut()
&& attrs.getColorMode() == ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT;
mAttachInfo.mThreadedRenderer = ThreadedRenderer.create(mContext, translucent,
attrs.getTitle().toString());
mAttachInfo.mThreadedRenderer.setWideGamut(wideGamut);
updateColorModeIfNeeded(attrs.getColorMode());
updateForceDarkMode();
if (mAttachInfo.mThreadedRenderer != null) {
mAttachInfo.mHardwareAccelerated =
@@ -2648,7 +2644,7 @@ public final class ViewRootImpl implements ViewParent,
& WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED) != 0;
final boolean alwaysConsumeSystemBarsChanged =
mPendingAlwaysConsumeSystemBars != mAttachInfo.mAlwaysConsumeSystemBars;
final boolean colorModeChanged = hasColorModeChanged(lp.getColorMode());
updateColorModeIfNeeded(lp.getColorMode());
surfaceCreated = !hadSurface && mSurface.isValid();
surfaceDestroyed = hadSurface && !mSurface.isValid();
surfaceReplaced = (surfaceGenerationId != mSurface.getGenerationId())
@@ -2677,10 +2673,6 @@ public final class ViewRootImpl implements ViewParent,
// hierarchy is measured below.
dispatchApplyInsets = true;
}
if (colorModeChanged && mAttachInfo.mThreadedRenderer != null) {
mAttachInfo.mThreadedRenderer.setWideGamut(
lp.getColorMode() == ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT);
}
if (surfaceCreated) {
// If we are creating a new surface, then we need to
@@ -2725,7 +2717,7 @@ public final class ViewRootImpl implements ViewParent,
mAttachInfo.mThreadedRenderer.destroy();
}
} else if ((surfaceReplaced
|| surfaceSizeChanged || windowRelayoutWasForced || colorModeChanged)
|| surfaceSizeChanged || windowRelayoutWasForced)
&& mSurfaceHolder == null
&& mAttachInfo.mThreadedRenderer != null
&& mSurface.isValid()) {
@@ -4557,18 +4549,16 @@ public final class ViewRootImpl implements ViewParent,
}
}
private boolean hasColorModeChanged(int colorMode) {
private void updateColorModeIfNeeded(int colorMode) {
if (mAttachInfo.mThreadedRenderer == null) {
return false;
return;
}
final boolean isWideGamut = colorMode == ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT;
if (mAttachInfo.mThreadedRenderer.isWideGamut() == isWideGamut) {
return false;
// TODO: Centralize this sanitization? Why do we let setting bad modes?
// Alternatively, can we just let HWUI figure it out? Do we need to care here?
if (!mContext.getResources().getConfiguration().isScreenWideColorGamut()) {
colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
}
if (isWideGamut && !mContext.getResources().getConfiguration().isScreenWideColorGamut()) {
return false;
}
return true;
mAttachInfo.mThreadedRenderer.setColorMode(colorMode);
}
@Override

View File

@@ -23,6 +23,7 @@ import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.hardware.display.DisplayManager;
import android.os.IBinder;
@@ -157,7 +158,7 @@ public class HardwareRenderer {
protected RenderNode mRootNode;
private boolean mOpaque = true;
private boolean mForceDark = false;
private boolean mIsWideGamut = false;
private @ActivityInfo.ColorMode int mColorMode = ActivityInfo.COLOR_MODE_DEFAULT;
/**
* Creates a new instance of a HardwareRenderer. The HardwareRenderer will default
@@ -167,7 +168,7 @@ public class HardwareRenderer {
ProcessInitializer.sInstance.initDisplayInfo();
mRootNode = RenderNode.adopt(nCreateRootRenderNode());
mRootNode.setClipToBounds(false);
mNativeProxy = nCreateProxy(!mOpaque, mIsWideGamut, mRootNode.mNativeRenderNode);
mNativeProxy = nCreateProxy(!mOpaque, mRootNode.mNativeRenderNode);
if (mNativeProxy == 0) {
throw new OutOfMemoryError("Unable to create hardware renderer");
}
@@ -619,17 +620,17 @@ public class HardwareRenderer {
}
/**
* Enable/disable wide gamut rendering on this renderer. Whether or not the actual rendering
* will be wide gamut depends on the hardware support for such rendering.
* Sets the desired color mode on this renderer. Whether or not the actual rendering
* will use the requested colorMode depends on the hardware support for such rendering.
*
* @param wideGamut true if this renderer should render in wide gamut, false if it should
* render in sRGB
* TODO: Figure out color...
* @param colorMode The @{@link ActivityInfo.ColorMode} to request
* @hide
*/
public void setWideGamut(boolean wideGamut) {
mIsWideGamut = wideGamut;
nSetWideGamut(mNativeProxy, wideGamut);
public void setColorMode(@ActivityInfo.ColorMode int colorMode) {
if (mColorMode != colorMode) {
mColorMode = colorMode;
nSetColorMode(mNativeProxy, colorMode);
}
}
/**
@@ -804,11 +805,6 @@ public class HardwareRenderer {
nSetPictureCaptureCallback(mNativeProxy, callback);
}
/** @hide */
public boolean isWideGamut() {
return mIsWideGamut;
}
/** called by native */
static void invokePictureCapturedCallback(long picturePtr, PictureCapturedCallback callback) {
Picture picture = new Picture(picturePtr);
@@ -1207,8 +1203,7 @@ public class HardwareRenderer {
private static native long nCreateRootRenderNode();
private static native long nCreateProxy(boolean translucent, boolean isWideGamut,
long rootRenderNode);
private static native long nCreateProxy(boolean translucent, long rootRenderNode);
private static native void nDeleteProxy(long nativeProxy);
@@ -1230,7 +1225,7 @@ public class HardwareRenderer {
private static native void nSetOpaque(long nativeProxy, boolean opaque);
private static native void nSetWideGamut(long nativeProxy, boolean wideGamut);
private static native void nSetColorMode(long nativeProxy, int colorMode);
private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size);

34
libs/hwui/ColorMode.h Normal file
View File

@@ -0,0 +1,34 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
namespace android::uirenderer {
// Must match the constants in ActivityInfo.java
enum class ColorMode {
// SRGB means HWUI will produce buffer in SRGB color space.
Default = 0,
// WideColorGamut selects the most optimal colorspace & format for the device's display
// Most commonly DisplayP3 + RGBA_8888 currently.
WideColorGamut = 1,
// HDR Rec2020 + F16
Hdr = 2,
// HDR Rec2020 + 1010102
Hdr10 = 3,
};
} // namespace android::uirenderer

View File

@@ -143,11 +143,10 @@ static jlong android_view_ThreadedRenderer_createRootRenderNode(JNIEnv* env, job
}
static jlong android_view_ThreadedRenderer_createProxy(JNIEnv* env, jobject clazz,
jboolean translucent, jboolean isWideGamut, jlong rootRenderNodePtr) {
jboolean translucent, jlong rootRenderNodePtr) {
RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootRenderNodePtr);
ContextFactoryImpl factory(rootRenderNode);
RenderProxy* proxy = new RenderProxy(translucent, rootRenderNode, &factory);
proxy->setWideGamut(isWideGamut);
return (jlong) proxy;
}
@@ -218,10 +217,10 @@ static void android_view_ThreadedRenderer_setOpaque(JNIEnv* env, jobject clazz,
proxy->setOpaque(opaque);
}
static void android_view_ThreadedRenderer_setWideGamut(JNIEnv* env, jobject clazz,
jlong proxyPtr, jboolean wideGamut) {
static void android_view_ThreadedRenderer_setColorMode(JNIEnv* env, jobject clazz,
jlong proxyPtr, jint colorMode) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
proxy->setWideGamut(wideGamut);
proxy->setColorMode(static_cast<ColorMode>(colorMode));
}
static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
@@ -659,7 +658,7 @@ static const JNINativeMethod gMethods[] = {
(void*)android_view_ThreadedRenderer_setProcessStatsBuffer},
{"nGetRenderThreadTid", "(J)I", (void*)android_view_ThreadedRenderer_getRenderThreadTid},
{"nCreateRootRenderNode", "()J", (void*)android_view_ThreadedRenderer_createRootRenderNode},
{"nCreateProxy", "(ZZJ)J", (void*)android_view_ThreadedRenderer_createProxy},
{"nCreateProxy", "(ZJ)J", (void*)android_view_ThreadedRenderer_createProxy},
{"nDeleteProxy", "(J)V", (void*)android_view_ThreadedRenderer_deleteProxy},
{"nLoadSystemProperties", "(J)Z",
(void*)android_view_ThreadedRenderer_loadSystemProperties},
@@ -671,7 +670,7 @@ static const JNINativeMethod gMethods[] = {
{"nSetLightAlpha", "(JFF)V", (void*)android_view_ThreadedRenderer_setLightAlpha},
{"nSetLightGeometry", "(JFFFF)V", (void*)android_view_ThreadedRenderer_setLightGeometry},
{"nSetOpaque", "(JZ)V", (void*)android_view_ThreadedRenderer_setOpaque},
{"nSetWideGamut", "(JZ)V", (void*)android_view_ThreadedRenderer_setWideGamut},
{"nSetColorMode", "(JI)V", (void*)android_view_ThreadedRenderer_setColorMode},
{"nSyncAndDrawFrame", "(J[JI)I", (void*)android_view_ThreadedRenderer_syncAndDrawFrame},
{"nDestroy", "(JJ)V", (void*)android_view_ThreadedRenderer_destroy},
{"nRegisterAnimatingRenderNode", "(JJ)V",

View File

@@ -87,6 +87,8 @@ bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, con
// Note: The default preference of pixel format is RGBA_8888, when other
// pixel format is available, we should branch out and do more check.
fboInfo.fFormat = GL_RGBA8;
} else if (colorType == kRGBA_1010102_SkColorType) {
fboInfo.fFormat = GL_RGB10_A2;
} else {
LOG_ALWAYS_FATAL("Unsupported color type.");
}

View File

@@ -35,6 +35,7 @@
#include "VectorDrawable.h"
#include "thread/CommonPool.h"
#include "tools/SkSharingProc.h"
#include "utils/Color.h"
#include "utils/String8.h"
#include "utils/TraceUtils.h"
@@ -587,14 +588,23 @@ void SkiaPipeline::dumpResourceCacheUsage() const {
void SkiaPipeline::setSurfaceColorProperties(ColorMode colorMode) {
mColorMode = colorMode;
if (colorMode == ColorMode::SRGB) {
mSurfaceColorType = SkColorType::kN32_SkColorType;
mSurfaceColorSpace = SkColorSpace::MakeSRGB();
} else if (colorMode == ColorMode::WideColorGamut) {
mSurfaceColorType = DeviceInfo::get()->getWideColorType();
mSurfaceColorSpace = DeviceInfo::get()->getWideColorSpace();
} else {
LOG_ALWAYS_FATAL("Unreachable: unsupported color mode.");
switch (colorMode) {
case ColorMode::Default:
mSurfaceColorType = SkColorType::kN32_SkColorType;
mSurfaceColorSpace = SkColorSpace::MakeSRGB();
break;
case ColorMode::WideColorGamut:
mSurfaceColorType = DeviceInfo::get()->getWideColorType();
mSurfaceColorSpace = DeviceInfo::get()->getWideColorSpace();
break;
case ColorMode::Hdr:
mSurfaceColorType = SkColorType::kRGBA_F16_SkColorType;
mSurfaceColorSpace = SkColorSpace::MakeRGB(GetPQSkTransferFunction(), SkNamedGamut::kRec2020);
break;
case ColorMode::Hdr10:
mSurfaceColorType = SkColorType::kRGBA_1010102_SkColorType;
mSurfaceColorSpace = SkColorSpace::MakeRGB(GetPQSkTransferFunction(), SkNamedGamut::kRec2020);
break;
}
}

View File

@@ -50,7 +50,7 @@ public:
bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
ErrorHandler* errorHandler) override;
void setSurfaceColorProperties(renderthread::ColorMode colorMode) override;
void setSurfaceColorProperties(ColorMode colorMode) override;
SkColorType getSurfaceColorType() const override { return mSurfaceColorType; }
sk_sp<SkColorSpace> getSurfaceColorSpace() override { return mSurfaceColorSpace; }
@@ -76,7 +76,7 @@ protected:
renderthread::RenderThread& mRenderThread;
renderthread::ColorMode mColorMode = renderthread::ColorMode::SRGB;
ColorMode mColorMode = ColorMode::Default;
SkColorType mSurfaceColorType;
sk_sp<SkColorSpace> mSurfaceColorSpace;

View File

@@ -174,7 +174,10 @@ void CanvasContext::setSurface(ANativeWindow* window, bool enableTimeout) {
} else {
mNativeSurface = nullptr;
}
setupPipelineSurface();
}
void CanvasContext::setupPipelineSurface() {
bool hasSurface = mRenderPipeline->setSurface(
mNativeSurface ? mNativeSurface->getNativeWindow() : nullptr, mSwapBehavior);
@@ -184,7 +187,7 @@ void CanvasContext::setSurface(ANativeWindow* window, bool enableTimeout) {
mFrameNumber = -1;
if (window != nullptr && hasSurface) {
if (mNativeSurface != nullptr && hasSurface) {
mHaveNewSurface = true;
mSwapHistory.clear();
// Enable frame stats after the surface has been bound to the appropriate graphics API.
@@ -239,9 +242,9 @@ void CanvasContext::setOpaque(bool opaque) {
mOpaque = opaque;
}
void CanvasContext::setWideGamut(bool wideGamut) {
ColorMode colorMode = wideGamut ? ColorMode::WideColorGamut : ColorMode::SRGB;
mRenderPipeline->setSurfaceColorProperties(colorMode);
void CanvasContext::setColorMode(ColorMode mode) {
mRenderPipeline->setSurfaceColorProperties(mode);
setupPipelineSurface();
}
bool CanvasContext::makeCurrent() {

View File

@@ -30,6 +30,7 @@
#include "renderthread/RenderTask.h"
#include "renderthread/RenderThread.h"
#include "utils/RingBuffer.h"
#include "ColorMode.h"
#include <SkBitmap.h>
#include <SkRect.h>
@@ -119,7 +120,7 @@ public:
void setLightAlpha(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
void setLightGeometry(const Vector3& lightCenter, float lightRadius);
void setOpaque(bool opaque);
void setWideGamut(bool wideGamut);
void setColorMode(ColorMode mode);
bool makeCurrent();
void prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued, RenderNode* target);
void draw();
@@ -211,6 +212,7 @@ private:
bool isSwapChainStuffed();
bool surfaceRequiresRedraw();
void setPresentTime();
void setupPipelineSurface();
SkRect computeDirtyRect(const Frame& frame, SkRect* dirty);

View File

@@ -76,6 +76,7 @@ static struct {
bool glColorSpace = false;
bool scRGB = false;
bool displayP3 = false;
bool hdr = false;
bool contextPriority = false;
bool surfacelessContext = false;
bool nativeFenceSync = false;
@@ -86,7 +87,8 @@ static struct {
EglManager::EglManager()
: mEglDisplay(EGL_NO_DISPLAY)
, mEglConfig(nullptr)
, mEglConfigWideGamut(nullptr)
, mEglConfigF16(nullptr)
, mEglConfig1010102(nullptr)
, mEglContext(EGL_NO_CONTEXT)
, mPBufferSurface(EGL_NO_SURFACE)
, mCurrentSurface(EGL_NO_SURFACE)
@@ -143,8 +145,7 @@ void EglManager::initialize() {
} else {
LOG_ALWAYS_FATAL("Unsupported wide color space.");
}
mHasWideColorGamutSupport = EglExtensions.glColorSpace && hasWideColorSpaceExtension &&
mEglConfigWideGamut != EGL_NO_CONFIG_KHR;
mHasWideColorGamutSupport = EglExtensions.glColorSpace && hasWideColorSpaceExtension;
}
EGLConfig EglManager::load8BitsConfig(EGLDisplay display, EglManager::SwapBehavior swapBehavior) {
@@ -177,6 +178,35 @@ EGLConfig EglManager::load8BitsConfig(EGLDisplay display, EglManager::SwapBehavi
return config;
}
EGLConfig EglManager::load1010102Config(EGLDisplay display, SwapBehavior swapBehavior) {
EGLint eglSwapBehavior =
(swapBehavior == SwapBehavior::Preserved) ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
// If we reached this point, we have a valid swap behavior
EGLint attribs[] = {EGL_RENDERABLE_TYPE,
EGL_OPENGL_ES2_BIT,
EGL_RED_SIZE,
10,
EGL_GREEN_SIZE,
10,
EGL_BLUE_SIZE,
10,
EGL_ALPHA_SIZE,
2,
EGL_DEPTH_SIZE,
0,
EGL_STENCIL_SIZE,
STENCIL_BUFFER_SIZE,
EGL_SURFACE_TYPE,
EGL_WINDOW_BIT | eglSwapBehavior,
EGL_NONE};
EGLConfig config = EGL_NO_CONFIG_KHR;
EGLint numConfigs = 1;
if (!eglChooseConfig(display, attribs, &config, numConfigs, &numConfigs) || numConfigs != 1) {
return EGL_NO_CONFIG_KHR;
}
return config;
}
EGLConfig EglManager::loadFP16Config(EGLDisplay display, SwapBehavior swapBehavior) {
EGLint eglSwapBehavior =
(swapBehavior == SwapBehavior::Preserved) ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
@@ -230,6 +260,7 @@ void EglManager::initExtensions() {
EglExtensions.pixelFormatFloat = extensions.has("EGL_EXT_pixel_format_float");
EglExtensions.scRGB = extensions.has("EGL_EXT_gl_colorspace_scrgb");
EglExtensions.displayP3 = extensions.has("EGL_EXT_gl_colorspace_display_p3_passthrough");
EglExtensions.hdr = extensions.has("EGL_EXT_gl_colorspace_bt2020_pq");
EglExtensions.contextPriority = extensions.has("EGL_IMG_context_priority");
EglExtensions.surfacelessContext = extensions.has("EGL_KHR_surfaceless_context");
EglExtensions.fenceSync = extensions.has("EGL_KHR_fence_sync");
@@ -260,18 +291,20 @@ void EglManager::loadConfigs() {
LOG_ALWAYS_FATAL("Failed to choose config, error = %s", eglErrorString());
}
}
SkColorType wideColorType = DeviceInfo::get()->getWideColorType();
// When we reach this point, we have a valid swap behavior
if (wideColorType == SkColorType::kRGBA_F16_SkColorType && EglExtensions.pixelFormatFloat) {
mEglConfigWideGamut = loadFP16Config(mEglDisplay, mSwapBehavior);
if (mEglConfigWideGamut == EGL_NO_CONFIG_KHR) {
if (EglExtensions.pixelFormatFloat) {
mEglConfigF16 = loadFP16Config(mEglDisplay, mSwapBehavior);
if (mEglConfigF16 == EGL_NO_CONFIG_KHR) {
ALOGE("Device claims wide gamut support, cannot find matching config, error = %s",
eglErrorString());
EglExtensions.pixelFormatFloat = false;
}
} else if (wideColorType == SkColorType::kN32_SkColorType) {
mEglConfigWideGamut = load8BitsConfig(mEglDisplay, mSwapBehavior);
}
mEglConfig1010102 = load1010102Config(mEglDisplay, mSwapBehavior);
if (mEglConfig1010102 == EGL_NO_CONFIG_KHR) {
ALOGW("Failed to initialize 101010-2 format, error = %s",
eglErrorString());
}
}
@@ -311,8 +344,9 @@ Result<EGLSurface, EGLint> EglManager::createSurface(EGLNativeWindowType window,
sk_sp<SkColorSpace> colorSpace) {
LOG_ALWAYS_FATAL_IF(!hasEglContext(), "Not initialized");
bool wideColorGamut = colorMode == ColorMode::WideColorGamut && mHasWideColorGamutSupport &&
EglExtensions.noConfigContext;
if (!mHasWideColorGamutSupport || !EglExtensions.noConfigContext) {
colorMode = ColorMode::Default;
}
// The color space we want to use depends on whether linear blending is turned
// on and whether the app has requested wide color gamut rendering. When wide
@@ -338,26 +372,47 @@ Result<EGLSurface, EGLint> EglManager::createSurface(EGLNativeWindowType window,
// list is considered empty if the first entry is EGL_NONE
EGLint attribs[] = {EGL_NONE, EGL_NONE, EGL_NONE};
EGLConfig config = mEglConfig;
if (DeviceInfo::get()->getWideColorType() == kRGBA_F16_SkColorType) {
if (mEglConfigF16 == EGL_NO_CONFIG_KHR) {
colorMode = ColorMode::Default;
} else {
config = mEglConfigF16;
}
}
if (EglExtensions.glColorSpace) {
attribs[0] = EGL_GL_COLORSPACE_KHR;
if (wideColorGamut) {
skcms_Matrix3x3 colorGamut;
LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&colorGamut),
"Could not get gamut matrix from color space");
if (memcmp(&colorGamut, &SkNamedGamut::kDisplayP3, sizeof(colorGamut)) == 0) {
attribs[1] = EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT;
} else if (memcmp(&colorGamut, &SkNamedGamut::kSRGB, sizeof(colorGamut)) == 0) {
attribs[1] = EGL_GL_COLORSPACE_SCRGB_EXT;
} else {
LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
switch (colorMode) {
case ColorMode::Default:
attribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR;
break;
case ColorMode::WideColorGamut: {
skcms_Matrix3x3 colorGamut;
LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&colorGamut),
"Could not get gamut matrix from color space");
if (memcmp(&colorGamut, &SkNamedGamut::kDisplayP3, sizeof(colorGamut)) == 0) {
attribs[1] = EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT;
} else if (memcmp(&colorGamut, &SkNamedGamut::kSRGB, sizeof(colorGamut)) == 0) {
attribs[1] = EGL_GL_COLORSPACE_SCRGB_EXT;
} else if (memcmp(&colorGamut, &SkNamedGamut::kRec2020, sizeof(colorGamut)) == 0) {
attribs[1] = EGL_GL_COLORSPACE_BT2020_PQ_EXT;
} else {
LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
}
break;
}
} else {
attribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR;
case ColorMode::Hdr:
config = mEglConfigF16;
attribs[1] = EGL_GL_COLORSPACE_BT2020_PQ_EXT;
break;
case ColorMode::Hdr10:
config = mEglConfig1010102;
attribs[1] = EGL_GL_COLORSPACE_BT2020_PQ_EXT;
break;
}
}
EGLSurface surface = eglCreateWindowSurface(
mEglDisplay, wideColorGamut ? mEglConfigWideGamut : mEglConfig, window, attribs);
EGLSurface surface = eglCreateWindowSurface(mEglDisplay, config, window, attribs);
if (surface == EGL_NO_SURFACE) {
return Error<EGLint>{eglGetError()};
}

View File

@@ -88,6 +88,7 @@ private:
static EGLConfig load8BitsConfig(EGLDisplay display, SwapBehavior swapBehavior);
static EGLConfig loadFP16Config(EGLDisplay display, SwapBehavior swapBehavior);
static EGLConfig load1010102Config(EGLDisplay display, SwapBehavior swapBehavior);
void initExtensions();
void createPBufferSurface();
@@ -97,7 +98,8 @@ private:
EGLDisplay mEglDisplay;
EGLConfig mEglConfig;
EGLConfig mEglConfigWideGamut;
EGLConfig mEglConfigF16;
EGLConfig mEglConfig1010102;
EGLContext mEglContext;
EGLSurface mPBufferSurface;
EGLSurface mCurrentSurface;

View File

@@ -22,6 +22,7 @@
#include "Lighting.h"
#include "SwapBehavior.h"
#include "hwui/Bitmap.h"
#include "ColorMode.h"
#include <SkRect.h>
#include <utils/RefBase.h>
@@ -42,16 +43,6 @@ namespace renderthread {
enum class MakeCurrentResult { AlreadyCurrent, Failed, Succeeded };
enum class ColorMode {
// SRGB means HWUI will produce buffer in SRGB color space.
SRGB,
// WideColorGamut means HWUI would support rendering scRGB non-linear into
// a signed buffer with enough range to support the wide color gamut of the
// display.
WideColorGamut,
// Hdr
};
class Frame;
class IRenderPipeline {

View File

@@ -109,8 +109,8 @@ void RenderProxy::setOpaque(bool opaque) {
mRenderThread.queue().post([=]() { mContext->setOpaque(opaque); });
}
void RenderProxy::setWideGamut(bool wideGamut) {
mRenderThread.queue().post([=]() { mContext->setWideGamut(wideGamut); });
void RenderProxy::setColorMode(ColorMode mode) {
mRenderThread.queue().post([=]() { mContext->setColorMode(mode); });
}
int64_t* RenderProxy::frameInfo() {

View File

@@ -24,6 +24,7 @@
#include "../FrameMetricsObserver.h"
#include "../IContextFactory.h"
#include "ColorMode.h"
#include "DrawFrameTask.h"
#include "SwapBehavior.h"
#include "hwui/Bitmap.h"
@@ -77,7 +78,7 @@ public:
void setLightAlpha(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
void setLightGeometry(const Vector3& lightCenter, float lightRadius);
void setOpaque(bool opaque);
void setWideGamut(bool wideGamut);
void setColorMode(ColorMode mode);
int64_t* frameInfo();
int syncAndDrawFrame();
void destroy();

View File

@@ -344,5 +344,27 @@ SkColor LabToSRGB(const Lab& lab, SkAlpha alpha) {
static_cast<uint8_t>(rgb.b * 255));
}
// Note that SkColorSpace doesn't have the notion of an unspecified SDR white
// level.
static constexpr float kDefaultSDRWhiteLevel = 150.f;
skcms_TransferFunction GetPQSkTransferFunction(float sdr_white_level) {
if (sdr_white_level <= 0.f) {
sdr_white_level = kDefaultSDRWhiteLevel;
}
// The generic PQ transfer function produces normalized luminance values i.e.
// the range 0-1 represents 0-10000 nits for the reference display, but we
// want to map 1.0 to |sdr_white_level| nits so we need to scale accordingly.
const double w = 10000. / sdr_white_level;
// Distribute scaling factor W by scaling A and B with X ^ (1/F):
// ((A + Bx^C) / (D + Ex^C))^F * W = ((A + Bx^C) / (D + Ex^C) * W^(1/F))^F
// See https://crbug.com/1058580#c32 for discussion.
skcms_TransferFunction fn = SkNamedTransferFn::kPQ;
const double ws = pow(w, 1. / fn.f);
fn.a = ws * fn.a;
fn.b = ws * fn.b;
return fn;
}
} // namespace uirenderer
} // namespace android

View File

@@ -126,6 +126,7 @@ struct Lab {
Lab sRGBToLab(SkColor color);
SkColor LabToSRGB(const Lab& lab, SkAlpha alpha);
skcms_TransferFunction GetPQSkTransferFunction(float sdr_white_level = 0.f);
} /* namespace uirenderer */
} /* namespace android */