mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-22 19:06:15 +08:00
472fc96a37e4d39a98f59327357ca80455fdd548
7 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
472fc96a37 |
[AGC] Support the clamp modifier on packed f16 VOP3P ops (#460)
The VOP3P emitter rejected any packed op with the clamp bit set. Clamp saturates each f16 output half to [0, 1] (and flushes NaN to 0, matching RDNA), so games that emit clamped packed arithmetic fell back to a loud emit failure. Apply the saturation to the f32 result of each lane, before it is narrowed back to f16. Because 0.0 and 1.0 are exact in both f32 and f16 and the clamp is monotonic, clamping in f32 and then rounding to f16 yields the same value as clamping the f16 result directly; for the fused multiply-add the pre-narrowing value is the round-to-odd f32, which preserves that equivalence through the final round-to-nearest-even. The saturation uses ordered compares so a NaN result collapses to 0 without a separate IsNan test. Verification: - The local exact-reference harness now also clamps: add, mul, and fma each compared against an f16-domain clamp reference (NaN -> 0, else [0, 1]) over directed boundary inputs and 24M random cases. 0 mismatches, alongside the existing 34M unclamped fma cases. - ShaderDump pk-f16 gains a clamped add and a clamped fma; all decode and emit. - The exec program computes the pinned fma with clamp (both lanes exceed 1.0, so each saturates to 0x3C00) and stores it at offset 28; GpuConformance checks it on device. All values match on an AMD Radeon RX 7700 XT. |
||
|
|
3005babab8 |
[AGC] Emit v_pk_fma_f16 with exact single rounding (#420)
Completes the fused-FMA slice deferred by the VOP3P first slice (#145). v_pk_fma_f16 previously failed emission loudly because an f32 multiply-add followed by an f16 pack rounds twice; the pinned miss is fma(0x4100, 0x7522, 0x04EA) = 0x7A6B fused vs 0x7A6A via f32. The f32 product of two f16 values is exact, so only the addition needs correcting: compute sum = RN(product + addend), recover the exact residual with Knuth 2Sum, and if the sum is inexact with an even significand, step one ulp towards the true value. That is round-to-odd, and rounding the f32 result to f16 with round-to-nearest-even then matches a true fused f16 FMA exactly (24 significand bits >= 11 + 2). Inf/NaN inputs turn the residual into NaN, the ordered compare skips the parity fix, and IEEE special behaviour passes through unchanged. The op_sel/op_sel_hi/neg_lo/neg_hi source modifiers apply to src2 through the existing operand path; clamp stays rejected like the other packed ops. Every op in the 2Sum chain is decorated NoContraction: without it the AMD RDNA3 Windows driver folds the sequence, collapses the residual to zero, and the midpoint case decays to the double-rounded result. This was caught by running the emitted shader on a real device (see below). Verification: - A mirror of the emitted sequence was checked against an exact integer reference (every finite f16 is m * 2^-24, so a*b + c is an exact Int128 multiple of 2^-48, rounded once to f16 RNE) across 34M cases: directed midpoint pins, random sweeps over all operand classes, tiny-addend midpoint stress, subnormal products, and Inf/NaN propagation. 0 mismatches. - ShaderDump gains a pk-f16 program covering all five packed opcodes, both fma modifier paths, and the pinned constants; all programs decode and emit. - The executable exec program now computes the pinned fma and its negated-addend twin (0x7A6B7A6B / 0x7A6A7A6A, straddling an f16 midpoint) and stores them at offsets 20/24; GpuConformance checks both on device. All values match on an AMD Radeon RX 7700 XT. |
||
|
|
847371d2de |
[AGC] Decode VOP3P and emit packed f16 arithmetic (first slice) (#145)
* [AGC] Decode VOP3P and emit packed f16 arithmetic (first slice) On gfx10 the VOP3P family lives under its own 0b110011000 prefix (word0 top byte 0xCC), which the major-opcode switch currently routes to the SMEM branch, so packed instructions were decoded as scalar memory ops and emitted as silent no-ops. Intercept the exact 9-bit prefix ahead of the switch, decode the five packed-f16 arithmetic opcodes with their op_sel/op_sel_hi/neg_lo/neg_hi/clamp modifiers, and emit them as UnpackHalf2x16 -> component-wise f32 vec2 ops -> PackHalf2x16 so no Float16 capability is needed. Bit layout and opcode numbers pinned to LLVM MC test encodings (vop3p.s, gfx10_vop3p_literalv216.txt) and VOP3PInstructions.td. Unsupported modifiers, packed constants and out-of-scope packed opcodes fail with a clear error instead of emitting wrong results. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * [AGC] Make packed f16 exact and drop v_pk_fma_f16 (review response) Address the FP16 correctness review on the VOP3P slice. Replace GLSL UnpackHalf2x16/PackHalf2x16 with explicit integer f16<->f32 conversions (EmitHalfToFloat/EmitFloatToHalf): exact widening with subnormal normalisation, and narrowing with round-to-nearest-even, overflow-to-Inf and NaN/Inf handling. Their subnormal and rounding behaviour no longer depends on implementation-defined float-controls modes. With exact conversions, v_pk_add_f16 and v_pk_mul_f16 are bit-exact to a true f16 op (f32 result rounds losslessly to f16; a f16 product fits in f32). Emit v_pk_min_f16/v_pk_max_f16 as fminnum_like/fmaxnum_like (NaN operand returns the other; ordered numeric compare) instead of GLSL FMin/FMax. v_pk_fma_f16 now fails emission loudly: a fused f16 FMA rounds once, an f32 multiply-add then pack double-rounds (fma(0x4100,0x7522,0x04EA) is 0x7A6B fused vs 0x7A6A via f32). Exact fused emulation is a planned follow-up slice. ShaderDump gains an Expect model (Translates/DecodeFails/EmitFails) and packed regressions: arith, non-default modifiers, and loud-failure pins for the fma case above and for clamp. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: tensorcrush <tensorcrush@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Antigravity AI <antigravity@gemini.com> |
||
|
|
864cbb0fa0 |
[AGC/Vulkan] Extend PS5 runtime and rendering compatibility (#216)
* [Core] Add POSIX native execution and PS5 SELF support Extend the native backend, guest TLS, fixed-address memory, and loader paths needed by PS5 titles on Windows, Linux, and macOS. Keep workstation GC so high-core-count hosts do not reserve over fixed guest image bases. * [HLE] Expand PS5 service and media compatibility Add the kernel, threading, save-data, networking, audio, video-codec, font, dialog, and service exports required by newer PS5 software. Preserve every SysAbi NID currently registered by main while adding the compatibility surface used by ASTRO BOT. * [AGC/Vulkan] Extend Gen5 shader and presentation support Expand PM4 handling, Gen5 shader translation, MRT and packed export support, guest image tracking, depth initialization, texture aliasing, and Vulkan presentation. Add the performance overlay and address-filtered diagnostics used to validate ASTRO BOT with original shaders. * [Core] Align static TLS reservation across hosts * [Pad] Align primary user ID with UserService * [Gpu] Preserve runtime scalar buffers across renderer seam * [AGC] Restore omitted command helper exports * [Vulkan] Reuse primary views for promoted MRT targets * [Vulkan] Preserve scratch storage bindings in compute dispatches |
||
|
|
b5930465f2 |
[AGC] Correct VReadlaneB32 decode and emission (#237)
VReadlaneB32 (VOP3 0x360) had two bugs: 1. Decode: VOP3 decode always set destinations = Vector(word & 0xFF). For VReadlaneB32, bits 0-7 are unused — the scalar destination is in bits 8-14. Now decodes as Scalar((word >> 8) & 0x7F). 2. Emission: VReadlaneB32 was in the VMovB32 fall-through group, just returning GetRawSource(instruction, 0) — reading the current lane's value. By ISA, sdst = vsrc0[lane(src1)], which requires reading a different lane's value. Now uses SPIR-V GroupNonUniformBroadcast(scope=Subgroup, value=src0, lane=src1) when subgroup operations are available, with a fallback to the current-lane simplification when not. 3. Routing: TryEmitVectorAlu called TryGetVectorDestination first, which checks for VectorRegister kind. With the scalar destination fix, VReadlaneB32 now routes to a new TryEmitReadlane handler before the vector destination check. 4. Subgroup capability: UsesSubgroupShuffle now includes VReadlaneB32 so GroupNonUniform capability is enabled when needed. Verified: dotnet build 0 errors/0 warnings, 26/26 tests pass, ShaderDump all programs behaved as expected. |
||
|
|
92497689ab |
[AGC] Fix VOP3 decode for V_READLANE_B32 and V_WRITELANE_B32 (#232)
PR #200 moved shader files from SharpEmu.Libs/Agc/ to new projects SharpEmu.ShaderCompiler and SharpEmu.ShaderCompiler.Vulkan. This re-ports the VOP3 decode fix from PR #226 to the new file paths. Decode table (Gen5ShaderTranslator.cs): - 0x360: VMadU32U16 -> VReadlaneB32 (per RDNA2 ISA) - 0x361: VMulLoU32 -> VWritelaneB32 (0x361 was a duplicate of 0x169) - 0x373: added VMadU32U16 at its correct opcode Emission (Gen5SpirvTranslator.Alu.cs): - VWritelaneB32: per-lane conditional write via IEqual+Select, stores with guardWithExec:false (writelane bypasses exec mask) - VReadlaneB32: kept as GetRawSource(instruction, 0) simplification (correct emission with src1 lane select is a follow-up) Verified: dotnet build 0 errors/0 warnings, 26/26 tests pass, ShaderDump all programs behaved as expected. |
||
|
|
30fdd8d6ed |
[Gpu] Backend-neutral shader compiler and guest-GPU renderer seam (#200)
* [ShaderCompiler] Extract the backend-neutral shader compiler project Move the Gen5 (gfx10) microcode decoder, the scalar evaluator, the shader IR, and the metadata reader out of SharpEmu.Libs/Agc into a new SharpEmu.ShaderCompiler project — the half of shader compilation every codegen backend (SPIR-V today; MSL and DXIL later) consumes. Types go public: they are the contract now. Nothing in the project may depend on a host graphics API; the SPIR-V-specific artifact types (Gen5SpirvShader, Gen5SpirvStage) stay beside the emitter in Libs. Three couplings surfaced by the move, each resolved at the right depth: GuestDrawKind was defined inside VulkanVideoPresenter despite being a guest-domain, decoder-produced concept — it moves to the shared project; the evaluator's one HLE dependency (the tracked-libc-heap read fallback) becomes an injectable hook that a Libs module initializer installs before any caller can reach the evaluator; and the inline- constant table is promoted to a shared Gen5InlineConstants so backends cannot drift on constant semantics (the SPIR-V translator now delegates to it). The ShaderDump tool drops its reflection over the moved types in favor of direct typed calls; only the SPIR-V emitter, still internal to Libs until it moves to its own backend project, is reached via reflection. Verified by a clean solution build, the existing test suite, and a full ShaderDump conformance run. * [ShaderCompiler] Move the SPIR-V emitter into SharpEmu.ShaderCompiler.Vulkan Gen5SpirvTranslator (with its ALU partial), SpirvModuleBuilder, SpirvFixedShaders, and the Gen5SpirvShader/Gen5SpirvStage artifact types move whole from SharpEmu.Libs/Agc into the first per-backend codegen project. Notably it needs no Vulkan bindings reference: emitters produce bytes from the shared IR; renderers own graphics APIs. Types go public as the backend's contract; AgcExports and the presenter consume them exactly as before. The ShaderDump tool drops its last reflection: with both halves of the pipeline public it drives decode and all three emit entry points with direct typed calls, retiring the PadWithDefaults invoke shim — and it no longer references SharpEmu.Libs at all, making the conformance tool emulator-independent by design. Verified by a clean solution build, the test suite, a full ShaderDump conformance run, and a locked-mode restore under the pinned SDK. * [Gpu] Extract the guest-GPU backend seam (IGuestGpuBackend) The AGC/VideoOut/SystemService export layers now reach the renderer through IGuestGpuBackend via GuestGpu.Current (mirroring HostPlatform), instead of calling VulkanVideoPresenter statics. The Vulkan backend is a thin adapter over the existing presenter, so the extraction stays mechanical; only the adapter and the presenter itself reference the presenter now. The types crossing the seam move to Gpu/GuestGpuTypes.cs and drop their Vulkan prefixes, which an audit showed were misnomers: every field is a neutral primitive or a raw guest value (guest addresses, format and number-type codes, CB_BLEND register bitfields, verbatim sampler descriptor dwords). The one genuine Vulkan value in the old surface — the Silk.NET Format inside VulkanRenderTargetFormat, which callers never read — stops crossing: TryDecodeRenderTargetFormat is replaced at the seam by TryGetRenderTargetOutputKind, which surfaces only the Gen5PixelOutputKind callers actually consume, keeping native formats a backend-internal concern. ToVulkanSampler in AgcExports is renamed ToGuestSampler to match what it always produced. Seam rules are documented on the interface: no host-API value crosses, and submission stays coarse-grained with synchronization internal to backends. Interim exception, resolved next: shader parameters are still SPIR-V blobs. * [Gpu] Move shader compilation behind the guest-GPU backend The seam's interim exception is gone: AgcExports no longer calls Gen5SpirvTranslator or handles SPIR-V bytes. IGuestGpuBackend gains the three TryCompile entry points, which take the backend-neutral (Gen5ShaderState, Gen5ShaderEvaluation) contract plus the flat per-role resource-slot bases a multi-stage draw needs, and return opaque IGuestCompiledShader handles that only the producing backend can submit — the Vulkan backend wraps its SPIR-V in VulkanCompiledGuestShader and rejects foreign handles loudly. Draw and dispatch submissions take handles instead of byte arrays; the shader caches in AgcExports store handles. IGuestCompiledShader.Payload exposes the backend-defined compiled bytes for exactly two callers: the diagnostics dump and the size trace — documented as never-interpret. The unused _pixelSpirvCache is deleted. With this, a Metal or DX12 backend plugs in by implementing IGuestGpuBackend with its own codegen; nothing in the export layers knows which shader format exists. Verified by a clean solution build, the test suite, and a full ShaderDump conformance run under the pinned SDK. * [Gpu] Fix rename collateral from the seam extraction Address review findings: a doc comment picked up the mechanical VulkanVideoPresenter -> GuestGpu.Current rewrite and ended up naming members that do not exist on the interface, and CreateVulkanIndexBuffer kept its Vulkan prefix while every sibling factory was de-Vulkanized — it produces the neutral GuestIndexBuffer, so it is CreateGuestIndexBuffer. * [Gpu] Label diagnostics dumps with the backend's payload extension Address the review's altitude finding on DumpSpirv: the dump helper's IR-disassembly half is backend-neutral and stays put, but writing the opaque payload to a hardcoded .spv interpreted bytes the seam says never to interpret. IGuestCompiledShader now declares its payload's file extension, and the renamed DumpCompiledShader takes the handle and writes honestly-labeled dumps whichever backend produced them. * [Gpu] Make the shader-cache hit path allocation-free and lock-free Every translated draw built its cache key with a LINQ Select feeding string.Join plus one interpolated string per render target — steady per-draw allocation whether or not the shaders were already cached. The output layout is now packed exactly into a ulong (guest slot in 6 bits + output kind in 2 bits per target, host locations being the byte positions, target count in the key beside it), and the Gen5PixelOutputBinding array is only materialized on a cache miss, where compilation dwarfs it. The graphics/compute shader caches switch from Dictionary guarded by _submitTraceGate to ConcurrentDictionary, making the per-draw and per-dispatch hit paths lock-free and decoupling them from the tracing gate they coincidentally shared. And the seam-shaped render-target list is built once when a translated draw is created instead of a Select/ToArray per submission of a cached draw. * [Gpu] Replace LINQ with explicit loops in code this branch introduced Project rule going forward: no LINQ — it allocates enumerators, closures, and delegates, and this codebase is GC-pause-sensitive. The pixel-output and guest-render-target array builds and the ShaderDump store-PC collection become plain loops; pre-existing LINQ elsewhere is left for changes that already touch those lines. * [ShaderCompiler] Suppress CA2255 on the evaluator hook installer The analyzer coverage that arrived with the rebase flags ModuleInitializer in library code; this is the rule's intended advanced scenario — the hook must be installed before any code path can reach the evaluator, and every such path enters through this assembly — so suppress with that justification rather than weaken the guarantee to a static constructor's lazier timing. * [Gpu] Resolve rebase artifacts onto main Dedupe the System.Collections.Concurrent using in AgcExports that the rebase merge duplicated (main and this branch each added it), and regenerate the lock files for the new shader-compiler projects and SharpEmu.Libs against main's current package graph so --locked-mode restore matches at the branch tip. * [CI] Comment per-platform build artifact links on PRs Adds a workflow_run workflow that, after "Build and Release" finishes a pull-request build, posts (and keeps updated in place) a single PR comment linking the Windows, Linux, and macOS artifacts from that run. It runs via workflow_run rather than in the build workflow because PRs from forks build with a read-only token that cannot comment; the follow-on run executes in the base-repo context with write access and without checking out fork code. GitHub only triggers workflow_run from the default branch, so this takes effect once merged to main. |