• Stars
    star
    277
  • Rank 148,875 (Top 3 %)
  • Language
    C++
  • License
    MIT License
  • Created almost 2 years ago
  • Updated 5 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A single-file zero-overhead C++ idiomatic wrapper for WebGPU native

WebGPU-C++

Table of Contents

What is this?

This is a single-file shallow wrapper for using the WebGPU native API in a more C++ idiomatic way. It comes with zero overhead and is mostly syntactic sugar to make the original C API less verbose. All C++ types are naturally compatible with original C-style types, the memory layout remains untouched.

The C++ wrapper is automatically generated from the official webgpu.h, with the possibility to inject custom code and blacklist symbols that your implementation of webgpu.h does not handle yet (see Going Further).

Features at a glance

  • Namespace
  • Default descriptor values
  • Object notation
  • Capturing closures
  • Scoped enumerations

Quick Start

The easiest route is to use the Web service: https://eliemichel.github.io/WebGPU-Cpp

NB To get started with WebGPU in general, see our Learn WebGPU for C++ documentation!

Setup

  1. Copy the file dawn/webgpu.hpp, wgpu-native/webgpu.hpp or emscripten/webgpu.hpp (depending on your backend) to your C++17 project.

NB You should also check the git tag that is in a file of this repo next to each webgpu.hpp. If your version of the backend is newer, see below how to generate the webgpu.hpp file yourself.

  1. Replace #include <webgpu/webgpu.h> by #include "webgpu/webgpu.hpp" in your source files:
#include "webgpu/webgpu.hpp"
  1. In exactly one of your source files, add #define WEBGPU_CPP_IMPLEMENTATION before including webgpu.cpp:
#define WEBGPU_CPP_IMPLEMENTATION
#include "webgpu/webgpu.hpp"

Usage

NB By default, the wrapper is built for the last version of the wgpu-native implementation of webgpu.h. If you use the Dawn implementation, you may need to read advanced instructions.

Namespace

Instead of prefixing every struct name with WGPU and every function name with wgpu (the C way), all symbols are put in a wgpu namespace (the C++ way):

// C style
WGPUInstanceDescriptor desc = {};
desc.nextInChain = nullptr;
WGPUInstance instance = wgpuCreateInstance(&desc);

becomes with namespaces:

// C++ style
wgpu::InstanceDescriptor desc = {};
wgpu::Instance instance = wgpu::createInstance(&desc);

And of course you can start your source file with using namespace wgpu; to avoid spelling out wgpu:: everywhere.

Default descriptor values

Sometimes we just need to build a descriptor by default. More generally, we rarely need to have all the fields of the descriptor deviate from the default, so this wrapper provides an easy way to set all fields to the default values, which is automatically synchronized from the official WebGPU specification.

Since it is very common, the nextInChain value is automatically set to nullptr by default. For other fields, the user must call the setDefault() method. This manual action prevents the wrapper from having hidden overhead:

BindGroupLayoutEntry bindGroupLayoutEntry;

// This recursively set defaults for bindGroupLayoutEntry.buffer,
// bindGroupLayoutEntry.sampler, etc.
bindGroupLayoutEntry.setDefault();

// Even more compact:
BindGroupLayoutEntry bindGroupLayoutEntry = Default;

Object notation

Beyond namespace, most functions are also previewed by the name of their first argument, e.g.:

// C style
WGPUBuffer wgpuDeviceCreateBuffer(WGPUDevice device, WGPUBufferDescriptor const * descriptor);
               ^^^^^^             ^^^^^^^^^^^^^^^^^
size_t wgpuAdapterEnumerateFeatures(WGPUAdapter adapter, WGPUFeatureName * features);
           ^^^^^^^                  ^^^^^^^^^^^^^^^^^^^
void wgpuBufferDestroy(WGPUBuffer buffer);
         ^^^^^^        ^^^^^^^^^^^^^^^^^

