Tonemap everywhere in PixelCopy

* Hookup tonemap support for PixelCopying a SurfaceView
* Fix issue in PixelCopying a SurfaceView where the wrong dataspace was
  retrieved from the last queued buffer, since the bufferqueue dataspace
  may drift due to another process like camera setting the dataspace
  without being propagated to the app process
* Cleanup LayerDrawable to share code

Bug: 238395777
Test: Switching HDR cameras doesn't color shift
Test: TextureView playback in Photos
Change-Id: I0fd1bd86410630acfbb7de72339874a3d0ecac58
diff --git a/libs/hwui/Tonemapper.cpp b/libs/hwui/Tonemapper.cpp
new file mode 100644
index 0000000..a7e76b6
--- /dev/null
+++ b/libs/hwui/Tonemapper.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2022 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.
+ */
+
+#include "Tonemapper.h"
+
+#include <SkRuntimeEffect.h>
+#include <log/log.h>
+#include <shaders/shaders.h>
+
+#include "utils/Color.h"
+
+namespace android::uirenderer {
+
+namespace {
+
+class ColorFilterRuntimeEffectBuilder : public SkRuntimeEffectBuilder {
+public:
+    explicit ColorFilterRuntimeEffectBuilder(sk_sp<SkRuntimeEffect> effect)
+            : SkRuntimeEffectBuilder(std::move(effect)) {}
+
+    sk_sp<SkColorFilter> makeColorFilter() {
+        return this->effect()->makeColorFilter(this->uniforms());
+    }
+};
+
+static sk_sp<SkColorFilter> createLinearEffectColorFilter(const shaders::LinearEffect& linearEffect,
+                                                          float maxDisplayLuminance,
+                                                          float currentDisplayLuminanceNits,
+                                                          float maxLuminance) {
+    auto shaderString = SkString(shaders::buildLinearEffectSkSL(linearEffect));
+    auto [runtimeEffect, error] = SkRuntimeEffect::MakeForColorFilter(std::move(shaderString));
+    if (!runtimeEffect) {
+        LOG_ALWAYS_FATAL("LinearColorFilter construction error: %s", error.c_str());
+    }
+
+    ColorFilterRuntimeEffectBuilder effectBuilder(std::move(runtimeEffect));
+
+    const auto uniforms =
+            shaders::buildLinearEffectUniforms(linearEffect, android::mat4(), maxDisplayLuminance,
+                                               currentDisplayLuminanceNits, maxLuminance);
+
+    for (const auto& uniform : uniforms) {
+        effectBuilder.uniform(uniform.name.c_str()).set(uniform.value.data(), uniform.value.size());
+    }
+
+    return effectBuilder.makeColorFilter();
+}
+
+static bool extractTransfer(ui::Dataspace dataspace) {
+    return dataspace & HAL_DATASPACE_TRANSFER_MASK;
+}
+
+static bool isHdrDataspace(ui::Dataspace dataspace) {
+    const auto transfer = extractTransfer(dataspace);
+
+    return transfer == HAL_DATASPACE_TRANSFER_ST2084 || transfer == HAL_DATASPACE_TRANSFER_HLG;
+}
+
+static ui::Dataspace getDataspace(const SkImageInfo& image) {
+    return static_cast<ui::Dataspace>(
+            ColorSpaceToADataSpace(image.colorSpace(), image.colorType()));
+}
+
+}  // namespace
+
+// Given a source and destination image info, and the max content luminance, generate a tonemaping
+// shader and tag it on the supplied paint.
+void tonemapPaint(const SkImageInfo& source, const SkImageInfo& destination, float maxLuminanceNits,
+                  SkPaint& paint) {
+    const auto sourceDataspace = getDataspace(source);
+    const auto destinationDataspace = getDataspace(destination);
+
+    if (extractTransfer(sourceDataspace) != extractTransfer(destinationDataspace) &&
+        (isHdrDataspace(sourceDataspace) || isHdrDataspace(destinationDataspace))) {
+        const auto effect = shaders::LinearEffect{
+                .inputDataspace = sourceDataspace,
+                .outputDataspace = destinationDataspace,
+                .undoPremultipliedAlpha = source.alphaType() == kPremul_SkAlphaType,
+                .fakeInputDataspace = destinationDataspace,
+                .type = shaders::LinearEffect::SkSLType::ColorFilter};
+        constexpr float kMaxDisplayBrightnessNits = 1000.f;
+        constexpr float kCurrentDisplayBrightnessNits = 500.f;
+        sk_sp<SkColorFilter> colorFilter = createLinearEffectColorFilter(
+                effect, kMaxDisplayBrightnessNits, kCurrentDisplayBrightnessNits, maxLuminanceNits);
+
+        if (paint.getColorFilter()) {
+            paint.setColorFilter(SkColorFilters::Compose(paint.refColorFilter(), colorFilter));
+        } else {
+            paint.setColorFilter(colorFilter);
+        }
+    }
+}
+
+}  // namespace android::uirenderer