1 /*
2  * Copyright 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <aidl/android/hardware/graphics/common/Dataspace.h>
20 #include <aidl/android/hardware/graphics/composer3/RenderIntent.h>
21 #include <android/hardware_buffer.h>
22 #include <math/vec3.h>
23 
24 #include <string>
25 #include <vector>
26 
27 namespace android::tonemap {
28 
29 // Describes a shader uniform
30 // The shader uniform is intended to be passed into a SkRuntimeShaderBuilder, i.e.:
31 //
32 // SkRuntimeShaderBuilder builder;
33 // builder.uniform(<uniform name>).set(<uniform value>.data(), <uniform value>.size());
34 struct ShaderUniform {
35     // The name of the uniform, used for binding into a shader.
36     // The shader must contain a uniform whose name matches this.
37     std::string name;
38 
39     // The value for the uniform, which should be bound to the uniform identified by <name>
40     std::vector<uint8_t> value;
41 };
42 
43 // Describes metadata which may be used for constructing the shader uniforms.
44 // This metadata should not be used for manipulating the source code of the shader program directly,
45 // as otherwise caching by other parts of the system using these shaders may break.
46 struct Metadata {
47     // The maximum luminance of the display in nits
48     float displayMaxLuminance = 0.0;
49 
50     // The maximum luminance of the content in nits
51     float contentMaxLuminance = 0.0;
52 
53     // The current brightness of the display in nits
54     float currentDisplayLuminance = 0.0;
55 
56     // Reference to an AHardwareBuffer.
57     // Devices that support gralloc 4.0 and higher may attach metadata onto a
58     // particular frame's buffer, including metadata used by HDR-standards like
59     // SMPTE 2086 or SMPTE 2094-40.
60     // Note that this parameter may be optional if there is no hardware buffer
61     // available, for instance if the source content is generated from a GL
62     // texture that does not have associated metadata. As such, implementations
63     // must support nullptr.
64     AHardwareBuffer* buffer = nullptr;
65 
66     // RenderIntent of the destination display.
67     // Non-colorimetric render-intents may be defined in order to take advantage of the full display
68     // gamut. Various contrast-enhancement mechanisms may be employed on SDR content as a result,
69     // which means that HDR content may need to be compensated in order to achieve correct blending
70     // behavior. This default is effectively optional - the display render intent may not be
71     // available to clients such as HWUI which are display-agnostic. For those clients, tone-map
72     // colorimetric may be assumed so that the luminance range may be converted to the correct range
73     // based on the output dataspace.
74     aidl::android::hardware::graphics::composer3::RenderIntent renderIntent =
75             aidl::android::hardware::graphics::composer3::RenderIntent::TONE_MAP_COLORIMETRIC;
76 };
77 
78 // Utility class containing pre-processed conversions for a particular color
79 struct Color {
80     // RGB color in linear space
81     vec3 linearRGB;
82     // CIE 1931 XYZ representation of the color
83     vec3 xyz;
84 };
85 
86 class ToneMapper {
87 public:
~ToneMapper()88     virtual ~ToneMapper() {}
89     // Constructs a tonemap shader whose shader language is SkSL, which tonemaps from an
90     // input whose dataspace is described by sourceDataspace, to an output whose dataspace
91     // is described by destinationDataspace
92     //
93     // The returned shader string *must* contain a function with the following signature:
94     // float libtonemap_LookupTonemapGain(vec3 linearRGB, vec3 xyz);
95     //
96     // The arguments are:
97     // * linearRGB is the absolute nits of the RGB pixels in linear space
98     // * xyz is linearRGB converted into XYZ
99     //
100     // libtonemap_LookupTonemapGain() returns a float representing the amount by which to scale the
101     // absolute nits of the pixels. This function may be plugged into any existing SkSL shader, and
102     // is expected to look something like this:
103     //
104     // vec3 rgb = ...;
105     // // apply the EOTF based on the incoming dataspace to convert to linear nits.
106     // vec3 linearRGB = applyEOTF(rgb);
107     // // apply a RGB->XYZ matrix float3
108     // vec3 xyz = toXYZ(linearRGB);
109     // // Scale the luminance based on the content standard
110     // vec3 absoluteRGB = ScaleLuminance(linearRGB);
111     // vec3 absoluteXYZ = ScaleLuminance(xyz);
112     // float gain = libtonemap_LookupTonemapGain(absoluteRGB, absoluteXYZ);
113     // // Normalize the luminance back down to a [0, 1] range
114     // xyz = NormalizeLuminance(absoluteXYZ * gain);
115     // // apply a XYZ->RGB matrix and apply the output OETf.
116     // vec3 finalColor = applyOETF(ToRGB(xyz));
117     // ...
118     //
119     // Helper methods in this shader should be prefixed with "libtonemap_". Accordingly, libraries
120     // which consume this shader must *not* contain any methods prefixed with "libtonemap_" to
121     // guarantee that there are no conflicts in name resolution.
122     virtual std::string generateTonemapGainShaderSkSL(
123             aidl::android::hardware::graphics::common::Dataspace sourceDataspace,
124             aidl::android::hardware::graphics::common::Dataspace destinationDataspace) = 0;
125 
126     // Constructs uniform descriptions that correspond to those that are generated for the tonemap
127     // shader. Uniforms must be prefixed with "in_libtonemap_". Libraries which consume this shader
128     // must not bind any new uniforms that begin with this prefix.
129     //
130     // Downstream shaders may assume the existence of the uniform in_libtonemap_displayMaxLuminance
131     // and in_libtonemap_inputMaxLuminance, in order to assist with scaling and normalizing
132     // luminance as described in the documentation for generateTonemapGainShaderSkSL(). That is,
133     // shaders plugging in a tone-mapping shader returned by generateTonemapGainShaderSkSL() may
134     // assume that there are predefined floats in_libtonemap_displayMaxLuminance and
135     // in_libtonemap_inputMaxLuminance inside of the body of the tone-mapping shader.
136     virtual std::vector<ShaderUniform> generateShaderSkSLUniforms(const Metadata& metadata) = 0;
137 
138     // CPU implementation of the tonemapping gain. This must match the GPU implementation returned
139     // by generateTonemapGainShaderSKSL() above, with some epsilon difference to account for
140     // differences in hardware precision.
141     //
142     // The gain is computed assuming an input described by sourceDataspace, tonemapped to an output
143     // described by destinationDataspace. To compute the gain, the input colors are provided by
144     // linearRGB, which is the RGB colors in linear space. The colors in XYZ space are also
145     // provided. Metadata is also provided for helping to compute the tonemapping curve.
146     using Gain = double;
147     virtual std::vector<Gain> lookupTonemapGain(
148             aidl::android::hardware::graphics::common::Dataspace sourceDataspace,
149             aidl::android::hardware::graphics::common::Dataspace destinationDataspace,
150             const std::vector<Color>& colors, const Metadata& metadata) = 0;
151 };
152 
153 // Retrieves a tonemapper instance.
154 // This instance is globally constructed.
155 ToneMapper* getToneMapper();
156 
157 } // namespace android::tonemap
158