These functions are conceptually methods of the object constituted by their first argument, so in this wrapper they are exposed as such:

// C++ style
namespace wgpu {
	struct Device {
		// [...]
		createBuffer(const BufferDescriptor& descriptor);
	};

	struct Adapter {
		// [...]
		enumerateFeatures(FeatureName * features);
	};

	struct Device {
		// [...]
		destroy();
	};
} // namespace wgpu

Note also that descriptors are passed by reference rather than by pointer.

Capturing closures

Many asynchronous operations use callbacks. In order to provide some context to the callback's body, there is always a void *userdata argument passed around. This can be alleviated in C++ by using capturing closures.

NB This only alleviates the notations, but technically mechanism very similar to the user data pointer is automatically implemented when creating a capturing lambda.

// C style
struct Context {
	WGPUBuffer buffer;
};
auto onBufferMapped = [](WGPUBufferMapAsyncStatus status, void* pUserData) {
	Context* context = reinterpret_cast<Context*>(pUserData);
	std::cout << "Buffer mapped with status " << status << std::endl;
	unsigned char* bufferData = (unsigned char*)wgpuBufferGetMappedRange(context->buffer, 0, 16);
	std::cout << "bufferData[0] = " << (int)bufferData[0] << std::endl;
	wgpuBufferUnmap(context->buffer);
};
Context context;
wgpuBufferMapAsync(buffer, WGPUMapMode_Read, 0, 16, onBufferMapped, (void*)&context);

becomes

// C++ style
buffer.mapAsync(buffer, [&context](wgpu::BufferMapAsyncStatus status) {
	std::cout << "Buffer mapped with status " << status << std::endl;
	unsigned char* bufferData = (unsigned char*)context.buffer.getMappedRange(0, 16);
	std::cout << "bufferData[0] = " << (int)bufferData[0] << std::endl;
	context.buffer.unmap();
});

Scoped enumerations

Because enums are unscoped by default, the WebGPU API is forced to prefix all values that an enum can take with the name of the enum, leading to quite long names:

typedef enum WGPURequestAdapterStatus {
    WGPURequestAdapterStatus_Success = 0x00000000,
    WGPURequestAdapterStatus_Unavailable = 0x00000001,
    WGPURequestAdapterStatus_Error = 0x00000002,
    WGPURequestAdapterStatus_Unknown = 0x00000003,
    WGPURequestAdapterStatus_Force32 = 0x7FFFFFFF
} WGPURequestAdapterStatus;

It is possible in C++ to define scoped enums, which are strongly typed and can only be accessed through the name, for instance this scoped enum:

enum class RequestAdapterStatus {
    Success = 0x00000000,
    Unavailable = 0x00000001,
    Error = 0x00000002,
    Unknown = 0x00000003,
    Force32 = 0x7FFFFFFF
};

This can be used as follows:

wgpu::RequestAdapterStatus::Success;

NB The actual implementation use a little trickery so that enum names are scoped, but implicitly converted to and from the original WebGPU enum values.

Going further

Custom generation

The file webgpu.hpp is generated by running the generate.py script (with at least Python 3.10). The best way to get an up to date doc is through it's help message:

$ python generate.py --help
usage: generate.py [-h] [-t TEMPLATE] [-o OUTPUT] [-u HEADER_URL] [-d DEFAULTS] [--pplux] [--no-scoped-enums]
                   [--no-fake-scoped-enums] [--use-non-member-procedures]

Generate the webgpu-cpp binding from official webgpu-native headers. You should not have to change any of the default
arguments for a regular use. This generates a webgpu.hpp file that you can include in your project. Exactly one of
your source files must #define WEBGPU_CPP_IMPLEMENTATION before including this header.

