Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integer uniforms get uploaded to the GPU as Floats #29952

Closed
holtsetio opened this issue Nov 23, 2024 · 0 comments · Fixed by #29976
Closed

Integer uniforms get uploaded to the GPU as Floats #29952

holtsetio opened this issue Nov 23, 2024 · 0 comments · Fixed by #29976
Labels
Milestone

Comments

@holtsetio
Copy link
Contributor

holtsetio commented Nov 23, 2024

Description

When creating Uniform Nodes for WebGPU, the default uniform type in the shader is float. If you want to use integer values in the shader, fp32 is capable of every integer value up to 2^24=16777216, after which fp32 precision breaks down. For better precision, you can set the nodetype of the uniform nodes to create, for example, uniforms of type uint. However, when setting the value of the integer uniform node, the value still gets uploaded to the GPU as a float, but is interpreted by the shader as an uint, which causes nonsense values. Right now you can only use integer uniforms with a little hack to interpret the value as float before uploading to the GPU (see attached jsfiddle)

Reproduction steps

  1. Create a uniform with type uint: uniform(value, "uint")
  2. Use a compute shader to write the value to an output buffer of type uint
  3. Read the output and compare

Code

import * as THREE from 'three';
import { Fn, uniform, storage } from 'three/tsl';

const renderer = new THREE.WebGPURenderer();
const outputNode = document.createElement("div");
document.body.appendChild(outputNode);

const int2float_hack = (x) => {
    return new Float32Array(new Uint32Array([x]).buffer)[0];
};

const run = async () => {
  const buffer = new THREE.StorageBufferAttribute(new Uint32Array(3), 1, Uint32Array);
  const outputStorage = storage(buffer, "uint", 3);
  
  const value = 16777217;
  const u0 = uniform(value);
  const u1 = uniform(value, "uint");
  const u2 = uniform(int2float_hack(value), "uint");

  const kernel = Fn(()=>{
    outputStorage.element(0).assign(u0);
    outputStorage.element(1).assign(u1);
    outputStorage.element(2).assign(u2);
  })().compute(3);

  await renderer.computeAsync(kernel);

  const result = new Uint32Array(await renderer.getArrayBufferAsync(buffer));
  
  outputNode.innerText += "input value: " + value + "\n\n";
  outputNode.innerText += "Element 0 (float uniform): " + result[0] + "\n";
  outputNode.innerText += "Element 1 (uint uniform): " + result[1] + "\n";
  outputNode.innerText += "Element 2 (uint uniform with hack): " + result[2] + "\n";
}
run();

Live example

jsfiddle

Screenshots

threejsbug

Version

r171-dev

Device

No response

Browser

No response

OS

No response

@sunag sunag added the WebGPU label Nov 25, 2024
holtsetio added a commit to holtsetio/three.js that referenced this issue Nov 26, 2024
@sunag sunag added this to the r171 milestone Nov 26, 2024
sunag pushed a commit that referenced this issue Nov 26, 2024
* WebGPU: Fix integer uniforms (#29952)

* Update WebGPU Compute Attractors Particles Demo to use uint uniform for number of attractors
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants