Make RenderContextProvider an abstract class that reports its colour target size - #485
Merged
Conversation
|
✅ Development package |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
#481 moved the
Pixely.Uibuild into the update phase. That phase has no render context, so it cannot readColorTarget.Sizethe wayRenderused to. It fell back to the window's size, which is right only when the context targets the swapchain. A context drawing into a same-format target of a different size was left laid out for the window, and the renderer then refused to draw it, so the UI stayed blank.An earlier revision of #481 patched this with a
viewportSourcedelegate onUseUi. That was dropped: it asked the caller to restate a size the framework already knows, and it could be got wrong as silently as the bug it patched.The size belongs to whoever decides the target, and that is the provider.
The provider answers for its target
IRenderContextProvider<T>becomes the abstract classRenderContextProvider<T>with a new virtual member:UseUiresolves the provider it already knows the type of and lays out against that. Nothing changes for a swapchain target, because the default is the window. A provider drawing somewhere else overrides one method, in the class it already had to write.Named for what it measures.
IRenderContext.ColorTargetandWindow.ColorTargetFormatmake "colour target" the existing vocabulary.Abstract class rather than an interface
A default interface member would have kept source compatibility, but it is the worse tool here:
myProvider.GetColorTargetSize(window)would not compile without a cast to the interface.overrideautocomplete gives it.The cost is the type's single inheritance slot. That is unlikely to matter for a provider, and
docs/class-registration.md:43already documents resolving a service by a base class, so the container supports this directly.CLAUDE.mdsays composition over inheritance. This is a deliberate exception: a one level extension point with a sensible default is what abstract classes are for, in the shape ofTextWriterorHttpMessageHandler.Breaking
IRenderContextProvider<T>is gone. Implementations derive fromRenderContextProvider<T>and markTryCreateRenderContextasoverride. Registrations name the class instead of the interface:Three implementations in the repository were updated, plus the sample in
docs/window-rendering.md.UiUpdateSystemtakes what it uses#481 gave the system
Func<Vector2Int>andFunc<bool>rather than a window, becauseRenderSizeInPixelsandIsVisibleare non-virtual SDL calls and a system holding a window could not be built in a test. There was never a production case for either delegate. Both always closed over the same window.A virtual
GetColorTargetSizeremoves that reason for the size, so the system now takes the window and the provider:Window.IsVisiblebecomes virtual, which is what lets a test answer it without a display. The class is generic over the context type, asUiRenderer<TRenderContext>already is.The delegates cost more than they looked. Two
Funcs say nothing about where their values come from, and codex made the point during the #481 review: a test could not tell which window a closure had captured without calling it or reflecting over compiler generated fields.ResolveUpdateTargetsexists to work around that opacity.Tests
ResolveUpdateTargetsis now generic over the context type and returns the provider alongside the root and window.A case #481 could not reach is now covered directly: that the size the tree is laid out against comes from the provider rather than the window. It needed a GPU before, because
UseUibuildsUiRenderereagerly. The system is now built in the test from a fake provider and an uninitialised window that has no SDL size to give, so a viewport taken from the window could not produce the expected answer.The hidden window test no longer counts on a delegate never being called. It asserts on a provider that records how many times it was asked, which is the behaviour the code claims: a hidden window does not pay for a size call.
The ordering test asserts a sequence rather than build counts. Both systems build once, so counts cannot distinguish them. Verified it fails when the expected sequence is reversed.