/ src / Ryujinx.Graphics.Gpu / Image / TextureInfo.cs
TextureInfo.cs
  1  using Ryujinx.Common;
  2  using Ryujinx.Graphics.GAL;
  3  using Ryujinx.Graphics.Texture;
  4  using System;
  5  
  6  namespace Ryujinx.Graphics.Gpu.Image
  7  {
  8      /// <summary>
  9      /// Texture information.
 10      /// </summary>
 11      readonly struct TextureInfo
 12      {
 13          /// <summary>
 14          /// Address of the texture in GPU mapped memory.
 15          /// </summary>
 16          public ulong GpuAddress { get; }
 17  
 18          /// <summary>
 19          /// The width of the texture.
 20          /// </summary>
 21          public int Width { get; }
 22  
 23          /// <summary>
 24          /// The height of the texture, or layers count for 1D array textures.
 25          /// </summary>
 26          public int Height { get; }
 27  
 28          /// <summary>
 29          /// The depth of the texture (for 3D textures), or layers count for array textures.
 30          /// </summary>
 31          public int DepthOrLayers { get; }
 32  
 33          /// <summary>
 34          /// The number of mipmap levels of the texture.
 35          /// </summary>
 36          public int Levels { get; }
 37  
 38          /// <summary>
 39          /// The number of samples in the X direction for multisampled textures.
 40          /// </summary>
 41          public int SamplesInX { get; }
 42  
 43          /// <summary>
 44          /// The number of samples in the Y direction for multisampled textures.
 45          /// </summary>
 46          public int SamplesInY { get; }
 47  
 48          /// <summary>
 49          /// The number of bytes per line for linear textures.
 50          /// </summary>
 51          public int Stride { get; }
 52  
 53          /// <summary>
 54          /// Indicates whenever or not the texture is a linear texture.
 55          /// </summary>
 56          public bool IsLinear { get; }
 57  
 58          /// <summary>
 59          /// GOB blocks in the Y direction, for block linear textures.
 60          /// </summary>
 61          public int GobBlocksInY { get; }
 62  
 63          /// <summary>
 64          /// GOB blocks in the Z direction, for block linear textures.
 65          /// </summary>
 66          public int GobBlocksInZ { get; }
 67  
 68          /// <summary>
 69          /// Number of GOB blocks per tile in the X direction, for block linear textures.
 70          /// </summary>
 71          public int GobBlocksInTileX { get; }
 72  
 73          /// <summary>
 74          /// Total number of samples for multisampled textures.
 75          /// </summary>
 76          public int Samples => SamplesInX * SamplesInY;
 77  
 78          /// <summary>
 79          /// Texture target type.
 80          /// </summary>
 81          public Target Target { get; }
 82  
 83          /// <summary>
 84          /// Texture format information.
 85          /// </summary>
 86          public FormatInfo FormatInfo { get; }
 87  
 88          /// <summary>
 89          /// Depth-stencil mode of the texture. This defines whenever the depth or stencil value is read from shaders,
 90          /// for depth-stencil texture formats.
 91          /// </summary>
 92          public DepthStencilMode DepthStencilMode { get; }
 93  
 94          /// <summary>
 95          /// Texture swizzle for the red color channel.
 96          /// </summary>
 97          public SwizzleComponent SwizzleR { get; }
 98  
 99          /// <summary>
100          /// Texture swizzle for the green color channel.
101          /// </summary>
102          public SwizzleComponent SwizzleG { get; }
103  
104          /// <summary>
105          /// Texture swizzle for the blue color channel.
106          /// </summary>
107          public SwizzleComponent SwizzleB { get; }
108  
109          /// <summary>
110          /// Texture swizzle for the alpha color channel.
111          /// </summary>
112          public SwizzleComponent SwizzleA { get; }
113  
114          /// <summary>
115          /// Constructs the texture information structure.
116          /// </summary>
117          /// <param name="gpuAddress">The GPU address of the texture</param>
118          /// <param name="width">The width of the texture</param>
119          /// <param name="height">The height or the texture</param>
120          /// <param name="depthOrLayers">The depth or layers count of the texture</param>
121          /// <param name="levels">The amount of mipmap levels of the texture</param>
122          /// <param name="samplesInX">The number of samples in the X direction for multisample textures, should be 1 otherwise</param>
123          /// <param name="samplesInY">The number of samples in the Y direction for multisample textures, should be 1 otherwise</param>
124          /// <param name="stride">The stride for linear textures</param>
125          /// <param name="isLinear">Whenever the texture is linear or block linear</param>
126          /// <param name="gobBlocksInY">Number of GOB blocks in the Y direction</param>
127          /// <param name="gobBlocksInZ">Number of GOB blocks in the Z direction</param>
128          /// <param name="gobBlocksInTileX">Number of GOB blocks per tile in the X direction</param>
129          /// <param name="target">Texture target type</param>
130          /// <param name="formatInfo">Texture format information</param>
131          /// <param name="depthStencilMode">Depth-stencil mode</param>
132          /// <param name="swizzleR">Swizzle for the red color channel</param>
133          /// <param name="swizzleG">Swizzle for the green color channel</param>
134          /// <param name="swizzleB">Swizzle for the blue color channel</param>
135          /// <param name="swizzleA">Swizzle for the alpha color channel</param>
136          public TextureInfo(
137              ulong gpuAddress,
138              int width,
139              int height,
140              int depthOrLayers,
141              int levels,
142              int samplesInX,
143              int samplesInY,
144              int stride,
145              bool isLinear,
146              int gobBlocksInY,
147              int gobBlocksInZ,
148              int gobBlocksInTileX,
149              Target target,
150              FormatInfo formatInfo,
151              DepthStencilMode depthStencilMode = DepthStencilMode.Depth,
152              SwizzleComponent swizzleR = SwizzleComponent.Red,
153              SwizzleComponent swizzleG = SwizzleComponent.Green,
154              SwizzleComponent swizzleB = SwizzleComponent.Blue,
155              SwizzleComponent swizzleA = SwizzleComponent.Alpha)
156          {
157              GpuAddress = gpuAddress;
158              Width = width;
159              Height = height;
160              DepthOrLayers = depthOrLayers;
161              Levels = levels;
162              SamplesInX = samplesInX;
163              SamplesInY = samplesInY;
164              Stride = stride;
165              IsLinear = isLinear;
166              GobBlocksInY = gobBlocksInY;
167              GobBlocksInZ = gobBlocksInZ;
168              GobBlocksInTileX = gobBlocksInTileX;
169              Target = target;
170              FormatInfo = formatInfo;
171              DepthStencilMode = depthStencilMode;
172              SwizzleR = swizzleR;
173              SwizzleG = swizzleG;
174              SwizzleB = swizzleB;
175              SwizzleA = swizzleA;
176          }
177  
178          /// <summary>
179          /// Gets the real texture depth.
180          /// Returns 1 for any target other than 3D textures.
181          /// </summary>
182          /// <returns>Texture depth</returns>
183          public int GetDepth()
184          {
185              return GetDepth(Target, DepthOrLayers);
186          }
187  
188          /// <summary>
189          /// Gets the real texture depth.
190          /// Returns 1 for any target other than 3D textures.
191          /// </summary>
192          /// <param name="target">Texture target</param>
193          /// <param name="depthOrLayers">Texture depth if the texture is 3D, otherwise ignored</param>
194          /// <returns>Texture depth</returns>
195          public static int GetDepth(Target target, int depthOrLayers)
196          {
197              return target == Target.Texture3D ? depthOrLayers : 1;
198          }
199  
200          /// <summary>
201          /// Gets the number of layers of the texture.
202          /// Returns 1 for non-array textures, 6 for cubemap textures, and layer faces for cubemap array textures.
203          /// </summary>
204          /// <returns>The number of texture layers</returns>
205          public int GetLayers()
206          {
207              return GetLayers(Target, DepthOrLayers);
208          }
209  
210          /// <summary>
211          /// Gets the number of layers of the texture.
212          /// Returns 1 for non-array textures, 6 for cubemap textures, and layer faces for cubemap array textures.
213          /// </summary>
214          /// <param name="target">Texture target</param>
215          /// <param name="depthOrLayers">Texture layers if the is a array texture, ignored otherwise</param>
216          /// <returns>The number of texture layers</returns>
217          public static int GetLayers(Target target, int depthOrLayers)
218          {
219              if (target == Target.Texture2DArray || target == Target.Texture2DMultisampleArray)
220              {
221                  return depthOrLayers;
222              }
223              else if (target == Target.CubemapArray)
224              {
225                  return depthOrLayers * 6;
226              }
227              else if (target == Target.Cubemap)
228              {
229                  return 6;
230              }
231              else
232              {
233                  return 1;
234              }
235          }
236  
237          /// <summary>
238          /// Gets the number of 2D slices of the texture.
239          /// Returns 6 for cubemap textures, layer faces for cubemap array textures, and DepthOrLayers for everything else.
240          /// </summary>
241          /// <returns>The number of texture slices</returns>
242          public int GetSlices()
243          {
244              if (Target == Target.Texture3D || Target == Target.Texture2DArray || Target == Target.Texture2DMultisampleArray)
245              {
246                  return DepthOrLayers;
247              }
248              else if (Target == Target.CubemapArray)
249              {
250                  return DepthOrLayers * 6;
251              }
252              else if (Target == Target.Cubemap)
253              {
254                  return 6;
255              }
256              else
257              {
258                  return 1;
259              }
260          }
261  
262          /// <summary>
263          /// Calculates the size information from the texture information.
264          /// </summary>
265          /// <param name="layerSize">Optional size of each texture layer in bytes</param>
266          /// <returns>Texture size information</returns>
267          public SizeInfo CalculateSizeInfo(int layerSize = 0)
268          {
269              if (Target == Target.TextureBuffer)
270              {
271                  return new SizeInfo(Width * FormatInfo.BytesPerPixel);
272              }
273              else if (IsLinear)
274              {
275                  return SizeCalculator.GetLinearTextureSize(
276                      Stride,
277                      Height,
278                      FormatInfo.BlockHeight);
279              }
280              else
281              {
282                  return SizeCalculator.GetBlockLinearTextureSize(
283                      Width,
284                      Height,
285                      GetDepth(),
286                      Levels,
287                      GetLayers(),
288                      FormatInfo.BlockWidth,
289                      FormatInfo.BlockHeight,
290                      FormatInfo.BytesPerPixel,
291                      GobBlocksInY,
292                      GobBlocksInZ,
293                      GobBlocksInTileX,
294                      layerSize);
295              }
296          }
297  
298          /// <summary>
299          /// Creates texture information for a given mipmap level of the specified parent texture and this information.
300          /// </summary>
301          /// <param name="parent">The parent texture</param>
302          /// <param name="firstLevel">The first level of the texture view</param>
303          /// <param name="parentFormat">True if the parent format should be inherited</param>
304          /// <returns>The adjusted texture information with the new size</returns>
305          public TextureInfo CreateInfoForLevelView(Texture parent, int firstLevel, bool parentFormat)
306          {
307              // When the texture is used as view of another texture, we must
308              // ensure that the sizes are valid, otherwise data uploads would fail
309              // (and the size wouldn't match the real size used on the host API).
310              // Given a parent texture from where the view is created, we have the
311              // following rules:
312              // - The view size must be equal to the parent size, divided by (2 ^ l),
313              // where l is the first mipmap level of the view. The division result must
314              // be rounded down, and the result must be clamped to 1.
315              // - If the parent format is compressed, and the view format isn't, the
316              // view size is calculated as above, but the width and height of the
317              // view must be also divided by the compressed format block width and height.
318              // - If the parent format is not compressed, and the view is, the view
319              // size is calculated as described on the first point, but the width and height
320              // of the view must be also multiplied by the block width and height.
321              int width = Math.Max(1, parent.Info.Width >> firstLevel);
322              int height = Math.Max(1, parent.Info.Height >> firstLevel);
323  
324              if (parent.Info.FormatInfo.IsCompressed && !FormatInfo.IsCompressed)
325              {
326                  width = BitUtils.DivRoundUp(width, parent.Info.FormatInfo.BlockWidth);
327                  height = BitUtils.DivRoundUp(height, parent.Info.FormatInfo.BlockHeight);
328              }
329              else if (!parent.Info.FormatInfo.IsCompressed && FormatInfo.IsCompressed)
330              {
331                  width *= FormatInfo.BlockWidth;
332                  height *= FormatInfo.BlockHeight;
333              }
334  
335              int depthOrLayers;
336  
337              if (Target == Target.Texture3D)
338              {
339                  depthOrLayers = Math.Max(1, parent.Info.DepthOrLayers >> firstLevel);
340              }
341              else
342              {
343                  depthOrLayers = DepthOrLayers;
344              }
345  
346              // 2D and 2D multisample textures are not considered compatible.
347              // This specific case is required for copies, where the source texture might be multisample.
348              // In this case, we inherit the parent texture multisample state.
349              Target target = Target;
350              int samplesInX = SamplesInX;
351              int samplesInY = SamplesInY;
352  
353              if (target == Target.Texture2D && parent.Target == Target.Texture2DMultisample)
354              {
355                  target = Target.Texture2DMultisample;
356                  samplesInX = parent.Info.SamplesInX;
357                  samplesInY = parent.Info.SamplesInY;
358              }
359  
360              return new TextureInfo(
361                  GpuAddress,
362                  width,
363                  height,
364                  depthOrLayers,
365                  Levels,
366                  samplesInX,
367                  samplesInY,
368                  Stride,
369                  IsLinear,
370                  GobBlocksInY,
371                  GobBlocksInZ,
372                  GobBlocksInTileX,
373                  target,
374                  parentFormat ? parent.Info.FormatInfo : FormatInfo,
375                  DepthStencilMode,
376                  SwizzleR,
377                  SwizzleG,
378                  SwizzleB,
379                  SwizzleA);
380          }
381  
382          /// <summary>
383          /// Creates texture information for a given format and this information.
384          /// </summary>
385          /// <param name="formatInfo">Format for the new texture info</param>
386          /// <returns>New info with the specified format</returns>
387          public TextureInfo CreateInfoWithFormat(FormatInfo formatInfo)
388          {
389              return new TextureInfo(
390                  GpuAddress,
391                  Width,
392                  Height,
393                  DepthOrLayers,
394                  Levels,
395                  SamplesInX,
396                  SamplesInY,
397                  Stride,
398                  IsLinear,
399                  GobBlocksInY,
400                  GobBlocksInZ,
401                  GobBlocksInTileX,
402                  Target,
403                  formatInfo,
404                  DepthStencilMode,
405                  SwizzleR,
406                  SwizzleG,
407                  SwizzleB,
408                  SwizzleA);
409          }
410      }
411  }