by Monstrous Software
This is an extension for LibGDX which allows you to use the WebGPU graphics API instead of OpenGL.
WebGPU is a modern graphics API that was developed for browsers, but can also be used for native applications. So it is not just for web, but also for desktop and mobile applications. WebGPU can make use of different backends, such as Vulkan, Metal or DirectX.
The gdx-webgpu extension provides a number of graphics classes (WgSpriteBatch, WgModelBatch, WgStage, etc.) to use instead of the ones from LibGDX. These provide the same behaviour without using OpenGL.
The gdx-webgpu extension uses jWebGPU by Xpenatan as underlying API which provides a multi-platform Java interface to a native WebGPU implementation, in particular to WGPU.
Instead of the regular application launcher, use the gdx-webgpu launcher for your platform as described below.
Then in your application, you can generally code as normal for LibGDX applications, except that for some graphics classes you need to use an alternative class.
Gdx-webgpu provides substitute classes for many of the LibGDX graphics classes.
For example, instead of Texture, you would use WgTexture, instead of SpriteBatch you would use WgSpriteBatch, etcetera. It's not possible to mix and match;
there is no OpenGL context so using any classes that rely on OpenGL will result in error messages.
Here is an example that should look very familiar to LibGDX users:
package main.java;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.monstrous.gdx.webgpu.backends.desktop.WgDesktopApplication;
import com.monstrous.gdx.webgpu.graphics.WgTexture;
import com.monstrous.gdx.webgpu.graphics.g2d.WgSpriteBatch;
public class HelloTexture extends ApplicationAdapter {
private Texture texture;
private SpriteBatch batch;
@Override
public void create() {
texture = new WgTexture(Gdx.files.internal("data/badlogic.jpg")); // note: WgTexture
batch = new WgSpriteBatch(); // note: WgSpriteBatch
}
@Override
public void render() {
batch.begin();
batch.draw(texture, 0, 0);
batch.end();
}
@Override
public void dispose(){
batch.dispose();
texture.dispose();
}
}Note in the example that WgTexture was used to create the Texture object. WgTexture is a subclass of Texture, suitable for WebGPU. Also note that WgSpriteBatch was used instead of SpriteBatch. In this example, these are the only two changes from a regular LibGDX application: using types with a Wg- prefix instead of the standard LibGDX graphics classes.
For more information see the User Guide in the docs folder
To start up a gdx-webgpu application, a platform-specific starter class will call the relevant back-end and run the application specific code.
For example to launch a gdx-webgpu application for desktop, create a WgApplication and pass it an instance of ApplicationListener and optionally a configuration object.
package com.example.mygame;
import com.example.mygame.MyGame;
import com.monstrous.gdx.webgpu.application.WebGPUContext;
import com.monstrous.gdx.webgpu.backends.desktop.WgDesktopApplication;
import com.monstrous.gdx.webgpu.backends.desktop.WgDesktopApplicationConfiguration;
public class Launcher {
public static void main (String[] argv) {
WgApplicationConfiguration config = new WgApplicationConfiguration();
config.setWindowedMode(1200, 800);
new WgApplication(new MyGame(), config);
}
}Yes, you can call WebGPU functions directly through the jWebGPU interface. This may be necessary for example when working with compute shaders.
See here for some more information: intro to WebGPU
If you run the WebGPUTestStarter application in the tests module, you get a menu with lots of
different test cases.
You can also check out the web version here: tests. (Press Escape to return to the test selection menu).
The tests/ folder contains a suite of test applications. You can run them on desktop, web, or Android, either interactively (with a chooser UI), as a single test by name, or in auto mode (all tests sequentially, 3 seconds each).
Use the backend-specific Gradle task names:
# Interactive test chooser (default):
./gradlew gdx_webgpu_tests_desktop_jni_wgpu_run
./gradlew gdx_webgpu_tests_desktop_jni_dawn_run
./gradlew gdx_webgpu_tests_desktop_ffm_wgpu_run
./gradlew gdx_webgpu_tests_desktop_ffm_dawn_run
# Run a single test by class name:
./gradlew gdx_webgpu_tests_desktop_jni_wgpu_run --args="Particles3D"
./gradlew gdx_webgpu_tests_desktop_jni_dawn_run --args="Particles3D"
./gradlew gdx_webgpu_tests_desktop_ffm_wgpu_run --args="Particles3D"
./gradlew gdx_webgpu_tests_desktop_ffm_dawn_run --args="Particles3D"
# Run ALL tests sequentially (auto mode):
./gradlew gdx_webgpu_tests_auto_desktop_jni_wgpu_run
./gradlew gdx_webgpu_tests_auto_desktop_jni_dawn_run
./gradlew gdx_webgpu_tests_auto_desktop_ffm_wgpu_run
./gradlew gdx_webgpu_tests_auto_desktop_ffm_dawn_runDesktop applications can select the Java binding and native WebGPU implementation entirely through gdx-webgpu:
implementation("io.github.monstroussoftware.gdx-webgpu:backend-desktop-jni-wgpu:$gdxWebGPUVersion")
// Add this too when the application must support both implementations:
implementation("io.github.monstroussoftware.gdx-webgpu:backend-desktop-jni-dawn:$gdxWebGPUVersion")Choose either the JNI or FFM binding, then declare WGPU, Dawn, or both matching artifacts. Gradle deduplicates their shared dependencies when both are present. Each artifact supplies the matching Windows x64, Linux x64, macOS x64, and macOS arm64 native runtimes transitively, so applications do not declare jWebGPU dependencies. Set config.backendWebGPU to the implementation to use; Dawn is the current default. The unsuffixed backend-desktop-jni and backend-desktop-ffm coordinates are not published.
If an application is distributed for only one desktop platform, append the platform to the artifact ID so that only its native runtime is included:
implementation("io.github.monstroussoftware.gdx-webgpu:backend-desktop-jni-wgpu_linux_x64:$gdxWebGPUVersion")
implementation("io.github.monstroussoftware.gdx-webgpu:backend-desktop-jni-dawn_linux_x64:$gdxWebGPUVersion") // optionalThe available suffixes are _windows_x64, _linux_x64, _mac_x64, and _mac_arm64, and they are available for every JNI/FFM and WGPU/Dawn combination. These are separate Maven coordinates rather than classifiers because classifiers share the aggregate coordinate's POM and therefore cannot have a platform-specific transitive dependency set.
The TeaVM C test project selects the native WebGPU implementation at build time. It automatically chooses the matching Windows x64, Linux x64, macOS x64, or macOS arm64 artifact for the current host.
# WGPU (default)
./gradlew gdx_teavm_glfw_run
# Dawn
./gradlew gdx_teavm_glfw_run -PwebgpuCBackend=dawnUse gdx_teavm_glfw_generate or gdx_teavm_glfw_build instead of the run task when only generation or compilation is needed. Supported values for webgpuCBackend are wgpu and dawn; exactly one backend artifact is packaged in each output under tests/gdx-tests-desktop-c/build/dist/<backend>/<platform>.
The published Windows TeaVM C payloads use the dynamic MSVC runtime, so this test project passes the standard CMake value CMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDLL (/MD). When substituting jWebGPU libraries built for /MT, select the matching consumer runtime with -PwebgpuCMSVCRuntime=MultiThreaded.
First, build the web version. This compiles to JavaScript/WebAssembly and starts a local Jetty server:
./gradlew gdx_webgpu_tests_teavm_runThen open one of the following URLs in a WebGPU-capable browser:
| URL | Mode |
|---|---|
http://localhost:8080/index.html |
Interactive test chooser |
http://localhost:8080/index.html?test=Particles3D |
Run a single test by name |
http://localhost:8080/index.html?auto |
Run all tests sequentially |
Press Escape to return to the test chooser when running an individual test interactively.
Build and install exactly one native WebGPU implementation on a connected device or emulator:
# WGPU
./gradlew :tests:gdx-tests-android:installWgpuDebug
# Dawn
./gradlew :tests:gdx-tests-android:installDawnDebugThen launch via adb:
# Interactive test chooser (default):
adb shell am start -n com.monstrous.gdx.tests.webgpu/.GdxTestActivity
# Run a single test by class name:
adb shell am start -n com.monstrous.gdx.tests.webgpu/.GdxTestActivity --es test "Particles3D"
# Run ALL tests sequentially (auto mode):
adb shell am start -n com.monstrous.gdx.tests.webgpu/.GdxTestActivity --es test "auto"On mobile, tap the bottom-right corner hotspot to close a running test and return to the chooser.
Apart from the graphics platform, gdx-webgpu offers some new features with regard to LibGDX:
- support for 32-bit index values for a mesh allowing for larger meshes.
- automatic instancing of identical modelInstances so that they are rendered in a single draw call.
- built-in support for GLTF and GLB model format.
- debug feature to measure GPU time per render pass.
| gdx-webgpu | libgdx | gdx-teavm | jWebGPU |
|---|---|---|---|
| -SNAPSHOT | 1.14.2 | 1.6.1 | 0.3.4 |
| 0.8 | 1.14.0 | 1.5.0 | 0.1.13 |
| 0.7.2 | 1.14.0 | 1.4.0 | 0.1.11 |
| 0.7.1 | 1.14.0 | 1.4.0 | 0.1.9 |
| 0.7 | 1.14.0 | 1.4.0 | 0.1.9 |
| 0.6 | 1.13.5 | 1.3.0 | 0.1.6 |
There are a few configuration steps to use gdx-webgpu. This assumes you have created a project with gdx-liftoff.
If you are starting a new project, it is also a good idea to start with gdx-liftoff to set up a project structure.
The library is available via Maven Central. Make sure the following section is included under subprojects in build.gradle:
repositories {
maven { url = uri("https://central.sonatype.com/repository/maven-snapshots/") }
}
Define the version you want to use in the gradle.properties file, e.g.
gdxWebGPUVersion=0.8
You can refer to the latest stable release number, e.g. 0.8 or use -SNAPSHOT to follow the very latest developments.
(Beware when using a snapshot version, that functions may break without notice. Use a stable version by preference).
To include the library in your project add the following lines to your build.gradle file in the core module:
dependencies {
api "io.github.monstroussoftware.gdx-webgpu:gdx-webgpu:$gdxWebGPUVersion"
// comment out the following:
// api "com.badlogicgames.gdx:gdx:$gdxVersion"
}
Assuming we want to use the LWJGL3 (=Desktop) platform, choose one binding and native implementation in the lwjgl3 module:
dependencies {
// Choose JNI or FFM, then include one or both implementations:
implementation "io.github.monstroussoftware.gdx-webgpu:backend-desktop-jni-dawn:$gdxWebGPUVersion"
// implementation "io.github.monstroussoftware.gdx-webgpu:backend-desktop-jni-wgpu:$gdxWebGPUVersion" // optional second implementation
// implementation "io.github.monstroussoftware.gdx-webgpu:backend-desktop-ffm-dawn:$gdxWebGPUVersion"
// implementation "io.github.monstroussoftware.gdx-webgpu:backend-desktop-ffm-wgpu:$gdxWebGPUVersion" // optional second implementation
// comment out the following:
// implementation "com.badlogicgames.gdx:gdx-backend-lwjgl3:$gdxVersion"
// implementation "com.badlogicgames.gdx:gdx-lwjgl3-angle:$gdxVersion"
// implementation "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop"
}
These are wrapper artifacts: they pull in backend-desktop, the Java binding, and all supported
platform natives for the selected implementation. Users only need to set gdxWebGPUVersion and
do not need a direct jWebGPU dependency. To support both native implementations, declare the WGPU
and Dawn artifacts for the same Java binding. The unsuffixed backend-desktop-jni and
backend-desktop-ffm coordinates are not published.
For a platform-specific distribution, append _windows_x64, _linux_x64, _mac_x64, or
_mac_arm64 to the selected artifact ID. For example,
backend-desktop-ffm-dawn_mac_arm64 includes only the macOS arm64 Dawn native runtime.
For Android, choose exactly one native WebGPU implementation in the Android launcher module:
dependencies {
implementation "io.github.monstroussoftware.gdx-webgpu:backend-android-wgpu:$gdxWebGPUVersion"
// or:
// implementation "io.github.monstroussoftware.gdx-webgpu:backend-android-dawn:$gdxWebGPUVersion"
}Both artifacts contain the same gdx-webgpu Android backend. Each one pulls in the matching jWebGPU AAR and initializes WGPU or Dawn automatically; applications must not include both.
In the lwjgl3 module add a starter class called Launcher.java with a content as follows:
Launcher.java:
package com.monstrous.test.lwjgl3;
import com.monstrous.gdx.webgpu.backends.desktop.WgDesktopApplication;
import com.monstrous.gdx.webgpu.backends.desktop.WgDesktopApplicationConfiguration;
import com.monstrous.test.Main;
public class Launcher {
public static void main (String[] argv) {
WgDesktopApplicationConfiguration config = new WgDesktopApplicationConfiguration();
config.setWindowedMode(640, 480);
config.setTitle("WebGPU");
config.enableGPUtiming = false;
config.useVsync(true);
new WgDesktopApplication(new Main(), config);
}
}In the lwjgl3 module find the line in build.gradle which defines mainClassName and point it to the new starter class (delete the file Lwjgl3Launcher.java):
// old line:
//mainClassName = 'com.monstrous.test.lwjgl3.Lwjgl3Launcher'
// new line:
mainClassName = 'com.monstrous.test.lwjgl3.Launcher'
Make sure your application uses gdx-webgpu classes where necessary, e.g. WgSpriteBatch instead of SpriteBatch, WgTexture instead of Texture, WgScreenUtils instead of ScreenUtils, etcetera.
If you want to use the Web TeaVM platform, set the dependencies as follows in build.gradle of the teavm module:
dependencies {
implementation "com.github.xpenatan.gdx-teavm:backend-web:$gdxTeaVMVersion"
implementation "io.github.monstroussoftware.gdx-webgpu:backend-teavm:$gdxWebGPUVersion"
implementation "io.github.monstroussoftware.gdx-webgpu:backend-teavm:$gdxWebGPUVersion:sources"
// the following lines can be commented out as gdx-teavm will pull these in anyway:
// implementation "org.teavm:teavm-classlib:$teaVMVersion"
// implementation "org.teavm:teavm-core:$teaVMVersion"
// implementation "org.teavm:teavm-jso-apis:$teaVMVersion"
// implementation "org.teavm:teavm-jso-impl:$teaVMVersion"
// implementation "org.teavm:teavm-jso:$teaVMVersion"
// implementation "org.teavm:teavm-tooling:$teaVMVersion"
implementation project(':core')
}
Also here, you will need to modify the launcher class (to be described...).
Modify the last line which creates a TeaApplication to create a WgTeaApplication instead:
public static void main(String[] args) {
TeaApplicationConfiguration config = new TeaApplicationConfiguration("canvas");
//...
new WgTeaApplication(new Main(), config);
//new TeaApplication(new Main(), config);
}