Kgpu

A Cross Platform Graphics API For Kotlin JVM/JS

Warning: Because WebGPU is under active development, kgpu is very unstable! Once the specification is more finalized, this will not be an issue.

Requirements:

  • JDK 11

Supported Platforms:

  • Windows 10
  • MacOS (See Issue #1)
  • Linux
  • Chrome Canary
  • Firefox Nightly

Links

Documentation

Live Example

Modules

kgpu is split into multiple modules:

  • kgpu: The core of this library (Kotlin bindings to WebGPU)
  • kcgmath: A cross platform graphics library for Kotlin based on the Rust crate cgmath
  • kshader: A library to help compile GLSL to SPIR-V

Images

Earth Example

Examples

To run the examples on Desktop:

gradlew runTriangleExample
gradlew runCubeExample
gradlew runTextureExample
gradlew runEarthExample

To run the examples on the Web:

gradlew buildWeb startWebServer

Then navigate to http://localhost:8080/index.html

How to add to Gradle (Kotlin DSL)

First you need to add the snapshots repository:

repositories {
    maven(url = "https://oss.sonatype.org/content/repositories/snapshots/")
}

Then you can add the dependency:

dependencies {
    //Add it to a kotlin multiplatform project
    implementation("io.github.kgpu:kgpu:0.1.0-SNAPSHOT")

    //Or you can add a specific platform
    implementation("io.github.kgpu:kgpu-common:0.1.0-SNAPSHOT")
    implementation("io.github.kgpu:kgpu-js:0.1.0-SNAPSHOT")
    implementation("io.github.kgpu:kgpu-jvm:0.1.0-SNAPSHOT")
}

Introduction

Kgpu is cross platform library that exposes the WebGPU api for Kotlin Javascript, and for Kotlin on the JVM. This allows users to write code that can be run on both web browsers and natively on their computers.

What is WebGPU

According to the W3C website, WebGPU is,

an interface between the Web Platform and modern 3D graphics and computation capabilities present in native system platforms. The goal is to design a new Web API that exposes these modern technologies in a performant, powerful and safe manner. It should work with existing platform APIs such as Direct3D 12 from Microsoft, Metal from Apple, and Vulkan from the Khronos Group. This API will also expose the generic computational facilities available in today's GPUs to the Web, and investigate shader languages to produce a cross-platform solution.

What is Wgpu

Wgpu is Mozilla's Rust implementation of the WebGPU specification. It is similar to Dawn, Google's WebGPU implementation for Chromium

Modules

kgpu

The core of kgpu. It provides the following APIs:

  • WebGPU Bindings

    • JVM/Desktop: Native Bindings to wgpu
    • JS/Web: Javascript Bindings
  • Window API

    • JVM/Desktop: GLFW Bindings via LWJGL
    • JS/Web: Canvas API via Web Browser
  • Image Loading API:

    • JVM/Desktop: AWT Image Loading
    • JS/Web: Off-screen Canvas Image Loading

kcgmath

Kotlin Computer Graphics Math Library

A cross platform graphics library for Kotlin based on the Rust crate cgmath

Note: This library is meant to be used as a basic computer graphics library for WebGPU. If you are using OpenGL or want something more complex, you may want to consider one of the following:

  • JOML: JVM Only, More Complex, Faster
  • Korma: Built for OpenGL

kshader

A library to help compile GLSL to SPIR-V

On the JVM/Desktop it uses Shaderc via LWJGL.

For JS/Web it uses the glslang library.

Getting Started

To start a new project, you can use the kgpu-template repository. It allows you to get a basic project setup by only needing to change a few files.

Cloning the project

Using Github

  1. Navigate to the kgpu-template repository
  2. Click the Use This Template Button

For more info, see Creating a repository from a template

No Github Account

  1. Navigate to the kgpu-template repository
  2. Click the Clone or Download (or Code) dropdown
  3. Select the Download Zip option

Editing the project settings

Once you have the project copied, then you can open it in any text editor, and then open the gradle.properties file.

You can edit the file to change the name of the project, the project's group, and the version of KGPU to use.

Here is an example properties file:

kotlin.code.style=official
kgpuVersion=0.1.0-SNAPSHOT
projectName=ProjectName
projectGroup=your.group.here
projectVersion=0.1.0
desktopMainClass=DesktopKt

Editing Website

The last part of setup is setting up the index.html page to use.

Open the src/jsMain/resources/index.html file

Then change the ProjectName in the script source, to the name you set in the gradle.properties file.

<script>
     if (!navigator.gpu) {
        document.body.className = 'error';
        document.getElementById('content').hidden = true
        document.getElementById('errorMessage').hidden = false
    }
</script>
<script src="ProjectName.js"></script> <!-- Change this line! -->

Start Coding

You can now start working on your project! There are three kotlin files in the template: Application, Desktop, and Browser

src/commonMain/kotlin/Application.kt: This is the code that is shared between all of the platforms.

src/jsMain/kotlin/Browser.kt: This is the code that will be compiled into javascript for the browser

src/jvmMain/kotlin/Desktop.kt: This is the code that will be compiled into java classes and executed on the Desktop via the JVM.

Running the application

To run on the desktop:

gradlew runJvm

To build the examples for the Web:

gradlew jsBrowserDistribution

And you can start a static file server for the web:

gradlew startWebServer

And then navigate to http://localhost:8080/index.html

Coordinates

In kgpu, both textures and screen coordinates start in the top left:

Coordinates

Internal Structure

This page documents the non-library projects in the kgpu repo. These libraries should not be used directly and do not have stable APIs. If you want to see info about the different public modules kgpu provides, see this page

examples

This contains the example code for Kgpu. Like the core library, it is split into three parts: common, js, and jvm. The js and jvm modules are responible for setting up the basic application, and selecting which example to run.

The common folder contains all of the core code examples, and the resources used (images, shaders)

wgpuj

This module is written in Java and has the FFI code between the JVM and wgpu. It uses the jnr-ffi library, which creates JNI bindings at runtime. Most of the code in this module is generated by jnr-gen

wgpuj/jnrgen

jnr-gen is a tool that generates jnr enum and struct classes from the wgpu.h header. For more info see this page all about jnr-gen.

JNR Gen

JNR Gen is a program to generate Java enums, structs, and constants from a c header file. To run JNR Gen and update the java files, run the following command:

gradlew wgpuj:updateBindings

Example Enum

package io.github.kgpu.wgpuj.jni;


/** NOTE: THIS FILE WAS PRE-GENERATED BY JNR_GEN! */
public enum WgpuBindingType {
    UNIFORM_BUFFER,
    STORAGE_BUFFER,
    READONLY_STORAGE_BUFFER,
    SAMPLER,
    COMPARISON_SAMPLER,
    SAMPLED_TEXTURE,
    READONLY_STORAGE_TEXTURE,
    WRITEONLY_STORAGE_TEXTURE,
}

Example Struct

package io.github.kgpu.wgpuj.jni;

import io.github.kgpu.wgpuj.WgpuJava;
import io.github.kgpu.wgpuj.util.WgpuJavaStruct;
import io.github.kgpu.wgpuj.util.CStrPointer;
import io.github.kgpu.wgpuj.util.RustCString;
import jnr.ffi.Runtime;
import jnr.ffi.Struct;

/** NOTE: THIS FILE WAS PRE-GENERATED BY JNR_GEN! */
public class WgpuBindGroupDescriptor extends WgpuJavaStruct {

    private final @CStrPointer Struct.Pointer label = new Struct.Pointer();
    private final DynamicStructRef<WgpuBindGroupEntry> entries = new DynamicStructRef<>(WgpuBindGroupEntry.class);

    protected WgpuBindGroupDescriptor(boolean direct){
         if(direct){
             useDirectMemory();
        }
    }

    @Deprecated
    public WgpuBindGroupDescriptor(Runtime runtime){
        super(runtime);
    }

    public static WgpuBindGroupDescriptor createHeap(){
        return new WgpuBindGroupDescriptor(false);
    }

    public static WgpuBindGroupDescriptor createDirect(){
        return new WgpuBindGroupDescriptor(true);
    }

    public java.lang.String getLabel(){
        return RustCString.fromPointer(label.get());
    }

    public void setLabel(java.lang.String x){
        this.label.set(RustCString.toPointer(x));
    }

    public DynamicStructRef<WgpuBindGroupEntry> getEntries(){
        return entries;
    }

    public void setEntries(WgpuBindGroupEntry... x){
        if(x.length == 0 || x[0] == null){
            this.entries.set(WgpuJava.createNullPointer());
        } else {
            this.entries.set(x);
        }
    }

}

Example Constants

package io.github.kgpu.wgpuj.jni;


/** NOTE: THIS FILE WAS PRE-GENERATED BY JNR_GEN! */
public final class Wgpu{

    public static final int BIND_BUFFER_ALIGNMENT = 256;
    public static final int COPY_BYTES_PER_ROW_ALIGNMENT = 256;
    public static final int DEFAULT_BIND_GROUPS = 4;
    public static final int DESIRED_NUM_FRAMES = 3;
    public static final int MAX_ANISOTROPY = 16;
    public static final int MAX_COLOR_TARGETS = 4;
    public static final int MAX_MIP_LEVELS = 16;
    public static final int MAX_VERTEX_BUFFERS = 16;

    public static final class ShaderStage{
        public static final int NONE = 0;
        public static final int VERTEX = 1;
        public static final int FRAGMENT = 2;
        public static final int COMPUTE = 4;
    }

}

Additional Resources

Documentation

Tutorials / Examples

Learn Wgpu

Wgpu-rs Examples

WebGPU Examples

WebGPU

WebGPU Specification

WebGPU Github Page

Wgpu

Wgpu-native Github Repo

Wgpu Github Repo

jnr-ffi Github Repo

jnr-ffi Javadoc

LWJGL Github Repo

LWJGL Javadoc

LWJGL Website