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}