options:
  -h, --help            show this help message and exit
  -t TEMPLATE, --template TEMPLATE
                        Template used for generating the output binding file
  -o OUTPUT, --output OUTPUT
                        Path where to output the generated webgpu.hpp
  -u HEADER_URL, --header-url HEADER_URL
                        URL of the official webgpu.h from the webgpu-native project. If the URL does not start with
                        http(s)://, it is considered as a local file
  -d DEFAULTS, --defaults DEFAULTS
                        File listing default values for descriptor fields. This argument can be provided multiple
                        times, the last ones override the previous values.
  --pplux               Generate a binding compatible with https://github.com/pplux/wgpu.hpp (requires the use of
                        pplux.template.h as the template)
  --no-scoped-enums     Do not replace WebGPU enums with C++ scoped enums
  --no-fake-scoped-enums
                        Use scoped aliases to original enum values so that no casting is needed
  --use-non-member-procedures
                        Include WebGPU methods that are not members of any WebGPU object

The default options download the last version of webgpu.h from the webgpu-native/webgpu-headers repository, but it is recommended to check that it matches your own version of this file (provided by your implementation, e.g., wgpu-native or Dawn).

The template file uses a quite simple format: variables to be replaced by a snippet of code is put inside double brackets, e.g., {{foo}}. You can look at webgpu.template.hpp for a list of available such variables.

There are two special pairs of tags which are not variables:

Blacklist

Between {{begin-blacklist}} and {{end-blacklist}}, you can list WebGPU procedures that you would like the binding to ignore. This must be used when your version of webgpu.h declares some symbols that are not actually implemented by your binaries of WebGPU.

Member injection

Between {{begin-inject}} and {{end-inject}}, you can specify extra methods to inject in the auto-generated handle types. Within this scope, define a subscope with HANDLE(Foo) and END tags to add arbitrary members in type Foo.

You must then declare the body of this method at the end of the file, between #ifdef WEBGPU_CPP_IMPLEMENTATION and #endif // WEBGPU_CPP_IMPLEMENTATION

PpluX

This generator was inspired by PpluX' wgpu.hpp, and it can actually generate the very same headers:

python generate.py -t wgpu-pplux.template.hpp -o wgpu-pplux.hpp --pplux

Default values

Default values for descriptors and structs are not provided in the webgpu.h native header. They are however specified in the official WebGPU specification, so we provide a script that downloads and scraps this document to extract the default values.

NB Running this script creates a defaults.txt file. If you want to add your own default values overrides, it is recommended to do so in the extra-defaults.txt file so that they do not get overwritten when running the scraper again.

Enumeration for which there exists an enum value Undefined default to this value, unless they have been specified a different default value in one of the default.txt files.

$ python fetch_default_values.py --help
usage: fetch_default_values [-h] [-u URL] [-v LOG_LEVEL] [-s OUTPUT_SPEC] [-d OUTPUT_DEFAULTS]

Fetch from the official WebGPU specification the default values for descriptors. Copyright (c) 2022-2023 Élie Michel

options:
  -h, --help            show this help message and exit
  -u URL, --url URL     URL of the specification document
  -v LOG_LEVEL, --log-level LOG_LEVEL
                        level of verbosity: DEBUG, INFO, WARNING ou ERROR
  -s OUTPUT_SPEC, --output-spec OUTPUT_SPEC
                        output JSON file containing the scraped API
  -d OUTPUT_DEFAULTS, --output-defaults OUTPUT_DEFAULTS
                        output file containing the default values

Nullable descriptors

Some procedures (e.g., wgpuTextureCreateView) have their last argument marked as "nullable". In this case, an overloaded version of the fonction is generated by the wrapper, where this last argument is removed, and internally nullptr is provided.

Update all generated examples

The examples provided in this repository were generated as follows:

python generate.py -u wgpu-native/webgpu.h -u wgpu-native/wgpu.h -t wgpu-native/webgpu.template.hpp -o wgpu-native/webgpu.hpp -d defaults.txt -d extra-defaults.txt
python generate.py -u dawn/webgpu.h -t dawn/webgpu.template.hpp -o dawn/webgpu.hpp -d defaults.txt -d extra-defaults.txt
python generate.py -u emscripten/webgpu.h -t emscripten/webgpu.template.hpp -o emscripten/webgpu.hpp -d defaults.txt -d extra-defaults.txt
python generate.py -t pplux/wgpu-pplux.template.hpp -o pplux/wgpu-pplux.hpp --pplux

