/ src / Ryujinx.Graphics.Shader / TextureHandle.cs
TextureHandle.cs
  1  using System;
  2  using System.Runtime.CompilerServices;
  3  
  4  namespace Ryujinx.Graphics.Shader
  5  {
  6      public enum TextureHandleType
  7      {
  8          CombinedSampler = 0, // Must be 0.
  9          SeparateSamplerHandle = 1,
 10          SeparateSamplerId = 2,
 11          SeparateConstantSamplerHandle = 3,
 12          Direct = 4,
 13      }
 14  
 15      public static class TextureHandle
 16      {
 17          [MethodImpl(MethodImplOptions.AggressiveInlining)]
 18          public static int PackSlots(int cbufSlot0, int cbufSlot1)
 19          {
 20              return cbufSlot0 | ((cbufSlot1 + 1) << 16);
 21          }
 22  
 23          [MethodImpl(MethodImplOptions.AggressiveInlining)]
 24          public static (int, int) UnpackSlots(int slots, int defaultTextureBufferIndex)
 25          {
 26              int textureBufferIndex;
 27              int samplerBufferIndex;
 28  
 29              if (slots < 0)
 30              {
 31                  textureBufferIndex = defaultTextureBufferIndex;
 32                  samplerBufferIndex = textureBufferIndex;
 33              }
 34              else
 35              {
 36                  uint high = (uint)slots >> 16;
 37  
 38                  textureBufferIndex = (ushort)slots;
 39                  samplerBufferIndex = high != 0 ? (int)high - 1 : textureBufferIndex;
 40              }
 41  
 42              return (textureBufferIndex, samplerBufferIndex);
 43          }
 44  
 45          [MethodImpl(MethodImplOptions.AggressiveInlining)]
 46          public static int PackOffsets(int cbufOffset0, int cbufOffset1, TextureHandleType type)
 47          {
 48              return cbufOffset0 | (cbufOffset1 << 14) | ((int)type << 28);
 49          }
 50  
 51          [MethodImpl(MethodImplOptions.AggressiveInlining)]
 52          public static (int, int, TextureHandleType) UnpackOffsets(int handle)
 53          {
 54              return (handle & 0x3fff, (handle >> 14) & 0x3fff, (TextureHandleType)((uint)handle >> 28));
 55          }
 56  
 57          /// <summary>
 58          /// Unpacks the texture ID from the real texture handle.
 59          /// </summary>
 60          /// <param name="packedId">The real texture handle</param>
 61          /// <returns>The texture ID</returns>
 62          [MethodImpl(MethodImplOptions.AggressiveInlining)]
 63          public static int UnpackTextureId(int packedId)
 64          {
 65              return packedId & 0xfffff;
 66          }
 67  
 68          /// <summary>
 69          /// Unpacks the sampler ID from the real texture handle.
 70          /// </summary>
 71          /// <param name="packedId">The real texture handle</param>
 72          /// <returns>The sampler ID</returns>
 73          [MethodImpl(MethodImplOptions.AggressiveInlining)]
 74          public static int UnpackSamplerId(int packedId)
 75          {
 76              return (packedId >> 20) & 0xfff;
 77          }
 78  
 79          /// <summary>
 80          /// Reads a packed texture and sampler ID (basically, the real texture handle)
 81          /// from a given texture/sampler constant buffer.
 82          /// </summary>
 83          /// <param name="wordOffset">A word offset of the handle on the buffer (the "fake" shader handle)</param>
 84          /// <param name="cachedTextureBuffer">The constant buffer to fetch texture IDs from</param>
 85          /// <param name="cachedSamplerBuffer">The constant buffer to fetch sampler IDs from</param>
 86          /// <returns>The packed texture and sampler ID (the real texture handle)</returns>
 87          [MethodImpl(MethodImplOptions.AggressiveInlining)]
 88          public static int ReadPackedId(int wordOffset, ReadOnlySpan<int> cachedTextureBuffer, ReadOnlySpan<int> cachedSamplerBuffer)
 89          {
 90              (int textureWordOffset, int samplerWordOffset, TextureHandleType handleType) = UnpackOffsets(wordOffset);
 91  
 92              int handle = textureWordOffset < cachedTextureBuffer.Length ? cachedTextureBuffer[textureWordOffset] : 0;
 93  
 94              // The "wordOffset" (which is really the immediate value used on texture instructions on the shader)
 95              // is a 13-bit value. However, in order to also support separate samplers and textures (which uses
 96              // bindless textures on the shader), we extend it with another value on the higher 16 bits with
 97              // another offset for the sampler.
 98              // The shader translator has code to detect separate texture and sampler uses with a bindless texture,
 99              // turn that into a regular texture access and produce those special handles with values on the higher 16 bits.
100              if (handleType != TextureHandleType.CombinedSampler)
101              {
102                  int samplerHandle;
103  
104                  if (handleType != TextureHandleType.SeparateConstantSamplerHandle)
105                  {
106                      samplerHandle = samplerWordOffset < cachedSamplerBuffer.Length ? cachedSamplerBuffer[samplerWordOffset] : 0;
107                  }
108                  else
109                  {
110                      samplerHandle = samplerWordOffset;
111                  }
112  
113                  if (handleType == TextureHandleType.SeparateSamplerId ||
114                      handleType == TextureHandleType.SeparateConstantSamplerHandle)
115                  {
116                      samplerHandle <<= 20;
117                  }
118  
119                  handle |= samplerHandle;
120              }
121  
122              return handle;
123          }
124      }
125  }