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 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
- constructor(passName) {
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
- if (!this.passes.find((pass) => pass.name === passName)) throw new Error(`Cannot find pass named '${passName}'. Available passes: [${this.passes.map((p) => p.name).join(", ")}]`);
438
- return PassTextureRef.create(passName);
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) texture = this.textureManager.createTexture(textureName, this.format);
450
- return texture.createView();
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
- if (pass.renderToCanvas || i === enabledPasses.length - 1) renderTarget = this.ctx.getCurrentTexture().createView();
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 (!texture) texture = this.textureManager.createTexture(textureName, pass.format || this.format);
686
- renderTarget = texture.createView();
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;
@@ -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
- constructor(passName: string);
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): PassTextureRef;
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): PassTextureRef;
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 { type BindingResource, type PassTextureRef, type RenderPassOptions, type WGSLRenderer, createWGSLRenderer };
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
- constructor(passName) {
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
- if (!this.passes.find((pass) => pass.name === passName)) throw new Error(`Cannot find pass named '${passName}'. Available passes: [${this.passes.map((p) => p.name).join(", ")}]`);
437
- return PassTextureRef.create(passName);
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) texture = this.textureManager.createTexture(textureName, this.format);
449
- return texture.createView();
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
- if (pass.renderToCanvas || i === enabledPasses.length - 1) renderTarget = this.ctx.getCurrentTexture().createView();
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 (!texture) texture = this.textureManager.createTexture(textureName, pass.format || this.format);
685
- renderTarget = texture.createView();
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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wgsl-renderer",
3
- "version": "0.1.8",
3
+ "version": "0.2.0",
4
4
  "description": "A multi-pass renderer based on WebGPU and WGSL.",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.js",