wgsl-renderer 0.1.8 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.js +111 -13
- package/dist/esm/index.d.ts +35 -4
- package/dist/esm/index.js +110 -14
- package/package.json +1 -1
package/dist/cjs/index.js
CHANGED
|
@@ -10,6 +10,7 @@ var RenderPass = class {
|
|
|
10
10
|
view;
|
|
11
11
|
format;
|
|
12
12
|
renderToCanvas;
|
|
13
|
+
sampleCount = 1;
|
|
13
14
|
passResources = [];
|
|
14
15
|
bindGroups = {};
|
|
15
16
|
activeBindGroupSet = "default";
|
|
@@ -30,6 +31,7 @@ var RenderPass = class {
|
|
|
30
31
|
this.view = descriptor.view;
|
|
31
32
|
this.format = descriptor.format;
|
|
32
33
|
this.renderToCanvas = descriptor.renderToCanvas;
|
|
34
|
+
this.sampleCount = descriptor.sampleCount || 1;
|
|
33
35
|
const actualFormat = descriptor.format || format;
|
|
34
36
|
const module$1 = this.device.createShaderModule({
|
|
35
37
|
code: descriptor.shaderCode,
|
|
@@ -76,7 +78,8 @@ var RenderPass = class {
|
|
|
76
78
|
blend: this.getBlendState()
|
|
77
79
|
}]
|
|
78
80
|
},
|
|
79
|
-
primitive: { topology: "triangle-list" }
|
|
81
|
+
primitive: { topology: "triangle-list" },
|
|
82
|
+
multisample: { count: this.sampleCount }
|
|
80
83
|
});
|
|
81
84
|
this.bindGroup = null;
|
|
82
85
|
}
|
|
@@ -341,6 +344,12 @@ var TextureManager = class {
|
|
|
341
344
|
});
|
|
342
345
|
this.textures.clear();
|
|
343
346
|
}
|
|
347
|
+
/**
|
|
348
|
+
* Store a texture in the manager
|
|
349
|
+
*/
|
|
350
|
+
setTexture(name, texture) {
|
|
351
|
+
this.textures.set(name, texture);
|
|
352
|
+
}
|
|
344
353
|
destroy() {
|
|
345
354
|
this.textures.forEach((texture) => texture.destroy());
|
|
346
355
|
this.textures.clear();
|
|
@@ -359,8 +368,10 @@ const PASS_TEXTURE_REF_SYMBOL = Symbol("PassTextureRef");
|
|
|
359
368
|
var PassTextureRef = class PassTextureRef {
|
|
360
369
|
[PASS_TEXTURE_REF_SYMBOL] = true;
|
|
361
370
|
passName;
|
|
362
|
-
|
|
371
|
+
options;
|
|
372
|
+
constructor(passName, options) {
|
|
363
373
|
this.passName = passName;
|
|
374
|
+
this.options = options;
|
|
364
375
|
}
|
|
365
376
|
static is(obj) {
|
|
366
377
|
return obj && typeof obj === "object" && PASS_TEXTURE_REF_SYMBOL in obj;
|
|
@@ -369,8 +380,8 @@ var PassTextureRef = class PassTextureRef {
|
|
|
369
380
|
if (this.is(resource)) return resource;
|
|
370
381
|
return null;
|
|
371
382
|
}
|
|
372
|
-
static create(passName) {
|
|
373
|
-
return new PassTextureRef(passName);
|
|
383
|
+
static create(passName, options) {
|
|
384
|
+
return new PassTextureRef(passName, options);
|
|
374
385
|
}
|
|
375
386
|
};
|
|
376
387
|
function isPassTextureRef(obj) {
|
|
@@ -387,6 +398,8 @@ var WGSLRenderer = class {
|
|
|
387
398
|
textureManager;
|
|
388
399
|
animationFrameId = null;
|
|
389
400
|
isResizing = false;
|
|
401
|
+
supportedSampleCounts = [];
|
|
402
|
+
testedSampleCounts = /* @__PURE__ */ new Set();
|
|
390
403
|
constructor(canvas, options) {
|
|
391
404
|
this.canvas = canvas;
|
|
392
405
|
this.options = options;
|
|
@@ -396,6 +409,8 @@ var WGSLRenderer = class {
|
|
|
396
409
|
async init() {
|
|
397
410
|
this.device = await (await navigator.gpu.requestAdapter()).requestDevice();
|
|
398
411
|
this.format = navigator.gpu.getPreferredCanvasFormat();
|
|
412
|
+
this.supportedSampleCounts = [1];
|
|
413
|
+
this.testedSampleCounts = new Set([1]);
|
|
399
414
|
const config = Object.assign({
|
|
400
415
|
device: this.device,
|
|
401
416
|
format: this.format,
|
|
@@ -429,13 +444,25 @@ var WGSLRenderer = class {
|
|
|
429
444
|
getDevice() {
|
|
430
445
|
return this.device;
|
|
431
446
|
}
|
|
447
|
+
getSupportedSampleCounts() {
|
|
448
|
+
return [...this.supportedSampleCounts];
|
|
449
|
+
}
|
|
450
|
+
isSampleCountSupported(sampleCount) {
|
|
451
|
+
if (this.testedSampleCounts.has(sampleCount)) return this.supportedSampleCounts.includes(sampleCount);
|
|
452
|
+
return this.supportedSampleCounts.includes(sampleCount);
|
|
453
|
+
}
|
|
432
454
|
/**
|
|
433
455
|
* Get texture reference by pass name
|
|
434
456
|
* Returns a PassTextureRef that will resolve to the actual texture at render time
|
|
457
|
+
*
|
|
458
|
+
* @param passName Name of the pass to reference
|
|
459
|
+
* @param options Optional texture creation options for when the texture needs to be created
|
|
435
460
|
*/
|
|
436
|
-
getPassTexture(passName) {
|
|
437
|
-
|
|
438
|
-
|
|
461
|
+
getPassTexture(passName, options) {
|
|
462
|
+
const pass = this.passes.find((pass$1) => pass$1.name === passName);
|
|
463
|
+
if (!pass) throw new Error(`Cannot find pass named '${passName}'. Available passes: [${this.passes.map((p) => p.name).join(", ")}]`);
|
|
464
|
+
if ((options?.format ?? "rgba8unorm") !== pass.format) throw new Error(`Format must be set to ${pass.format}, pass name: '${passName}'`);
|
|
465
|
+
return PassTextureRef.create(passName, options);
|
|
439
466
|
}
|
|
440
467
|
/**
|
|
441
468
|
* Resolve a PassTextureRef to actual GPUTextureView with validation
|
|
@@ -446,8 +473,24 @@ var WGSLRenderer = class {
|
|
|
446
473
|
if (targetPass.view) return targetPass.view;
|
|
447
474
|
const textureName = `pass_${this.passes.indexOf(targetPass)}_output`;
|
|
448
475
|
let texture = this.textureManager.getTexture(textureName);
|
|
449
|
-
if (!texture)
|
|
450
|
-
|
|
476
|
+
if (!texture) {
|
|
477
|
+
const format = ref.options?.format || this.format;
|
|
478
|
+
const usage = ref.options?.usage || GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT;
|
|
479
|
+
const size = this.textureManager.getPixelSize();
|
|
480
|
+
const requestedSampleCount = ref.options?.sampleCount || 1;
|
|
481
|
+
const actualSampleCount = this.isSampleCountSupported(requestedSampleCount) ? requestedSampleCount : 1;
|
|
482
|
+
texture = this.device.createTexture({
|
|
483
|
+
size: [size.width, size.height],
|
|
484
|
+
format,
|
|
485
|
+
usage,
|
|
486
|
+
sampleCount: actualSampleCount
|
|
487
|
+
});
|
|
488
|
+
this.textureManager.setTexture(textureName, texture);
|
|
489
|
+
}
|
|
490
|
+
return texture.createView({
|
|
491
|
+
baseMipLevel: 0,
|
|
492
|
+
mipLevelCount: ref.options?.mipmaps ? texture.mipLevelCount : 1
|
|
493
|
+
});
|
|
451
494
|
}
|
|
452
495
|
/**
|
|
453
496
|
* Get pass by name
|
|
@@ -552,7 +595,8 @@ var WGSLRenderer = class {
|
|
|
552
595
|
bindGroupSets: bindGroupSetsCopy,
|
|
553
596
|
view: descriptor.view,
|
|
554
597
|
format: descriptor.format,
|
|
555
|
-
renderToCanvas: descriptor.renderToCanvas
|
|
598
|
+
renderToCanvas: descriptor.renderToCanvas,
|
|
599
|
+
sampleCount: descriptor.sampleCount
|
|
556
600
|
};
|
|
557
601
|
const pipelineFormat = descriptor.format || this.format;
|
|
558
602
|
return new RenderPass(internalDescriptor, this.device, pipelineFormat);
|
|
@@ -561,6 +605,10 @@ var WGSLRenderer = class {
|
|
|
561
605
|
* Add a render pass to the multi-pass pipeline
|
|
562
606
|
*/
|
|
563
607
|
addPass(descriptor) {
|
|
608
|
+
if (descriptor.sampleCount && !this.isSampleCountSupported(descriptor.sampleCount)) {
|
|
609
|
+
console.warn(`Sample count ${descriptor.sampleCount} is not supported. Using sample count 1 instead.`);
|
|
610
|
+
descriptor.sampleCount = 1;
|
|
611
|
+
}
|
|
564
612
|
const pass = this.createPass(descriptor);
|
|
565
613
|
pass.passResources = descriptor.resources ?? [];
|
|
566
614
|
this.passes.push(pass);
|
|
@@ -677,16 +725,64 @@ var WGSLRenderer = class {
|
|
|
677
725
|
let loadOp = "load";
|
|
678
726
|
if (i === 0) loadOp = "clear";
|
|
679
727
|
let renderTarget;
|
|
680
|
-
|
|
728
|
+
let resolveTarget;
|
|
729
|
+
const canvasTexture = this.ctx.getCurrentTexture();
|
|
730
|
+
const isLastPass = i === enabledPasses.length - 1;
|
|
731
|
+
if (pass.renderToCanvas || isLastPass && !pass.view) if (pass.sampleCount && pass.sampleCount > 1) {
|
|
732
|
+
const actualSampleCount = this.isSampleCountSupported(pass.sampleCount) ? pass.sampleCount : 1;
|
|
733
|
+
if (actualSampleCount === 1) renderTarget = canvasTexture.createView();
|
|
734
|
+
else {
|
|
735
|
+
renderTarget = this.device.createTexture({
|
|
736
|
+
size: [canvasTexture.width, canvasTexture.height],
|
|
737
|
+
format: canvasTexture.format,
|
|
738
|
+
usage: GPUTextureUsage.RENDER_ATTACHMENT,
|
|
739
|
+
sampleCount: actualSampleCount
|
|
740
|
+
}).createView();
|
|
741
|
+
resolveTarget = canvasTexture.createView();
|
|
742
|
+
}
|
|
743
|
+
} else renderTarget = canvasTexture.createView();
|
|
681
744
|
else if (pass.view) renderTarget = pass.view;
|
|
682
745
|
else {
|
|
683
746
|
const textureName = `pass_${i}_output`;
|
|
684
747
|
let texture = this.textureManager.getTexture(textureName);
|
|
685
|
-
if (
|
|
686
|
-
|
|
748
|
+
if (texture) {
|
|
749
|
+
const msaaTexture = this.textureManager.getTexture(`${textureName}_msaa`);
|
|
750
|
+
const resolveTexture = this.textureManager.getTexture(`${textureName}_resolve`);
|
|
751
|
+
if (msaaTexture && resolveTexture && pass.sampleCount && pass.sampleCount > 1) {
|
|
752
|
+
renderTarget = msaaTexture.createView();
|
|
753
|
+
resolveTarget = resolveTexture.createView();
|
|
754
|
+
} else renderTarget = texture.createView();
|
|
755
|
+
} else if (pass.sampleCount && pass.sampleCount > 1) {
|
|
756
|
+
const actualSampleCount = this.isSampleCountSupported(pass.sampleCount) ? pass.sampleCount : 1;
|
|
757
|
+
if (actualSampleCount > 1) {
|
|
758
|
+
texture = this.device.createTexture({
|
|
759
|
+
size: [this.textureManager.getPixelSize().width, this.textureManager.getPixelSize().height],
|
|
760
|
+
format: pass.format || this.format,
|
|
761
|
+
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,
|
|
762
|
+
sampleCount: actualSampleCount
|
|
763
|
+
});
|
|
764
|
+
const resolveTexture = this.device.createTexture({
|
|
765
|
+
size: [this.textureManager.getPixelSize().width, this.textureManager.getPixelSize().height],
|
|
766
|
+
format: pass.format || this.format,
|
|
767
|
+
usage: GPUTextureUsage.TEXTURE_BINDING,
|
|
768
|
+
sampleCount: 1
|
|
769
|
+
});
|
|
770
|
+
this.textureManager.setTexture(`${textureName}_msaa`, texture);
|
|
771
|
+
this.textureManager.setTexture(`${textureName}_resolve`, resolveTexture);
|
|
772
|
+
renderTarget = texture.createView();
|
|
773
|
+
resolveTarget = resolveTexture.createView();
|
|
774
|
+
} else {
|
|
775
|
+
texture = this.textureManager.createTexture(textureName, pass.format || this.format);
|
|
776
|
+
renderTarget = texture.createView();
|
|
777
|
+
}
|
|
778
|
+
} else {
|
|
779
|
+
texture = this.textureManager.createTexture(textureName, pass.format || this.format);
|
|
780
|
+
renderTarget = texture.createView();
|
|
781
|
+
}
|
|
687
782
|
}
|
|
688
783
|
const renderPass = commandEncoder.beginRenderPass({ colorAttachments: [{
|
|
689
784
|
view: renderTarget,
|
|
785
|
+
resolveTarget,
|
|
690
786
|
loadOp,
|
|
691
787
|
storeOp: "store",
|
|
692
788
|
clearValue: pass.clearColor
|
|
@@ -726,4 +822,6 @@ async function createWGSLRenderer(cvs, options) {
|
|
|
726
822
|
}
|
|
727
823
|
|
|
728
824
|
//#endregion
|
|
825
|
+
exports.PassTextureRef = PassTextureRef;
|
|
826
|
+
exports.WGSLRenderer = WGSLRenderer;
|
|
729
827
|
exports.createWGSLRenderer = createWGSLRenderer;
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -3,10 +3,26 @@ declare const PASS_TEXTURE_REF_SYMBOL: unique symbol;
|
|
|
3
3
|
declare class PassTextureRef {
|
|
4
4
|
readonly [PASS_TEXTURE_REF_SYMBOL] = true;
|
|
5
5
|
readonly passName: string;
|
|
6
|
-
|
|
6
|
+
readonly options?: {
|
|
7
|
+
format?: GPUTextureFormat;
|
|
8
|
+
mipmaps?: boolean;
|
|
9
|
+
sampleCount?: number;
|
|
10
|
+
usage?: GPUTextureUsageFlags;
|
|
11
|
+
};
|
|
12
|
+
constructor(passName: string, options?: {
|
|
13
|
+
format?: GPUTextureFormat;
|
|
14
|
+
mipmaps?: boolean;
|
|
15
|
+
sampleCount?: number;
|
|
16
|
+
usage?: GPUTextureUsageFlags;
|
|
17
|
+
});
|
|
7
18
|
static is(obj: any): obj is PassTextureRef;
|
|
8
19
|
static fromGPUBindingResource(resource: GPUBindingResource): PassTextureRef | null;
|
|
9
|
-
static create(passName: string
|
|
20
|
+
static create(passName: string, options?: {
|
|
21
|
+
format?: GPUTextureFormat;
|
|
22
|
+
mipmaps?: boolean;
|
|
23
|
+
sampleCount?: number;
|
|
24
|
+
usage?: GPUTextureUsageFlags;
|
|
25
|
+
}): PassTextureRef;
|
|
10
26
|
}
|
|
11
27
|
//#endregion
|
|
12
28
|
//#region src/RenderPass.d.ts
|
|
@@ -37,6 +53,7 @@ interface RenderPassOptions {
|
|
|
37
53
|
view?: GPUTextureView;
|
|
38
54
|
format?: GPUTextureFormat;
|
|
39
55
|
renderToCanvas?: boolean;
|
|
56
|
+
sampleCount?: number;
|
|
40
57
|
}
|
|
41
58
|
interface InternalRenderPassDescriptor {
|
|
42
59
|
name: string;
|
|
@@ -59,6 +76,7 @@ interface InternalRenderPassDescriptor {
|
|
|
59
76
|
view?: GPUTextureView;
|
|
60
77
|
format?: GPUTextureFormat;
|
|
61
78
|
renderToCanvas?: boolean;
|
|
79
|
+
sampleCount?: number;
|
|
62
80
|
}
|
|
63
81
|
declare class RenderPass {
|
|
64
82
|
name: string;
|
|
@@ -75,6 +93,7 @@ declare class RenderPass {
|
|
|
75
93
|
view?: GPUTextureView;
|
|
76
94
|
format?: GPUTextureFormat;
|
|
77
95
|
renderToCanvas?: boolean;
|
|
96
|
+
sampleCount: number;
|
|
78
97
|
passResources: BindingResource[];
|
|
79
98
|
bindGroups: {
|
|
80
99
|
[setName: string]: GPUBindGroup;
|
|
@@ -132,16 +151,28 @@ declare class WGSLRenderer {
|
|
|
132
151
|
private textureManager;
|
|
133
152
|
private animationFrameId;
|
|
134
153
|
private isResizing;
|
|
154
|
+
private supportedSampleCounts;
|
|
155
|
+
private testedSampleCounts;
|
|
135
156
|
constructor(canvas: HTMLCanvasElement, options?: WGSLRendererOptions | undefined);
|
|
136
157
|
init(): Promise<void>;
|
|
137
158
|
resize(width: number, height: number): Promise<void>;
|
|
138
159
|
getContext(): GPUCanvasContext;
|
|
139
160
|
getDevice(): GPUDevice;
|
|
161
|
+
getSupportedSampleCounts(): number[];
|
|
162
|
+
isSampleCountSupported(sampleCount: number): boolean;
|
|
140
163
|
/**
|
|
141
164
|
* Get texture reference by pass name
|
|
142
165
|
* Returns a PassTextureRef that will resolve to the actual texture at render time
|
|
166
|
+
*
|
|
167
|
+
* @param passName Name of the pass to reference
|
|
168
|
+
* @param options Optional texture creation options for when the texture needs to be created
|
|
143
169
|
*/
|
|
144
|
-
getPassTexture(passName: string
|
|
170
|
+
getPassTexture(passName: string, options?: {
|
|
171
|
+
format?: GPUTextureFormat;
|
|
172
|
+
mipmaps?: boolean;
|
|
173
|
+
sampleCount?: number;
|
|
174
|
+
usage?: GPUTextureUsageFlags;
|
|
175
|
+
}): PassTextureRef;
|
|
145
176
|
/**
|
|
146
177
|
* Resolve a PassTextureRef to actual GPUTextureView with validation
|
|
147
178
|
*/
|
|
@@ -232,4 +263,4 @@ declare class WGSLRenderer {
|
|
|
232
263
|
}
|
|
233
264
|
declare function createWGSLRenderer(cvs: HTMLCanvasElement, options?: WGSLRendererOptions): Promise<WGSLRenderer>;
|
|
234
265
|
//#endregion
|
|
235
|
-
export {
|
|
266
|
+
export { BindingResource, PassTextureRef, RenderPassOptions, WGSLRenderer, createWGSLRenderer };
|
package/dist/esm/index.js
CHANGED
|
@@ -9,6 +9,7 @@ var RenderPass = class {
|
|
|
9
9
|
view;
|
|
10
10
|
format;
|
|
11
11
|
renderToCanvas;
|
|
12
|
+
sampleCount = 1;
|
|
12
13
|
passResources = [];
|
|
13
14
|
bindGroups = {};
|
|
14
15
|
activeBindGroupSet = "default";
|
|
@@ -29,6 +30,7 @@ var RenderPass = class {
|
|
|
29
30
|
this.view = descriptor.view;
|
|
30
31
|
this.format = descriptor.format;
|
|
31
32
|
this.renderToCanvas = descriptor.renderToCanvas;
|
|
33
|
+
this.sampleCount = descriptor.sampleCount || 1;
|
|
32
34
|
const actualFormat = descriptor.format || format;
|
|
33
35
|
const module = this.device.createShaderModule({
|
|
34
36
|
code: descriptor.shaderCode,
|
|
@@ -75,7 +77,8 @@ var RenderPass = class {
|
|
|
75
77
|
blend: this.getBlendState()
|
|
76
78
|
}]
|
|
77
79
|
},
|
|
78
|
-
primitive: { topology: "triangle-list" }
|
|
80
|
+
primitive: { topology: "triangle-list" },
|
|
81
|
+
multisample: { count: this.sampleCount }
|
|
79
82
|
});
|
|
80
83
|
this.bindGroup = null;
|
|
81
84
|
}
|
|
@@ -340,6 +343,12 @@ var TextureManager = class {
|
|
|
340
343
|
});
|
|
341
344
|
this.textures.clear();
|
|
342
345
|
}
|
|
346
|
+
/**
|
|
347
|
+
* Store a texture in the manager
|
|
348
|
+
*/
|
|
349
|
+
setTexture(name, texture) {
|
|
350
|
+
this.textures.set(name, texture);
|
|
351
|
+
}
|
|
343
352
|
destroy() {
|
|
344
353
|
this.textures.forEach((texture) => texture.destroy());
|
|
345
354
|
this.textures.clear();
|
|
@@ -358,8 +367,10 @@ const PASS_TEXTURE_REF_SYMBOL = Symbol("PassTextureRef");
|
|
|
358
367
|
var PassTextureRef = class PassTextureRef {
|
|
359
368
|
[PASS_TEXTURE_REF_SYMBOL] = true;
|
|
360
369
|
passName;
|
|
361
|
-
|
|
370
|
+
options;
|
|
371
|
+
constructor(passName, options) {
|
|
362
372
|
this.passName = passName;
|
|
373
|
+
this.options = options;
|
|
363
374
|
}
|
|
364
375
|
static is(obj) {
|
|
365
376
|
return obj && typeof obj === "object" && PASS_TEXTURE_REF_SYMBOL in obj;
|
|
@@ -368,8 +379,8 @@ var PassTextureRef = class PassTextureRef {
|
|
|
368
379
|
if (this.is(resource)) return resource;
|
|
369
380
|
return null;
|
|
370
381
|
}
|
|
371
|
-
static create(passName) {
|
|
372
|
-
return new PassTextureRef(passName);
|
|
382
|
+
static create(passName, options) {
|
|
383
|
+
return new PassTextureRef(passName, options);
|
|
373
384
|
}
|
|
374
385
|
};
|
|
375
386
|
function isPassTextureRef(obj) {
|
|
@@ -386,6 +397,8 @@ var WGSLRenderer = class {
|
|
|
386
397
|
textureManager;
|
|
387
398
|
animationFrameId = null;
|
|
388
399
|
isResizing = false;
|
|
400
|
+
supportedSampleCounts = [];
|
|
401
|
+
testedSampleCounts = /* @__PURE__ */ new Set();
|
|
389
402
|
constructor(canvas, options) {
|
|
390
403
|
this.canvas = canvas;
|
|
391
404
|
this.options = options;
|
|
@@ -395,6 +408,8 @@ var WGSLRenderer = class {
|
|
|
395
408
|
async init() {
|
|
396
409
|
this.device = await (await navigator.gpu.requestAdapter()).requestDevice();
|
|
397
410
|
this.format = navigator.gpu.getPreferredCanvasFormat();
|
|
411
|
+
this.supportedSampleCounts = [1];
|
|
412
|
+
this.testedSampleCounts = new Set([1]);
|
|
398
413
|
const config = Object.assign({
|
|
399
414
|
device: this.device,
|
|
400
415
|
format: this.format,
|
|
@@ -428,13 +443,25 @@ var WGSLRenderer = class {
|
|
|
428
443
|
getDevice() {
|
|
429
444
|
return this.device;
|
|
430
445
|
}
|
|
446
|
+
getSupportedSampleCounts() {
|
|
447
|
+
return [...this.supportedSampleCounts];
|
|
448
|
+
}
|
|
449
|
+
isSampleCountSupported(sampleCount) {
|
|
450
|
+
if (this.testedSampleCounts.has(sampleCount)) return this.supportedSampleCounts.includes(sampleCount);
|
|
451
|
+
return this.supportedSampleCounts.includes(sampleCount);
|
|
452
|
+
}
|
|
431
453
|
/**
|
|
432
454
|
* Get texture reference by pass name
|
|
433
455
|
* Returns a PassTextureRef that will resolve to the actual texture at render time
|
|
456
|
+
*
|
|
457
|
+
* @param passName Name of the pass to reference
|
|
458
|
+
* @param options Optional texture creation options for when the texture needs to be created
|
|
434
459
|
*/
|
|
435
|
-
getPassTexture(passName) {
|
|
436
|
-
|
|
437
|
-
|
|
460
|
+
getPassTexture(passName, options) {
|
|
461
|
+
const pass = this.passes.find((pass$1) => pass$1.name === passName);
|
|
462
|
+
if (!pass) throw new Error(`Cannot find pass named '${passName}'. Available passes: [${this.passes.map((p) => p.name).join(", ")}]`);
|
|
463
|
+
if ((options?.format ?? "rgba8unorm") !== pass.format) throw new Error(`Format must be set to ${pass.format}, pass name: '${passName}'`);
|
|
464
|
+
return PassTextureRef.create(passName, options);
|
|
438
465
|
}
|
|
439
466
|
/**
|
|
440
467
|
* Resolve a PassTextureRef to actual GPUTextureView with validation
|
|
@@ -445,8 +472,24 @@ var WGSLRenderer = class {
|
|
|
445
472
|
if (targetPass.view) return targetPass.view;
|
|
446
473
|
const textureName = `pass_${this.passes.indexOf(targetPass)}_output`;
|
|
447
474
|
let texture = this.textureManager.getTexture(textureName);
|
|
448
|
-
if (!texture)
|
|
449
|
-
|
|
475
|
+
if (!texture) {
|
|
476
|
+
const format = ref.options?.format || this.format;
|
|
477
|
+
const usage = ref.options?.usage || GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT;
|
|
478
|
+
const size = this.textureManager.getPixelSize();
|
|
479
|
+
const requestedSampleCount = ref.options?.sampleCount || 1;
|
|
480
|
+
const actualSampleCount = this.isSampleCountSupported(requestedSampleCount) ? requestedSampleCount : 1;
|
|
481
|
+
texture = this.device.createTexture({
|
|
482
|
+
size: [size.width, size.height],
|
|
483
|
+
format,
|
|
484
|
+
usage,
|
|
485
|
+
sampleCount: actualSampleCount
|
|
486
|
+
});
|
|
487
|
+
this.textureManager.setTexture(textureName, texture);
|
|
488
|
+
}
|
|
489
|
+
return texture.createView({
|
|
490
|
+
baseMipLevel: 0,
|
|
491
|
+
mipLevelCount: ref.options?.mipmaps ? texture.mipLevelCount : 1
|
|
492
|
+
});
|
|
450
493
|
}
|
|
451
494
|
/**
|
|
452
495
|
* Get pass by name
|
|
@@ -551,7 +594,8 @@ var WGSLRenderer = class {
|
|
|
551
594
|
bindGroupSets: bindGroupSetsCopy,
|
|
552
595
|
view: descriptor.view,
|
|
553
596
|
format: descriptor.format,
|
|
554
|
-
renderToCanvas: descriptor.renderToCanvas
|
|
597
|
+
renderToCanvas: descriptor.renderToCanvas,
|
|
598
|
+
sampleCount: descriptor.sampleCount
|
|
555
599
|
};
|
|
556
600
|
const pipelineFormat = descriptor.format || this.format;
|
|
557
601
|
return new RenderPass(internalDescriptor, this.device, pipelineFormat);
|
|
@@ -560,6 +604,10 @@ var WGSLRenderer = class {
|
|
|
560
604
|
* Add a render pass to the multi-pass pipeline
|
|
561
605
|
*/
|
|
562
606
|
addPass(descriptor) {
|
|
607
|
+
if (descriptor.sampleCount && !this.isSampleCountSupported(descriptor.sampleCount)) {
|
|
608
|
+
console.warn(`Sample count ${descriptor.sampleCount} is not supported. Using sample count 1 instead.`);
|
|
609
|
+
descriptor.sampleCount = 1;
|
|
610
|
+
}
|
|
563
611
|
const pass = this.createPass(descriptor);
|
|
564
612
|
pass.passResources = descriptor.resources ?? [];
|
|
565
613
|
this.passes.push(pass);
|
|
@@ -676,16 +724,64 @@ var WGSLRenderer = class {
|
|
|
676
724
|
let loadOp = "load";
|
|
677
725
|
if (i === 0) loadOp = "clear";
|
|
678
726
|
let renderTarget;
|
|
679
|
-
|
|
727
|
+
let resolveTarget;
|
|
728
|
+
const canvasTexture = this.ctx.getCurrentTexture();
|
|
729
|
+
const isLastPass = i === enabledPasses.length - 1;
|
|
730
|
+
if (pass.renderToCanvas || isLastPass && !pass.view) if (pass.sampleCount && pass.sampleCount > 1) {
|
|
731
|
+
const actualSampleCount = this.isSampleCountSupported(pass.sampleCount) ? pass.sampleCount : 1;
|
|
732
|
+
if (actualSampleCount === 1) renderTarget = canvasTexture.createView();
|
|
733
|
+
else {
|
|
734
|
+
renderTarget = this.device.createTexture({
|
|
735
|
+
size: [canvasTexture.width, canvasTexture.height],
|
|
736
|
+
format: canvasTexture.format,
|
|
737
|
+
usage: GPUTextureUsage.RENDER_ATTACHMENT,
|
|
738
|
+
sampleCount: actualSampleCount
|
|
739
|
+
}).createView();
|
|
740
|
+
resolveTarget = canvasTexture.createView();
|
|
741
|
+
}
|
|
742
|
+
} else renderTarget = canvasTexture.createView();
|
|
680
743
|
else if (pass.view) renderTarget = pass.view;
|
|
681
744
|
else {
|
|
682
745
|
const textureName = `pass_${i}_output`;
|
|
683
746
|
let texture = this.textureManager.getTexture(textureName);
|
|
684
|
-
if (
|
|
685
|
-
|
|
747
|
+
if (texture) {
|
|
748
|
+
const msaaTexture = this.textureManager.getTexture(`${textureName}_msaa`);
|
|
749
|
+
const resolveTexture = this.textureManager.getTexture(`${textureName}_resolve`);
|
|
750
|
+
if (msaaTexture && resolveTexture && pass.sampleCount && pass.sampleCount > 1) {
|
|
751
|
+
renderTarget = msaaTexture.createView();
|
|
752
|
+
resolveTarget = resolveTexture.createView();
|
|
753
|
+
} else renderTarget = texture.createView();
|
|
754
|
+
} else if (pass.sampleCount && pass.sampleCount > 1) {
|
|
755
|
+
const actualSampleCount = this.isSampleCountSupported(pass.sampleCount) ? pass.sampleCount : 1;
|
|
756
|
+
if (actualSampleCount > 1) {
|
|
757
|
+
texture = this.device.createTexture({
|
|
758
|
+
size: [this.textureManager.getPixelSize().width, this.textureManager.getPixelSize().height],
|
|
759
|
+
format: pass.format || this.format,
|
|
760
|
+
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,
|
|
761
|
+
sampleCount: actualSampleCount
|
|
762
|
+
});
|
|
763
|
+
const resolveTexture = this.device.createTexture({
|
|
764
|
+
size: [this.textureManager.getPixelSize().width, this.textureManager.getPixelSize().height],
|
|
765
|
+
format: pass.format || this.format,
|
|
766
|
+
usage: GPUTextureUsage.TEXTURE_BINDING,
|
|
767
|
+
sampleCount: 1
|
|
768
|
+
});
|
|
769
|
+
this.textureManager.setTexture(`${textureName}_msaa`, texture);
|
|
770
|
+
this.textureManager.setTexture(`${textureName}_resolve`, resolveTexture);
|
|
771
|
+
renderTarget = texture.createView();
|
|
772
|
+
resolveTarget = resolveTexture.createView();
|
|
773
|
+
} else {
|
|
774
|
+
texture = this.textureManager.createTexture(textureName, pass.format || this.format);
|
|
775
|
+
renderTarget = texture.createView();
|
|
776
|
+
}
|
|
777
|
+
} else {
|
|
778
|
+
texture = this.textureManager.createTexture(textureName, pass.format || this.format);
|
|
779
|
+
renderTarget = texture.createView();
|
|
780
|
+
}
|
|
686
781
|
}
|
|
687
782
|
const renderPass = commandEncoder.beginRenderPass({ colorAttachments: [{
|
|
688
783
|
view: renderTarget,
|
|
784
|
+
resolveTarget,
|
|
689
785
|
loadOp,
|
|
690
786
|
storeOp: "store",
|
|
691
787
|
clearValue: pass.clearColor
|
|
@@ -725,4 +821,4 @@ async function createWGSLRenderer(cvs, options) {
|
|
|
725
821
|
}
|
|
726
822
|
|
|
727
823
|
//#endregion
|
|
728
|
-
export { createWGSLRenderer };
|
|
824
|
+
export { PassTextureRef, WGSLRenderer, createWGSLRenderer };
|