Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Where to Go From Here

Owning the graphics backend

Everything in Part II went through pebble::wgpu — a ready-made Backend/FrameOperations implementation plus the descriptor-based material/mesh/texture layer on top of it. None of that is required by the framework itself. App, systems, resources, events, the asset pipeline — everything from Part I — work identically against a Backend you write by hand, for Metal, Vulkan, D3D12, or a second, differently-configured wgpu setup of your own.

Two traits, both covered conceptually in Opening a Window and Camera, Depth, and Lazy Resources without you writing them yourself:

FrameOperations — one acquired frame:

impl FrameOperations for MyFrame {
    type Context<'a> = MyRenderPass<'a>;  // what you draw with
    type Attachment = MyTextureView;
    type DepthAttachment = MyTextureView;

    fn begin(&mut self, pass: Pass<'_, Self>) -> Self::Context<'_> { /* ... */ }
}

Backend — the swapchain and device:

impl Backend for MyBackend {
    type Frame = MyFrame;

    fn init(handle: impl GPUSurfaceHandle, width: u32, height: u32, sender: InitSender<Self>) {
        // create device/swapchain synchronously or on a thread, then:
        sender.send(MyBackend { /* ... */ });
    }

    fn acquire(&mut self) -> Result<Self::Frame, AcquireError> { /* ... */ }
    fn present(&mut self, frame: Self::Frame) { /* ... */ }
}

init always delivers the backend through an InitSender — synchronously (sender.send before returning) or asynchronously (spawn a thread, call sender.send once it’s ready). App polls the channel every PreRender tick until the backend arrives — which is exactly the same “resource that arrives asynchronously” shape from Chapter 2, applied to the one resource every graphical app needs most.

Once you have Backend/FrameOperations, Asset<B> (Chapter 6) works against your own types exactly as it does against WGPUBackend — write your own Mesh/Material/Texture types implementing Asset<MyBackend> in place of reaching for pebble::wgpu’s. examples/hello_triangle, examples/textured_quad, and examples/orbit_camera do exactly this against a hand-rolled wgpu backend in examples/common — read them once you want to see the pattern applied for real, end to end.

The examples, ordered by complexity

ExampleWhat it adds
ecs_basicsPart I’s material, no window
clear_screenA window, a hand-rolled Backend, nothing drawn
hello_triangleA hand-rolled Asset pipeline, a triangle
textured_quadTexture loading, asset-to-asset dependencies
orbit_cameraCustom plugins, LazyResource, depth buffer, camera — the source for Chapter 10
wgpu_showcaseChapters 7–9’s exact code, running

Further reading

  • API docs: docs.rs/pebble-engine — every type and method this book covers, plus the ones it didn’t have room for (dynamic uniform/storage buffers, texture arrays, cubemaps, Query::single/get_single, ordering constraints between systems in the same stage).
  • The Readme: a denser, single-page version of Part I and the pebble::wgpu overview — good as a quick reference once you’ve read this book once.
  • learn-wgpu: for wgpu concepts this book takes as given — bind groups, pipelines, shader stages — sotrh.github.io/learn-wgpu covers them from first principles.

Pebble is under active development — expect the API to keep moving. If something in this book drifts out of date, it’s a bug in the book, not a reason to distrust it wholesale: open an issue.