Correctly render ISO gainmapped images

* Apply the gainmap in reverse when using an HDR base image
* Support alternative primaries
* Nudge the guards that optimize away applying the gainmap shader

Bug: 349357636
Flag: com.android.graphics.hwui.flags.iso_gainmap_apis
Test: GainmapTests
Change-Id: I230a765feddb306330e643e6ead8e62719f49ee5
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 7c15086..7f5ca44 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -622,18 +622,13 @@
     auto colorSpace = info.colorSpace();
     // If we don't have a colorspace, we can't apply a gainmap
     if (!colorSpace) return false;
-    skcms_TransferFunction tfn;
-    colorSpace->transferFn(&tfn);
 
-    auto transferType = skcms_TransferFunction_getType(&tfn);
-    switch (transferType) {
-        case skcms_TFType_HLGish:
-        case skcms_TFType_HLGinvish:
-        case skcms_TFType_PQish:
-            return true;
-        case skcms_TFType_Invalid:
-        case skcms_TFType_sRGBish:
-            return false;
+    const float targetRatio = uirenderer::getTargetHdrSdrRatio(colorSpace);
+
+    if (bitmap.gainmap()->info.fBaseImageType == SkGainmapInfo::BaseImageType::kHDR) {
+        return targetRatio < bitmap.gainmap()->info.fDisplayRatioHdr;
+    } else {
+        return targetRatio > bitmap.gainmap()->info.fDisplayRatioSdr;
     }
 }
 
diff --git a/libs/hwui/effects/GainmapRenderer.cpp b/libs/hwui/effects/GainmapRenderer.cpp
index eac0360..18b77bc 100644
--- a/libs/hwui/effects/GainmapRenderer.cpp
+++ b/libs/hwui/effects/GainmapRenderer.cpp
@@ -73,7 +73,9 @@
 #ifdef __ANDROID__
     auto destColorspace = c->imageInfo().refColorSpace();
     float targetSdrHdrRatio = getTargetHdrSdrRatio(destColorspace.get());
-    if (targetSdrHdrRatio > 1.f && gainmapImage) {
+    const bool baseImageHdr = gainmapInfo.fBaseImageType == SkGainmapInfo::BaseImageType::kHDR;
+    if (gainmapImage && ((baseImageHdr && targetSdrHdrRatio < gainmapInfo.fDisplayRatioHdr) ||
+                         (!baseImageHdr && targetSdrHdrRatio > gainmapInfo.fDisplayRatioSdr))) {
         SkPaint gainmapPaint = *paint;
         float sX = gainmapImage->width() / (float)image->width();
         float sY = gainmapImage->height() / (float)image->height();
@@ -183,7 +185,10 @@
                 baseImage->colorSpace() ? baseImage->refColorSpace() : SkColorSpace::MakeSRGB();
 
         // Determine the color space in which the gainmap math is to be applied.
-        sk_sp<SkColorSpace> gainmapMathColorSpace = baseColorSpace->makeLinearGamma();
+        sk_sp<SkColorSpace> gainmapMathColorSpace =
+                mGainmapInfo.fGainmapMathColorSpace
+                        ? mGainmapInfo.fGainmapMathColorSpace->makeLinearGamma()
+                        : baseColorSpace->makeLinearGamma();
 
         // Create a color filter to transform from the base image's color space to the color space
         // in which the gainmap is to be applied.
@@ -266,6 +271,10 @@
                     W = 1.f;
                 }
             }
+
+            if (mGainmapInfo.fBaseImageType == SkGainmapInfo::BaseImageType::kHDR) {
+                W -= 1.f;
+            }
             mBuilder.uniform("W") = W;
             uniforms = mBuilder.uniforms();
         }
@@ -317,4 +326,4 @@
 
 #endif  // __ANDROID__
 
-}  // namespace android::uirenderer
\ No newline at end of file
+}  // namespace android::uirenderer