surfaceflinger: always advertise HDR10 when wide color is available

For HWC that already adversises HDR10 support, this has no effect.
Otherwise, SurfaceFlinger will insert HDR10 into HdrCapabilities
when wide color is supported.

SurfaceFlinger simulates HDR10 support by switching the color mode
to DISPLAY_P3 and forcing client composition for HDR10 layers.  It
also has a special path to treat RGBA_1010102/BT2020_PQ as
Y410/BT2020_PQ in RenderEngine when the buffer is from media.

Test: manual
Change-Id: Ib5f18e0100f5610ee65218108bdb9843baccbe98
diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp
index f7409dc..f50379b 100644
--- a/libs/gui/BufferItem.cpp
+++ b/libs/gui/BufferItem.cpp
@@ -55,7 +55,8 @@
     mSurfaceDamage(),
     mAutoRefresh(false),
     mQueuedBuffer(true),
-    mIsStale(false) {
+    mIsStale(false),
+    mApi(0) {
 }
 
 BufferItem::~BufferItem() {}
@@ -84,6 +85,7 @@
     addAligned(size, mAutoRefresh);
     addAligned(size, mQueuedBuffer);
     addAligned(size, mIsStale);
+    addAligned(size, mApi);
     return size;
 }
 
@@ -177,6 +179,7 @@
     writeAligned(buffer, size, mAutoRefresh);
     writeAligned(buffer, size, mQueuedBuffer);
     writeAligned(buffer, size, mIsStale);
+    writeAligned(buffer, size, mApi);
 
     return NO_ERROR;
 }
@@ -247,6 +250,7 @@
     readAligned(buffer, size, mAutoRefresh);
     readAligned(buffer, size, mQueuedBuffer);
     readAligned(buffer, size, mIsStale);
+    readAligned(buffer, size, mApi);
 
     return NO_ERROR;
 }
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index add857c..e583b40 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -878,6 +878,7 @@
         item.mSurfaceDamage = surfaceDamage;
         item.mQueuedBuffer = true;
         item.mAutoRefresh = mCore->mSharedBufferMode && mCore->mAutoRefresh;
+        item.mApi = mCore->mConnectedApi;
 
         mStickyTransform = stickyTransform;
 
diff --git a/libs/gui/include/gui/BufferItem.h b/libs/gui/include/gui/BufferItem.h
index 7740b9f..218bb42 100644
--- a/libs/gui/include/gui/BufferItem.h
+++ b/libs/gui/include/gui/BufferItem.h
@@ -127,6 +127,9 @@
     // Indicates that this BufferItem contains a stale buffer which has already
     // been released by the BufferQueue.
     bool mIsStale;
+
+    // Indicates the API (NATIVE_WINDOW_API_xxx) that queues the buffer.
+    int mApi;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index d860f58..ab6a559 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -821,8 +821,17 @@
     engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s), false /* disableTexture */,
                               getColor());
     engine.setSourceDataSpace(mCurrentState.dataSpace);
+
+    if (mCurrentState.dataSpace == HAL_DATASPACE_BT2020_PQ &&
+        mConsumer->getCurrentApi() == NATIVE_WINDOW_API_MEDIA &&
+        getBE().compositionInfo.mBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102) {
+        engine.setSourceY410BT2020(true);
+    }
+
     engine.drawMesh(getBE().mMesh);
     engine.disableBlending();
+
+    engine.setSourceY410BT2020(false);
 }
 
 uint32_t BufferLayer::getProducerStickyTransform() const {
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 8f5c9c7..4d9b43f 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -68,6 +68,7 @@
         mCurrentFrameNumber(0),
         mCurrentTransformToDisplayInverse(false),
         mCurrentSurfaceDamage(),
+        mCurrentApi(0),
         mDefaultWidth(1),
         mDefaultHeight(1),
         mFilteringEnabled(true),
@@ -346,6 +347,7 @@
     mCurrentFrameNumber = item.mFrameNumber;
     mCurrentTransformToDisplayInverse = item.mTransformToDisplayInverse;
     mCurrentSurfaceDamage = item.mSurfaceDamage;
+    mCurrentApi = item.mApi;
 
     computeCurrentTransformMatrixLocked();
 
@@ -469,6 +471,11 @@
     return mCurrentSurfaceDamage;
 }
 
