[Gpu] Upload complete unchecked constant vertex attributes

This commit is contained in:
kuba 2026-10-04 09:20:07 +02:00
parent 44e223c5c8
commit d5de44b6fb
3 changed files with 53 additions and 2 deletions

View File

@ -360,7 +360,24 @@ public static class VertexInputResolver
for (var bufferIndex = 0; bufferIndex < buffers.Count; bufferIndex++)
{
var buffer = buffers[bufferIndex];
result[bufferIndex] = new VertexInputBuffer(buffer.Address, buffer.Stride, buffer.RecordCount, buffer.FetchIndex != 0);
uint minimumFetchBytes = 0;
foreach (var resourceIndex in buffer.AttributeIndices)
{
var resource = resources[resourceIndex];
var descriptor = resource.Descriptor;
// OOB_SELECT=2 only tests for an unbound (zero-record) descriptor.
// A constant stream still reads the whole formatted element, even
// when NUM_RECORDS is smaller than that element's byte width.
if (descriptor.Stride == 0 && descriptor.OutOfBounds == 2 && descriptor.RecordCount != 0 &&
VertexAttributeFormats.TryResolve(in descriptor, 4, out var format, out _))
{
minimumFetchBytes = Math.Max(minimumFetchBytes, Images.ViewFormatRules.BlockBytes(format));
}
}
result[bufferIndex] = new VertexInputBuffer(buffer.Address, buffer.Stride, buffer.RecordCount, buffer.FetchIndex != 0)
{
MinimumFetchBytes = minimumFetchBytes,
};
foreach (var resourceIndex in buffer.AttributeIndices)
{
var resource = resources[resourceIndex];

View File

@ -100,7 +100,9 @@ public readonly record struct DispatchThreadLimits(uint X, uint Y, uint Z);
// The vertex buffer words of one fetch slot as the vertex program declares them.
public readonly record struct VertexInputBuffer(ulong Address, uint Stride, uint RecordCount, bool PerInstance = false)
{
public ulong Size => Stride != 0 ? (ulong)Stride * RecordCount : RecordCount;
public uint MinimumFetchBytes { get; init; }
public ulong Size => Math.Max(Stride != 0 ? (ulong)Stride * RecordCount : RecordCount, MinimumFetchBytes);
}
// One attribute of the vertex tables: its buffer words, the registers it fills and its buffer slot.

View File

@ -354,4 +354,36 @@ public sealed class VertexInputResolverTests : IDisposable
Assert.Contains("records=4/5", fatal.Message);
}
[Theory]
[InlineData(74u, 3, 12ul)]
[InlineData(77u, 4, 16ul)]
[InlineData(77u, 3, 16ul)]
[InlineData(64u, 2, 8ul)]
public void MergeBuffers_ConstantUncheckedStreamIncludesFullFormattedFetch(uint format, int components, ulong expectedSize)
{
var resource = Attribute(StreamBase, 0, 1, 0);
resource = resource with
{
Descriptor = resource.Descriptor with { Word3 = IdentitySelect | (format << 12) | (2u << 28) },
RegisterCount = components,
};
var buffer = Assert.Single(VertexInputResolver.MergeBuffers([resource], ShaderAddress));
Assert.Equal(1u, buffer.RecordCount);
Assert.Equal(0u, buffer.Stride);
Assert.Equal(expectedSize, buffer.Size);
}
[Theory]
[InlineData(0u, 1u)]
[InlineData(1u, 1u)]
[InlineData(3u, 1u)]
[InlineData(2u, 0u)]
public void MergeBuffers_BoundedOrUnboundConstantStreamKeepsDeclaredFootprint(uint outOfBounds, uint records)
{
var resource = Attribute(StreamBase, 0, records, 0);
resource = resource with { Descriptor = resource.Descriptor with { Word3 = resource.Descriptor.Word3 | (outOfBounds << 28) } };
var buffer = Assert.Single(VertexInputResolver.MergeBuffers([resource], ShaderAddress));
Assert.Equal((ulong)records, buffer.Size);
}
}