Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 84feade5 authored by Alec Mouri's avatar Alec Mouri Committed by Android (Google) Code Review
Browse files

Merge "Support HDR tonemapping in TextureView"

parents 24a62f80 d0001fee
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -107,6 +107,8 @@ cc_defaults {
    target: {
        android: {
            shared_libs: [
                "android.hardware.graphics.common-V3-ndk",
                "android.hardware.graphics.common@1.2",
                "liblog",
                "libcutils",
                "libutils",
@@ -126,9 +128,11 @@ cc_defaults {
            static_libs: [
                "libEGL_blobCache",
                "libprotoutil",
                "libshaders",
                "libstatslog_hwui",
                "libstatspull_lazy",
                "libstatssocket_lazy",
                "libtonemap",
            ],
        },
        host: {
+23 −4
Original line number Diff line number Diff line
@@ -20,9 +20,11 @@

// TODO: Use public SurfaceTexture APIs once available and include public NDK header file instead.
#include <surfacetexture/surface_texture_platform.h>

#include "AutoBackendTextureRelease.h"
#include "Matrix.h"
#include "Properties.h"
#include "android/hdr_metadata.h"
#include "renderstate/RenderState.h"
#include "renderthread/EglManager.h"
#include "renderthread/RenderThread.h"
@@ -147,6 +149,9 @@ void DeferredLayerUpdater::apply() {
            mUpdateTexImage = false;
            float transformMatrix[16];
            android_dataspace dataspace;
            AHdrMetadataType hdrMetadataType;
            android_cta861_3_metadata cta861_3;
            android_smpte2086_metadata smpte2086;
            int slot;
            bool newContent = false;
            ARect currentCrop;
@@ -155,8 +160,9 @@ void DeferredLayerUpdater::apply() {
            // is necessary if the SurfaceTexture queue is in synchronous mode, and we
            // cannot tell which mode it is in.
            AHardwareBuffer* hardwareBuffer = ASurfaceTexture_dequeueBuffer(
                    mSurfaceTexture.get(), &slot, &dataspace, transformMatrix, &outTransform,
                    &newContent, createReleaseFence, fenceWait, this, &currentCrop);
                    mSurfaceTexture.get(), &slot, &dataspace, &hdrMetadataType, &cta861_3,
                    &smpte2086, transformMatrix, &outTransform, &newContent, createReleaseFence,
                    fenceWait, this, &currentCrop);

            if (hardwareBuffer) {
                mCurrentSlot = slot;
@@ -173,7 +179,18 @@ void DeferredLayerUpdater::apply() {
                    SkRect currentCropRect =
                            SkRect::MakeLTRB(currentCrop.left, currentCrop.top, currentCrop.right,
                                             currentCrop.bottom);
                    updateLayer(forceFilter, layerImage, outTransform, currentCropRect);

                    float maxLuminanceNits = -1.f;
                    if (hdrMetadataType & HDR10_SMPTE2086) {
                        maxLuminanceNits = std::max(smpte2086.maxLuminance, maxLuminanceNits);
                    }

                    if (hdrMetadataType & HDR10_CTA861_3) {
                        maxLuminanceNits =
                                std::max(cta861_3.maxContentLightLevel, maxLuminanceNits);
                    }
                    updateLayer(forceFilter, layerImage, outTransform, currentCropRect,
                                maxLuminanceNits);
                }
            }
        }
@@ -186,13 +203,15 @@ void DeferredLayerUpdater::apply() {
}

void DeferredLayerUpdater::updateLayer(bool forceFilter, const sk_sp<SkImage>& layerImage,
                                       const uint32_t transform, SkRect currentCrop) {
                                       const uint32_t transform, SkRect currentCrop,
                                       float maxLuminanceNits) {
    mLayer->setBlend(mBlend);
    mLayer->setForceFilter(forceFilter);
    mLayer->setSize(mWidth, mHeight);
    mLayer->setCurrentCropRect(currentCrop);
    mLayer->setWindowTransform(transform);
    mLayer->setImage(layerImage);
    mLayer->setMaxLuminanceNits(maxLuminanceNits);
}

void DeferredLayerUpdater::detachSurfaceTexture() {
+1 −1
Original line number Diff line number Diff line
@@ -91,7 +91,7 @@ public:
    void detachSurfaceTexture();

    void updateLayer(bool forceFilter, const sk_sp<SkImage>& layerImage, const uint32_t transform,
                     SkRect currentCrop);
                     SkRect currentCrop, float maxLuminanceNits = -1.f);

    void destroyLayer();

+11 −0
Original line number Diff line number Diff line
@@ -96,6 +96,12 @@ public:

    inline sk_sp<SkImage> getImage() const { return this->layerImage; }

    inline void setMaxLuminanceNits(float maxLuminanceNits) {
        mMaxLuminanceNits = maxLuminanceNits;
    }

    inline float getMaxLuminanceNits() { return mMaxLuminanceNits; }

    void draw(SkCanvas* canvas);

protected:
@@ -158,6 +164,11 @@ private:
     */
    bool mBlend = false;

    /**
     * Max input luminance if the layer is HDR
     */
    float mMaxLuminanceNits = -1;

};  // struct Layer

}  // namespace uirenderer
+60 −2
Original line number Diff line number Diff line
@@ -15,12 +15,19 @@
 */

#include "LayerDrawable.h"

#include <shaders/shaders.h>
#include <utils/Color.h>
#include <utils/MathUtils.h>

#include "DeviceInfo.h"
#include "GrBackendSurface.h"
#include "SkColorFilter.h"
#include "SkRuntimeEffect.h"
#include "SkSurface.h"
#include "gl/GrGLTypes.h"
#include "math/mat4.h"
#include "system/graphics-base-v1.0.h"
#include "system/window.h"

namespace android {
@@ -69,6 +76,35 @@ static bool shouldFilterRect(const SkMatrix& matrix, const SkRect& srcRect, cons
             isIntegerAligned(dstDevRect.y()));
}

static sk_sp<SkShader> createLinearEffectShader(sk_sp<SkShader> shader,
                                                const shaders::LinearEffect& linearEffect,
                                                float maxDisplayLuminance, float maxLuminance) {
    auto shaderString = SkString(shaders::buildLinearEffectSkSL(linearEffect));
    auto [runtimeEffect, error] = SkRuntimeEffect::MakeForShader(std::move(shaderString));
    if (!runtimeEffect) {
        LOG_ALWAYS_FATAL("LinearColorFilter construction error: %s", error.c_str());
    }

    SkRuntimeShaderBuilder effectBuilder(std::move(runtimeEffect));

    effectBuilder.child("child") = std::move(shader);

    const auto uniforms = shaders::buildLinearEffectUniforms(linearEffect, mat4(),
                                                             maxDisplayLuminance, maxLuminance);

    for (const auto& uniform : uniforms) {
        effectBuilder.uniform(uniform.name.c_str()).set(uniform.value.data(), uniform.value.size());
    }

    return effectBuilder.makeShader(nullptr, false);
}

static bool isHdrDataspace(ui::Dataspace dataspace) {
    const auto transfer = dataspace & HAL_DATASPACE_TRANSFER_MASK;

    return transfer == HAL_DATASPACE_TRANSFER_ST2084 || transfer == HAL_DATASPACE_TRANSFER_HLG;
}

// TODO: Context arg probably doesn't belong here – do debug check at callsite instead.
bool LayerDrawable::DrawLayer(GrRecordingContext* context,
                              SkCanvas* canvas,
@@ -150,8 +186,30 @@ bool LayerDrawable::DrawLayer(GrRecordingContext* context,
            sampling = SkSamplingOptions(SkFilterMode::kLinear);
        }

        const auto sourceDataspace = static_cast<ui::Dataspace>(
                ColorSpaceToADataSpace(layerImage->colorSpace(), layerImage->colorType()));
        const SkImageInfo& imageInfo = canvas->imageInfo();
        const auto destinationDataspace = static_cast<ui::Dataspace>(
                ColorSpaceToADataSpace(imageInfo.colorSpace(), imageInfo.colorType()));

        if (isHdrDataspace(sourceDataspace) || isHdrDataspace(destinationDataspace)) {
            const auto effect = shaders::LinearEffect{
                    .inputDataspace = sourceDataspace,
                    .outputDataspace = destinationDataspace,
                    .undoPremultipliedAlpha = layerImage->alphaType() == kPremul_SkAlphaType,
                    .fakeInputDataspace = destinationDataspace};
            auto shader = layerImage->makeShader(sampling,
                                                 SkMatrix::RectToRect(skiaSrcRect, skiaDestRect));
            constexpr float kMaxDisplayBrightess = 1000.f;
            shader = createLinearEffectShader(std::move(shader), effect, kMaxDisplayBrightess,
                                              layer->getMaxLuminanceNits());
            paint.setShader(shader);
            canvas->drawRect(skiaDestRect, paint);
        } else {
            canvas->drawImageRect(layerImage.get(), skiaSrcRect, skiaDestRect, sampling, &paint,
                                  constraint);
        }

        canvas->restore();
        // restore the original matrix
        if (useLayerTransform) {