@gridspace/raster-path 1.0.4 → 1.0.6

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.
@@ -0,0 +1,185 @@
1
+ /**
2
+ * ═══════════════════════════════════════════════════════════════════════════
3
+ * Raster Config - Shared WebGPU State and Configuration
4
+ * ═══════════════════════════════════════════════════════════════════════════
5
+ *
6
+ * Central module providing shared state, configuration, and utilities for all
7
+ * worker modules. All WebGPU resources and pipelines are initialized here.
8
+ *
9
+ * EXPORTS:
10
+ * ────────
11
+ * State Variables:
12
+ * - config - Worker configuration (memory limits, tiling, etc.)
13
+ * - device - WebGPU device handle
14
+ * - deviceCapabilities - Device limits and capabilities
15
+ * - isInitialized - Initialization status flag
16
+ *
17
+ * Cached Pipelines:
18
+ * - cachedRasterizePipeline - Planar rasterization compute pipeline
19
+ * - cachedToolpathPipeline - Planar toolpath generation pipeline
20
+ * - cachedRadialBatchPipeline - Radial rasterization pipeline
21
+ * - cachedRasterizeShaderModule - Compiled planar rasterize shader
22
+ * - cachedToolpathShaderModule - Compiled planar toolpath shader
23
+ * - cachedRadialBatchShaderModule - Compiled radial shader
24
+ *
25
+ * Constants:
26
+ * - EMPTY_CELL - Sentinel value for empty raster cells (-1e10)
27
+ * - log_pre - Log prefix string "[Worker]"
28
+ * - diagnostic - Debug mode flag
29
+ *
30
+ * Utilities:
31
+ * - debug - Logging object (error, warn, log, ok)
32
+ * - round(v, d) - Round number to d decimal places
33
+ *
34
+ * Functions:
35
+ * - initWebGPU() - Initialize WebGPU device and compile pipelines
36
+ * - setConfig(obj) - Replace entire config object
37
+ * - updateConfig(obj) - Merge updates into existing config
38
+ *
39
+ * ARCHITECTURE:
40
+ * ─────────────
41
+ * This module acts as a singleton state container. All worker modules import
42
+ * from here to access GPU resources. The initWebGPU() function is called once
43
+ * during worker initialization and pre-compiles all compute pipelines to avoid
44
+ * runtime compilation overhead.
45
+ *
46
+ * Shader code placeholders ('SHADER:xxx') are replaced during build by the
47
+ * build-shaders.js script, which bundles modules with esbuild then injects
48
+ * WGSL shader source code.
49
+ *
50
+ * ═══════════════════════════════════════════════════════════════════════════
51
+ */
52
+
53
+ // WebGPU state
54
+ export let config = {};
55
+ export let device = null;
56
+ export let deviceCapabilities = null;
57
+ export let isInitialized = false;
58
+
59
+ // Cached pipelines (created during initialization)
60
+ export let cachedRasterizePipeline = null;
61
+ export let cachedRasterizeShaderModule = null;
62
+ export let cachedToolpathPipeline = null;
63
+ export let cachedToolpathShaderModule = null;
64
+ export let cachedRadialBatchPipeline = null;
65
+ export let cachedRadialBatchShaderModule = null;
66
+
67
+ // Constants
68
+ export const EMPTY_CELL = -1e10;
69
+ export const log_pre = '[Worker]';
70
+ export const diagnostic = false;
71
+
72
+ // Logging utilities
73
+ let lastlog;
74
+ export const debug = {
75
+ error: function() { console.error(log_pre, ...arguments) },
76
+ warn: function() { console.warn(log_pre, ...arguments) },
77
+ log: function() {
78
+ if (!config.quiet) {
79
+ let now = performance.now();
80
+ let since = ((now - (lastlog ?? now)) | 0).toString().padStart(4,' ');
81
+ console.log(log_pre, `[${since}]`, ...arguments);
82
+ lastlog = now;
83
+ }
84
+ },
85
+ ok: function() { console.log(log_pre, '✅', ...arguments) },
86
+ };
87
+
88
+ // Utility functions
89
+ export function round(v, d = 1) {
90
+ return parseFloat(v.toFixed(d));
91
+ }
92
+
93
+ // Shader code placeholders (replaced by build script)
94
+ const rasterizeShaderCode = 'SHADER:planar-rasterize';
95
+ const toolpathShaderCode = 'SHADER:planar-toolpath';
96
+ const radialRasterizeShaderCode = 'SHADER:radial-raster';
97
+
98
+ // Initialize WebGPU device in worker context
99
+ export async function initWebGPU() {
100
+ if (isInitialized) return true;
101
+
102
+ if (!navigator.gpu) {
103
+ debug.warn('WebGPU not supported');
104
+ return false;
105
+ }
106
+
107
+ try {
108
+ const adapter = await navigator.gpu.requestAdapter();
109
+ if (!adapter) {
110
+ debug.warn('WebGPU adapter not available');
111
+ return false;
112
+ }
113
+
114
+ // Request device with higher limits for large meshes
115
+ const adapterLimits = adapter.limits;
116
+ debug.log('Adapter limits:', {
117
+ maxStorageBufferBindingSize: adapterLimits.maxStorageBufferBindingSize,
118
+ maxBufferSize: adapterLimits.maxBufferSize
119
+ });
120
+
121
+ device = await adapter.requestDevice({
122
+ requiredLimits: {
123
+ maxStorageBufferBindingSize: Math.min(
124
+ adapterLimits.maxStorageBufferBindingSize,
125
+ 1024 * 1024 * 1024 // Request up to 1GB
126
+ ),
127
+ maxBufferSize: Math.min(
128
+ adapterLimits.maxBufferSize,
129
+ 1024 * 1024 * 1024 // Request up to 1GB
130
+ )
131
+ }
132
+ });
133
+
134
+ // Pre-compile rasterize shader module (expensive operation)
135
+ cachedRasterizeShaderModule = device.createShaderModule({ code: rasterizeShaderCode });
136
+
137
+ // Pre-create rasterize pipeline (very expensive operation)
138
+ cachedRasterizePipeline = device.createComputePipeline({
139
+ layout: 'auto',
140
+ compute: { module: cachedRasterizeShaderModule, entryPoint: 'main' },
141
+ });
142
+
143
+ // Pre-compile toolpath shader module
144
+ cachedToolpathShaderModule = device.createShaderModule({ code: toolpathShaderCode });
145
+
146
+ // Pre-create toolpath pipeline
147
+ cachedToolpathPipeline = device.createComputePipeline({
148
+ layout: 'auto',
149
+ compute: { module: cachedToolpathShaderModule, entryPoint: 'main' },
150
+ });
151
+
152
+ // Pre-compile radial batch shader module
153
+ cachedRadialBatchShaderModule = device.createShaderModule({ code: radialRasterizeShaderCode });
154
+
155
+ // Pre-create radial batch pipeline
156
+ cachedRadialBatchPipeline = device.createComputePipeline({
157
+ layout: 'auto',
158
+ compute: { module: cachedRadialBatchShaderModule, entryPoint: 'main' },
159
+ });
160
+
161
+ // Store device capabilities
162
+ deviceCapabilities = {
163
+ maxStorageBufferBindingSize: device.limits.maxStorageBufferBindingSize,
164
+ maxBufferSize: device.limits.maxBufferSize,
165
+ maxComputeWorkgroupSizeX: device.limits.maxComputeWorkgroupSizeX,
166
+ maxComputeWorkgroupSizeY: device.limits.maxComputeWorkgroupSizeY,
167
+ };
168
+
169
+ isInitialized = true;
170
+ debug.log('Initialized (pipelines cached)');
171
+ return true;
172
+ } catch (error) {
173
+ debug.error('Failed to initialize:', error);
174
+ return false;
175
+ }
176
+ }
177
+
178
+ // Mutators for config (called from worker main)
179
+ export function setConfig(newConfig) {
180
+ config = newConfig;
181
+ }
182
+
183
+ export function updateConfig(updates) {
184
+ Object.assign(config, updates);
185
+ }
@@ -48,13 +48,9 @@
48
48
  * @property {'planar'|'radial'} mode - Rasterization mode (default: 'planar')