See also

To get started with WebGPU, see our Learn WebGPU for C++ documentation!

This work was inspired by PpluX' wgpu.hpp.

License

MIT License
Copyright (c) 2022-2023 Elie Michel

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

More Repositories

1

MapsModelsImporter

A Blender add-on to import models from google maps
Python
2,414
star
2

LilySurfaceScraper

Import shaders end environments in Blender from a single URL
Cython
596
star
3

LearnWebGPU

Learn to use WebGPU for native graphic applications in C++
C++
383
star
4

BMeshUnity

A Unity package to make runtime procedural mesh generation more flexible.
C#
350
star
5

HoudiniEngineForBlender

Branch of Blender featuring a Houdini Engine based modifier
181
star
6

OpenMfxForBlender

A branch of Blender featuring an OpenMfx modifier
C
176
star
7

DagAmendment

The official implementation of the research paper "DAG Amendment for Inverse Control of Parametric Shapes"
C++
171
star
8

OpenMfx

A low-overhead mesh-processing plug-in API for cross-software procedural effects
C
161
star
9

WebGPU-distribution

Distributions of WebGPU for native and web development, easy to integrate and interchangeable.
CMake
145
star
10

LearnWebGPU-Code

The accompanying code of the Learn WebGPU C++ programming guide
99
star
11

BlenderImgui

Custom GUI for your Blender add-ons using Dear ImGui
Python
94
star
12

glfw3webgpu

An extension for the GLFW library for using WebGPU native.
C
62
star
13

LilyRender360

Lily Render 360 is a tool for rendering a Unity scene into stitch-free equirectangular images
C#
59
star
14

MfxHoudini

A Houdini-Engine based Open Mesh Effect
C
57
star
15

AdvancedBlenderAddon

A starter kit and reference for writing advanced Blender add-ons
Python
39
star
16

Python3dViewer

A simple starter Python code for experimenting 3D graphics
Python
30
star
17

sdl2webgpu

An extension for the SDL2 library for using WebGPU native.
C
25
star
18

MesoGen

The official implementation of MesoGen: Designing Procedural On-Surface Stranded Mesostructures (Siggraph 2023)
C++
24
star
19

RayStep

A real-time 3D distance field modeling software
C++
22
star
20

MapsModelsImporter-samples

Sample file to check MapsModelsImporter installation
20
star
21

LilyImageFromURL

A very very simple Blender add-on to very very quickly import images from URLs.
Python
17
star
22

GrainViewer

The official implementation of the research paper "Real-time multiscale rendering of dense dynamic stackings"
C++
13
star
23

MonumentValley

A little toy reproducing Monument Alley basic mechanism in Unity
C#
12
star
24

MfxVCG

An OpenMfx plug-in providing effects from VCGlib
C++
12
star
25

WebGPU-utils

A bunch of utility functions for WebGPU
C++
11
star
26

WebGPU-AutoLayout

An online utility tool to generate C++ boilerplate binding code by parsing WGSL.
Rust
10
star
27

TownBuilder

This is an experiment around the reproduction of Stalberg's Townscaper
C#
10
star
28

IRL

Inverse Reinforcement Learning
Jupyter Notebook
9
star
29

CodenameGogh

A node-based front-end to ffmpeg
C++
8
star
30

MfxExamples

An example of OpenMfx plug-in using the C++ SDK
C++
7
star
31

ModernGlad

Depreciation warnings to help writing more modern OpenGL using glad
Python
7
star
32

AugenLight

A cross-plateform OpenGL 4.5 starter kit
C++
6
star
33

firefox-webmention-addon

