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

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

Merge "Tonemap everywhere in PixelCopy"

parents e671a18a 97326742
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -589,6 +589,7 @@ cc_defaults {
                "ProfileData.cpp",
                "ProfileData.cpp",
                "ProfileDataContainer.cpp",
                "ProfileDataContainer.cpp",
                "Readback.cpp",
                "Readback.cpp",
                "Tonemapper.cpp",
                "TreeInfo.cpp",
                "TreeInfo.cpp",
                "WebViewFunctorManager.cpp",
                "WebViewFunctorManager.cpp",
                "protos/graphicsstats.proto",
                "protos/graphicsstats.proto",
+29 −12
Original line number Original line Diff line number Diff line
@@ -16,16 +16,6 @@


#include "Readback.h"
#include "Readback.h"


#include <sync/sync.h>
#include <system/window.h>

#include <gui/TraceUtils.h>
#include "DeferredLayerUpdater.h"
#include "Properties.h"
#include "hwui/Bitmap.h"
#include "pipeline/skia/LayerDrawable.h"
#include "renderthread/EglManager.h"
#include "renderthread/VulkanManager.h"
#include <SkBitmap.h>
#include <SkBitmap.h>
#include <SkBlendMode.h>
#include <SkBlendMode.h>
#include <SkCanvas.h>
#include <SkCanvas.h>
@@ -38,6 +28,19 @@
#include <SkRefCnt.h>
#include <SkRefCnt.h>
#include <SkSamplingOptions.h>
#include <SkSamplingOptions.h>
#include <SkSurface.h>
#include <SkSurface.h>
#include <gui/TraceUtils.h>
#include <private/android/AHardwareBufferHelpers.h>
#include <shaders/shaders.h>
#include <sync/sync.h>
#include <system/window.h>

#include "DeferredLayerUpdater.h"
#include "Properties.h"
#include "Tonemapper.h"
#include "hwui/Bitmap.h"
#include "pipeline/skia/LayerDrawable.h"
#include "renderthread/EglManager.h"
#include "renderthread/VulkanManager.h"
#include "utils/Color.h"
#include "utils/Color.h"
#include "utils/MathUtils.h"
#include "utils/MathUtils.h"
#include "utils/NdkUtils.h"
#include "utils/NdkUtils.h"
@@ -91,8 +94,18 @@ void Readback::copySurfaceInto(ANativeWindow* window, const std::shared_ptr<Copy
        }
        }
    }
    }


    sk_sp<SkColorSpace> colorSpace = DataSpaceToColorSpace(
    int32_t dataspace = ANativeWindow_getBuffersDataSpace(window);
            static_cast<android_dataspace>(ANativeWindow_getBuffersDataSpace(window)));

    // If the application is not updating the Surface themselves, e.g., another
    // process is producing buffers for the application to display, then
    // ANativeWindow_getBuffersDataSpace will return an unknown answer, so grab
    // the dataspace from buffer metadata instead, if it exists.
    if (dataspace == 0) {
        dataspace = AHardwareBuffer_getDataSpace(sourceBuffer.get());
    }

    sk_sp<SkColorSpace> colorSpace =
            DataSpaceToColorSpace(static_cast<android_dataspace>(dataspace));
    sk_sp<SkImage> image =
    sk_sp<SkImage> image =
            SkImage::MakeFromAHardwareBuffer(sourceBuffer.get(), kPremul_SkAlphaType, colorSpace);
            SkImage::MakeFromAHardwareBuffer(sourceBuffer.get(), kPremul_SkAlphaType, colorSpace);


