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