Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
99 commits
Select commit Hold shift + click to select a range
2fa995a
Factor out a base 3D renderer
davepagurek May 23, 2025
3af1624
Get background() working
davepagurek May 23, 2025
b1eac69
Start to factor out buffers
davepagurek May 23, 2025
bdfaf35
Refactor more shader binding
davepagurek May 24, 2025
cb1b022
More shader refactoring
davepagurek May 24, 2025
6576ac5
Pack data into uniform buffer
davepagurek May 25, 2025
7895d19
Fix packing bugs
davepagurek May 25, 2025
83e7557
Fix color rendering bug
davepagurek May 25, 2025
e6c3256
Add shader hooks to WGSL color shader
davepagurek Jun 7, 2025
77a9733
added stroke shader, currently not working
lukeplowden Jun 14, 2025
ae2c566
Add material shader
davepagurek Jun 15, 2025
5db2d33
changed drawbuffers to draw stroke and fill buffers depending on curr…
lukeplowden Jun 16, 2025
a116e6f
fixed uViewport uniform (uniform problem fixed in upstream)
lukeplowden Jun 16, 2025
ddfeb05
remove console log
lukeplowden Jun 16, 2025
14f1857
remove unused variable
lukeplowden Jun 16, 2025
2c19cdc
remove hardcoded viewport (uniform issue fixed upstream)
lukeplowden Jun 16, 2025
e7696f0
fix stroke shader bugs from porting process)
lukeplowden Jun 16, 2025
ed88f91
stroke test
lukeplowden Jun 16, 2025
186f423
Merge remote-tracking branch 'upstream/webgpu' into webgpu
lukeplowden Jun 16, 2025
ce4b31e
Coerce modified hooks to boolean
davepagurek Jun 16, 2025
1e9b308
Merge remote-tracking branch 'upstream/webgpu' into webgpu
lukeplowden Jun 16, 2025
4dc493d
add stroke to preview
lukeplowden Jun 16, 2025
d88fba9
change stroke shader constants/ preprocessor to be compatible with we…
lukeplowden Jun 16, 2025
c48977a
rename fillHooks to populateHooks (ambiguous with fill/stroke)
lukeplowden Jun 16, 2025
f0875d7
add strokes back to WebGL mode
lukeplowden Jun 16, 2025
e8bedfc
add strokes back to WebGL mode
lukeplowden Jun 16, 2025
0b50257
missing }
lukeplowden Jun 16, 2025
0af8df9
typo in string
lukeplowden Jun 16, 2025
f120ad9
typo in string
lukeplowden Jun 16, 2025
1474c97
Merge branch 'webgpu' of github.com:lukeplowden/p5.js into webgpu
lukeplowden Jun 16, 2025
468b638
multiply alpha after hook
lukeplowden Jun 16, 2025
a454ffe
Merge pull request #7915 from lukeplowden/webgpu
davepagurek Jun 16, 2025
01a7c1c
Fix some RendererGL + filterRenderer2D tests
davepagurek Jun 17, 2025
aef17d5
Fix the rest of the tests!
davepagurek Jun 17, 2025
abc4074
Get textures working
davepagurek Jun 25, 2025
397c1d8
Add visual tests
davepagurek Jun 26, 2025
e7c1d6b
Fix usage of textures in setup
davepagurek Jun 26, 2025
b65080f
Merge branch 'dev-2.0' into webgpu
davepagurek Jul 27, 2025
ca5f9c6
Refactor framebuffers
davepagurek Jul 28, 2025
f94f898
Fix ordering of dirty flag
davepagurek Jul 28, 2025
5dfcd24
Make sure textures are cleared at start
davepagurek Jul 28, 2025
4fd6c19
Add fixes for other gl-specific cases
davepagurek Jul 28, 2025
edce029
Fix canvas readback
davepagurek Jul 29, 2025
9fc319f
Start adding tests
davepagurek Jul 29, 2025
76c0108
Add another test
davepagurek Jul 29, 2025
a3daa14
Fix main canvas not being drawable after resizing
davepagurek Jul 29, 2025
01110c9
Add screenshots
davepagurek Jul 29, 2025
da86527
Try setting different launch options
davepagurek Jul 29, 2025
02eef85
Test different options
davepagurek Jul 29, 2025
3c6c195
Try sequential
davepagurek Jul 29, 2025
e450957
Attempt to install later chrome
davepagurek Jul 29, 2025
f44629b
Add some debug info
davepagurek Jul 29, 2025
b281d33
Try different flags
davepagurek Jul 29, 2025
7773341
Does it work in xvfb?
davepagurek Jul 29, 2025
cfeac93
Try enabling swiftshader
davepagurek Aug 1, 2025
af5194a
less flags
davepagurek Aug 1, 2025
88b4fe4
Try disabling dawn
davepagurek Aug 1, 2025
ff83226
Try installing swiftshader?
davepagurek Aug 1, 2025
4314cf2
Just vulkan
davepagurek Aug 1, 2025
c01dee7
Try with xvfb
davepagurek Aug 1, 2025
7b3ed67
Test ci flow with warp.
tychedelia Aug 6, 2025
22f5294
Fixes for CI.
tychedelia Aug 7, 2025
a8dea15
Revert change.
tychedelia Aug 7, 2025
9c49827
Add setAttributes api to WebGPU renderer.
tychedelia Aug 8, 2025
695e9e6
Try ignore-blocklist flag
davepagurek Sep 14, 2025
48ce320
Go back to ubuntu for now, try different swiftshader flags
davepagurek Sep 14, 2025
4753544
Different flag
davepagurek Sep 14, 2025
9eb541d
Check if the adapter is defined
davepagurek Sep 14, 2025
74c1672
Try without setAttributes since the adapter seems to exist before that
davepagurek Sep 14, 2025
498bb83
Try installing chrome with swiftshader
davepagurek Sep 14, 2025
bc3501a
Revert "Try installing chrome with swiftshader"
davepagurek Sep 14, 2025
88dec1b
Try chrome on windows
davepagurek Sep 14, 2025
d5f584f
Don't run webgpu tests on CI for now
davepagurek Sep 14, 2025
3ea32ed
Exclude other webgpu tests
davepagurek Sep 14, 2025
724b41a
Move setAttributes implementation to renderer
davepagurek Sep 14, 2025
117ab93
Merge pull request #8008 from processing/webgpu-fbo
davepagurek Sep 14, 2025
d010b45
Merge branch 'dev-2.0' into webgpu
davepagurek Oct 21, 2025
abe3cd8
Merge branch 'dev-2.0' into webgpu
davepagurek Nov 16, 2025
254d1a6
Add whole-module addon for webgpu, prevent duplicate addon registers
davepagurek Nov 16, 2025
cb221da
Add webgpu to package.json
davepagurek Nov 16, 2025
ef28cbc
Get font rendering working on WebGPU
davepagurek Nov 16, 2025
39fb383
Read backend off of renderer
davepagurek Nov 22, 2025
7c592e2
First pass of WebGPU backend
davepagurek Nov 22, 2025
56c0bef
Refactor hook type system to be backend-agnostic
davepagurek Nov 22, 2025
9ec22e7
Fix some issues with async, braceless ifs, and incorrect type objects
davepagurek Nov 22, 2025
9eee9aa
Fix issues with swizzle assignment and updating uniforms
davepagurek Nov 22, 2025
d8e08a4
Fix more webgpu tests
davepagurek Nov 22, 2025
66fe4c0
Get webgpu strands tests working
davepagurek Nov 23, 2025
7bcfa76
end to end preview sketch
davepagurek Nov 23, 2025
fee47a0
Start using buffer pooling
davepagurek Nov 23, 2025
5d3874c
Use pools to push everything into one onSubmit
davepagurek Nov 23, 2025
745d029
Make sure framebuffers submit separately
davepagurek Nov 23, 2025
80ea758
Fix some bugs
davepagurek Nov 23, 2025
bf769e1
Use a main framebuffer instead of other hacks to get pixels
davepagurek Nov 23, 2025
5aedaa6
Clean up code
davepagurek Nov 24, 2025
263ed1d
Update regex
davepagurek Nov 24, 2025
287b5bb
Merge branch 'dev-2.0' into webgpu
davepagurek Nov 24, 2025
0a97a35
one more regex fix
davepagurek Nov 24, 2025
a51a15e
ok we arent escaping regex braces
davepagurek Nov 24, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 28 additions & 5 deletions .github/workflows/ci-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,48 +11,71 @@

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
include:
- os: ubuntu-latest
browser: chrome
# - os: windows-latest
# browser: chrome

