@rings-webgpu/core 1.0.41 → 1.0.43

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.
@@ -1686,21 +1686,47 @@
1686
1686
  this.adapter = await navigator.gpu.requestAdapter({
1687
1687
  powerPreference: "high-performance"
1688
1688
  // 或 low-power
1689
+ // xrCompatible: canvasConfig?.xrCompatible, // 可选:如果需要 XR 支持
1689
1690
  });
1690
1691
  if (this.adapter == null) {
1691
1692
  throw new Error("Your browser does not support WebGPU!");
1692
1693
  }
1694
+ const requiredFeatures = [];
1695
+ const requireFeature = (feature) => {
1696
+ const supported = this.adapter.features.has(feature);
1697
+ if (supported) {
1698
+ requiredFeatures.push(feature);
1699
+ }
1700
+ return supported;
1701
+ };
1702
+ requireFeature("bgra8unorm-storage");
1703
+ requireFeature("depth-clip-control");
1704
+ requireFeature("depth32float-stencil8");
1705
+ requireFeature("indirect-first-instance");
1706
+ requireFeature("rg11b10ufloat-renderable");
1707
+ requireFeature("float32-filterable");
1708
+ requireFeature("float32-blendable");
1709
+ requireFeature("timestamp-query");
1710
+ requireFeature("shader-f16");
1711
+ requireFeature("clip-distances");
1712
+ requireFeature("texture-compression-bc");
1713
+ requireFeature("texture-compression-etc2");
1714
+ requireFeature("texture-compression-astc");
1715
+ const adapterLimits = this.adapter?.limits;
1716
+ const requiredLimits = {};
1717
+ if (adapterLimits) {
1718
+ for (const limitName in adapterLimits) {
1719
+ if (limitName === "minSubgroupSize" || limitName === "maxSubgroupSize") {
1720
+ continue;
1721
+ }
1722
+ requiredLimits[limitName] = adapterLimits[limitName];
1723
+ }
1724
+ }
1693
1725
  this.device = await this.adapter.requestDevice({
1694
- requiredFeatures: [
1695
- "bgra8unorm-storage",
1696
- "depth-clip-control",
1697
- "depth32float-stencil8",
1698
- "indirect-first-instance",
1699
- "rg11b10ufloat-renderable"
1700
- ],
1701
- requiredLimits: {
1702
- minUniformBufferOffsetAlignment: 256,
1703
- maxStorageBufferBindingSize: this.adapter.limits.maxStorageBufferBindingSize
1726
+ requiredFeatures,
1727
+ requiredLimits,
1728
+ defaultQueue: {
1729
+ label: "RingsDefaultQueue"
1704
1730
  }
1705
1731
  });
1706
1732
  if (this.device == null) {
@@ -1708,15 +1734,18 @@
1708
1734
  }
1709
1735
  this._pixelRatio = this.canvasConfig?.devicePixelRatio || window.devicePixelRatio || 1;
1710
1736
  this._pixelRatio = Math.min(this._pixelRatio, 2);
1711
- this.device.label = "device";
1737
+ this.device.label = "RingsWebGPUDevice";
1712
1738
  this.presentationFormat = navigator.gpu.getPreferredCanvasFormat();
1713
1739
  this.context = this.canvas.getContext("webgpu");
1714
1740
  this.context.configure({
1715
1741
  device: this.device,
1716
1742
  format: this.presentationFormat,
1717
- usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
1743
+ // RENDER_ATTACHMENT is required, COPY_SRC allows scene grab/copy operations
1744
+ usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST,
1718
1745
  alphaMode: "premultiplied",
1719
- colorSpace: `srgb`
1746
+ colorSpace: "srgb"
1747
+ // Optional: viewFormats can be added here if needed for SRGB views
1748
+ // viewFormats: [this.presentationFormat + '-srgb']
1720
1749
  });
1721
1750
  this._resizeEvent = new CResizeEvent(CResizeEvent.RESIZE, {
1722
1751
  width: this.windowWidth,
@@ -22886,11 +22915,23 @@ struct InstanceData {
22886
22915
  let radius = length(vec2f((diagonal1 - diagonal2) * 0.5, offDiagonal));
22887
22916
  let lambda1 = mid + radius;
22888
22917
  let lambda2 = max(mid - radius, MIN_LAMBDA);
22918
+
22919
+ let vmin = min(MAX_SPLAT_SIZE, min(viewport.x, viewport.y));
22920
+ let l1 = 2.0 * min(sqrt(2.0 * lambda1), vmin);
22921
+ let l2 = 2.0 * min(sqrt(2.0 * lambda2), vmin);
22922
+
22923
+ // if (l1 < 2.0 && l2 < 2.0) {
22924
+ // return discardSplat();
22925
+ // }
22926
+
22927
+ let centerProj = projMat * vec4f(splat_cam, 1.0);
22928
+ let c = centerProj.ww * vec2f(1.0 / viewport.x, 1.0 / viewport.y);
22929
+
22889
22930
  let diagonalVector = normalize(vec2f(offDiagonal, lambda1 - diagonal1));
22890
22931
 
22891
22932
  // Calculate axis vectors with size clamping
22892
- let v1 = min(sqrt(2.0 * lambda1), MAX_SPLAT_SIZE) * diagonalVector;
22893
- let v2 = min(sqrt(2.0 * lambda2), MAX_SPLAT_SIZE) * vec2f(diagonalVector.y, -diagonalVector.x);
22933
+ let v1 = l1 * diagonalVector;
22934
+ let v2 = l2 * vec2f(diagonalVector.y, -diagonalVector.x);
22894
22935
 
22895
22936
  // WebGPU Y-axis flip: WebGPU NDC Y goes from top(-1) to bottom(1), opposite of WebGL
22896
22937
  return vec4f(v1.x, -v1.y, v2.x, -v2.y);
@@ -22956,11 +22997,13 @@ struct InstanceData {
22956
22997
  let v1v2 = calcV1V2(splat_cam.xyz, splatData.covA, splatData.covB, W, viewport, matrix_projection);
22957
22998
 
22958
22999
  // Calculate scale based on alpha (optimized formula)
22959
- let scale = min(1.0, sqrt(LOG_255 + log(color.a)) * 0.5);
23000
+ let t = pow(splat_cam.z + 0.5, 5);
23001
+ let scale = min(1.0, sqrt(-log(1.0 / (255.0 * color.a))) / 2.0);
22960
23002
 
22961
23003
  // Apply visBoost (size multiplier)
22962
23004
  let visBoost = materialUniform.tex_params.w;
22963
- let v1v2_scaled = v1v2 * (scale * visBoost);
23005
+ let expt = exp(-1.0 / t);
23006
+ let v1v2_scaled = v1v2 * (scale * visBoost * expt);
22964
23007
 
22965
23008
  // Pixel coverage culling (vectorized squared length calculation)
22966
23009
  let v1v2_sq = v1v2_scaled * v1v2_scaled;
@@ -22994,7 +23037,7 @@ struct InstanceData {
22994
23037
 
22995
23038
  var o: VSOut;
22996
23039
  o.member = splat_proj + vec4f(offset, 0.0, 0.0);
22997
- o.vTexCoord = vertex_pos * (scale * 0.5);
23040
+ o.vTexCoord = vertex_pos * (scale);
22998
23041
  o.vColor = color;
22999
23042
 
23000
23043
  return o;
@@ -23008,16 +23051,30 @@ struct InstanceData {
23008
23051
 
23009
23052
  // Constants
23010
23053
  const ALPHA_THRESHOLD: f32 = 0.00392156863; // 1.0 / 255.0
23011
- const GAUSSIAN_SCALE: f32 = 4.0;
23054
+ // const GAUSSIAN_SCALE: f32 = 4.0;
23055
+ const EXP4 = exp(-4.0);
23056
+ const INV_EXP4 = 1.0 / (1.0 - EXP4);
23057
+
23058
+ fn normExp(x: f32) -> f32 {
23059
+ return (exp(x * -4.0) - EXP4) * INV_EXP4;
23060
+ }
23012
23061
 
23013
23062
  // === evalSplat() - optimized gaussian evaluation ===
23014
23063
  fn evalSplat(texCoord: vec2f, color: vec4f) -> vec4f {
23015
23064
  let A = dot(texCoord, texCoord);
23065
+
23066
+ if (A > 1.0) {
23067
+ discard;
23068
+ // return vec4f(1.0, 0.0, 0.0, 0.5);
23069
+ }
23016
23070
 
23017
23071
  // Branch-less optimization using select
23018
- let gaussian = exp(-A * GAUSSIAN_SCALE) * color.a;
23019
- let alpha = select(gaussian, 0.0, A > 1.0 || gaussian < ALPHA_THRESHOLD);
23020
-
23072
+ var alpha = normExp(A) * color.a;
23073
+
23074
+ if (alpha < ALPHA_THRESHOLD) {
23075
+ discard;
23076
+ // alpha = 0.5;
23077
+ }
23021
23078
  return vec4f(color.rgb, alpha);
23022
23079
  }
23023
23080
 
@@ -23264,8 +23321,9 @@ struct InstanceData {
23264
23321
  pass.cullMode = GPUCullMode.none;
23265
23322
  pass.shaderState.transparent = true;
23266
23323
  pass.shaderState.blendMode = BlendMode.NORMAL;
23267
- pass.shaderState.writeMasks = [15, 15];
23324
+ pass.shaderState.writeMasks = [15, 0];
23268
23325
  pass.shaderState.castReflection = false;
23326
+ pass.shaderState.depthCompare = GPUCompareFunction.less;
23269
23327
  this.addRenderPass(pass);
23270
23328
  this.setDefault();
23271
23329
  }
@@ -24014,17 +24072,17 @@ struct InstanceData {
24014
24072
  const meshPositions = new Float32Array(12 * batchSize);
24015
24073
  for (let i = 0; i < batchSize; ++i) {
24016
24074
  meshPositions.set([
24017
- -2,
24018
- -2,
24075
+ -1,
24076
+ -1,
24019
24077
  i,
24020
- 2,
24021
- -2,
24078
+ 1,
24079
+ -1,
24022
24080
  i,
24023
- 2,
24024
- 2,
24081
+ 1,
24082
+ 1,
24025
24083
  i,
24026
- -2,
24027
- 2,
24084
+ -1,
24085
+ 1,
24028
24086
  i
24029
24087
  ], i * 12);
24030
24088
  }
@@ -27488,6 +27546,8 @@ struct InstanceData {
27488
27546
  static matrixCount = 0;
27489
27547
  static lastRenderPassState;
27490
27548
  static LastCommand;
27549
+ static multiTextureViewCache = /* @__PURE__ */ new WeakMap();
27550
+ static swapchainTextureCache = { texture: null, view: null };
27491
27551
  static bindPipeline(encoder, renderShader) {
27492
27552
  if (GPUContext.lastShader != renderShader) {
27493
27553
  GPUContext.lastShader = renderShader;
@@ -27575,21 +27635,40 @@ struct InstanceData {
27575
27635
  const renderTarget = renderPassState.renderTargets[i];
27576
27636
  let att = renderPassState.renderPassDescriptor.colorAttachments[i];
27577
27637
  if (renderPassState.multisample > 0 && renderPassState.renderTargets.length == 1) {
27578
- att.view = renderPassState.multiTexture.createView();
27638
+ let multiView = this.multiTextureViewCache.get(renderPassState.multiTexture);
27639
+ if (!multiView) {
27640
+ multiView = renderPassState.multiTexture.createView();
27641
+ this.multiTextureViewCache.set(renderPassState.multiTexture, multiView);
27642
+ }
27643
+ att.view = multiView;
27579
27644
  att.resolveTarget = renderTarget.getGPUView();
27580
27645
  } else {
27581
- att.view = renderTarget.getGPUTexture().createView();
27646
+ att.view = renderTarget.getGPUView();
27582
27647
  }
27583
27648
  }
27584
27649
  return command.beginRenderPass(renderPassState.renderPassDescriptor);
27585
27650
  } else {
27586
27651
  let att0 = renderPassState.renderPassDescriptor.colorAttachments[0];
27587
27652
  if (att0) {
27653
+ const swapchainTexture = webGPUContext.context.getCurrentTexture();
27588
27654
  if (renderPassState.multisample > 0) {
27589
- att0.view = renderPassState.multiTexture.createView();
27590
- att0.resolveTarget = webGPUContext.context.getCurrentTexture().createView();
27655
+ let multiView = this.multiTextureViewCache.get(renderPassState.multiTexture);
27656
+ if (!multiView) {
27657
+ multiView = renderPassState.multiTexture.createView();
27658
+ this.multiTextureViewCache.set(renderPassState.multiTexture, multiView);
27659
+ }
27660
+ att0.view = multiView;
27661
+ if (this.swapchainTextureCache.texture !== swapchainTexture) {
27662
+ this.swapchainTextureCache.texture = swapchainTexture;
27663
+ this.swapchainTextureCache.view = swapchainTexture.createView();
27664
+ }
27665
+ att0.resolveTarget = this.swapchainTextureCache.view;
27591
27666
  } else {
27592
- att0.view = webGPUContext.context.getCurrentTexture().createView();
27667
+ if (this.swapchainTextureCache.texture !== swapchainTexture) {
27668
+ this.swapchainTextureCache.texture = swapchainTexture;
27669
+ this.swapchainTextureCache.view = swapchainTexture.createView();
27670
+ }
27671
+ att0.view = this.swapchainTextureCache.view;
27593
27672
  }
27594
27673
  }
27595
27674
  return command.beginRenderPass(renderPassState.renderPassDescriptor);
@@ -42292,7 +42371,7 @@ else if (typeof exports === 'object')
42292
42371
  }
42293
42372
  }
42294
42373
 
42295
- const version = "1.0.41";
42374
+ const version = "1.0.42";
42296
42375
 
42297
42376
  class Engine3D {
42298
42377
  /**
@@ -66281,6 +66360,7 @@ fn frag(){
66281
66360
  used: 0,
66282
66361
  active: 0,
66283
66362
  visible: 0,
66363
+ sceneCount: 0,
66284
66364
  inCacheSinceLoad: 0
66285
66365
  };
66286
66366
  // Configuration options
@@ -66884,6 +66964,7 @@ fn frag(){
66884
66964
  tile.__wasSetVisible = true;
66885
66965
  this.stats.visible++;
66886
66966
  }
66967
+ this.stats.sceneCount++;
66887
66968
  tile.loadingState = LOADED;
66888
66969
  tile.usedLastFrame = true;
66889
66970
  markVisibleTiles(tile, this);
@@ -15,6 +15,8 @@ export declare class GPUContext {
15
15
  static matrixCount: number;
16
16
  static lastRenderPassState: RendererPassState;
17
17
  static LastCommand: GPUCommandEncoder | null;
18
+ private static multiTextureViewCache;
19
+ private static swapchainTextureCache;
18
20
  static bindPipeline(encoder: GPURenderPassEncoder | GPURenderBundleEncoder, renderShader: RenderShaderPass): boolean;
19
21
  static bindCamera(encoder: GPURenderPassEncoder | GPURenderBundleEncoder, camera: Camera3D): void;
20
22
  static bindGeometryBuffer(encoder: GPURenderPassEncoder | GPURenderBundleEncoder, geometry: GeometryBase): void;
@@ -27,6 +27,7 @@ export interface TilesRendererStats {
27
27
  used: number;
28
28
  active: number;
29
29
  visible: number;
30
+ sceneCount: number;
30
31
  inCacheSinceLoad: number;
31
32
  }
32
33
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rings-webgpu/core",
3
- "version": "1.0.41",
3
+ "version": "1.0.43",
4
4
  "description": "Rings webgpu Engine",
5
5
  "main": "index.js",
6
6
  "exports": {