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}