/ src / Ryujinx.Graphics.OpenGL / HwCapabilities.cs
HwCapabilities.cs
  1  using OpenTK.Graphics.OpenGL;
  2  using System;
  3  
  4  namespace Ryujinx.Graphics.OpenGL
  5  {
  6      static class HwCapabilities
  7      {
  8          private static readonly Lazy<bool> _supportsAlphaToCoverageDitherControl = new(() => HasExtension("GL_NV_alpha_to_coverage_dither_control"));
  9          private static readonly Lazy<bool> _supportsAstcCompression = new(() => HasExtension("GL_KHR_texture_compression_astc_ldr"));
 10          private static readonly Lazy<bool> _supportsBlendEquationAdvanced = new(() => HasExtension("GL_NV_blend_equation_advanced"));
 11          private static readonly Lazy<bool> _supportsDrawTexture = new(() => HasExtension("GL_NV_draw_texture"));
 12          private static readonly Lazy<bool> _supportsFragmentShaderInterlock = new(() => HasExtension("GL_ARB_fragment_shader_interlock"));
 13          private static readonly Lazy<bool> _supportsFragmentShaderOrdering = new(() => HasExtension("GL_INTEL_fragment_shader_ordering"));
 14          private static readonly Lazy<bool> _supportsGeometryShaderPassthrough = new(() => HasExtension("GL_NV_geometry_shader_passthrough"));
 15          private static readonly Lazy<bool> _supportsImageLoadFormatted = new(() => HasExtension("GL_EXT_shader_image_load_formatted"));
 16          private static readonly Lazy<bool> _supportsIndirectParameters = new(() => HasExtension("GL_ARB_indirect_parameters"));
 17          private static readonly Lazy<bool> _supportsParallelShaderCompile = new(() => HasExtension("GL_ARB_parallel_shader_compile"));
 18          private static readonly Lazy<bool> _supportsPolygonOffsetClamp = new(() => HasExtension("GL_EXT_polygon_offset_clamp"));
 19          private static readonly Lazy<bool> _supportsQuads = new(SupportsQuadsCheck);
 20          private static readonly Lazy<bool> _supportsSeamlessCubemapPerTexture = new(() => HasExtension("GL_ARB_seamless_cubemap_per_texture"));
 21          private static readonly Lazy<bool> _supportsShaderBallot = new(() => HasExtension("GL_ARB_shader_ballot"));
 22          private static readonly Lazy<bool> _supportsShaderViewportLayerArray = new(() => HasExtension("GL_ARB_shader_viewport_layer_array"));
 23          private static readonly Lazy<bool> _supportsViewportArray2 = new(() => HasExtension("GL_NV_viewport_array2"));
 24          private static readonly Lazy<bool> _supportsTextureCompressionBptc = new(() => HasExtension("GL_EXT_texture_compression_bptc"));
 25          private static readonly Lazy<bool> _supportsTextureCompressionRgtc = new(() => HasExtension("GL_EXT_texture_compression_rgtc"));
 26          private static readonly Lazy<bool> _supportsTextureCompressionS3tc = new(() => HasExtension("GL_EXT_texture_compression_s3tc"));
 27          private static readonly Lazy<bool> _supportsTextureShadowLod = new(() => HasExtension("GL_EXT_texture_shadow_lod"));
 28          private static readonly Lazy<bool> _supportsViewportSwizzle = new(() => HasExtension("GL_NV_viewport_swizzle"));
 29  
 30          private static readonly Lazy<int> _maximumComputeSharedMemorySize = new(() => GetLimit(All.MaxComputeSharedMemorySize));
 31          private static readonly Lazy<int> _storageBufferOffsetAlignment = new(() => GetLimit(All.ShaderStorageBufferOffsetAlignment));
 32          private static readonly Lazy<int> _textureBufferOffsetAlignment = new(() => GetLimit(All.TextureBufferOffsetAlignment));
 33  
 34          public enum GpuVendor
 35          {
 36              Unknown,
 37              AmdWindows,
 38              AmdUnix,
 39              IntelWindows,
 40              IntelUnix,
 41              Nvidia,
 42          }
 43  
 44          private static readonly Lazy<GpuVendor> _gpuVendor = new(GetGpuVendor);
 45  
 46          private static bool IsIntel => _gpuVendor.Value == GpuVendor.IntelWindows || _gpuVendor.Value == GpuVendor.IntelUnix;
 47  
 48          public static GpuVendor Vendor => _gpuVendor.Value;
 49  
 50          private static readonly Lazy<float> _maxSupportedAnisotropy = new(GL.GetFloat((GetPName)All.MaxTextureMaxAnisotropy));
 51  
 52          public static bool UsePersistentBufferForFlush => _gpuVendor.Value == GpuVendor.AmdWindows || _gpuVendor.Value == GpuVendor.Nvidia;
 53  
 54          public static bool SupportsAlphaToCoverageDitherControl => _supportsAlphaToCoverageDitherControl.Value;
 55          public static bool SupportsAstcCompression => _supportsAstcCompression.Value;
 56          public static bool SupportsBlendEquationAdvanced => _supportsBlendEquationAdvanced.Value;
 57          public static bool SupportsDrawTexture => _supportsDrawTexture.Value;
 58          public static bool SupportsFragmentShaderInterlock => _supportsFragmentShaderInterlock.Value;
 59          public static bool SupportsFragmentShaderOrdering => _supportsFragmentShaderOrdering.Value;
 60          public static bool SupportsGeometryShaderPassthrough => _supportsGeometryShaderPassthrough.Value;
 61          public static bool SupportsImageLoadFormatted => _supportsImageLoadFormatted.Value;
 62          public static bool SupportsIndirectParameters => _supportsIndirectParameters.Value;
 63          public static bool SupportsParallelShaderCompile => _supportsParallelShaderCompile.Value;
 64          public static bool SupportsPolygonOffsetClamp => _supportsPolygonOffsetClamp.Value;
 65          public static bool SupportsQuads => _supportsQuads.Value;
 66          public static bool SupportsSeamlessCubemapPerTexture => _supportsSeamlessCubemapPerTexture.Value;
 67          public static bool SupportsShaderBallot => _supportsShaderBallot.Value;
 68          public static bool SupportsShaderViewportLayerArray => _supportsShaderViewportLayerArray.Value;
 69          public static bool SupportsViewportArray2 => _supportsViewportArray2.Value;
 70          public static bool SupportsTextureCompressionBptc => _supportsTextureCompressionBptc.Value;
 71          public static bool SupportsTextureCompressionRgtc => _supportsTextureCompressionRgtc.Value;
 72          public static bool SupportsTextureCompressionS3tc => _supportsTextureCompressionS3tc.Value;
 73          public static bool SupportsTextureShadowLod => _supportsTextureShadowLod.Value;
 74          public static bool SupportsViewportSwizzle => _supportsViewportSwizzle.Value;
 75  
 76          public static bool SupportsMismatchingViewFormat => _gpuVendor.Value != GpuVendor.AmdWindows && _gpuVendor.Value != GpuVendor.IntelWindows;
 77          public static bool SupportsNonConstantTextureOffset => _gpuVendor.Value == GpuVendor.Nvidia;
 78          public static bool RequiresSyncFlush => _gpuVendor.Value == GpuVendor.AmdWindows || IsIntel;
 79  
 80          public static int MaximumComputeSharedMemorySize => _maximumComputeSharedMemorySize.Value;
 81          public static int StorageBufferOffsetAlignment => _storageBufferOffsetAlignment.Value;
 82          public static int TextureBufferOffsetAlignment => _textureBufferOffsetAlignment.Value;
 83  
 84          public static float MaximumSupportedAnisotropy => _maxSupportedAnisotropy.Value;
 85  
 86          private static bool HasExtension(string name)
 87          {
 88              int numExtensions = GL.GetInteger(GetPName.NumExtensions);
 89  
 90              for (int extension = 0; extension < numExtensions; extension++)
 91              {
 92                  if (GL.GetString(StringNameIndexed.Extensions, extension) == name)
 93                  {
 94                      return true;
 95                  }
 96              }
 97  
 98              return false;
 99          }
100  
101          private static int GetLimit(All name)
102          {
103              return GL.GetInteger((GetPName)name);
104          }
105  
106          private static GpuVendor GetGpuVendor()
107          {
108              string vendor = GL.GetString(StringName.Vendor).ToLowerInvariant();
109  
110              if (vendor == "nvidia corporation")
111              {
112                  return GpuVendor.Nvidia;
113              }
114              else if (vendor == "intel")
115              {
116                  string renderer = GL.GetString(StringName.Renderer).ToLowerInvariant();
117  
118                  return renderer.Contains("mesa") ? GpuVendor.IntelUnix : GpuVendor.IntelWindows;
119              }
120              else if (vendor == "ati technologies inc." || vendor == "advanced micro devices, inc.")
121              {
122                  return GpuVendor.AmdWindows;
123              }
124              else if (vendor == "amd" || vendor == "x.org")
125              {
126                  return GpuVendor.AmdUnix;
127              }
128              else
129              {
130                  return GpuVendor.Unknown;
131              }
132          }
133  
134          private static bool SupportsQuadsCheck()
135          {
136              GL.GetError(); // Clear any existing error.
137              GL.Begin(PrimitiveType.Quads);
138              GL.End();
139  
140              return GL.GetError() == ErrorCode.NoError;
141          }
142      }
143  }