No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

HDROutputUtils.cs 14KB

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