runs-on: ${{ matrix.os }}

steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v4

- name: Use Node.js 20.x
uses: actions/setup-node@v1
uses: actions/setup-node@v4
with:
node-version: 20.x

- name: Verify Chrome (Ubuntu)
if: matrix.os == 'ubuntu-latest' && matrix.browser == 'chrome'
run: |
google-chrome --version

- name: Verify Chrome (Windows)
if: matrix.os == 'windows-latest' && matrix.browser == 'chrome'
run: |
& "C:\Program Files\Google\Chrome\Application\chrome.exe" --version

- name: Get node modules
run: npm ci
env:
CI: true
- name: build and test

- name: Build and test (Ubuntu)
id: test
run: npm test
if: matrix.os == 'ubuntu-latest'
run: npm test -- --project=unit-tests
continue-on-error: true
env:
CI: true

- name: Generate Visual Test Report
if: always()
run: node visual-report.js
env:
CI: true
- name: Upload Visual Test Report
if: always()
uses: actions/upload-artifact@v4
with:
name: visual-test-report
path: test/unit/visual/visual-report.html
retention-days: 14
- name: generate TypeScript types
run: npm run generate-types
env:
CI: true
- name: test TypeScript types
run: npm run test:types
env:
CI: true
- name: report test coverage
if: steps.test.outcome == 'success'
run: bash <(curl -s https://codecov.io/bash) -f coverage/coverage-final.json
env:
CI: true
- name: fail job if tests failed
if: steps.test.outcome != 'success'
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
"./math": "./dist/math/index.js",
"./utilities": "./dist/utilities/index.js",
"./webgl": "./dist/webgl/index.js",
"./webgpu": "./dist/webgpu/index.js",
"./type": "./dist/type/index.js"
},
"files": [
Expand Down
146 changes: 133 additions & 13 deletions preview/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,148 @@
<body>
<script type="module">
import p5 from '../src/app.js';
import rendererWebGPU from '../src/webgpu/p5.RendererWebGPU.js';

p5.registerAddon(rendererWebGPU);

const sketch = function (p) {
let fbo;
let sh;
let ssh;
let tex;
let font;

p.setup = async function () {
p.createCanvas(400, 400, p.WEBGL);
fbo = p.createFramebuffer()
await p.createCanvas(400, 400, p.WEBGPU);
font = await p.loadFont(
'font/PlayfairDisplay.ttf'
);
fbo = p.createFramebuffer();

tex = p.createImage(100, 100);
tex.loadPixels();
for (let x = 0; x < tex.width; x++) {
for (let y = 0; y < tex.height; y++) {
const off = (x + y * tex.width) * 4;
tex.pixels[off] = p.round((x / tex.width) * 255);
tex.pixels[off + 1] = p.round((y / tex.height) * 255);
tex.pixels[off + 2] = 0;
tex.pixels[off + 3] = 255;
}
}
tex.updatePixels();
fbo.draw(() => {
//p.clear();
//p.background('orange');
p.imageMode(p.CENTER);
p.image(tex, 0, 0, p.width, p.height);
});

/*sh = p.baseMaterialShader().modify({
uniforms: {
'f32 time': () => p.millis(),
},
'Vertex getWorldInputs': `(inputs: Vertex) {
var result = inputs;
result.position.y += 40.0 * sin(uniforms.time * 0.005);
return result;
}`,
})*/
sh = p.baseMaterialShader().modify(() => {
const time = p.uniformFloat(() => p.millis());
p.getWorldInputs((inputs) => {
inputs.position.y += 40 * p.sin(time * 0.005);
return inputs;
});
}, { p })
/*ssh = p.baseStrokeShader().modify({
uniforms: {
'f32 time': () => p.millis(),
},
'StrokeVertex getWorldInputs': `(inputs: StrokeVertex) {
var result = inputs;
result.position.y += 40.0 * sin(uniforms.time * 0.005);
return result;
}`,
})*/
};

p.draw = function () {
p.clear();
/*p.orbitControl();
p.push();
p.background(200);
fbo.begin()
p.background('blue')
p.strokeWeight(10);
p.textAlign(p.CENTER, p.CENTER);
p.textFont(font);
p.textSize(85)
p.fill('red')
p.noStroke()
p.rect(0, 0, 100, 100);
p.fill(0);
p.push()
p.stroke('red')
p.line(-100, -100, 100, 100);
p.rotate(p.millis() * 0.001)
p.text('Hello!', 0, 0);
p.pop()
p.translate(200, 200)
p.line(-100, -100, 100, 100);
fbo.end()
p.image(fbo, 0, 0)
p.pop();
return;*/
p.orbitControl();
const t = p.millis() * 0.002;
p.background(200);
p.shader(sh);
// p.strokeShader(ssh)
p.ambientLight(150);
p.directionalLight(100, 100, 100, 0, 1, -1);
p.pointLight(155, 155, 155, 0, -200, 500);
p.specularMaterial(255);
p.shininess(300);
//p.stroke('white');
p.noStroke();
for (const [i, c] of ['red', 'lime', 'blue'].entries()) {
p.push();
p.fill(c);
p.translate(
p.width/3 * p.sin(t + i * Math.E),
0, //p.width/3 * p.sin(t * 0.9 + i * Math.E + 0.2),
p.width/3 * p.sin(t * 1.2 + i * Math.E + 0.3),
)
if (i % 2 === 0) {
if (i === 0) {
p.texture(fbo)
}
p.box(30);
} else {
p.sphere(30);
}
p.pop();
}

// Test beginShape/endShape with immediate mode shapes
p.push();
p.translate(0, 100, 0);
p.fill('yellow');
p.noStroke();

// Draw a circle using beginShape/endShape
p.beginShape();
const numPoints = 16;
for (let i = 0; i < numPoints; i++) {
const angle = (i / numPoints) * Math.PI * 2;
const x = Math.cos(angle) * 50;
const y = Math.sin(angle) * 50;
p.vertex(x, y);
}
p.endShape(p.CLOSE);

p.translate(100, 0, 0);
p.fill('purple');

// Draw a square using beginShape/endShape
p.beginShape();
p.vertex(-30, -30);
p.vertex(30, -30);
p.vertex(30, 30);
p.vertex(-30, 30);
p.endShape(p.CLOSE);

p.pop();
};
};
Expand All @@ -48,4 +168,4 @@
</script>
</body>

</html>
</html>
2 changes: 1 addition & 1 deletion src/accessibility/gridOutput.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ function gridOutput(p5, fn){

//updates gridOutput
fn._updateGridOutput = function(idT) {
if (this._renderer && this._renderer instanceof p5.RendererGL) {
if (this._renderer && this._renderer.isP3D) {
if (!this._didOutputGridWebGLMessage) {
this._didOutputGridWebGLMessage = true;
console.error('gridOutput() does not yet work in WebGL mode.');
Expand Down
2 changes: 1 addition & 1 deletion src/accessibility/textOutput.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ function textOutput(p5, fn){

//updates textOutput
fn._updateTextOutput = function(idT) {
if (this._renderer && this._renderer instanceof p5.RendererGL) {
if (this._renderer && this._renderer.isP3D) {
if (!this._didOutputTextWebGLMessage) {
this._didOutputTextWebGLMessage = true;
console.error('textOutput() does not yet work in WebGL mode.');
Expand Down
7 changes: 7 additions & 0 deletions src/core/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ export const WEBGL = 'webgl';
*/
export const WEBGL2 = 'webgl2';

/**
* A constant used for creating a WebGPU rendering context
* @property {'webgpu'} WEBGPU
* @final
*/
export const WEBGPU = 'webgpu';

// ENVIRONMENT
/**
* @typedef {'default'} ARROW
Expand Down
8 changes: 8 additions & 0 deletions src/core/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ class p5 {
this._curElement = null;
this._elements = [];
this._glAttributes = null;
this._webgpuAttributes = null;
this._requestAnimId = 0;
this._isGlobal = false;
this._loop = true;
Expand Down Expand Up @@ -171,9 +172,16 @@ class p5 {
return this._renderer.drawingContext;
}

static _registeredAddons = new Set();
static registerAddon(addon) {
const lifecycles = {};

// Don't re-register an addon. This allows addons
// to register dependency addons without worrying about
// them getting double-added.
if (p5._registeredAddons.has(addon)) return;
p5._registeredAddons.add(addon);

addon(p5, p5.prototype, lifecycles);

const validLifecycles = Object.keys(p5.lifecycleHooks);
Expand Down
5 changes: 5 additions & 0 deletions src/core/p5.Renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,11 @@ class Renderer {
return this;
}

finishDraw() {
// Default no-op implementation
// Override in specific renderers as needed
}

};

function renderer(p5, fn){
Expand Down
Loading
Loading