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:
parent
0e95a8271a
commit
eb0bb36bbf
21 changed files with 375 additions and 68 deletions
|
@ -16,9 +16,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
_descriptorSets = descriptorSets;
|
||||
}
|
||||
|
||||
public void InitializeBuffers(int setIndex, int baseBinding, int countPerUnit, DescriptorType type, VkBuffer dummyBuffer)
|
||||
public void InitializeBuffers(int setIndex, int baseBinding, int count, DescriptorType type, VkBuffer dummyBuffer)
|
||||
{
|
||||
Span<DescriptorBufferInfo> infos = stackalloc DescriptorBufferInfo[countPerUnit];
|
||||
Span<DescriptorBufferInfo> infos = stackalloc DescriptorBufferInfo[count];
|
||||
|
||||
infos.Fill(new DescriptorBufferInfo()
|
||||
{
|
||||
|
|
|
@ -596,36 +596,19 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void Initialize(CommandBufferScoped cbs, int setIndex, DescriptorSetCollection dsc)
|
||||
{
|
||||
// We don't support clearing texture descriptors currently.
|
||||
if (setIndex != PipelineBase.UniformSetIndex && setIndex != PipelineBase.StorageSetIndex)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var dummyBuffer = _dummyBuffer?.GetBuffer().Get(cbs).Value ?? default;
|
||||
|
||||
uint stages = _program.Stages;
|
||||
|
||||
while (stages != 0)
|
||||
foreach (ResourceBindingSegment segment in _program.ClearSegments[setIndex])
|
||||
{
|
||||
int stage = BitOperations.TrailingZeroCount(stages);
|
||||
stages &= ~(1u << stage);
|
||||
|
||||
if (setIndex == PipelineBase.UniformSetIndex)
|
||||
{
|
||||
dsc.InitializeBuffers(
|
||||
0,
|
||||
1 + stage * Constants.MaxUniformBuffersPerStage,
|
||||
Constants.MaxUniformBuffersPerStage,
|
||||
DescriptorType.UniformBuffer,
|
||||
dummyBuffer);
|
||||
}
|
||||
else if (setIndex == PipelineBase.StorageSetIndex)
|
||||
{
|
||||
dsc.InitializeBuffers(
|
||||
0,
|
||||
stage * Constants.MaxStorageBuffersPerStage,
|
||||
Constants.MaxStorageBuffersPerStage,
|
||||
DescriptorType.StorageBuffer,
|
||||
dummyBuffer);
|
||||
}
|
||||
dsc.InitializeBuffers(0, segment.Binding, segment.Count, segment.Type.Convert(), dummyBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
public uint Stages { get; }
|
||||
|
||||
public ResourceBindingSegment[][] ClearSegments { get; }
|
||||
public ResourceBindingSegment[][] BindingSegments { get; }
|
||||
|
||||
public ProgramLinkStatus LinkStatus { get; private set; }
|
||||
|
@ -115,6 +116,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
Stages = stages;
|
||||
|
||||
ClearSegments = BuildClearSegments(resourceLayout.Sets);
|
||||
BindingSegments = BuildBindingSegments(resourceLayout.SetUsages);
|
||||
|
||||
_compileTask = Task.CompletedTask;
|
||||
|
@ -135,6 +137,60 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
_firstBackgroundUse = !fromCache;
|
||||
}
|
||||
|
||||
private static ResourceBindingSegment[][] BuildClearSegments(ReadOnlyCollection<ResourceDescriptorCollection> sets)
|
||||
{
|
||||
ResourceBindingSegment[][] segments = new ResourceBindingSegment[sets.Count][];
|
||||
|
||||
for (int setIndex = 0; setIndex < sets.Count; setIndex++)
|
||||
{
|
||||
List<ResourceBindingSegment> currentSegments = new List<ResourceBindingSegment>();
|
||||
|
||||
ResourceDescriptor currentDescriptor = default;
|
||||
int currentCount = 0;
|
||||
|
||||
for (int index = 0; index < sets[setIndex].Descriptors.Count; index++)
|
||||
{
|
||||
ResourceDescriptor descriptor = sets[setIndex].Descriptors[index];
|
||||
|
||||
if (currentDescriptor.Binding + currentCount != descriptor.Binding ||
|
||||
currentDescriptor.Type != descriptor.Type ||
|
||||
currentDescriptor.Stages != descriptor.Stages)
|
||||
{
|
||||
if (currentCount != 0)
|
||||
{
|
||||
currentSegments.Add(new ResourceBindingSegment(
|
||||
currentDescriptor.Binding,
|
||||
currentCount,
|
||||
currentDescriptor.Type,
|
||||
currentDescriptor.Stages,
|
||||
ResourceAccess.ReadWrite));
|
||||
}
|
||||
|
||||
currentDescriptor = descriptor;
|
||||
currentCount = descriptor.Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentCount += descriptor.Count;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentCount != 0)
|
||||
{
|
||||
currentSegments.Add(new ResourceBindingSegment(
|
||||
currentDescriptor.Binding,
|
||||
currentCount,
|
||||
currentDescriptor.Type,
|
||||
currentDescriptor.Stages,
|
||||
ResourceAccess.ReadWrite));
|
||||
}
|
||||
|
||||
segments[setIndex] = currentSegments.ToArray();
|
||||
}
|
||||
|
||||
return segments;
|
||||
}
|
||||
|
||||
private static ResourceBindingSegment[][] BuildBindingSegments(ReadOnlyCollection<ResourceUsageCollection> setUsages)
|
||||
{
|
||||
ResourceBindingSegment[][] segments = new ResourceBindingSegment[setUsages.Count][];
|
||||
|
|
|
@ -589,6 +589,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
supportsFragmentShaderOrderingIntel: false,
|
||||
supportsGeometryShader: Capabilities.SupportsGeometryShader,
|
||||
supportsGeometryShaderPassthrough: Capabilities.SupportsGeometryShaderPassthrough,
|
||||
supportsTransformFeedback: Capabilities.SupportsTransformFeedback,
|
||||
supportsImageLoadFormatted: features2.Features.ShaderStorageImageReadWithoutFormat,
|
||||
supportsLayerVertexTessellation: featuresVk12.ShaderOutputLayer,
|
||||
supportsMismatchingViewFormat: true,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue