blob: 852fc87c570d6b6ef2ff75d35d72b1d34df9ec40 [file] [log] [blame]
/*
* Copyright 2021 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 <aidl/android/hardware/graphics/common/Dataspace.h>
#include <aidl/android/hardware/graphics/composer3/RenderIntent.h>
#include <android/hardware_buffer.h>
#include <math/vec3.h>
#include <string>
#include <vector>
namespace android::tonemap {
// Describes a shader uniform
// The shader uniform is intended to be passed into a SkRuntimeShaderBuilder, i.e.:
//
// SkRuntimeShaderBuilder builder;
// builder.uniform(<uniform name>).set(<uniform value>.data(), <uniform value>.size());
struct ShaderUniform {
// The name of the uniform, used for binding into a shader.
// The shader must contain a uniform whose name matches this.
std::string name;
// The value for the uniform, which should be bound to the uniform identified by <name>
std::vector<uint8_t> value;
};
// Describes metadata which may be used for constructing the shader uniforms.
// This metadata should not be used for manipulating the source code of the shader program directly,
// as otherwise caching by other parts of the system using these shaders may break.
struct Metadata {
// The maximum luminance of the display in nits
float displayMaxLuminance = 0.0;
// The maximum luminance of the content in nits
float contentMaxLuminance = 0.0;
// The current brightness of the display in nits
float currentDisplayLuminance = 0.0;
// Reference to an AHardwareBuffer.
// Devices that support gralloc 4.0 and higher may attach metadata onto a
// particular frame's buffer, including metadata used by HDR-standards like
// SMPTE 2086 or SMPTE 2094-40.
// Note that this parameter may be optional if there is no hardware buffer
// available, for instance if the source content is generated from a GL
// texture that does not have associated metadata. As such, implementations
// must support nullptr.
AHardwareBuffer* buffer = nullptr;
// RenderIntent of the destination display.
// Non-colorimetric render-intents may be defined in order to take advantage of the full display
// gamut. Various contrast-enhancement mechanisms may be employed on SDR content as a result,
// which means that HDR content may need to be compensated in order to achieve correct blending
// behavior. This default is effectively optional - the display render intent may not be
// available to clients such as HWUI which are display-agnostic. For those clients, tone-map
// colorimetric may be assumed so that the luminance range may be converted to the correct range
// based on the output dataspace.
aidl::android::hardware::graphics::composer3::RenderIntent renderIntent =
aidl::android::hardware::graphics::composer3::RenderIntent::TONE_MAP_COLORIMETRIC;
};
// Utility class containing pre-processed conversions for a particular color
struct Color {
// RGB color in linear space
vec3 linearRGB;
// CIE 1931 XYZ representation of the color
vec3 xyz;
};
class ToneMapper {
public:
virtual ~ToneMapper() {}
// Constructs a tonemap shader whose shader language is SkSL, which tonemaps from an
// input whose dataspace is described by sourceDataspace, to an output whose dataspace
// is described by destinationDataspace
//
// The returned shader string *must* contain a function with the following signature:
// float libtonemap_LookupTonemapGain(vec3 linearRGB, vec3 xyz);
//
// The arguments are:
// * linearRGB is the absolute nits of the RGB pixels in linear space
// * xyz is linearRGB converted into XYZ
//
// libtonemap_LookupTonemapGain() returns a float representing the amount by which to scale the
// absolute nits of the pixels. This function may be plugged into any existing SkSL shader, and
// is expected to look something like this:
//
// vec3 rgb = ...;
// // apply the EOTF based on the incoming dataspace to convert to linear nits.
// vec3 linearRGB = applyEOTF(rgb);
// // apply a RGB->XYZ matrix float3
// vec3 xyz = toXYZ(linearRGB);
// // Scale the luminance based on the content standard
// vec3 absoluteRGB = ScaleLuminance(linearRGB);
// vec3 absoluteXYZ = ScaleLuminance(xyz);
// float gain = libtonemap_LookupTonemapGain(absoluteRGB, absoluteXYZ);
// // Normalize the luminance back down to a [0, 1] range
// xyz = NormalizeLuminance(absoluteXYZ * gain);
// // apply a XYZ->RGB matrix and apply the output OETf.
// vec3 finalColor = applyOETF(ToRGB(xyz));
// ...
//
// Helper methods in this shader should be prefixed with "libtonemap_". Accordingly, libraries
// which consume this shader must *not* contain any methods prefixed with "libtonemap_" to
// guarantee that there are no conflicts in name resolution.
virtual std::string generateTonemapGainShaderSkSL(
aidl::android::hardware::graphics::common::Dataspace sourceDataspace,
aidl::android::hardware::graphics::common::Dataspace destinationDataspace) = 0;
// Constructs uniform descriptions that correspond to those that are generated for the tonemap
// shader. Uniforms must be prefixed with "in_libtonemap_". Libraries which consume this shader
// must not bind any new uniforms that begin with this prefix.
//
// Downstream shaders may assume the existence of the uniform in_libtonemap_displayMaxLuminance
// and in_libtonemap_inputMaxLuminance, in order to assist with scaling and normalizing
// luminance as described in the documentation for generateTonemapGainShaderSkSL(). That is,
// shaders plugging in a tone-mapping shader returned by generateTonemapGainShaderSkSL() may
// assume that there are predefined floats in_libtonemap_displayMaxLuminance and
// in_libtonemap_inputMaxLuminance inside of the body of the tone-mapping shader.
virtual std::vector<ShaderUniform> generateShaderSkSLUniforms(const Metadata& metadata) = 0;
// CPU implementation of the tonemapping gain. This must match the GPU implementation returned
// by generateTonemapGainShaderSKSL() above, with some epsilon difference to account for
// differences in hardware precision.
//
// The gain is computed assuming an input described by sourceDataspace, tonemapped to an output
// described by destinationDataspace. To compute the gain, the input colors are provided by
// linearRGB, which is the RGB colors in linear space. The colors in XYZ space are also
// provided. Metadata is also provided for helping to compute the tonemapping curve.
using Gain = double;
virtual std::vector<Gain> lookupTonemapGain(
aidl::android::hardware::graphics::common::Dataspace sourceDataspace,
aidl::android::hardware::graphics::common::Dataspace destinationDataspace,
const std::vector<Color>& colors, const Metadata& metadata) = 0;
};
// Retrieves a tonemapper instance.
// This instance is globally constructed.
ToneMapper* getToneMapper();
} // namespace android::tonemap