Split graphics host contract

This commit is contained in:
gamer147
2026-08-03 10:50:18 -04:00
parent a584b734b3
commit 4b05135c38
4 changed files with 64 additions and 38 deletions

View File

@@ -167,8 +167,11 @@ timed-deadline waiting, frame yield, and scene reset. `engine/Age.Engine/Hosting
SFX, fade, volume, and route-control contracts, including the compatibility overload/default chains used by SFX, fade, volume, and route-control contracts, including the compatibility overload/default chains used by
simple hosts. `engine/Age.Engine/Hosting/IMovieHost.cs` owns ordinary, positioned, mask-transition, activity-query, simple hosts. `engine/Age.Engine/Hosting/IMovieHost.cs` owns ordinary, positioned, mask-transition, activity-query,
and modal movie playback contracts. `IHost` inherits all four focused contracts; their required and default and modal movie playback contracts. `IHost` inherits all four focused contracts; their required and default
behavior is unchanged. The neutral `engine/Age.Engine/Model/MovieMaskTransitionRequest.cs` record carries movie behavior is unchanged. `engine/Age.Engine/Hosting/IGraphicsHost.cs` owns mutable surfaces, retained-range/frame
mask work between the VM, host, and retained graphics without making `Model` depend on `Hosting`. presentation, transitions, texture lifecycle, pixel capture/replace, draw, and size contracts; `IHost` also
inherits this focused surface without changing existing hosts. The neutral
`engine/Age.Engine/Model/MovieMaskTransitionRequest.cs` record carries movie mask work between the VM, host, and
retained graphics without making `Model` depend on `Hosting`.
`engine/Age.Engine/Model/RgbaImage.cs` owns the format-independent packed RGBA image transported between SYS4 `engine/Age.Engine/Model/RgbaImage.cs` owns the format-independent packed RGBA image transported between SYS4
decoders, host surfaces, renderers, persistence, and tests; consumers do not depend on `Sys4` merely to exchange decoders, host surfaces, renderers, persistence, and tests; consumers do not depend on `Sys4` merely to exchange
decoded pixels. decoded pixels.

View File

@@ -786,6 +786,13 @@ do not mix mechanical moves with semantic changes.
the neutral image contract; image-only format imports were removed while genuine SYS4 consumers retained the neutral image contract; image-only format imports were removed while genuine SYS4 consumers retained
theirs. Decoder and image behavior remain unchanged, and runtime validation remains green. theirs. Decoder and image behavior remain unchanged, and runtime validation remains green.
The sixth bounded contract slice introduced `IGraphicsHost` for mutable surface fill/copy, retained-range and
frame presentation, transition waits/fades, texture lifecycle, pixel capture/replace, drawing, and size
queries. `IHost` inherits the focused contract; all seventeen members, required implementations, default
fallbacks, and existing host classes remain behaviorally unchanged. Surface request records and the fade
direction remain in their prior locations pending a separate transport cleanup. Runtime validation remains
green.
4. **Make the build graph express source ownership.** Stop linking production `.cs` files from `godot/` and 4. **Make the build graph express source ownership.** Stop linking production `.cs` files from `godot/` and
`tools/movie-corpus-gate/` into `Age.Engine.Tests`. Extract the platform-neutral frontend/movie/diagnostic `tools/movie-corpus-gate/` into `Age.Engine.Tests`. Extract the platform-neutral frontend/movie/diagnostic
code into a small production project referenced by Godot, tests, and the corpus gate. Retain both existing code into a small production project referenced by Godot, tests, and the corpus gate. Retain both existing
@@ -1146,8 +1153,8 @@ layer's rendering diverges from ADV; save layout.
## 8. Immediate next step ## 8. Immediate next step
Continue step 3 of the **codebase consolidation** maintenance slice: clarify runtime contracts without changing Continue step 3 of the **codebase consolidation** maintenance slice: clarify runtime contracts without changing
behavior or the aggregate host accepted by the VM. With diagnostic, lifecycle, audio, and movie contracts behavior or the aggregate host accepted by the VM. With diagnostic, lifecycle, audio, and movie contracts
established beneath `IHost` and shared movie/image transport now neutral, introduce the graphics host contract established beneath `IHost`, shared movie/image transport neutral, and the graphics contract now separated, move
next. Preserve its surface, retained-range presentation, transition, texture, capture/replace, and headless-default the unchanged `SurfaceRectFill`, `SurfaceRectCopy`, and `SurfaceBlackFadeDirection` contracts from `Hosting` to
behavior while leaving the remaining surface request records in place for a separate transport cleanup. `Model` next. Preserve all consumers and graphics behavior before separating the remaining ADV/input domains.
Concrete playthrough blockers may still preempt this bounded maintenance work; the consolidation effort does Concrete playthrough blockers may still preempt this bounded maintenance work; the consolidation effort does
not replace Phase B gameplay validation or the open cross-platform gates. not replace Phase B gameplay validation or the open cross-platform gates.

View File

@@ -0,0 +1,48 @@
using Age.Engine.Model;
namespace Age.Engine.Hosting;
public interface IGraphicsHost
{
void FillSurfaceRect(SurfaceRectFill fill) { }
void CopySurfaceRect(SurfaceRectCopy copy) { }
void PresentObjectRange(GfxState gfx, long firstHandle, long count) { }
// Normal playback reaches op 0x21c and parks until a queued 0x223 transition completes. The
// read/message-skip branch reaches op 0x20c and presents the completed endpoint immediately.
void WaitForForegroundTransition(GfxState gfx) { }
void PresentFrame(GfxState gfx) { }
// Legacy SYS4 screen-transition family (ops 0x21, 0x22, and 0x25): scripts render complete
// frames into numbered surfaces, then block while the engine alpha-composites an endpoint.
// Native bypasses the timed service when ADV fast-forward is already active at opcode dispatch.
void FadeSurfaceWithBlack(
GfxState gfx, int surface, long intervalArgument, SurfaceBlackFadeDirection direction,
bool forceEndpoint = false) { }
void CrossfadeSurfaces(
GfxState gfx, int sourceSurface, int targetSurface, long intervalArgument,
bool forceEndpoint = false) { }
void CreateTexture(int slot, int width, int height);
/// <summary>Return a stable RGBA snapshot of one numbered surface, or null when unavailable.</summary>
RgbaImage? CaptureSurfacePixels(int slot) => null;
/// <summary>Replace one numbered surface from decoded RGBA pixels. False means unsupported.</summary>
bool ReplaceSurfacePixels(int slot, RgbaImage image) => false;
void SetTexture(long resourceId, int slot);
void SetTexture(long resourceId, int slot, long colorKey) => SetTexture(resourceId, slot);
void ReleaseSurface(int slot) { }
/// <summary>Clear the selected target's pixels; -1 denotes the main backbuffer.</summary>
void ClearRenderTarget(int surfaceSlot) { }
void ReleaseSurfaceRange(int firstSlot, int count)
{
for (int slot = firstSlot; slot < firstSlot + count; slot++) ReleaseSurface(slot);
}
void DrawTexture(int slot, int srcX, int srcY, int width, int height, int dstX, int dstY);
(int Width, int Height) GetTextureSize(int slot);
}

View File

@@ -40,7 +40,7 @@ public enum SurfaceBlackFadeDirection
ToBlack, ToBlack,
} }
public interface IHost : IDiagnosticHost, ILifecycleHost, IAudioHost, IMovieHost public interface IHost : IDiagnosticHost, ILifecycleHost, IAudioHost, IMovieHost, IGraphicsHost
{ {
/// <summary>Present AGERc's modal full-width editor. Cancel preserves CurrentText.</summary> /// <summary>Present AGERc's modal full-width editor. Cancel preserves CurrentText.</summary>
FullwidthTextEditResult EditFullwidthString(FullwidthTextEditRequest request) FullwidthTextEditResult EditFullwidthString(FullwidthTextEditRequest request)
@@ -84,9 +84,6 @@ public interface IHost : IDiagnosticHost, ILifecycleHost, IAudioHost, IMovieHost
void EndTextHistoryPresentation(GfxState gfx) => EndTextHistoryPresentation(); void EndTextHistoryPresentation(GfxState gfx) => EndTextHistoryPresentation();
int MessageWindowAlphaSetting => 0; int MessageWindowAlphaSetting => 0;
void SetMessageWindowAlphaSetting(int value) { } void SetMessageWindowAlphaSetting(int value) { }
void FillSurfaceRect(SurfaceRectFill fill) { }
void CopySurfaceRect(SurfaceRectCopy copy) { }
void PresentObjectRange(GfxState gfx, long firstHandle, long count) { }
void ConfigureAdvWaitIndicator(AdvWaitIndicatorConfig config) { } void ConfigureAdvWaitIndicator(AdvWaitIndicatorConfig config) { }
// Op 0x212 supplies the ordinary retained handle used to publish the configured atlas cell. // Op 0x212 supplies the ordinary retained handle used to publish the configured atlas cell.
void BindAdvWaitIndicator( void BindAdvWaitIndicator(
@@ -134,33 +131,4 @@ public interface IHost : IDiagnosticHost, ILifecycleHost, IAudioHost, IMovieHost
// Optional diagnostic override. Native ReadTextDB state is VM/profile-owned; interactive hosts // Optional diagnostic override. Native ReadTextDB state is VM/profile-owned; interactive hosts
// normally leave this false. // normally leave this false.
bool IsAdvReadSkipActive => false; bool IsAdvReadSkipActive => false;
// Normal playback reaches op 0x21c and parks until a queued 0x223 transition completes. The
// read/message-skip branch reaches op 0x20c and presents the completed endpoint immediately.
void WaitForForegroundTransition(GfxState gfx) { }
void PresentFrame(GfxState gfx) { }
// Legacy SYS4 screen-transition family (ops 0x21, 0x22, and 0x25): scripts render complete
// frames into numbered surfaces, then block while the engine alpha-composites an endpoint.
// Native bypasses the timed service when ADV fast-forward is already active at opcode dispatch.
void FadeSurfaceWithBlack(
GfxState gfx, int surface, long intervalArgument, SurfaceBlackFadeDirection direction,
bool forceEndpoint = false) { }
void CrossfadeSurfaces(
GfxState gfx, int sourceSurface, int targetSurface, long intervalArgument,
bool forceEndpoint = false) { }
void CreateTexture(int slot, int width, int height);
/// <summary>Return a stable RGBA snapshot of one numbered surface, or null when unavailable.</summary>
RgbaImage? CaptureSurfacePixels(int slot) => null;
/// <summary>Replace one numbered surface from decoded RGBA pixels. False means unsupported.</summary>
bool ReplaceSurfacePixels(int slot, RgbaImage image) => false;
void SetTexture(long resourceId, int slot);
void SetTexture(long resourceId, int slot, long colorKey) => SetTexture(resourceId, slot);
void ReleaseSurface(int slot) { }
/// <summary>Clear the selected target's pixels; -1 denotes the main backbuffer.</summary>
void ClearRenderTarget(int surfaceSlot) { }
void ReleaseSurfaceRange(int firstSlot, int count)
{
for (int slot = firstSlot; slot < firstSlot + count; slot++) ReleaseSurface(slot);
}
void DrawTexture(int slot, int srcX, int srcY, int width, int height, int dstX, int dstY);
(int Width, int Height) GetTextureSize(int slot);
} }