Merge "[SurfaceFlinger] Adapt min/max luminance from hardware composer." into pi-dev
am: 8c53323232

Change-Id: Ied84bbac9df6ca5c3521c2b3ddbe441e715fef40
diff --git a/libs/ui/HdrCapabilities.cpp b/libs/ui/HdrCapabilities.cpp
index 50f9bf1..a36911d 100644
--- a/libs/ui/HdrCapabilities.cpp
+++ b/libs/ui/HdrCapabilities.cpp
@@ -27,7 +27,6 @@
 HdrCapabilities::HdrCapabilities(HdrCapabilities&& other) = default;
 HdrCapabilities& HdrCapabilities::operator=(HdrCapabilities&& other) = default;
 
-
 size_t HdrCapabilities::getFlattenedSize() const {
     return  sizeof(mMaxLuminance) +
             sizeof(mMaxAverageLuminance) +
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 7c6302e..00f8cc9 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -108,7 +108,8 @@
       mSupportedPerFrameMetadata(supportedPerFrameMetadata)
 {
     // clang-format on
-    for (Hdr hdrType : hdrCapabilities.getSupportedHdrTypes()) {
+    std::vector<Hdr> types = hdrCapabilities.getSupportedHdrTypes();
+    for (Hdr hdrType : types) {
         switch (hdrType) {
             case Hdr::HDR10:
                 mHasHdr10 = true;
@@ -124,6 +125,26 @@
         }
     }
 
+    float minLuminance = hdrCapabilities.getDesiredMinLuminance();
+    float maxLuminance = hdrCapabilities.getDesiredMaxLuminance();
+    float maxAverageLuminance = hdrCapabilities.getDesiredMaxAverageLuminance();
+
+    minLuminance = minLuminance <= 0.0 ? sDefaultMinLumiance : minLuminance;
+    maxLuminance = maxLuminance <= 0.0 ? sDefaultMaxLumiance : maxLuminance;
+    maxAverageLuminance = maxAverageLuminance <= 0.0 ? sDefaultMaxLumiance : maxAverageLuminance;
+    if (this->hasWideColorGamut()) {
+        // insert HDR10/HLG as we will force client composition for HDR10/HLG
+        // layers
+        if (!hasHDR10Support()) {
+          types.push_back(Hdr::HDR10);
+        }
+
+        if (!hasHLGSupport()) {
+          types.push_back(Hdr::HLG);
+        }
+    }
+    mHdrCapabilities = HdrCapabilities(types, maxLuminance, maxAverageLuminance, minLuminance);
+
     // initialize the display orientation transform.
     setProjection(DisplayState::eOrientationDefault, mViewport, mFrame);
 }
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index df5d945..1df8c49 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -27,6 +27,7 @@
 #include <gui/ISurfaceComposer.h>
 #include <hardware/hwcomposer_defs.h>
 #include <ui/GraphicTypes.h>
+#include <ui/HdrCapabilities.h>
 #include <ui/Region.h>
 #include <utils/RefBase.h>
 #include <utils/Mutex.h>
@@ -53,6 +54,9 @@
 class DisplayDevice : public LightRefBase<DisplayDevice>
 {
 public:
+    constexpr static float sDefaultMinLumiance = 0.0;
+    constexpr static float sDefaultMaxLumiance = 500.0;
+
     // region in layer-stack space
     mutable Region dirtyRegion;
     // region in screen space
@@ -141,6 +145,13 @@
     bool hasHDR10Support() const { return mHasHdr10; }
     bool hasHLGSupport() const { return mHasHLG; }
     bool hasDolbyVisionSupport() const { return mHasDolbyVision; }
+    // The returned HdrCapabilities is the combination of HDR capabilities from
+    // hardware composer and RenderEngine. When the DisplayDevice supports wide
+    // color gamut, RenderEngine is able to simulate HDR support in Display P3
+    // color space for both PQ and HLG HDR contents. The minimum and maximum
+    // luminance will be set to sDefaultMinLumiance and sDefaultMaxLumiance
+    // respectively if hardware composer doesn't return meaningful values.
+    const HdrCapabilities& getHdrCapabilities() const { return mHdrCapabilities; }
 
     void swapBuffers(HWComposer& hwc) const;
 
@@ -261,7 +272,7 @@
     bool mHasHdr10;
     bool mHasHLG;
     bool mHasDolbyVision;
-
+    HdrCapabilities mHdrCapabilities;
     const int32_t mSupportedPerFrameMetadata;
 };
 
@@ -309,6 +320,9 @@
     ui::Dataspace getDataSpace() const override {
         return mDevice->getCompositionDataSpace();
     }
+    float getDisplayMaxLuminance() const override {
+        return mDevice->getHdrCapabilities().getDesiredMaxLuminance();
+    }
 
 private:
     const sp<const DisplayDevice> mDevice;
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index 3630677..4694403 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -32,6 +32,7 @@
     virtual Rect getSourceCrop() const = 0;
     virtual bool getWideColorSupport() const = 0;
     virtual ui::Dataspace getDataSpace() const = 0;
+    virtual float getDisplayMaxLuminance() const = 0;
 
     virtual void render(std::function<void()> drawLayers) { drawLayers(); }
 
diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/services/surfaceflinger/RenderEngine/Description.cpp
index 323bdb2..0ccdbc4 100644
--- a/services/surfaceflinger/RenderEngine/Description.cpp
+++ b/services/surfaceflinger/RenderEngine/Description.cpp
@@ -73,4 +73,8 @@
     mOutputTransferFunction = transferFunction;
 }
 
+void Description::setDisplayMaxLuminance(const float maxLuminance) {
+    mDisplayMaxLuminance = maxLuminance;
+}
+
 } /* namespace android */
diff --git a/services/surfaceflinger/RenderEngine/Description.h b/services/surfaceflinger/RenderEngine/Description.h
index 5854ba4..b09e3a8 100644
--- a/services/surfaceflinger/RenderEngine/Description.h
+++ b/services/surfaceflinger/RenderEngine/Description.h
@@ -55,6 +55,7 @@
     };
     void setInputTransferFunction(TransferFunction transferFunction);
     void setOutputTransferFunction(TransferFunction transferFunction);
+    void setDisplayMaxLuminance(const float maxLuminance);
 
 private:
     friend class Program;
@@ -83,6 +84,8 @@
     // transfer functions for the input/output
     TransferFunction mInputTransferFunction = TransferFunction::LINEAR;
     TransferFunction mOutputTransferFunction = TransferFunction::LINEAR;
+
+    float mDisplayMaxLuminance;
 };
 
 } /* namespace android */
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
index 6e0fa32..8e3c837 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -224,6 +224,10 @@
     mOutputDataSpace = dataspace;
 }
 
+void GLES20RenderEngine::setDisplayMaxLuminance(const float maxLuminance) {
+    mState.setDisplayMaxLuminance(maxLuminance);
+}
+
 void GLES20RenderEngine::setupLayerTexturing(const Texture& texture) {
     GLuint target = texture.getTextureTarget();
     glBindTexture(target, texture.getTextureName());
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
index 99da19d..7177aad 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
@@ -75,17 +75,7 @@
     void setSourceY410BT2020(bool enable) override;
     void setSourceDataSpace(ui::Dataspace source) override;
     void setOutputDataSpace(ui::Dataspace dataspace) override;
-
-    // Current dataspace of layer being rendered
-    ui::Dataspace mDataSpace = ui::Dataspace::UNKNOWN;
-
-    // Current output dataspace of the render engine
-    ui::Dataspace mOutputDataSpace = ui::Dataspace::UNKNOWN;
-
-    // Currently only supporting sRGB, BT2020 and DisplayP3 color spaces
-    const bool mPlatformHasWideColor = false;
-    mat4 mSrgbToDisplayP3;
-    mat4 mBt2020ToDisplayP3;
+    void setDisplayMaxLuminance(const float maxLuminance) override;
 
     virtual void setupLayerTexturing(const Texture& texture);
     virtual void setupLayerBlackedOut();
@@ -98,6 +88,17 @@
 
     virtual size_t getMaxTextureSize() const;
     virtual size_t getMaxViewportDims() const;
+
+    // Current dataspace of layer being rendered
+    ui::Dataspace mDataSpace = ui::Dataspace::UNKNOWN;
+
+    // Current output dataspace of the render engine
+    ui::Dataspace mOutputDataSpace = ui::Dataspace::UNKNOWN;
+
+    // Currently only supporting sRGB, BT2020 and DisplayP3 color spaces
+    const bool mPlatformHasWideColor = false;
+    mat4 mSrgbToDisplayP3;
+    mat4 mBt2020ToDisplayP3;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/RenderEngine/Program.cpp b/services/surfaceflinger/RenderEngine/Program.cpp
index 225bcf0..e5261c2 100644
--- a/services/surfaceflinger/RenderEngine/Program.cpp
+++ b/services/surfaceflinger/RenderEngine/Program.cpp
@@ -64,6 +64,7 @@
         mTextureMatrixLoc = glGetUniformLocation(programId, "texture");
         mSamplerLoc = glGetUniformLocation(programId, "sampler");
         mColorLoc = glGetUniformLocation(programId, "color");
+        mDisplayMaxLuminanceLoc = glGetUniformLocation(programId, "displayMaxLuminance");
 
         // set-up the default values for our uniforms
         glUseProgram(programId);
@@ -136,6 +137,9 @@
     if (mColorMatrixLoc >= 0) {
         glUniformMatrix4fv(mColorMatrixLoc, 1, GL_FALSE, desc.mColorMatrix.asArray());
     }
+    if (mDisplayMaxLuminanceLoc >= 0) {
+        glUniform1f(mDisplayMaxLuminanceLoc, desc.mDisplayMaxLuminance);
+    }
     // these uniforms are always present
     glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, desc.mProjectionMatrix.asArray());
 }
diff --git a/services/surfaceflinger/RenderEngine/Program.h b/services/surfaceflinger/RenderEngine/Program.h
index 6e57fdd..55b9cdd 100644
--- a/services/surfaceflinger/RenderEngine/Program.h
+++ b/services/surfaceflinger/RenderEngine/Program.h
@@ -80,6 +80,9 @@
 
     /* location of the color uniform */
     GLint mColorLoc;
+
+    /* location of display luminance uniform */
+    GLint mDisplayMaxLuminanceLoc;
 };
 
 } /* namespace android */
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
index fb63296..5d5462f 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
@@ -247,7 +247,7 @@
                     const float maxMasteringLumi = 1000.0;
                     const float maxContentLumi = 1000.0;
                     const float maxInLumi = min(maxMasteringLumi, maxContentLumi);
-                    const float maxOutLumi = 500.0;
+                    const float maxOutLumi = displayMaxLuminance;
 
                     // Calculate Y value in XYZ color space.
                     float colorY = CalculateY(color);
@@ -443,6 +443,10 @@
 
     if (needs.hasColorMatrix()) {
         fs << "uniform mat4 colorMatrix;";
+        // Currently, only the OOTF of BT2020 PQ needs display maximum luminance.
+        if (needs.getInputTF() == Key::INPUT_TF_ST2084) {
+            fs << "uniform float displayMaxLuminance";
+        }
 
         generateEOTF(fs, needs);
         generateOOTF(fs, needs);
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index f78b230..df9e6a7 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -117,10 +117,11 @@
     virtual void disableTexturing() = 0;
     virtual void disableBlending() = 0;
 
-    // wide color support
+    // HDR and wide color gamut support
     virtual void setSourceY410BT2020(bool enable) = 0;
     virtual void setSourceDataSpace(ui::Dataspace source) = 0;
     virtual void setOutputDataSpace(ui::Dataspace dataspace) = 0;
+    virtual void setDisplayMaxLuminance(const float maxLuminance) = 0;
 
     // drawing
     virtual void drawMesh(const Mesh& mesh) = 0;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e12d7ca..f736c8c 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1119,31 +1119,14 @@
         return BAD_VALUE;
     }
 