@@ -227,6 +240,10 @@ void Readback::copySurfaceInto(ANativeWindow* window, const std::shared_ptr<Copy
    const bool hasBufferCrop = cropRect.left < cropRect.right && cropRect.top < cropRect.bottom;
    const bool hasBufferCrop = cropRect.left < cropRect.right && cropRect.top < cropRect.bottom;
    auto constraint =
    auto constraint =
            hasBufferCrop ? SkCanvas::kStrict_SrcRectConstraint : SkCanvas::kFast_SrcRectConstraint;
            hasBufferCrop ? SkCanvas::kStrict_SrcRectConstraint : SkCanvas::kFast_SrcRectConstraint;

    static constexpr float kMaxLuminanceNits = 4000.f;
    tonemapPaint(image->imageInfo(), canvas->imageInfo(), kMaxLuminanceNits, paint);

    canvas->drawImageRect(image, imageSrcRect, imageDstRect, sampling, &paint, constraint);
    canvas->drawImageRect(image, imageSrcRect, imageDstRect, sampling, &paint, constraint);
    canvas->restore();
    canvas->restore();


+107 −0
Original line number Original line Diff line number Diff line
/*
 * 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

libs/hwui/Tonemapper.h

0 → 100644
+28 −0
Original line number Original line Diff line number Diff line
/*
 * 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.
 */

#pragma once

#include <SkCanvas.h>

namespace android::uirenderer {

// 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);

}  // namespace android::uirenderer
+5 −56
Original line number Original line Diff line number Diff line
@@ -25,6 +25,7 @@
#include "SkColorFilter.h"
#include "SkColorFilter.h"
#include "SkRuntimeEffect.h"
#include "SkRuntimeEffect.h"
#include "SkSurface.h"
#include "SkSurface.h"
#include "Tonemapper.h"
#include "gl/GrGLTypes.h"
#include "gl/GrGLTypes.h"
#include "math/mat4.h"
#include "math/mat4.h"
#include "system/graphics-base-v1.0.h"
#include "system/graphics-base-v1.0.h"
@@ -76,37 +77,6 @@ static bool shouldFilterRect(const SkMatrix& matrix, const SkRect& srcRect, cons
             isIntegerAligned(dstDevRect.y()));
             isIntegerAligned(dstDevRect.y()));
}
}


static sk_sp<SkShader> createLinearEffectShader(sk_sp<SkShader> shader,
                                                const shaders::LinearEffect& linearEffect,
                                                float maxDisplayLuminance,
                                                float currentDisplayLuminanceNits,
                                                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, currentDisplayLuminanceNits, maxLuminance);

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

    return effectBuilder.makeShader();
}

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;
}

static void adjustCropForYUV(uint32_t format, int bufferWidth, int bufferHeight, SkRect* cropRect) {
static void adjustCropForYUV(uint32_t format, int bufferWidth, int bufferHeight, SkRect* cropRect) {
    // Chroma channels of YUV420 images are subsampled we may need to shrink the crop region by
    // Chroma channels of YUV420 images are subsampled we may need to shrink the crop region by
    // a whole texel on each side. Since skia still adds its own 0.5 inset, we apply an
    // a whole texel on each side. Since skia still adds its own 0.5 inset, we apply an
@@ -215,31 +185,10 @@ bool LayerDrawable::DrawLayer(GrRecordingContext* context,
            sampling = SkSamplingOptions(SkFilterMode::kLinear);
            sampling = SkSamplingOptions(SkFilterMode::kLinear);
        }
        }


        const auto sourceDataspace = static_cast<ui::Dataspace>(
        tonemapPaint(layerImage->imageInfo(), canvas->imageInfo(), layer->getMaxLuminanceNits(),
                ColorSpaceToADataSpace(layerImage->colorSpace(), layerImage->colorType()));
                     paint);
        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;
            constexpr float kCurrentDisplayBrightness = 500.f;
            shader = createLinearEffectShader(std::move(shader), effect, kMaxDisplayBrightess,
                                              kCurrentDisplayBrightness,
                                              layer->getMaxLuminanceNits());
            paint.setShader(shader);
            canvas->drawRect(skiaDestRect, paint);
        } else {
        canvas->drawImageRect(layerImage.get(), skiaSrcRect, skiaDestRect, sampling, &paint,
        canvas->drawImageRect(layerImage.get(), skiaSrcRect, skiaDestRect, sampling, &paint,
                              constraint);
                              constraint);
        }


        canvas->restore();
        canvas->restore();
        // restore the original matrix
        // restore the original matrix