Skip to content

Commit 6dce90f

Browse files
authored
Merge pull request #8731 from processing/fix/webgpu
Minor WebGL->WebGPU fixes
2 parents 347c10d + 6195a95 commit 6dce90f

14 files changed

Lines changed: 399 additions & 286 deletions

File tree

docs/parameterData.json

Lines changed: 253 additions & 247 deletions
Large diffs are not rendered by default.

src/core/rendering.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,12 @@ function rendering(p5, fn){
4545
* system variable to check what version is being used, or call
4646
* `setAttributes({ version: 1 })` to create a WebGL1 context.
4747
*
48+
* Note: In WebGPU mode, you must `await` this function.
49+
*
4850
* @method createCanvas
4951
* @param {Number} [width] width of the canvas. Defaults to 100.
5052
* @param {Number} [height] height of the canvas. Defaults to 100.
51-
* @param {(P2D|WEBGL|P2DHDR|WEBGPU)} [renderer] either P2D, WEBGL, or WEBGPU. Defaults to `P2D`.
53+
* @param {(P2D|WEBGL|P2DHDR)} [renderer] either P2D or WEBGL. Defaults to `P2D`.
5254
* @param {HTMLCanvasElement} [canvas] existing canvas element that should be used for the sketch.
5355
* @return {p5.Renderer} new `p5.Renderer` that holds the canvas.
5456
*
@@ -106,6 +108,14 @@ function rendering(p5, fn){
106108
* describe('A diagonal line drawn from top-left to bottom-right on a gray background.');
107109
* }
108110
*/
111+
/**
112+
* @method createCanvas
113+
* @param {Number} width
114+
* @param {Number} height
115+
* @param {WEBGPU} renderer
116+
* @param {HTMLCanvasElement} [canvas]
117+
* @return {Promise<p5.Renderer>}
118+
*/
109119
/**
110120
* @method createCanvas
111121
* @param {Number} [width]

src/shape/attributes.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,10 @@ function attributes(p5, fn){
107107
* In WebGL mode, `noSmooth()` causes all shapes to be drawn with jagged
108108
* (aliased) edges. The functions don't affect images or fonts.
109109
*
110+
* Note: In WebGPU mode, you must `await` this function.
111+
*
110112
* @method noSmooth
111-
* @chainable
113+
* @return {void|Promise<void>}
112114
*
113115
* @example
114116
* let heart;
@@ -162,10 +164,10 @@ function attributes(p5, fn){
162164
if ('imageSmoothingEnabled' in this.drawingContext) {
163165
this.drawingContext.imageSmoothingEnabled = false;
164166
}
167+
return this;
165168
} else {
166-
this.setAttributes('antialias', false);
169+
return this.setAttributes('antialias', false);
167170
}
168-
return this;
169171
};
170172

171173
/**

src/webgpu/p5.RendererWebGPU.js

Lines changed: 25 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ function rendererWebGPU(p5, fn) {
319319
}
320320
if (this._pInst._webgpuAttributes[key] !== value) {
321321
//changing value of previously altered attribute
322-
this._webgpuAttributes[key] = value;
322+
this._pInst._webgpuAttributes[key] = value;
323323
unchanged = false;
324324
}
325325
//setting all attributes with some change
@@ -682,9 +682,9 @@ function rendererWebGPU(p5, fn) {
682682
1; // No MSAA needed when blitting already-antialiased textures to canvas
683683
const sampleCount = this._getValidSampleCount(requestedSampleCount);
684684

685-
const depthFormat = activeFramebuffer && activeFramebuffer.useDepth ?
686-
this._getWebGPUDepthFormat(activeFramebuffer) :
687-
this.depthFormat;
685+
const depthFormat = activeFramebuffer
686+
? (activeFramebuffer.useDepth ? this._getWebGPUDepthFormat(activeFramebuffer) : undefined)
687+
: this.depthFormat;
688688

689689
const drawTarget = this.drawTarget();
690690
const clipping = this._clipping;
@@ -761,25 +761,27 @@ function rendererWebGPU(p5, fn) {
761761
},
762762
primitive: { topology },
763763
multisample: { count: sampleCount },
764-
depthStencil: {
765-
format: depthFormat,
766-
depthWriteEnabled: !clipping,
767-
depthCompare: 'less-equal',
768-
stencilFront: {
769-
compare: clipping ? 'always' : (clipApplied ? 'not-equal' : 'always'),
770-
failOp: 'keep',
771-
depthFailOp: 'keep',
772-
passOp: clipping ? 'replace' : 'keep',
764+
...(depthFormat ? {
765+
depthStencil: {
766+
format: depthFormat,
767+
depthWriteEnabled: !clipping,
768+
depthCompare: 'less-equal',
769+
stencilFront: {
770+
compare: clipping ? 'always' : (clipApplied ? 'not-equal' : 'always'),
771+
failOp: 'keep',
772+
depthFailOp: 'keep',
773+
passOp: clipping ? 'replace' : 'keep',
774+
},
775+
stencilBack: {
776+
compare: clipping ? 'always' : (clipApplied ? 'not-equal' : 'always'),
777+
failOp: 'keep',
778+
depthFailOp: 'keep',
779+
passOp: clipping ? 'replace' : 'keep',
780+
},
781+
stencilReadMask: 0xFF,
782+
stencilWriteMask: clipping ? 0xFF : 0x00,
773783
},
774-
stencilBack: {
775-
compare: clipping ? 'always' : (clipApplied ? 'not-equal' : 'always'),
776-
failOp: 'keep',
777-
depthFailOp: 'keep',
778-
passOp: clipping ? 'replace' : 'keep',
779-
},
780-
stencilReadMask: 0xFF,
781-
stencilWriteMask: clipping ? 0xFF : 0x00,
782-
},
784+
} : {}),
783785
});
784786
shader._pipelineCache.set(key, pipeline);
785787
}
@@ -2986,7 +2988,7 @@ ${hookUniformFields}}
29862988
}
29872989

29882990
defaultFramebufferAntialias() {
2989-
return true;
2991+
return this._pInst._webgpuAttributes?.antialias !== false;
29902992
}
29912993

29922994
supportsFramebufferAntialias() {
@@ -3852,13 +3854,6 @@ ${hookUniformFields}}
38523854
px = Math.ceil(Math.sqrt(totalIterations));
38533855
py = Math.ceil(totalIterations / px);
38543856
pz = 1;
3855-
3856-
if (p5.debug || exceedsLimits) {
3857-
console.warn(
3858-
`p5.js: Compute dispatch (${x}, ${y}, ${z}) auto-spread to (${px}, ${py}, 1) ` +
3859-
`to ${exceedsLimits ? 'stay within GPU limits' : 'optimize performance'}.`
3860-
);
3861-
}
38623857
}
38633858

38643859
shader.setUniform('uPhysicalCount', [px, py, pz]);

src/webgpu/strands_wgslBackend.js

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -584,12 +584,25 @@ export const wgslBackend = {
584584
const samplerVariable = build.variableNode(strandsContext, { baseType: BaseType.SAMPLER, dimension: 1 }, samplerIdentifier);
585585
const samplerNode = createStrandsNode(samplerVariable.id, samplerVariable.dimension, strandsContext);
586586

587-
// Create the augmented args: [texture, sampler, coords]
588-
const augmentedArgs = [textureArg, samplerNode, coordsArg];
589-
590-
const { id, dimension } = build.functionCallNode(strandsContext, 'textureSample', augmentedArgs, {
587+
// Create a LOD literal node (0.0) so we can use textureSampleLevel instead
588+
// of textureSample. textureSample doesn't let you use uniform values in control
589+
// flow, whereas textureSampleLevel does. While we don't have mipmaps, we don't
590+
// miss out.
591+
// TODO: if we *do* add mipmap support, update this logic -- we'd need to hoist
592+
// the texture lookup out of the control flow.
593+
const lodLiteral = build.scalarLiteralNode(
594+
strandsContext,
595+
{ dimension: 1, baseType: BaseType.FLOAT },
596+
0.0
597+
);
598+
const lodNode = createStrandsNode(lodLiteral.id, lodLiteral.dimension, strandsContext);
599+
600+
// Create the augmented args: [texture, sampler, coords, lod]
601+
const augmentedArgs = [textureArg, samplerNode, coordsArg, lodNode];
602+
603+
const { id, dimension } = build.functionCallNode(strandsContext, 'textureSampleLevel', augmentedArgs, {
591604
overloads: [{
592-
params: [DataType.sampler2D, DataType.sampler, DataType.float2],
605+
params: [DataType.sampler2D, DataType.sampler, DataType.float2, DataType.float1],
593606
returnType: DataType.float4
594607
}]
595608
});

test/types/webgpu.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import p5 from '../../types/global'
2+
3+
async function setup() {
4+
const renderer: p5.Renderer = await createCanvas(100, 100, WEBGPU);
5+
background(0);
6+
fill(255);
7+
noStroke();
8+
circle(0, 0, 50);
9+
}

test/unit/visual/cases/webgpu.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,31 @@ visualSuite("WebGPU", function () {
273273
await screenshot();
274274
});
275275

276+
visualTest('filter shaders can sample a texture inside a conditional branch', async function(p5, screenshot) {
277+
await p5.createCanvas(50, 50, p5.WEBGPU);
278+
p5.background(255);
279+
p5.noStroke();
280+
p5.fill(0);
281+
p5.circle(0, 0, 20);
282+
// This shader only samples the texture for pixels in the left half of the
283+
// canvas, exercising getTexture() inside a non-uniform conditional
284+
const conditionalInvert = p5.buildFilterShader(({ p5 }) => {
285+
p5.filterColor.begin();
286+
if (p5.filterColor.texCoord.x < 0.5) {
287+
const col = p5.getTexture(
288+
p5.filterColor.canvasContent,
289+
p5.filterColor.texCoord
290+
);
291+
p5.filterColor.set([1 - col.rgb, col.a]);
292+
} else {
293+
p5.filterColor.set([0, 0, 1, 1]);
294+
}
295+
p5.filterColor.end();
296+
}, { p5 });
297+
p5.filter(conditionalInvert);
298+
await screenshot();
299+
});
300+
276301
visualTest('instanceID in fragment hook colors instances (WebGPU)', async function(p5, screenshot) {
277302
await p5.createCanvas(50, 50, p5.WEBGPU);
278303
const numInstances = 4;
@@ -523,6 +548,28 @@ visualSuite("WebGPU", function () {
523548
},
524549
);
525550

551+
visualTest(
552+
"Framebuffer with depth disabled",
553+
async function (p5, screenshot) {
554+
await p5.createCanvas(50, 50, p5.WEBGPU);
555+
const fbo = p5.createFramebuffer({ width: 50, height: 50, depth: false });
556+
557+
fbo.draw(() => {
558+
p5.background(0, 0, 200);
559+
p5.fill(255, 200, 0);
560+
p5.noStroke();
561+
p5.circle(0, 0, 30);
562+
});
563+
564+
p5.background(50);
565+
p5.texture(fbo);
566+
p5.noStroke();
567+
p5.plane(50, 50);
568+
569+
await screenshot();
570+
},
571+
);
572+
526573
visualTest(
527574
"Fixed-size framebuffer after manual resize",
528575
async function (p5, screenshot) {
@@ -564,6 +611,21 @@ visualSuite("WebGPU", function () {
564611
);
565612
});
566613

614+
visualSuite("Rendering attributes", function () {
615+
visualTest(
616+
"noSmooth() does not crash and disables antialiasing",
617+
async function (p5, screenshot) {
618+
await p5.createCanvas(50, 50, p5.WEBGPU);
619+
await p5.noSmooth();
620+
p5.background(0);
621+
p5.fill(255);
622+
p5.noStroke();
623+
p5.circle(0, 0, 30);
624+
await screenshot();
625+
},
626+
);
627+
});
628+
567629
visualSuite("Clipping", function () {
568630
visualTest(
569631
"Basic clipping with circles",
564 Bytes
Loading
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"numScreenshots": 1
3+
}
438 Bytes
Loading

0 commit comments

Comments
 (0)