-    HdrCapabilities capabilities;
-    int status = getBE().mHwc->getHdrCapabilities(
-        displayDevice->getHwcDisplayId(), &capabilities);
-    if (status == NO_ERROR) {
-        if (displayDevice->hasWideColorGamut()) {
-            std::vector<Hdr> types = capabilities.getSupportedHdrTypes();
-            // insert HDR10/HLG as we will force client composition for HDR10/HLG
-            // layers
-            if (!displayDevice->hasHDR10Support()) {
-                types.push_back(Hdr::HDR10);
-            }
-            if (!displayDevice->hasHLGSupport()) {
-                types.push_back(Hdr::HLG);
-            }
-
-            *outCapabilities = HdrCapabilities(types,
-                    capabilities.getDesiredMaxLuminance(),
-                    capabilities.getDesiredMaxAverageLuminance(),
-                    capabilities.getDesiredMinLuminance());
-        } else {
-            *outCapabilities = std::move(capabilities);
-        }
-    } else {
-        return BAD_VALUE;
-    }
+    // At this point the DisplayDeivce should already be set up,
+    // meaning the luminance information is already queried from
+    // hardware composer and stored properly.
+    const HdrCapabilities& capabilities = displayDevice->getHdrCapabilities();
+    *outCapabilities = HdrCapabilities(capabilities.getSupportedHdrTypes(),
+                                       capabilities.getDesiredMaxLuminance(),
+                                       capabilities.getDesiredMaxAverageLuminance(),
+                                       capabilities.getDesiredMinLuminance());
 
     return NO_ERROR;
 }
@@ -2917,6 +2900,8 @@
             outputDataspace = displayDevice->getCompositionDataSpace();
         }
         getBE().mRenderEngine->setOutputDataSpace(outputDataspace);
+        getBE().mRenderEngine->setDisplayMaxLuminance(
+                displayDevice->getHdrCapabilities().getDesiredMaxLuminance());
 
         if (!displayDevice->makeCurrent()) {
             ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",
@@ -4721,6 +4706,9 @@
         }
         bool getWideColorSupport() const override { return false; }
         Dataspace getDataSpace() const override { return Dataspace::UNKNOWN; }
+        float getDisplayMaxLuminance() const override {
+            return DisplayDevice::sDefaultMaxLumiance;
+        }
 
         class ReparentForDrawing {
         public:
@@ -4923,7 +4911,8 @@
     if (renderArea.getWideColorSupport()) {
         outputDataspace = renderArea.getDataSpace();
     }
-    getBE().mRenderEngine->setOutputDataSpace(outputDataspace);
+    engine.setOutputDataSpace(outputDataspace);
+    engine.setDisplayMaxLuminance(renderArea.getDisplayMaxLuminance());
 
     // make sure to clear all GL error flags
     engine.checkErrors();
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
index 9bb2a3c..29cd2d5 100644
--- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
+++ b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
@@ -66,6 +66,7 @@
     MOCK_METHOD1(setSourceY410BT2020, void(bool));
     MOCK_METHOD1(setSourceDataSpace, void(ui::Dataspace));
     MOCK_METHOD1(setOutputDataSpace, void(ui::Dataspace));
+    MOCK_METHOD1(setDisplayMaxLuminance, void(const float));
     MOCK_METHOD2(bindNativeBufferAsFrameBuffer,
                  void(ANativeWindowBuffer*, RE::BindNativeBufferAsFramebuffer*));
     MOCK_METHOD1(unbindNativeBufferAsFrameBuffer, void(RE::BindNativeBufferAsFramebuffer*));