A game about forced loneliness, made by TACStudios
1using System; 2 3namespace UnityEngine.Rendering 4{ 5 /// <summary> 6 /// Utility class for outputting to an HDR display. 7 /// </summary> 8 public static class HDROutputUtils 9 { 10 /// <summary> HDR color operations that the shader applies. </summary> 11 [Flags] 12 public enum Operation 13 { 14 /// <summary> Do not perform operations specific to HDR output. </summary> 15 None = 0, 16 /// <summary> Convert colors to the color space of the HDR display. </summary> 17 ColorConversion = 1 << 0, 18 /// <summary> Encode colors with the transfer function corresponding to the HDR display. </summary> 19 ColorEncoding = 1 << 1 20 } 21 22 /// <summary> 23 /// This struct Provides access to HDR display settings and information. 24 /// </summary> 25 public struct HDRDisplayInformation 26 { 27 /// <summary> 28 /// Constructs HDR Display settings. 29 /// </summary> 30 /// <param name="maxFullFrameToneMapLuminance">Maximum input luminance at which gradation is preserved even when the entire screen is bright.</param> 31 /// <param name="maxToneMapLuminance">Maximum input luminance at which gradation is preserved when 10% of the screen is bright.</param> 32 /// <param name="minToneMapLuminance">Minimum input luminance at which gradation is identifiable.</param> 33 /// <param name="hdrPaperWhiteNits">The base luminance of a white paper surface in nits or candela per square meter.</param> 34 public HDRDisplayInformation(int maxFullFrameToneMapLuminance, int maxToneMapLuminance, int minToneMapLuminance, float hdrPaperWhiteNits) 35 { 36 this.maxFullFrameToneMapLuminance = maxFullFrameToneMapLuminance; 37 this.maxToneMapLuminance = maxToneMapLuminance; 38 this.minToneMapLuminance = minToneMapLuminance; 39 this.paperWhiteNits = hdrPaperWhiteNits; 40 } 41 42 /// <summary>Maximum input luminance at which gradation is preserved even when the entire screen is bright. </summary> 43 public int maxFullFrameToneMapLuminance; 44 45 /// <summary>Maximum input luminance at which gradation is preserved when 10% of the screen is bright. </summary> 46 public int maxToneMapLuminance; 47 48 /// <summary>Minimum input luminance at which gradation is identifiable. </summary> 49 public int minToneMapLuminance; 50 51 /// <summary>The base luminance of a white paper surface in nits or candela per square meter. </summary> 52 public float paperWhiteNits; 53 } 54 55 /// <summary>Shader keywords for communicating with the HDR Output shader implementation.</summary> 56 public static class ShaderKeywords 57 { 58 /// <summary>Keyword string for converting to the correct output color space. </summary> 59 public const string HDR_COLORSPACE_CONVERSION = "HDR_COLORSPACE_CONVERSION"; 60 61 /// <summary>Keyword string for applying the color encoding. </summary> 62 public const string HDR_ENCODING = "HDR_ENCODING"; 63 64 /// <summary>Keyword string for converting to the correct output color space and applying the color encoding. </summary> 65 public const string HDR_COLORSPACE_CONVERSION_AND_ENCODING = "HDR_COLORSPACE_CONVERSION_AND_ENCODING"; 66 67 /// <summary>Keyword string to enable when a shader must be aware the input color space is in nits HDR range. </summary> 68 public const string HDR_INPUT = "HDR_INPUT"; 69 70 /// <summary>Keyword for converting to the correct output color space. </summary> 71 internal static readonly ShaderKeyword HDRColorSpaceConversion = new ShaderKeyword(HDR_COLORSPACE_CONVERSION); 72 73 /// <summary>Keyword for applying the color encoding. </summary> 74 internal static readonly ShaderKeyword HDREncoding = new ShaderKeyword(HDR_ENCODING); 75 76 /// <summary>Keyword for converting to the correct output color space and applying the color encoding. </summary> 77 internal static readonly ShaderKeyword HDRColorSpaceConversionAndEncoding = new ShaderKeyword(HDR_COLORSPACE_CONVERSION_AND_ENCODING); 78 79 /// <summary>Keyword to enable when a shader must be aware the input color space is in nits HDR range. </summary> 80 internal static readonly ShaderKeyword HDRInput = new ShaderKeyword(HDR_INPUT); 81 } 82 83 static class ShaderPropertyId 84 { 85 public static readonly int hdrColorSpace = Shader.PropertyToID("_HDRColorspace"); 86 public static readonly int hdrEncoding = Shader.PropertyToID("_HDREncoding"); 87 } 88 89 /// <summary> 90 /// Extracts the color space part of the ColorGamut 91 /// </summary> 92 /// <param name="gamut">Color gamut (a combination of color space and encoding) queried from the device.</param> 93 /// <param name="colorspace">The HDRColorspace value the color gamut contains as an int.</param> 94 /// <returns>Returns true if there was a valid HDRColorspace for the ColorGamut, false otherwise</returns> 95 public static bool GetColorSpaceForGamut(ColorGamut gamut, out int colorspace) 96 { 97 WhitePoint whitePoint = ColorGamutUtility.GetWhitePoint(gamut); 98 if (whitePoint != WhitePoint.D65) 99 { 100 Debug.LogWarningFormat("{0} white point is currently unsupported for outputting to HDR.", gamut.ToString()); 101 colorspace = -1; 102 return false; 103 } 104 105 ColorPrimaries primaries = ColorGamutUtility.GetColorPrimaries(gamut); 106 switch (primaries) 107 { 108 case ColorPrimaries.Rec709: 109 colorspace = (int)HDRColorspace.Rec709; 110 return true; 111 112 case ColorPrimaries.Rec2020: 113 colorspace = (int)HDRColorspace.Rec2020; 114 return true; 115 116 case ColorPrimaries.P3: 117 colorspace = (int)HDRColorspace.P3D65; 118 return true; 119 120 default: 121 Debug.LogWarningFormat("{0} color space is currently unsupported for outputting to HDR.", gamut.ToString()); 122 colorspace = -1; 123 return false; 124 } 125 } 126 127 /// <summary> 128 /// Extracts the encoding part of the ColorGamut 129 /// </summary> 130 /// <param name="gamut">Color gamut (a combination of color space and encoding) queried from the device.</param> 131 /// <param name="encoding">The HDREncoding value the color gamut contains as an int.</param> 132 /// <returns>Returns true if there was a valid HDREncoding for the ColorGamut, false otherwise</returns> 133 public static bool GetColorEncodingForGamut(ColorGamut gamut, out int encoding) 134 { 135 TransferFunction transferFunction = ColorGamutUtility.GetTransferFunction(gamut); 136 switch (transferFunction) 137 { 138 case TransferFunction.Linear: 139 encoding = (int)HDREncoding.Linear; 140 return true; 141 142 case TransferFunction.PQ: 143 encoding = (int)HDREncoding.PQ; 144 return true; 145 146 case TransferFunction.Gamma22: 147 encoding = (int)HDREncoding.Gamma22; 148 return true; 149 150 case TransferFunction.sRGB: 151 encoding = (int)HDREncoding.sRGB; 152 return true; 153 154 default: 155 Debug.LogWarningFormat("{0} color encoding is currently unsupported for outputting to HDR.", gamut.ToString()); 156 encoding = -1; 157 return false; 158 } 159 160 } 161 162 /// <summary> 163 /// Configures the Material keywords to use HDR output parameters. 164 /// </summary> 165 /// <param name="material">The Material used with HDR output.</param> 166 /// <param name="gamut">Color gamut (a combination of color space and encoding) queried from the device.</param> 167 /// <param name="operations">HDR color operations the shader applies.</param> 168 public static void ConfigureHDROutput(Material material, ColorGamut gamut, Operation operations) 169 { 170 int colorSpace; 171 int encoding; 172 if (!GetColorSpaceForGamut(gamut, out colorSpace) || !GetColorEncodingForGamut(gamut, out encoding)) 173 return; // only exit here if there is an error or unsupported mode 174 175 material.SetInteger(ShaderPropertyId.hdrColorSpace, colorSpace); 176 material.SetInteger(ShaderPropertyId.hdrEncoding, encoding); 177 178 CoreUtils.SetKeyword(material, ShaderKeywords.HDRColorSpaceConversionAndEncoding.name, operations.HasFlag(Operation.ColorConversion) && operations.HasFlag(Operation.ColorEncoding)); 179 CoreUtils.SetKeyword(material, ShaderKeywords.HDREncoding.name, operations.HasFlag(Operation.ColorEncoding) && !operations.HasFlag(Operation.ColorConversion)); 180 CoreUtils.SetKeyword(material, ShaderKeywords.HDRColorSpaceConversion.name, operations.HasFlag(Operation.ColorConversion) && !operations.HasFlag(Operation.ColorEncoding)); 181 182 // Optimizing shader variants: define HDR_INPUT only if HDR_COLORSPACE_CONVERSION and HDR_ENCODING were not previously defined 183 CoreUtils.SetKeyword(material, ShaderKeywords.HDRInput.name, operations == Operation.None); 184 } 185 186 /// <summary> 187 /// Configures the Material Property Block variables to use HDR output parameters. 188 /// </summary> 189 /// <param name="properties">The Material Property Block used with HDR output.</param> 190 /// <param name="gamut">Color gamut (a combination of color space and encoding) queried from the device.</param> 191 public static void ConfigureHDROutput(MaterialPropertyBlock properties, ColorGamut gamut) 192 { 193 int colorSpace; 194 int encoding; 195 if (!GetColorSpaceForGamut(gamut, out colorSpace) || !GetColorEncodingForGamut(gamut, out encoding)) 196 return; 197 198 properties.SetInteger(ShaderPropertyId.hdrColorSpace, colorSpace); 199 properties.SetInteger(ShaderPropertyId.hdrEncoding, encoding); 200 } 201 202 /// <summary> 203 /// Configures the Material keywords to use HDR output parameters. 204 /// </summary> 205 /// <param name="material">The Material used with HDR output.</param> 206 /// <param name="operations">HDR color operations the shader applies.</param> 207 public static void ConfigureHDROutput(Material material, Operation operations) 208 { 209 CoreUtils.SetKeyword(material, ShaderKeywords.HDRColorSpaceConversionAndEncoding.name, operations.HasFlag(Operation.ColorConversion) && operations.HasFlag(Operation.ColorEncoding)); 210 CoreUtils.SetKeyword(material, ShaderKeywords.HDREncoding.name, operations.HasFlag(Operation.ColorEncoding) && !operations.HasFlag(Operation.ColorConversion)); 211 CoreUtils.SetKeyword(material, ShaderKeywords.HDRColorSpaceConversion.name, operations.HasFlag(Operation.ColorConversion) && !operations.HasFlag(Operation.ColorEncoding)); 212 213 // Optimizing shader variants: define HDR_INPUT only if HDR_COLORSPACE_CONVERSION and HDR_ENCODING were not previously defined 214 CoreUtils.SetKeyword(material, ShaderKeywords.HDRInput.name, operations == Operation.None); 215 } 216 217 /// <summary> 218 /// Configures the compute shader keywords to use HDR output parameters. 219 /// </summary> 220 /// <param name="computeShader">The compute shader used with HDR output.</param> 221 /// <param name="gamut">Color gamut (a combination of color space and encoding) queried from the device.</param> 222 /// <param name="operations">HDR color operations the shader applies.</param> 223 public static void ConfigureHDROutput(ComputeShader computeShader, ColorGamut gamut, Operation operations) 224 { 225 int colorSpace; 226 int encoding; 227 if (!GetColorSpaceForGamut(gamut, out colorSpace) || !GetColorEncodingForGamut(gamut, out encoding)) 228 return; // only exit here if there is an error or unsupported mode 229 230 computeShader.SetInt(ShaderPropertyId.hdrColorSpace, colorSpace); 231 computeShader.SetInt(ShaderPropertyId.hdrEncoding, encoding); 232 233 CoreUtils.SetKeyword(computeShader, ShaderKeywords.HDRColorSpaceConversionAndEncoding.name, operations.HasFlag(Operation.ColorConversion) && operations.HasFlag(Operation.ColorEncoding)); 234 CoreUtils.SetKeyword(computeShader, ShaderKeywords.HDREncoding.name, operations.HasFlag(Operation.ColorEncoding) && !operations.HasFlag(Operation.ColorConversion)); 235 CoreUtils.SetKeyword(computeShader, ShaderKeywords.HDRColorSpaceConversion.name, operations.HasFlag(Operation.ColorConversion) && !operations.HasFlag(Operation.ColorEncoding)); 236 237 // Optimizing shader variants: define HDR_INPUT only if HDR_COLORSPACE_CONVERSION and HDR_ENCODING were not previously defined 238 CoreUtils.SetKeyword(computeShader, ShaderKeywords.HDRInput.name, operations == Operation.None); 239 } 240 241 /// <summary> 242 /// Returns true if the given set of keywords is valid for HDR output. 243 /// </summary> 244 /// <param name="shaderKeywordSet">Shader keywords combination that represents a shader variant.</param> 245 /// <param name="isHDREnabled">Whether HDR output shader variants are required.</param> 246 /// <returns>True if the shader variant is valid and should not be stripped.</returns> 247 public static bool IsShaderVariantValid(ShaderKeywordSet shaderKeywordSet, bool isHDREnabled) 248 { 249 bool hasHDRKeywords = shaderKeywordSet.IsEnabled(ShaderKeywords.HDREncoding) || shaderKeywordSet.IsEnabled(ShaderKeywords.HDRColorSpaceConversion) || shaderKeywordSet.IsEnabled(ShaderKeywords.HDRColorSpaceConversionAndEncoding) || shaderKeywordSet.IsEnabled(ShaderKeywords.HDRInput); 250 251 // If we don't plan to enable HDR, remove all HDR Output variants 252 if (!isHDREnabled && hasHDRKeywords) 253 return false; 254 255 return true; 256 } 257 } 258}