1 /* 2 * Copyright 2020 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 <math/mat4.h> 20 21 #include <optional> 22 23 #include "SkRuntimeEffect.h" 24 #include "SkShader.h" 25 #include "ui/GraphicTypes.h" 26 27 namespace android { 28 namespace renderengine { 29 namespace skia { 30 31 /** 32 * Arguments for creating an effect that applies color transformations in linear XYZ space. 33 * A linear effect is decomposed into the following steps when operating on an image: 34 * 1. Electrical-Optical Transfer Function (EOTF) maps the input RGB signal into the intended 35 * relative display brightness of the scene in nits for each RGB channel 36 * 2. Transformation matrix from linear RGB brightness to linear XYZ, to operate on display 37 * luminance. 38 * 3. Opto-Optical Transfer Function (OOTF) applies a "rendering intent". This can include tone 39 * mapping to display SDR content alongside HDR content, or any number of subjective transformations 40 * 4. Transformation matrix from linear XYZ back to linear RGB brightness. 41 * 5. Opto-Electronic Transfer Function (OETF) maps the display brightness of the scene back to 42 * output RGB colors. 43 * 44 * For further reading, consult the recommendation in ITU-R BT.2390-4: 45 * https://www.itu.int/dms_pub/itu-r/opb/rep/R-REP-BT.2390-4-2018-PDF-E.pdf 46 * 47 * Skia normally attempts to do its own simple tone mapping, i.e., the working color space is 48 * intended to be the output surface. However, Skia does not support complex tone mapping such as 49 * polynomial interpolation. As such, this filter assumes that tone mapping has not yet been applied 50 * to the source colors. so that the tone mapping process is only applied once by this effect. Tone 51 * mapping is applied when presenting HDR content (content with HLG or PQ transfer functions) 52 * alongside other content, whereby maximum input luminance is mapped to maximum output luminance 53 * and intermediate values are interpolated. 54 */ 55 struct LinearEffect { 56 // Input dataspace of the source colors. 57 const ui::Dataspace inputDataspace = ui::Dataspace::SRGB; 58 59 // Working dataspace for the output surface, for conversion from linear space. 60 const ui::Dataspace outputDataspace = ui::Dataspace::SRGB; 61 62 // Sets whether alpha premultiplication must be undone. 63 // This is required if the source colors use premultiplied alpha and is not opaque. 64 const bool undoPremultipliedAlpha = false; 65 }; 66 67 static inline bool operator==(const LinearEffect& lhs, const LinearEffect& rhs) { 68 return lhs.inputDataspace == rhs.inputDataspace && lhs.outputDataspace == rhs.outputDataspace && 69 lhs.undoPremultipliedAlpha == rhs.undoPremultipliedAlpha; 70 } 71 72 struct LinearEffectHasher { 73 // Inspired by art/runtime/class_linker.cc 74 // Also this is what boost:hash_combine does HashCombineLinearEffectHasher75 static size_t HashCombine(size_t seed, size_t val) { 76 return seed ^ (val + 0x9e3779b9 + (seed << 6) + (seed >> 2)); 77 } operatorLinearEffectHasher78 size_t operator()(const LinearEffect& le) const { 79 size_t result = std::hash<ui::Dataspace>{}(le.inputDataspace); 80 result = HashCombine(result, std::hash<ui::Dataspace>{}(le.outputDataspace)); 81 return HashCombine(result, std::hash<bool>{}(le.undoPremultipliedAlpha)); 82 } 83 }; 84 85 sk_sp<SkRuntimeEffect> buildRuntimeEffect(const LinearEffect& linearEffect); 86 87 // Generates a shader resulting from applying the a linear effect created from 88 // LinearEffectArgs::buildEffect to an inputShader. 89 // Optionally, a color transform may also be provided, which combines with the 90 // matrix transforming from linear XYZ to linear RGB immediately before OETF. 91 // We also provide additional HDR metadata upon creating the shader: 92 // * The max display luminance is the max luminance of the physical display in nits 93 // * The max luminance is provided as the max luminance for the buffer, either from the SMPTE 2086 94 // or as the max light level from the CTA 861.3 standard. 95 sk_sp<SkShader> createLinearEffectShader(sk_sp<SkShader> inputShader, 96 const LinearEffect& linearEffect, 97 sk_sp<SkRuntimeEffect> runtimeEffect, 98 const mat4& colorTransform, float maxDisplayLuminance, 99 float maxLuminance); 100 } // namespace skia 101 } // namespace renderengine 102 } // namespace android 103