mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-22 19:06:15 +08:00
Vulkan: trim disabled draw diagnostics overhead (#307)
This commit is contained in:
@@ -2775,6 +2775,11 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
|
|
||||||
private void LoadDebugUtilsCommands()
|
private void LoadDebugUtilsCommands()
|
||||||
{
|
{
|
||||||
|
if (!_vulkanDebugUtilsEnabled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var setObjectName = _vk.GetDeviceProcAddr(_device, "vkSetDebugUtilsObjectNameEXT");
|
var setObjectName = _vk.GetDeviceProcAddr(_device, "vkSetDebugUtilsObjectNameEXT");
|
||||||
var beginLabel = _vk.GetDeviceProcAddr(_device, "vkCmdBeginDebugUtilsLabelEXT");
|
var beginLabel = _vk.GetDeviceProcAddr(_device, "vkCmdBeginDebugUtilsLabelEXT");
|
||||||
var endLabel = _vk.GetDeviceProcAddr(_device, "vkCmdEndDebugUtilsLabelEXT");
|
var endLabel = _vk.GetDeviceProcAddr(_device, "vkCmdEndDebugUtilsLabelEXT");
|
||||||
@@ -2877,10 +2882,48 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
$"SharpEmu texture 0x{texture.Address:X16} {texture.Width}x{texture.Height} " +
|
$"SharpEmu texture 0x{texture.Address:X16} {texture.Width}x{texture.Height} " +
|
||||||
$"fmt{texture.Format}/{format}";
|
$"fmt{texture.Format}/{format}";
|
||||||
|
|
||||||
|
private static bool IsTitleDraw(IReadOnlyList<GuestVertexBuffer> vertexBuffers)
|
||||||
|
{
|
||||||
|
foreach (var buffer in vertexBuffers)
|
||||||
|
{
|
||||||
|
if (buffer.Location == 0 &&
|
||||||
|
buffer.ComponentCount == 4 &&
|
||||||
|
buffer.DataFormat == 10 &&
|
||||||
|
buffer.NumberFormat == 0 &&
|
||||||
|
buffer.Stride == 16 &&
|
||||||
|
buffer.OffsetBytes == 12 &&
|
||||||
|
buffer.Length == 67568)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool AnyTargetAddressMatches(
|
||||||
|
IReadOnlyList<GuestImageResource>? targets,
|
||||||
|
string environmentVariable)
|
||||||
|
{
|
||||||
|
if (targets is null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var target in targets)
|
||||||
|
{
|
||||||
|
if (AddressListContains(environmentVariable, target.Address))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private void CreateInstance()
|
private void CreateInstance()
|
||||||
{
|
{
|
||||||
var applicationName = (byte*)SilkMarshal.StringToPtr("SharpEmu");
|
var applicationName = (byte*)SilkMarshal.StringToPtr("SharpEmu");
|
||||||
var enableValidation = Environment.GetEnvironmentVariable("SHARPEMU_VK_VALIDATION") == "1";
|
|
||||||
byte* validationLayerName = null;
|
byte* validationLayerName = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -2906,7 +2949,8 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
enabledExtensions[index] = extensions[index];
|
enabledExtensions[index] = extensions[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsInstanceExtensionAvailable(DebugUtilsExtensionName))
|
if (_vulkanDebugUtilsEnabled &&
|
||||||
|
IsInstanceExtensionAvailable(DebugUtilsExtensionName))
|
||||||
{
|
{
|
||||||
debugUtilsExtension = (byte*)SilkMarshal.StringToPtr(DebugUtilsExtensionName);
|
debugUtilsExtension = (byte*)SilkMarshal.StringToPtr(DebugUtilsExtensionName);
|
||||||
enabledExtensions[enabledExtensionCount++] = debugUtilsExtension;
|
enabledExtensions[enabledExtensionCount++] = debugUtilsExtension;
|
||||||
@@ -2921,11 +2965,12 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
instanceCreateFlags |= InstanceCreateFlags.EnumeratePortabilityBitKhr;
|
instanceCreateFlags |= InstanceCreateFlags.EnumeratePortabilityBitKhr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enableValidation && IsInstanceLayerAvailable("VK_LAYER_KHRONOS_validation"))
|
if (_vulkanValidationEnabled &&
|
||||||
|
IsInstanceLayerAvailable("VK_LAYER_KHRONOS_validation"))
|
||||||
{
|
{
|
||||||
validationLayerName = (byte*)SilkMarshal.StringToPtr("VK_LAYER_KHRONOS_validation");
|
validationLayerName = (byte*)SilkMarshal.StringToPtr("VK_LAYER_KHRONOS_validation");
|
||||||
}
|
}
|
||||||
else if (enableValidation)
|
else if (_vulkanValidationEnabled)
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine("[LOADER][WARN] SHARPEMU_VK_VALIDATION=1 but VK_LAYER_KHRONOS_validation not found (Vulkan SDK installed?).");
|
Console.Error.WriteLine("[LOADER][WARN] SHARPEMU_VK_VALIDATION=1 but VK_LAYER_KHRONOS_validation not found (Vulkan SDK installed?).");
|
||||||
}
|
}
|
||||||
@@ -4898,6 +4943,13 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
IReadOnlyList<GuestImageResource>? renderTargets = null,
|
IReadOnlyList<GuestImageResource>? renderTargets = null,
|
||||||
ulong shaderAddress = 0)
|
ulong shaderAddress = 0)
|
||||||
{
|
{
|
||||||
|
if (!_traceGuestImagesEnabled &&
|
||||||
|
!_traceGuestImageAddressFilterEnabled &&
|
||||||
|
GuestImageTraceInterval() is null)
|
||||||
|
{
|
||||||
|
return Array.Empty<GuestImageResource>();
|
||||||
|
}
|
||||||
|
|
||||||
var candidates = new HashSet<GuestImageResource>();
|
var candidates = new HashSet<GuestImageResource>();
|
||||||
foreach (var renderTarget in renderTargets ?? [])
|
foreach (var renderTarget in renderTargets ?? [])
|
||||||
{
|
{
|
||||||
@@ -5140,47 +5192,35 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
bool hasDepthAttachment = false,
|
bool hasDepthAttachment = false,
|
||||||
GuestDepthResource? feedbackDepth = null)
|
GuestDepthResource? feedbackDepth = null)
|
||||||
{
|
{
|
||||||
var isTitleDraw = draw.VertexBuffers.Any(buffer =>
|
var isTitleDraw = IsTitleDraw(draw.VertexBuffers);
|
||||||
buffer.Location == 0 &&
|
var forceFullscreenVertex = _forceFullscreenPipeline ||
|
||||||
buffer.ComponentCount == 4 &&
|
_forceFullscreenVertex ||
|
||||||
buffer.DataFormat == 10 &&
|
isTitleDraw && _forceTitleFullscreenVertex ||
|
||||||
buffer.NumberFormat == 0 &&
|
AnyTargetAddressMatches(
|
||||||
buffer.Stride == 16 &&
|
feedbackTargets,
|
||||||
buffer.OffsetBytes == 12 &&
|
"SHARPEMU_FORCE_FULLSCREEN_VERTEX_TARGETS");
|
||||||
buffer.Length == 67568);
|
var forceRasterState = _forceFullscreenPipeline ||
|
||||||
var forceFullscreenPipeline = Environment.GetEnvironmentVariable(
|
_forceDefaultRasterState ||
|
||||||
"SHARPEMU_FORCE_FULLSCREEN_PIPELINE") == "1";
|
isTitleDraw && _forceTitleDefaultRasterState ||
|
||||||
var forceFullscreenVertex = forceFullscreenPipeline ||
|
AnyTargetAddressMatches(
|
||||||
Environment.GetEnvironmentVariable(
|
feedbackTargets,
|
||||||
"SHARPEMU_FORCE_FULLSCREEN_VERTEX") == "1" ||
|
"SHARPEMU_FORCE_DEFAULT_RASTER_STATE_TARGETS");
|
||||||
isTitleDraw && Environment.GetEnvironmentVariable(
|
|
||||||
"SHARPEMU_FORCE_TITLE_FULLSCREEN_VERTEX") == "1" ||
|
|
||||||
feedbackTargets?.Any(target => AddressListContains(
|
|
||||||
"SHARPEMU_FORCE_FULLSCREEN_VERTEX_TARGETS",
|
|
||||||
target.Address)) == true;
|
|
||||||
var forceRasterState = forceFullscreenPipeline ||
|
|
||||||
Environment.GetEnvironmentVariable(
|
|
||||||
"SHARPEMU_FORCE_DEFAULT_RASTER_STATE") == "1" ||
|
|
||||||
isTitleDraw && Environment.GetEnvironmentVariable(
|
|
||||||
"SHARPEMU_FORCE_TITLE_DEFAULT_RASTER_STATE") == "1" ||
|
|
||||||
feedbackTargets?.Any(target => AddressListContains(
|
|
||||||
"SHARPEMU_FORCE_DEFAULT_RASTER_STATE_TARGETS",
|
|
||||||
target.Address)) == true;
|
|
||||||
var forceTitleSolidFragment =
|
var forceTitleSolidFragment =
|
||||||
Environment.GetEnvironmentVariable(
|
_forceTitleSolidFragment &&
|
||||||
"SHARPEMU_FORCE_TITLE_SOLID_FRAGMENT") == "1" &&
|
|
||||||
isTitleDraw;
|
isTitleDraw;
|
||||||
var forceSolidFragment = forceTitleSolidFragment || forceFullscreenPipeline ||
|
var forceSolidFragment = forceTitleSolidFragment ||
|
||||||
Environment.GetEnvironmentVariable("SHARPEMU_FORCE_SOLID_FRAGMENT") == "1" ||
|
_forceFullscreenPipeline ||
|
||||||
feedbackTargets?.Any(target => AddressListContains(
|
_forceSolidFragment ||
|
||||||
"SHARPEMU_FORCE_SOLID_FRAGMENT_TARGETS",
|
AnyTargetAddressMatches(
|
||||||
target.Address)) == true;
|
feedbackTargets,
|
||||||
var forceAttributeFragment = uint.TryParse(
|
"SHARPEMU_FORCE_SOLID_FRAGMENT_TARGETS");
|
||||||
Environment.GetEnvironmentVariable("SHARPEMU_FORCE_ATTRIBUTE_FRAGMENT"),
|
var attributeFragmentLocation =
|
||||||
out var attributeFragmentLocation) &&
|
_forceAttributeFragmentLocation.GetValueOrDefault();
|
||||||
feedbackTargets?.Any(target => AddressListContains(
|
var forceAttributeFragment =
|
||||||
"SHARPEMU_FORCE_ATTRIBUTE_FRAGMENT_TARGETS",
|
_forceAttributeFragmentLocation.HasValue &&
|
||||||
target.Address)) == true;
|
AnyTargetAddressMatches(
|
||||||
|
feedbackTargets,
|
||||||
|
"SHARPEMU_FORCE_ATTRIBUTE_FRAGMENT_TARGETS");
|
||||||
var vertexSpirv = forceFullscreenVertex
|
var vertexSpirv = forceFullscreenVertex
|
||||||
? SpirvFixedShaders.CreateFullscreenVertex(0)
|
? SpirvFixedShaders.CreateFullscreenVertex(0)
|
||||||
: draw.VertexSpirv;
|
: draw.VertexSpirv;
|
||||||
@@ -5189,11 +5229,9 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
: forceAttributeFragment
|
: forceAttributeFragment
|
||||||
? SpirvFixedShaders.CreateAttributeFragment(attributeFragmentLocation)
|
? SpirvFixedShaders.CreateAttributeFragment(attributeFragmentLocation)
|
||||||
: draw.PixelSpirv;
|
: draw.PixelSpirv;
|
||||||
var fixedFragmentDumpPath = Environment.GetEnvironmentVariable(
|
if (forceSolidFragment && !string.IsNullOrWhiteSpace(_fixedFragmentDumpPath))
|
||||||
"SHARPEMU_DUMP_FIXED_SOLID_FRAGMENT");
|
|
||||||
if (forceSolidFragment && !string.IsNullOrWhiteSpace(fixedFragmentDumpPath))
|
|
||||||
{
|
{
|
||||||
File.WriteAllBytes(fixedFragmentDumpPath, fragmentSpirv);
|
File.WriteAllBytes(_fixedFragmentDumpPath, fragmentSpirv);
|
||||||
}
|
}
|
||||||
if (draw.RenderState.Blends.Count != renderTargetFormats.Count)
|
if (draw.RenderState.Blends.Count != renderTargetFormats.Count)
|
||||||
{
|
{
|
||||||
@@ -5243,21 +5281,18 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
resources.Raster = GuestRasterState.Default;
|
resources.Raster = GuestRasterState.Default;
|
||||||
resources.Depth = GuestDepthState.Default;
|
resources.Depth = GuestDepthState.Default;
|
||||||
}
|
}
|
||||||
if (isTitleDraw && Environment.GetEnvironmentVariable(
|
if (isTitleDraw && _forceTitleDefaultBlend)
|
||||||
"SHARPEMU_FORCE_TITLE_DEFAULT_BLEND") == "1")
|
|
||||||
{
|
{
|
||||||
resources.Blends = Enumerable.Repeat(
|
resources.Blends = Enumerable.Repeat(
|
||||||
GuestBlendState.Default,
|
GuestBlendState.Default,
|
||||||
renderTargetFormats.Count).ToArray();
|
renderTargetFormats.Count).ToArray();
|
||||||
}
|
}
|
||||||
if (isTitleDraw && Environment.GetEnvironmentVariable(
|
if (isTitleDraw && _forceTitleDefaultViewportScissor)
|
||||||
"SHARPEMU_FORCE_TITLE_DEFAULT_VIEWPORT_SCISSOR") == "1")
|
|
||||||
{
|
{
|
||||||
resources.Scissor = null;
|
resources.Scissor = null;
|
||||||
resources.Viewport = null;
|
resources.Viewport = null;
|
||||||
}
|
}
|
||||||
if (isTitleDraw && Environment.GetEnvironmentVariable(
|
if (isTitleDraw && _forceTitleDisableCull)
|
||||||
"SHARPEMU_FORCE_TITLE_DISABLE_CULL") == "1")
|
|
||||||
{
|
{
|
||||||
resources.Raster = resources.Raster with
|
resources.Raster = resources.Raster with
|
||||||
{
|
{
|
||||||
@@ -5265,13 +5300,11 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
CullBack = false,
|
CullBack = false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (isTitleDraw && Environment.GetEnvironmentVariable(
|
if (isTitleDraw && _forceTitleDisableDepth)
|
||||||
"SHARPEMU_FORCE_TITLE_DISABLE_DEPTH") == "1")
|
|
||||||
{
|
{
|
||||||
resources.Depth = GuestDepthState.Default;
|
resources.Depth = GuestDepthState.Default;
|
||||||
}
|
}
|
||||||
if (isTitleDraw && Environment.GetEnvironmentVariable(
|
if (isTitleDraw && _traceTitleState)
|
||||||
"SHARPEMU_TRACE_TITLE_STATE") == "1")
|
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine(
|
Console.Error.WriteLine(
|
||||||
$"[LOADER][TRACE] vk.title_state " +
|
$"[LOADER][TRACE] vk.title_state " +
|
||||||
@@ -7874,7 +7907,7 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
{
|
{
|
||||||
ReadOnlySpan<byte> source = guestBuffer.Data.AsSpan(0, guestBuffer.Length);
|
ReadOnlySpan<byte> source = guestBuffer.Data.AsSpan(0, guestBuffer.Length);
|
||||||
byte[]? forcedVertexColors = null;
|
byte[]? forcedVertexColors = null;
|
||||||
if (Environment.GetEnvironmentVariable("SHARPEMU_FORCE_TITLE_VERTEX_COLOR_WHITE") == "1" &&
|
if (_forceTitleVertexColorWhite &&
|
||||||
guestBuffer.Location == 0 &&
|
guestBuffer.Location == 0 &&
|
||||||
guestBuffer.ComponentCount == 4 &&
|
guestBuffer.ComponentCount == 4 &&
|
||||||
guestBuffer.DataFormat == 10 &&
|
guestBuffer.DataFormat == 10 &&
|
||||||
@@ -9400,37 +9433,67 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetFormats
|
for (var index = 0; index < targetFormats.Length; index++)
|
||||||
.Select((format, index) => format.IsInteger && work.Draw.RenderState.Blends[index].Enable)
|
|
||||||
.Any(invalid => invalid))
|
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine(
|
if (targetFormats[index].IsInteger &&
|
||||||
"[LOADER][WARN] Vulkan skipped MRT draw with blending enabled for an integer attachment.");
|
work.Draw.RenderState.Blends[index].Enable)
|
||||||
ReturnPooledGuestData(work.Draw);
|
{
|
||||||
return;
|
Console.Error.WriteLine(
|
||||||
|
"[LOADER][WARN] Vulkan skipped MRT draw with blending enabled for an integer attachment.");
|
||||||
|
ReturnPooledGuestData(work.Draw);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_supportsIndependentBlend &&
|
if (!_supportsIndependentBlend)
|
||||||
work.Draw.RenderState.Blends.Skip(1).Any(blend => blend != work.Draw.RenderState.Blends[0]))
|
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine(
|
for (var index = 1; index < work.Draw.RenderState.Blends.Count; index++)
|
||||||
"[LOADER][WARN] Vulkan skipped MRT draw requiring unsupported independentBlend.");
|
{
|
||||||
ReturnPooledGuestData(work.Draw);
|
if (work.Draw.RenderState.Blends[index] !=
|
||||||
return;
|
work.Draw.RenderState.Blends[0])
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine(
|
||||||
|
"[LOADER][WARN] Vulkan skipped MRT draw requiring unsupported independentBlend.");
|
||||||
|
ReturnPooledGuestData(work.Draw);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var formats = targetFormats.Select(target => target.Format).ToArray();
|
var formats = new Format[targetFormats.Length];
|
||||||
|
for (var index = 0; index < targetFormats.Length; index++)
|
||||||
|
{
|
||||||
|
formats[index] = targetFormats[index].Format;
|
||||||
|
}
|
||||||
|
|
||||||
var targetAddresses = work.Targets
|
var hasStorageFeedback = false;
|
||||||
.Where(target => target.Address != 0)
|
foreach (var texture in work.Draw.Textures)
|
||||||
.Select(target => target.Address)
|
{
|
||||||
.ToHashSet();
|
if (!texture.IsStorage || texture.Address == 0)
|
||||||
if (work.Draw.Textures.Any(texture =>
|
{
|
||||||
texture.IsStorage && targetAddresses.Contains(texture.Address)))
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var target in work.Targets)
|
||||||
|
{
|
||||||
|
if (target.Address != 0 && target.Address == texture.Address)
|
||||||
|
{
|
||||||
|
hasStorageFeedback = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasStorageFeedback)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasStorageFeedback)
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine(
|
Console.Error.WriteLine(
|
||||||
$"[LOADER][WARN] Vulkan skipped storage render-target feedback loop " +
|
$"[LOADER][WARN] Vulkan skipped storage render-target feedback loop " +
|
||||||
$"targets={string.Join(',', targetAddresses.Select(address => $"0x{address:X16}"))}; " +
|
$"targets={string.Join(',', work.Targets.Where(target => target.Address != 0).Select(target => $"0x{target.Address:X16}"))}; " +
|
||||||
"sampled aliases use ordered snapshots");
|
"sampled aliases use ordered snapshots");
|
||||||
ReturnPooledGuestData(work.Draw);
|
ReturnPooledGuestData(work.Draw);
|
||||||
return;
|
return;
|
||||||
@@ -9802,64 +9865,34 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var guestWritesMode = Environment.GetEnvironmentVariable(
|
|
||||||
"SHARPEMU_TRACE_GUEST_WRITES");
|
|
||||||
var traceAddressWriteOrdinal = 0L;
|
|
||||||
_ = long.TryParse(
|
|
||||||
Environment.GetEnvironmentVariable("SHARPEMU_TRACE_GUEST_WRITE_ORDINAL"),
|
|
||||||
out traceAddressWriteOrdinal);
|
|
||||||
var traceLargeWriteOrdinal = 0L;
|
|
||||||
if (guestWritesMode is not null &&
|
|
||||||
guestWritesMode.StartsWith("large@", StringComparison.Ordinal) &&
|
|
||||||
long.TryParse(
|
|
||||||
guestWritesMode.AsSpan("large@".Length),
|
|
||||||
out var parsedTraceLargeWriteOrdinal) &&
|
|
||||||
parsedTraceLargeWriteOrdinal > 0)
|
|
||||||
{
|
|
||||||
traceLargeWriteOrdinal = parsedTraceLargeWriteOrdinal;
|
|
||||||
}
|
|
||||||
|
|
||||||
var tracePixelSpirv = false;
|
var tracePixelSpirv = false;
|
||||||
if (int.TryParse(
|
if (_tracePixelSpirvBytes > 0 &&
|
||||||
Environment.GetEnvironmentVariable("SHARPEMU_TRACE_PIXEL_SPIRV_BYTES"),
|
_tracePixelSpirvBytes == work.Draw.PixelSpirv.Length)
|
||||||
out var tracePixelSpirvBytes) &&
|
|
||||||
tracePixelSpirvBytes == work.Draw.PixelSpirv.Length)
|
|
||||||
{
|
{
|
||||||
var pixelWriteCount = _pixelSpirvWriteCounts.TryGetValue(
|
var pixelWriteCount = _pixelSpirvWriteCounts.TryGetValue(
|
||||||
tracePixelSpirvBytes,
|
_tracePixelSpirvBytes,
|
||||||
out var previousPixelWriteCount)
|
out var previousPixelWriteCount)
|
||||||
? previousPixelWriteCount + 1
|
? previousPixelWriteCount + 1
|
||||||
: 1;
|
: 1;
|
||||||
_pixelSpirvWriteCounts[tracePixelSpirvBytes] = pixelWriteCount;
|
_pixelSpirvWriteCounts[_tracePixelSpirvBytes] = pixelWriteCount;
|
||||||
var tracePixelSpirvOccurrence = 1;
|
|
||||||
_ = int.TryParse(
|
|
||||||
Environment.GetEnvironmentVariable(
|
|
||||||
"SHARPEMU_TRACE_PIXEL_SPIRV_OCCURRENCE"),
|
|
||||||
out tracePixelSpirvOccurrence);
|
|
||||||
tracePixelSpirv =
|
tracePixelSpirv =
|
||||||
pixelWriteCount == Math.Max(tracePixelSpirvOccurrence, 1);
|
pixelWriteCount == _tracePixelSpirvOccurrence;
|
||||||
}
|
}
|
||||||
var traceTitleDraw =
|
var traceTitleDraw =
|
||||||
!_tracedTitleDraw &&
|
!_tracedTitleDraw &&
|
||||||
Environment.GetEnvironmentVariable("SHARPEMU_TRACE_TITLE_DRAW") == "1" &&
|
_traceTitleDrawEnabled &&
|
||||||
work.Draw.VertexBuffers.Any(buffer =>
|
IsTitleDraw(work.Draw.VertexBuffers);
|
||||||
buffer.Location == 0 &&
|
|
||||||
buffer.ComponentCount == 4 &&
|
|
||||||
buffer.DataFormat == 10 &&
|
|
||||||
buffer.NumberFormat == 0 &&
|
|
||||||
buffer.Stride == 16 &&
|
|
||||||
buffer.OffsetBytes == 12 &&
|
|
||||||
buffer.Length == 67568);
|
|
||||||
_tracedTitleDraw |= traceTitleDraw;
|
_tracedTitleDraw |= traceTitleDraw;
|
||||||
|
|
||||||
foreach (var target in targets)
|
foreach (var target in targets)
|
||||||
{
|
{
|
||||||
var traceAddressWrite =
|
var traceAddressWrite =
|
||||||
ShouldTraceGuestImageWriteForDiagnostics(target.Address);
|
ShouldTraceGuestImageWriteForDiagnostics(target.Address);
|
||||||
var traceSmallWrites = guestWritesMode == "small" &&
|
var traceSmallWrites = _traceGuestWritesMode == "small" &&
|
||||||
target.Width <= 512 && target.Height <= 256;
|
target.Width <= 512 && target.Height <= 256;
|
||||||
var traceLargeWrites =
|
var traceLargeWrites =
|
||||||
(guestWritesMode == "large" || traceLargeWriteOrdinal != 0) &&
|
(_traceGuestWritesMode == "large" ||
|
||||||
|
_traceLargeGuestWriteOrdinal != 0) &&
|
||||||
target.Width >= 2560 && target.Height >= 1440;
|
target.Width >= 2560 && target.Height >= 1440;
|
||||||
if (traceAddressWrite || traceSmallWrites ||
|
if (traceAddressWrite || traceSmallWrites ||
|
||||||
traceLargeWrites || tracePixelSpirv || traceTitleDraw)
|
traceLargeWrites || tracePixelSpirv || traceTitleDraw)
|
||||||
@@ -9872,10 +9905,10 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
_tracedGuestWriteCounts[target.Address] = writeCount;
|
_tracedGuestWriteCounts[target.Address] = writeCount;
|
||||||
var shouldTraceWrite = tracePixelSpirv || traceTitleDraw
|
var shouldTraceWrite = tracePixelSpirv || traceTitleDraw
|
||||||
? true
|
? true
|
||||||
: traceAddressWrite && traceAddressWriteOrdinal > 0
|
: traceAddressWrite && _traceGuestWriteOrdinal > 0
|
||||||
? writeCount == traceAddressWriteOrdinal
|
? writeCount == _traceGuestWriteOrdinal
|
||||||
: traceLargeWriteOrdinal != 0
|
: _traceLargeGuestWriteOrdinal != 0
|
||||||
? writeCount == traceLargeWriteOrdinal
|
? writeCount == _traceLargeGuestWriteOrdinal
|
||||||
: writeCount <=
|
: writeCount <=
|
||||||
(traceLargeWrites ? 2 : traceSmallWrites ? 48 : 3);
|
(traceLargeWrites ? 2 : traceSmallWrites ? 48 : 3);
|
||||||
if (traceAddressWrite || shouldTraceWrite)
|
if (traceAddressWrite || shouldTraceWrite)
|
||||||
@@ -12849,6 +12882,20 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
// Diagnostics toggles are read once: these run per draw / per cached
|
// Diagnostics toggles are read once: these run per draw / per cached
|
||||||
// texture hit, and env lookups plus string parsing are far too
|
// texture hit, and env lookups plus string parsing are far too
|
||||||
// expensive there (and non-trivially so under Rosetta 2).
|
// expensive there (and non-trivially so under Rosetta 2).
|
||||||
|
private static readonly bool _vulkanValidationEnabled =
|
||||||
|
string.Equals(
|
||||||
|
Environment.GetEnvironmentVariable("SHARPEMU_VK_VALIDATION"),
|
||||||
|
"1",
|
||||||
|
StringComparison.Ordinal);
|
||||||
|
// Object names and command labels are useful in RenderDoc and validation
|
||||||
|
// captures, but formatting them and calling the debug-utils driver hooks
|
||||||
|
// for every draw is measurable overhead in normal gameplay.
|
||||||
|
private static readonly bool _vulkanDebugUtilsEnabled =
|
||||||
|
_vulkanValidationEnabled ||
|
||||||
|
string.Equals(
|
||||||
|
Environment.GetEnvironmentVariable("SHARPEMU_VK_DEBUG_LABELS"),
|
||||||
|
"1",
|
||||||
|
StringComparison.Ordinal);
|
||||||
private static readonly string? _traceGuestImagesMode =
|
private static readonly string? _traceGuestImagesMode =
|
||||||
Environment.GetEnvironmentVariable("SHARPEMU_TRACE_GUEST_IMAGES");
|
Environment.GetEnvironmentVariable("SHARPEMU_TRACE_GUEST_IMAGES");
|
||||||
private static readonly bool _traceGuestImagesEnabled =
|
private static readonly bool _traceGuestImagesEnabled =
|
||||||
@@ -12912,10 +12959,80 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
!string.IsNullOrWhiteSpace(
|
!string.IsNullOrWhiteSpace(
|
||||||
Environment.GetEnvironmentVariable(
|
Environment.GetEnvironmentVariable(
|
||||||
"SHARPEMU_TRACE_GUEST_IMAGE_ADDRS"));
|
"SHARPEMU_TRACE_GUEST_IMAGE_ADDRS"));
|
||||||
|
private static readonly bool _forceFullscreenPipeline =
|
||||||
|
Environment.GetEnvironmentVariable("SHARPEMU_FORCE_FULLSCREEN_PIPELINE") == "1";
|
||||||
|
private static readonly bool _forceFullscreenVertex =
|
||||||
|
Environment.GetEnvironmentVariable("SHARPEMU_FORCE_FULLSCREEN_VERTEX") == "1";
|
||||||
|
private static readonly bool _forceTitleFullscreenVertex =
|
||||||
|
Environment.GetEnvironmentVariable("SHARPEMU_FORCE_TITLE_FULLSCREEN_VERTEX") == "1";
|
||||||
|
private static readonly bool _forceDefaultRasterState =
|
||||||
|
Environment.GetEnvironmentVariable("SHARPEMU_FORCE_DEFAULT_RASTER_STATE") == "1";
|
||||||
|
private static readonly bool _forceTitleDefaultRasterState =
|
||||||
|
Environment.GetEnvironmentVariable("SHARPEMU_FORCE_TITLE_DEFAULT_RASTER_STATE") == "1";
|
||||||
|
private static readonly bool _forceTitleSolidFragment =
|
||||||
|
Environment.GetEnvironmentVariable("SHARPEMU_FORCE_TITLE_SOLID_FRAGMENT") == "1";
|
||||||
|
private static readonly bool _forceSolidFragment =
|
||||||
|
Environment.GetEnvironmentVariable("SHARPEMU_FORCE_SOLID_FRAGMENT") == "1";
|
||||||
|
private static readonly uint? _forceAttributeFragmentLocation =
|
||||||
|
uint.TryParse(
|
||||||
|
Environment.GetEnvironmentVariable("SHARPEMU_FORCE_ATTRIBUTE_FRAGMENT"),
|
||||||
|
out var forceAttributeFragmentLocation)
|
||||||
|
? forceAttributeFragmentLocation
|
||||||
|
: null;
|
||||||
|
private static readonly string? _fixedFragmentDumpPath =
|
||||||
|
Environment.GetEnvironmentVariable("SHARPEMU_DUMP_FIXED_SOLID_FRAGMENT");
|
||||||
|
private static readonly bool _forceTitleDefaultBlend =
|
||||||
|
Environment.GetEnvironmentVariable("SHARPEMU_FORCE_TITLE_DEFAULT_BLEND") == "1";
|
||||||
|
private static readonly bool _forceTitleDefaultViewportScissor =
|
||||||
|
Environment.GetEnvironmentVariable("SHARPEMU_FORCE_TITLE_DEFAULT_VIEWPORT_SCISSOR") == "1";
|
||||||
|
private static readonly bool _forceTitleDisableCull =
|
||||||
|
Environment.GetEnvironmentVariable("SHARPEMU_FORCE_TITLE_DISABLE_CULL") == "1";
|
||||||
|
private static readonly bool _forceTitleDisableDepth =
|
||||||
|
Environment.GetEnvironmentVariable("SHARPEMU_FORCE_TITLE_DISABLE_DEPTH") == "1";
|
||||||
|
private static readonly bool _traceTitleState =
|
||||||
|
Environment.GetEnvironmentVariable("SHARPEMU_TRACE_TITLE_STATE") == "1";
|
||||||
|
private static readonly bool _forceTitleVertexColorWhite =
|
||||||
|
Environment.GetEnvironmentVariable("SHARPEMU_FORCE_TITLE_VERTEX_COLOR_WHITE") == "1";
|
||||||
|
private static readonly bool _chunkedDrawsEnabled =
|
||||||
|
Environment.GetEnvironmentVariable("SHARPEMU_ENABLE_CHUNKED_DRAWS") == "1";
|
||||||
|
private static readonly string? _traceGuestWritesMode =
|
||||||
|
Environment.GetEnvironmentVariable("SHARPEMU_TRACE_GUEST_WRITES");
|
||||||
|
private static readonly long _traceGuestWriteOrdinal =
|
||||||
|
long.TryParse(
|
||||||
|
Environment.GetEnvironmentVariable("SHARPEMU_TRACE_GUEST_WRITE_ORDINAL"),
|
||||||
|
out var traceGuestWriteOrdinal)
|
||||||
|
? traceGuestWriteOrdinal
|
||||||
|
: 0;
|
||||||
|
private static readonly long _traceLargeGuestWriteOrdinal =
|
||||||
|
ParseTraceLargeGuestWriteOrdinal(_traceGuestWritesMode);
|
||||||
|
private static readonly int _tracePixelSpirvBytes =
|
||||||
|
int.TryParse(
|
||||||
|
Environment.GetEnvironmentVariable("SHARPEMU_TRACE_PIXEL_SPIRV_BYTES"),
|
||||||
|
out var tracePixelSpirvBytes)
|
||||||
|
? tracePixelSpirvBytes
|
||||||
|
: 0;
|
||||||
|
private static readonly int _tracePixelSpirvOccurrence =
|
||||||
|
int.TryParse(
|
||||||
|
Environment.GetEnvironmentVariable("SHARPEMU_TRACE_PIXEL_SPIRV_OCCURRENCE"),
|
||||||
|
out var tracePixelSpirvOccurrence)
|
||||||
|
? Math.Max(tracePixelSpirvOccurrence, 1)
|
||||||
|
: 1;
|
||||||
|
private static readonly bool _traceTitleDrawEnabled =
|
||||||
|
Environment.GetEnvironmentVariable("SHARPEMU_TRACE_TITLE_DRAW") == "1";
|
||||||
private static readonly System.Collections.Concurrent.ConcurrentDictionary<
|
private static readonly System.Collections.Concurrent.ConcurrentDictionary<
|
||||||
string,
|
string,
|
||||||
(bool Wildcard, ulong[] Addresses)> _cachedAddressLists = new();
|
(bool Wildcard, ulong[] Addresses)> _cachedAddressLists = new();
|
||||||
|
|
||||||
|
private static long ParseTraceLargeGuestWriteOrdinal(string? mode)
|
||||||
|
{
|
||||||
|
return mode is not null &&
|
||||||
|
mode.StartsWith("large@", StringComparison.Ordinal) &&
|
||||||
|
long.TryParse(mode.AsSpan("large@".Length), out var ordinal) &&
|
||||||
|
ordinal > 0
|
||||||
|
? ordinal
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
|
||||||
private static bool ShouldTraceGuestImageContentsForDiagnostics() =>
|
private static bool ShouldTraceGuestImageContentsForDiagnostics() =>
|
||||||
_traceGuestImagesEnabled;
|
_traceGuestImagesEnabled;
|
||||||
|
|
||||||
@@ -13113,8 +13230,7 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
// MoltenVK this starves the render thread and makes the guest fall
|
// MoltenVK this starves the render thread and makes the guest fall
|
||||||
// behind its own flip queue. Vulkan clips a normal fullscreen draw
|
// behind its own flip queue. Vulkan clips a normal fullscreen draw
|
||||||
// efficiently; keep tiling only as an explicit driver diagnostic.
|
// efficiently; keep tiling only as an explicit driver diagnostic.
|
||||||
var maxPixelsPerDraw = Environment.GetEnvironmentVariable(
|
var maxPixelsPerDraw = _chunkedDrawsEnabled
|
||||||
"SHARPEMU_ENABLE_CHUNKED_DRAWS") == "1"
|
|
||||||
? 512u * 512u
|
? 512u * 512u
|
||||||
: uint.MaxValue;
|
: uint.MaxValue;
|
||||||
var rowsPerDraw = Math.Max(
|
var rowsPerDraw = Math.Max(
|
||||||
|
|||||||
Reference in New Issue
Block a user