using AcDream.App.Input; using AcDream.App.Rendering; using AcDream.App.Rendering.Gpu; using AcDream.App.Rendering.Gpu.Vk; using AcDream.UI.Abstractions.Input; using Silk.NET.Input; namespace AcDream.App.Composition; /// /// Campaign V slice V6h: the Vulkan arm of the host phase — now the only arm, /// the raw-GL RetailHostInputCameraCompositionFactory it used to fork /// from having been deleted at slice V11. Input, camera and pointer /// construction are inlined directly rather than delegated, since there is no /// longer a second implementation to share them with. /// /// What is absent, and why. There is no GL fence ring: the RHI /// device owns its own frames-in-flight through a timeline semaphore, so /// retirement and slot indexing come from the device instead. There is no /// : it was a raw-GL state tripwire, and /// Vulkan has no global state for it to watch. Both nulls are read by the /// phases that would otherwise consume them. /// internal sealed class VulkanHostInputCameraCompositionFactory : IHostInputCameraCompositionFactory { public IFramebufferViewportTarget CreateViewportTarget( GameWindowGraphics graphics) => // The viewport is a pipeline dynamic state on Vulkan, set per pass by // the encoder from the pass extent, so there is no persistent viewport // to bind here. The framebuffer-resize controller still drives the // camera aspect through its own target. NullFramebufferViewportTarget.Instance; public GpuFrameFlightController? CreateGpuFrameFlights( GameWindowGraphics graphics) => null; public IGpuDevice CreateGpuDevice( GameWindowGraphics graphics, GpuFrameFlightController? frameFlights) => RequireContext(graphics).Device; public IGpuResourceRetirementQueue CreateRetirement( GameWindowGraphics graphics, GpuFrameFlightController? frameFlights, IGpuDevice device) => device.Retirement; public IRenderFrameSlotSource CreateFrameSlots( GameWindowGraphics graphics, GpuFrameFlightController? frameFlights, IGpuDevice device) => new VulkanRenderFrameSlotSource(RequireContext(graphics).Device); public WorldRenderDiagnostics? CreateWorldRenderDiagnostics( GameWindowGraphics graphics, IRenderFrameDiagnosticLog log) => null; public SilkKeyboardSource CreateKeyboardSource( IKeyboard keyboard, HostQuiescenceGate quiescence) => SilkKeyboardSource.CreateDetached(keyboard, quiescence); public SilkMouseSource CreateMouseSource( IMouse mouse, IInputCaptureSource capture, IKeyboardSource? keyboard, HostQuiescenceGate quiescence) => SilkMouseSource.CreateDetached(mouse, capture, keyboard, quiescence); public IMouseLookCursor CreateMouseLookCursor(IMouse mouse) => new SilkMouseLookCursor(mouse); public InputDispatcher CreateInputDispatcher( IKeyboardSource keyboard, IMouseSource mouse, KeyBindings bindings) => InputDispatcher.CreateDetached(keyboard, mouse, bindings); public CameraController CreateCameraController() => new(new OrbitCamera(), new FlyCamera()); public IFramebufferCameraTarget CreateCameraTarget(CameraController camera) => new CameraFramebufferTarget(camera); public CameraPointerInputController CreateCameraPointerInput( IReadOnlyList mice, HostQuiescenceGate quiescence, IInputCaptureSource capture, LocalPlayerModeState playerMode, CameraController camera, ChaseCameraInputState chase, IMouseSource mouse, PointerPositionState pointer) => CameraPointerInputController.Create( mice, quiescence, capture, playerMode, camera, chase, mouse, pointer, new EnvironmentInputMonotonicClock()); private static VulkanGraphicsContext RequireContext( GameWindowGraphics graphics) => graphics.Vulkan ?? throw new InvalidOperationException( "The Vulkan host factory was composed against a backend with no " + "Vulkan context."); /// /// Vulkan sets the viewport per pass from the pass extent, so there is no /// persistent viewport binding for the resize controller to update. Size is /// still recorded, because the swapchain recreation the host performs is /// what actually resizes the surface. /// private sealed class NullFramebufferViewportTarget : IFramebufferViewportTarget { public static NullFramebufferViewportTarget Instance { get; } = new(); private NullFramebufferViewportTarget() { } public void ResizeViewport(int width, int height) { } } /// /// The flight slot per-frame buffers index by. Identical in role to the GL /// ring's ; the count comes /// from the device's timeline flight controller rather than a fence array. /// private sealed class VulkanRenderFrameSlotSource(VulkanGpuDevice device) : IRenderFrameSlotSource { public int CurrentSlot => device.Flights.CurrentSlot; } }