7 releases
Uses new Rust 2024
| 0.2.4 | Feb 28, 2026 |
|---|---|
| 0.2.3 | Feb 11, 2026 |
| 0.1.0 | Jan 21, 2026 |
| 0.0.1 | Dec 4, 2025 |
#718 in Graphics APIs
Used in 5 crates
665KB
13K
SLoC
astrelis-render
Modular rendering framework for the Astrelis game engine.
Overview
astrelis-render provides a modular, extensible architecture for managing GPU resources and rendering. It wraps WGPU with higher-level abstractions while maintaining low-level control when needed.
Architecture
Core Modules
context- Graphics context management (device, queue, adapter)window- Window rendering contexts and surface managementframe- Frame lifecycle and render pass buildersrenderer- Low-level extensible renderer for resource management
Design Philosophy
- Modular: Each component has a clear responsibility
- Extensible: Easy to build higher-level renderers (TextRenderer, SceneRenderer, etc.)
- Type-Safe: Leverages Rust's type system for safety
- Zero-Cost: Minimal overhead over raw WGPU
Quick Start
Basic Setup
use astrelis_render::{GraphicsContext, RenderableWindow, WindowContextDescriptor};
use astrelis_winit::{app::run_app, window::WindowDescriptor};
run_app(|ctx| {
// Create graphics context
let graphics_ctx = GraphicsContext::new_sync();
// Create window
let window = ctx.create_window(WindowDescriptor::default())?;
let window = RenderableWindow::new(window, graphics_ctx);
Box::new(MyApp { window })
});
Using the Renderer API
use astrelis_render::Renderer;
let graphics_ctx = GraphicsContext::new_sync();
let renderer = Renderer::new(graphics_ctx);
// Create shader
let shader = renderer.create_shader(Some("My Shader"), shader_source);
// Create vertex buffer
let vertices: &[f32] = &[/* ... */];
let vertex_buffer = renderer.create_vertex_buffer(Some("Vertices"), vertices);
// Create texture
let texture = renderer.create_texture_2d(
Some("My Texture"),
width, height,
wgpu::TextureFormat::Rgba8UnormSrgb,
wgpu::TextureUsages::TEXTURE_BINDING,
texture_data,
);
// Create sampler
let sampler = renderer.create_linear_sampler(Some("Sampler"));
// Create bind group
let bind_group_layout = renderer.create_bind_group_layout(
Some("Layout"),
&[/* entries */],
);
let bind_group = renderer.create_bind_group(
Some("Bind Group"),
&bind_group_layout,
&[/* entries */],
);
Render Loop
impl App for MyApp {
fn update(&mut self, _ctx: &mut AppCtx) {
// Global logic
}
fn render(&mut self, _ctx: &mut AppCtx, window_id: WindowId, events: &mut EventBatch) {
if window_id != self.window_id {
return;
}
// Handle events
events.dispatch(|event| {
match event {
Event::WindowResized(size) => {
self.window.resized(*size);
HandleStatus::consumed()
}
_ => HandleStatus::ignored()
}
});
// Begin frame
let mut frame = self.window.begin_drawing();
{
// Create render pass
let mut render_pass = RenderPassBuilder::new()
.label("Main Pass")
.color_attachment(
None, // Use window surface
None,
wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
store: wgpu::StoreOp::Store,
},
)
.build(&mut frame);
let pass = render_pass.wgpu_pass();
// ... render commands
}
frame.finish();
}
}
API Reference
GraphicsContext
Manages the WGPU instance, adapter, device, and queue.
// Create with defaults
let ctx = GraphicsContext::new_sync();
// Create with custom descriptor
let ctx = GraphicsContext::new_with_descriptor(
GraphicsContextDescriptor {
backends: wgpu::Backends::VULKAN | wgpu::Backends::METAL,
power_preference: wgpu::PowerPreference::HighPerformance,
features: wgpu::Features::PUSH_CONSTANTS,
..Default::default()
}
).await;
// Query device info
let info = ctx.info();
let limits = ctx.limits();
let features = ctx.features();
WindowContext
Manages a window surface and its configuration.
let window_ctx = WindowContext::new(
window,
graphics_ctx,
WindowContextDescriptor {
format: Some(wgpu::TextureFormat::Bgra8UnormSrgb),
present_mode: Some(wgpu::PresentMode::Mailbox),
alpha_mode: Some(wgpu::CompositeAlphaMode::Opaque),
},
);
// Handle resize
window_ctx.resized(new_size);
// Reconfigure surface
window_ctx.reconfigure_surface(new_config);
// Access surface
let surface = window_ctx.surface();
let config = window_ctx.surface_config();
Renderer
Low-level API for creating GPU resources.
Buffer Creation
// Vertex buffer
let vertex_buffer = renderer.create_vertex_buffer(label, vertices);
// Index buffer
let index_buffer = renderer.create_index_buffer(label, indices);
// Uniform buffer
let uniform_buffer = renderer.create_uniform_buffer(label, &uniforms);
// Update uniform
renderer.update_uniform_buffer(&uniform_buffer, &new_uniforms);
Texture Creation
// 2D texture with data
let texture = renderer.create_texture_2d(
label,
width, height,
format,
usage,
data,
);
// Custom texture descriptor
let texture = renderer.create_texture(&descriptor);
Sampler Creation
// Linear sampler
let sampler = renderer.create_linear_sampler(label);
// Nearest sampler
let sampler = renderer.create_nearest_sampler(label);
// Custom sampler
let sampler = renderer.create_sampler(&descriptor);
Bind Groups
// Create layout
let layout = renderer.create_bind_group_layout(label, &entries);
// Create bind group
let bind_group = renderer.create_bind_group(label, &layout, &entries);
Pipeline Creation
// Create shader
let shader = renderer.create_shader(label, source);
// Create pipeline layout
let pipeline_layout = renderer.create_pipeline_layout(
label,
&[&bind_group_layout],
&push_constant_ranges,
);
// Create render pipeline
let pipeline = renderer.create_render_pipeline(&descriptor);
// Create compute pipeline
let compute_pipeline = renderer.create_compute_pipeline(&descriptor);
Command Submission
// Create encoder
let mut encoder = renderer.create_command_encoder(label);
// ... record commands
// Submit
renderer.submit(std::iter::once(encoder.finish()));
RenderPassBuilder
Builder for creating render passes with automatic encoder management.
let mut render_pass = RenderPassBuilder::new()
.label("My Pass")
.color_attachment(
Some(&texture_view),
None, // No resolve target
wgpu::Operations {
load: wgpu::LoadOp::Clear(color),
store: wgpu::StoreOp::Store,
},
)
.depth_stencil_attachment(
&depth_view,
Some(wgpu::Operations {
load: wgpu::LoadOp::Clear(1.0),
store: wgpu::StoreOp::Store,
}),
None, // No stencil
)
.build(&mut frame);
// Use the render pass
let pass = render_pass.wgpu_pass();
pass.set_pipeline(&pipeline);
// ... render commands
// Encoder automatically returned to frame when dropped
WGPU Re-export
All WGPU types are re-exported for convenience:
use astrelis_render::wgpu;
// Instead of:
// use wgpu::TextureFormat;
// You can use:
use astrelis_render::wgpu::TextureFormat;
Building Higher-Level Renderers
The Renderer is designed as a foundation for specialized renderers:
pub struct TextRenderer {
renderer: Renderer,
pipeline: wgpu::RenderPipeline,
font_atlas: wgpu::Texture,
// ...
}
impl TextRenderer {
pub fn new(context: &'static GraphicsContext) -> Self {
let renderer = Renderer::new(context);
// Use renderer API to create resources
let shader = renderer.create_shader(/* ... */);
let font_atlas = renderer.create_texture_2d(/* ... */);
Self { renderer, pipeline, font_atlas }
}
pub fn draw_text(&mut self, text: &str, position: Vec2) {
// High-level text rendering API
}
}
Example Renderer Types
- TextRenderer - Text rendering with font atlases
- SpriteRenderer - 2D sprite batching
- SceneRenderer - 3D scene rendering with lighting
- UIRenderer - Immediate-mode UI rendering
- ParticleRenderer - GPU particle systems
- DebugRenderer - Debug shapes and lines
Examples
See the examples/ directory for complete examples:
renderer_api.rs- Demonstrates the low-level Renderer APItextured_window.rs- Basic textured quad renderingmulti_window.rs- Multiple windows with different content
Run an example:
cargo run --package astrelis-render --example renderer_api
Features
- Modular Architecture - Clean separation of concerns
- Type-Safe - Compile-time safety with Rust
- Zero-Cost Abstractions - Minimal overhead
- Multi-Window Support - Render to multiple windows
- Extensible - Easy to build specialized renderers
- WGPU Integration - Full access to WGPU features
- Profiling Integration - Built-in profiling support
License
Part of the Astrelis game engine.
Dependencies
~18–44MB
~683K SLoC