Add extended brightness plumbing to VRI

Test: manual, builds & boots
Bug: 266628247
Change-Id: I6310883f3d10bb3eefa3cc189938b6c2c1a14544
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 8dea684..0cc68cc 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -299,9 +299,40 @@
     mOpaque = opaque;
 }
 
-void CanvasContext::setColorMode(ColorMode mode) {
-    mRenderPipeline->setSurfaceColorProperties(mode);
-    setupPipelineSurface();
+float CanvasContext::setColorMode(ColorMode mode) {
+    if (mode != mColorMode) {
+        if (mode == ColorMode::Hdr && !mRenderPipeline->supportsExtendedRangeHdr()) {
+            mode = ColorMode::WideColorGamut;
+        }
+        mColorMode = mode;
+        mRenderPipeline->setSurfaceColorProperties(mode);
+        setupPipelineSurface();
+    }
+    switch (mColorMode) {
+        case ColorMode::Hdr:
+            return 3.f;  // TODO: Refine this number
+        default:
+            return 1.f;
+    }
+}
+
+float CanvasContext::targetSdrHdrRatio() const {
+    if (mColorMode == ColorMode::Hdr) {
+        return mTargetSdrHdrRatio;
+    } else {
+        return 1.f;
+    }
+}
+
+void CanvasContext::setTargetSdrHdrRatio(float ratio) {
+    if (mTargetSdrHdrRatio == ratio) return;
+
+    mTargetSdrHdrRatio = ratio;
+    mRenderPipeline->setTargetSdrHdrRatio(ratio);
+    // We don't actually but we need to behave as if we do. Specifically we need to ensure
+    // all buffers in the swapchain are fully re-rendered as any partial updates to them will
+    // result in mixed target white points which looks really bad & flickery
+    mHaveNewSurface = true;
 }
 
 bool CanvasContext::makeCurrent() {
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index a274d2f..a811670 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -137,7 +137,9 @@
     void setLightAlpha(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
     void setLightGeometry(const Vector3& lightCenter, float lightRadius);
     void setOpaque(bool opaque);
-    void setColorMode(ColorMode mode);
+    float setColorMode(ColorMode mode);
+    float targetSdrHdrRatio() const;
+    void setTargetSdrHdrRatio(float ratio);
     bool makeCurrent();
     void prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued, RenderNode* target);
     // Returns the DequeueBufferDuration.
@@ -352,6 +354,9 @@
     nsecs_t mLastDequeueBufferDuration = 0;
     nsecs_t mSyncDelayDuration = 0;
     nsecs_t mIdleDuration = 0;
+
+    ColorMode mColorMode = ColorMode::Default;
+    float mTargetSdrHdrRatio = 1.f;
 };
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index b06c5dd..fab2f46 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -91,6 +91,7 @@
     ATRACE_FORMAT("DrawFrames %" PRId64, vsyncId);
 
     mContext->setSyncDelayDuration(systemTime(SYSTEM_TIME_MONOTONIC) - mSyncQueued);
+    mContext->setTargetSdrHdrRatio(mRenderSdrHdrRatio);
 
     auto hardwareBufferParams = mHardwareBufferParams;
     mContext->setHardwareBufferRenderParams(hardwareBufferParams);
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index c5c5fe2..4130d4a 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -100,6 +100,8 @@
         mHardwareBufferParams = params;
     }
 
+    void setRenderSdrHdrRatio(float ratio) { mRenderSdrHdrRatio = ratio; }
+
 private:
     void postAndWait();
     bool syncFrameState(TreeInfo& info);
@@ -112,6 +114,7 @@
     CanvasContext* mContext;
     RenderNode* mTargetNode = nullptr;
     Rect mContentDrawBounds;
