From 1e96eca316319381bf21edf14523c41bac9c79aa Mon Sep 17 00:00:00 2001 From: Astell <34811047+Astellou@users.noreply.github.com> Date: Mon, 10 Aug 2026 23:36:12 +0200 Subject: [PATCH] Astrobot - Canonicalize fix and ffmpeg library on build (#817) --- docs/bink2-bridge.md | 34 +++++++++++++----------- src/SharpEmu.CLI/SharpEmu.CLI.csproj | 21 ++++++++++++++- src/SharpEmu.Libs/Agc/GpuWaitRegistry.cs | 10 ++++--- 3 files changed, 46 insertions(+), 19 deletions(-) diff --git a/docs/bink2-bridge.md b/docs/bink2-bridge.md index d32fdcda..8fb7112f 100644 --- a/docs/bink2-bridge.md +++ b/docs/bink2-bridge.md @@ -47,24 +47,28 @@ built against `ffmpeg-core` specifically. ## Supplying the FFmpeg libraries -`dotnet publish` fetches a prebuilt release of `github.com/sharpemu/ffmpeg-core` -(the tag is pinned in `SharpEmu.CLI.csproj`'s `FfmpegRuntimeTag`, matched to -the `FFmpeg.AutoGen` package version in `Directory.Packages.props` -- both -need to agree on the same FFmpeg ABI) and copies its dynamically linked -libraries into a `plugins` folder next to the published executable. No C -toolchain is required to build SharpEmu; publishing just downloads a zip. -`plugins` is a loose, unpacked folder rather than something embedded in the -single-file bundle, so the OS loader can resolve the libraries' own -inter-dependencies (`avcodec` depends on `avutil`, etc.) itself. +Both `dotnet build` and `dotnet publish` fetch a prebuilt release of +`github.com/sharpemu/ffmpeg-core` (the tag is pinned in +`SharpEmu.CLI.csproj`'s `FfmpegRuntimeTag`, matched to the `FFmpeg.AutoGen` +package version in `Directory.Packages.props` -- both need to agree on the +same FFmpeg ABI) and copy its dynamically linked libraries into a `plugins` +folder next to the resulting executable (`artifacts/bin/...` for build, +`artifacts/publish/...` for publish). No C toolchain is required to build +SharpEmu; both just download a zip once (cached under +`$(BaseIntermediateOutputPath)ffmpeg-runtime/`, so later builds/publishes +reuse it instead of re-fetching). `plugins` is a loose, unpacked folder +rather than something embedded in the single-file bundle, so the OS loader +can resolve the libraries' own inter-dependencies (`avcodec` depends on +`avutil`, etc.) itself. -A plain `dotnet publish` with no `-r` still works: it defaults to the host -machine's own RID (see `Directory.Build.props`), so it fetches the matching -`ffmpeg-core` archive and populates `plugins` without any extra flags. -Passing an explicit `-r ` (e.g. to cross-publish `linux-x64` from +A plain `dotnet build`/`dotnet publish` with no `-r` still works: it defaults +to the host machine's own RID (see `Directory.Build.props`), so it fetches +the matching `ffmpeg-core` archive and populates `plugins` without any extra +flags. Passing an explicit `-r ` (e.g. to cross-publish `linux-x64` from Windows) still overrides that default normally. -To use a different set of FFmpeg libraries, drop them into the published -`plugins` folder yourself (matching FFmpeg's own file-naming and versioning +To use a different set of FFmpeg libraries, drop them into the build or +published `plugins` folder yourself (matching FFmpeg's own file-naming and versioning conventions, e.g. `avformat-61.dll` / `libavformat.so.61` / matching `.dylib`) -- `FfmpegNativeBinkFrameSource` points `ffmpeg.RootPath` at that folder and does not otherwise care where the files came from. diff --git a/src/SharpEmu.CLI/SharpEmu.CLI.csproj b/src/SharpEmu.CLI/SharpEmu.CLI.csproj index a2a896c5..7cc497b0 100644 --- a/src/SharpEmu.CLI/SharpEmu.CLI.csproj +++ b/src/SharpEmu.CLI/SharpEmu.CLI.csproj @@ -130,7 +130,7 @@ SPDX-License-Identifier: GPL-2.0-or-later + + + + <_FfmpegRuntimeFiles Condition="$(RuntimeIdentifier.StartsWith('win'))" + Include="$(FfmpegRuntimeExtractDir)/bin/*.dll" /> + <_FfmpegRuntimeFiles Condition="!$(RuntimeIdentifier.StartsWith('win'))" + Include="$(FfmpegRuntimeExtractDir)/lib/*.so;$(FfmpegRuntimeExtractDir)/lib/*.so.*;$(FfmpegRuntimeExtractDir)/lib/*.dylib" /> + + + + diff --git a/src/SharpEmu.Libs/Agc/GpuWaitRegistry.cs b/src/SharpEmu.Libs/Agc/GpuWaitRegistry.cs index 33381ea8..09383397 100644 --- a/src/SharpEmu.Libs/Agc/GpuWaitRegistry.cs +++ b/src/SharpEmu.Libs/Agc/GpuWaitRegistry.cs @@ -60,9 +60,7 @@ internal static class GpuWaitRegistry // address) so distinct guest processes never alias. private static readonly Dictionary<(object, ulong), ulong> _lastProduced = new(); - // Unwraps to the shared root: per-thread TrackedCpuMemory decorators - // over ONE virtual memory are not reference-equal, so a raw-reference - // filter would make waits invisible across threads. + private static object? Canonicalize(object? memory) { while (memory is SharpEmu.HLE.ICpuMemoryWrapper wrapper) @@ -120,6 +118,7 @@ internal static class GpuWaitRegistry /// public static OutstandingSnapshot SnapshotOutstanding(object? memory = null) { + memory = Canonicalize(memory); lock (_gate) { var outstanding = 0; @@ -346,6 +345,7 @@ internal static class GpuWaitRegistry /// public static bool LatchSatisfiedByValue(object memory, ulong address, ulong value) { + memory = Canonicalize(memory)!; var latchedAny = false; lock (_gate) { @@ -431,6 +431,7 @@ internal static class GpuWaitRegistry /// public static List? CollectExpiredRetries(object memory, long nowTicks) { + memory = Canonicalize(memory)!; List? expired = null; lock (_gate) { @@ -473,6 +474,7 @@ internal static class GpuWaitRegistry public static List? CollectAllForMemory(object memory) { + memory = Canonicalize(memory)!; List? collected = null; lock (_gate) { @@ -558,6 +560,7 @@ internal static class GpuWaitRegistry /// breaker. Also latches any already-waiting waiter it satisfies. public static bool RecordProduced(object memory, ulong address, ulong value) { + memory = Canonicalize(memory)!; lock (_gate) { if (_lastProduced.Count >= 8192) @@ -591,6 +594,7 @@ internal static class GpuWaitRegistry long nowTicks, long minAgeTicks) { + memory = Canonicalize(memory)!; List? broken = null; lock (_gate) {