using System.Linq; using System.Numerics; using System.Reflection; using System.Reflection.Emit; using AcDream.App.Composition; using AcDream.App.Rendering; using AcDream.App.Rendering.Gpu; using AcDream.App.Rendering.Gpu.Vk; using AcDream.App.Rendering.Sky; using AcDream.App.Rendering.Walk; using AcDream.App.Tests.Architecture; using AcDream.App.Tests.Rendering.Gpu; namespace AcDream.App.Tests.Rendering; public sealed class RetailPViewPassExecutorTests { [Fact] public void Extracted_contracts_retain_no_window_callbacks_or_visibility_owner() { Assert.DoesNotContain( typeof(RetailPViewFrameInput).GetProperties(), property => typeof(Delegate).IsAssignableFrom(property.PropertyType)); FieldInfo[] fields = typeof(RetailPViewPassExecutor).GetFields( BindingFlags.Instance | BindingFlags.NonPublic); Assert.DoesNotContain(fields, field => field.FieldType == typeof(GameWindow)); Assert.DoesNotContain(fields, field => field.FieldType == typeof(CellVisibility)); Assert.DoesNotContain(fields, field => field.FieldType == typeof(RetailPViewFrameInput)); Assert.DoesNotContain(fields, field => field.FieldType == typeof(RetailPViewFrameResult)); Assert.DoesNotContain(fields, field => field.FieldType == typeof(ClipFrameAssembly)); Assert.DoesNotContain( fields, field => typeof(Delegate).IsAssignableFrom(field.FieldType)); } [Fact] public void Concrete_executor_accumulates_walk_terrain_batch_timing() { // S3 chunk 3 fix round 1 (F3): the walk leaf no longer brackets // itself with Begin()/Complete() (that stopwatch-restart pair would // push one timing SAMPLE per batch, not one per frame) — it times // itself with a raw Stopwatch.GetTimestamp() delta and hands the // elapsed ticks to AccumulateWalkBatch, which only accumulates. MethodInfo landscape = typeof(RetailPViewPassExecutor).GetMethod( "DrawWalkLandCellBatch", BindingFlags.Instance | BindingFlags.NonPublic)!; IReadOnlyList landscapeCalls = CompiledCallGraph.Read(landscape); int terrainDraw = RequiredCallIndex( landscapeCalls, typeof(TerrainModernRenderer), nameof(TerrainModernRenderer.DrawLandCells)); int accumulate = RequiredCallIndex( landscapeCalls, typeof(TerrainDrawDiagnosticsController), nameof(TerrainDrawDiagnosticsController.AccumulateWalkBatch)); Assert.True(terrainDraw < accumulate); Assert.DoesNotContain( landscapeCalls, call => call.Target.DeclaringType == typeof(TerrainDrawDiagnosticsController) && call.Target.Name == nameof(TerrainDrawDiagnosticsController.Begin)); Assert.DoesNotContain( landscapeCalls, call => call.Target.DeclaringType == typeof(TerrainDrawDiagnosticsController) && call.Target.Name == nameof(TerrainDrawDiagnosticsController.Complete)); } [Fact] public void Concrete_executor_pushes_the_walk_terrain_frame_sample_at_replay_end() { // S3 chunk 3 fix round 1 (F3): DrawWalkDrivenStatics is the ONE call // site of driver.Replay in production — CompleteWalkTerrainFrame // must run immediately after it, so the frame's sample is pushed // exactly once, at "the end of the walk replay". MethodInfo drawWalkDrivenStatics = typeof(RetailPViewRenderer).GetMethod( "DrawWalkDrivenStatics", BindingFlags.Instance | BindingFlags.NonPublic)!; IReadOnlyList calls = CompiledCallGraph.Read(drawWalkDrivenStatics); int replay = RequiredCallIndex( calls, typeof(AcDream.App.Rendering.Walk.WalkFrameDriver), nameof(AcDream.App.Rendering.Walk.WalkFrameDriver.Replay)); int completeWalkFrame = RequiredCallIndex( calls, typeof(RetailPViewPassExecutor), nameof(RetailPViewPassExecutor.CompleteWalkTerrainFrame)); Assert.True(replay < completeWalkFrame); } [Fact] public void Frame_composition_constructs_one_walk_executor() { MethodInfo compose = typeof(FrameRootCompositionPhase).GetMethod( "ComposeCore", BindingFlags.Instance | BindingFlags.NonPublic)!; IReadOnlyList calls = CompiledCallGraph.Read(compose); int executor = RequiredCallIndex( calls, typeof(RetailPViewPassExecutor), ".ctor"); int renderer = RequiredCallIndex( calls, typeof(WorldScenePViewRenderer), ".ctor"); Assert.True(executor < renderer); Assert.Single( calls, call => call.Target.DeclaringType == typeof(RetailPViewPassExecutor) && call.Target.Name == ".ctor"); Assert.Single( calls, call => call.Target.DeclaringType == typeof(WorldScenePViewRenderer) && call.Target.Name == ".ctor"); } /// /// S3 chunk 1 fix round 2 (§11.6 H1): the weather MESH draw + its OC /// print moved OUT of /// entirely — S3 chunk 4 (O3) relocated the print to /// WalkFrameDriver.OnWeatherTurn, fired at Collect time by /// RetailFrameWalk.DrawLandscape (see the real transcript pins in /// WalkFrameDriverTranscriptTests: Collect_OutdoorRoot_... /// and Collect_InteriorRoot_...). This method now draws the /// weather MESH and the rain PARTICLES only — the former per-outside- /// view-slice loop that used to run before this call (the walk's own /// screen-space terrain-clip writer + its per-frame clip-routing reset /// call + the old DrawLandscapeSliceLate leaf) is deleted outright (§10.2): retail /// draws the weather mesh and its /// rain particles ONCE, unclipped, never once per doorway aperture. /// MUTATION: re-inlining a /// WalkTranscriptDump.PrintObjectCellTurn call back into this /// method makes the Assert.DoesNotContain below fail; deleting /// either the mesh or the particle call makes the matching /// Assert.Single fail (zero matches instead of one). /// [Fact] public void DrawWeatherOnce_DrawsTheWeatherMeshAndParticlesButNeverPrints() { MethodInfo method = typeof(RetailPViewPassExecutor).GetMethod( nameof(RetailPViewPassExecutor.DrawWeatherOnce), BindingFlags.Instance | BindingFlags.Public)!; IReadOnlyList calls = CompiledCallGraph.Read(method); Assert.Single( calls, call => call.Target.DeclaringType == typeof(SkyRenderer) && call.Target.Name == nameof(SkyRenderer.RenderWeather)); Assert.Single( calls, call => call.Target.DeclaringType == typeof(ParticleRenderer) && call.Target.Name == nameof(ParticleRenderer.Draw)); Assert.DoesNotContain( calls, call => call.Target.DeclaringType == typeof(WalkTranscriptDump)); } /// /// S3 chunk 4 (§10.2): the former per-outside-view-slice loop /// (the walk's own screen-space terrain-clip writer + its per-frame /// clip-routing reset call + the old DrawLandscapeSliceLate leaf, /// one call per active landscape view) is deleted — DrawLandscapeDynamicsPhase now calls /// exactly once, /// conditional on /// (see /// — the L1 pin), with no loop of any kind around it. This /// Assert.Single alone proved insufficient at fix round 1 (K1): /// it counts DISTINCT call-site offsets, so it stays green even with a /// foreach wrapped around the one call site (the exact round-1 /// regression this file's review caught) — see /// /// for the pin that actually rules that out. Kept as a cheap first-line /// check: MUTATION: adding a second, textually distinct call site (e.g. /// a duplicated call, not a loop) makes Assert.Single fail. /// [Fact] public void DrawLandscapeDynamicsPhase_CallsDrawWeatherOnceExactlyOnce() { MethodInfo method = typeof(RetailPViewRenderer).GetMethod( "DrawLandscapeDynamicsPhase", BindingFlags.Instance | BindingFlags.NonPublic)!; IReadOnlyList calls = CompiledCallGraph.Read(method); Assert.Single( calls, call => call.Target.DeclaringType == typeof(RetailPViewPassExecutor) && call.Target.Name == nameof(RetailPViewPassExecutor.DrawWeatherOnce)); } /// /// S3 chunk 4 fix round 1 (K1, blocking): the real loop-shape pin. /// 's /// Assert.Single over call-site offsets still passes when the ONE /// call site sits inside a foreach — an IL-offset ORDER pin has /// now failed three times to be discriminating for this exact class of /// regression, so this asks the LOOP-SHAPE question directly: does any /// BACKWARD branch (a branch whose target offset is lower than its own /// offset — the shape every C# loop compiles to, whether /// for/foreach/while) enclose the /// DrawWeatherOnce call's own IL offset? A call sitting strictly /// between a backward branch's target and its own offset is inside that /// loop's body and can run more than once per method invocation; a call /// outside every backward branch's span cannot. MUTATION: wrap the call /// in foreach (var slice in clipAssembly.OutsideViewSlices) — /// the compiled foreach emits a backward branch (the /// condition-check jump back to the loop body) whose span now contains /// the call's offset, so this test fails; restore the single /// unconditional call to make it pass again. Note for reviewers (added /// at S3 landing hygiene, H4, matching 's /// own note): reads only /// br/brtrue/brfalse-family single-target branches — /// it does not decode a compiled switch jump table, but no C# loop /// construct (for/foreach/while/do) ever /// compiles to one, so this pin's blind spot is not a loop shape it /// could miss. /// [Fact] public void DrawLandscapeDynamicsPhase_DrawWeatherOnceCallSiteHasNoEnclosingBackwardBranch() { MethodInfo method = typeof(RetailPViewRenderer).GetMethod( "DrawLandscapeDynamicsPhase", BindingFlags.Instance | BindingFlags.NonPublic)!; IReadOnlyList calls = CompiledCallGraph.Read(method); int callIndex = RequiredCallIndex( calls, typeof(RetailPViewPassExecutor), nameof(RetailPViewPassExecutor.DrawWeatherOnce)); int callOffset = calls[callIndex].Offset; IReadOnlyList branches = CompiledCallGraph.ReadBranches(method); Assert.DoesNotContain( branches, branch => branch.TargetOffset < branch.Offset && branch.TargetOffset <= callOffset && callOffset < branch.Offset); } /// /// S3 chunk 4 fix round 2 (L1, BLOCKING). Round 1's three-lens review /// found that neither existing pin above actually looks at the /// production CONDITION gating DrawWeatherOnce: restoring the /// pre-fix gate if (clipAssembly.OutsideViewSlices.Length != 0) — /// the exact regression K2 was supposed to close — leaves both green, /// because both only ask "is the call site shaped correctly", never /// "does the call site read WalkFrameDriver.WeatherTurnFired". /// This pin reads the compiled condition directly: with c the /// index of the DrawWeatherOnce call, (a) calls[c-1] must /// be the WeatherTurnFired getter — the LAST call before the draw /// — and (b) exactly one branch must sit strictly between that getter /// call and the draw call, be a brfalse/brfalse.s, and /// jump FORWARD past the draw call — the compiled shape of /// if (walkDriver.WeatherTurnFired) passes.DrawWeatherOnce(ctx); /// and nothing else (an inverted test, an unconditional call, or a /// different condition entirely all fail one of the two checks). /// MUTATION M1 (restores the pre-fix regression): change the gate back /// to if (clipAssembly.OutsideViewSlices.Length != 0) — check (a) /// fails because calls[c-1] is no longer the /// WeatherTurnFired getter. MUTATION M2 (drops the gate /// entirely): make the call unconditional — check (b) fails because no /// branch sits between the getter call and the draw call (in fact the /// getter call itself disappears with the gate, so check (a) fails /// first). MUTATION M3 (inverts the condition): change the gate to /// if (!walkDriver.WeatherTurnFired)calls[c-1] is still /// the getter (check (a) passes), but the compiler emits a /// brtrue/brtrue.s to skip the draw instead of a /// brfalse/brfalse.s, so check (b)'s opcode filter finds /// nothing and Assert.Single fails on zero matches. /// [Fact] public void DrawLandscapeDynamicsPhase_GatesDrawWeatherOnceOnWalkDriverWeatherTurnFired() { MethodInfo method = typeof(RetailPViewRenderer).GetMethod( "DrawLandscapeDynamicsPhase", BindingFlags.Instance | BindingFlags.NonPublic)!; IReadOnlyList calls = CompiledCallGraph.Read(method); int callIndex = RequiredCallIndex( calls, typeof(RetailPViewPassExecutor), nameof(RetailPViewPassExecutor.DrawWeatherOnce)); Assert.True(callIndex > 0, "Expected a call before DrawWeatherOnce — the gate condition."); CompiledCall condition = calls[callIndex - 1]; Assert.Equal(typeof(AcDream.App.Rendering.Walk.WalkFrameDriver), condition.Target.DeclaringType); Assert.Equal("get_WeatherTurnFired", condition.Target.Name); int conditionOffset = condition.Offset; int drawOffset = calls[callIndex].Offset; IReadOnlyList branches = CompiledCallGraph.ReadBranches(method); Assert.Single( branches, branch => branch.Offset > conditionOffset && branch.Offset < drawOffset && (branch.OpCode == OpCodes.Brfalse || branch.OpCode == OpCodes.Brfalse_S) && branch.TargetOffset > drawOffset); } /// /// S3 landing hygiene (H5): strengthens the L1 pin above against a /// conjoined gate the post-hoc three-lens review found it does not /// reject. L1's check (b) only looks at branches STRICTLY BETWEEN the /// WeatherTurnFired getter call and the DrawWeatherOnce /// call — so if (clipAssembly.OutsideViewSlices.Length != 0 && /// walkDriver.WeatherTurnFired) passes.DrawWeatherOnce(ctx); still /// passes it: the compiler evaluates OutsideViewSlices.Length != 0 /// FIRST, so ITS OWN brfalse lands BEFORE the getter call's /// offset — outside L1's window — while calls[c-1] is still the /// getter (the added condition reads OutsideViewSlices, a /// property getter, then .Length, a non-call ldlen, so no /// OTHER call intervenes before the getter). This pin widens the window /// to start at the call immediately before the whole gate — /// , /// the outdoor-emitters call the method's own comment names as the last /// call before the gate — and counts EVERY branch in that wider window /// with Assert.Single: production has exactly one, the forward /// brfalse/brfalse.s right after the getter. A conjoined /// gate's extra, earlier condition adds a second branch this wider /// window catches but L1's narrower one cannot. /// MUTATION: change the gate to if /// (clipAssembly.OutsideViewSlices.Length != 0 && /// walkDriver.WeatherTurnFired) — the branch count in the window /// goes from 1 to 2 and Assert.Single fails (see the commit body /// for the exact recorded failure text). /// [Fact] public void DrawLandscapeDynamicsPhase_ExactlyOneBranchGuardsDrawWeatherOnce() { MethodInfo method = typeof(RetailPViewRenderer).GetMethod( "DrawLandscapeDynamicsPhase", BindingFlags.Instance | BindingFlags.NonPublic)!; IReadOnlyList calls = CompiledCallGraph.Read(method); int particlesIndex = RequiredCallIndex( calls, typeof(RetailPViewPassExecutor), nameof(RetailPViewPassExecutor.DrawUnattachedSceneParticles)); int drawIndex = RequiredCallIndex( calls, typeof(RetailPViewPassExecutor), nameof(RetailPViewPassExecutor.DrawWeatherOnce)); int particlesOffset = calls[particlesIndex].Offset; int drawOffset = calls[drawIndex].Offset; IReadOnlyList branches = CompiledCallGraph.ReadBranches(method); CompiledBranch onlyGuard = Assert.Single( branches, branch => branch.Offset > particlesOffset && branch.Offset < drawOffset); Assert.True( onlyGuard.OpCode == OpCodes.Brfalse || onlyGuard.OpCode == OpCodes.Brfalse_S, $"Expected the sole branch between DrawUnattachedSceneParticles and " + $"DrawWeatherOnce to be a brfalse, was {onlyGuard.OpCode}."); Assert.True( onlyGuard.TargetOffset > drawOffset, "Expected the guard branch to skip forward past DrawWeatherOnce."); } /// /// S3 chunk 4 fix round 2 (L8): the identical loop-shape question K1 /// asked of 's call /// site, applied to 's /// own call — retail draws the sky /// dome exactly once per frame too (K4's own doc comment on /// DrawWalkSky), so nothing may wrap this call in a loop either. /// Note for reviewers: reads /// only br/brtrue/brfalse-family single-target /// branches — it does not decode a compiled switch jump table, /// but no C# loop construct (for/foreach/while/ /// do) ever compiles to one, so this pin's blind spot is not a /// loop shape it could miss. MUTATION: wrapping the call in /// for (int i = 0; i < 2; i++) { _sky?.RenderSky(...); } makes /// this fail; restoring the single unconditional call makes it pass /// again. /// [Fact] public void DrawWalkSky_RenderSkyCallSiteHasNoEnclosingBackwardBranch() { MethodInfo method = typeof(RetailPViewPassExecutor).GetMethod( "DrawWalkSky", BindingFlags.Instance | BindingFlags.NonPublic)!; IReadOnlyList calls = CompiledCallGraph.Read(method); int callIndex = RequiredCallIndex( calls, typeof(SkyRenderer), nameof(SkyRenderer.RenderSky)); int callOffset = calls[callIndex].Offset; IReadOnlyList branches = CompiledCallGraph.ReadBranches(method); Assert.DoesNotContain( branches, branch => branch.TargetOffset < branch.Offset && branch.TargetOffset <= callOffset && callOffset < branch.Offset); } /// /// S3 chunk 1 fix round 2 (§11.6 H1): is /// 's /// gate, extracted as a pure predicate so this suite can pin "no OC line /// while the player stands indoors" without a live GL/DAT /// — combined with the two structural tests /// above (moved out of the loop; drawn/printed exactly once per call), /// this proves both halves of the spec's pin: an outdoor root (or an /// interior root with several exit-view slices) prints exactly one OC /// line, and an indoor player prints none. Retail's own check: /// SmartBox::is_player_outside @0x00451e80, /// (player objcell_id & 0xFFFF) < 0x100. MUTATION: negating /// the < 0x100 comparison (or dropping either bool AND) makes /// one of the four rows below fail. /// [Theory] [InlineData(true, true, 0xF4180003u, true)] // outdoor root, player outside a land cell -> draws [InlineData(true, true, 0xA9B40100u, false)] // player indoors (local id >= 0x100) -> no draw [InlineData(false, true, 0xF4180003u, false)] // RenderSky off -> no draw [InlineData(true, false, 0xF4180003u, false)] // RenderWeather off -> no draw public void ShouldDrawWeatherOnce_MatchesRetailIsPlayerOutsideGate( bool renderSky, bool renderWeather, uint playerCellId, bool expected) { Assert.Equal( expected, RetailPViewPassExecutor.ShouldDrawWeatherOnce(renderSky, renderWeather, playerCellId)); } /// /// S4-c1 C1 (T2, seal half): D3DPolyRender::DrawPortalPolyInternal /// @0x0059bc90's degenerate-input guard, ported at the exit-seal /// enumeration (DrawPortalDepthWrite — the SAME loop that reads /// cell.PortalPolygons[index], the LOCAL portal-polygon /// vertices, and is the only production caller of /// ). A live /// functional test of this private method needs a real /// the suite has no fake for (see /// WalkFrameDriverTests.OnPunchGeometry_RejectsWholePolygonOn... /// for the punch-fan half's functional proof instead), so this pin asks /// the compiled-call-graph question this file's other tests already use /// for exactly this situation: does /// /// run BEFORE the vertex loop's calls and BEFORE /// (retail's reject -> transform -> clip -> count order — a hit /// must never reach either), with a conditional branch gating that /// order directly off the guard's own return value. /// MUTATION: move the guard call to AFTER the transform loop (or /// delete it) — either check below fails because the guard call index /// is no longer the smallest, or (deletion) /// throws for finding no call at all. /// [Fact] public void DrawPortalDepthWrite_RejectsDegenerateLocalPolygons_BeforeTransformOrSubmission() { MethodInfo method = typeof(RetailPViewPassExecutor).GetMethod( "DrawPortalDepthWrite", BindingFlags.Instance | BindingFlags.NonPublic)!; IReadOnlyList calls = CompiledCallGraph.Read(method); int guardIndex = RequiredCallIndex( calls, typeof(AcDream.App.Rendering.Walk.WalkVisibilityMath), nameof(AcDream.App.Rendering.Walk.WalkVisibilityMath.IsRejectedByPortalPolygonBoundaryGuard)); int transformIndex = RequiredCallIndex(calls, typeof(Vector3), nameof(Vector3.Transform)); int drawIndex = RequiredCallIndex( calls, typeof(PortalDepthMaskRenderer), nameof(PortalDepthMaskRenderer.DrawDepthFan)); Assert.True( guardIndex < transformIndex, "The boundary guard must run BEFORE the world-transform loop " + "(retail's reject -> transform -> clip -> count order)."); Assert.True( guardIndex < drawIndex, "The boundary guard must run BEFORE the fan is submitted " + "(no draw, no `submitted` increment on a hit)."); int guardOffset = calls[guardIndex].Offset; int transformOffset = calls[transformIndex].Offset; IReadOnlyList branches = CompiledCallGraph.ReadBranches(method); Assert.Contains( branches, branch => branch.Offset > guardOffset && branch.Offset < transformOffset && (branch.OpCode == OpCodes.Brtrue || branch.OpCode == OpCodes.Brtrue_S || branch.OpCode == OpCodes.Brfalse || branch.OpCode == OpCodes.Brfalse_S)); } /// /// S4-c1 fix round 1, F2: retail increments portalsDrawnCount /// (0x59BD70-0x59BD74) BEFORE polyClipFinish runs (0x59BDB0) — /// the counter records accepted ATTEMPTS, not successful GPU fans /// (oh1-depth-lifecycle.md's "Far-Z punches and true-depth exit /// seals" section). A polygon that survives the boundary guard but has /// fewer than 3 vertices is still COUNTED by /// 's returned /// submitted total, even though /// draws nothing (its /// own < 3 guard stands in for retail's post-clip /// var_4 >= 3 check). Round 0 dropped the count too — a /// < 3 continue ahead of both the boundary guard and the /// count — never observed on authored dat data (every real portal /// polygon has >= 3 vertices) but the wrong order all the same. /// MUTATION (verified, S4-c1 fix round 2 R2-5b): restore the old /// localVertices.Length < 3 pre-filter ahead of the guard — /// this pin's synthetic 2-vertex polygon is no longer counted and the /// assertion fails (submitted comes back 0, not 1). Moving the /// submitted++ increment itself to AFTER /// — the mutation /// this doc comment used to name alongside the pre-filter one — does /// NOT fail this pin: DrawDepthFan has no effect on the local /// submitted counter either way, so the final returned count is /// identical regardless of which side of that call the increment sits /// on. That reordering is unobservable to any assertion on the return /// value; only the pre-filter mutation is a genuine regression check. /// [Fact] public void DrawExitPortalMask_CountsAnUnclippableTwoVertexPolygon_ButDrawsNothing() { var cell = new LoadedCell { CellId = 0xA9B40105u, WorldTransform = Matrix4x4.Identity, }; cell.Portals.Add(new CellPortalInfo(OtherCellId: 0xFFFF, PolygonId: 0, Flags: 0, OtherPortalId: 0)); // Ordinary (non-degenerate) coordinates — the boundary guard admits // this polygon — but only TWO vertices: retail's post-clip // `var_4 >= 3` check (this port's DrawDepthFan `< 3` guard) drops // the fan submission even though the count already happened. cell.PortalPolygons.Add( [ new Vector3(1f, 1f, 0f), new Vector3(2f, 1f, 0f), ]); using var device = new RecordingGpuDevice(); var frames = new GpuDeviceFrameLifetime(device); var scope = new VulkanWorldPassScope(sampleCount: 1); using var portalDepthMask = new PortalDepthMaskRenderer(device, frames, scope); var diagnostics = new WorldRenderDiagnostics(new NeverCalledGlStateReader(), new NeverCalledDiagnosticLog()); // DrawPortalDepthWrite only reads _portalDepthMask, frame.Cells, // frame.RootCell.IsOutdoorNode, frame.ViewProjection, and // _diagnostics (short-circuited off by RenderingDiagnostics. // ProbeSeamDrawEnabled's default-off value) — the same // constructor-bypass pattern WalkOutsideViewReassemblyTests already // uses for exercising a real leaf without a full GL/DAT renderer // graph. var executor = (RetailPViewPassExecutor)System.Runtime.CompilerServices.RuntimeHelpers .GetUninitializedObject(typeof(RetailPViewPassExecutor)); typeof(RetailPViewPassExecutor) .GetField("_portalDepthMask", BindingFlags.NonPublic | BindingFlags.Instance)! .SetValue(executor, portalDepthMask); typeof(RetailPViewPassExecutor) .GetField("_diagnostics", BindingFlags.NonPublic | BindingFlags.Instance)! .SetValue(executor, diagnostics); var root = new LoadedCell { CellId = 0xF4180003u, IsOutdoorNode = false }; RetailPViewFrameInput frame = new RetailPViewFrameInput().Reset( rootCell: root, nearbyBuildingCells: null, viewerEyePos: Vector3.Zero, viewProjection: Matrix4x4.Identity, cells: new SingleCellSource(cell), camera: null!, cameraWorldPosition: Vector3.Zero, frustum: null, playerLandblockId: null, animatedEntityIds: null, renderCenterLbX: 0, renderCenterLbY: 0, renderRadius: 0, landblockEntries: Array.Empty<(uint, Vector3, Vector3, IReadOnlyList, IReadOnlyDictionary?)>(), renderSky: false, renderWeather: false, dayFraction: 0f, activeDayGroup: null, skyKeyframe: default, environOverrideActive: false, viewerCellId: 0, playerCellId: 0, playerViewPosition: Vector3.Zero, cameraView: Matrix4x4.Identity, cameraCellResolution: default); int drawsBefore = device.Calls.OfType().Count(); int submitted = executor.DrawExitPortalMask(frame, cell.CellId, ReadOnlySpan.Empty); int drawsAfter = device.Calls.OfType().Count(); Assert.Equal(1, submitted); Assert.Equal(drawsBefore, drawsAfter); } private sealed class SingleCellSource(LoadedCell cell) : IRetailPViewCellSource { public LoadedCell? Find(uint cellId) => cellId == cell.CellId ? cell : null; } private sealed class NeverCalledGlStateReader : IRenderGlStateReader { public RenderGlStateSnapshot CaptureState() => throw new InvalidOperationException("EmitSeamMask must short-circuit before reading GL state."); public RenderGlScissorSnapshot CaptureScissor() => throw new InvalidOperationException("EmitSeamMask must short-circuit before reading GL state."); } private sealed class NeverCalledDiagnosticLog : IRenderFrameDiagnosticLog { public void WriteLine(string message) => throw new InvalidOperationException("EmitSeamMask must short-circuit before logging (ProbeSeamDrawEnabled defaults off)."); } private static int RequiredCallIndex( IReadOnlyList calls, Type declaringType, string methodName) { int index = CompiledCallGraph.IndexOf(calls, declaringType, methodName); Assert.True( index >= 0, $"Expected call to {declaringType.Name}.{methodName}."); return index; } }