Implement transform feedback emulation for hardware without native support (#5080)

* Implement transform feedback emulation for hardware without native support

* Stop doing some useless buffer updates and account for non-zero base instance

* Reduce redundant updates even more

* Update descriptor init logic to account for ResourceLayout

* Fix transform feedback and storage buffers not being updated in some cases

* Shader cache version bump

* PR feedback

* SetInstancedDrawVertexCount must be always called after UpdateState

* Minor typo
This commit is contained in:
gdkchan 2023-06-10 18:31:38 -03:00 committed by GitHub
parent 0e95a8271a
commit eb0bb36bbf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 375 additions and 68 deletions

View file

@ -17,40 +17,56 @@ namespace Ryujinx.Graphics.Gpu.Shader
private readonly ResourceCounts _resourceCounts;
private readonly int _stageIndex;
private readonly int _reservedConstantBuffers;
private readonly int _reservedStorageBuffers;
/// <summary>
/// Creates a new GPU accessor.
/// </summary>
/// <param name="context">GPU context</param>
public GpuAccessorBase(GpuContext context, ResourceCounts resourceCounts, int stageIndex)
/// <param name="resourceCounts">Counter of GPU resources used by the shader</param>
/// <param name="stageIndex">Index of the shader stage, 0 for compute</param>
/// <param name="tfEnabled">Indicates if the current graphics shader is used with transform feedback enabled</param>
public GpuAccessorBase(GpuContext context, ResourceCounts resourceCounts, int stageIndex, bool tfEnabled)
{
_context = context;
_resourceCounts = resourceCounts;
_stageIndex = stageIndex;
_reservedConstantBuffers = 1; // For the support buffer.
_reservedStorageBuffers = !context.Capabilities.SupportsTransformFeedback && tfEnabled ? 5 : 0;
}
public int QueryBindingConstantBuffer(int index)
{
int binding;
if (_context.Capabilities.Api == TargetApi.Vulkan)
{
// We need to start counting from 1 since binding 0 is reserved for the support uniform buffer.
return GetBindingFromIndex(index, _context.Capabilities.MaximumUniformBuffersPerStage, "Uniform buffer") + 1;
binding = GetBindingFromIndex(index, _context.Capabilities.MaximumUniformBuffersPerStage, "Uniform buffer");
}
else
{
return _resourceCounts.UniformBuffersCount++;
binding = _resourceCounts.UniformBuffersCount++;
}
return binding + _reservedConstantBuffers;
}
public int QueryBindingStorageBuffer(int index)
{
int binding;
if (_context.Capabilities.Api == TargetApi.Vulkan)
{
return GetBindingFromIndex(index, _context.Capabilities.MaximumStorageBuffersPerStage, "Storage buffer");
binding = GetBindingFromIndex(index, _context.Capabilities.MaximumStorageBuffersPerStage, "Storage buffer");
}
else
{
return _resourceCounts.StorageBuffersCount++;
binding = _resourceCounts.StorageBuffersCount++;
}
return binding + _reservedStorageBuffers;
}
public int QueryBindingTexture(int index, bool isBuffer)
@ -149,6 +165,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
public bool QueryHostSupportsTextureShadowLod() => _context.Capabilities.SupportsTextureShadowLod;
public bool QueryHostSupportsTransformFeedback() => _context.Capabilities.SupportsTransformFeedback;
public bool QueryHostSupportsViewportIndexVertexTessellation() => _context.Capabilities.SupportsViewportIndexVertexTessellation;
public bool QueryHostSupportsViewportMask() => _context.Capabilities.SupportsViewportMask;