noesis_wgpu 0.1.0

A wgpu render device for the Noesis GUI Native SDK: draws Noesis's batches on a wgpu device and queue you provide.
Documentation

noesis_wgpu

CI crates.io docs.rs

A wgpu render device for the Noesis GUI Native SDK. Noesis lays out and animates XAML UI but draws nothing itself: it hands a render device textures, render targets, and batches of triangles. WgpuRenderDevice draws them on a wgpu::Device and wgpu::Queue you provide.

It works with the Rust bindings in noesis_runtime, and also without them, for a host that loads Noesis another way and forwards the device calls. noesis_bevy uses it to render Noesis in Bevy.

Built for Dead Money's own games and mostly written by AI agents under human direction.

You need a Noesis license

With the default shim feature, this crate links the Noesis Native SDK through noesis_runtime. The SDK is closed-source commercial software from Noesis Technologies S.L. that we don't redistribute. Buy it separately and point NOESIS_SDK_DIR at your install.

This release targets Noesis Native SDK 3.2.13, the version noesis_runtime is built against.

Without the shim feature, nothing here or in noesis_runtime touches the SDK: the build needs no NOESIS_SDK_DIR and links no Noesis library.

Quick start

[dependencies]
noesis_runtime = "0.13"
noesis_wgpu = "0.1"
wgpu = "29"

Create the device on your wgpu device and queue, point it at the texture Noesis should draw into, and register it with noesis_runtime:

use noesis_runtime::render_device::register;
use noesis_runtime::view::{FrameworkElement, View};
use noesis_wgpu::WgpuRenderDevice;

noesis_runtime::init();

let root = FrameworkElement::parse(
    r#"<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
           <TextBlock Text="Hello"/>
       </Grid>"#,
)
.expect("XAML parses");
let mut view = View::create(root);
view.set_size(1280, 720);

// `target` is an Rgba8Unorm texture view the UI renders into.
let mut device = WgpuRenderDevice::new(wgpu_device.clone(), wgpu_queue.clone());
device.set_onscreen_target(target, 1280, 720);
let device = register(device);
view.renderer().init(&device);

// Each frame:
view.update(time_seconds);
let mut renderer = view.renderer();
renderer.update_render_tree();
renderer.render_offscreen();
renderer.render(false, true);

The device submits its own command encoders when the offscreen and onscreen phases end, so the UI texture is ready for anything you submit to the same queue afterwards. To render into a new target, for example after a resize, call set_onscreen_target again through Registered::device_mut.

Driving the device yourself

A host that receives Noesis's render-device calls some other way, such as a C# RenderDevice in the managed SDK that forwards them over a C ABI, calls the same methods on WgpuRenderDevice directly. Turn off default features so no Noesis library is linked:

[dependencies]
noesis_runtime = { version = "0.13", default-features = false }
noesis_wgpu = { version = "0.1", default-features = false }

That host creates Noesis's texture objects, so it knows which TextureHandle each texture pointer in a Batch stands for. It passes them with the batch:

use noesis_wgpu::{BatchTextures, WgpuRenderDevice};

let textures = BatchTextures {
    pattern: handle_for(batch.pattern),
    ramps: handle_for(batch.ramps),
    image: handle_for(batch.image),
    glyphs: handle_for(batch.glyphs),
    shadow: handle_for(batch.shadow),
};
device.draw_batch_with(batch, textures);

How it works

  • One shader source. noesis.wgsl covers Noesis's shader set with #ifdef branches, the convention of Noesis's own GL shaders. The device strips it down to one variant per Noesis shader and compiles a pipeline the first time a draw needs that shader, render state, vertex format, and stencil combination.
  • One encoder per phase. begin_offscreen_render and begin_onscreen_render each open a command encoder, and the matching end_* submits it. Every draw records its own render pass.
  • Per-draw uniforms. All of a phase's buffer writes land before its encoder is submitted, so each draw writes its uniforms to its own slot of a ring buffer, and geometry is appended rather than overwritten.
  • Stencil clipping. Render targets that ask for one, and the onscreen target, get a Stencil8 buffer, cleared before the first draw into each target.
  • No extra wgpu features. Text uses Noesis's grayscale SDF path. Subpixel (LCD) text, which needs dual-source blending, is off.

What it doesn't do yet: MSAA render targets (Noesis's offscreen sample count must stay 1), custom pixel shaders (ShaderEffect and BrushShader batches), and the SDF_* gradient and pattern paints. A phase holds at most 1024 draws.

Version compatibility

noesis_wgpu wgpu Bevy (through noesis_bevy)
0.1 29 0.19

wgpu types are part of the API, so each wgpu major gets a new noesis_wgpu minor. Older lines get fixes on release/0.N branches while a noesis_bevy release still uses them.

Building

unzip NoesisGUI-NativeSDK-linux-3.2.13-Indie.zip -d ~/sdks/noesis-3.2.13
export NOESIS_SDK_DIR=~/sdks/noesis-3.2.13
cargo test

The tests render on a real GPU adapter and read the pixels back; a software Vulkan driver such as lavapipe works too. They drive the device directly and need no Noesis license, so cargo test --no-default-features runs them without the SDK.

License

MIT. No Noesis SDK code is included. Binaries that link the SDK are covered by the Noesis EULA.

Acknowledgements

Built on wgpu and the Noesis Native SDK. The render-device protocol and shader set follow the SDK's own reference devices; the Noesis documentation is the source of truth for how Noesis drives a device. Report SDK bugs there; report bugs in this device here.