Firefox add-on to send webmentions though context menu
JavaScript
6
star
34

WebGPU-binaries

A CMake-ready binary release of a WebGPU native implementation (wgpu-native)
C
6
star
35

GreaseJs

A little demo of Grease Pencil using ThreeJS
JavaScript
6
star
36

sphinx_literate

An advanced literate programming tool for writing incremental programming courses.
Python
6
star
37

IvyGenerator

Update of Thomas Luft's original
C++
5
star
38

PythonMfx

A Python-based host for running OpenMfx mesh processing plugins
Python
5
star
39

WebGPU-Cpp-WebBackend

This is the backend of the Web service of https://github.com/eliemichel/WebGPU-Cpp
C++
5
star
40

fxos-AlphaRemote

A Firefox OS remote controller for Sony Alpha series cameras
JavaScript
4
star
41

AlignTools

Alignment tools add-on for Blender
Python
4
star
42

BiharmonicCoords

Webpage for the SIGGRAPH 24 paper "Biharmonic Coordinates and their Derivatives for Triangular 3D Cages"
HTML
4
star
43

WebGPU-raii

An RAII wrapper around the objects of the WebGPU native API.
C++
4
star
44

reshade

Fork ReShade adding Remote Control feature
C++
3
star
45

Cooldown

Feed rythm into live-coding tools
Rust
3
star
46

ReACORN

An attempt to reimplement ACORN
Python
3
star
47

WebMfx

A web-based host for OpenMfx using WASM plugins
C
3
star
48

PolyGreenCoords

Public page of "Polynomial 2D Green Coordinates for Polygonal Cages"(Siggraph 2023)
HTML
3
star
49

StatDeps

A lightweight C++ dependency graph library for compile-time dependent resource management.
C++
3
star
50

cartes-electorales

Python
2
star
51

MfxPlugins

Simple Open Mesh Effect plugins
C++
2
star
52

highspeedracer

Online racing game using Blender Game Engine
Python
2
star
53

LilyFuture

A header-only utiliy library to make std:futures fun to use!
C++
2
star
54

todo

A dead simple command line TODO-list manager
Python
2
star
55

Spillr

Mixed GLSL/C++ static C++ processor aiming at reducing boilerplate in shader writing
OCaml
2
star
56

UnitySsPattern

A screen space shader for Unity with object tracking
ShaderLab
2
star
57

SdfManipulation

Public page of "Direct Manipulation of Analytic Implicit Surfaces"(Siggraph Asia 2024)
HTML
2
star
58

webgpu-doc-jam

Set up for an incoming documentation jam of webgpu-headers, stay tuned!
2
star
59

JeuDePresse

Dessins d'actualité interactifs, produits en quelques heures avec MS Paint
JavaScript
2
star
60

irssi-notify

Notifications for Irssi via a simple http server
Python
1
star
61

WorLd

Simple 2D strategy game whom levels are autogenerated based on mathematical assertions
C++
1
star
62

texdown

Extension of markdown to support mathematics. Based on marked and MathJax.
JavaScript
1
star
63

join.js

The smallest JS library to love promises
JavaScript
1
star
64

fake-position

Firefox addon to spoof geolocation using openstreetmap
JavaScript
1
star
65

ColorSpaceViewer

A browser-based tool for visualizing images in color space
JavaScript
1
star
66

fHMM

Project for the lecture of Probabilistic Graphical Models
TeX
1
star
67

MemoryIDF

Code source du jeu Memory pour l'Ile de France, inspiré de la version pour Paris
HTML
1
star
68

OscToSpout

Forward OSC messages to KodeLife using a texture-sharing via Spout
C++
1
star
69

Dawn

Custom branches of Dawn for the Learn WebGPU for C++ guide
C++
1
star
70

PolyworldJs

Low-poly styled dynamic forest in ThreeJS
JavaScript
1
star
71

ZigDawn

Starter C++ project for using WebGPU native
C
1
star