Vulkan: reduce guest buffer upload allocations (#301)

This commit is contained in:
kuba
2026-07-17 01:36:39 +02:00
committed by GitHub
parent dabf723b3e
commit 8f405caebe
@@ -4405,11 +4405,14 @@ internal static unsafe class VulkanVideoPresenter
CollectCompletedGuestSubmissions(waitForOldest: false); CollectCompletedGuestSubmissions(waitForOldest: false);
var waitedMs = (System.Diagnostics.Stopwatch.GetTimestamp() - waitStart) * var waitedMs = (System.Diagnostics.Stopwatch.GetTimestamp() - waitStart) *
1000.0 / System.Diagnostics.Stopwatch.Frequency; 1000.0 / System.Diagnostics.Stopwatch.Frequency;
TraceVulkanShader( if (_traceVulkanShaderEnabled)
$"vk.queue_visibility queue={_activeGuestQueue.Name} " + {
$"submission={_activeGuestQueue.SubmissionId} " + TraceVulkanShader(
$"target_timeline={targetTimeline} completed_timeline={_completedTimeline} " + $"vk.queue_visibility queue={_activeGuestQueue.Name} " +
$"waited_ms={waitedMs:F3}"); $"submission={_activeGuestQueue.SubmissionId} " +
$"target_timeline={targetTimeline} completed_timeline={_completedTimeline} " +
$"waited_ms={waitedMs:F3}");
}
} }
private void ExecuteOrderedGuestAction(VulkanOrderedGuestAction work) private void ExecuteOrderedGuestAction(VulkanOrderedGuestAction work)
@@ -4417,10 +4420,13 @@ internal static unsafe class VulkanVideoPresenter
WaitForActiveGuestQueueSubmissionsForCpuVisibility(); WaitForActiveGuestQueueSubmissionsForCpuVisibility();
WriteBackAllDirtyGuestBuffers(_activeGuestQueue.Name); WriteBackAllDirtyGuestBuffers(_activeGuestQueue.Name);
work.Action(); work.Action();
TraceVulkanShader( if (_traceVulkanShaderEnabled)
$"vk.ordered_action queue={_activeGuestQueue.Name} " + {
$"submission={_activeGuestQueue.SubmissionId} " + TraceVulkanShader(
$"work_sequence={_activeGuestWorkSequence} name='{work.DebugName}'"); $"vk.ordered_action queue={_activeGuestQueue.Name} " +
$"submission={_activeGuestQueue.SubmissionId} " +
$"work_sequence={_activeGuestWorkSequence} name='{work.DebugName}'");
}
} }
private void ExecuteOrderedGuestFlip(VulkanOrderedGuestFlip work) private void ExecuteOrderedGuestFlip(VulkanOrderedGuestFlip work)
@@ -7529,21 +7535,43 @@ internal static unsafe class VulkanVideoPresenter
var size = (ulong)Math.Max(guestBuffer.Length, sizeof(uint)); var size = (ulong)Math.Max(guestBuffer.Length, sizeof(uint));
var endAddress = checked(guestBuffer.BaseAddress + size); var endAddress = checked(guestBuffer.BaseAddress + size);
var allocation = _guestBufferAllocations GuestBufferAllocation? allocation = null;
.Where(candidate => var allocationPriority = -1;
candidate.BaseAddress <= guestBuffer.BaseAddress && // This runs for every bound global buffer. Preserve the previous
candidate.BaseAddress + candidate.Size >= endAddress) // stable queue preference without allocating LINQ sort state.
.OrderByDescending(candidate => foreach (var candidate in _guestBufferAllocations)
string.Equals( {
if (candidate.BaseAddress > guestBuffer.BaseAddress ||
candidate.BaseAddress + candidate.Size < endAddress)
{
continue;
}
var candidatePriority = string.Equals(
candidate.QueueName, candidate.QueueName,
_activeGuestQueue.Name, _activeGuestQueue.Name,
StringComparison.Ordinal)) StringComparison.Ordinal)
.ThenByDescending(candidate => ? 2
string.Equals( : string.Equals(
candidate.QueueName, candidate.QueueName,
SharedReadOnlyGuestBufferQueue, SharedReadOnlyGuestBufferQueue,
StringComparison.Ordinal)) StringComparison.Ordinal)
.First(); ? 1
: 0;
if (candidatePriority > allocationPriority)
{
allocation = candidate;
allocationPriority = candidatePriority;
}
}
if (allocation is null)
{
throw new InvalidOperationException(
$"no Vulkan guest buffer allocation covers " +
$"0x{guestBuffer.BaseAddress:X16}-0x{endAddress:X16}");
}
var guestOffset = guestBuffer.BaseAddress - allocation.BaseAddress; var guestOffset = guestBuffer.BaseAddress - allocation.BaseAddress;
var descriptorOffset = guestOffset & var descriptorOffset = guestOffset &
~(GuestStorageBufferOffsetAlignment - 1); ~(GuestStorageBufferOffsetAlignment - 1);
@@ -7592,16 +7620,15 @@ internal static unsafe class VulkanVideoPresenter
WaitForActiveGuestQueueSubmissionsForCpuVisibility(); WaitForActiveGuestQueueSubmissionsForCpuVisibility();
WriteBackAllDirtyGuestBuffers(_activeGuestQueue.Name); WriteBackAllDirtyGuestBuffers(_activeGuestQueue.Name);
} }
var live = new byte[guestBuffer.Length]; var mapped = new Span<byte>(
if (_guestMemory?.TryRead(guestBuffer.BaseAddress, live) == true) (void*)(allocation.Mapped + checked((nint)guestOffset)),
guestBuffer.Length);
if (_guestMemory?.TryRead(guestBuffer.BaseAddress, mapped) != true)
{ {
source = live; source.CopyTo(mapped);
} }
source.CopyTo(new Span<byte>( mapped.CopyTo(shadow);
(void*)(allocation.Mapped + checked((nint)guestOffset)),
source.Length));
source.CopyTo(shadow);
} }
if (ShouldTraceVulkanResources() && if (ShouldTraceVulkanResources() &&
@@ -7611,14 +7638,6 @@ internal static unsafe class VulkanVideoPresenter
$"[LOADER][TRACE] vk.global_buffer base=0x{guestBuffer.BaseAddress:X16} " + $"[LOADER][TRACE] vk.global_buffer base=0x{guestBuffer.BaseAddress:X16} " +
$"bytes={guestBuffer.Length}"); $"bytes={guestBuffer.Length}");
} }
if (_setDebugUtilsObjectName is not null)
{
SetDebugName(
ObjectType.Buffer,
allocation.Buffer.Handle,
$"SharpEmu global 0x{guestBuffer.BaseAddress:X16} {guestBuffer.Length}b");
}
if (guestBuffer.Pooled) if (guestBuffer.Pooled)
{ {
GuestDataPool.Return(guestBuffer.Data); GuestDataPool.Return(guestBuffer.Data);
@@ -9890,10 +9909,13 @@ internal static unsafe class VulkanVideoPresenter
} }
} }
} }
TraceVulkanShader( if (_traceVulkanShaderEnabled)
$"vk.offscreen_draw mrt={targets.Length} " + {
$"size={firstTarget.Width}x{firstTarget.Height} " + TraceVulkanShader(
$"textures={work.Draw.Textures.Count}"); $"vk.offscreen_draw mrt={targets.Length} " +
$"size={firstTarget.Width}x{firstTarget.Height} " +
$"textures={work.Draw.Textures.Count}");
}
} }
catch (Exception exception) catch (Exception exception)
{ {