aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.OpenGL/HwCapabilities.cs
blob: ba2cc2df4beb69f015e832ebc9d17b088bc8afd4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
using OpenTK.Graphics.OpenGL;
using System;

namespace Ryujinx.Graphics.OpenGL
{
    static class HwCapabilities
    {
        private static readonly Lazy<bool> _supportsAlphaToCoverageDitherControl = new Lazy<bool>(() => HasExtension("GL_NV_alpha_to_coverage_dither_control"));
        private static readonly Lazy<bool> _supportsAstcCompression              = new Lazy<bool>(() => HasExtension("GL_KHR_texture_compression_astc_ldr"));
        private static readonly Lazy<bool> _supportsDrawTexture                  = new Lazy<bool>(() => HasExtension("GL_NV_draw_texture"));
        private static readonly Lazy<bool> _supportsFragmentShaderInterlock      = new Lazy<bool>(() => HasExtension("GL_ARB_fragment_shader_interlock"));
        private static readonly Lazy<bool> _supportsFragmentShaderOrdering       = new Lazy<bool>(() => HasExtension("GL_INTEL_fragment_shader_ordering"));
        private static readonly Lazy<bool> _supportsGeometryShaderPassthrough    = new Lazy<bool>(() => HasExtension("GL_NV_geometry_shader_passthrough"));
        private static readonly Lazy<bool> _supportsImageLoadFormatted           = new Lazy<bool>(() => HasExtension("GL_EXT_shader_image_load_formatted"));
        private static readonly Lazy<bool> _supportsIndirectParameters           = new Lazy<bool>(() => HasExtension("GL_ARB_indirect_parameters"));
        private static readonly Lazy<bool> _supportsParallelShaderCompile        = new Lazy<bool>(() => HasExtension("GL_ARB_parallel_shader_compile"));
        private static readonly Lazy<bool> _supportsPolygonOffsetClamp           = new Lazy<bool>(() => HasExtension("GL_EXT_polygon_offset_clamp"));
        private static readonly Lazy<bool> _supportsQuads                        = new Lazy<bool>(SupportsQuadsCheck);
        private static readonly Lazy<bool> _supportsSeamlessCubemapPerTexture    = new Lazy<bool>(() => HasExtension("GL_ARB_seamless_cubemap_per_texture"));
        private static readonly Lazy<bool> _supportsShaderBallot                 = new Lazy<bool>(() => HasExtension("GL_ARB_shader_ballot"));
        private static readonly Lazy<bool> _supportsTextureCompressionBptc       = new Lazy<bool>(() => HasExtension("GL_EXT_texture_compression_bptc"));
        private static readonly Lazy<bool> _supportsTextureCompressionRgtc       = new Lazy<bool>(() => HasExtension("GL_EXT_texture_compression_rgtc"));
        private static readonly Lazy<bool> _supportsTextureCompressionS3tc       = new Lazy<bool>(() => HasExtension("GL_EXT_texture_compression_s3tc"));
        private static readonly Lazy<bool> _supportsTextureShadowLod             = new Lazy<bool>(() => HasExtension("GL_EXT_texture_shadow_lod"));
        private static readonly Lazy<bool> _supportsViewportSwizzle              = new Lazy<bool>(() => HasExtension("GL_NV_viewport_swizzle"));

        private static readonly Lazy<int> _maximumComputeSharedMemorySize = new Lazy<int>(() => GetLimit(All.MaxComputeSharedMemorySize));
        private static readonly Lazy<int> _storageBufferOffsetAlignment   = new Lazy<int>(() => GetLimit(All.ShaderStorageBufferOffsetAlignment));

        public enum GpuVendor
        {
            Unknown,
            AmdWindows,
            AmdUnix,
            IntelWindows,
            IntelUnix,
            Nvidia
        }

        private static readonly Lazy<GpuVendor> _gpuVendor = new Lazy<GpuVendor>(GetGpuVendor);

        private static bool _isAMD   => _gpuVendor.Value == GpuVendor.AmdWindows || _gpuVendor.Value == GpuVendor.AmdUnix;
        private static bool _isIntel => _gpuVendor.Value == GpuVendor.IntelWindows || _gpuVendor.Value == GpuVendor.IntelUnix;

        public static GpuVendor Vendor => _gpuVendor.Value;

