Contents

Platform Integration

Presentation can be managed by the application or by a UI rendering control. This determines who acquires the current frame's output texture, records and submits the frame, and presents the result. That output texture is called the drawable.

Native presentation surfaces

The triangle tutorial uses Silk.NET to create the window and process its events. Zenith.NET receives the native window handles and dimensions through a Surface description, which it uses to create a SwapChain. The application remains responsible for the operating-system window.

Surface handles must match the selected backend:

Surface factory Handles supplied by the host Backend and platform
Win32 HWND DirectX 12 or Vulkan on Windows.
Wayland Wayland display and surface Vulkan with a native Wayland host.
Xlib X11 display and window Vulkan on Linux with X11 or XWayland.
Android ANativeWindow Vulkan on Android.
Apple CAMetalLayer Metal on Apple platforms.

The sample host in App.cs supports Windows, macOS, and X11. Its Linux window supplies Xlib handles, so a Wayland session needs XWayland to run it. A native Wayland application supplies its display and surface handles through Surface.Wayland.

Swap-chain dimensions and lifetime

The swap chain uses the framebuffer's width and height in pixels, which can differ from the window's logical dimensions under display scaling. Defer rendering and swap-chain resizing while either dimension is zero. Obtain SwapChain.Drawable for each frame: the swap chain owns this texture and may replace it after presentation or resizing.

When framebuffer dimensions change, wait for outstanding GPU uses of the old images before calling SwapChain.Resize. To replace the native presentation target, pass its new surface description and handles to SwapChain.Refresh after those uses finish. At shutdown, release the swap chain before destroying its native presentation target.

If application-owned depth or offscreen textures follow the window size, recreate them when that size changes and update constants that contain their handles. The pipeline can be reused as long as the attachment formats and sample counts still match. The spinning cube renderer demonstrates this separation between resized textures and a reusable pipeline.

Rendering through a UI control

The controls implement IZenithView. The application assigns GraphicsContext, updates scene data in UpdateRequested, and records commands in RenderRequested using the supplied RenderEventArgs.

For each frame, the control acquires a drawable and a command buffer, transitions the drawable to ColorAttachment, and calls the update and render handlers. It then submits the recorded work and presents the image using the framework's presentation mechanism.

Add using Zenith.NET; to the file. For an initialized IZenithView named view with a graphics context assigned, register this handler to clear its drawable:

view.RenderRequested += (_, args) =>
{
    args.CommandBuffer.BeginRenderPass([ColorAttachment.Clear(args.Drawable, new(0.04f, 0.055f, 0.075f, 1.0f))], null);

    args.CommandBuffer.EndRenderPass();
};

Record pipeline bindings and draw commands inside the pass, then end it before the handler returns. The control submits the commands and presents the result. The handler must not submit the command buffer or dispose either supplied object. If it changes the drawable's layout, restore ColorAttachment before returning so the control can perform its final transition.

The initial transition uses Undefined, which allows the previous image contents to be discarded. Draw or clear the full image on each frame. Keep accumulated or cached rendering in an application-owned texture, then draw that texture into the control's drawable.

ZenithViewHelper.DrawableFormat provides the default color format used by these integrations.

Use Desc.Width, Desc.Height, Desc.Format, and Desc.SampleCount from the drawable supplied by the render event when creating matching attachments. The event texture gives the render target's actual dimensions; they should not be inferred from the control's layout size or display scale.

Framework and presentation path

The event interface is shared, but the presentation mechanism depends on the framework:

Integration Presentation mechanism
Avalonia Renders to a texture and downloads pixels into a WriteableBitmap. See ZenithView.cs and Surface.cs.
WinForms Creates a Zenith.NET swap chain for the control's HWND. See ZenithView.cs.
WPF Imports a shared Direct3D 11 texture, then copies through Direct3D interop to a surface displayed by D3DImage. See Surface.cs.
WinUI on Windows Renders into an imported shared Direct3D 11 texture, then copies to a composition swap chain attached to SwapChainPanel. See ZenithView.WinUI.cs.
Uno path Downloads pixels into a WriteableBitmap. See ZenithView.Uno.cs.
.NET MAUI Uses native surfaces on Android, iOS and Mac Catalyst, and shared-texture composition on Windows. See the platform implementations.

These implementations differ in how the GPU image reaches the UI. Bitmap readback copies pixels into CPU memory before display. Shared-texture interop avoids that CPU copy but can still require GPU copies and synchronization. Consider this presentation path, as well as the shared RenderRequested event, when choosing an integration.

Add the integration package for your UI framework through NuGet. For Avalonia, use Zenith.NET.Views.Avalonia.

WinForms, WPF, and the Windows WinUI integration run on Windows. For MAUI, install the workload for the target platform and register the control handler with UseZenithView, as shown in Extensions.cs.

Application and control ownership

The application owns the assigned context and its rendering resources; the control owns its presentation resources. When the view's GraphicsContext changes, the scheduler recreates the control's resources for the new context. Recreate the application's pipelines, buffers, and textures for that context as well.

Before replacing rendering resources, stop the view's frame activity and wait for the GPU work that uses them. Only then release the old resources or context. The application remains responsible for releasing the assigned context when the view is removed.

The shared FrameScheduler.cs runs frame handlers through the view's UI dispatcher. Keep those handlers focused on updating scene data and recording commands; lengthy CPU work there also delays the interface.

Search documentation

Search tutorials, concepts, samples, and the API reference.