Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
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
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
41 changes: 35 additions & 6 deletions .github/workflows/ci-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,52 @@ on:

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
run: npm test

#- name: Build and test (Ubuntu)
# if: matrix.os == 'windows-latest'
# run: npm test -- --project=unit-tests-webgpu
# env:
# CI: true

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

- name: Report test coverage
run: bash <(curl -s https://codecov.io/bash) -f coverage/coverage-final.json
env:
CI: true
7 changes: 6 additions & 1 deletion preview/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

p.setup = async function () {
await p.createCanvas(400, 400, p.WEBGPU);
fbo = p.createFramebuffer();

tex = p.createImage(100, 100);
tex.loadPixels();
Expand All @@ -43,6 +44,10 @@
}
}
tex.updatePixels();
fbo.draw(() => {
p.imageMode(p.CENTER);
p.image(tex, 0, 0, p.width, p.height);
});

sh = p.baseMaterialShader().modify({
uniforms: {
Expand Down Expand Up @@ -87,7 +92,7 @@
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),
)
p.texture(tex)
p.texture(fbo)
p.sphere(30);
p.pop();
}
Expand Down
5 changes: 3 additions & 2 deletions src/core/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,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 @@ -468,11 +469,11 @@ for (const k in constants) {
* If `setup()` is declared `async` (e.g. `async function setup()`),
* execution pauses at each `await` until its promise resolves.
* For example, `font = await loadFont(...)` waits for the font asset
* to load because `loadFont()` function returns a promise, and the await
* to load because `loadFont()` function returns a promise, and the await
* keyword means the program will wait for the promise to resolve.
* This ensures that all assets are fully loaded before the sketch continues.

*
*
* loading assets.
*
* Note: `setup()` doesn’t have to be declared, but it’s common practice to do so.
Expand Down
75 changes: 75 additions & 0 deletions src/core/p5.Renderer3D.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as constants from "../core/constants";
import { Graphics } from "../core/p5.Graphics";
import { Renderer } from './p5.Renderer';
import GeometryBuilder from "../webgl/GeometryBuilder";
import { Matrix } from "../math/p5.Matrix";
Expand Down Expand Up @@ -350,6 +351,80 @@ export class Renderer3D extends Renderer {
};
}

//This is helper function to reset the context anytime the attributes
//are changed with setAttributes()

async _resetContext(options, callback, ctor = Renderer3D) {
const w = this.width;
const h = this.height;
const defaultId = this.canvas.id;
const isPGraphics = this._pInst instanceof Graphics;

// Preserve existing position and styles before recreation
const prevStyle = {
position: this.canvas.style.position,
top: this.canvas.style.top,
left: this.canvas.style.left,
};

if (isPGraphics) {
// Handle PGraphics: remove and recreate the canvas
const pg = this._pInst;
pg.canvas.parentNode.removeChild(pg.canvas);
pg.canvas = document.createElement("canvas");
const node = pg._pInst._userNode || document.body;
node.appendChild(pg.canvas);
Element.call(pg, pg.canvas, pg._pInst);
// Restore previous width and height
pg.width = w;
pg.height = h;
} else {
// Handle main canvas: remove and recreate it
let c = this.canvas;
if (c) {
c.parentNode.removeChild(c);
}
c = document.createElement("canvas");
c.id = defaultId;
// Attach the new canvas to the correct parent node
if (this._pInst._userNode) {
this._pInst._userNode.appendChild(c);
} else {
document.body.appendChild(c);
}
this._pInst.canvas = c;
this.canvas = c;

// Restore the saved position
this.canvas.style.position = prevStyle.position;
this.canvas.style.top = prevStyle.top;
this.canvas.style.left = prevStyle.left;
}

const renderer = new ctor(
this._pInst,
w,
h,
!isPGraphics,
this._pInst.canvas
);
this._pInst._renderer = renderer;

renderer._applyDefaults();

if (renderer.contextReady) {
await renderer.contextReady
}

if (typeof callback === "function") {
//setTimeout with 0 forces the task to the back of the queue, this ensures that
//we finish switching out the renderer
setTimeout(() => {
callback.apply(window._renderer, options);
}, 0);
}
}

remove() {
this.wrappedElt.remove();
this.wrappedElt = null;
Expand Down
2 changes: 1 addition & 1 deletion src/image/pixels.js
Original file line number Diff line number Diff line change
Expand Up @@ -933,7 +933,7 @@ function pixels(p5, fn){
*/
fn.loadPixels = function(...args) {
// p5._validateParameters('loadPixels', args);
this._renderer.loadPixels();
return this._renderer.loadPixels();
};

/**
Expand Down
2 changes: 1 addition & 1 deletion src/webgl/3d_primitives.js
Original file line number Diff line number Diff line change
Expand Up @@ -1869,7 +1869,7 @@ function primitives3D(p5, fn){
if (typeof args[4] === 'undefined') {
// Use the retained mode for drawing rectangle,
// if args for rounding rectangle is not provided by user.
const perPixelLighting = this._pInst._glAttributes.perPixelLighting;
const perPixelLighting = this._pInst._glAttributes?.perPixelLighting;
const detailX = args[4] || (perPixelLighting ? 1 : 24);
const detailY = args[5] || (perPixelLighting ? 1 : 16);
const gid = `rect|${detailX}|${detailY}`;
Expand Down
Loading
Loading