diff options
author | gdkchan <gab.dark.100@gmail.com> | 2024-04-22 15:05:55 -0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-22 15:05:55 -0300 |
commit | c6f8bfed904e30f7c5d890a2f0ef531eb9e298e5 (patch) | |
tree | e1c048d390867e8c9403904498184e3a64277e49 | |
parent | 9b94662b4bb2ebf846e1baf45ba8097fcd7da684 (diff) |
Add support for bindless textures from shader input (vertex buffer) on Vulkan (#6577)1.1.1291
* Add support for bindless textures from shader input (vertex buffer)
* Shader cache version bump
* Format whitespace
* Remove cache entries on pool removal, disable for OpenGL
* PR feedback
39 files changed, 1086 insertions, 306 deletions
diff --git a/src/Ryujinx.Graphics.GAL/Capabilities.cs b/src/Ryujinx.Graphics.GAL/Capabilities.cs index dc927eaba..70736fbd6 100644 --- a/src/Ryujinx.Graphics.GAL/Capabilities.cs +++ b/src/Ryujinx.Graphics.GAL/Capabilities.cs | |||
@@ -36,6 +36,7 @@ namespace Ryujinx.Graphics.GAL | |||
36 | public readonly bool SupportsMismatchingViewFormat; | 36 | public readonly bool SupportsMismatchingViewFormat; |
37 | public readonly bool SupportsCubemapView; | 37 | public readonly bool SupportsCubemapView; |
38 | public readonly bool SupportsNonConstantTextureOffset; | 38 | public readonly bool SupportsNonConstantTextureOffset; |
39 | public readonly bool SupportsSeparateSampler; | ||
39 | public readonly bool SupportsShaderBallot; | 40 | public readonly bool SupportsShaderBallot; |
40 | public readonly bool SupportsShaderBarrierDivergence; | 41 | public readonly bool SupportsShaderBarrierDivergence; |
41 | public readonly bool SupportsShaderFloat64; | 42 | public readonly bool SupportsShaderFloat64; |
@@ -92,6 +93,7 @@ namespace Ryujinx.Graphics.GAL | |||
92 | bool supportsMismatchingViewFormat, | 93 | bool supportsMismatchingViewFormat, |
93 | bool supportsCubemapView, | 94 | bool supportsCubemapView, |
94 | bool supportsNonConstantTextureOffset, | 95 | bool supportsNonConstantTextureOffset, |
96 | bool supportsSeparateSampler, | ||
95 | bool supportsShaderBallot, | 97 | bool supportsShaderBallot, |
96 | bool supportsShaderBarrierDivergence, | 98 | bool supportsShaderBarrierDivergence, |
97 | bool supportsShaderFloat64, | 99 | bool supportsShaderFloat64, |
@@ -144,6 +146,7 @@ namespace Ryujinx.Graphics.GAL | |||
144 | SupportsMismatchingViewFormat = supportsMismatchingViewFormat; | 146 | SupportsMismatchingViewFormat = supportsMismatchingViewFormat; |
145 | SupportsCubemapView = supportsCubemapView; | 147 | SupportsCubemapView = supportsCubemapView; |
146 | SupportsNonConstantTextureOffset = supportsNonConstantTextureOffset; | 148 | SupportsNonConstantTextureOffset = supportsNonConstantTextureOffset; |
149 | SupportsSeparateSampler = supportsSeparateSampler; | ||
147 | SupportsShaderBallot = supportsShaderBallot; | 150 | SupportsShaderBallot = supportsShaderBallot; |
148 | SupportsShaderBarrierDivergence = supportsShaderBarrierDivergence; | 151 | SupportsShaderBarrierDivergence = supportsShaderBarrierDivergence; |
149 | SupportsShaderFloat64 = supportsShaderFloat64; | 152 | SupportsShaderFloat64 = supportsShaderFloat64; |
diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs b/src/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs index ccdbe4748..cd8144724 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs | |||
@@ -126,6 +126,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute | |||
126 | ulong samplerPoolGpuVa = ((ulong)_state.State.SetTexSamplerPoolAOffsetUpper << 32) | _state.State.SetTexSamplerPoolB; | 126 | ulong samplerPoolGpuVa = ((ulong)_state.State.SetTexSamplerPoolAOffsetUpper << 32) | _state.State.SetTexSamplerPoolB; |
127 | ulong texturePoolGpuVa = ((ulong)_state.State.SetTexHeaderPoolAOffsetUpper << 32) | _state.State.SetTexHeaderPoolB; | 127 | ulong texturePoolGpuVa = ((ulong)_state.State.SetTexHeaderPoolAOffsetUpper << 32) | _state.State.SetTexHeaderPoolB; |
128 | 128 | ||
129 | int samplerPoolMaximumId = _state.State.SetTexSamplerPoolCMaximumIndex; | ||
130 | |||
129 | GpuChannelPoolState poolState = new( | 131 | GpuChannelPoolState poolState = new( |
130 | texturePoolGpuVa, | 132 | texturePoolGpuVa, |
131 | _state.State.SetTexHeaderPoolCMaximumIndex, | 133 | _state.State.SetTexHeaderPoolCMaximumIndex, |
@@ -139,7 +141,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute | |||
139 | sharedMemorySize, | 141 | sharedMemorySize, |
140 | _channel.BufferManager.HasUnalignedStorageBuffers); | 142 | _channel.BufferManager.HasUnalignedStorageBuffers); |
141 | 143 | ||
142 | CachedShaderProgram cs = memoryManager.Physical.ShaderCache.GetComputeShader(_channel, poolState, computeState, shaderGpuVa); | 144 | CachedShaderProgram cs = memoryManager.Physical.ShaderCache.GetComputeShader(_channel, samplerPoolMaximumId, poolState, computeState, shaderGpuVa); |
143 | 145 | ||
144 | _context.Renderer.Pipeline.SetProgram(cs.HostProgram); | 146 | _context.Renderer.Pipeline.SetProgram(cs.HostProgram); |
145 | 147 | ||
@@ -184,7 +186,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute | |||
184 | sharedMemorySize, | 186 | sharedMemorySize, |
185 | _channel.BufferManager.HasUnalignedStorageBuffers); | 187 | _channel.BufferManager.HasUnalignedStorageBuffers); |
186 | 188 | ||
187 | cs = memoryManager.Physical.ShaderCache.GetComputeShader(_channel, poolState, computeState, shaderGpuVa); | 189 | cs = memoryManager.Physical.ShaderCache.GetComputeShader(_channel, samplerPoolMaximumId, poolState, computeState, shaderGpuVa); |
188 | 190 | ||
189 | _context.Renderer.Pipeline.SetProgram(cs.HostProgram); | 191 | _context.Renderer.Pipeline.SetProgram(cs.HostProgram); |
190 | } | 192 | } |
diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs index b3eb62185..1dc77b52d 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs | |||
@@ -1429,7 +1429,18 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed | |||
1429 | addressesSpan[index] = baseAddress + shader.Offset; | 1429 | addressesSpan[index] = baseAddress + shader.Offset; |
1430 | } | 1430 | } |
1431 | 1431 | ||
1432 | CachedShaderProgram gs = shaderCache.GetGraphicsShader(ref _state.State, ref _pipeline, _channel, ref _currentSpecState.GetPoolState(), ref _currentSpecState.GetGraphicsState(), addresses); | 1432 | int samplerPoolMaximumId = _state.State.SamplerIndex == SamplerIndex.ViaHeaderIndex |
1433 | ? _state.State.TexturePoolState.MaximumId | ||
1434 | : _state.State.SamplerPoolState.MaximumId; | ||
1435 | |||
1436 | CachedShaderProgram gs = shaderCache.GetGraphicsShader( | ||
1437 | ref _state.State, | ||
1438 | ref _pipeline, | ||
1439 | _channel, | ||
1440 | samplerPoolMaximumId, | ||
1441 | ref _currentSpecState.GetPoolState(), | ||
1442 | ref _currentSpecState.GetGraphicsState(), | ||
1443 | addresses); | ||
1433 | 1444 | ||
1434 | // Consume the modified flag for spec state so that it isn't checked again. | 1445 | // Consume the modified flag for spec state so that it isn't checked again. |
1435 | _currentSpecState.SetShader(gs); | 1446 | _currentSpecState.SetShader(gs); |
diff --git a/src/Ryujinx.Graphics.Gpu/Image/PoolCache.cs b/src/Ryujinx.Graphics.Gpu/Image/PoolCache.cs index d9881f897..50872ab63 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/PoolCache.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/PoolCache.cs | |||
@@ -62,8 +62,9 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
62 | /// <param name="channel">GPU channel that the texture pool cache belongs to</param> | 62 | /// <param name="channel">GPU channel that the texture pool cache belongs to</param> |
63 | /// <param name="address">Start address of the texture pool</param> | 63 | /// <param name="address">Start address of the texture pool</param> |
64 | /// <param name="maximumId">Maximum ID of the texture pool</param> | 64 | /// <param name="maximumId">Maximum ID of the texture pool</param> |
65 | /// <param name="bindingsArrayCache">Cache of texture array bindings</param> | ||
65 | /// <returns>The found or newly created texture pool</returns> | 66 | /// <returns>The found or newly created texture pool</returns> |
66 | public T FindOrCreate(GpuChannel channel, ulong address, int maximumId) | 67 | public T FindOrCreate(GpuChannel channel, ulong address, int maximumId, TextureBindingsArrayCache bindingsArrayCache) |
67 | { | 68 | { |
68 | // Remove old entries from the cache, if possible. | 69 | // Remove old entries from the cache, if possible. |
69 | while (_pools.Count > MaxCapacity && (_currentTimestamp - _pools.First.Value.CacheTimestamp) >= MinDeltaForRemoval) | 70 | while (_pools.Count > MaxCapacity && (_currentTimestamp - _pools.First.Value.CacheTimestamp) >= MinDeltaForRemoval) |
@@ -73,6 +74,7 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
73 | _pools.RemoveFirst(); | 74 | _pools.RemoveFirst(); |
74 | oldestPool.Dispose(); | 75 | oldestPool.Dispose(); |
75 | oldestPool.CacheNode = null; | 76 | oldestPool.CacheNode = null; |
77 | bindingsArrayCache.RemoveAllWithPool(oldestPool); | ||
76 | } | 78 | } |
77 | 79 | ||
78 | T pool; | 80 | T pool; |
@@ -87,8 +89,7 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
87 | if (pool.CacheNode != _pools.Last) | 89 | if (pool.CacheNode != _pools.Last) |
88 | { | 90 | { |
89 | _pools.Remove(pool.CacheNode); | 91 | _pools.Remove(pool.CacheNode); |
90 | 92 | _pools.AddLast(pool.CacheNode); | |
91 | pool.CacheNode = _pools.AddLast(pool); | ||
92 | } | 93 | } |
93 | 94 | ||
94 | pool.CacheTimestamp = _currentTimestamp; | 95 | pool.CacheTimestamp = _currentTimestamp; |
diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureBindingInfo.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureBindingInfo.cs index 12a457dbc..ba895c60a 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/TextureBindingInfo.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/TextureBindingInfo.cs | |||
@@ -45,6 +45,11 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
45 | public TextureUsageFlags Flags { get; } | 45 | public TextureUsageFlags Flags { get; } |
46 | 46 | ||
47 | /// <summary> | 47 | /// <summary> |
48 | /// Indicates that the binding is for a sampler. | ||
49 | /// </summary> | ||
50 | public bool IsSamplerOnly { get; } | ||
51 | |||
52 | /// <summary> | ||
48 | /// Constructs the texture binding information structure. | 53 | /// Constructs the texture binding information structure. |
49 | /// </summary> | 54 | /// </summary> |
50 | /// <param name="target">The shader sampler target type</param> | 55 | /// <param name="target">The shader sampler target type</param> |
@@ -74,8 +79,17 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
74 | /// <param name="cbufSlot">Constant buffer slot where the texture handle is located</param> | 79 | /// <param name="cbufSlot">Constant buffer slot where the texture handle is located</param> |
75 | /// <param name="handle">The shader texture handle (read index into the texture constant buffer)</param> | 80 | /// <param name="handle">The shader texture handle (read index into the texture constant buffer)</param> |
76 | /// <param name="flags">The texture's usage flags, indicating how it is used in the shader</param> | 81 | /// <param name="flags">The texture's usage flags, indicating how it is used in the shader</param> |
77 | public TextureBindingInfo(Target target, int binding, int arrayLength, int cbufSlot, int handle, TextureUsageFlags flags) : this(target, (Format)0, binding, arrayLength, cbufSlot, handle, flags) | 82 | /// <param name="isSamplerOnly">Indicates that the binding is for a sampler</param> |
83 | public TextureBindingInfo( | ||
84 | Target target, | ||
85 | int binding, | ||
86 | int arrayLength, | ||
87 | int cbufSlot, | ||
88 | int handle, | ||
89 | TextureUsageFlags flags, | ||
90 | bool isSamplerOnly) : this(target, 0, binding, arrayLength, cbufSlot, handle, flags) | ||
78 | { | 91 | { |
92 | IsSamplerOnly = isSamplerOnly; | ||
79 | } | 93 | } |
80 | } | 94 | } |
81 | } | 95 | } |
diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsArrayCache.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsArrayCache.cs index 4645317c4..7e486e0a8 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsArrayCache.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsArrayCache.cs | |||
@@ -21,12 +21,98 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
21 | 21 | ||
22 | private readonly GpuContext _context; | 22 | private readonly GpuContext _context; |
23 | private readonly GpuChannel _channel; | 23 | private readonly GpuChannel _channel; |
24 | private readonly bool _isCompute; | ||
25 | 24 | ||
26 | /// <summary> | 25 | /// <summary> |
27 | /// Array cache entry key. | 26 | /// Array cache entry key. |
28 | /// </summary> | 27 | /// </summary> |
29 | private readonly struct CacheEntryKey : IEquatable<CacheEntryKey> | 28 | private readonly struct CacheEntryFromPoolKey : IEquatable<CacheEntryFromPoolKey> |
29 | { | ||
30 | /// <summary> | ||
31 | /// Whether the entry is for an image. | ||
32 | /// </summary> | ||
33 | public readonly bool IsImage; | ||
34 | |||
35 | /// <summary> | ||
36 | /// Whether the entry is for a sampler. | ||
37 | /// </summary> | ||
38 | public readonly bool IsSampler; | ||
39 | |||
40 | /// <summary> | ||
41 | /// Texture or image target type. | ||
42 | /// </summary> | ||
43 | public readonly Target Target; | ||
44 | |||
45 | /// <summary> | ||
46 | /// Number of entries of the array. | ||
47 | /// </summary> | ||
48 | public readonly int ArrayLength; | ||
49 | |||
50 | private readonly TexturePool _texturePool; | ||
51 | private readonly SamplerPool _samplerPool; | ||
52 | |||
53 | /// <summary> | ||
54 | /// Creates a new array cache entry. | ||
55 | /// </summary> | ||
56 | /// <param name="isImage">Whether the entry is for an image</param> | ||
57 | /// <param name="bindingInfo">Binding information for the array</param> | ||
58 | /// <param name="texturePool">Texture pool where the array textures are located</param> | ||
59 | /// <param name="samplerPool">Sampler pool where the array samplers are located</param> | ||
60 | public CacheEntryFromPoolKey(bool isImage, TextureBindingInfo bindingInfo, TexturePool texturePool, SamplerPool samplerPool) | ||
61 | { | ||
62 | IsImage = isImage; | ||
63 | IsSampler = bindingInfo.IsSamplerOnly; | ||
64 | Target = bindingInfo.Target; | ||
65 | ArrayLength = bindingInfo.ArrayLength; | ||
66 | |||
67 | _texturePool = texturePool; | ||
68 | _samplerPool = samplerPool; | ||
69 | } | ||
70 | |||
71 | /// <summary> | ||
72 | /// Checks if the pool matches the cached pool. | ||
73 | /// </summary> | ||
74 | /// <param name="texturePool">Texture or sampler pool instance</param> | ||
75 | /// <returns>True if the pool matches, false otherwise</returns> | ||
76 | public bool MatchesPool<T>(IPool<T> pool) | ||
77 | { | ||
78 | return _texturePool == pool || _samplerPool == pool; | ||
79 | } | ||
80 | |||
81 | /// <summary> | ||
82 | /// Checks if the texture and sampler pools matches the cached pools. | ||
83 | /// </summary> | ||
84 | /// <param name="texturePool">Texture pool instance</param> | ||
85 | /// <param name="samplerPool">Sampler pool instance</param> | ||
86 | /// <returns>True if the pools match, false otherwise</returns> | ||
87 | private bool MatchesPools(TexturePool texturePool, SamplerPool samplerPool) | ||
88 | { | ||
89 | return _texturePool == texturePool && _samplerPool == samplerPool; | ||
90 | } | ||
91 | |||
92 | public bool Equals(CacheEntryFromPoolKey other) | ||
93 | { | ||
94 | return IsImage == other.IsImage && | ||
95 | IsSampler == other.IsSampler && | ||
96 | Target == other.Target && | ||
97 | ArrayLength == other.ArrayLength && | ||
98 | MatchesPools(other._texturePool, other._samplerPool); | ||
99 | } | ||
100 | |||
101 | public override bool Equals(object obj) | ||
102 | { | ||
103 | return obj is CacheEntryFromBufferKey other && Equals(other); | ||
104 | } | ||
105 | |||
106 | public override int GetHashCode() | ||
107 | { | ||
108 | return HashCode.Combine(_texturePool, _samplerPool, IsSampler); | ||
109 | } | ||
110 | } | ||
111 | |||
112 | /// <summary> | ||
113 | /// Array cache entry key. | ||
114 | /// </summary> | ||
115 | private readonly struct CacheEntryFromBufferKey : IEquatable<CacheEntryFromBufferKey> | ||
30 | { | 116 | { |
31 | /// <summary> | 117 | /// <summary> |
32 | /// Whether the entry is for an image. | 118 | /// Whether the entry is for an image. |
@@ -61,7 +147,7 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
61 | /// <param name="texturePool">Texture pool where the array textures are located</param> | 147 | /// <param name="texturePool">Texture pool where the array textures are located</param> |
62 | /// <param name="samplerPool">Sampler pool where the array samplers are located</param> | 148 | /// <param name="samplerPool">Sampler pool where the array samplers are located</param> |
63 | /// <param name="textureBufferBounds">Constant buffer bounds with the texture handles</param> | 149 | /// <param name="textureBufferBounds">Constant buffer bounds with the texture handles</param> |
64 | public CacheEntryKey( | 150 | public CacheEntryFromBufferKey( |
65 | bool isImage, | 151 | bool isImage, |
66 | TextureBindingInfo bindingInfo, | 152 | TextureBindingInfo bindingInfo, |
67 | TexturePool texturePool, | 153 | TexturePool texturePool, |
@@ -100,7 +186,7 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
100 | return _textureBufferBounds.Equals(textureBufferBounds); | 186 | return _textureBufferBounds.Equals(textureBufferBounds); |
101 | } | 187 | } |
102 | 188 | ||
103 | public bool Equals(CacheEntryKey other) | 189 | public bool Equals(CacheEntryFromBufferKey other) |
104 | { | 190 | { |
105 | return IsImage == other.IsImage && | 191 | return IsImage == other.IsImage && |
106 | Target == other.Target && | 192 | Target == other.Target && |
@@ -112,7 +198,7 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
112 | 198 | ||
113 | public override bool Equals(object obj) | 199 | public override bool Equals(object obj) |
114 | { | 200 | { |
115 | return obj is CacheEntryKey other && Equals(other); | 201 | return obj is CacheEntryFromBufferKey other && Equals(other); |
116 | } | 202 | } |
117 | 203 | ||
118 | public override int GetHashCode() | 204 | public override int GetHashCode() |
@@ -122,88 +208,58 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
122 | } | 208 | } |
123 | 209 | ||
124 | /// <summary> | 210 | /// <summary> |
125 | /// Array cache entry. | 211 | /// Array cache entry from pool. |
126 | /// </summary> | 212 | /// </summary> |
127 | private class CacheEntry | 213 | private class CacheEntry |
128 | { | 214 | { |
129 | /// <summary> | 215 | /// <summary> |
130 | /// Key for this entry on the cache. | ||
131 | /// </summary> | ||
132 | public readonly CacheEntryKey Key; | ||
133 | |||
134 | /// <summary> | ||
135 | /// Linked list node used on the texture bindings array cache. | ||
136 | /// </summary> | ||
137 | public LinkedListNode<CacheEntry> CacheNode; | ||
138 | |||
139 | /// <summary> | ||
140 | /// Timestamp set on the last use of the array by the cache. | ||
141 | /// </summary> | ||
142 | public int CacheTimestamp; | ||
143 | |||
144 | /// <summary> | ||
145 | /// All cached textures, along with their invalidated sequence number as value. | 216 | /// All cached textures, along with their invalidated sequence number as value. |
146 | /// </summary> | 217 | /// </summary> |
147 | public readonly Dictionary<Texture, int> Textures; | 218 | public readonly Dictionary<Texture, int> Textures; |
148 | 219 | ||
149 | /// <summary> | 220 | /// <summary> |
150 | /// All pool texture IDs along with their textures. | 221 | /// Backend texture array if the entry is for a texture, otherwise null. |
151 | /// </summary> | 222 | /// </summary> |
152 | public readonly Dictionary<int, Texture> TextureIds; | 223 | public readonly ITextureArray TextureArray; |
153 | 224 | ||
154 | /// <summary> | 225 | /// <summary> |
155 | /// All pool sampler IDs along with their samplers. | 226 | /// Backend image array if the entry is for an image, otherwise null. |
156 | /// </summary> | 227 | /// </summary> |
157 | public readonly Dictionary<int, Sampler> SamplerIds; | 228 | public readonly IImageArray ImageArray; |
158 | 229 | ||
159 | /// <summary> | 230 | /// <summary> |
160 | /// Backend texture array if the entry is for a texture, otherwise null. | 231 | /// Texture pool where the array textures are located. |
161 | /// </summary> | 232 | /// </summary> |
162 | public readonly ITextureArray TextureArray; | 233 | protected readonly TexturePool TexturePool; |
163 | 234 | ||
164 | /// <summary> | 235 | /// <summary> |
165 | /// Backend image array if the entry is for an image, otherwise null. | 236 | /// Sampler pool where the array samplers are located. |
166 | /// </summary> | 237 | /// </summary> |
167 | public readonly IImageArray ImageArray; | 238 | protected readonly SamplerPool SamplerPool; |
168 | |||
169 | private readonly TexturePool _texturePool; | ||
170 | private readonly SamplerPool _samplerPool; | ||
171 | 239 | ||
172 | private int _texturePoolSequence; | 240 | private int _texturePoolSequence; |
173 | private int _samplerPoolSequence; | 241 | private int _samplerPoolSequence; |
174 | 242 | ||
175 | private int[] _cachedTextureBuffer; | ||
176 | private int[] _cachedSamplerBuffer; | ||
177 | |||
178 | private int _lastSequenceNumber; | ||
179 | |||
180 | /// <summary> | 243 | /// <summary> |
181 | /// Creates a new array cache entry. | 244 | /// Creates a new array cache entry. |
182 | /// </summary> | 245 | /// </summary> |
183 | /// <param name="key">Key for this entry on the cache</param> | ||
184 | /// <param name="texturePool">Texture pool where the array textures are located</param> | 246 | /// <param name="texturePool">Texture pool where the array textures are located</param> |
185 | /// <param name="samplerPool">Sampler pool where the array samplers are located</param> | 247 | /// <param name="samplerPool">Sampler pool where the array samplers are located</param> |
186 | private CacheEntry(ref CacheEntryKey key, TexturePool texturePool, SamplerPool samplerPool) | 248 | private CacheEntry(TexturePool texturePool, SamplerPool samplerPool) |
187 | { | 249 | { |
188 | Key = key; | ||
189 | Textures = new Dictionary<Texture, int>(); | 250 | Textures = new Dictionary<Texture, int>(); |
190 | TextureIds = new Dictionary<int, Texture>(); | ||
191 | SamplerIds = new Dictionary<int, Sampler>(); | ||
192 | 251 | ||
193 | _texturePool = texturePool; | 252 | TexturePool = texturePool; |
194 | _samplerPool = samplerPool; | 253 | SamplerPool = samplerPool; |
195 | |||
196 | _lastSequenceNumber = -1; | ||
197 | } | 254 | } |
198 | 255 | ||
199 | /// <summary> | 256 | /// <summary> |
200 | /// Creates a new array cache entry. | 257 | /// Creates a new array cache entry. |
201 | /// </summary> | 258 | /// </summary> |
202 | /// <param name="key">Key for this entry on the cache</param> | ||
203 | /// <param name="array">Backend texture array</param> | 259 | /// <param name="array">Backend texture array</param> |
204 | /// <param name="texturePool">Texture pool where the array textures are located</param> | 260 | /// <param name="texturePool">Texture pool where the array textures are located</param> |
205 | /// <param name="samplerPool">Sampler pool where the array samplers are located</param> | 261 | /// <param name="samplerPool">Sampler pool where the array samplers are located</param> |
206 | public CacheEntry(ref CacheEntryKey key, ITextureArray array, TexturePool texturePool, SamplerPool samplerPool) : this(ref key, texturePool, samplerPool) | 262 | public CacheEntry(ITextureArray array, TexturePool texturePool, SamplerPool samplerPool) : this(texturePool, samplerPool) |
207 | { | 263 | { |
208 | TextureArray = array; | 264 | TextureArray = array; |
209 | } | 265 | } |
@@ -211,11 +267,10 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
211 | /// <summary> | 267 | /// <summary> |
212 | /// Creates a new array cache entry. | 268 | /// Creates a new array cache entry. |
213 | /// </summary> | 269 | /// </summary> |
214 | /// <param name="key">Key for this entry on the cache</param> | ||
215 | /// <param name="array">Backend image array</param> | 270 | /// <param name="array">Backend image array</param> |
216 | /// <param name="texturePool">Texture pool where the array textures are located</param> | 271 | /// <param name="texturePool">Texture pool where the array textures are located</param> |
217 | /// <param name="samplerPool">Sampler pool where the array samplers are located</param> | 272 | /// <param name="samplerPool">Sampler pool where the array samplers are located</param> |
218 | public CacheEntry(ref CacheEntryKey key, IImageArray array, TexturePool texturePool, SamplerPool samplerPool) : this(ref key, texturePool, samplerPool) | 273 | public CacheEntry(IImageArray array, TexturePool texturePool, SamplerPool samplerPool) : this(texturePool, samplerPool) |
219 | { | 274 | { |
220 | ImageArray = array; | 275 | ImageArray = array; |
221 | } | 276 | } |
@@ -248,23 +303,9 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
248 | /// <summary> | 303 | /// <summary> |
249 | /// Clears all cached texture instances. | 304 | /// Clears all cached texture instances. |
250 | /// </summary> | 305 | /// </summary> |
251 | public void Reset() | 306 | public virtual void Reset() |
252 | { | 307 | { |
253 | Textures.Clear(); | 308 | Textures.Clear(); |
254 | TextureIds.Clear(); | ||
255 | SamplerIds.Clear(); | ||
256 | } | ||
257 | |||
258 | /// <summary> | ||
259 | /// Updates the cached constant buffer data. | ||
260 | /// </summary> | ||
261 | /// <param name="cachedTextureBuffer">Constant buffer data with the texture handles (and sampler handles, if they are combined)</param> | ||
262 | /// <param name="cachedSamplerBuffer">Constant buffer data with the sampler handles</param> | ||
263 | /// <param name="separateSamplerBuffer">Whether <paramref name="cachedTextureBuffer"/> and <paramref name="cachedSamplerBuffer"/> comes from different buffers</param> | ||
264 | public void UpdateData(ReadOnlySpan<int> cachedTextureBuffer, ReadOnlySpan<int> cachedSamplerBuffer, bool separateSamplerBuffer) | ||
265 | { | ||
266 | _cachedTextureBuffer = cachedTextureBuffer.ToArray(); | ||
267 | _cachedSamplerBuffer = separateSamplerBuffer ? cachedSamplerBuffer.ToArray() : _cachedTextureBuffer; | ||
268 | } | 309 | } |
269 | 310 | ||
270 | /// <summary> | 311 | /// <summary> |
@@ -287,39 +328,105 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
287 | /// <summary> | 328 | /// <summary> |
288 | /// Checks if the cached texture or sampler pool has been modified since the last call to this method. | 329 | /// Checks if the cached texture or sampler pool has been modified since the last call to this method. |
289 | /// </summary> | 330 | /// </summary> |
290 | /// <returns>True if any used entries of the pools might have been modified, false otherwise</returns> | 331 | /// <returns>True if any used entries of the pool might have been modified, false otherwise</returns> |
291 | public bool PoolsModified() | 332 | public bool TexturePoolModified() |
292 | { | 333 | { |
293 | bool texturePoolModified = _texturePool.WasModified(ref _texturePoolSequence); | 334 | return TexturePool.WasModified(ref _texturePoolSequence); |
294 | bool samplerPoolModified = _samplerPool.WasModified(ref _samplerPoolSequence); | 335 | } |
295 | 336 | ||
296 | // If both pools were not modified since the last check, we have nothing else to check. | 337 | /// <summary> |
297 | if (!texturePoolModified && !samplerPoolModified) | 338 | /// Checks if the cached texture or sampler pool has been modified since the last call to this method. |
298 | { | 339 | /// </summary> |
299 | return false; | 340 | /// <returns>True if any used entries of the pool might have been modified, false otherwise</returns> |
300 | } | 341 | public bool SamplerPoolModified() |
342 | { | ||
343 | return SamplerPool.WasModified(ref _samplerPoolSequence); | ||
344 | } | ||
345 | } | ||
301 | 346 | ||
302 | // If the pools were modified, let's check if any of the entries we care about changed. | 347 | /// <summary> |
348 | /// Array cache entry from constant buffer. | ||
349 | /// </summary> | ||
350 | private class CacheEntryFromBuffer : CacheEntry | ||
351 | { | ||
352 | /// <summary> | ||
353 | /// Key for this entry on the cache. | ||
354 | /// </summary> | ||
355 | public readonly CacheEntryFromBufferKey Key; | ||
303 | 356 | ||
304 | // Check if any of our cached textures changed on the pool. | 357 | /// <summary> |
305 | foreach ((int textureId, Texture texture) in TextureIds) | 358 | /// Linked list node used on the texture bindings array cache. |
306 | { | 359 | /// </summary> |
307 | if (_texturePool.GetCachedItem(textureId) != texture) | 360 | public LinkedListNode<CacheEntryFromBuffer> CacheNode; |
308 | { | ||
309 | return true; | ||
310 | } | ||
311 | } | ||
312 | 361 | ||
313 | // Check if any of our cached samplers changed on the pool. | 362 | /// <summary> |
314 | foreach ((int samplerId, Sampler sampler) in SamplerIds) | 363 | /// Timestamp set on the last use of the array by the cache. |
315 | { | 364 | /// </summary> |
316 | if (_samplerPool.GetCachedItem(samplerId) != sampler) | 365 | public int CacheTimestamp; |
317 | { | ||
318 | return true; | ||
319 | } | ||
320 | } | ||
321 | 366 | ||
322 | return false; | 367 | /// <summary> |
368 | /// All pool texture IDs along with their textures. | ||
369 | /// </summary> | ||
370 | public readonly Dictionary<int, (Texture, TextureDescriptor)> TextureIds; | ||
371 | |||
372 | /// <summary> | ||
373 | /// All pool sampler IDs along with their samplers. | ||
374 | /// </summary> | ||
375 | public readonly Dictionary<int, (Sampler, SamplerDescriptor)> SamplerIds; | ||
376 | |||
377 | private int[] _cachedTextureBuffer; | ||
378 | private int[] _cachedSamplerBuffer; | ||
379 | |||
380 | private int _lastSequenceNumber; | ||
381 | |||
382 | /// <summary> | ||
383 | /// Creates a new array cache entry. | ||
384 | /// </summary> | ||
385 | /// <param name="key">Key for this entry on the cache</param> | ||
386 | /// <param name="array">Backend texture array</param> | ||
387 | /// <param name="texturePool">Texture pool where the array textures are located</param> | ||
388 | /// <param name="samplerPool">Sampler pool where the array samplers are located</param> | ||
389 | public CacheEntryFromBuffer(ref CacheEntryFromBufferKey key, ITextureArray array, TexturePool texturePool, SamplerPool samplerPool) : base(array, texturePool, samplerPool) | ||
390 | { | ||
391 | Key = key; | ||
392 | _lastSequenceNumber = -1; | ||
393 | TextureIds = new Dictionary<int, (Texture, TextureDescriptor)>(); | ||
394 | SamplerIds = new Dictionary<int, (Sampler, SamplerDescriptor)>(); | ||
395 | } | ||
396 | |||
397 | /// <summary> | ||
398 | /// Creates a new array cache entry. | ||
399 | /// </summary> | ||
400 | /// <param name="key">Key for this entry on the cache</param> | ||
401 | /// <param name="array">Backend image array</param> | ||
402 | /// <param name="texturePool">Texture pool where the array textures are located</param> | ||
403 | /// <param name="samplerPool">Sampler pool where the array samplers are located</param> | ||
404 | public CacheEntryFromBuffer(ref CacheEntryFromBufferKey key, IImageArray array, TexturePool texturePool, SamplerPool samplerPool) : base(array, texturePool, samplerPool) | ||
405 | { | ||
406 | Key = key; | ||
407 | _lastSequenceNumber = -1; | ||
408 | TextureIds = new Dictionary<int, (Texture, TextureDescriptor)>(); | ||
409 | SamplerIds = new Dictionary<int, (Sampler, SamplerDescriptor)>(); | ||
410 | } | ||
411 | |||
412 | /// <inheritdoc/> | ||
413 | public override void Reset() | ||
414 | { | ||
415 | base.Reset(); | ||
416 | TextureIds.Clear(); | ||
417 | SamplerIds.Clear(); | ||
418 | } | ||
419 | |||
420 | /// <summary> | ||
421 | /// Updates the cached constant buffer data. | ||
422 | /// </summary> | ||
423 | /// <param name="cachedTextureBuffer">Constant buffer data with the texture handles (and sampler handles, if they are combined)</param> | ||
424 | /// <param name="cachedSamplerBuffer">Constant buffer data with the sampler handles</param> | ||
425 | /// <param name="separateSamplerBuffer">Whether <paramref name="cachedTextureBuffer"/> and <paramref name="cachedSamplerBuffer"/> comes from different buffers</param> | ||
426 | public void UpdateData(ReadOnlySpan<int> cachedTextureBuffer, ReadOnlySpan<int> cachedSamplerBuffer, bool separateSamplerBuffer) | ||
427 | { | ||
428 | _cachedTextureBuffer = cachedTextureBuffer.ToArray(); | ||
429 | _cachedSamplerBuffer = separateSamplerBuffer ? cachedSamplerBuffer.ToArray() : _cachedTextureBuffer; | ||
323 | } | 430 | } |
324 | 431 | ||
325 | /// <summary> | 432 | /// <summary> |
@@ -380,10 +487,51 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
380 | 487 | ||
381 | return true; | 488 | return true; |
382 | } | 489 | } |
490 | |||
491 | /// <summary> | ||
492 | /// Checks if the cached texture or sampler pool has been modified since the last call to this method. | ||
493 | /// </summary> | ||
494 | /// <returns>True if any used entries of the pools might have been modified, false otherwise</returns> | ||
495 | public bool PoolsModified() | ||
496 | { | ||
497 | bool texturePoolModified = TexturePoolModified(); | ||
498 | bool samplerPoolModified = SamplerPoolModified(); | ||
499 | |||
500 | // If both pools were not modified since the last check, we have nothing else to check. | ||
501 | if (!texturePoolModified && !samplerPoolModified) | ||
502 | { | ||
503 | return false; | ||
504 | } | ||
505 | |||
506 | // If the pools were modified, let's check if any of the entries we care about changed. | ||
507 | |||
508 | // Check if any of our cached textures changed on the pool. | ||
509 | foreach ((int textureId, (Texture texture, TextureDescriptor descriptor)) in TextureIds) | ||
510 | { | ||
511 | if (TexturePool.GetCachedItem(textureId) != texture || | ||
512 | (texture == null && TexturePool.IsValidId(textureId) && !TexturePool.GetDescriptorRef(textureId).Equals(descriptor))) | ||
513 | { | ||
514 | return true; | ||
515 | } | ||
516 | } | ||
517 | |||
518 | // Check if any of our cached samplers changed on the pool. | ||
519 | foreach ((int samplerId, (Sampler sampler, SamplerDescriptor descriptor)) in SamplerIds) | ||
520 | { | ||
521 | if (SamplerPool.GetCachedItem(samplerId) != sampler || | ||
522 | (sampler == null && SamplerPool.IsValidId(samplerId) && !SamplerPool.GetDescriptorRef(samplerId).Equals(descriptor))) | ||
523 | { | ||
524 | return true; | ||
525 | } | ||
526 | } | ||
527 | |||
528 | return false; | ||
529 | } | ||
383 | } | 530 | } |
384 | 531 | ||
385 | private readonly Dictionary<CacheEntryKey, CacheEntry> _cache; | 532 | private readonly Dictionary<CacheEntryFromBufferKey, CacheEntryFromBuffer> _cacheFromBuffer; |
386 | private readonly LinkedList<CacheEntry> _lruCache; | 533 | private readonly Dictionary<CacheEntryFromPoolKey, CacheEntry> _cacheFromPool; |
534 | private readonly LinkedList<CacheEntryFromBuffer> _lruCache; | ||
387 | 535 | ||
388 | private int _currentTimestamp; | 536 | private int _currentTimestamp; |
389 | 537 | ||
@@ -392,14 +540,13 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
392 | /// </summary> | 540 | /// </summary> |
393 | /// <param name="context">GPU context</param> | 541 | /// <param name="context">GPU context</param> |
394 | /// <param name="channel">GPU channel</param> | 542 | /// <param name="channel">GPU channel</param> |
395 | /// <param name="isCompute">Whether the bindings will be used for compute or graphics pipelines</param> | 543 | public TextureBindingsArrayCache(GpuContext context, GpuChannel channel) |
396 | public TextureBindingsArrayCache(GpuContext context, GpuChannel channel, bool isCompute) | ||
397 | { | 544 | { |
398 | _context = context; | 545 | _context = context; |
399 | _channel = channel; | 546 | _channel = channel; |
400 | _isCompute = isCompute; | 547 | _cacheFromBuffer = new Dictionary<CacheEntryFromBufferKey, CacheEntryFromBuffer>(); |
401 | _cache = new Dictionary<CacheEntryKey, CacheEntry>(); | 548 | _cacheFromPool = new Dictionary<CacheEntryFromPoolKey, CacheEntry>(); |
402 | _lruCache = new LinkedList<CacheEntry>(); | 549 | _lruCache = new LinkedList<CacheEntryFromBuffer>(); |
403 | } | 550 | } |
404 | 551 | ||
405 | /// <summary> | 552 | /// <summary> |
@@ -458,14 +605,179 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
458 | SamplerIndex samplerIndex, | 605 | SamplerIndex samplerIndex, |
459 | TextureBindingInfo bindingInfo) | 606 | TextureBindingInfo bindingInfo) |
460 | { | 607 | { |
608 | if (IsDirectHandleType(bindingInfo.Handle)) | ||
609 | { | ||
610 | UpdateFromPool(texturePool, samplerPool, stage, isImage, bindingInfo); | ||
611 | } | ||
612 | else | ||
613 | { | ||
614 | UpdateFromBuffer(texturePool, samplerPool, stage, stageIndex, textureBufferIndex, isImage, samplerIndex, bindingInfo); | ||
615 | } | ||
616 | } | ||
617 | |||
618 | /// <summary> | ||
619 | /// Updates a texture or image array bindings and textures from a texture or sampler pool. | ||
620 | /// </summary> | ||
621 | /// <param name="texturePool">Texture pool</param> | ||
622 | /// <param name="samplerPool">Sampler pool</param> | ||
623 | /// <param name="stage">Shader stage where the array is used</param> | ||
624 | /// <param name="isImage">Whether the array is a image or texture array</param> | ||
625 | /// <param name="bindingInfo">Array binding information</param> | ||
626 | private void UpdateFromPool(TexturePool texturePool, SamplerPool samplerPool, ShaderStage stage, bool isImage, TextureBindingInfo bindingInfo) | ||
627 | { | ||
628 | CacheEntry entry = GetOrAddEntry(texturePool, samplerPool, bindingInfo, isImage, out bool isNewEntry); | ||
629 | |||
630 | bool isSampler = bindingInfo.IsSamplerOnly; | ||
631 | bool poolModified = isSampler ? entry.SamplerPoolModified() : entry.TexturePoolModified(); | ||
632 | bool isStore = bindingInfo.Flags.HasFlag(TextureUsageFlags.ImageStore); | ||
633 | bool resScaleUnsupported = bindingInfo.Flags.HasFlag(TextureUsageFlags.ResScaleUnsupported); | ||
634 | |||
635 | if (!poolModified && !isNewEntry && entry.ValidateTextures()) | ||
636 | { | ||
637 | entry.SynchronizeMemory(isStore, resScaleUnsupported); | ||
638 | |||
639 | if (isImage) | ||
640 | { | ||
641 | _context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, entry.ImageArray); | ||
642 | } | ||
643 | else | ||
644 | { | ||
645 | _context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, entry.TextureArray); | ||
646 | } | ||
647 | |||
648 | return; | ||
649 | } | ||
650 | |||
651 | if (!isNewEntry) | ||
652 | { | ||
653 | entry.Reset(); | ||
654 | } | ||
655 | |||
656 | int length = (isSampler ? samplerPool.MaximumId : texturePool.MaximumId) + 1; | ||
657 | length = Math.Min(length, bindingInfo.ArrayLength); | ||
658 | |||
659 | Format[] formats = isImage ? new Format[bindingInfo.ArrayLength] : null; | ||
660 | ISampler[] samplers = isImage ? null : new ISampler[bindingInfo.ArrayLength]; | ||
661 | ITexture[] textures = new ITexture[bindingInfo.ArrayLength]; | ||
662 | |||
663 | for (int index = 0; index < length; index++) | ||
664 | { | ||
665 | Texture texture = null; | ||
666 | Sampler sampler = null; | ||
667 | |||
668 | if (isSampler) | ||
669 | { | ||
670 | sampler = samplerPool?.Get(index); | ||
671 | } | ||
672 | else | ||
673 | { | ||
674 | ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(index, out texture); | ||
675 | |||
676 | if (texture != null) | ||
677 | { | ||
678 | entry.Textures[texture] = texture.InvalidatedSequence; | ||
679 | |||
680 | if (isStore) | ||
681 | { | ||
682 | texture.SignalModified(); | ||
683 | } | ||
684 | |||
685 | if (resScaleUnsupported && texture.ScaleMode != TextureScaleMode.Blacklisted) | ||
686 | { | ||
687 | // Scaling textures used on arrays is currently not supported. | ||
688 | |||
689 | texture.BlacklistScale(); | ||
690 | } | ||
691 | } | ||
692 | } | ||
693 | |||
694 | ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target); | ||
695 | ISampler hostSampler = sampler?.GetHostSampler(texture); | ||
696 | |||
697 | Format format = bindingInfo.Format; | ||
698 | |||
699 | if (hostTexture != null && texture.Target == Target.TextureBuffer) | ||
700 | { | ||
701 | // Ensure that the buffer texture is using the correct buffer as storage. | ||
702 | // Buffers are frequently re-created to accommodate larger data, so we need to re-bind | ||
703 | // to ensure we're not using a old buffer that was already deleted. | ||
704 | if (isImage) | ||
705 | { | ||
706 | if (format == 0 && texture != null) | ||
707 | { | ||
708 | format = texture.Format; | ||
709 | } | ||
710 | |||
711 | _channel.BufferManager.SetBufferTextureStorage(entry.ImageArray, hostTexture, texture.Range, bindingInfo, index, format); | ||
712 | } | ||
713 | else | ||
714 | { | ||
715 | _channel.BufferManager.SetBufferTextureStorage(entry.TextureArray, hostTexture, texture.Range, bindingInfo, index, format); | ||
716 | } | ||
717 | } | ||
718 | else if (isImage) | ||
719 | { | ||
720 | if (format == 0 && texture != null) | ||
721 | { | ||
722 | format = texture.Format; | ||
723 | } | ||
724 | |||
725 | formats[index] = format; | ||
726 | textures[index] = hostTexture; | ||
727 | } | ||
728 | else | ||
729 | { | ||
730 | samplers[index] = hostSampler; | ||
731 | textures[index] = hostTexture; | ||
732 | } | ||
733 | } | ||
734 | |||
735 | if (isImage) | ||
736 | { | ||
737 | entry.ImageArray.SetFormats(0, formats); | ||
738 | entry.ImageArray.SetImages(0, textures); | ||
739 | |||
740 | _context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, entry.ImageArray); | ||
741 | } | ||
742 | else | ||
743 | { | ||
744 | entry.TextureArray.SetSamplers(0, samplers); | ||
745 | entry.TextureArray.SetTextures(0, textures); | ||
746 | |||
747 | _context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, entry.TextureArray); | ||
748 | } | ||
749 | } | ||
750 | |||
751 | /// <summary> | ||
752 | /// Updates a texture or image array bindings and textures from constant buffer handles. | ||
753 | /// </summary> | ||
754 | /// <param name="texturePool">Texture pool</param> | ||
755 | /// <param name="samplerPool">Sampler pool</param> | ||
756 | /// <param name="stage">Shader stage where the array is used</param> | ||
757 | /// <param name="stageIndex">Shader stage index where the array is used</param> | ||
758 | /// <param name="textureBufferIndex">Texture constant buffer index</param> | ||
759 | /// <param name="isImage">Whether the array is a image or texture array</param> | ||
760 | /// <param name="samplerIndex">Sampler handles source</param> | ||
761 | /// <param name="bindingInfo">Array binding information</param> | ||
762 | private void UpdateFromBuffer( | ||
763 | TexturePool texturePool, | ||
764 | SamplerPool samplerPool, | ||
765 | ShaderStage stage, | ||
766 | int stageIndex, | ||
767 | int textureBufferIndex, | ||
768 | bool isImage, | ||
769 | SamplerIndex samplerIndex, | ||
770 | TextureBindingInfo bindingInfo) | ||
771 | { | ||
461 | (textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(bindingInfo.CbufSlot, textureBufferIndex); | 772 | (textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(bindingInfo.CbufSlot, textureBufferIndex); |
462 | 773 | ||
463 | bool separateSamplerBuffer = textureBufferIndex != samplerBufferIndex; | 774 | bool separateSamplerBuffer = textureBufferIndex != samplerBufferIndex; |
775 | bool isCompute = stage == ShaderStage.Compute; | ||
464 | 776 | ||
465 | ref BufferBounds textureBufferBounds = ref _channel.BufferManager.GetUniformBufferBounds(_isCompute, stageIndex, textureBufferIndex); | 777 | ref BufferBounds textureBufferBounds = ref _channel.BufferManager.GetUniformBufferBounds(isCompute, stageIndex, textureBufferIndex); |
466 | ref BufferBounds samplerBufferBounds = ref _channel.BufferManager.GetUniformBufferBounds(_isCompute, stageIndex, samplerBufferIndex); | 778 | ref BufferBounds samplerBufferBounds = ref _channel.BufferManager.GetUniformBufferBounds(isCompute, stageIndex, samplerBufferIndex); |
467 | 779 | ||
468 | CacheEntry entry = GetOrAddEntry( | 780 | CacheEntryFromBuffer entry = GetOrAddEntry( |
469 | texturePool, | 781 | texturePool, |
470 | samplerPool, | 782 | samplerPool, |
471 | bindingInfo, | 783 | bindingInfo, |
@@ -589,8 +901,8 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
589 | 901 | ||
590 | Sampler sampler = samplerPool?.Get(samplerId); | 902 | Sampler sampler = samplerPool?.Get(samplerId); |
591 | 903 | ||
592 | entry.TextureIds[textureId] = texture; | 904 | entry.TextureIds[textureId] = (texture, descriptor); |
593 | entry.SamplerIds[samplerId] = sampler; | 905 | entry.SamplerIds[samplerId] = (sampler, samplerPool?.GetDescriptorRef(samplerId) ?? default); |
594 | 906 | ||
595 | ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target); | 907 | ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target); |
596 | ISampler hostSampler = sampler?.GetHostSampler(texture); | 908 | ISampler hostSampler = sampler?.GetHostSampler(texture); |
@@ -650,13 +962,12 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
650 | } | 962 | } |
651 | 963 | ||
652 | /// <summary> | 964 | /// <summary> |
653 | /// Gets a cached texture entry, or creates a new one if not found. | 965 | /// Gets a cached texture entry from pool, or creates a new one if not found. |
654 | /// </summary> | 966 | /// </summary> |
655 | /// <param name="texturePool">Texture pool</param> | 967 | /// <param name="texturePool">Texture pool</param> |
656 | /// <param name="samplerPool">Sampler pool</param> | 968 | /// <param name="samplerPool">Sampler pool</param> |
657 | /// <param name="bindingInfo">Array binding information</param> | 969 | /// <param name="bindingInfo">Array binding information</param> |
658 | /// <param name="isImage">Whether the array is a image or texture array</param> | 970 | /// <param name="isImage">Whether the array is a image or texture array</param> |
659 | /// <param name="textureBufferBounds">Constant buffer bounds with the texture handles</param> | ||
660 | /// <param name="isNew">Whether a new entry was created, or an existing one was returned</param> | 971 | /// <param name="isNew">Whether a new entry was created, or an existing one was returned</param> |
661 | /// <returns>Cache entry</returns> | 972 | /// <returns>Cache entry</returns> |
662 | private CacheEntry GetOrAddEntry( | 973 | private CacheEntry GetOrAddEntry( |
@@ -664,17 +975,59 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
664 | SamplerPool samplerPool, | 975 | SamplerPool samplerPool, |
665 | TextureBindingInfo bindingInfo, | 976 | TextureBindingInfo bindingInfo, |
666 | bool isImage, | 977 | bool isImage, |
978 | out bool isNew) | ||
979 | { | ||
980 | CacheEntryFromPoolKey key = new CacheEntryFromPoolKey(isImage, bindingInfo, texturePool, samplerPool); | ||
981 | |||
982 | isNew = !_cacheFromPool.TryGetValue(key, out CacheEntry entry); | ||
983 | |||
984 | if (isNew) | ||
985 | { | ||
986 | int arrayLength = bindingInfo.ArrayLength; | ||
987 | |||
988 | if (isImage) | ||
989 | { | ||
990 | IImageArray array = _context.Renderer.CreateImageArray(arrayLength, bindingInfo.Target == Target.TextureBuffer); | ||
991 | |||
992 | _cacheFromPool.Add(key, entry = new CacheEntry(array, texturePool, samplerPool)); | ||
993 | } | ||
994 | else | ||
995 | { | ||
996 | ITextureArray array = _context.Renderer.CreateTextureArray(arrayLength, bindingInfo.Target == Target.TextureBuffer); | ||
997 | |||
998 | _cacheFromPool.Add(key, entry = new CacheEntry(array, texturePool, samplerPool)); | ||
999 | } | ||
1000 | } | ||
1001 | |||
1002 | return entry; | ||
1003 | } | ||
1004 | |||
1005 | /// <summary> | ||
1006 | /// Gets a cached texture entry from constant buffer, or creates a new one if not found. | ||
1007 | /// </summary> | ||
1008 | /// <param name="texturePool">Texture pool</param> | ||
1009 | /// <param name="samplerPool">Sampler pool</param> | ||
1010 | /// <param name="bindingInfo">Array binding information</param> | ||
1011 | /// <param name="isImage">Whether the array is a image or texture array</param> | ||
1012 | /// <param name="textureBufferBounds">Constant buffer bounds with the texture handles</param> | ||
1013 | /// <param name="isNew">Whether a new entry was created, or an existing one was returned</param> | ||
1014 | /// <returns>Cache entry</returns> | ||
1015 | private CacheEntryFromBuffer GetOrAddEntry( | ||
1016 | TexturePool texturePool, | ||
1017 | SamplerPool samplerPool, | ||
1018 | TextureBindingInfo bindingInfo, | ||
1019 | bool isImage, | ||
667 | ref BufferBounds textureBufferBounds, | 1020 | ref BufferBounds textureBufferBounds, |
668 | out bool isNew) | 1021 | out bool isNew) |
669 | { | 1022 | { |
670 | CacheEntryKey key = new CacheEntryKey( | 1023 | CacheEntryFromBufferKey key = new CacheEntryFromBufferKey( |
671 | isImage, | 1024 | isImage, |
672 | bindingInfo, | 1025 | bindingInfo, |
673 | texturePool, | 1026 | texturePool, |
674 | samplerPool, | 1027 | samplerPool, |
675 | ref textureBufferBounds); | 1028 | ref textureBufferBounds); |
676 | 1029 | ||
677 | isNew = !_cache.TryGetValue(key, out CacheEntry entry); | 1030 | isNew = !_cacheFromBuffer.TryGetValue(key, out CacheEntryFromBuffer entry); |
678 | 1031 | ||
679 | if (isNew) | 1032 | if (isNew) |
680 | { | 1033 | { |
@@ -684,13 +1037,13 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
684 | { | 1037 | { |
685 | IImageArray array = _context.Renderer.CreateImageArray(arrayLength, bindingInfo.Target == Target.TextureBuffer); | 1038 | IImageArray array = _context.Renderer.CreateImageArray(arrayLength, bindingInfo.Target == Target.TextureBuffer); |
686 | 1039 | ||
687 | _cache.Add(key, entry = new CacheEntry(ref key, array, texturePool, samplerPool)); | 1040 | _cacheFromBuffer.Add(key, entry = new CacheEntryFromBuffer(ref key, array, texturePool, samplerPool)); |
688 | } | 1041 | } |
689 | else | 1042 | else |
690 | { | 1043 | { |
691 | ITextureArray array = _context.Renderer.CreateTextureArray(arrayLength, bindingInfo.Target == Target.TextureBuffer); | 1044 | ITextureArray array = _context.Renderer.CreateTextureArray(arrayLength, bindingInfo.Target == Target.TextureBuffer); |
692 | 1045 | ||
693 | _cache.Add(key, entry = new CacheEntry(ref key, array, texturePool, samplerPool)); | 1046 | _cacheFromBuffer.Add(key, entry = new CacheEntryFromBuffer(ref key, array, texturePool, samplerPool)); |
694 | } | 1047 | } |
695 | } | 1048 | } |
696 | 1049 | ||
@@ -716,15 +1069,52 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
716 | /// </summary> | 1069 | /// </summary> |
717 | private void RemoveLeastUsedEntries() | 1070 | private void RemoveLeastUsedEntries() |
718 | { | 1071 | { |
719 | LinkedListNode<CacheEntry> nextNode = _lruCache.First; | 1072 | LinkedListNode<CacheEntryFromBuffer> nextNode = _lruCache.First; |
720 | 1073 | ||
721 | while (nextNode != null && _currentTimestamp - nextNode.Value.CacheTimestamp >= MinDeltaForRemoval) | 1074 | while (nextNode != null && _currentTimestamp - nextNode.Value.CacheTimestamp >= MinDeltaForRemoval) |
722 | { | 1075 | { |
723 | LinkedListNode<CacheEntry> toRemove = nextNode; | 1076 | LinkedListNode<CacheEntryFromBuffer> toRemove = nextNode; |
724 | nextNode = nextNode.Next; | 1077 | nextNode = nextNode.Next; |
725 | _cache.Remove(toRemove.Value.Key); | 1078 | _cacheFromBuffer.Remove(toRemove.Value.Key); |
726 | _lruCache.Remove(toRemove); | 1079 | _lruCache.Remove(toRemove); |
727 | } | 1080 | } |
728 | } | 1081 | } |
1082 | |||
1083 | /// <summary> | ||
1084 | /// Removes all cached texture arrays matching the specified texture pool. | ||
1085 | /// </summary> | ||
1086 | /// <param name="pool">Texture pool</param> | ||
1087 | public void RemoveAllWithPool<T>(IPool<T> pool) | ||
1088 | { | ||
1089 | List<CacheEntryFromPoolKey> keysToRemove = null; | ||
1090 | |||
1091 | foreach (CacheEntryFromPoolKey key in _cacheFromPool.Keys) | ||
1092 | { | ||
1093 | if (key.MatchesPool(pool)) | ||
1094 | { | ||
1095 | (keysToRemove ??= new()).Add(key); | ||
1096 | } | ||
1097 | } | ||
1098 | |||
1099 | if (keysToRemove != null) | ||
1100 | { | ||
1101 | foreach (CacheEntryFromPoolKey key in keysToRemove) | ||
1102 | { | ||
1103 | _cacheFromPool.Remove(key); | ||
1104 | } | ||
1105 | } | ||
1106 | } | ||
1107 | |||
1108 | /// <summary> | ||
1109 | /// Checks if a handle indicates the binding should have all its textures sourced directly from a pool. | ||
1110 | /// </summary> | ||
1111 | /// <param name="handle">Handle to check</param> | ||
1112 | /// <returns>True if the handle represents direct pool access, false otherwise</returns> | ||
1113 | private static bool IsDirectHandleType(int handle) | ||
1114 | { | ||
1115 | (_, _, TextureHandleType type) = TextureHandle.UnpackOffsets(handle); | ||
1116 | |||
1117 | return type == TextureHandleType.Direct; | ||
1118 | } | ||
729 | } | 1119 | } |
730 | } | 1120 | } |
diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs index a1dde673b..9f1f60d95 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs | |||
@@ -34,7 +34,7 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
34 | private readonly TexturePoolCache _texturePoolCache; | 34 | private readonly TexturePoolCache _texturePoolCache; |
35 | private readonly SamplerPoolCache _samplerPoolCache; | 35 | private readonly SamplerPoolCache _samplerPoolCache; |
36 | 36 | ||
37 | private readonly TextureBindingsArrayCache _arrayBindingsCache; | 37 | private readonly TextureBindingsArrayCache _bindingsArrayCache; |
38 | 38 | ||
39 | private TexturePool _cachedTexturePool; | 39 | private TexturePool _cachedTexturePool; |
40 | private SamplerPool _cachedSamplerPool; | 40 | private SamplerPool _cachedSamplerPool; |
@@ -72,12 +72,14 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
72 | /// </summary> | 72 | /// </summary> |
73 | /// <param name="context">The GPU context that the texture bindings manager belongs to</param> | 73 | /// <param name="context">The GPU context that the texture bindings manager belongs to</param> |
74 | /// <param name="channel">The GPU channel that the texture bindings manager belongs to</param> | 74 | /// <param name="channel">The GPU channel that the texture bindings manager belongs to</param> |
75 | /// <param name="bindingsArrayCache">Cache of texture array bindings</param> | ||
75 | /// <param name="texturePoolCache">Texture pools cache used to get texture pools from</param> | 76 | /// <param name="texturePoolCache">Texture pools cache used to get texture pools from</param> |
76 | /// <param name="samplerPoolCache">Sampler pools cache used to get sampler pools from</param> | 77 | /// <param name="samplerPoolCache">Sampler pools cache used to get sampler pools from</param> |
77 | /// <param name="isCompute">True if the bindings manager is used for the compute engine</param> | 78 | /// <param name="isCompute">True if the bindings manager is used for the compute engine</param> |
78 | public TextureBindingsManager( | 79 | public TextureBindingsManager( |
79 | GpuContext context, | 80 | GpuContext context, |
80 | GpuChannel channel, | 81 | GpuChannel channel, |
82 | TextureBindingsArrayCache bindingsArrayCache, | ||
81 | TexturePoolCache texturePoolCache, | 83 | TexturePoolCache texturePoolCache, |
82 | SamplerPoolCache samplerPoolCache, | 84 | SamplerPoolCache samplerPoolCache, |
83 | bool isCompute) | 85 | bool isCompute) |
@@ -89,7 +91,7 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
89 | 91 | ||
90 | _isCompute = isCompute; | 92 | _isCompute = isCompute; |
91 | 93 | ||
92 | _arrayBindingsCache = new TextureBindingsArrayCache(context, channel, isCompute); | 94 | _bindingsArrayCache = bindingsArrayCache; |
93 | 95 | ||
94 | int stages = isCompute ? 1 : Constants.ShaderStages; | 96 | int stages = isCompute ? 1 : Constants.ShaderStages; |
95 | 97 | ||
@@ -456,7 +458,7 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
456 | 458 | ||
457 | if (bindingInfo.ArrayLength > 1) | 459 | if (bindingInfo.ArrayLength > 1) |
458 | { | 460 | { |
459 | _arrayBindingsCache.UpdateTextureArray(texturePool, samplerPool, stage, stageIndex, _textureBufferIndex, _samplerIndex, bindingInfo); | 461 | _bindingsArrayCache.UpdateTextureArray(texturePool, samplerPool, stage, stageIndex, _textureBufferIndex, _samplerIndex, bindingInfo); |
460 | 462 | ||
461 | continue; | 463 | continue; |
462 | } | 464 | } |
@@ -594,7 +596,7 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
594 | 596 | ||
595 | if (bindingInfo.ArrayLength > 1) | 597 | if (bindingInfo.ArrayLength > 1) |
596 | { | 598 | { |
597 | _arrayBindingsCache.UpdateImageArray(pool, stage, stageIndex, _textureBufferIndex, bindingInfo); | 599 | _bindingsArrayCache.UpdateImageArray(pool, stage, stageIndex, _textureBufferIndex, bindingInfo); |
598 | 600 | ||
599 | continue; | 601 | continue; |
600 | } | 602 | } |
@@ -732,7 +734,7 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
732 | 734 | ||
733 | ulong poolAddress = _channel.MemoryManager.Translate(poolGpuVa); | 735 | ulong poolAddress = _channel.MemoryManager.Translate(poolGpuVa); |
734 | 736 | ||
735 | TexturePool texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, maximumId); | 737 | TexturePool texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, maximumId, _bindingsArrayCache); |
736 | 738 | ||
737 | TextureDescriptor descriptor; | 739 | TextureDescriptor descriptor; |
738 | 740 | ||
@@ -828,7 +830,7 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
828 | 830 | ||
829 | if (poolAddress != MemoryManager.PteUnmapped) | 831 | if (poolAddress != MemoryManager.PteUnmapped) |
830 | { | 832 | { |
831 | texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, _texturePoolMaximumId); | 833 | texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, _texturePoolMaximumId, _bindingsArrayCache); |
832 | _texturePool = texturePool; | 834 | _texturePool = texturePool; |
833 | } | 835 | } |
834 | } | 836 | } |
@@ -839,7 +841,7 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
839 | 841 | ||
840 | if (poolAddress != MemoryManager.PteUnmapped) | 842 | if (poolAddress != MemoryManager.PteUnmapped) |
841 | { | 843 | { |
842 | samplerPool = _samplerPoolCache.FindOrCreate(_channel, poolAddress, _samplerPoolMaximumId); | 844 | samplerPool = _samplerPoolCache.FindOrCreate(_channel, poolAddress, _samplerPoolMaximumId, _bindingsArrayCache); |
843 | _samplerPool = samplerPool; | 845 | _samplerPool = samplerPool; |
844 | } | 846 | } |
845 | } | 847 | } |
diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureManager.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureManager.cs index 8c2a88727..db2921468 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/TextureManager.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/TextureManager.cs | |||
@@ -15,6 +15,7 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
15 | 15 | ||
16 | private readonly TextureBindingsManager _cpBindingsManager; | 16 | private readonly TextureBindingsManager _cpBindingsManager; |
17 | private readonly TextureBindingsManager _gpBindingsManager; | 17 | private readonly TextureBindingsManager _gpBindingsManager; |
18 | private readonly TextureBindingsArrayCache _bindingsArrayCache; | ||
18 | private readonly TexturePoolCache _texturePoolCache; | 19 | private readonly TexturePoolCache _texturePoolCache; |
19 | private readonly SamplerPoolCache _samplerPoolCache; | 20 | private readonly SamplerPoolCache _samplerPoolCache; |
20 | 21 | ||
@@ -46,8 +47,9 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
46 | TexturePoolCache texturePoolCache = new(context); | 47 | TexturePoolCache texturePoolCache = new(context); |
47 | SamplerPoolCache samplerPoolCache = new(context); | 48 | SamplerPoolCache samplerPoolCache = new(context); |
48 | 49 | ||
49 | _cpBindingsManager = new TextureBindingsManager(context, channel, texturePoolCache, samplerPoolCache, isCompute: true); | 50 | _bindingsArrayCache = new TextureBindingsArrayCache(context, channel); |
50 | _gpBindingsManager = new TextureBindingsManager(context, channel, texturePoolCache, samplerPoolCache, isCompute: false); | 51 | _cpBindingsManager = new TextureBindingsManager(context, channel, _bindingsArrayCache, texturePoolCache, samplerPoolCache, isCompute: true); |
52 | _gpBindingsManager = new TextureBindingsManager(context, channel, _bindingsArrayCache, texturePoolCache, samplerPoolCache, isCompute: false); | ||
51 | _texturePoolCache = texturePoolCache; | 53 | _texturePoolCache = texturePoolCache; |
52 | _samplerPoolCache = samplerPoolCache; | 54 | _samplerPoolCache = samplerPoolCache; |
53 | 55 | ||
@@ -384,7 +386,7 @@ namespace Ryujinx.Graphics.Gpu.Image | |||
384 | { | 386 | { |
385 | ulong poolAddress = _channel.MemoryManager.Translate(poolGpuVa); | 387 | ulong poolAddress = _channel.MemoryManager.Translate(poolGpuVa); |
386 | 388 | ||
387 | TexturePool texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, maximumId); | 389 | TexturePool texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, maximumId, _bindingsArrayCache); |
388 | 390 | ||
389 | return texturePool; | 391 | return texturePool; |
390 | } | 392 | } |
diff --git a/src/Ryujinx.Graphics.Gpu/Shader/CachedShaderBindings.cs b/src/Ryujinx.Graphics.Gpu/Shader/CachedShaderBindings.cs index 6e36753e8..a80dcbc87 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/CachedShaderBindings.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/CachedShaderBindings.cs | |||
@@ -58,7 +58,7 @@ namespace Ryujinx.Graphics.Gpu.Shader | |||
58 | 58 | ||
59 | TextureBindings[i] = stage.Info.Textures.Select(descriptor => | 59 | TextureBindings[i] = stage.Info.Textures.Select(descriptor => |
60 | { | 60 | { |
61 | Target target = ShaderTexture.GetTarget(descriptor.Type); | 61 | Target target = descriptor.Type != SamplerType.None ? ShaderTexture.GetTarget(descriptor.Type) : default; |
62 | 62 | ||
63 | var result = new TextureBindingInfo( | 63 | var result = new TextureBindingInfo( |
64 | target, | 64 | target, |
@@ -66,7 +66,8 @@ namespace Ryujinx.Graphics.Gpu.Shader | |||
66 | descriptor.ArrayLength, | 66 | descriptor.ArrayLength, |
67 | descriptor.CbufSlot, | 67 | descriptor.CbufSlot, |
68 | descriptor.HandleIndex, | 68 | descriptor.HandleIndex, |
69 | descriptor.Flags); | 69 | descriptor.Flags, |
70 | descriptor.Type == SamplerType.None); | ||
70 | 71 | ||
71 | if (descriptor.ArrayLength <= 1) | 72 | if (descriptor.ArrayLength <= 1) |
72 | { | 73 | { |
diff --git a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGpuAccessor.cs b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGpuAccessor.cs index 681838a9b..45f32e2d3 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGpuAccessor.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGpuAccessor.cs | |||
@@ -110,6 +110,13 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache | |||
110 | } | 110 | } |
111 | 111 | ||
112 | /// <inheritdoc/> | 112 | /// <inheritdoc/> |
113 | /// <exception cref="DiskCacheLoadException">Pool length is not available on the cache</exception> | ||
114 | public int QuerySamplerArrayLengthFromPool() | ||
115 | { | ||
116 | return QueryArrayLengthFromPool(isSampler: true); | ||
117 | } | ||
118 | |||
119 | /// <inheritdoc/> | ||
113 | public SamplerType QuerySamplerType(int handle, int cbufSlot) | 120 | public SamplerType QuerySamplerType(int handle, int cbufSlot) |
114 | { | 121 | { |
115 | _newSpecState.RecordTextureSamplerType(_stageIndex, handle, cbufSlot); | 122 | _newSpecState.RecordTextureSamplerType(_stageIndex, handle, cbufSlot); |
@@ -117,6 +124,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache | |||
117 | } | 124 | } |
118 | 125 | ||
119 | /// <inheritdoc/> | 126 | /// <inheritdoc/> |
127 | /// <exception cref="DiskCacheLoadException">Constant buffer derived length is not available on the cache</exception> | ||
120 | public int QueryTextureArrayLengthFromBuffer(int slot) | 128 | public int QueryTextureArrayLengthFromBuffer(int slot) |
121 | { | 129 | { |
122 | if (!_oldSpecState.TextureArrayFromBufferRegistered(_stageIndex, 0, slot)) | 130 | if (!_oldSpecState.TextureArrayFromBufferRegistered(_stageIndex, 0, slot)) |
@@ -131,6 +139,13 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache | |||
131 | } | 139 | } |
132 | 140 | ||
133 | /// <inheritdoc/> | 141 | /// <inheritdoc/> |
142 | /// <exception cref="DiskCacheLoadException">Pool length is not available on the cache</exception> | ||
143 | public int QueryTextureArrayLengthFromPool() | ||
144 | { | ||
145 | return QueryArrayLengthFromPool(isSampler: false); | ||
146 | } | ||
147 | |||
148 | /// <inheritdoc/> | ||
134 | public TextureFormat QueryTextureFormat(int handle, int cbufSlot) | 149 | public TextureFormat QueryTextureFormat(int handle, int cbufSlot) |
135 | { | 150 | { |
136 | _newSpecState.RecordTextureFormat(_stageIndex, handle, cbufSlot); | 151 | _newSpecState.RecordTextureFormat(_stageIndex, handle, cbufSlot); |
@@ -170,6 +185,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache | |||
170 | } | 185 | } |
171 | 186 | ||
172 | /// <inheritdoc/> | 187 | /// <inheritdoc/> |
188 | /// <exception cref="DiskCacheLoadException">Texture information is not available on the cache</exception> | ||
173 | public void RegisterTexture(int handle, int cbufSlot) | 189 | public void RegisterTexture(int handle, int cbufSlot) |
174 | { | 190 | { |
175 | if (!_oldSpecState.TextureRegistered(_stageIndex, handle, cbufSlot)) | 191 | if (!_oldSpecState.TextureRegistered(_stageIndex, handle, cbufSlot)) |
@@ -182,5 +198,24 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache | |||
182 | bool coordNormalized = _oldSpecState.GetCoordNormalized(_stageIndex, handle, cbufSlot); | 198 | bool coordNormalized = _oldSpecState.GetCoordNormalized(_stageIndex, handle, cbufSlot); |
183 | _newSpecState.RegisterTexture(_stageIndex, handle, cbufSlot, format, formatSrgb, target, coordNormalized); | 199 | _newSpecState.RegisterTexture(_stageIndex, handle, cbufSlot, format, formatSrgb, target, coordNormalized); |
184 | } | 200 | } |
201 | |||
202 | /// <summary> | ||
203 | /// Gets the cached texture or sampler pool capacity. | ||
204 | /// </summary> | ||
205 | /// <param name="isSampler">True to get sampler pool length, false for texture pool length</param> | ||
206 | /// <returns>Pool length</returns> | ||
207 | /// <exception cref="DiskCacheLoadException">Pool length is not available on the cache</exception> | ||
208 | private int QueryArrayLengthFromPool(bool isSampler) | ||
209 | { | ||
210 | if (!_oldSpecState.TextureArrayFromPoolRegistered(isSampler)) | ||
211 | { | ||
212 | throw new DiskCacheLoadException(DiskCacheLoadResult.MissingTextureArrayLength); | ||
213 | } | ||
214 | |||
215 | int arrayLength = _oldSpecState.GetTextureArrayFromPoolLength(isSampler); | ||
216 | _newSpecState.RegisterTextureArrayLengthFromPool(isSampler, arrayLength); | ||
217 | |||
218 | return arrayLength; | ||
219 | } | ||
185 | } | 220 | } |
186 | } | 221 | } |
diff --git a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs index b6a277a2a..2c19cc4b9 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs | |||
@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache | |||
22 | private const ushort FileFormatVersionMajor = 1; | 22 | private const ushort FileFormatVersionMajor = 1; |
23 | private const ushort FileFormatVersionMinor = 2; | 23 | private const ushort FileFormatVersionMinor = 2; |
24 | private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor; | 24 | private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor; |
25 | private const uint CodeGenVersion = 6489; | 25 | private const uint CodeGenVersion = 6577; |
26 | 26 | ||
27 | private const string SharedTocFileName = "shared.toc"; | 27 | private const string SharedTocFileName = "shared.toc"; |
28 | private const string SharedDataFileName = "shared.data"; | 28 | private const string SharedDataFileName = "shared.data"; |
diff --git a/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs b/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs index 1d22ab933..04949690a 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs | |||
@@ -121,6 +121,15 @@ namespace Ryujinx.Graphics.Gpu.Shader | |||
121 | } | 121 | } |
122 | 122 | ||
123 | /// <inheritdoc/> | 123 | /// <inheritdoc/> |
124 | public int QuerySamplerArrayLengthFromPool() | ||
125 | { | ||
126 | int length = _state.SamplerPoolMaximumId + 1; | ||
127 | _state.SpecializationState?.RegisterTextureArrayLengthFromPool(isSampler: true, length); | ||
128 | |||
129 | return length; | ||
130 | } | ||
131 | |||
132 | /// <inheritdoc/> | ||
124 | public SamplerType QuerySamplerType(int handle, int cbufSlot) | 133 | public SamplerType QuerySamplerType(int handle, int cbufSlot) |
125 | { | 134 | { |
126 | _state.SpecializationState?.RecordTextureSamplerType(_stageIndex, handle, cbufSlot); | 135 | _state.SpecializationState?.RecordTextureSamplerType(_stageIndex, handle, cbufSlot); |
@@ -141,6 +150,15 @@ namespace Ryujinx.Graphics.Gpu.Shader | |||
141 | return arrayLength; | 150 | return arrayLength; |
142 | } | 151 | } |
143 | 152 | ||
153 | /// <inheritdoc/> | ||
154 | public int QueryTextureArrayLengthFromPool() | ||
155 | { | ||
156 | int length = _state.PoolState.TexturePoolMaximumId + 1; | ||
157 | _state.SpecializationState?.RegisterTextureArrayLengthFromPool(isSampler: false, length); | ||
158 | |||
159 | return length; | ||
160 | } | ||
161 | |||
144 | //// <inheritdoc/> | 162 | //// <inheritdoc/> |
145 | public TextureFormat QueryTextureFormat(int handle, int cbufSlot) | 163 | public TextureFormat QueryTextureFormat(int handle, int cbufSlot) |
146 | { | 164 | { |
diff --git a/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs b/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs index 06e5edf1e..0d562b0da 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs | |||
@@ -213,6 +213,8 @@ namespace Ryujinx.Graphics.Gpu.Shader | |||
213 | 213 | ||
214 | public bool QueryHostSupportsScaledVertexFormats() => _context.Capabilities.SupportsScaledVertexFormats; | 214 | public bool QueryHostSupportsScaledVertexFormats() => _context.Capabilities.SupportsScaledVertexFormats; |
215 | 215 | ||
216 | public bool QueryHostSupportsSeparateSampler() => _context.Capabilities.SupportsSeparateSampler; | ||
217 | |||
216 | public bool QueryHostSupportsShaderBallot() => _context.Capabilities.SupportsShaderBallot; | 218 | public bool QueryHostSupportsShaderBallot() => _context.Capabilities.SupportsShaderBallot; |
217 | 219 | ||
218 | public bool QueryHostSupportsShaderBarrierDivergence() => _context.Capabilities.SupportsShaderBarrierDivergence; | 220 | public bool QueryHostSupportsShaderBarrierDivergence() => _context.Capabilities.SupportsShaderBarrierDivergence; |
diff --git a/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorState.cs b/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorState.cs index cfc4a2ccc..808bf1851 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorState.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorState.cs | |||
@@ -6,6 +6,11 @@ namespace Ryujinx.Graphics.Gpu.Shader | |||
6 | class GpuAccessorState | 6 | class GpuAccessorState |
7 | { | 7 | { |
8 | /// <summary> | 8 | /// <summary> |
9 | /// Maximum ID that a sampler pool entry may have. | ||
10 | /// </summary> | ||
11 | public readonly int SamplerPoolMaximumId; | ||
12 | |||
13 | /// <summary> | ||
9 | /// GPU texture pool state. | 14 | /// GPU texture pool state. |
10 | /// </summary> | 15 | /// </summary> |
11 | public readonly GpuChannelPoolState PoolState; | 16 | public readonly GpuChannelPoolState PoolState; |
@@ -38,18 +43,21 @@ namespace Ryujinx.Graphics.Gpu.Shader | |||
38 | /// <summary> | 43 | /// <summary> |
39 | /// Creates a new GPU accessor state. | 44 | /// Creates a new GPU accessor state. |
40 | /// </summary> | 45 | /// </summary> |
46 | /// <param name="samplerPoolMaximumId">Maximum ID that a sampler pool entry may have</param> | ||
41 | /// <param name="poolState">GPU texture pool state</param> | 47 | /// <param name="poolState">GPU texture pool state</param> |
42 | /// <param name="computeState">GPU compute state, for compute shaders</param> | 48 | /// <param name="computeState">GPU compute state, for compute shaders</param> |
43 | /// <param name="graphicsState">GPU graphics state, for vertex, tessellation, geometry and fragment shaders</param> | 49 | /// <param name="graphicsState">GPU graphics state, for vertex, tessellation, geometry and fragment shaders</param> |
44 | /// <param name="specializationState">Shader specialization state (shared by all stages)</param> | 50 | /// <param name="specializationState">Shader specialization state (shared by all stages)</param> |
45 | /// <param name="transformFeedbackDescriptors">Transform feedback information, if the shader uses transform feedback. Otherwise, should be null</param> | 51 | /// <param name="transformFeedbackDescriptors">Transform feedback information, if the shader uses transform feedback. Otherwise, should be null</param> |
46 | public GpuAccessorState( | 52 | public GpuAccessorState( |
53 | int samplerPoolMaximumId, | ||
47 | GpuChannelPoolState poolState, | 54 | GpuChannelPoolState poolState, |
48 | GpuChannelComputeState computeState, | 55 | GpuChannelComputeState computeState, |
49 | GpuChannelGraphicsState graphicsState, | 56 | GpuChannelGraphicsState graphicsState, |
50 | ShaderSpecializationState specializationState, | 57 | ShaderSpecializationState specializationState, |
51 | TransformFeedbackDescriptor[] transformFeedbackDescriptors = null) | 58 | TransformFeedbackDescriptor[] transformFeedbackDescriptors = null) |
52 | { | 59 | { |
60 | SamplerPoolMaximumId = samplerPoolMaximumId; | ||
53 | PoolState = poolState; | 61 | PoolState = poolState; |
54 | GraphicsState = graphicsState; | 62 | GraphicsState = graphicsState; |
55 | ComputeState = computeState; | 63 | ComputeState = computeState; |
diff --git a/src/Ryujinx.Graphics.Gpu/Shader/GpuChannelPoolState.cs b/src/Ryujinx.Graphics.Gpu/Shader/GpuChannelPoolState.cs index ddb45152e..a2ab99335 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/GpuChannelPoolState.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/GpuChannelPoolState.cs | |||
@@ -2,7 +2,6 @@ using System; | |||
2 | 2 | ||
3 | namespace Ryujinx.Graphics.Gpu.Shader | 3 | namespace Ryujinx.Graphics.Gpu.Shader |
4 | { | 4 | { |
5 | #pragma warning disable CS0659 // Class overrides Object.Equals(object o) but does not override Object.GetHashCode() | ||
6 | /// <summary> | 5 | /// <summary> |
7 | /// State used by the <see cref="GpuAccessor"/>. | 6 | /// State used by the <see cref="GpuAccessor"/>. |
8 | /// </summary> | 7 | /// </summary> |
@@ -52,6 +51,10 @@ namespace Ryujinx.Graphics.Gpu.Shader | |||
52 | { | 51 | { |
53 | return obj is GpuChannelPoolState state && Equals(state); | 52 | return obj is GpuChannelPoolState state && Equals(state); |
54 | } | 53 | } |
54 | |||
55 | public override int GetHashCode() | ||
56 | { | ||
57 | return HashCode.Combine(TexturePoolGpuVa, TexturePoolMaximumId, TextureBufferIndex); | ||
58 | } | ||
55 | } | 59 | } |
56 | #pragma warning restore CS0659 | ||
57 | } | 60 | } |
diff --git a/src/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/src/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs index 0b17af8b2..31cc94a25 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs | |||
@@ -192,12 +192,14 @@ namespace Ryujinx.Graphics.Gpu.Shader | |||
192 | /// This automatically translates, compiles and adds the code to the cache if not present. | 192 | /// This automatically translates, compiles and adds the code to the cache if not present. |
193 | /// </remarks> | 193 | /// </remarks> |
194 | /// <param name="channel">GPU channel</param> | 194 | /// <param name="channel">GPU channel</param> |
195 | /// <param name="samplerPoolMaximumId">Maximum ID that an entry in the sampler pool may have</param> | ||
195 | /// <param name="poolState">Texture pool state</param> | 196 | /// <param name="poolState">Texture pool state</param> |
196 | /// <param name="computeState">Compute engine state</param> | 197 | /// <param name="computeState">Compute engine state</param> |
197 | /// <param name="gpuVa">GPU virtual address of the binary shader code</param> | 198 | /// <param name="gpuVa">GPU virtual address of the binary shader code</param> |
198 | /// <returns>Compiled compute shader code</returns> | 199 | /// <returns>Compiled compute shader code</returns> |
199 | public CachedShaderProgram GetComputeShader( | 200 | public CachedShaderProgram GetComputeShader( |
200 | GpuChannel channel, | 201 | GpuChannel channel, |
202 | int samplerPoolMaximumId, | ||
201 | GpuChannelPoolState poolState, | 203 | GpuChannelPoolState poolState, |
202 | GpuChannelComputeState computeState, | 204 | GpuChannelComputeState computeState, |
203 | ulong gpuVa) | 205 | ulong gpuVa) |
@@ -214,7 +216,7 @@ namespace Ryujinx.Graphics.Gpu.Shader | |||
214 | } | 216 | } |
215 | 217 | ||
216 | ShaderSpecializationState specState = new(ref computeState); | 218 | ShaderSpecializationState specState = new(ref computeState); |
217 | GpuAccessorState gpuAccessorState = new(poolState, computeState, default, specState); | 219 | GpuAccessorState gpuAccessorState = new(samplerPoolMaximumId, poolState, computeState, default, specState); |
218 | GpuAccessor gpuAccessor = new(_context, channel, gpuAccessorState); | 220 | GpuAccessor gpuAccessor = new(_context, channel, gpuAccessorState); |
219 | gpuAccessor.InitializeReservedCounts(tfEnabled: false, vertexAsCompute: false); | 221 | gpuAccessor.InitializeReservedCounts(tfEnabled: false, vertexAsCompute: false); |
220 | 222 | ||
@@ -291,6 +293,7 @@ namespace Ryujinx.Graphics.Gpu.Shader | |||
291 | /// <param name="state">GPU state</param> | 293 | /// <param name="state">GPU state</param> |
292 | /// <param name="pipeline">Pipeline state</param> | 294 | /// <param name="pipeline">Pipeline state</param> |
293 | /// <param name="channel">GPU channel</param> | 295 | /// <param name="channel">GPU channel</param> |
296 | /// <param name="samplerPoolMaximumId">Maximum ID that an entry in the sampler pool may have</param> | ||
294 | /// <param name="poolState">Texture pool state</param> | 297 | /// <param name="poolState">Texture pool state</param> |
295 | /// <param name="graphicsState">3D engine state</param> | 298 | /// <param name="graphicsState">3D engine state</param> |
296 | /// <param name="addresses">Addresses of the shaders for each stage</param> | 299 | /// <param name="addresses">Addresses of the shaders for each stage</param> |
@@ -299,6 +302,7 @@ namespace Ryujinx.Graphics.Gpu.Shader | |||
299 | ref ThreedClassState state, | 302 | ref ThreedClassState state, |
300 | ref ProgramPipelineState pipeline, | 303 | ref ProgramPipelineState pipeline, |
301 | GpuChannel channel, | 304 | GpuChannel channel, |
305 | int samplerPoolMaximumId, | ||
302 | ref GpuChannelPoolState poolState, | 306 | ref GpuChannelPoolState poolState, |
303 | ref GpuChannelGraphicsState graphicsState, | 307 | ref GpuChannelGraphicsState graphicsState, |
304 | ShaderAddresses addresses) | 308 | ShaderAddresses addresses) |
@@ -319,7 +323,7 @@ namespace Ryujinx.Graphics.Gpu.Shader | |||
319 | UpdatePipelineInfo(ref state, ref pipeline, graphicsState, channel); | 323 | UpdatePipelineInfo(ref state, ref pipeline, graphicsState, channel); |
320 | 324 | ||
321 | ShaderSpecializationState specState = new(ref graphicsState, ref pipeline, transformFeedbackDescriptors); | 325 | ShaderSpecializationState specState = new(ref graphicsState, ref pipeline, transformFeedbackDescriptors); |
322 | GpuAccessorState gpuAccessorState = new(poolState, default, graphicsState, specState, transformFeedbackDescriptors); | 326 | GpuAccessorState gpuAccessorState = new(samplerPoolMaximumId, poolState, default, graphicsState, specState, transformFeedbackDescriptors); |
323 | 327 | ||
324 | ReadOnlySpan<ulong> addressesSpan = addresses.AsSpan(); | 328 | ReadOnlySpan<ulong> addressesSpan = addresses.AsSpan(); |
325 | 329 | ||
diff --git a/src/Ryujinx.Graphics.Gpu/Shader/ShaderInfoBuilder.cs b/src/Ryujinx.Graphics.Gpu/Shader/ShaderInfoBuilder.cs index ea8f164f1..ed56db3b3 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/ShaderInfoBuilder.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/ShaderInfoBuilder.cs | |||
@@ -185,11 +185,7 @@ namespace Ryujinx.Graphics.Gpu.Shader | |||
185 | { | 185 | { |
186 | if (texture.ArrayLength > 1) | 186 | if (texture.ArrayLength > 1) |
187 | { | 187 | { |
188 | bool isBuffer = (texture.Type & SamplerType.Mask) == SamplerType.TextureBuffer; | 188 | ResourceType type = GetTextureResourceType(texture, isImage); |
189 | |||
190 | ResourceType type = isBuffer | ||
191 | ? (isImage ? ResourceType.BufferImage : ResourceType.BufferTexture) | ||
192 | : (isImage ? ResourceType.Image : ResourceType.TextureAndSampler); | ||
193 | 189 | ||
194 | _resourceDescriptors[setIndex].Add(new ResourceDescriptor(texture.Binding, texture.ArrayLength, type, stages)); | 190 | _resourceDescriptors[setIndex].Add(new ResourceDescriptor(texture.Binding, texture.ArrayLength, type, stages)); |
195 | } | 191 | } |
@@ -242,16 +238,38 @@ namespace Ryujinx.Graphics.Gpu.Shader | |||
242 | { | 238 | { |
243 | foreach (TextureDescriptor texture in textures) | 239 | foreach (TextureDescriptor texture in textures) |
244 | { | 240 | { |
245 | bool isBuffer = (texture.Type & SamplerType.Mask) == SamplerType.TextureBuffer; | 241 | ResourceType type = GetTextureResourceType(texture, isImage); |
246 | |||
247 | ResourceType type = isBuffer | ||
248 | ? (isImage ? ResourceType.BufferImage : ResourceType.BufferTexture) | ||
249 | : (isImage ? ResourceType.Image : ResourceType.TextureAndSampler); | ||
250 | 242 | ||
251 | _resourceUsages[setIndex].Add(new ResourceUsage(texture.Binding, texture.ArrayLength, type, stages)); | 243 | _resourceUsages[setIndex].Add(new ResourceUsage(texture.Binding, texture.ArrayLength, type, stages)); |
252 | } | 244 | } |
253 | } | 245 | } |
254 | 246 | ||
247 | private static ResourceType GetTextureResourceType(TextureDescriptor texture, bool isImage) | ||
248 | { | ||
249 | bool isBuffer = (texture.Type & SamplerType.Mask) == SamplerType.TextureBuffer; | ||
250 | |||
251 | if (isBuffer) | ||
252 | { | ||
253 | return isImage ? ResourceType.BufferImage : ResourceType.BufferTexture; | ||
254 | } | ||
255 | else if (isImage) | ||
256 | { | ||
257 | return ResourceType.Image; | ||
258 | } | ||
259 | else if (texture.Type == SamplerType.None) | ||
260 | { | ||
261 | return ResourceType.Sampler; | ||
262 | } | ||
263 | else if (texture.Separate) | ||
264 | { | ||
265 | return ResourceType.Texture; | ||
266 | } | ||
267 | else | ||
268 | { | ||
269 | return ResourceType.TextureAndSampler; | ||
270 | } | ||
271 | } | ||
272 | |||
255 | /// <summary> | 273 | /// <summary> |
256 | /// Creates a new shader information structure from the added information. | 274 | /// Creates a new shader information structure from the added information. |
257 | /// </summary> | 275 | /// </summary> |
diff --git a/src/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs b/src/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs index c90a0b8f4..98acb6f27 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs | |||
@@ -31,6 +31,7 @@ namespace Ryujinx.Graphics.Gpu.Shader | |||
31 | PrimitiveTopology = 1 << 1, | 31 | PrimitiveTopology = 1 << 1, |
32 | TransformFeedback = 1 << 3, | 32 | TransformFeedback = 1 << 3, |
33 | TextureArrayFromBuffer = 1 << 4, | 33 | TextureArrayFromBuffer = 1 << 4, |
34 | TextureArrayFromPool = 1 << 5, | ||
34 | } | 35 | } |
35 | 36 | ||
36 | private QueriedStateFlags _queriedState; | 37 | private QueriedStateFlags _queriedState; |
@@ -154,7 +155,8 @@ namespace Ryujinx.Graphics.Gpu.Shader | |||
154 | } | 155 | } |
155 | 156 | ||
156 | private readonly Dictionary<TextureKey, Box<TextureSpecializationState>> _textureSpecialization; | 157 | private readonly Dictionary<TextureKey, Box<TextureSpecializationState>> _textureSpecialization; |
157 | private readonly Dictionary<TextureKey, int> _textureArraySpecialization; | 158 | private readonly Dictionary<TextureKey, int> _textureArrayFromBufferSpecialization; |
159 | private readonly Dictionary<bool, int> _textureArrayFromPoolSpecialization; | ||
158 | private KeyValuePair<TextureKey, Box<TextureSpecializationState>>[] _allTextures; | 160 | private KeyValuePair<TextureKey, Box<TextureSpecializationState>>[] _allTextures; |
159 | private Box<TextureSpecializationState>[][] _textureByBinding; | 161 | private Box<TextureSpecializationState>[][] _textureByBinding; |
160 | private Box<TextureSpecializationState>[][] _imageByBinding; | 162 | private Box<TextureSpecializationState>[][] _imageByBinding; |
@@ -165,7 +167,8 @@ namespace Ryujinx.Graphics.Gpu.Shader | |||
165 | private ShaderSpecializationState() | 167 | private ShaderSpecializationState() |
166 | { | 168 | { |
167 | _textureSpecialization = new Dictionary<TextureKey, Box<TextureSpecializationState>>(); | 169 | _textureSpecialization = new Dictionary<TextureKey, Box<TextureSpecializationState>>(); |
168 | _textureArraySpecialization = new Dictionary<TextureKey, int>(); | 170 | _textureArrayFromBufferSpecialization = new Dictionary<TextureKey, int>(); |
171 | _textureArrayFromPoolSpecialization = new Dictionary<bool, int>(); | ||
169 | } | 172 | } |
170 | 173 | ||
171 | /// <summary> | 174 | /// <summary> |
@@ -327,7 +330,7 @@ namespace Ryujinx.Graphics.Gpu.Shader | |||
327 | } | 330 | } |
328 | 331 | ||
329 | /// <summary> | 332 | /// <summary> |
330 | /// Indicates that the coordinate normalization state of a given texture was used during the shader translation process. | 333 | /// Registers the length of a texture array calculated from a constant buffer size. |
331 | /// </summary> | 334 | /// </summary> |
332 | /// <param name="stageIndex">Shader stage where the texture is used</param> | 335 | /// <param name="stageIndex">Shader stage where the texture is used</param> |
333 | /// <param name="handle">Offset in words of the texture handle on the texture buffer</param> | 336 | /// <param name="handle">Offset in words of the texture handle on the texture buffer</param> |
@@ -335,11 +338,22 @@ namespace Ryujinx.Graphics.Gpu.Shader | |||
335 | /// <param name="length">Number of elements in the texture array</param> | 338 | /// <param name="length">Number of elements in the texture array</param> |
336 | public void RegisterTextureArrayLengthFromBuffer(int stageIndex, int handle, int cbufSlot, int length) | 339 | public void RegisterTextureArrayLengthFromBuffer(int stageIndex, int handle, int cbufSlot, int length) |
337 | { | 340 | { |
338 | _textureArraySpecialization[new TextureKey(stageIndex, handle, cbufSlot)] = length; | 341 | _textureArrayFromBufferSpecialization[new TextureKey(stageIndex, handle, cbufSlot)] = length; |
339 | _queriedState |= QueriedStateFlags.TextureArrayFromBuffer; | 342 | _queriedState |= QueriedStateFlags.TextureArrayFromBuffer; |
340 | } | 343 | } |
341 | 344 | ||
342 | /// <summary> | 345 | /// <summary> |
346 | /// Registers the length of a texture array calculated from a texture or sampler pool capacity. | ||
347 | /// </summary> | ||
348 | /// <param name="isSampler">True for sampler pool, false for texture pool</param> | ||
349 | /// <param name="length">Number of elements in the texture array</param> | ||
350 | public void RegisterTextureArrayLengthFromPool(bool isSampler, int length) | ||
351 | { | ||
352 | _textureArrayFromPoolSpecialization[isSampler] = length; | ||
353 | _queriedState |= QueriedStateFlags.TextureArrayFromPool; | ||
354 | } | ||
355 | |||
356 | /// <summary> | ||
343 | /// Indicates that the format of a given texture was used during the shader translation process. | 357 | /// Indicates that the format of a given texture was used during the shader translation process. |
344 | /// </summary> | 358 | /// </summary> |
345 | /// <param name="stageIndex">Shader stage where the texture is used</param> | 359 | /// <param name="stageIndex">Shader stage where the texture is used</param> |
@@ -385,7 +399,7 @@ namespace Ryujinx.Graphics.Gpu.Shader | |||
385 | } | 399 | } |
386 | 400 | ||
387 | /// <summary> | 401 | /// <summary> |
388 | /// Checks if a given texture was registerd on this specialization state. | 402 | /// Checks if a given texture was registered on this specialization state. |
389 | /// </summary> | 403 | /// </summary> |
390 | /// <param name="stageIndex">Shader stage where the texture is used</param> | 404 | /// <param name="stageIndex">Shader stage where the texture is used</param> |
391 | /// <param name="handle">Offset in words of the texture handle on the texture buffer</param> | 405 | /// <param name="handle">Offset in words of the texture handle on the texture buffer</param> |
@@ -396,14 +410,25 @@ namespace Ryujinx.Graphics.Gpu.Shader | |||
396 | } | 410 | } |
397 | 411 | ||
398 | /// <summary> | 412 | /// <summary> |
399 | /// Checks if a given texture array (from constant buffer) was registerd on this specialization state. | 413 | /// Checks if a given texture array (from constant buffer) was registered on this specialization state. |
400 | /// </summary> | 414 | /// </summary> |
401 | /// <param name="stageIndex">Shader stage where the texture is used</param> | 415 | /// <param name="stageIndex">Shader stage where the texture is used</param> |
402 | /// <param name="handle">Offset in words of the texture handle on the texture buffer</param> | 416 | /// <param name="handle">Offset in words of the texture handle on the texture buffer</param> |
403 | /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param> | 417 | /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param> |
418 | /// <returns>True if the length for the given buffer and stage exists, false otherwise</returns> | ||
404 | public bool TextureArrayFromBufferRegistered(int stageIndex, int handle, int cbufSlot) | 419 | public bool TextureArrayFromBufferRegistered(int stageIndex, int handle, int cbufSlot) |
405 | { | 420 | { |
406 | return _textureArraySpecialization.ContainsKey(new TextureKey(stageIndex, handle, cbufSlot)); | 421 | return _textureArrayFromBufferSpecialization.ContainsKey(new TextureKey(stageIndex, handle, cbufSlot)); |
422 | } | ||
423 | |||
424 | /// <summary> | ||
425 | /// Checks if a given texture array (from a sampler pool or texture pool) was registered on this specialization state. | ||
426 | /// </summary> | ||
427 | /// <param name="isSampler">True for sampler pool, false for texture pool</param> | ||
428 | /// <returns>True if the length for the given pool, false otherwise</returns> | ||
429 | public bool TextureArrayFromPoolRegistered(bool isSampler) | ||
430 | { | ||
431 | return _textureArrayFromPoolSpecialization.ContainsKey(isSampler); | ||
407 | } | 432 | } |
408 | 433 | ||
409 | /// <summary> | 434 | /// <summary> |
@@ -412,6 +437,7 @@ namespace Ryujinx.Graphics.Gpu.Shader | |||
412 | /// <param name="stageIndex">Shader stage where the texture is used</param> | 437 | /// <param name="stageIndex">Shader stage where the texture is used</param> |
413 | /// <param name="handle">Offset in words of the texture handle on the texture buffer</param> | 438 | /// <param name="handle">Offset in words of the texture handle on the texture buffer</param> |
414 | /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param> | 439 | /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param> |
440 | /// <returns>Format and sRGB tuple</returns> | ||
415 | public (uint, bool) GetFormat(int stageIndex, int handle, int cbufSlot) | 441 | public (uint, bool) GetFormat(int stageIndex, int handle, int cbufSlot) |
416 | { | 442 | { |
417 | TextureSpecializationState state = GetTextureSpecState(stageIndex, handle, cbufSlot).Value; | 443 | TextureSpecializationState state = GetTextureSpecState(stageIndex, handle, cbufSlot).Value; |
@@ -424,6 +450,7 @@ namespace Ryujinx.Graphics.Gpu.Shader | |||
424 | /// <param name="stageIndex">Shader stage where the texture is used</param> | 450 | /// <param name="stageIndex">Shader stage where the texture is used</param> |
425 | /// <param name="handle">Offset in words of the texture handle on the texture buffer</param> | 451 | /// <param name="handle">Offset in words of the texture handle on the texture buffer</param> |
426 | /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param> | 452 | /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param> |
453 | /// <returns>Texture target</returns> | ||
427 | public TextureTarget GetTextureTarget(int stageIndex, int handle, int cbufSlot) | 454 | public TextureTarget GetTextureTarget(int stageIndex, int handle, int cbufSlot) |
428 | { | 455 | { |
429 | return GetTextureSpecState(stageIndex, handle, cbufSlot).Value.TextureTarget; | 456 | return GetTextureSpecState(stageIndex, handle, cbufSlot).Value.TextureTarget; |
@@ -435,6 +462,7 @@ namespace Ryujinx.Graphics.Gpu.Shader | |||
435 | /// <param name="stageIndex">Shader stage where the texture is used</param> | 462 | /// <param name="stageIndex">Shader stage where the texture is used</param> |
436 | /// <param name="handle">Offset in words of the texture handle on the texture buffer</param> | 463 | /// <param name="handle">Offset in words of the texture handle on the texture buffer</param> |
437 | /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param> | 464 | /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param> |
465 | /// <returns>True if coordinates are normalized, false otherwise</returns> | ||
438 | public bool GetCoordNormalized(int stageIndex, int handle, int cbufSlot) | 466 | public bool GetCoordNormalized(int stageIndex, int handle, int cbufSlot) |
439 | { | 467 | { |
440 | return GetTextureSpecState(stageIndex, handle, cbufSlot).Value.CoordNormalized; | 468 | return GetTextureSpecState(stageIndex, handle, cbufSlot).Value.CoordNormalized; |
@@ -446,9 +474,20 @@ namespace Ryujinx.Graphics.Gpu.Shader | |||
446 | /// <param name="stageIndex">Shader stage where the texture is used</param> | 474 | /// <param name="stageIndex">Shader stage where the texture is used</param> |
447 | /// <param name="handle">Offset in words of the texture handle on the texture buffer</param> | 475 | /// <param name="handle">Offset in words of the texture handle on the texture buffer</param> |
448 | /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param> | 476 | /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param> |
477 | /// <returns>Texture array length</returns> | ||
449 | public int GetTextureArrayFromBufferLength(int stageIndex, int handle, int cbufSlot) | 478 | public int GetTextureArrayFromBufferLength(int stageIndex, int handle, int cbufSlot) |
450 | { | 479 | { |
451 | return _textureArraySpecialization[new TextureKey(stageIndex, handle, cbufSlot)]; | 480 | return _textureArrayFromBufferSpecialization[new TextureKey(stageIndex, handle, cbufSlot)]; |
481 | } | ||
482 | |||
483 | /// <summary> | ||
484 | /// Gets the recorded length of a given texture array (from a sampler or texture pool). | ||
485 | /// </summary> | ||
486 | /// <param name="isSampler">True to get the sampler pool length, false to get the texture pool length</param> | ||
487 | /// <returns>Texture array length</returns> | ||
488 | public int GetTextureArrayFromPoolLength(bool isSampler) | ||
489 | { | ||
490 | return _textureArrayFromPoolSpecialization[isSampler]; | ||
452 | } | 491 | } |
453 | 492 | ||
454 | /// <summary> | 493 | /// <summary> |
@@ -894,7 +933,23 @@ namespace Ryujinx.Graphics.Gpu.Shader | |||
894 | dataReader.ReadWithMagicAndSize(ref textureKey, TexkMagic); | 933 | dataReader.ReadWithMagicAndSize(ref textureKey, TexkMagic); |
895 | dataReader.Read(ref length); | 934 | dataReader.Read(ref length); |
896 | 935 | ||
897 | specState._textureArraySpecialization[textureKey] = length; | 936 | specState._textureArrayFromBufferSpecialization[textureKey] = length; |
937 | } | ||
938 | } | ||
939 | |||
940 | if (specState._queriedState.HasFlag(QueriedStateFlags.TextureArrayFromPool)) | ||
941 | { | ||
942 | dataReader.Read(ref count); | ||
943 | |||
944 | for (int index = 0; index < count; index++) | ||
945 | { | ||
946 | bool textureKey = default; | ||
947 | int length = 0; | ||
948 | |||
949 | dataReader.ReadWithMagicAndSize(ref textureKey, TexkMagic); | ||
950 | dataReader.Read(ref length); | ||
951 | |||
952 | specState._textureArrayFromPoolSpecialization[textureKey] = length; | ||
898 | } | 953 | } |
899 | } | 954 | } |
900 | 955 | ||
@@ -965,10 +1020,25 @@ namespace Ryujinx.Graphics.Gpu.Shader | |||
965 | 1020 | ||
966 | if (_queriedState.HasFlag(QueriedStateFlags.TextureArrayFromBuffer)) | 1021 | if (_queriedState.HasFlag(QueriedStateFlags.TextureArrayFromBuffer)) |
967 | { | 1022 | { |
968 | count = (ushort)_textureArraySpecialization.Count; | 1023 | count = (ushort)_textureArrayFromBufferSpecialization.Count; |
1024 | dataWriter.Write(ref count); | ||
1025 | |||
1026 | foreach (var kv in _textureArrayFromBufferSpecialization) | ||
1027 | { | ||
1028 | var textureKey = kv.Key; | ||
1029 | var length = kv.Value; | ||
1030 | |||
1031 | dataWriter.WriteWithMagicAndSize(ref textureKey, TexkMagic); | ||
1032 | dataWriter.Write(ref length); | ||
1033 | } | ||
1034 | } | ||
1035 | |||
1036 | if (_queriedState.HasFlag(QueriedStateFlags.TextureArrayFromPool)) | ||
1037 | { | ||
1038 | count = (ushort)_textureArrayFromPoolSpecialization.Count; | ||
969 | dataWriter.Write(ref count); | 1039 | dataWriter.Write(ref count); |
970 | 1040 | ||
971 | foreach (var kv in _textureArraySpecialization) | 1041 | foreach (var kv in _textureArrayFromPoolSpecialization) |
972 | { | 1042 | { |
973 | var textureKey = kv.Key; | 1043 | var textureKey = kv.Key; |
974 | var length = kv.Value; | 1044 | var length = kv.Value; |
diff --git a/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs b/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs index a945cbf20..d56c40af4 100644 --- a/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs +++ b/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs | |||
@@ -176,6 +176,7 @@ namespace Ryujinx.Graphics.OpenGL | |||
176 | supportsCubemapView: true, | 176 | supportsCubemapView: true, |
177 | supportsNonConstantTextureOffset: HwCapabilities.SupportsNonConstantTextureOffset, | 177 | supportsNonConstantTextureOffset: HwCapabilities.SupportsNonConstantTextureOffset, |
178 | supportsScaledVertexFormats: true, | 178 | supportsScaledVertexFormats: true, |
179 | supportsSeparateSampler: false, | ||
179 | supportsShaderBallot: HwCapabilities.SupportsShaderBallot, | 180 | supportsShaderBallot: HwCapabilities.SupportsShaderBallot, |
180 | supportsShaderBarrierDivergence: !(intelWindows || intelUnix), | 181 | supportsShaderBarrierDivergence: !(intelWindows || intelUnix), |
181 | supportsShaderFloat64: true, | 182 | supportsShaderFloat64: true, |
diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs index 763487dac..eb6c689b8 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs | |||
@@ -6,7 +6,6 @@ using System; | |||
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
7 | using System.Globalization; | 7 | using System.Globalization; |
8 | using System.Linq; | 8 | using System.Linq; |
9 | using System.Numerics; | ||
10 | 9 | ||
11 | namespace Ryujinx.Graphics.Shader.CodeGen.Glsl | 10 | namespace Ryujinx.Graphics.Shader.CodeGen.Glsl |
12 | { | 11 | { |
@@ -352,7 +351,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl | |||
352 | arrayDecl = "[]"; | 351 | arrayDecl = "[]"; |
353 | } | 352 | } |
354 | 353 | ||
355 | string samplerTypeName = definition.Type.ToGlslSamplerType(); | 354 | string samplerTypeName = definition.Separate ? definition.Type.ToGlslTextureType() : definition.Type.ToGlslSamplerType(); |
356 | 355 | ||
357 | string layout = string.Empty; | 356 | string layout = string.Empty; |
358 | 357 | ||
diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs index b4773b819..f0e57b534 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs | |||
@@ -639,14 +639,27 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions | |||
639 | 639 | ||
640 | private static string GetSamplerName(CodeGenContext context, AstTextureOperation texOp, ref int srcIndex) | 640 | private static string GetSamplerName(CodeGenContext context, AstTextureOperation texOp, ref int srcIndex) |
641 | { | 641 | { |
642 | TextureDefinition definition = context.Properties.Textures[texOp.Binding]; | 642 | TextureDefinition textureDefinition = context.Properties.Textures[texOp.Binding]; |
643 | string name = definition.Name; | 643 | string name = textureDefinition.Name; |
644 | 644 | ||
645 | if (definition.ArrayLength != 1) | 645 | if (textureDefinition.ArrayLength != 1) |
646 | { | 646 | { |
647 | name = $"{name}[{GetSourceExpr(context, texOp.GetSource(srcIndex++), AggregateType.S32)}]"; | 647 | name = $"{name}[{GetSourceExpr(context, texOp.GetSource(srcIndex++), AggregateType.S32)}]"; |
648 | } | 648 | } |
649 | 649 | ||
650 | if (texOp.IsSeparate) | ||
651 | { | ||
652 | TextureDefinition samplerDefinition = context.Properties.Textures[texOp.SamplerBinding]; | ||
653 | string samplerName = samplerDefinition.Name; | ||
654 | |||
655 | if (samplerDefinition.ArrayLength != 1) | ||
656 | { | ||
657 | samplerName = $"{samplerName}[{GetSourceExpr(context, texOp.GetSource(srcIndex++), AggregateType.S32)}]"; | ||
658 | } | ||
659 | |||
660 | name = $"{texOp.Type.ToGlslSamplerType()}({name}, {samplerName})"; | ||
661 | } | ||
662 | |||
650 | return name; | 663 | return name; |
651 | } | 664 | } |
652 | 665 | ||
diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs index 9633c522e..37df4df80 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs | |||
@@ -160,37 +160,49 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv | |||
160 | { | 160 | { |
161 | int setIndex = context.TargetApi == TargetApi.Vulkan ? sampler.Set : 0; | 161 | int setIndex = context.TargetApi == TargetApi.Vulkan ? sampler.Set : 0; |
162 | 162 | ||
163 | var dim = (sampler.Type & SamplerType.Mask) switch | 163 | SpvInstruction imageType; |
164 | SpvInstruction sampledImageType; | ||
165 | |||
166 | if (sampler.Type != SamplerType.None) | ||
164 | { | 167 | { |
165 | SamplerType.Texture1D => Dim.Dim1D, | 168 | var dim = (sampler.Type & SamplerType.Mask) switch |
166 | SamplerType.Texture2D => Dim.Dim2D, | 169 | { |
167 | SamplerType.Texture3D => Dim.Dim3D, | 170 | SamplerType.Texture1D => Dim.Dim1D, |
168 | SamplerType.TextureCube => Dim.Cube, | 171 | SamplerType.Texture2D => Dim.Dim2D, |
169 | SamplerType.TextureBuffer => Dim.Buffer, | 172 | SamplerType.Texture3D => Dim.Dim3D, |
170 | _ => throw new InvalidOperationException($"Invalid sampler type \"{sampler.Type & SamplerType.Mask}\"."), | 173 | SamplerType.TextureCube => Dim.Cube, |
171 | }; | 174 | SamplerType.TextureBuffer => Dim.Buffer, |
175 | _ => throw new InvalidOperationException($"Invalid sampler type \"{sampler.Type & SamplerType.Mask}\"."), | ||
176 | }; | ||
177 | |||
178 | imageType = context.TypeImage( | ||
179 | context.TypeFP32(), | ||
180 | dim, | ||
181 | sampler.Type.HasFlag(SamplerType.Shadow), | ||
182 | sampler.Type.HasFlag(SamplerType.Array), | ||
183 | sampler.Type.HasFlag(SamplerType.Multisample), | ||
184 | 1, | ||
185 | ImageFormat.Unknown); | ||
186 | |||
187 | sampledImageType = context.TypeSampledImage(imageType); | ||
188 | } | ||
189 | else | ||
190 | { | ||
191 | imageType = sampledImageType = context.TypeSampler(); | ||
192 | } | ||
172 | 193 | ||
173 | var imageType = context.TypeImage( | 194 | var sampledOrSeparateImageType = sampler.Separate ? imageType : sampledImageType; |
174 | context.TypeFP32(), | 195 | var sampledImagePointerType = context.TypePointer(StorageClass.UniformConstant, sampledOrSeparateImageType); |
175 | dim, | ||
176 | sampler.Type.HasFlag(SamplerType.Shadow), | ||
177 | sampler.Type.HasFlag(SamplerType.Array), | ||
178 | sampler.Type.HasFlag(SamplerType.Multisample), | ||
179 | 1, | ||
180 | ImageFormat.Unknown); | ||
181 | |||
182 | var sampledImageType = context.TypeSampledImage(imageType); | ||
183 | var sampledImagePointerType = context.TypePointer(StorageClass.UniformConstant, sampledImageType); | ||
184 | var sampledImageArrayPointerType = sampledImagePointerType; | 196 | var sampledImageArrayPointerType = sampledImagePointerType; |
185 | 197 | ||
186 | if (sampler.ArrayLength == 0) | 198 | if (sampler.ArrayLength == 0) |
187 | { | 199 | { |
188 | var sampledImageArrayType = context.TypeRuntimeArray(sampledImageType); | 200 | var sampledImageArrayType = context.TypeRuntimeArray(sampledOrSeparateImageType); |
189 | sampledImageArrayPointerType = context.TypePointer(StorageClass.UniformConstant, sampledImageArrayType); | 201 | sampledImageArrayPointerType = context.TypePointer(StorageClass.UniformConstant, sampledImageArrayType); |
190 | } | 202 | } |
191 | else if (sampler.ArrayLength != 1) | 203 | else if (sampler.ArrayLength != 1) |
192 | { | 204 | { |
193 | var sampledImageArrayType = context.TypeArray(sampledImageType, context.Constant(context.TypeU32(), sampler.ArrayLength)); | 205 | var sampledImageArrayType = context.TypeArray(sampledOrSeparateImageType, context.Constant(context.TypeU32(), sampler.ArrayLength)); |
194 | sampledImageArrayPointerType = context.TypePointer(StorageClass.UniformConstant, sampledImageArrayType); | 206 | sampledImageArrayPointerType = context.TypePointer(StorageClass.UniformConstant, sampledImageArrayType); |
195 | } | 207 | } |
196 | 208 | ||
diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs index 409e466cd..34f8532a6 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs | |||
@@ -838,16 +838,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv | |||
838 | } | 838 | } |
839 | 839 | ||
840 | SamplerDeclaration declaration = context.Samplers[texOp.Binding]; | 840 | SamplerDeclaration declaration = context.Samplers[texOp.Binding]; |
841 | SpvInstruction image = declaration.Image; | 841 | SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex); |
842 | |||
843 | if (declaration.IsIndexed) | ||
844 | { | ||
845 | SpvInstruction textureIndex = Src(AggregateType.S32); | ||
846 | |||
847 | image = context.AccessChain(declaration.SampledImagePointerType, image, textureIndex); | ||
848 | } | ||
849 | |||
850 | image = context.Load(declaration.SampledImageType, image); | ||
851 | 842 | ||
852 | int pCount = texOp.Type.GetDimensions(); | 843 | int pCount = texOp.Type.GetDimensions(); |
853 | 844 | ||
@@ -1171,16 +1162,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv | |||
1171 | } | 1162 | } |
1172 | 1163 | ||
1173 | SamplerDeclaration declaration = context.Samplers[texOp.Binding]; | 1164 | SamplerDeclaration declaration = context.Samplers[texOp.Binding]; |
1174 | SpvInstruction image = declaration.Image; | 1165 | SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex); |
1175 | |||
1176 | if (declaration.IsIndexed) | ||
1177 | { | ||
1178 | SpvInstruction textureIndex = Src(AggregateType.S32); | ||
1179 | |||
1180 | image = context.AccessChain(declaration.SampledImagePointerType, image, textureIndex); | ||
1181 | } | ||
1182 | |||
1183 | image = context.Load(declaration.SampledImageType, image); | ||
1184 | 1166 | ||
1185 | int coordsCount = texOp.Type.GetDimensions(); | 1167 | int coordsCount = texOp.Type.GetDimensions(); |
1186 | 1168 | ||
@@ -1449,17 +1431,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv | |||
1449 | { | 1431 | { |
1450 | AstTextureOperation texOp = (AstTextureOperation)operation; | 1432 | AstTextureOperation texOp = (AstTextureOperation)operation; |
1451 | 1433 | ||
1452 | SamplerDeclaration declaration = context.Samplers[texOp.Binding]; | 1434 | int srcIndex = 0; |
1453 | SpvInstruction image = declaration.Image; | ||
1454 | |||
1455 | if (declaration.IsIndexed) | ||
1456 | { | ||
1457 | SpvInstruction textureIndex = context.GetS32(texOp.GetSource(0)); | ||
1458 | 1435 | ||
1459 | image = context.AccessChain(declaration.SampledImagePointerType, image, textureIndex); | 1436 | SamplerDeclaration declaration = context.Samplers[texOp.Binding]; |
1460 | } | 1437 | SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex); |
1461 | 1438 | ||
1462 | image = context.Load(declaration.SampledImageType, image); | ||
1463 | image = context.Image(declaration.ImageType, image); | 1439 | image = context.Image(declaration.ImageType, image); |
1464 | 1440 | ||
1465 | SpvInstruction result = context.ImageQuerySamples(context.TypeS32(), image); | 1441 | SpvInstruction result = context.ImageQuerySamples(context.TypeS32(), image); |
@@ -1471,17 +1447,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv | |||
1471 | { | 1447 | { |
1472 | AstTextureOperation texOp = (AstTextureOperation)operation; | 1448 | AstTextureOperation texOp = (AstTextureOperation)operation; |
1473 | 1449 | ||
1474 | SamplerDeclaration declaration = context.Samplers[texOp.Binding]; | 1450 | int srcIndex = 0; |
1475 | SpvInstruction image = declaration.Image; | ||
1476 | |||
1477 | if (declaration.IsIndexed) | ||
1478 | { | ||
1479 | SpvInstruction textureIndex = context.GetS32(texOp.GetSource(0)); | ||
1480 | 1451 | ||
1481 | image = context.AccessChain(declaration.SampledImagePointerType, image, textureIndex); | 1452 | SamplerDeclaration declaration = context.Samplers[texOp.Binding]; |
1482 | } | 1453 | SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex); |
1483 | 1454 | ||
1484 | image = context.Load(declaration.SampledImageType, image); | ||
1485 | image = context.Image(declaration.ImageType, image); | 1455 | image = context.Image(declaration.ImageType, image); |
1486 | 1456 | ||
1487 | if (texOp.Index == 3) | 1457 | if (texOp.Index == 3) |
@@ -1506,8 +1476,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv | |||
1506 | 1476 | ||
1507 | if (hasLod) | 1477 | if (hasLod) |
1508 | { | 1478 | { |
1509 | int lodSrcIndex = declaration.IsIndexed ? 1 : 0; | 1479 | var lod = context.GetS32(operation.GetSource(srcIndex)); |
1510 | var lod = context.GetS32(operation.GetSource(lodSrcIndex)); | ||
1511 | result = context.ImageQuerySizeLod(resultType, image, lod); | 1480 | result = context.ImageQuerySizeLod(resultType, image, lod); |
1512 | } | 1481 | } |
1513 | else | 1482 | else |
@@ -1905,6 +1874,43 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv | |||
1905 | } | 1874 | } |
1906 | } | 1875 | } |
1907 | 1876 | ||
1877 | private static SpvInstruction GenerateSampledImageLoad(CodeGenContext context, AstTextureOperation texOp, SamplerDeclaration declaration, ref int srcIndex) | ||
1878 | { | ||
1879 | SpvInstruction image = declaration.Image; | ||
1880 | |||
1881 | if (declaration.IsIndexed) | ||
1882 | { | ||
1883 | SpvInstruction textureIndex = context.Get(AggregateType.S32, texOp.GetSource(srcIndex++)); | ||
1884 | |||
1885 | image = context.AccessChain(declaration.SampledImagePointerType, image, textureIndex); | ||
1886 | } | ||
1887 | |||
1888 | if (texOp.IsSeparate) | ||
1889 | { | ||
1890 | image = context.Load(declaration.ImageType, image); | ||
1891 | |||
1892 | SamplerDeclaration samplerDeclaration = context.Samplers[texOp.SamplerBinding]; | ||
1893 | |||
1894 | SpvInstruction sampler = samplerDeclaration.Image; | ||
1895 | |||
1896 | if (samplerDeclaration.IsIndexed) | ||
1897 | { | ||
1898 | SpvInstruction samplerIndex = context.Get(AggregateType.S32, texOp.GetSource(srcIndex++)); | ||
1899 | |||
1900 | sampler = context.AccessChain(samplerDeclaration.SampledImagePointerType, sampler, samplerIndex); | ||
1901 | } | ||
1902 | |||
1903 | sampler = context.Load(samplerDeclaration.ImageType, sampler); | ||
1904 | image = context.SampledImage(declaration.SampledImageType, image, sampler); | ||
1905 | } | ||
1906 | else | ||
1907 | { | ||
1908 | image = context.Load(declaration.SampledImageType, image); | ||
1909 | } | ||
1910 | |||
1911 | return image; | ||
1912 | } | ||
1913 | |||
1908 | private static OperationResult GenerateUnary( | 1914 | private static OperationResult GenerateUnary( |
1909 | CodeGenContext context, | 1915 | CodeGenContext context, |
1910 | AstOperation operation, | 1916 | AstOperation operation, |
diff --git a/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs b/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs index 99366ad67..b1a9f9f84 100644 --- a/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs +++ b/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs | |||
@@ -27,13 +27,6 @@ namespace Ryujinx.Graphics.Shader | |||
27 | ReadOnlySpan<ulong> GetCode(ulong address, int minimumSize); | 27 | ReadOnlySpan<ulong> GetCode(ulong address, int minimumSize); |
28 | 28 | ||
29 | /// <summary> | 29 | /// <summary> |
30 | /// Gets the size in bytes of a bound constant buffer for the current shader stage. | ||
31 | /// </summary> | ||
32 | /// <param name="slot">The number of the constant buffer to get the size from</param> | ||
33 | /// <returns>Size in bytes</returns> | ||
34 | int QueryTextureArrayLengthFromBuffer(int slot); | ||
35 | |||
36 | /// <summary> | ||
37 | /// Queries the binding number of a constant buffer. | 30 | /// Queries the binding number of a constant buffer. |
38 | /// </summary> | 31 | /// </summary> |
39 | /// <param name="index">Constant buffer index</param> | 32 | /// <param name="index">Constant buffer index</param> |
@@ -299,6 +292,15 @@ namespace Ryujinx.Graphics.Shader | |||
299 | } | 292 | } |
300 | 293 | ||
301 | /// <summary> | 294 | /// <summary> |
295 | /// Queries host API support for separate textures and samplers. | ||
296 | /// </summary> | ||
297 | /// <returns>True if the API supports samplers and textures to be combined on the shader, false otherwise</returns> | ||
298 | bool QueryHostSupportsSeparateSampler() | ||
299 | { | ||
300 | return true; | ||
301 | } | ||
302 | |||
303 | /// <summary> | ||
302 | /// Queries host GPU shader ballot support. | 304 | /// Queries host GPU shader ballot support. |
303 | /// </summary> | 305 | /// </summary> |
304 | /// <returns>True if the GPU and driver supports shader ballot, false otherwise</returns> | 306 | /// <returns>True if the GPU and driver supports shader ballot, false otherwise</returns> |
@@ -389,6 +391,12 @@ namespace Ryujinx.Graphics.Shader | |||
389 | } | 391 | } |
390 | 392 | ||
391 | /// <summary> | 393 | /// <summary> |
394 | /// Gets the maximum number of samplers that the bound texture pool may have. | ||
395 | /// </summary> | ||
396 | /// <returns>Maximum amount of samplers that the pool may have</returns> | ||
397 | int QuerySamplerArrayLengthFromPool(); | ||
398 | |||
399 | /// <summary> | ||
392 | /// Queries sampler type information. | 400 | /// Queries sampler type information. |
393 | /// </summary> | 401 | /// </summary> |
394 | /// <param name="handle">Texture handle</param> | 402 | /// <param name="handle">Texture handle</param> |
@@ -400,6 +408,19 @@ namespace Ryujinx.Graphics.Shader | |||
400 | } | 408 | } |
401 | 409 | ||
402 | /// <summary> | 410 | /// <summary> |
411 | /// Gets the size in bytes of a bound constant buffer for the current shader stage. | ||
412 | /// </summary> | ||
413 | /// <param name="slot">The number of the constant buffer to get the size from</param> | ||
414 | /// <returns>Size in bytes</returns> | ||
415 | int QueryTextureArrayLengthFromBuffer(int slot); | ||
416 | |||
417 | /// <summary> | ||
418 | /// Gets the maximum number of textures that the bound texture pool may have. | ||
419 | /// </summary> | ||
420 | /// <returns>Maximum amount of textures that the pool may have</returns> | ||
421 | int QueryTextureArrayLengthFromPool(); | ||
422 | |||
423 | /// <summary> | ||
403 | /// Queries texture coordinate normalization information. | 424 | /// Queries texture coordinate normalization information. |
404 | /// </summary> | 425 | /// </summary> |
405 | /// <param name="handle">Texture handle</param> | 426 | /// <param name="handle">Texture handle</param> |
diff --git a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs index 0c1b2a3f3..713e8a4fb 100644 --- a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs +++ b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs | |||
@@ -216,6 +216,11 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation | |||
216 | 216 | ||
217 | newSources[index] = source; | 217 | newSources[index] = source; |
218 | 218 | ||
219 | if (source != null && source.Type == OperandType.LocalVariable) | ||
220 | { | ||
221 | source.UseOps.Add(this); | ||
222 | } | ||
223 | |||
219 | _sources = newSources; | 224 | _sources = newSources; |
220 | } | 225 | } |
221 | 226 | ||
diff --git a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs index 1b82e2945..74ec5ca61 100644 --- a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs +++ b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs | |||
@@ -9,6 +9,7 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation | |||
9 | public TextureFlags Flags { get; private set; } | 9 | public TextureFlags Flags { get; private set; } |
10 | 10 | ||
11 | public int Binding { get; private set; } | 11 | public int Binding { get; private set; } |
12 | public int SamplerBinding { get; private set; } | ||
12 | 13 | ||
13 | public TextureOperation( | 14 | public TextureOperation( |
14 | Instruction inst, | 15 | Instruction inst, |
@@ -24,6 +25,7 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation | |||
24 | Format = format; | 25 | Format = format; |
25 | Flags = flags; | 26 | Flags = flags; |
26 | Binding = binding; | 27 | Binding = binding; |
28 | SamplerBinding = -1; | ||
27 | } | 29 | } |
28 | 30 | ||
29 | public void TurnIntoArray(int binding) | 31 | public void TurnIntoArray(int binding) |
@@ -32,6 +34,13 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation | |||
32 | Binding = binding; | 34 | Binding = binding; |
33 | } | 35 | } |
34 | 36 | ||
37 | public void TurnIntoArray(int textureBinding, int samplerBinding) | ||
38 | { | ||
39 | TurnIntoArray(textureBinding); | ||
40 | |||
41 | SamplerBinding = samplerBinding; | ||
42 | } | ||
43 | |||
35 | public void SetBinding(int binding) | 44 | public void SetBinding(int binding) |
36 | { | 45 | { |
37 | if ((Flags & TextureFlags.Bindless) != 0) | 46 | if ((Flags & TextureFlags.Bindless) != 0) |
diff --git a/src/Ryujinx.Graphics.Shader/SamplerType.cs b/src/Ryujinx.Graphics.Shader/SamplerType.cs index 66c748bf3..a693495fa 100644 --- a/src/Ryujinx.Graphics.Shader/SamplerType.cs +++ b/src/Ryujinx.Graphics.Shader/SamplerType.cs | |||
@@ -69,6 +69,7 @@ namespace Ryujinx.Graphics.Shader | |||
69 | { | 69 | { |
70 | string typeName = (type & SamplerType.Mask) switch | 70 | string typeName = (type & SamplerType.Mask) switch |
71 | { | 71 | { |
72 | SamplerType.None => "sampler", | ||
72 | SamplerType.Texture1D => "sampler1D", | 73 | SamplerType.Texture1D => "sampler1D", |
73 | SamplerType.TextureBuffer => "samplerBuffer", | 74 | SamplerType.TextureBuffer => "samplerBuffer", |
74 | SamplerType.Texture2D => "sampler2D", | 75 | SamplerType.Texture2D => "sampler2D", |
@@ -95,6 +96,31 @@ namespace Ryujinx.Graphics.Shader | |||
95 | return typeName; | 96 | return typeName; |
96 | } | 97 | } |
97 | 98 | ||
99 | public static string ToGlslTextureType(this SamplerType type) | ||
100 | { | ||
101 | string typeName = (type & SamplerType.Mask) switch | ||
102 | { | ||
103 | SamplerType.Texture1D => "texture1D", | ||
104 | SamplerType.TextureBuffer => "textureBuffer", | ||
105 | SamplerType.Texture2D => "texture2D", | ||
106 | SamplerType.Texture3D => "texture3D", | ||
107 | SamplerType.TextureCube => "textureCube", | ||
108 | _ => throw new ArgumentException($"Invalid texture type \"{type}\"."), | ||
109 | }; | ||
110 | |||
111 | if ((type & SamplerType.Multisample) != 0) | ||
112 | { | ||
113 | typeName += "MS"; | ||
114 | } | ||
115 | |||
116 | if ((type & SamplerType.Array) != 0) | ||
117 | { | ||
118 | typeName += "Array"; | ||
119 | } | ||
120 | |||
121 | return typeName; | ||
122 | } | ||
123 | |||
98 | public static string ToGlslImageType(this SamplerType type, AggregateType componentType) | 124 | public static string ToGlslImageType(this SamplerType type, AggregateType componentType) |
99 | { | 125 | { |
100 | string typeName = (type & SamplerType.Mask) switch | 126 | string typeName = (type & SamplerType.Mask) switch |
diff --git a/src/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs b/src/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs index 3970df1e9..4068c4127 100644 --- a/src/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs +++ b/src/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs | |||
@@ -9,6 +9,9 @@ namespace Ryujinx.Graphics.Shader.StructuredIr | |||
9 | public TextureFlags Flags { get; } | 9 | public TextureFlags Flags { get; } |
10 | 10 | ||
11 | public int Binding { get; } | 11 | public int Binding { get; } |
12 | public int SamplerBinding { get; } | ||
13 | |||
14 | public bool IsSeparate => SamplerBinding >= 0; | ||
12 | 15 | ||
13 | public AstTextureOperation( | 16 | public AstTextureOperation( |
14 | Instruction inst, | 17 | Instruction inst, |
@@ -16,6 +19,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr | |||
16 | TextureFormat format, | 19 | TextureFormat format, |
17 | TextureFlags flags, | 20 | TextureFlags flags, |
18 | int binding, | 21 | int binding, |
22 | int samplerBinding, | ||
19 | int index, | 23 | int index, |
20 | params IAstNode[] sources) : base(inst, StorageKind.None, false, index, sources, sources.Length) | 24 | params IAstNode[] sources) : base(inst, StorageKind.None, false, index, sources, sources.Length) |
21 | { | 25 | { |
@@ -23,6 +27,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr | |||
23 | Format = format; | 27 | Format = format; |
24 | Flags = flags; | 28 | Flags = flags; |
25 | Binding = binding; | 29 | Binding = binding; |
30 | SamplerBinding = samplerBinding; | ||
26 | } | 31 | } |
27 | } | 32 | } |
28 | } | 33 | } |
diff --git a/src/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs b/src/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs index 2e2df7546..c4ebaee73 100644 --- a/src/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs +++ b/src/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs | |||
@@ -169,7 +169,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr | |||
169 | 169 | ||
170 | AstTextureOperation GetAstTextureOperation(TextureOperation texOp) | 170 | AstTextureOperation GetAstTextureOperation(TextureOperation texOp) |
171 | { | 171 | { |
172 | return new AstTextureOperation(inst, texOp.Type, texOp.Format, texOp.Flags, texOp.Binding, texOp.Index, sources); | 172 | return new AstTextureOperation(inst, texOp.Type, texOp.Format, texOp.Flags, texOp.Binding, texOp.SamplerBinding, texOp.Index, sources); |
173 | } | 173 | } |
174 | 174 | ||
175 | int componentsCount = BitOperations.PopCount((uint)operation.Index); | 175 | int componentsCount = BitOperations.PopCount((uint)operation.Index); |
diff --git a/src/Ryujinx.Graphics.Shader/StructuredIr/TextureDefinition.cs b/src/Ryujinx.Graphics.Shader/StructuredIr/TextureDefinition.cs index bdd3a2ed1..1021dff0e 100644 --- a/src/Ryujinx.Graphics.Shader/StructuredIr/TextureDefinition.cs +++ b/src/Ryujinx.Graphics.Shader/StructuredIr/TextureDefinition.cs | |||
@@ -5,25 +5,39 @@ namespace Ryujinx.Graphics.Shader | |||
5 | public int Set { get; } | 5 | public int Set { get; } |
6 | public int Binding { get; } | 6 | public int Binding { get; } |
7 | public int ArrayLength { get; } | 7 | public int ArrayLength { get; } |
8 | public bool Separate { get; } | ||
8 | public string Name { get; } | 9 | public string Name { get; } |
9 | public SamplerType Type { get; } | 10 | public SamplerType Type { get; } |
10 | public TextureFormat Format { get; } | 11 | public TextureFormat Format { get; } |
11 | public TextureUsageFlags Flags { get; } | 12 | public TextureUsageFlags Flags { get; } |
12 | 13 | ||
13 | public TextureDefinition(int set, int binding, int arrayLength, string name, SamplerType type, TextureFormat format, TextureUsageFlags flags) | 14 | public TextureDefinition( |
15 | int set, | ||
16 | int binding, | ||
17 | int arrayLength, | ||
18 | bool separate, | ||
19 | string name, | ||
20 | SamplerType type, | ||
21 | TextureFormat format, | ||
22 | TextureUsageFlags flags) | ||
14 | { | 23 | { |
15 | Set = set; | 24 | Set = set; |
16 | Binding = binding; | 25 | Binding = binding; |
17 | ArrayLength = arrayLength; | 26 | ArrayLength = arrayLength; |
27 | Separate = separate; | ||
18 | Name = name; | 28 | Name = name; |
19 | Type = type; | 29 | Type = type; |
20 | Format = format; | 30 | Format = format; |
21 | Flags = flags; | 31 | Flags = flags; |
22 | } | 32 | } |
23 | 33 | ||
34 | public TextureDefinition(int set, int binding, string name, SamplerType type) : this(set, binding, 1, false, name, type, TextureFormat.Unknown, TextureUsageFlags.None) | ||
35 | { | ||
36 | } | ||
37 | |||
24 | public TextureDefinition SetFlag(TextureUsageFlags flag) | 38 | public TextureDefinition SetFlag(TextureUsageFlags flag) |
25 | { | 39 | { |
26 | return new TextureDefinition(Set, Binding, ArrayLength, Name, Type, Format, Flags | flag); | 40 | return new TextureDefinition(Set, Binding, ArrayLength, Separate, Name, Type, Format, Flags | flag); |
27 | } | 41 | } |
28 | } | 42 | } |
29 | } | 43 | } |
diff --git a/src/Ryujinx.Graphics.Shader/TextureDescriptor.cs b/src/Ryujinx.Graphics.Shader/TextureDescriptor.cs index 38834da72..d287a1aa7 100644 --- a/src/Ryujinx.Graphics.Shader/TextureDescriptor.cs +++ b/src/Ryujinx.Graphics.Shader/TextureDescriptor.cs | |||
@@ -13,6 +13,8 @@ namespace Ryujinx.Graphics.Shader | |||
13 | public readonly int HandleIndex; | 13 | public readonly int HandleIndex; |
14 | public readonly int ArrayLength; | 14 | public readonly int ArrayLength; |
15 | 15 | ||
16 | public readonly bool Separate; | ||
17 | |||
16 | public readonly TextureUsageFlags Flags; | 18 | public readonly TextureUsageFlags Flags; |
17 | 19 | ||
18 | public TextureDescriptor( | 20 | public TextureDescriptor( |
@@ -22,6 +24,7 @@ namespace Ryujinx.Graphics.Shader | |||
22 | int cbufSlot, | 24 | int cbufSlot, |
23 | int handleIndex, | 25 | int handleIndex, |
24 | int arrayLength, | 26 | int arrayLength, |
27 | bool separate, | ||
25 | TextureUsageFlags flags) | 28 | TextureUsageFlags flags) |
26 | { | 29 | { |
27 | Binding = binding; | 30 | Binding = binding; |
@@ -30,6 +33,7 @@ namespace Ryujinx.Graphics.Shader | |||
30 | CbufSlot = cbufSlot; | 33 | CbufSlot = cbufSlot; |
31 | HandleIndex = handleIndex; | 34 | HandleIndex = handleIndex; |
32 | ArrayLength = arrayLength; | 35 | ArrayLength = arrayLength; |
36 | Separate = separate; | ||
33 | Flags = flags; | 37 | Flags = flags; |
34 | } | 38 | } |
35 | } | 39 | } |
diff --git a/src/Ryujinx.Graphics.Shader/TextureHandle.cs b/src/Ryujinx.Graphics.Shader/TextureHandle.cs index 7df9c8e47..3aaceac48 100644 --- a/src/Ryujinx.Graphics.Shader/TextureHandle.cs +++ b/src/Ryujinx.Graphics.Shader/TextureHandle.cs | |||
@@ -9,6 +9,7 @@ namespace Ryujinx.Graphics.Shader | |||
9 | SeparateSamplerHandle = 1, | 9 | SeparateSamplerHandle = 1, |
10 | SeparateSamplerId = 2, | 10 | SeparateSamplerId = 2, |
11 | SeparateConstantSamplerHandle = 3, | 11 | SeparateConstantSamplerHandle = 3, |
12 | Direct = 4, | ||
12 | } | 13 | } |
13 | 14 | ||
14 | public static class TextureHandle | 15 | public static class TextureHandle |
diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs index ad955278f..223215439 100644 --- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs +++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs | |||
@@ -1,6 +1,7 @@ | |||
1 | using Ryujinx.Graphics.Shader.Instructions; | 1 | using Ryujinx.Graphics.Shader.Instructions; |
2 | using Ryujinx.Graphics.Shader.IntermediateRepresentation; | 2 | using Ryujinx.Graphics.Shader.IntermediateRepresentation; |
3 | using Ryujinx.Graphics.Shader.StructuredIr; | 3 | using Ryujinx.Graphics.Shader.StructuredIr; |
4 | using System; | ||
4 | using System.Collections.Generic; | 5 | using System.Collections.Generic; |
5 | 6 | ||
6 | namespace Ryujinx.Graphics.Shader.Translation.Optimizations | 7 | namespace Ryujinx.Graphics.Shader.Translation.Optimizations |
@@ -31,7 +32,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations | |||
31 | continue; | 32 | continue; |
32 | } | 33 | } |
33 | 34 | ||
34 | if (!TryConvertBindless(block, resourceManager, gpuAccessor, texOp)) | 35 | if (!TryConvertBindless(block, resourceManager, gpuAccessor, texOp) && |
36 | !GenerateBindlessAccess(block, resourceManager, gpuAccessor, texOp, node)) | ||
35 | { | 37 | { |
36 | // If we can't do bindless elimination, remove the texture operation. | 38 | // If we can't do bindless elimination, remove the texture operation. |
37 | // Set any destination variables to zero. | 39 | // Set any destination variables to zero. |
@@ -46,6 +48,88 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations | |||
46 | } | 48 | } |
47 | } | 49 | } |
48 | 50 | ||
51 | private static bool GenerateBindlessAccess( | ||
52 | BasicBlock block, | ||
53 | ResourceManager resourceManager, | ||
54 | IGpuAccessor gpuAccessor, | ||
55 | TextureOperation texOp, | ||
56 | LinkedListNode<INode> node) | ||
57 | { | ||
58 | if (!gpuAccessor.QueryHostSupportsSeparateSampler()) | ||
59 | { | ||
60 | // We depend on combining samplers and textures in the shader being supported for this. | ||
61 | |||
62 | return false; | ||
63 | } | ||
64 | |||
65 | Operand nvHandle = texOp.GetSource(0); | ||
66 | |||
67 | if (nvHandle.AsgOp is not Operation handleOp || | ||
68 | handleOp.Inst != Instruction.Load || | ||
69 | handleOp.StorageKind != StorageKind.Input) | ||
70 | { | ||
71 | // Right now, we only allow bindless access when the handle comes from a shader input. | ||
72 | // This is an artificial limitation to prevent it from being used in cases where it | ||
73 | // would have a large performance impact of loading all textures in the pool. | ||
74 | // It might be removed in the future, if we can mitigate the performance impact. | ||
75 | |||
76 | return false; | ||
77 | } | ||
78 | |||
79 | Operand textureHandle = OperandHelper.Local(); | ||
80 | Operand samplerHandle = OperandHelper.Local(); | ||
81 | Operand textureIndex = OperandHelper.Local(); | ||
82 | |||
83 | block.Operations.AddBefore(node, new Operation(Instruction.BitwiseAnd, textureHandle, nvHandle, OperandHelper.Const(0xfffff))); | ||
84 | block.Operations.AddBefore(node, new Operation(Instruction.ShiftRightU32, samplerHandle, nvHandle, OperandHelper.Const(20))); | ||
85 | |||
86 | int texturePoolLength = Math.Max(BindlessToArray.MinimumArrayLength, gpuAccessor.QueryTextureArrayLengthFromPool()); | ||
87 | |||
88 | block.Operations.AddBefore(node, new Operation(Instruction.MinimumU32, textureIndex, textureHandle, OperandHelper.Const(texturePoolLength - 1))); | ||
89 | |||
90 | texOp.SetSource(0, textureIndex); | ||
91 | |||
92 | bool hasSampler = !texOp.Inst.IsImage(); | ||
93 | |||
94 | int textureBinding = resourceManager.GetTextureOrImageBinding( | ||
95 | texOp.Inst, | ||
96 | texOp.Type, | ||
97 | texOp.Format, | ||
98 | texOp.Flags & ~TextureFlags.Bindless, | ||
99 | 0, | ||
100 | TextureHandle.PackOffsets(0, 0, TextureHandleType.Direct), | ||
101 | texturePoolLength, | ||
102 | hasSampler); | ||
103 | |||
104 | if (hasSampler) | ||
105 | { | ||
106 | Operand samplerIndex = OperandHelper.Local(); | ||
107 | |||
108 | int samplerPoolLength = Math.Max(BindlessToArray.MinimumArrayLength, gpuAccessor.QuerySamplerArrayLengthFromPool()); | ||
109 | |||
110 | block.Operations.AddBefore(node, new Operation(Instruction.MinimumU32, samplerIndex, samplerHandle, OperandHelper.Const(samplerPoolLength - 1))); | ||
111 | |||
112 | texOp.InsertSource(1, samplerIndex); | ||
113 | |||
114 | int samplerBinding = resourceManager.GetTextureOrImageBinding( | ||
115 | texOp.Inst, | ||
116 | SamplerType.None, | ||
117 | texOp.Format, | ||
118 | TextureFlags.None, | ||
119 | 0, | ||
120 | TextureHandle.PackOffsets(0, 0, TextureHandleType.Direct), | ||
121 | samplerPoolLength); | ||
122 | |||
123 | texOp.TurnIntoArray(textureBinding, samplerBinding); | ||
124 | } | ||
125 | else | ||
126 | { | ||
127 | texOp.TurnIntoArray(textureBinding); | ||
128 | } | ||
129 | |||
130 | return true; | ||
131 | } | ||
132 | |||
49 | private static bool TryConvertBindless(BasicBlock block, ResourceManager resourceManager, IGpuAccessor gpuAccessor, TextureOperation texOp) | 133 | private static bool TryConvertBindless(BasicBlock block, ResourceManager resourceManager, IGpuAccessor gpuAccessor, TextureOperation texOp) |
50 | { | 134 | { |
51 | if (texOp.Inst == Instruction.TextureSample || texOp.Inst.IsTextureQuery()) | 135 | if (texOp.Inst == Instruction.TextureSample || texOp.Inst.IsTextureQuery()) |
diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToArray.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToArray.cs index 7543d1c24..f2be7975d 100644 --- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToArray.cs +++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToArray.cs | |||
@@ -11,7 +11,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations | |||
11 | private const int HardcodedArrayLengthOgl = 4; | 11 | private const int HardcodedArrayLengthOgl = 4; |
12 | 12 | ||
13 | // 1 and 0 elements are not considered arrays anymore. | 13 | // 1 and 0 elements are not considered arrays anymore. |
14 | private const int MinimumArrayLength = 2; | 14 | public const int MinimumArrayLength = 2; |
15 | 15 | ||
16 | public static void RunPassOgl(BasicBlock block, ResourceManager resourceManager) | 16 | public static void RunPassOgl(BasicBlock block, ResourceManager resourceManager) |
17 | { | 17 | { |
diff --git a/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs b/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs index e9fe0b1ee..890501c91 100644 --- a/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs +++ b/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs | |||
@@ -29,7 +29,7 @@ namespace Ryujinx.Graphics.Shader.Translation | |||
29 | 29 | ||
30 | private readonly HashSet<int> _usedConstantBufferBindings; | 30 | private readonly HashSet<int> _usedConstantBufferBindings; |
31 | 31 | ||
32 | private readonly record struct TextureInfo(int CbufSlot, int Handle, int ArrayLength, SamplerType Type, TextureFormat Format); | 32 | private readonly record struct TextureInfo(int CbufSlot, int Handle, int ArrayLength, bool Separate, SamplerType Type, TextureFormat Format); |
33 | 33 | ||
34 | private struct TextureMeta | 34 | private struct TextureMeta |
35 | { | 35 | { |
@@ -225,7 +225,8 @@ namespace Ryujinx.Graphics.Shader.Translation | |||
225 | TextureFlags flags, | 225 | TextureFlags flags, |
226 | int cbufSlot, | 226 | int cbufSlot, |
227 | int handle, | 227 | int handle, |
228 | int arrayLength = 1) | 228 | int arrayLength = 1, |
229 | bool separate = false) | ||
229 | { | 230 | { |
230 | inst &= Instruction.Mask; | 231 | inst &= Instruction.Mask; |
231 | bool isImage = inst.IsImage(); | 232 | bool isImage = inst.IsImage(); |
@@ -239,7 +240,18 @@ namespace Ryujinx.Graphics.Shader.Translation | |||
239 | format = TextureFormat.Unknown; | 240 | format = TextureFormat.Unknown; |
240 | } | 241 | } |
241 | 242 | ||
242 | int binding = GetTextureOrImageBinding(cbufSlot, handle, arrayLength, type, format, isImage, intCoords, isWrite, accurateType, coherent); | 243 | int binding = GetTextureOrImageBinding( |
244 | cbufSlot, | ||
245 | handle, | ||
246 | arrayLength, | ||
247 | type, | ||
248 | format, | ||
249 | isImage, | ||
250 | intCoords, | ||
251 | isWrite, | ||
252 | accurateType, | ||
253 | coherent, | ||
254 | separate); | ||
243 | 255 | ||
244 | _gpuAccessor.RegisterTexture(handle, cbufSlot); | 256 | _gpuAccessor.RegisterTexture(handle, cbufSlot); |
245 | 257 | ||
@@ -256,9 +268,10 @@ namespace Ryujinx.Graphics.Shader.Translation | |||
256 | bool intCoords, | 268 | bool intCoords, |
257 | bool write, | 269 | bool write, |
258 | bool accurateType, | 270 | bool accurateType, |
259 | bool coherent) | 271 | bool coherent, |
272 | bool separate) | ||
260 | { | 273 | { |
261 | var dimensions = type.GetDimensions(); | 274 | var dimensions = type == SamplerType.None ? 0 : type.GetDimensions(); |
262 | var dict = isImage ? _usedImages : _usedTextures; | 275 | var dict = isImage ? _usedImages : _usedTextures; |
263 | 276 | ||
264 | var usageFlags = TextureUsageFlags.None; | 277 | var usageFlags = TextureUsageFlags.None; |
@@ -290,7 +303,7 @@ namespace Ryujinx.Graphics.Shader.Translation | |||
290 | // For array textures, we also want to use type as key, | 303 | // For array textures, we also want to use type as key, |
291 | // since we may have texture handles stores in the same buffer, but for textures with different types. | 304 | // since we may have texture handles stores in the same buffer, but for textures with different types. |
292 | var keyType = arrayLength > 1 ? type : SamplerType.None; | 305 | var keyType = arrayLength > 1 ? type : SamplerType.None; |
293 | var info = new TextureInfo(cbufSlot, handle, arrayLength, keyType, format); | 306 | var info = new TextureInfo(cbufSlot, handle, arrayLength, separate, keyType, format); |
294 | var meta = new TextureMeta() | 307 | var meta = new TextureMeta() |
295 | { | 308 | { |
296 | AccurateType = accurateType, | 309 | AccurateType = accurateType, |
@@ -332,6 +345,10 @@ namespace Ryujinx.Graphics.Shader.Translation | |||
332 | ? $"{prefix}_tcb_{handle:X}_{format.ToGlslFormat()}" | 345 | ? $"{prefix}_tcb_{handle:X}_{format.ToGlslFormat()}" |
333 | : $"{prefix}_cb{cbufSlot}_{handle:X}_{format.ToGlslFormat()}"; | 346 | : $"{prefix}_cb{cbufSlot}_{handle:X}_{format.ToGlslFormat()}"; |
334 | } | 347 | } |
348 | else if (type == SamplerType.None) | ||
349 | { | ||
350 | nameSuffix = cbufSlot < 0 ? $"s_tcb_{handle:X}" : $"s_cb{cbufSlot}_{handle:X}"; | ||
351 | } | ||
335 | else | 352 | else |
336 | { | 353 | { |
337 | nameSuffix = cbufSlot < 0 ? $"{prefix}_tcb_{handle:X}" : $"{prefix}_cb{cbufSlot}_{handle:X}"; | 354 | nameSuffix = cbufSlot < 0 ? $"{prefix}_tcb_{handle:X}" : $"{prefix}_cb{cbufSlot}_{handle:X}"; |
@@ -341,6 +358,7 @@ namespace Ryujinx.Graphics.Shader.Translation | |||
341 | isImage ? 3 : 2, | 358 | isImage ? 3 : 2, |
342 | binding, | 359 | binding, |
343 | arrayLength, | 360 | arrayLength, |
361 | separate, | ||
344 | $"{_stagePrefix}_{nameSuffix}", | 362 | $"{_stagePrefix}_{nameSuffix}", |
345 | meta.Type, | 363 | meta.Type, |
346 | info.Format, | 364 | info.Format, |
@@ -495,6 +513,7 @@ namespace Ryujinx.Graphics.Shader.Translation | |||
495 | info.CbufSlot, | 513 | info.CbufSlot, |
496 | info.Handle, | 514 | info.Handle, |
497 | info.ArrayLength, | 515 | info.ArrayLength, |
516 | info.Separate, | ||
498 | meta.UsageFlags)); | 517 | meta.UsageFlags)); |
499 | } | 518 | } |
500 | 519 | ||
@@ -514,6 +533,7 @@ namespace Ryujinx.Graphics.Shader.Translation | |||
514 | info.CbufSlot, | 533 | info.CbufSlot, |
515 | info.Handle, | 534 | info.Handle, |
516 | info.ArrayLength, | 535 | info.ArrayLength, |
536 | info.Separate, | ||
517 | meta.UsageFlags)); | 537 | meta.UsageFlags)); |
518 | } | 538 | } |
519 | } | 539 | } |
diff --git a/src/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs b/src/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs index 581f4372c..106535588 100644 --- a/src/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs +++ b/src/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs | |||
@@ -413,7 +413,7 @@ namespace Ryujinx.Graphics.Shader.Translation | |||
413 | if (Stage == ShaderStage.Vertex) | 413 | if (Stage == ShaderStage.Vertex) |
414 | { | 414 | { |
415 | int ibBinding = resourceManager.Reservations.IndexBufferTextureBinding; | 415 | int ibBinding = resourceManager.Reservations.IndexBufferTextureBinding; |
416 | TextureDefinition indexBuffer = new(2, ibBinding, 1, "ib_data", SamplerType.TextureBuffer, TextureFormat.Unknown, TextureUsageFlags.None); | 416 | TextureDefinition indexBuffer = new(2, ibBinding, "ib_data", SamplerType.TextureBuffer); |
417 | resourceManager.Properties.AddOrUpdateTexture(indexBuffer); | 417 | resourceManager.Properties.AddOrUpdateTexture(indexBuffer); |
418 | 418 | ||
419 | int inputMap = _program.AttributeUsage.UsedInputAttributes; | 419 | int inputMap = _program.AttributeUsage.UsedInputAttributes; |
@@ -422,7 +422,7 @@ namespace Ryujinx.Graphics.Shader.Translation | |||
422 | { | 422 | { |
423 | int location = BitOperations.TrailingZeroCount(inputMap); | 423 | int location = BitOperations.TrailingZeroCount(inputMap); |
424 | int binding = resourceManager.Reservations.GetVertexBufferTextureBinding(location); | 424 | int binding = resourceManager.Reservations.GetVertexBufferTextureBinding(location); |
425 | TextureDefinition vaBuffer = new(2, binding, 1, $"vb_data{location}", SamplerType.TextureBuffer, TextureFormat.Unknown, TextureUsageFlags.None); | 425 | TextureDefinition vaBuffer = new(2, binding, $"vb_data{location}", SamplerType.TextureBuffer); |
426 | resourceManager.Properties.AddOrUpdateTexture(vaBuffer); | 426 | resourceManager.Properties.AddOrUpdateTexture(vaBuffer); |
427 | 427 | ||
428 | inputMap &= ~(1 << location); | 428 | inputMap &= ~(1 << location); |
@@ -431,7 +431,7 @@ namespace Ryujinx.Graphics.Shader.Translation | |||
431 | else if (Stage == ShaderStage.Geometry) | 431 | else if (Stage == ShaderStage.Geometry) |
432 | { | 432 | { |
433 | int trbBinding = resourceManager.Reservations.TopologyRemapBufferTextureBinding; | 433 | int trbBinding = resourceManager.Reservations.TopologyRemapBufferTextureBinding; |
434 | TextureDefinition remapBuffer = new(2, trbBinding, 1, "trb_data", SamplerType.TextureBuffer, TextureFormat.Unknown, TextureUsageFlags.None); | 434 | TextureDefinition remapBuffer = new(2, trbBinding, "trb_data", SamplerType.TextureBuffer); |
435 | resourceManager.Properties.AddOrUpdateTexture(remapBuffer); | 435 | resourceManager.Properties.AddOrUpdateTexture(remapBuffer); |
436 | 436 | ||
437 | int geometryVbOutputSbBinding = resourceManager.Reservations.GeometryVertexOutputStorageBufferBinding; | 437 | int geometryVbOutputSbBinding = resourceManager.Reservations.GeometryVertexOutputStorageBufferBinding; |
diff --git a/src/Ryujinx.Graphics.Vulkan/DescriptorSetTemplate.cs b/src/Ryujinx.Graphics.Vulkan/DescriptorSetTemplate.cs index b9abd8fcd..117f79bb4 100644 --- a/src/Ryujinx.Graphics.Vulkan/DescriptorSetTemplate.cs +++ b/src/Ryujinx.Graphics.Vulkan/DescriptorSetTemplate.cs | |||
@@ -43,11 +43,11 @@ namespace Ryujinx.Graphics.Vulkan | |||
43 | int binding = segment.Binding; | 43 | int binding = segment.Binding; |
44 | int count = segment.Count; | 44 | int count = segment.Count; |
45 | 45 | ||
46 | if (setIndex == PipelineBase.UniformSetIndex) | 46 | if (IsBufferType(segment.Type)) |
47 | { | 47 | { |
48 | entries[seg] = new DescriptorUpdateTemplateEntry() | 48 | entries[seg] = new DescriptorUpdateTemplateEntry() |
49 | { | 49 | { |
50 | DescriptorType = DescriptorType.UniformBuffer, | 50 | DescriptorType = segment.Type.Convert(), |
51 | DstBinding = (uint)binding, | 51 | DstBinding = (uint)binding, |
52 | DescriptorCount = (uint)count, | 52 | DescriptorCount = (uint)count, |
53 | Offset = structureOffset, | 53 | Offset = structureOffset, |
@@ -56,76 +56,31 @@ namespace Ryujinx.Graphics.Vulkan | |||
56 | 56 | ||
57 | structureOffset += (nuint)(Unsafe.SizeOf<DescriptorBufferInfo>() * count); | 57 | structureOffset += (nuint)(Unsafe.SizeOf<DescriptorBufferInfo>() * count); |
58 | } | 58 | } |
59 | else if (setIndex == PipelineBase.StorageSetIndex) | 59 | else if (IsBufferTextureType(segment.Type)) |
60 | { | 60 | { |
61 | entries[seg] = new DescriptorUpdateTemplateEntry() | 61 | entries[seg] = new DescriptorUpdateTemplateEntry() |
62 | { | 62 | { |
63 | DescriptorType = DescriptorType.StorageBuffer, | 63 | DescriptorType = segment.Type.Convert(), |
64 | DstBinding = (uint)binding, | 64 | DstBinding = (uint)binding, |
65 | DescriptorCount = (uint)count, | 65 | DescriptorCount = (uint)count, |
66 | Offset = structureOffset, | 66 | Offset = structureOffset, |
67 | Stride = (nuint)Unsafe.SizeOf<DescriptorBufferInfo>() | 67 | Stride = (nuint)Unsafe.SizeOf<BufferView>() |
68 | }; | 68 | }; |
69 | 69 | ||
70 | structureOffset += (nuint)(Unsafe.SizeOf<DescriptorBufferInfo>() * count); | 70 | structureOffset += (nuint)(Unsafe.SizeOf<BufferView>() * count); |
71 | } | ||
72 | else if (setIndex == PipelineBase.TextureSetIndex) | ||
73 | { | ||
74 | if (segment.Type != ResourceType.BufferTexture) | ||
75 | { | ||
76 | entries[seg] = new DescriptorUpdateTemplateEntry() | ||
77 | { | ||
78 | DescriptorType = DescriptorType.CombinedImageSampler, | ||
79 | DstBinding = (uint)binding, | ||
80 | DescriptorCount = (uint)count, | ||
81 | Offset = structureOffset, | ||
82 | Stride = (nuint)Unsafe.SizeOf<DescriptorImageInfo>() | ||
83 | }; | ||
84 | |||
85 | structureOffset += (nuint)(Unsafe.SizeOf<DescriptorImageInfo>() * count); | ||
86 | } | ||
87 | else | ||
88 | { | ||
89 | entries[seg] = new DescriptorUpdateTemplateEntry() | ||
90 | { | ||
91 | DescriptorType = DescriptorType.UniformTexelBuffer, | ||
92 | DstBinding = (uint)binding, | ||
93 | DescriptorCount = (uint)count, | ||
94 | Offset = structureOffset, | ||
95 | Stride = (nuint)Unsafe.SizeOf<BufferView>() | ||
96 | }; | ||
97 | |||
98 | structureOffset += (nuint)(Unsafe.SizeOf<BufferView>() * count); | ||
99 | } | ||
100 | } | 71 | } |
101 | else if (setIndex == PipelineBase.ImageSetIndex) | 72 | else |
102 | { | 73 | { |
103 | if (segment.Type != ResourceType.BufferImage) | 74 | entries[seg] = new DescriptorUpdateTemplateEntry() |
104 | { | ||
105 | entries[seg] = new DescriptorUpdateTemplateEntry() | ||
106 | { | ||
107 | DescriptorType = DescriptorType.StorageImage, | ||
108 | DstBinding = (uint)binding, | ||
109 | DescriptorCount = (uint)count, | ||
110 | Offset = structureOffset, | ||
111 | Stride = (nuint)Unsafe.SizeOf<DescriptorImageInfo>() | ||
112 | }; | ||
113 | |||
114 | structureOffset += (nuint)(Unsafe.SizeOf<DescriptorImageInfo>() * count); | ||
115 | } | ||
116 | else | ||
117 | { | 75 | { |
118 | entries[seg] = new DescriptorUpdateTemplateEntry() | 76 | DescriptorType = segment.Type.Convert(), |
119 | { | 77 | DstBinding = (uint)binding, |
120 | DescriptorType = DescriptorType.StorageTexelBuffer, | 78 | DescriptorCount = (uint)count, |
121 | DstBinding = (uint)binding, | 79 | Offset = structureOffset, |
122 | DescriptorCount = (uint)count, | 80 | Stride = (nuint)Unsafe.SizeOf<DescriptorImageInfo>() |
123 | Offset = structureOffset, | 81 | }; |
124 | Stride = (nuint)Unsafe.SizeOf<BufferView>() | 82 | |
125 | }; | 83 | structureOffset += (nuint)(Unsafe.SizeOf<DescriptorImageInfo>() * count); |
126 | |||
127 | structureOffset += (nuint)(Unsafe.SizeOf<BufferView>() * count); | ||
128 | } | ||
129 | } | 84 | } |
130 | } | 85 | } |
131 | 86 | ||
@@ -237,6 +192,16 @@ namespace Ryujinx.Graphics.Vulkan | |||
237 | Template = result; | 192 | Template = result; |
238 | } | 193 | } |
239 | 194 | ||
195 | private static bool IsBufferType(ResourceType type) | ||
196 | { | ||
197 | return type == ResourceType.UniformBuffer || type == ResourceType.StorageBuffer; | ||
198 | } | ||
199 | |||
200 | private static bool IsBufferTextureType(ResourceType type) | ||
201 | { | ||
202 | return type == ResourceType.BufferTexture || type == ResourceType.BufferImage; | ||
203 | } | ||
204 | |||
240 | public unsafe void Dispose() | 205 | public unsafe void Dispose() |
241 | { | 206 | { |
242 | _gd.Api.DestroyDescriptorUpdateTemplate(_device, Template, null); | 207 | _gd.Api.DestroyDescriptorUpdateTemplate(_device, Template, null); |
diff --git a/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs b/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs index e75e7f4b4..b46ba9c46 100644 --- a/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs +++ b/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs | |||
@@ -706,6 +706,7 @@ namespace Ryujinx.Graphics.Vulkan | |||
706 | supportsCubemapView: !IsAmdGcn, | 706 | supportsCubemapView: !IsAmdGcn, |
707 | supportsNonConstantTextureOffset: false, | 707 | supportsNonConstantTextureOffset: false, |
708 | supportsScaledVertexFormats: FormatCapabilities.SupportsScaledVertexFormats(), | 708 | supportsScaledVertexFormats: FormatCapabilities.SupportsScaledVertexFormats(), |
709 | supportsSeparateSampler: true, | ||
709 | supportsShaderBallot: false, | 710 | supportsShaderBallot: false, |
710 | supportsShaderBarrierDivergence: Vendor != Vendor.Intel, | 711 | supportsShaderBarrierDivergence: Vendor != Vendor.Intel, |
711 | supportsShaderFloat64: Capabilities.SupportsShaderFloat64, | 712 | supportsShaderFloat64: Capabilities.SupportsShaderFloat64, |
diff --git a/src/Ryujinx.ShaderTools/Program.cs b/src/Ryujinx.ShaderTools/Program.cs index 4252f1b25..d2c6bd59e 100644 --- a/src/Ryujinx.ShaderTools/Program.cs +++ b/src/Ryujinx.ShaderTools/Program.cs | |||
@@ -58,10 +58,20 @@ namespace Ryujinx.ShaderTools | |||
58 | return MemoryMarshal.Cast<byte, ulong>(new ReadOnlySpan<byte>(_data)[(int)address..]); | 58 | return MemoryMarshal.Cast<byte, ulong>(new ReadOnlySpan<byte>(_data)[(int)address..]); |
59 | } | 59 | } |
60 | 60 | ||
61 | public int QuerySamplerArrayLengthFromPool() | ||
62 | { | ||
63 | return DefaultArrayLength; | ||
64 | } | ||
65 | |||
61 | public int QueryTextureArrayLengthFromBuffer(int slot) | 66 | public int QueryTextureArrayLengthFromBuffer(int slot) |
62 | { | 67 | { |
63 | return DefaultArrayLength; | 68 | return DefaultArrayLength; |
64 | } | 69 | } |
70 | |||
71 | public int QueryTextureArrayLengthFromPool() | ||
72 | { | ||
73 | return DefaultArrayLength; | ||
74 | } | ||
65 | } | 75 | } |
66 | 76 | ||
67 | private class Options | 77 | private class Options |