+    float mRenderSdrHdrRatio = 1.f;
 
     /*********************************************
      *  Single frame data
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 02257db..5b7cf75 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -450,6 +450,11 @@
                 case ColorMode::Default:
                     attribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR;
                     break;
+                // Extended Range HDR requires being able to manipulate the dataspace in ways
+                // we cannot easily do while going through EGLSurface. Given this requires
+                // composer3 support, just treat HDR as equivalent to wide color gamut if
+                // the GLES path is still being hit
+                case ColorMode::Hdr:
                 case ColorMode::WideColorGamut: {
                     skcms_Matrix3x3 colorGamut;
                     LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&colorGamut),
@@ -466,14 +471,6 @@
                     }
                     break;
                 }
-                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;
                 case ColorMode::A8:
                     LOG_ALWAYS_FATAL("Unreachable: A8 doesn't use a color space");
                     break;
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index 715c17d..c68fcdf 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -95,6 +95,9 @@
     virtual void setPictureCapturedCallback(
             const std::function<void(sk_sp<SkPicture>&&)>& callback) = 0;
 
+    virtual bool supportsExtendedRangeHdr() const { return false; }
+    virtual void setTargetSdrHdrRatio(float ratio) = 0;
+
     virtual ~IRenderPipeline() {}
 };
 
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 5edb0b1..1e011c2 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -143,8 +143,20 @@
     mRenderThread.queue().post([=]() { mContext->setOpaque(opaque); });
 }
 
-void RenderProxy::setColorMode(ColorMode mode) {
-    mRenderThread.queue().post([=]() { mContext->setColorMode(mode); });
+float RenderProxy::setColorMode(ColorMode mode) {
+    // We only need to figure out what the renderer supports for HDR, otherwise this can stay
+    // an async call since we already know the return value
+    if (mode == ColorMode::Hdr) {
+        return mRenderThread.queue().runSync(
+                [=]() -> float { return mContext->setColorMode(mode); });
+    } else {
+        mRenderThread.queue().post([=]() { mContext->setColorMode(mode); });
+        return 1.f;
+    }
+}
+
+void RenderProxy::setRenderSdrHdrRatio(float ratio) {
+    mDrawFrameTask.setRenderSdrHdrRatio(ratio);
 }
 
 int64_t* RenderProxy::frameInfo() {
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 2aafe76..82072a6 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -87,7 +87,8 @@
     void setLightGeometry(const Vector3& lightCenter, float lightRadius);
     void setHardwareBufferRenderParams(const HardwareBufferRenderParams& params);
     void setOpaque(bool opaque);
-    void setColorMode(ColorMode mode);
+    float setColorMode(ColorMode mode);
+    void setRenderSdrHdrRatio(float ratio);
     int64_t* frameInfo();
     void forceDrawNextFrame();
     int syncAndDrawFrame();
diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp
index 7dd3561..2efa5d6 100644
--- a/libs/hwui/renderthread/VulkanSurface.cpp
+++ b/libs/hwui/renderthread/VulkanSurface.cpp
@@ -199,7 +199,14 @@
 
     outWindowInfo->bufferFormat = ColorTypeToBufferFormat(colorType);
     outWindowInfo->colorspace = colorSpace;
-    outWindowInfo->dataspace = ColorSpaceToADataSpace(colorSpace.get(), colorType);
+    outWindowInfo->colorMode = colorMode;
+
+    if (colorMode == ColorMode::Hdr) {
+        outWindowInfo->dataspace =
+                static_cast<android_dataspace>(STANDARD_DCI_P3 | TRANSFER_SRGB | RANGE_EXTENDED);
+    } else {
+        outWindowInfo->dataspace = ColorSpaceToADataSpace(colorSpace.get(), colorType);
+    }
     LOG_ALWAYS_FATAL_IF(
             outWindowInfo->dataspace == HAL_DATASPACE_UNKNOWN && colorType != kAlpha_8_SkColorType,
             "Unsupported colorspace");
@@ -496,6 +503,33 @@
     return currentBuffer.hasValidContents ? (mPresentCount - currentBuffer.lastPresentedCount) : 0;
 }
 
+void VulkanSurface::setColorSpace(sk_sp<SkColorSpace> colorSpace) {
+    mWindowInfo.colorspace = std::move(colorSpace);
+    for (int i = 0; i < kNumBufferSlots; i++) {
+        mNativeBuffers[i].skSurface.reset();
+    }
+
+    if (mWindowInfo.colorMode == ColorMode::Hdr) {
+        mWindowInfo.dataspace =
+                static_cast<android_dataspace>(STANDARD_DCI_P3 | TRANSFER_SRGB | RANGE_EXTENDED);
+    } else {
+        mWindowInfo.dataspace = ColorSpaceToADataSpace(
+                mWindowInfo.colorspace.get(), BufferFormatToColorType(mWindowInfo.bufferFormat));
+    }
+    LOG_ALWAYS_FATAL_IF(mWindowInfo.dataspace == HAL_DATASPACE_UNKNOWN &&
+                                mWindowInfo.bufferFormat != AHARDWAREBUFFER_FORMAT_R8_UNORM,
+                        "Unsupported colorspace");
+
+    if (mNativeWindow) {
+        int err = native_window_set_buffers_data_space(mNativeWindow.get(), mWindowInfo.dataspace);
+        if (err != 0) {
+            ALOGE("VulkanSurface::setColorSpace() native_window_set_buffers_data_space(%d) "
+                  "failed: %s (%d)",
+                  mWindowInfo.dataspace, strerror(-err), err);
+        }
+    }
+}
+
 } /* namespace renderthread */
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/renderthread/VulkanSurface.h b/libs/hwui/renderthread/VulkanSurface.h
index 2648666..e2ddc6b 100644
--- a/libs/hwui/renderthread/VulkanSurface.h
+++ b/libs/hwui/renderthread/VulkanSurface.h
@@ -46,6 +46,8 @@
     }
     const SkMatrix& getCurrentPreTransform() { return mWindowInfo.preTransform; }
 
+    void setColorSpace(sk_sp<SkColorSpace> colorSpace);
+
 private:
     /*
      * All structs/methods in this private section are specifically for use by the VulkanManager
@@ -94,6 +96,7 @@
         uint32_t bufferFormat;
         android_dataspace dataspace;
         sk_sp<SkColorSpace> colorspace;
+        ColorMode colorMode;
         int transform;
         size_t bufferCount;
         uint64_t windowUsageFlags;