diff options
Diffstat (limited to 'libs')
34 files changed, 288 insertions, 108 deletions
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SettingsSidecarImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SettingsSidecarImpl.java index 92e575804bbe..ca3a5112bc55 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SettingsSidecarImpl.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SettingsSidecarImpl.java @@ -192,7 +192,7 @@ class SettingsSidecarImpl extends StubSidecar { Rect featureRect = new Rect(left, top, right, bottom); rotateRectToDisplayRotation(featureRect, displayId); transformToWindowSpaceRect(featureRect, windowToken); - if (!featureRect.isEmpty()) { + if (isNotZero(featureRect)) { SidecarDisplayFeature feature = new SidecarDisplayFeature(); feature.setRect(featureRect); feature.setType(type); @@ -207,6 +207,10 @@ class SettingsSidecarImpl extends StubSidecar { return features; } + private static boolean isNotZero(Rect rect) { + return rect.height() > 0 || rect.width() > 0; + } + @Override protected void onListenersChanged() { if (mSettingsObserver == null) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java index 338ece5afbc2..aeda2d923490 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java @@ -68,12 +68,15 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged private final SparseArray<PerDisplay> mImePerDisplay = new SparseArray<>(); private final ArrayList<ImePositionProcessor> mPositionProcessors = new ArrayList<>(); - public DisplayImeController(IWindowManager wmService, DisplayController displayController, + protected DisplayImeController(IWindowManager wmService, DisplayController displayController, Handler mainHandler, TransactionPool transactionPool) { mHandler = mainHandler; mWmService = wmService; mTransactionPool = transactionPool; mDisplayController = displayController; + } + + protected void startMonitorDisplays() { mDisplayController.addDisplayWindowListener(this); } @@ -490,4 +493,29 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged return IInputMethodManager.Stub.asInterface( ServiceManager.getService(Context.INPUT_METHOD_SERVICE)); } + + /** Builds {@link DisplayImeController} instance. */ + public static class Builder { + private IWindowManager mWmService; + private DisplayController mDisplayController; + private Handler mHandler; + private TransactionPool mTransactionPool; + + public Builder(IWindowManager wmService, DisplayController displayController, + Handler handler, TransactionPool transactionPool) { + mWmService = wmService; + mDisplayController = displayController; + mHandler = handler; + mTransactionPool = transactionPool; + } + + /** Builds and initializes {@link DisplayImeController} instance. */ + public DisplayImeController build() { + DisplayImeController displayImeController = new DisplayImeController(mWmService, + mDisplayController, mHandler, mTransactionPool); + // Separates startMonitorDisplays from constructor to prevent circular init issue. + displayImeController.startMonitorDisplays(); + return displayImeController; + } + } } diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp index 3893041b05d9..8ab7da5257ab 100644 --- a/libs/androidfw/Android.bp +++ b/libs/androidfw/Android.bp @@ -101,7 +101,7 @@ cc_library { }, }, sanitize: { - blacklist: "libandroidfw_blacklist.txt", + blocklist: "libandroidfw_blocklist.txt", }, } diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h index e351a46d633a..e10a7f3f5c61 100644 --- a/libs/androidfw/include/androidfw/ResourceTypes.h +++ b/libs/androidfw/include/androidfw/ResourceTypes.h @@ -1717,6 +1717,10 @@ struct ResTable_overlayable_policy_header // The overlay must be signed with the same signature as the actor declared for the target // resource ACTOR_SIGNATURE = 0x00000080, + + // The overlay must be signed with the same signature as the reference package declared + // in the SystemConfig + CONFIG_SIGNATURE = 0x00000100, }; using PolicyBitmask = uint32_t; diff --git a/libs/androidfw/libandroidfw_blacklist.txt b/libs/androidfw/libandroidfw_blocklist.txt index dd17e4d5b1e8..dd17e4d5b1e8 100644 --- a/libs/androidfw/libandroidfw_blacklist.txt +++ b/libs/androidfw/libandroidfw_blocklist.txt diff --git a/libs/hwui/AutoBackendTextureRelease.cpp b/libs/hwui/AutoBackendTextureRelease.cpp index 72747e8fa543..33264d5d5c86 100644 --- a/libs/hwui/AutoBackendTextureRelease.cpp +++ b/libs/hwui/AutoBackendTextureRelease.cpp @@ -25,7 +25,8 @@ using namespace android::uirenderer::renderthread; namespace android { namespace uirenderer { -AutoBackendTextureRelease::AutoBackendTextureRelease(GrContext* context, AHardwareBuffer* buffer) { +AutoBackendTextureRelease::AutoBackendTextureRelease(GrDirectContext* context, + AHardwareBuffer* buffer) { AHardwareBuffer_Desc desc; AHardwareBuffer_describe(buffer, &desc); bool createProtectedImage = 0 != (desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT); @@ -67,8 +68,9 @@ static void releaseProc(SkImage::ReleaseContext releaseContext) { textureRelease->unref(false); } -void AutoBackendTextureRelease::makeImage(AHardwareBuffer* buffer, android_dataspace dataspace, - GrContext* context) { +void AutoBackendTextureRelease::makeImage(AHardwareBuffer* buffer, + android_dataspace dataspace, + GrDirectContext* context) { AHardwareBuffer_Desc desc; AHardwareBuffer_describe(buffer, &desc); SkColorType colorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(desc.format); @@ -81,7 +83,7 @@ void AutoBackendTextureRelease::makeImage(AHardwareBuffer* buffer, android_datas } } -void AutoBackendTextureRelease::newBufferContent(GrContext* context) { +void AutoBackendTextureRelease::newBufferContent(GrDirectContext* context) { if (mBackendTexture.isValid()) { mUpdateProc(mImageCtx, context); } diff --git a/libs/hwui/AutoBackendTextureRelease.h b/libs/hwui/AutoBackendTextureRelease.h index acdd63cb7921..06f51fcd1105 100644 --- a/libs/hwui/AutoBackendTextureRelease.h +++ b/libs/hwui/AutoBackendTextureRelease.h @@ -31,7 +31,8 @@ namespace uirenderer { */ class AutoBackendTextureRelease final { public: - AutoBackendTextureRelease(GrContext* context, AHardwareBuffer* buffer); + AutoBackendTextureRelease(GrDirectContext* context, + AHardwareBuffer* buffer); const GrBackendTexture& getTexture() const { return mBackendTexture; } @@ -42,9 +43,11 @@ public: inline sk_sp<SkImage> getImage() const { return mImage; } - void makeImage(AHardwareBuffer* buffer, android_dataspace dataspace, GrContext* context); + void makeImage(AHardwareBuffer* buffer, + android_dataspace dataspace, + GrDirectContext* context); - void newBufferContent(GrContext* context); + void newBufferContent(GrDirectContext* context); private: // The only way to invoke dtor is with unref, when mUsageCount is 0. diff --git a/libs/hwui/ColorMode.h b/libs/hwui/ColorMode.h new file mode 100644 index 000000000000..6d387f9ef43d --- /dev/null +++ b/libs/hwui/ColorMode.h @@ -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 diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp index 67d8c07e61de..6589dbd50cf7 100644 --- a/libs/hwui/DeferredLayerUpdater.cpp +++ b/libs/hwui/DeferredLayerUpdater.cpp @@ -189,7 +189,7 @@ void DeferredLayerUpdater::detachSurfaceTexture() { sk_sp<SkImage> DeferredLayerUpdater::ImageSlot::createIfNeeded(AHardwareBuffer* buffer, android_dataspace dataspace, bool forceCreate, - GrContext* context) { + GrDirectContext* context) { if (!mTextureRelease || !mTextureRelease->getImage().get() || dataspace != mDataspace || forceCreate || mBuffer != buffer) { if (buffer != mBuffer) { diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h index 05f3774d6951..6731e9c428d6 100644 --- a/libs/hwui/DeferredLayerUpdater.h +++ b/libs/hwui/DeferredLayerUpdater.h @@ -106,7 +106,7 @@ private: ~ImageSlot() { clear(); } sk_sp<SkImage> createIfNeeded(AHardwareBuffer* buffer, android_dataspace dataspace, - bool forceCreate, GrContext* context); + bool forceCreate, GrDirectContext* context); private: void clear(); diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp index c2d2ff874816..87244427a719 100644 --- a/libs/hwui/HardwareBitmapUploader.cpp +++ b/libs/hwui/HardwareBitmapUploader.cpp @@ -21,7 +21,7 @@ #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> #include <GLES3/gl3.h> -#include <GrContext.h> +#include <GrDirectContext.h> #include <SkCanvas.h> #include <SkImage.h> #include <utils/GLUtils.h> @@ -285,7 +285,7 @@ private: return (image.get() != nullptr); } - sk_sp<GrContext> mGrContext; + sk_sp<GrDirectContext> mGrContext; renderthread::VulkanManager mVulkanManager; std::mutex mVkLock; }; diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp index 0dea354b7200..b71bb07dbc86 100644 --- a/libs/hwui/Readback.cpp +++ b/libs/hwui/Readback.cpp @@ -118,7 +118,7 @@ CopyResult Readback::copyImageInto(const sk_sp<SkImage>& image, Matrix4& texTran } int imgWidth = image->width(); int imgHeight = image->height(); - sk_sp<GrContext> grContext = sk_ref_sp(mRenderThread.getGrContext()); + sk_sp<GrDirectContext> grContext = sk_ref_sp(mRenderThread.getGrContext()); if (bitmap->colorType() == kRGBA_F16_SkColorType && !grContext->colorTypeSupportedAsSurface(bitmap->colorType())) { diff --git a/libs/hwui/apex/jni_runtime.cpp b/libs/hwui/apex/jni_runtime.cpp index b933813550d4..12e2e8135278 100644 --- a/libs/hwui/apex/jni_runtime.cpp +++ b/libs/hwui/apex/jni_runtime.cpp @@ -16,14 +16,14 @@ #include "android/graphics/jni_runtime.h" -#include <android/log.h> -#include <nativehelper/JNIHelp.h> -#include <sys/cdefs.h> - #include <EGL/egl.h> #include <GraphicsJNI.h> #include <Properties.h> #include <SkGraphics.h> +#include <android/log.h> +#include <nativehelper/JNIHelp.h> +#include <sys/cdefs.h> +#include <vulkan/vulkan.h> #undef LOG_TAG #define LOG_TAG "AndroidGraphicsJNI" @@ -172,6 +172,11 @@ using android::uirenderer::RenderPipelineType; void zygote_preload_graphics() { if (Properties::peekRenderPipelineType() == RenderPipelineType::SkiaGL) { + // Preload GL driver if HWUI renders with GL backend. eglGetDisplay(EGL_DEFAULT_DISPLAY); + } else { + // Preload Vulkan driver if HWUI renders with Vulkan backend. + uint32_t apiVersion; + vkEnumerateInstanceVersion(&apiVersion); } -}
\ No newline at end of file +} diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp index 42743db3061c..7d6875f59d17 100644 --- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp +++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp @@ -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", diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp index 14a297f785fc..dd0fc695c246 100644 --- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp +++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp @@ -15,7 +15,7 @@ */ #include "GLFunctorDrawable.h" -#include <GrContext.h> +#include <GrDirectContext.h> #include <private/hwui/DrawGlInfo.h> #include "FunctorDrawable.h" #include "GrBackendSurface.h" diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp index f839213e9007..f95f347cffaf 100644 --- a/libs/hwui/pipeline/skia/LayerDrawable.cpp +++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp @@ -29,7 +29,7 @@ namespace skiapipeline { void LayerDrawable::onDraw(SkCanvas* canvas) { Layer* layer = mLayerUpdater->backingLayer(); if (layer) { - DrawLayer(canvas->getGrContext(), canvas, layer, nullptr, nullptr, true); + DrawLayer(canvas->recordingContext(), canvas, layer, nullptr, nullptr, true); } } @@ -67,8 +67,12 @@ static bool shouldFilterRect(const SkMatrix& matrix, const SkRect& srcRect, cons isIntegerAligned(dstDevRect.y())); } -bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer, - const SkRect* srcRect, const SkRect* dstRect, +// TODO: Context arg probably doesn't belong here – do debug check at callsite instead. +bool LayerDrawable::DrawLayer(GrRecordingContext* context, + SkCanvas* canvas, + Layer* layer, + const SkRect* srcRect, + const SkRect* dstRect, bool useLayerTransform) { if (context == nullptr) { SkDEBUGF(("Attempting to draw LayerDrawable into an unsupported surface")); diff --git a/libs/hwui/pipeline/skia/LayerDrawable.h b/libs/hwui/pipeline/skia/LayerDrawable.h index 7cd515ae9fcb..ffbb480023ac 100644 --- a/libs/hwui/pipeline/skia/LayerDrawable.h +++ b/libs/hwui/pipeline/skia/LayerDrawable.h @@ -32,8 +32,12 @@ class LayerDrawable : public SkDrawable { public: explicit LayerDrawable(DeferredLayerUpdater* layerUpdater) : mLayerUpdater(layerUpdater) {} - static bool DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer, const SkRect* srcRect, - const SkRect* dstRect, bool useLayerTransform); + static bool DrawLayer(GrRecordingContext* context, + SkCanvas* canvas, + Layer* layer, + const SkRect* srcRect, + const SkRect* dstRect, + bool useLayerTransform); protected: virtual SkRect onGetBounds() override { diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp index 24a6228242a5..389fe7eed7c7 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp @@ -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."); } diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp index 89a1c713ef62..6dd36981e8aa 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -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; } } diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h index 8341164edc19..100bfb6b159a 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaPipeline.h @@ -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; diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index a362bd220936..13d544c68e95 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -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() { diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 0306eeccc5d4..cba710f01063 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -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); diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp index c7013531c07f..2a8aa8c3e5b7 100644 --- a/libs/hwui/renderthread/EglManager.cpp +++ b/libs/hwui/renderthread/EglManager.cpp @@ -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()}; } diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h index f67fb31db951..69f3ed014c53 100644 --- a/libs/hwui/renderthread/EglManager.h +++ b/libs/hwui/renderthread/EglManager.h @@ -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; diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h index c3c22869a42f..a04738d6a6f0 100644 --- a/libs/hwui/renderthread/IRenderPipeline.h +++ b/libs/hwui/renderthread/IRenderPipeline.h @@ -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 { diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index b764f74bf116..aad0cca80cdc 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -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() { diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index 16eabadc064c..33dabc9895b1 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -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(); diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index 206b58f62ea7..565fb61c8994 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -190,7 +190,7 @@ void RenderThread::requireGlContext() { auto glesVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION)); auto size = glesVersion ? strlen(glesVersion) : -1; cacheManager().configureContext(&options, glesVersion, size); - sk_sp<GrContext> grContext(GrContext::MakeGL(std::move(glInterface), options)); + sk_sp<GrDirectContext> grContext(GrDirectContext::MakeGL(std::move(glInterface), options)); LOG_ALWAYS_FATAL_IF(!grContext.get()); setGrContext(grContext); } @@ -204,7 +204,7 @@ void RenderThread::requireVkContext() { initGrContextOptions(options); auto vkDriverVersion = mVkManager->getDriverVersion(); cacheManager().configureContext(&options, &vkDriverVersion, sizeof(vkDriverVersion)); - sk_sp<GrContext> grContext = mVkManager->createContext(options); + sk_sp<GrDirectContext> grContext = mVkManager->createContext(options); LOG_ALWAYS_FATAL_IF(!grContext.get()); setGrContext(grContext); } @@ -263,7 +263,7 @@ Readback& RenderThread::readback() { return *mReadback; } -void RenderThread::setGrContext(sk_sp<GrContext> context) { +void RenderThread::setGrContext(sk_sp<GrDirectContext> context) { mCacheManager->reset(context); if (mGrContext) { mRenderState->onContextDestroyed(); diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h index 2c295bcd8105..b8ce55650516 100644 --- a/libs/hwui/renderthread/RenderThread.h +++ b/libs/hwui/renderthread/RenderThread.h @@ -17,7 +17,7 @@ #ifndef RENDERTHREAD_H_ #define RENDERTHREAD_H_ -#include <GrContext.h> +#include <GrDirectContext.h> #include <SkBitmap.h> #include <apex/choreographer.h> #include <cutils/compiler.h> @@ -106,8 +106,8 @@ public: ProfileDataContainer& globalProfileData() { return mGlobalProfileData; } Readback& readback(); - GrContext* getGrContext() const { return mGrContext.get(); } - void setGrContext(sk_sp<GrContext> cxt); + GrDirectContext* getGrContext() const { return mGrContext.get(); } + void setGrContext(sk_sp<GrDirectContext> cxt); CacheManager& cacheManager() { return *mCacheManager; } VulkanManager& vulkanManager() { return *mVkManager; } @@ -186,7 +186,7 @@ private: ProfileDataContainer mGlobalProfileData; Readback* mReadback = nullptr; - sk_sp<GrContext> mGrContext; + sk_sp<GrDirectContext> mGrContext; CacheManager* mCacheManager; VulkanManager* mVkManager; }; diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp index 3cb16074dd5e..249936eb485e 100644 --- a/libs/hwui/renderthread/VulkanManager.cpp +++ b/libs/hwui/renderthread/VulkanManager.cpp @@ -20,7 +20,7 @@ #include <EGL/eglext.h> #include <GrBackendSemaphore.h> #include <GrBackendSurface.h> -#include <GrContext.h> +#include <GrDirectContext.h> #include <GrTypes.h> #include <android/sync.h> #include <ui/FatVector.h> @@ -369,7 +369,7 @@ void VulkanManager::initialize() { } } -sk_sp<GrContext> VulkanManager::createContext(const GrContextOptions& options) { +sk_sp<GrDirectContext> VulkanManager::createContext(const GrContextOptions& options) { auto getProc = [](const char* proc_name, VkInstance instance, VkDevice device) { if (device != VK_NULL_HANDLE) { return vkGetDeviceProcAddr(device, proc_name); @@ -388,7 +388,7 @@ sk_sp<GrContext> VulkanManager::createContext(const GrContextOptions& options) { backendContext.fDeviceFeatures2 = &mPhysicalDeviceFeatures2; backendContext.fGetProc = std::move(getProc); - return GrContext::MakeVulkan(backendContext, options); + return GrDirectContext::MakeVulkan(backendContext, options); } VkFunctorInitParams VulkanManager::getVkFunctorInitParams() const { @@ -562,9 +562,11 @@ void VulkanManager::destroySurface(VulkanSurface* surface) { delete surface; } -VulkanSurface* VulkanManager::createSurface(ANativeWindow* window, ColorMode colorMode, +VulkanSurface* VulkanManager::createSurface(ANativeWindow* window, + ColorMode colorMode, sk_sp<SkColorSpace> surfaceColorSpace, - SkColorType surfaceColorType, GrContext* grContext, + SkColorType surfaceColorType, + GrDirectContext* grContext, uint32_t extraBuffers) { LOG_ALWAYS_FATAL_IF(!hasVkContext(), "Not initialized"); if (!window) { @@ -575,7 +577,7 @@ VulkanSurface* VulkanManager::createSurface(ANativeWindow* window, ColorMode col *this, extraBuffers); } -status_t VulkanManager::fenceWait(int fence, GrContext* grContext) { +status_t VulkanManager::fenceWait(int fence, GrDirectContext* grContext) { if (!hasVkContext()) { ALOGE("VulkanManager::fenceWait: VkDevice not initialized"); return INVALID_OPERATION; @@ -623,7 +625,7 @@ status_t VulkanManager::fenceWait(int fence, GrContext* grContext) { return OK; } -status_t VulkanManager::createReleaseFence(int* nativeFence, GrContext* grContext) { +status_t VulkanManager::createReleaseFence(int* nativeFence, GrDirectContext* grContext) { *nativeFence = -1; if (!hasVkContext()) { ALOGE("VulkanManager::createReleaseFence: VkDevice not initialized"); diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h index 8b19f13fdfb9..3f2df8d75d89 100644 --- a/libs/hwui/renderthread/VulkanManager.h +++ b/libs/hwui/renderthread/VulkanManager.h @@ -57,9 +57,11 @@ public: bool hasVkContext() { return mDevice != VK_NULL_HANDLE; } // Create and destroy functions for wrapping an ANativeWindow in a VulkanSurface - VulkanSurface* createSurface(ANativeWindow* window, ColorMode colorMode, + VulkanSurface* createSurface(ANativeWindow* window, + ColorMode colorMode, sk_sp<SkColorSpace> surfaceColorSpace, - SkColorType surfaceColorType, GrContext* grContext, + SkColorType surfaceColorType, + GrDirectContext* grContext, uint32_t extraBuffers); void destroySurface(VulkanSurface* surface); @@ -70,18 +72,18 @@ public: void destroy(); // Inserts a wait on fence command into the Vulkan command buffer. - status_t fenceWait(int fence, GrContext* grContext); + status_t fenceWait(int fence, GrDirectContext* grContext); // Creates a fence that is signaled when all the pending Vulkan commands are finished on the // GPU. - status_t createReleaseFence(int* nativeFence, GrContext* grContext); + status_t createReleaseFence(int* nativeFence, GrDirectContext* grContext); // Returned pointers are owned by VulkanManager. // An instance of VkFunctorInitParams returned from getVkFunctorInitParams refers to // the internal state of VulkanManager: VulkanManager must be alive to use the returned value. VkFunctorInitParams getVkFunctorInitParams() const; - sk_sp<GrContext> createContext(const GrContextOptions& options); + sk_sp<GrDirectContext> createContext(const GrContextOptions& options); uint32_t getDriverVersion() const { return mDriverVersion; } diff --git a/libs/hwui/tests/unit/CacheManagerTests.cpp b/libs/hwui/tests/unit/CacheManagerTests.cpp index a4d7b825520d..edd3e4e4f4d4 100644 --- a/libs/hwui/tests/unit/CacheManagerTests.cpp +++ b/libs/hwui/tests/unit/CacheManagerTests.cpp @@ -26,7 +26,7 @@ using namespace android; using namespace android::uirenderer; using namespace android::uirenderer::renderthread; -static size_t getCacheUsage(GrContext* grContext) { +static size_t getCacheUsage(GrDirectContext* grContext) { size_t cacheUsage; grContext->getResourceCacheUsage(nullptr, &cacheUsage); return cacheUsage; @@ -35,7 +35,7 @@ static size_t getCacheUsage(GrContext* grContext) { RENDERTHREAD_SKIA_PIPELINE_TEST(CacheManager, trimMemory) { int32_t width = DeviceInfo::get()->getWidth(); int32_t height = DeviceInfo::get()->getHeight(); - GrContext* grContext = renderThread.getGrContext(); + GrDirectContext* grContext = renderThread.getGrContext(); ASSERT_TRUE(grContext != nullptr); // create pairs of offscreen render targets and images until we exceed the diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp index ca1bf690cfd0..eff34a83af1b 100644 --- a/libs/hwui/utils/Color.cpp +++ b/libs/hwui/utils/Color.cpp @@ -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 diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h index 71ed68371a9a..1654072fd264 100644 --- a/libs/hwui/utils/Color.h +++ b/libs/hwui/utils/Color.h @@ -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 */ |