49
49
  * @property {boolean} autoTiling - Automatically tile large datasets (default: true)
50
50
  * @property {number} gpuMemorySafetyMargin - Safety margin as percentage (default: 0.8 = 80%)
51
- * @property {number} maxConcurrentTiles - Max concurrent tiles for radial rasterization (default: 50)
52
51
  * @property {number} maxGPUMemoryMB - Maximum GPU memory per tile (default: 256MB)
53
- * @property {number} minTileSize - Minimum tile dimension (default: 50mm)
54
- * @property {number} radialRotationOffset - Radial mode: rotation offset in degrees (default: 0, use 90 to start at Z-axis)
55
52
  * @property {number} resolution - Grid step size in mm (required)
56
53
  * @property {number} rotationStep - Radial mode only: degrees between rays (e.g., 1.0 = 360 rays)
57
- * @property {number} trianglesPerTile - Target triangles per tile for radial rasterization (default: calculated)
58
54
  * @property {number} batchDivisor - Testing parameter to artificially divide batch size (default: 1)
59
55
  * @property {boolean} debug - Enable debug logging (default: false)
60
56
  * @property {boolean} quiet - Suppress log output (default: false)
@@ -110,14 +106,10 @@ export class RasterPath {
110
106
 
111
107
  // Configuration with defaults
112
108
  this.config = {
113
- workerName: config.workerName ?? "webgpu-worker.js",
109
+ workerName: config.workerName ?? "raster-worker.js",
114
110
  maxGPUMemoryMB: config.maxGPUMemoryMB ?? 256,
115
111
  gpuMemorySafetyMargin: config.gpuMemorySafetyMargin ?? 0.8,
116
112
  autoTiling: config.autoTiling ?? true,
117
- minTileSize: config.minTileSize ?? 50,
118
- maxConcurrentTiles: config.maxConcurrentTiles ?? 10,
119
- trianglesPerTile: config.trianglesPerTile, // undefined = auto-calculate
120
- radialRotationOffset: config.radialRotationOffset ?? 0, // degrees
121
113
  batchDivisor: config.batchDivisor ?? 1, // For testing batching overhead
122
114
  debug: config.debug,
123
115
  quiet: config.quiet
@@ -138,14 +130,14 @@ export class RasterPath {
138
130
 
139
131
  return new Promise((resolve, reject) => {
140
132
  try {
141
- // Create worker from the webgpu-worker.js file
133
+ // Create worker from the raster-worker.js file
142
134
  const workerName = this.config.workerName;
143
135
  const isBuildVersion = import.meta.url.includes('/build/') || import.meta.url.includes('raster-path.js');
144
136
  const workerPath = workerName
145
137
  ? new URL(workerName, import.meta.url)
146
138
  : isBuildVersion
147
- ? new URL(`./webgpu-worker.js`, import.meta.url)
148
- : new URL(`./web/webgpu-worker.js`, import.meta.url);
139
+ ? new URL(`./raster-worker.js`, import.meta.url)
140
+ : new URL(`../core/raster-worker.js`, import.meta.url);
149
141
  this.worker = new Worker(workerPath, { type: 'module' });
150
142
 
151
143
  // Set up message handler