mirror of
https://github.com/par274/sharpemu.git
synced 2026-08-19 07:51:30 +08:00
Fix/agc zero dim and storage (#828)
* fix(videoout): promote guest images to storage usage * fix(agc): treat zero-dimension indirect compute dispatches as valid no-ops
This commit is contained in:
@@ -12174,15 +12174,18 @@ public static partial class AgcExports
|
||||
|
||||
if (dispatchEndX == 0 || dispatchEndY == 0 || dispatchEndZ == 0)
|
||||
{
|
||||
// Indirect dispatches read their dimensions from a guest buffer a
|
||||
// prior GPU dispatch fills. Zero here means that producer has not run
|
||||
// yet — signal the caller to suspend on the dims buffer and retry,
|
||||
// rather than dropping the work (which black-screens GPU-driven games
|
||||
// like Astro Bot). Direct dispatches carry dims inline, so a zero is
|
||||
// genuinely malformed and still rejected.
|
||||
if (opcode == ItDispatchIndirect)
|
||||
// For indirect dispatches (both absolute and base), zero dimensions are a valid outcome
|
||||
// of GPU culling passes (0 workgroups). VulkanVideoPresenter handles groupCount = 0 as a clean no-op.
|
||||
if (opcode == ItDispatchIndirect || dispatchSource is "absolute-indirect" or "base-indirect")
|
||||
{
|
||||
indirectDimsRetryAddress = dimensionsAddress;
|
||||
var waveCount = (initiator & (1u << 15)) != 0 ? 32u : 64u;
|
||||
dispatch = new ComputeDispatch(
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
waveCount,
|
||||
IsIndirect: true,
|
||||
0, 0, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
return RejectComputeDispatch(
|
||||
|
||||
@@ -13828,16 +13828,10 @@ internal static unsafe class VulkanVideoPresenter
|
||||
existing.LogicalDepth == depth &&
|
||||
existing.Type == type &&
|
||||
existing.MipLevels == mipLevels &&
|
||||
(!requiresStorage || existing.SupportsStorageUsage) &&
|
||||
(exactFormatMatch ||
|
||||
(IsAliasableGuestImageFormat(existing.Format, format) &&
|
||||
(!requiresStorage || existing.SupportsStorageUsage))))
|
||||
IsAliasableGuestImageFormat(existing.Format, format)))
|
||||
{
|
||||
if (requiresStorage && !existing.SupportsStorageUsage)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Guest image 0x{target.Address:X16} was created without storage usage.");
|
||||
}
|
||||
|
||||
existing.IsCpuBacked = false;
|
||||
existing.CpuContentFingerprint = 0;
|
||||
if (existing.RenderPass.Handle == 0 &&
|
||||
@@ -13870,14 +13864,9 @@ internal static unsafe class VulkanVideoPresenter
|
||||
if (existing.Width == target.Width &&
|
||||
existing.Height == target.Height &&
|
||||
existing.MipLevels == mipLevels &&
|
||||
(!requiresStorage || existing.SupportsStorageUsage) &&
|
||||
IsCompatibleViewFormat(existing.Format, format))
|
||||
{
|
||||
if (requiresStorage && !existing.SupportsStorageUsage)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Guest image 0x{target.Address:X16} was created without storage usage.");
|
||||
}
|
||||
|
||||
if (_traceGuestImageEvents)
|
||||
{
|
||||
Console.Error.WriteLine(
|
||||
@@ -13952,50 +13941,52 @@ internal static unsafe class VulkanVideoPresenter
|
||||
{
|
||||
if (requiresStorage && !retained.SupportsStorageUsage)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Retained guest image 0x{target.Address:X16} was created without storage usage.");
|
||||
// Do not reuse retained image if it lacks required storage usage
|
||||
DestroyGuestImage(retained);
|
||||
}
|
||||
|
||||
retained.IsCpuBacked = false;
|
||||
retained.CpuContentFingerprint = 0;
|
||||
_guestImages.Add(target.Address, retained);
|
||||
var retainedByteCount = GetTextureByteCount(
|
||||
target.Format,
|
||||
target.Width,
|
||||
target.Height,
|
||||
depth);
|
||||
lock (_gate)
|
||||
else
|
||||
{
|
||||
_cpuBackedUploadGenerations.Remove(target.Address);
|
||||
_guestImageExtents[target.Address] = (
|
||||
retained.IsCpuBacked = false;
|
||||
retained.CpuContentFingerprint = 0;
|
||||
_guestImages.Add(target.Address, retained);
|
||||
var retainedByteCount = GetTextureByteCount(
|
||||
target.Format,
|
||||
target.Width,
|
||||
target.Height,
|
||||
retainedByteCount);
|
||||
}
|
||||
depth);
|
||||
lock (_gate)
|
||||
{
|
||||
_cpuBackedUploadGenerations.Remove(target.Address);
|
||||
_guestImageExtents[target.Address] = (
|
||||
target.Width,
|
||||
target.Height,
|
||||
retainedByteCount);
|
||||
}
|
||||
|
||||
// Arm the exact extent the flip/acquire sync path would read
|
||||
// back, budgeted by bytes rather than by resolution: the old
|
||||
// 1920x1080 cap left every 4K surface permanently
|
||||
// un-invalidated, so a guest CPU rewrite of one was never
|
||||
// reflected and the sample served stale bytes.
|
||||
if (ShouldTrackGuestImageWrites(retainedByteCount))
|
||||
{
|
||||
SharpEmu.HLE.GuestImageWriteTracker.Track(
|
||||
target.Address,
|
||||
retainedByteCount,
|
||||
CurrentGuestWorkSequenceForDiagnostics,
|
||||
"vulkan.render-target");
|
||||
}
|
||||
// Arm the exact extent the flip/acquire sync path would read
|
||||
// back, budgeted by bytes rather than by resolution: the old
|
||||
// 1920x1080 cap left every 4K surface permanently
|
||||
// un-invalidated, so a guest CPU rewrite of one was never
|
||||
// reflected and the sample served stale bytes.
|
||||
if (ShouldTrackGuestImageWrites(retainedByteCount))
|
||||
{
|
||||
SharpEmu.HLE.GuestImageWriteTracker.Track(
|
||||
target.Address,
|
||||
retainedByteCount,
|
||||
CurrentGuestWorkSequenceForDiagnostics,
|
||||
"vulkan.render-target");
|
||||
}
|
||||
|
||||
if (_traceGuestImageEvents)
|
||||
{
|
||||
Console.Error.WriteLine(
|
||||
$"[GIMG] retained addr=0x{target.Address:X} " +
|
||||
$"{target.Width}x{target.Height} fmt={format} " +
|
||||
$"initialized={retained.Initialized}");
|
||||
}
|
||||
if (_traceGuestImageEvents)
|
||||
{
|
||||
Console.Error.WriteLine(
|
||||
$"[GIMG] retained addr=0x{target.Address:X} " +
|
||||
$"{target.Width}x{target.Height} fmt={format} " +
|
||||
$"initialized={retained.Initialized}");
|
||||
}
|
||||
|
||||
return retained;
|
||||
return retained;
|
||||
}
|
||||
}
|
||||
|
||||
var imageInfo = new ImageCreateInfo
|
||||
|
||||
Reference in New Issue
Block a user