refactor(lifetime): own render resource prefixes
Give terrain, sky, retained UI, portal preparation, and the update/render frame pair explicit single owners. Make shader, texture, text, bindless, and GL construction prefixes checked and retryable so partial failure cannot lose or replay resource ownership. Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
parent
fec0d94148
commit
c87b15303d
41 changed files with 3768 additions and 355 deletions
|
|
@ -67,17 +67,18 @@ public sealed class GameWindowSlice8BoundaryTests
|
|||
"_dats = RuntimeDatCollectionFactory.OpenReadOnly(_datDir);",
|
||||
"_runtimeSettings.ApplyStartup(",
|
||||
"new RuntimeSettingsStartupTargets(",
|
||||
"_uiHost = new AcDream.App.UI.UiHost(",
|
||||
"_uiHost = _retailUiLease.AcquireHost(",
|
||||
"_uiHost.WireMouse(m)",
|
||||
"_uiHost.WireKeyboard(kb)",
|
||||
"_retailUiRuntime = AcDream.App.UI.RetailUiRuntime.Mount(",
|
||||
"_retailUiRuntime = _retailUiLease.Mount(",
|
||||
"_liveEntities = new AcDream.App.World.LiveEntityRuntime(",
|
||||
"_selectionInteractions ??= new AcDream.App.Interaction.SelectionInteractionController(",
|
||||
"_retainedUiGameplayBinding =",
|
||||
"AcDream.App.Input.RetainedUiGameplayBinding.Create(",
|
||||
"_retainedUiGameplayBinding.Attach();",
|
||||
"_renderFrameOrchestrator =",
|
||||
"_updateFrameOrchestrator = new AcDream.App.Update.UpdateFrameOrchestrator(",
|
||||
"var renderFrameOrchestrator =",
|
||||
"var updateFrameOrchestrator = new AcDream.App.Update.UpdateFrameOrchestrator(",
|
||||
"_frameGraphs.Publish(updateFrameOrchestrator, renderFrameOrchestrator);",
|
||||
"_liveSessionHost = CreateLiveSessionHost();",
|
||||
"_liveCombatModeCommands.Bind(combatCommand);",
|
||||
"_runtimeDiagnosticCommands.Bind(runtimeDiagnostics);",
|
||||
|
|
@ -265,7 +266,7 @@ public sealed class GameWindowSlice8BoundaryTests
|
|||
shutdown,
|
||||
"_runtimeSettings.UnbindViewModel()",
|
||||
"_runtimeSettings.UnbindRuntimeTargets",
|
||||
"_retailUiRuntime?.Dispose()",
|
||||
"_retailUiLease.Dispose()",
|
||||
"_streamer?.Dispose()",
|
||||
"_wbDrawDispatcher?.Dispose()",
|
||||
"_terrain?.Dispose()");
|
||||
|
|
@ -292,12 +293,12 @@ public sealed class GameWindowSlice8BoundaryTests
|
|||
"private void OnClosing()",
|
||||
"private ResourceShutdownTransaction CreateShutdownTransaction()");
|
||||
|
||||
Assert.Equal(1, CountOccurrences(update, "_updateFrameOrchestrator.Tick("));
|
||||
Assert.Equal(1, CountOccurrences(render, "_renderFrameOrchestrator!.Render("));
|
||||
Assert.Equal(1, CountOccurrences(update, "_frameGraphs.Tick("));
|
||||
Assert.Equal(1, CountOccurrences(render, "_frameGraphs.Render("));
|
||||
AssertAppearsInOrder(
|
||||
render,
|
||||
"Vector2D<int> size = _window!.Size;",
|
||||
"_renderFrameOrchestrator!.Render(",
|
||||
"_frameGraphs.Render(",
|
||||
"new AcDream.App.Rendering.RenderFrameInput(");
|
||||
Assert.DoesNotContain("FramebufferSize", render, StringComparison.Ordinal);
|
||||
Assert.Contains(
|
||||
|
|
@ -338,6 +339,8 @@ public sealed class GameWindowSlice8BoundaryTests
|
|||
"new ResourceShutdownStage(\"shared texture owners\"",
|
||||
"new ResourceShutdownStage(\"mesh adapter\"",
|
||||
"new ResourceShutdownStage(\"remaining render owners\"",
|
||||
"new ResourceShutdownStage(\"dedicated render resources\"",
|
||||
"new ResourceShutdownStage(\"failed render construction cleanup\"",
|
||||
"new ResourceShutdownStage(\"frame flight owner\"",
|
||||
"new ResourceShutdownStage(\"content mappings\"",
|
||||
"new ResourceShutdownStage(\"input\"",
|
||||
|
|
@ -390,6 +393,66 @@ public sealed class GameWindowSlice8BoundaryTests
|
|||
character => Assert.True(char.IsWhiteSpace(character) || character == '}'));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ResourceRootsAndFramePairHaveExplicitAcquireTransferAndReleaseBoundaries()
|
||||
{
|
||||
string source = GameWindowSource();
|
||||
string load = MethodBody(
|
||||
"private void OnLoad()",
|
||||
"private AcDream.App.Net.LiveSessionHost");
|
||||
string shutdown = Slice(
|
||||
source,
|
||||
"private ResourceShutdownTransaction CreateShutdownTransaction()",
|
||||
"private void OnFocusChanged(bool focused)");
|
||||
string terrainAtlas = File.ReadAllText(Path.Combine(
|
||||
FindRepoRoot(),
|
||||
"src",
|
||||
"AcDream.App",
|
||||
"Rendering",
|
||||
"TerrainAtlas.cs"));
|
||||
|
||||
AssertAppearsInOrder(
|
||||
load,
|
||||
"_renderResourceLifetime.AcquireTerrainAtlas(",
|
||||
"_terrain = new TerrainModernRenderer(",
|
||||
"_portalTunnelFallback.AcquirePrepared(",
|
||||
"static portalTunnel => portalTunnel.PrepareResources());",
|
||||
"_renderResourceLifetime.AcquireSkyShader(",
|
||||
"_skyRenderer = new AcDream.App.Rendering.Sky.SkyRenderer(",
|
||||
"_portalTunnelFallback.Transfer(",
|
||||
"_frameGraphs.Publish(updateFrameOrchestrator, renderFrameOrchestrator);");
|
||||
AssertAppearsInOrder(
|
||||
shutdown,
|
||||
"_frameGraphs.Withdraw();",
|
||||
"_retailUiLease.Dispose();",
|
||||
"_localPlayerTeleport?.Dispose();",
|
||||
"_portalTunnelFallback.ReleaseFallback();",
|
||||
"_skyRenderer?.Dispose()",
|
||||
"_terrain?.Dispose();",
|
||||
"_renderResourceLifetime.ReleaseSkyShader",
|
||||
"_renderResourceLifetime.ReleaseTerrainAtlas",
|
||||
"_glConstructionCleanup.Dispose",
|
||||
"_gl?.Dispose();");
|
||||
|
||||
Assert.DoesNotContain(
|
||||
"RetailUiRuntime.Mount(",
|
||||
load,
|
||||
StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("gl.GenTexture()", terrainAtlas, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain(
|
||||
"portalTunnel.PrepareResources();",
|
||||
load,
|
||||
StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("_portalTunnel =", source, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("_renderFrameOrchestrator", source, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("_updateFrameOrchestrator", source, StringComparison.Ordinal);
|
||||
AssertAppearsInOrder(
|
||||
source,
|
||||
"_window.Run();",
|
||||
"_glConstructionCleanup.RetainFrom(failure);",
|
||||
"_glConstructionCleanup.Dispose");
|
||||
}
|
||||
|
||||
private static string MethodBody(string start, string end) =>
|
||||
Slice(GameWindowSource(), start, end);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue