Expand description
§WIP (but definitely working)
Maybe Easier wgpu, a thin (?) abstraction to hopefully help organize your 3
buffers, 20 bind groups, 13 vertex formats, and 7 pipelines.
No other combination is allowed.
wgpu is a 1:1 API for the WebGPU standard. While that makes it very portable, versatile, and well-documented, since I’m not a hardcore graphics chud, I don’t find it very intuitive to use.
My main problem with it is how many bloody times you need to define the same
thing, and quadruple-check that all the layouts line up with each other: first
the BindGroupLayoutDescriptor, which turns into a BindGroupLayout, which is
then used in a PipelineLayoutDescriptor by putting it into a
BindGroupLayoutEntry…
Wait, crap, I think I forgot a struct somewhere along the line.
§The point of this
This library aims to, at least a little bit, make it easier to define all the
related information in one place (in wrapper structs).
It primarily uses like 10 macro_rules! to write boilerplate that generates
buffer, bind group, and pipeline layouts. It also stores them in a convenient
“render context” struct.
My original goal wasn’t to simplify the wgpu API, rather just to follow a programming pattern I used, but with the amount of boilerplate this let me cut down on, it did kind of end up as a “simplification wrapper”. However, it still should be possible to lobotomize my code and mix-and-match your own custom handlers, so you can do the same funky lower-level stuff as you could if you use wgpu directly.
It eventually mutated and grew a couple helper structs though, see below.
§Not the point of this
As I mentioned, this isn’t supposed to dumb down the wgpu API, but rather make it easier to define everything. This library is for people who have already used wgpu at least once, so if you’re brand-new to graphics programming, this likely isn’t the super-simple graphics toolkit you’re looking for.
I should also point out, this doesn’t handle making windows. You can use
winit for that, its API is actually quite usable
directly, especially compared to wgpu. The example highlights integrating
this and winit in practice, because, well, what else would an example do if not
drawing to the screen?
Update: Not that long after, I made a smol helper struct that bundled a
winit window with a wgpu surface and managed construction, which I found
really helpful to cut down on boilerplate.
Not long after that, I tried dealing with WebGL and realized I had to interleave
context creation with window creation… WHAT the FU-
Anyway, I made a helper struct to deal with that anti-pattern. It took a bit of
mental gymnastics to figure out what needed to happen, but I hope my API is
idiot-proof enough to keep myself from breaking everything, at least.
(Laughs in refactoring an already half-completed project)
§Final note
Because I’m not a graphics programming chud (my only “graphical” programming experience prior to wgpu is Processing, ShaderToy, a 3D wireframe demo in the terminal, raycasting in a 2D game engine, and Bevy), I don’t know the normal way to do proper graphics. All my knowledge of wgpu came from the docs, experimentation, and this tutorial, which is really handy though ever-so-slightly (very) outdated.
You’ll also need to excuse my weird code, using both really verbose traits in combination with macros where traits would be too painful (trust me, I tried). I use lots of type wrappers and generics to (maybe) make it easier to integrate your own types if you need any functionality that I missed.
§public static final note
§Usage
For actual code, see the examples. Hopefully you’ll just get it, it’s pretty straight forward.
TL;DR all those pesky layout descriptors you need to keep track of are
generated & stored in a central “context” object, and then fetched when needed.
The context also holds the adapter & device, handles creating buffers &
pipelines for you, etc.
Originally, I wrote a hacky “static map” tuple that mapped pipeline/bindgroup
types to their descriptor objects using generic functions. It was cool and
worked, but the biggest downside of it was that you need to declare all the
things you’re going to use beforehand in the root context object, which was
annoying if you had lots of graphics sub-modules. Now, it’s just one
RenderContext struct defined in the crate, mapping type IDs dynamically once
you use them the first time.
§Features
§android
Proxies feature android-native-activity in winit. Does nothing in the crate
itself.
§winit
Default
Enables winit as a public dependency and provides some handy utilities under
winitutils.
§webgl
Not compatible with poll
Proxies feature webgl in winit. Permits deferring RenderContext
construction in a JS thread until a window is created, by way of
winitutils::DeferredContext.
§poll
Not compatible with webgl
Enables pollster as a public dependency. Permits deferring RenderContext
construction on native targets until a window is created, by way of
winitutils::DeferredContext.
Re-exports§
pub use wgpu;pub use winit;
Modules§
- bindgroup
- buffer
- doc_
example - pipeline
- prelude
- sampler
- shaderprimitive
- shaderstruct
- texture
- vertexformat
- vertexstruct
- winitutils
Macros§
- bind_
group - Define a bind group, with internal buffer types (and their field names), and
their shader visibility (see
wgpu::ShaderStages). - buffer
- Define a storage buffer, with an optional internal type/struct to align its length with.
- pipeline
- Define a pipeline, with internal bind group and vertex types.
- sampler
- shader_
struct - Declare a shader struct (to use in a storage buffer).
- texture
- usage: variants of wgpu::TextureUsages format: variant of wgpu::TextureFormat dimension: variant of wgpu::TextureViewDimension sample_type: Float, FloatFiltering, Depth, Sint, or Uint
- vertex_
struct - Declare a vertex struct (to use in a vertex buffer).