Merge "Support HDR tonemapping in TextureView"
This commit is contained in:
@@ -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: {
|
||||
|
||||
@@ -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, ¤tCrop);
|
||||
mSurfaceTexture.get(), &slot, &dataspace, &hdrMetadataType, &cta861_3,
|
||||
&smpte2086, transformMatrix, &outTransform, &newContent, createReleaseFence,
|
||||
fenceWait, this, ¤tCrop);
|
||||
|
||||
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() {
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
canvas->drawImageRect(layerImage.get(), skiaSrcRect, skiaDestRect, sampling, &paint,
|
||||
constraint);
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user