mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-22 19:06:15 +08:00
[AGC] Quake rendering progress: WAIT_REG_MEM, draw fixes, VideoOut, and HLE improvements (#68)
* [agc] WAIT_REG_MEM suspend/resume, draw packet fixes, new HLE exports, debug cleanup
Rebased onto upstream 79a7437 (par274/sharpemu, rewritten history).
- GpuWaitRegistry: DCBs suspended on unsatisfied WAIT_REG_MEM are re-polled
against guest memory on every submit; fixed 64-bit and standard packet parse
offsets, apply the mask, treat PM4 compare function 0 as "always".
- TryReadSubmittedDrawCount: accept the 5-dword ItDrawIndex2 form emitted by
DcbDrawIndex (count at +4); menu draws were silently discarded before.
- sceAgcDriverSubmitMultiDcbs: reversed ABI (rdi=address array, rsi=dword
sizes, rdx=count).
- VideoOut: vblank events, sceVideoOutGetFlipStatus, buffers registered via
sceVideoOutRegisterBuffers are valid flip targets.
- New HLE: libc stdio (fopen/fread/fseek/ftell/fclose/fgets), Dinkumware
_Getpctype ctype table, NpTrophy2 stubs, AMPR PAK sequential-read tracker,
MsgDialog lifecycle, NGS2 alt NIDs + dummy vtable for handle objects,
guarded memset intrinsic, abort()/strcasecmp null-arg recovery.
- Removed investigation-only code (INT3 breakpoints, qfont/mcpp dumps,
error-candidate printf traces, unconditional debug logs).
First rendered frame: Quake (PPSA01880) presents a 1920x1080 guest frame.
* Implemented a guarded native intrinsic (rep movsb) in DirectExecutionBackend to bypass HLE dispatch overhead, while preserving memory safety checks.
This commit is contained in:
@@ -182,6 +182,13 @@ internal static unsafe class VulkanVideoPresenter
|
||||
private static long _enqueuedGuestWorkSequence;
|
||||
private static long _completedGuestWorkSequence;
|
||||
|
||||
private static bool ShouldTracePresentedGuestImageContentsForDiagnostics()
|
||||
{
|
||||
var mode = Environment.GetEnvironmentVariable("SHARPEMU_TRACE_GUEST_IMAGES");
|
||||
return string.Equals(mode, "1", StringComparison.Ordinal) ||
|
||||
string.Equals(mode, "present", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public static void EnsureStarted(uint width, uint height)
|
||||
{
|
||||
if (width == 0 || height == 0)
|
||||
@@ -279,6 +286,11 @@ internal static unsafe class VulkanVideoPresenter
|
||||
return;
|
||||
}
|
||||
|
||||
if (ShouldTracePresentedGuestImageContentsForDiagnostics())
|
||||
{
|
||||
Console.Error.WriteLine($"[LOADER][TRACE] vk.submit_call kind=Submit {width}x{height}");
|
||||
}
|
||||
|
||||
lock (_gate)
|
||||
{
|
||||
if (_closed)
|
||||
@@ -319,6 +331,11 @@ internal static unsafe class VulkanVideoPresenter
|
||||
return;
|
||||
}
|
||||
|
||||
if (ShouldTracePresentedGuestImageContentsForDiagnostics())
|
||||
{
|
||||
Console.Error.WriteLine($"[LOADER][TRACE] vk.submit_call kind=SubmitGuestDraw({drawKind}) {width}x{height}");
|
||||
}
|
||||
|
||||
lock (_gate)
|
||||
{
|
||||
if (_closed ||
|
||||
@@ -376,6 +393,12 @@ internal static unsafe class VulkanVideoPresenter
|
||||
return;
|
||||
}
|
||||
|
||||
if (ShouldTracePresentedGuestImageContentsForDiagnostics())
|
||||
{
|
||||
Console.Error.WriteLine(
|
||||
$"[LOADER][TRACE] vk.submit_call kind=SubmitTranslatedDraw {width}x{height} textures={textures.Count}");
|
||||
}
|
||||
|
||||
lock (_gate)
|
||||
{
|
||||
if (_closed)
|
||||
@@ -442,6 +465,13 @@ internal static unsafe class VulkanVideoPresenter
|
||||
return;
|
||||
}
|
||||
|
||||
if (ShouldTracePresentedGuestImageContentsForDiagnostics())
|
||||
{
|
||||
Console.Error.WriteLine(
|
||||
$"[LOADER][TRACE] vk.submit_call kind=SubmitOffscreenTranslatedDraw " +
|
||||
$"target=0x{target.Address:X16} {target.Width}x{target.Height} textures={textures.Count}");
|
||||
}
|
||||
|
||||
lock (_gate)
|
||||
{
|
||||
if (_closed)
|
||||
@@ -569,9 +599,31 @@ internal static unsafe class VulkanVideoPresenter
|
||||
var traceSubmission = false;
|
||||
lock (_gate)
|
||||
{
|
||||
if (_closed ||
|
||||
!_availableGuestImages.ContainsKey(address))
|
||||
var known = _availableGuestImages.ContainsKey(address);
|
||||
if (ShouldTracePresentedGuestImageContentsForDiagnostics())
|
||||
{
|
||||
Console.Error.WriteLine(
|
||||
$"[LOADER][TRACE] vk.submit_call kind=TrySubmitGuestImage addr=0x{address:X16} " +
|
||||
$"{width}x{height} known={known}");
|
||||
}
|
||||
|
||||
if (_closed)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// The caller (VideoOutExports.SubmitFlip) reports the flip as successful either
|
||||
// way, so an unregistered address means the frame is dropped silently; warn once
|
||||
// per address so that shows up in the log.
|
||||
if (!known)
|
||||
{
|
||||
if (_tracedGuestImageSubmissions.Add((address, width, height)))
|
||||
{
|
||||
Console.Error.WriteLine(
|
||||
$"[LOADER][WARN] vk.submit_guest_image_unknown addr=0x{address:X16} " +
|
||||
$"{width}x{height} - flip target was never registered as a render output");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -588,6 +640,19 @@ internal static unsafe class VulkanVideoPresenter
|
||||
RequiredGuestWorkSequence: 0,
|
||||
IsSplash: false,
|
||||
GuestImageAddress: address);
|
||||
if (_thread is not null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
_windowWidth = width;
|
||||
_windowHeight = height;
|
||||
_thread = new Thread(Run)
|
||||
{
|
||||
IsBackground = true,
|
||||
Name = "SharpEmu Vulkan VideoOut",
|
||||
};
|
||||
_thread.Start();
|
||||
}
|
||||
|
||||
if (traceSubmission)
|
||||
@@ -601,6 +666,21 @@ internal static unsafe class VulkanVideoPresenter
|
||||
return true;
|
||||
}
|
||||
|
||||
// Display buffers registered through sceVideoOutRegisterBuffers are valid flip targets
|
||||
// even when no AGC render-target write to them was ever observed.
|
||||
internal static void RegisterKnownDisplayBuffer(ulong address, uint guestFormat)
|
||||
{
|
||||
if (address == 0 || guestFormat == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_gate)
|
||||
{
|
||||
_availableGuestImages[address] = guestFormat;
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool IsGpuGuestImageAvailable(
|
||||
ulong address,
|
||||
uint format,
|
||||
@@ -5033,14 +5113,19 @@ internal static unsafe class VulkanVideoPresenter
|
||||
_renderPass,
|
||||
_extent);
|
||||
if (ShouldTracePresentedGuestImageContentsForDiagnostics() &&
|
||||
!_firstGuestDrawPresented &&
|
||||
translatedResources.Textures is
|
||||
[
|
||||
{ GuestImage: { } guestImage },
|
||||
] &&
|
||||
_tracedGuestImageContents.Add(guestImage.Address))
|
||||
!_firstGuestDrawPresented)
|
||||
{
|
||||
TraceGuestImageContents(guestImage);
|
||||
Console.Error.WriteLine(
|
||||
$"[LOADER][TRACE] vk.translated_draw kind={presentation.DrawKind} " +
|
||||
$"textures={translatedResources.Textures.Length}");
|
||||
foreach (var boundTexture in translatedResources.Textures)
|
||||
{
|
||||
if (boundTexture.GuestImage is { } guestImage &&
|
||||
_tracedGuestImageContents.Add(guestImage.Address))
|
||||
{
|
||||
TraceGuestImageContents(guestImage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
@@ -5810,13 +5895,6 @@ internal static unsafe class VulkanVideoPresenter
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool ShouldTracePresentedGuestImageContentsForDiagnostics()
|
||||
{
|
||||
var mode = Environment.GetEnvironmentVariable("SHARPEMU_TRACE_GUEST_IMAGES");
|
||||
return string.Equals(mode, "1", StringComparison.Ordinal) ||
|
||||
string.Equals(mode, "present", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private static bool ShouldTraceVulkanResources() =>
|
||||
string.Equals(
|
||||
Environment.GetEnvironmentVariable("SHARPEMU_LOG_VK_RESOURCES"),
|
||||
|
||||
Reference in New Issue
Block a user