+int BufferLayerConsumer::getCurrentApi() const {
+    Mutex::Autolock lock(mMutex);
+    return mCurrentApi;
+}
+
 sp<GraphicBuffer> BufferLayerConsumer::getCurrentBuffer(int* outSlot) const {
     Mutex::Autolock lock(mMutex);
 
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index f473390..a0272b3 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -138,6 +138,9 @@
     // must be called from SF main thread
     const Region& getSurfaceDamage() const;
 
+    // getCurrentApi retrieves the API which queues the current buffer.
+    int getCurrentApi() const;
+
     // See GLConsumer::setDefaultBufferSize.
     status_t setDefaultBufferSize(uint32_t width, uint32_t height);
 
@@ -337,6 +340,8 @@
     // The portion of this surface that has changed since the previous frame
     Region mCurrentSurfaceDamage;
 
+    int mCurrentApi;
+
     uint32_t mDefaultWidth, mDefaultHeight;
 
     // mFilteringEnabled indicates whether the transform matrix is computed for
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index d121a86..cf70529 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -76,7 +76,8 @@
         const wp<IBinder>& displayToken,
         const sp<DisplaySurface>& displaySurface,
         const sp<IGraphicBufferProducer>& producer,
-        bool supportWideColor)
+        bool supportWideColor,
+        bool supportHdr)
     : lastCompositionHadVisibleLayers(false),
       mFlinger(flinger),
       mType(type),
@@ -100,6 +101,8 @@
 
     mActiveColorMode = HAL_COLOR_MODE_NATIVE;
     mDisplayHasWideColor = supportWideColor;
+    mDisplayHasHdr = supportHdr;
+
     /*
      * Create our display's surface
      */
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 499bf8e..a470670 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -78,7 +78,7 @@
             const wp<IBinder>& displayToken,
             const sp<DisplaySurface>& displaySurface,
             const sp<IGraphicBufferProducer>& producer,
-            bool supportWideColor);
+            bool supportWideColor, bool supportHdr);
     // clang-format on
 
     ~DisplayDevice();
@@ -128,6 +128,7 @@
     status_t beginFrame(bool mustRecompose) const;
     status_t prepareFrame(HWComposer& hwc);
     bool getWideColorSupport() const { return mDisplayHasWideColor; }
+    bool getHdrSupport() const { return mDisplayHasHdr; }
 
     void swapBuffers(HWComposer& hwc) const;
 
@@ -235,6 +236,7 @@
     // Initialized by SurfaceFlinger when the DisplayDevice is created.
     // Fed to RenderEngine during composition.
     bool mDisplayHasWideColor;
