mirror of
https://github.com/par274/sharpemu.git
synced 2026-08-21 00:41:29 +08:00
A vplayer fix (#821)
* Astrobot-video-fix * Astrobot-video-fix with updated files * Astrobot-video-fix with tests files
This commit is contained in:
@@ -6,6 +6,7 @@ using Silk.NET.Core.Native;
|
||||
using System.Collections.Concurrent;
|
||||
using SharpEmu.HLE;
|
||||
using SharpEmu.Libs.Agc;
|
||||
using SharpEmu.Libs.AvPlayer;
|
||||
using SharpEmu.Libs.Media;
|
||||
using SharpEmu.Libs.Gpu;
|
||||
using SharpEmu.ShaderCompiler;
|
||||
@@ -2426,6 +2427,7 @@ internal static unsafe class VulkanVideoPresenter
|
||||
if (IsGuestWorkCompletedLocked(pending.RequiredGuestWorkSequence))
|
||||
{
|
||||
presentation = _pendingGuestImagePresentations.Dequeue();
|
||||
TryReplaceWithHostMovieFrame(ref presentation);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2458,10 +2460,97 @@ internal static unsafe class VulkanVideoPresenter
|
||||
}
|
||||
|
||||
presentation = latest;
|
||||
TryReplaceWithHostMovieFrame(ref presentation);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// AvPlayer titles whose guest texture allocators reject the decoded movie
|
||||
/// surface have no sampled image to draw, so the movie would never become
|
||||
/// visible. In that case the AvPlayer HLE keeps a host-decoded BGRA frame
|
||||
/// available; substitute it for the guest image the title is flipping.
|
||||
/// </summary>
|
||||
private static void TryReplaceWithHostMovieFrame(ref Presentation presentation)
|
||||
{
|
||||
if (!TryTakeHostMovieFrame(out var pixels, out var width, out var height))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
presentation = new Presentation(
|
||||
pixels,
|
||||
width,
|
||||
height,
|
||||
presentation.Sequence,
|
||||
GuestDrawKind.None,
|
||||
TranslatedDraw: null,
|
||||
presentation.RequiredGuestWorkSequence,
|
||||
IsSplash: false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The movie is decoded on the host clock, so it must not be limited to the
|
||||
/// title's flip rate: emulated flips are far slower than 59.94 Hz, which
|
||||
/// would turn the intro into a slideshow. The render loop uses this on the
|
||||
/// ticks where the guest produced no new flip, keeping the same presented
|
||||
/// sequence so guest presentation bookkeeping is untouched.
|
||||
/// </summary>
|
||||
private static bool TryTakeHostMovieOnlyPresentation(
|
||||
long presentedSequence,
|
||||
out Presentation presentation)
|
||||
{
|
||||
if (!TryTakeHostMovieFrame(out var pixels, out var width, out var height))
|
||||
{
|
||||
presentation = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
presentation = new Presentation(
|
||||
pixels,
|
||||
width,
|
||||
height,
|
||||
presentedSequence,
|
||||
GuestDrawKind.None,
|
||||
TranslatedDraw: null,
|
||||
RequiredGuestWorkSequence: 0,
|
||||
IsSplash: false);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool TryTakeHostMovieFrame(
|
||||
out byte[] pixels,
|
||||
out uint width,
|
||||
out uint height)
|
||||
{
|
||||
if (!AvPlayerExports.TryGetFallbackPresentationFrame(
|
||||
out pixels,
|
||||
out width,
|
||||
out height,
|
||||
out var serial))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Interlocked.Exchange(
|
||||
ref _tracedAvPlayerFallbackPresentationSerial,
|
||||
serial) != serial)
|
||||
{
|
||||
var frameCount = Interlocked.Increment(
|
||||
ref _avPlayerFallbackPresentationCount);
|
||||
if (frameCount <= 4 || frameCount % 30 == 0)
|
||||
{
|
||||
Console.Error.WriteLine(
|
||||
"[VIDEOOUT][INFO] AvPlayer host fallback frame presented: " +
|
||||
$"frame={frameCount} serial={serial} size={width}x{height}.");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static long _tracedAvPlayerFallbackPresentationSerial;
|
||||
private static long _avPlayerFallbackPresentationCount;
|
||||
private static readonly HashSet<long> _tracedGuestImagePresentRejections = new();
|
||||
|
||||
private static bool HasPendingGuestPresentation(long presentedSequence)
|
||||
@@ -15567,6 +15656,12 @@ internal static unsafe class VulkanVideoPresenter
|
||||
tookPresentation = TryTakePresentation(_presentedSequence, out presentation);
|
||||
}
|
||||
|
||||
if (!tookPresentation &&
|
||||
TryTakeHostMovieOnlyPresentation(_presentedSequence, out presentation))
|
||||
{
|
||||
tookPresentation = true;
|
||||
}
|
||||
|
||||
if (!tookPresentation)
|
||||
{
|
||||
// A render-loop tick with no newer flip is normal. Warn only when
|
||||
|
||||
Reference in New Issue
Block a user