        private static Lazy<float> _maxSupportedAnisotropy = new Lazy<float>(GL.GetFloat((GetPName)All.MaxTextureMaxAnisotropy));

        public static bool UsePersistentBufferForFlush       => _gpuVendor.Value == GpuVendor.AmdWindows || _gpuVendor.Value == GpuVendor.Nvidia;

        public static bool SupportsAlphaToCoverageDitherControl => _supportsAlphaToCoverageDitherControl.Value;
        public static bool SupportsAstcCompression              => _supportsAstcCompression.Value;
        public static bool SupportsDrawTexture                  => _supportsDrawTexture.Value;
        public static bool SupportsFragmentShaderInterlock      => _supportsFragmentShaderInterlock.Value;
        public static bool SupportsFragmentShaderOrdering       => _supportsFragmentShaderOrdering.Value;
        public static bool SupportsGeometryShaderPassthrough    => _supportsGeometryShaderPassthrough.Value;
        public static bool SupportsImageLoadFormatted           => _supportsImageLoadFormatted.Value;
        public static bool SupportsIndirectParameters           => _supportsIndirectParameters.Value;
        public static bool SupportsParallelShaderCompile        => _supportsParallelShaderCompile.Value;
        public static bool SupportsPolygonOffsetClamp           => _supportsPolygonOffsetClamp.Value;
        public static bool SupportsQuads                        => _supportsQuads.Value;
        public static bool SupportsSeamlessCubemapPerTexture    => _supportsSeamlessCubemapPerTexture.Value;
        public static bool SupportsShaderBallot                 => _supportsShaderBallot.Value;
        public static bool SupportsTextureCompressionBptc       => _supportsTextureCompressionBptc.Value;
        public static bool SupportsTextureCompressionRgtc       => _supportsTextureCompressionRgtc.Value;
        public static bool SupportsTextureCompressionS3tc       => _supportsTextureCompressionS3tc.Value;
        public static bool SupportsTextureShadowLod             => _supportsTextureShadowLod.Value;
        public static bool SupportsViewportSwizzle              => _supportsViewportSwizzle.Value;

        public static bool SupportsMismatchingViewFormat    => _gpuVendor.Value != GpuVendor.AmdWindows && _gpuVendor.Value != GpuVendor.IntelWindows;
        public static bool SupportsNonConstantTextureOffset => _gpuVendor.Value == GpuVendor.Nvidia;
        public static bool RequiresSyncFlush                => _gpuVendor.Value == GpuVendor.AmdWindows || _isIntel;

        public static int MaximumComputeSharedMemorySize => _maximumComputeSharedMemorySize.Value;
        public static int StorageBufferOffsetAlignment   => _storageBufferOffsetAlignment.Value;

        public static float MaximumSupportedAnisotropy => _maxSupportedAnisotropy.Value;

        private static bool HasExtension(string name)
        {
            int numExtensions = GL.GetInteger(GetPName.NumExtensions);

            for (int extension = 0; extension < numExtensions; extension++)
            {
                if (GL.GetString(StringNameIndexed.Extensions, extension) == name)
                {
                    return true;
                }
            }

            return false;
        }

        private static int GetLimit(All name)
        {
            return GL.GetInteger((GetPName)name);
        }

        private static GpuVendor GetGpuVendor()
        {
            string vendor = GL.GetString(StringName.Vendor).ToLower();

            if (vendor == "nvidia corporation")
            {
                return GpuVendor.Nvidia;
            }
            else if (vendor == "intel")
            {
                string renderer = GL.GetString(StringName.Renderer).ToLower();

                return renderer.Contains("mesa") ? GpuVendor.IntelUnix : GpuVendor.IntelWindows;
            }
            else if (vendor == "ati technologies inc." || vendor == "advanced micro devices, inc.")
            {
                return GpuVendor.AmdWindows;
            }
            else if (vendor == "amd" || vendor == "x.org")
            {
                return GpuVendor.AmdUnix;
            }
            else
            {
                return GpuVendor.Unknown;
            }
        }

        private static bool SupportsQuadsCheck()
        {
            GL.GetError(); // Clear any existing error.
            GL.Begin(PrimitiveType.Quads);
            GL.End();

            return GL.GetError() == ErrorCode.NoError;
        }
    }
}