+    bool mDisplayHasHdr;
 };
 
 struct DisplayDeviceState {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a91525d..974a261 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1041,7 +1041,19 @@
     std::unique_ptr<HdrCapabilities> capabilities =
             getBE().mHwc->getHdrCapabilities(displayDevice->getHwcDisplayId());
     if (capabilities) {
-        std::swap(*outCapabilities, *capabilities);
+        if (displayDevice->getWideColorSupport() && !displayDevice->getHdrSupport()) {
+            // insert HDR10 as we will force client composition for HDR10
+            // layers
+            std::vector<int32_t> types = capabilities->getSupportedHdrTypes();
+            types.push_back(HAL_HDR_HDR10);
+
+            *outCapabilities = HdrCapabilities(types,
+                    capabilities->getDesiredMaxLuminance(),
+                    capabilities->getDesiredMaxAverageLuminance(),
+                    capabilities->getDesiredMinLuminance());
+        } else {
+            *outCapabilities = std::move(*capabilities);
+        }
     } else {
         return BAD_VALUE;
     }
@@ -1793,7 +1805,7 @@
 }
 
 android_dataspace SurfaceFlinger::bestTargetDataSpace(
-        android_dataspace a, android_dataspace b) const {
+        android_dataspace a, android_dataspace b, bool hasHdr) const {
     // Only support sRGB and Display-P3 right now.
     if (a == HAL_DATASPACE_DISPLAY_P3 || b == HAL_DATASPACE_DISPLAY_P3) {
         return HAL_DATASPACE_DISPLAY_P3;
@@ -1804,6 +1816,9 @@
     if (a == HAL_DATASPACE_V0_SCRGB || b == HAL_DATASPACE_V0_SCRGB) {
         return HAL_DATASPACE_DISPLAY_P3;
     }
+    if (!hasHdr && (a == HAL_DATASPACE_BT2020_PQ || b == HAL_DATASPACE_BT2020_PQ)) {
+        return HAL_DATASPACE_DISPLAY_P3;
+    }
 
     return HAL_DATASPACE_V0_SRGB;
 }
@@ -1885,6 +1900,11 @@
                     "display %zd: %d", displayId, result);
         }
         for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+            if (layer->getDataSpace() == HAL_DATASPACE_BT2020_PQ &&
+                    !displayDevice->getHdrSupport()) {
+                layer->forceClientComposition(hwcId);
+            }
+
             if (layer->getForceClientComposition(hwcId)) {
                 ALOGV("[%s] Requesting Client composition", layer->getName().string());
                 layer->setCompositionType(hwcId, HWC2::Composition::Client);
@@ -1899,7 +1919,8 @@
             android_dataspace newDataSpace = HAL_DATASPACE_V0_SRGB;
 
             for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
-                newDataSpace = bestTargetDataSpace(layer->getDataSpace(), newDataSpace);
+                newDataSpace = bestTargetDataSpace(layer->getDataSpace(), newDataSpace,
+                        displayDevice->getHdrSupport());
                 ALOGV("layer: %s, dataspace: %s (%#x), newDataSpace: %s (%#x)",
                       layer->getName().string(), dataspaceDetails(layer->getDataSpace()).c_str(),
                       layer->getDataSpace(), dataspaceDetails(newDataSpace).c_str(), newDataSpace);
@@ -2253,9 +2274,19 @@
                         useWideColorMode = hasWideColorModes && hasWideColorDisplay;
                     }
 
+                    bool hasHdrSupport = false;
+                    std::unique_ptr<HdrCapabilities> hdrCapabilities =
+                        getHwComposer().getHdrCapabilities(state.type);
+                    if (hdrCapabilities) {
+                        const std::vector<int32_t> types = hdrCapabilities->getSupportedHdrTypes();
+                        auto iter = std::find(types.cbegin(), types.cend(), HAL_HDR_HDR10);
+                        hasHdrSupport = iter != types.cend();
+                    }
+
                     sp<DisplayDevice> hw =
                             new DisplayDevice(this, state.type, hwcId, state.isSecure, display,
-                                              dispSurface, producer, useWideColorMode);
+                                              dispSurface, producer, useWideColorMode,
+                                              hasHdrSupport);
 
                     android_color_mode defaultColorMode = HAL_COLOR_MODE_NATIVE;
                     if (useWideColorMode) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 4da0803..1349bec 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -607,7 +607,8 @@
     // Given a dataSpace, returns the appropriate color_mode to use
     // to display that dataSpace.
     android_color_mode pickColorMode(android_dataspace dataSpace) const;
-    android_dataspace bestTargetDataSpace(android_dataspace a, android_dataspace b) const;
+    android_dataspace bestTargetDataSpace(android_dataspace a, android_dataspace b,
+            bool hasHdr) const;
 
     mat4 computeSaturationMatrix() const;