TextureXR.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. using UnityEngine.Experimental.Rendering;
  2. namespace UnityEngine.Rendering
  3. {
  4. /// <summary>
  5. /// Utility class providing default textures compatible in any XR setup.
  6. /// </summary>
  7. public static class TextureXR
  8. {
  9. // Property set by XRSystem
  10. private static int m_MaxViews = 1;
  11. /// <summary>
  12. /// Maximum number of views handled by the XR system.
  13. /// </summary>
  14. public static int maxViews
  15. {
  16. set
  17. {
  18. m_MaxViews = value;
  19. }
  20. }
  21. // Property accessed when allocating a render target
  22. /// <summary>
  23. /// Number of slices used by the XR system.
  24. /// </summary>
  25. public static int slices { get => m_MaxViews; }
  26. // Must be in sync with shader define in TextureXR.hlsl
  27. /// <summary>
  28. /// Returns true if the XR system uses texture arrays.
  29. /// </summary>
  30. public static bool useTexArray
  31. {
  32. get
  33. {
  34. switch (SystemInfo.graphicsDeviceType)
  35. {
  36. case GraphicsDeviceType.Direct3D11:
  37. case GraphicsDeviceType.Direct3D12:
  38. case GraphicsDeviceType.PlayStation4:
  39. case GraphicsDeviceType.PlayStation5:
  40. case GraphicsDeviceType.Vulkan:
  41. return true;
  42. default:
  43. return false;
  44. }
  45. }
  46. }
  47. /// <summary>
  48. /// Dimension of XR textures.
  49. /// </summary>
  50. public static TextureDimension dimension
  51. {
  52. get
  53. {
  54. // TEXTURE2D_X macros will now expand to TEXTURE2D or TEXTURE2D_ARRAY
  55. return useTexArray ? TextureDimension.Tex2DArray : TextureDimension.Tex2D;
  56. }
  57. }
  58. // Need to keep both the Texture and the RTHandle in order to be able to track lifetime properly.
  59. static Texture m_BlackUIntTexture2DArray;
  60. static Texture m_BlackUIntTexture;
  61. static RTHandle m_BlackUIntTexture2DArrayRTH;
  62. static RTHandle m_BlackUIntTextureRTH;
  63. /// <summary>
  64. /// Default black unsigned integer texture.
  65. /// </summary>
  66. /// <returns>The default black unsigned integer texture.</returns>
  67. public static RTHandle GetBlackUIntTexture() { return useTexArray ? m_BlackUIntTexture2DArrayRTH : m_BlackUIntTextureRTH; }
  68. static Texture2DArray m_ClearTexture2DArray;
  69. static Texture2D m_ClearTexture;
  70. static RTHandle m_ClearTexture2DArrayRTH;
  71. static RTHandle m_ClearTextureRTH;
  72. /// <summary>
  73. /// Default clear color (0, 0, 0, 1) texture.
  74. /// </summary>
  75. /// <returns>The default clear color texture.</returns>
  76. public static RTHandle GetClearTexture() { return useTexArray ? m_ClearTexture2DArrayRTH : m_ClearTextureRTH; }
  77. static Texture2DArray m_MagentaTexture2DArray;
  78. static Texture2D m_MagentaTexture;
  79. static RTHandle m_MagentaTexture2DArrayRTH;
  80. static RTHandle m_MagentaTextureRTH;
  81. /// <summary>
  82. /// Default magenta texture.
  83. /// </summary>
  84. /// <returns>The default magenta texture.</returns>
  85. public static RTHandle GetMagentaTexture() { return useTexArray ? m_MagentaTexture2DArrayRTH : m_MagentaTextureRTH; }
  86. static Texture2D m_BlackTexture;
  87. static Texture3D m_BlackTexture3D;
  88. static Texture2DArray m_BlackTexture2DArray;
  89. static RTHandle m_BlackTexture2DArrayRTH;
  90. static RTHandle m_BlackTextureRTH;
  91. static RTHandle m_BlackTexture3DRTH;
  92. /// <summary>
  93. /// Default black texture.
  94. /// </summary>
  95. /// <returns>The default black texture.</returns>
  96. public static RTHandle GetBlackTexture() { return useTexArray ? m_BlackTexture2DArrayRTH : m_BlackTextureRTH; }
  97. /// <summary>
  98. /// Default black texture array.
  99. /// </summary>
  100. /// <returns>The default black texture array.</returns>
  101. public static RTHandle GetBlackTextureArray() { return m_BlackTexture2DArrayRTH; }
  102. /// <summary>
  103. /// Default black texture 3D.
  104. /// </summary>
  105. /// <returns>The default black texture 3D.</returns>
  106. public static RTHandle GetBlackTexture3D() { return m_BlackTexture3DRTH; }
  107. static Texture2DArray m_WhiteTexture2DArray;
  108. static RTHandle m_WhiteTexture2DArrayRTH;
  109. static RTHandle m_WhiteTextureRTH;
  110. /// <summary>
  111. /// Default white texture.
  112. /// </summary>
  113. /// <returns>The default white texture.</returns>
  114. public static RTHandle GetWhiteTexture() { return useTexArray ? m_WhiteTexture2DArrayRTH : m_WhiteTextureRTH; }
  115. /// <summary>
  116. /// Initialize XR textures. Must be called at least once.
  117. /// </summary>
  118. /// <param name="cmd">Command Buffer used to initialize textures.</param>
  119. /// <param name="clearR32_UIntShader">Compute shader used to intitialize unsigned integer textures.</param>
  120. public static void Initialize(CommandBuffer cmd, ComputeShader clearR32_UIntShader)
  121. {
  122. if (m_BlackUIntTexture2DArray == null) // We assume that everything is invalid if one is invalid.
  123. {
  124. // Black UINT
  125. RTHandles.Release(m_BlackUIntTexture2DArrayRTH);
  126. m_BlackUIntTexture2DArray = CreateBlackUIntTextureArray(cmd, clearR32_UIntShader);
  127. m_BlackUIntTexture2DArrayRTH = RTHandles.Alloc(m_BlackUIntTexture2DArray);
  128. RTHandles.Release(m_BlackUIntTextureRTH);
  129. m_BlackUIntTexture = CreateBlackUintTexture(cmd, clearR32_UIntShader);
  130. m_BlackUIntTextureRTH = RTHandles.Alloc(m_BlackUIntTexture);
  131. // Clear
  132. RTHandles.Release(m_ClearTextureRTH);
  133. m_ClearTexture = new Texture2D(1, 1, TextureFormat.ARGB32, false) { name = "Clear Texture" };
  134. m_ClearTexture.SetPixel(0, 0, Color.clear);
  135. m_ClearTexture.Apply();
  136. m_ClearTextureRTH = RTHandles.Alloc(m_ClearTexture);
  137. RTHandles.Release(m_ClearTexture2DArrayRTH);
  138. m_ClearTexture2DArray = CreateTexture2DArrayFromTexture2D(m_ClearTexture, "Clear Texture2DArray");
  139. m_ClearTexture2DArrayRTH = RTHandles.Alloc(m_ClearTexture2DArray);
  140. // Magenta
  141. RTHandles.Release(m_MagentaTextureRTH);
  142. m_MagentaTexture = new Texture2D(1, 1, TextureFormat.ARGB32, false) { name = "Magenta Texture" };
  143. m_MagentaTexture.SetPixel(0, 0, Color.magenta);
  144. m_MagentaTexture.Apply();
  145. m_MagentaTextureRTH = RTHandles.Alloc(m_MagentaTexture);
  146. RTHandles.Release(m_MagentaTexture2DArrayRTH);
  147. m_MagentaTexture2DArray = CreateTexture2DArrayFromTexture2D(m_MagentaTexture, "Magenta Texture2DArray");
  148. m_MagentaTexture2DArrayRTH = RTHandles.Alloc(m_MagentaTexture2DArray);
  149. // Black
  150. RTHandles.Release(m_BlackTextureRTH);
  151. m_BlackTexture = new Texture2D(1, 1, GraphicsFormat.R8G8B8A8_SRGB, TextureCreationFlags.None) { name = "Black Texture" };
  152. m_BlackTexture.SetPixel(0, 0, Color.black);
  153. m_BlackTexture.Apply();
  154. m_BlackTextureRTH = RTHandles.Alloc(m_BlackTexture);
  155. RTHandles.Release(m_BlackTexture2DArrayRTH);
  156. m_BlackTexture2DArray = CreateTexture2DArrayFromTexture2D(m_BlackTexture, "Black Texture2DArray");
  157. m_BlackTexture2DArrayRTH = RTHandles.Alloc(m_BlackTexture2DArray);
  158. RTHandles.Release(m_BlackTexture3DRTH);
  159. m_BlackTexture3D = CreateBlackTexture3D("Black Texture3D");
  160. m_BlackTexture3DRTH = RTHandles.Alloc(m_BlackTexture3D);
  161. // White
  162. RTHandles.Release(m_WhiteTextureRTH);
  163. m_WhiteTextureRTH = RTHandles.Alloc(Texture2D.whiteTexture);
  164. RTHandles.Release(m_WhiteTexture2DArrayRTH);
  165. m_WhiteTexture2DArray = CreateTexture2DArrayFromTexture2D(Texture2D.whiteTexture, "White Texture2DArray");
  166. m_WhiteTexture2DArrayRTH = RTHandles.Alloc(m_WhiteTexture2DArray);
  167. }
  168. }
  169. static Texture2DArray CreateTexture2DArrayFromTexture2D(Texture2D source, string name)
  170. {
  171. Texture2DArray texArray = new Texture2DArray(source.width, source.height, slices, source.format, false) { name = name };
  172. for (int i = 0; i < slices; ++i)
  173. Graphics.CopyTexture(source, 0, 0, texArray, i, 0);
  174. return texArray;
  175. }
  176. static Texture CreateBlackUIntTextureArray(CommandBuffer cmd, ComputeShader clearR32_UIntShader)
  177. {
  178. RenderTexture blackUIntTexture2DArray = new RenderTexture(1, 1, 0, GraphicsFormat.R32_UInt)
  179. {
  180. dimension = TextureDimension.Tex2DArray,
  181. volumeDepth = slices,
  182. useMipMap = false,
  183. autoGenerateMips = false,
  184. enableRandomWrite = true,
  185. name = "Black UInt Texture Array"
  186. };
  187. blackUIntTexture2DArray.Create();
  188. // Workaround because we currently can't create a Texture2DArray using an R32_UInt format
  189. // So we create a R32_UInt RenderTarget and clear it using a compute shader, because we can't
  190. // Clear this type of target on metal devices (output type nor compatible: float4 vs uint)
  191. int kernel = clearR32_UIntShader.FindKernel("ClearUIntTextureArray");
  192. cmd.SetComputeTextureParam(clearR32_UIntShader, kernel, "_TargetArray", blackUIntTexture2DArray);
  193. cmd.DispatchCompute(clearR32_UIntShader, kernel, 1, 1, slices);
  194. return blackUIntTexture2DArray as Texture;
  195. }
  196. static Texture CreateBlackUintTexture(CommandBuffer cmd, ComputeShader clearR32_UIntShader)
  197. {
  198. RenderTexture blackUIntTexture2D = new RenderTexture(1, 1, 0, GraphicsFormat.R32_UInt)
  199. {
  200. dimension = TextureDimension.Tex2D,
  201. volumeDepth = slices,
  202. useMipMap = false,
  203. autoGenerateMips = false,
  204. enableRandomWrite = true,
  205. name = "Black UInt Texture Array"
  206. };
  207. blackUIntTexture2D.Create();
  208. // Workaround because we currently can't create a Texture2DArray using an R32_UInt format
  209. // So we create a R32_UInt RenderTarget and clear it using a compute shader, because we can't
  210. // Clear this type of target on metal devices (output type nor compatible: float4 vs uint)
  211. int kernel = clearR32_UIntShader.FindKernel("ClearUIntTexture");
  212. cmd.SetComputeTextureParam(clearR32_UIntShader, kernel, "_Target", blackUIntTexture2D);
  213. cmd.DispatchCompute(clearR32_UIntShader, kernel, 1, 1, slices);
  214. return blackUIntTexture2D as Texture;
  215. }
  216. static Texture3D CreateBlackTexture3D(string name)
  217. {
  218. Texture3D texture3D = new Texture3D(width: 1, height: 1, depth: 1, textureFormat: TextureFormat.RGBA32, mipChain: false);
  219. texture3D.name = name;
  220. texture3D.SetPixel(0, 0, 0, Color.black, 0);
  221. texture3D.Apply(updateMipmaps: false);
  222. return texture3D;
  223. }
  224. }
  225. }