rayzee 5.11.0 → 6.0.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/README.md +81 -24
- package/dist/assets/AIUpscalerWorker-AXN-lKWN.js +2 -0
- package/dist/assets/AIUpscalerWorker-AXN-lKWN.js.map +1 -0
- package/dist/rayzee.es.js +1233 -1803
- package/dist/rayzee.es.js.map +1 -1
- package/dist/rayzee.umd.js +50 -74
- package/dist/rayzee.umd.js.map +1 -1
- package/package.json +1 -4
- package/src/AssetConfig.js +56 -0
- package/src/EngineDefaults.js +5 -3
- package/src/EngineEvents.js +1 -0
- package/src/Passes/AIUpscaler.js +44 -22
- package/src/Passes/OIDNDenoiser.js +4 -104
- package/src/PathTracerApp.js +54 -65
- package/src/Processor/AssetLoader.js +5 -2
- package/src/Processor/Workers/AIUpscalerWorker.js +21 -6
- package/src/Stages/ASVGF.js +6 -27
- package/src/Stages/AdaptiveSampling.js +10 -26
- package/src/Stages/PathTracer.js +4 -5
- package/src/TSL/BVHTraversal.js +2 -18
- package/src/TSL/Clearcoat.js +1 -2
- package/src/TSL/Common.js +0 -13
- package/src/TSL/EmissiveSampling.js +0 -16
- package/src/TSL/Environment.js +0 -7
- package/src/TSL/LightsDirect.js +3 -379
- package/src/TSL/LightsSampling.js +0 -171
- package/src/TSL/MaterialEvaluation.js +3 -103
- package/src/TSL/MaterialProperties.js +1 -56
- package/src/TSL/MaterialSampling.js +2 -284
- package/src/TSL/MaterialTransmission.js +0 -93
- package/src/TSL/Random.js +0 -23
- package/src/TSL/Struct.js +0 -21
- package/src/TSL/TextureSampling.js +0 -69
- package/src/index.js +5 -2
- package/src/managers/DenoisingManager.js +13 -5
- package/src/managers/VideoRenderManager.js +4 -4
- package/dist/assets/AIUpscalerWorker-D58dcMrY.js +0 -2
- package/dist/assets/AIUpscalerWorker-D58dcMrY.js.map +0 -1
- package/src/Processor/createRenderTargetHelper.js +0 -521
- package/src/TSL/RayIntersection.js +0 -162
- package/src/managers/helpers/StatsHelper.js +0 -45
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ A real-time WebGPU path tracing engine built on Three.js. Framework-agnostic —
|
|
|
8
8
|
npm install rayzee three
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
`three` (>=0.183.0) is a required peer dependency.
|
|
11
|
+
`three` (>=0.183.0) is a required peer dependency.
|
|
12
12
|
|
|
13
13
|
## Getting Started
|
|
14
14
|
|
|
@@ -66,7 +66,9 @@ npm install rayzee three
|
|
|
66
66
|
// Use namespaced APIs and direct methods
|
|
67
67
|
engine.cameraManager.switchCamera(0);
|
|
68
68
|
engine.lightManager.add('PointLight');
|
|
69
|
-
|
|
69
|
+
|
|
70
|
+
// Capture the current frame as a Blob (host handles save/upload)
|
|
71
|
+
const blob = await engine.screenshot();
|
|
70
72
|
```
|
|
71
73
|
|
|
72
74
|
4. **Run**
|
|
@@ -92,7 +94,6 @@ A single HTML file — no Node.js, no build step. Uses [ES module import maps](h
|
|
|
92
94
|
"three/tsl": "https://cdn.jsdelivr.net/npm/three@0.183.0/build/three.tsl.js",
|
|
93
95
|
"three/webgpu": "https://cdn.jsdelivr.net/npm/three@0.183.0/build/three.webgpu.js",
|
|
94
96
|
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.183.0/examples/jsm/",
|
|
95
|
-
"stats-gl": "https://cdn.jsdelivr.net/npm/stats-gl@4.0.2/dist/main.js",
|
|
96
97
|
"oidn-web": "https://cdn.jsdelivr.net/npm/oidn-web@0.3.5/dist/oidn.js",
|
|
97
98
|
"rayzee": "https://cdn.jsdelivr.net/npm/rayzee/dist/rayzee.es.js"
|
|
98
99
|
}
|
|
@@ -217,6 +218,41 @@ export default defineConfig({
|
|
|
217
218
|
|
|
218
219
|
## API Reference
|
|
219
220
|
|
|
221
|
+
### Configuring Assets (CDN URLs & cache namespace)
|
|
222
|
+
|
|
223
|
+
By default, the engine loads STBN blue-noise atlases, GLTF Draco/KTX2 decoders, OIDN denoiser weights, ONNX upscaler models, and the onnxruntime-web bundle from upstream CDNs. If you're self-hosting, embedding the engine alongside a different consumer of the same caches, or operating offline, override them **once before constructing `PathTracerApp`**:
|
|
224
|
+
|
|
225
|
+
```js
|
|
226
|
+
import { configureAssets } from 'rayzee';
|
|
227
|
+
|
|
228
|
+
configureAssets({
|
|
229
|
+
// STBN atlases (PNG, decoded as Float textures)
|
|
230
|
+
stbnScalarAtlas: '/assets/stbn_scalar_atlas.png',
|
|
231
|
+
stbnVec2Atlas: '/assets/stbn_vec2_atlas.png',
|
|
232
|
+
|
|
233
|
+
// onnxruntime-web (loaded by AI upscaler worker via dynamic import)
|
|
234
|
+
ortRuntimeUrl: '/ort/ort.webgpu.bundle.min.mjs',
|
|
235
|
+
ortWasmPaths: '/ort/',
|
|
236
|
+
|
|
237
|
+
// GLTFLoader extension decoders
|
|
238
|
+
dracoDecoderPath: '/draco/',
|
|
239
|
+
ktx2TranscoderPath: '/basis/',
|
|
240
|
+
|
|
241
|
+
// Denoiser & upscaler weights
|
|
242
|
+
oidnWeightsBaseUrl: '/oidn-tzas/',
|
|
243
|
+
upscalerModelBaseUrl: '/upscaler-onnx/',
|
|
244
|
+
|
|
245
|
+
// Prefix for engine-managed IndexedDB stores. Set to a unique value if multiple
|
|
246
|
+
// apps embed the engine on the same origin to avoid cache collisions.
|
|
247
|
+
cacheNamespace: 'my-app',
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
const engine = new PathTracerApp(canvas);
|
|
251
|
+
await engine.init();
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
All keys are optional — only what you pass is overridden. Call `getAssetConfig()` to read the current values.
|
|
255
|
+
|
|
220
256
|
### PathTracerApp
|
|
221
257
|
|
|
222
258
|
The main engine class. Extends Three.js `EventDispatcher`. Related functionality is grouped into **namespaced managers** accessed via `engine.cameraManager`, `engine.lightManager`, etc., or as direct methods on the engine instance.
|
|
@@ -229,11 +265,9 @@ const engine = new PathTracerApp(canvas, options?)
|
|
|
229
265
|
|---|---|---|
|
|
230
266
|
| `canvas` | `HTMLCanvasElement` | Rendering target |
|
|
231
267
|
| `options.autoResize` | `boolean` | Auto-resize on window resize (default: `true`) |
|
|
232
|
-
| `options.
|
|
233
|
-
| `options.container` | `HTMLElement` | Single DOM parent the engine mounts auxiliary elements into — HUD overlay (tile borders, helpers), denoiser canvas, and stats panel. Defaults to `canvas.parentNode`. |
|
|
234
|
-
| `options.statsContainer` | `HTMLElement` | Override mount target for the stats panel only. Defaults to `options.container`. |
|
|
268
|
+
| `options.container` | `HTMLElement` | Single DOM parent the engine mounts auxiliary elements into — HUD overlay (tile borders, helpers) and denoiser canvas. Defaults to `canvas.parentNode`. |
|
|
235
269
|
|
|
236
|
-
The engine creates and mounts everything it needs (denoiser canvas, tile/HUD overlay
|
|
270
|
+
The engine creates and mounts everything it needs (denoiser canvas, tile/HUD overlay) into a single parent on `init()`. Performance HUDs (e.g. `stats-gl`) are not bundled — listen to `EngineEvents.FRAME` and tick your own panel.
|
|
237
271
|
|
|
238
272
|
#### Lifecycle
|
|
239
273
|
|
|
@@ -299,11 +333,12 @@ See `ENGINE_DEFAULTS` for the full list with default values.
|
|
|
299
333
|
#### Rendering Modes
|
|
300
334
|
|
|
301
335
|
```js
|
|
302
|
-
engine.configureForMode('
|
|
303
|
-
engine.configureForMode('
|
|
304
|
-
engine.configureForMode('results') // Paused rendering for image viewing
|
|
336
|
+
engine.configureForMode('production') // High quality (tiled, 20 bounces, OIDN, controls disabled)
|
|
337
|
+
engine.configureForMode('interactive') // Real-time navigation (3 bounces, controls enabled)
|
|
305
338
|
```
|
|
306
339
|
|
|
340
|
+
To pause rendering for image-viewing UI, set `engine.pauseRendering = true` and disable camera controls directly — the engine doesn't model viewport visibility.
|
|
341
|
+
|
|
307
342
|
---
|
|
308
343
|
|
|
309
344
|
### engine.cameraManager
|
|
@@ -358,10 +393,17 @@ engine.reset() // Re-upload all material data to GPU
|
|
|
358
393
|
engine.stages.pathTracer.materialData.updateMaterial(index, mat) // Replace a material
|
|
359
394
|
await engine.rebuildMaterials(scene) // Full rebuild (after texture changes)
|
|
360
395
|
|
|
361
|
-
// Per-mesh visibility (
|
|
362
|
-
|
|
363
|
-
engine.
|
|
364
|
-
|
|
396
|
+
// Per-mesh visibility — recommended UUID-based API (handles lookup + sync internally)
|
|
397
|
+
engine.setMeshVisibilityByUuid(uuid, true) // explicit set
|
|
398
|
+
engine.setMeshVisibilityByUuid(uuid, prev => !prev) // toggle via updater fn
|
|
399
|
+
// Returns the new visibility state, or null if the mesh wasn't found.
|
|
400
|
+
|
|
401
|
+
// Lower-level — for callers that already have a meshIndex or have mutated object.visible directly
|
|
402
|
+
engine.setMeshVisibility(meshIndex, visible)
|
|
403
|
+
engine.updateAllMeshVisibility() // re-sync after manual object.visible mutations
|
|
404
|
+
|
|
405
|
+
// Read access to the active scene (returns the mesh-bearing scene)
|
|
406
|
+
engine.getScene()
|
|
365
407
|
```
|
|
366
408
|
|
|
367
409
|
### engine.environmentManager
|
|
@@ -435,13 +477,24 @@ engine.transformManager.controls // Access the underlying TransformC
|
|
|
435
477
|
Canvas output, screenshots, and scene statistics — accessed as direct methods on the engine.
|
|
436
478
|
|
|
437
479
|
```js
|
|
438
|
-
engine.getCanvas()
|
|
439
|
-
engine.screenshot()
|
|
440
|
-
engine.
|
|
441
|
-
engine.
|
|
442
|
-
engine.
|
|
443
|
-
engine.
|
|
444
|
-
engine.
|
|
480
|
+
engine.getCanvas() // Get the canvas with the final rendered image
|
|
481
|
+
const blob = await engine.screenshot() // Capture frame as Blob (default 'image/png')
|
|
482
|
+
const jpg = await engine.screenshot({ type: 'image/jpeg', quality: 0.9 })
|
|
483
|
+
engine.getStatistics() // Triangle count, mesh count, etc.
|
|
484
|
+
engine.setCanvasSize(1920, 1080) // Set explicit canvas dimensions
|
|
485
|
+
engine.onResize() // Trigger manual resize recalculation
|
|
486
|
+
engine.isComplete() // Check if rendering has converged
|
|
487
|
+
engine.getFrameCount() // Get the current accumulated frame count
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
`screenshot()` returns a `Blob` for the host to save, upload, or display. To trigger a browser download:
|
|
491
|
+
|
|
492
|
+
```js
|
|
493
|
+
const blob = await engine.screenshot();
|
|
494
|
+
const url = URL.createObjectURL(blob);
|
|
495
|
+
const a = Object.assign(document.createElement('a'), { href: url, download: 'render.png' });
|
|
496
|
+
a.click();
|
|
497
|
+
URL.revokeObjectURL(url);
|
|
445
498
|
```
|
|
446
499
|
|
|
447
500
|
---
|
|
@@ -462,6 +515,7 @@ engine.addEventListener(EngineEvents.RENDER_COMPLETE, (e) => {
|
|
|
462
515
|
|---|---|
|
|
463
516
|
| `RENDER_COMPLETE` | Rendering has converged |
|
|
464
517
|
| `RENDER_RESET` | Accumulation buffer is reset |
|
|
518
|
+
| `FRAME` | Fires once per `animate()` tick — hook external instrumentation (stats panels, telemetry) here |
|
|
465
519
|
| `DENOISING_START` / `DENOISING_END` | Denoiser runs |
|
|
466
520
|
| `UPSCALING_START` / `UPSCALING_PROGRESS` / `UPSCALING_END` | AI upscaler runs |
|
|
467
521
|
| `LOADING_UPDATE` / `LOADING_RESET` | Asset loading progress |
|
|
@@ -519,10 +573,13 @@ import {
|
|
|
519
573
|
TEXTURE_CONSTANTS,
|
|
520
574
|
DEFAULT_TEXTURE_MATRIX,
|
|
521
575
|
MEMORY_CONSTANTS,
|
|
522
|
-
|
|
523
|
-
|
|
576
|
+
PRODUCTION_RENDER_CONFIG,
|
|
577
|
+
INTERACTIVE_RENDER_CONFIG,
|
|
524
578
|
} from 'rayzee';
|
|
525
579
|
|
|
580
|
+
// Asset URL / cache namespace overrides
|
|
581
|
+
import { configureAssets, getAssetConfig } from 'rayzee';
|
|
582
|
+
|
|
526
583
|
// Advanced: managers & pipeline
|
|
527
584
|
import {
|
|
528
585
|
RenderSettings,
|
|
@@ -588,7 +645,7 @@ OIDN provides high-quality AI denoising for final renders. It runs automatically
|
|
|
588
645
|
| `'balance'` | ~50 MB | Moderate | General use (default) |
|
|
589
646
|
| `'high'` | ~100 MB | Slowest | Final quality renders |
|
|
590
647
|
|
|
591
|
-
> **Note:** The neural network model is downloaded on first use. Subsequent runs use the browser cache. OIDN also works with `configureForMode('
|
|
648
|
+
> **Note:** The neural network model is downloaded on first use. Subsequent runs use the browser cache. OIDN also works with `configureForMode('production')`, which enables it automatically alongside high-quality render settings.
|
|
592
649
|
|
|
593
650
|
### Enabling the AI Upscaler
|
|
594
651
|
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
(function(){let e={ortRuntimeUrl:`https://cdn.jsdelivr.net/npm/onnxruntime-web@1.24.3/dist/ort.webgpu.bundle.min.mjs`,ortWasmPaths:`https://cdn.jsdelivr.net/npm/onnxruntime-web@1.24.3/dist/`,cacheNamespace:`rayzee`},t=null;async function n(){return t||(t=await import(e.ortRuntimeUrl),t.env.wasm.wasmPaths=e.ortWasmPaths,t.env.logLevel=`error`,t)}function r(){return`${e.cacheNamespace}:ai-upscaler-models`}let i=`models`,a=null,o=null;function s(){return new Promise((e,t)=>{let n=indexedDB.open(r(),1);n.onupgradeneeded=()=>n.result.createObjectStore(i),n.onsuccess=()=>e(n.result),n.onerror=()=>t(n.error)})}async function c(e){try{let t=await s();return await new Promise((n,r)=>{let a=t.transaction(i,`readonly`).objectStore(i).get(e);a.onsuccess=()=>n(a.result||null),a.onerror=()=>r(a.error)})}catch{return null}}async function l(e,t){try{let n=await s();await new Promise((r,a)=>{let o=n.transaction(i,`readwrite`);o.objectStore(i).put(t,e),o.oncomplete=()=>r(),o.onerror=()=>a(o.error)})}catch{}}async function u(e){let t=await c(e);if(t)return console.log(`AI Upscaler Worker: model loaded from cache (${(t.byteLength/1024/1024).toFixed(1)}MB)`),t;let n=await fetch(e);if(!n.ok)throw Error(`Failed to fetch model: ${n.status}`);let r=await n.arrayBuffer();return l(e,r.slice(0)),r}async function d(e,t){if(a&&o===e){self.postMessage({type:`loaded`,backend:`webgpu`});return}a&&=(await a.release(),null);let[r,i]=await Promise.all([u(e),n()]);a=await i.InferenceSession.create(r,t),o=e;let s=512;try{let e=await navigator.gpu?.requestAdapter(),t=await e?.requestAdapterInfo?.()||e?.info,n=/apple|swiftshader|llvmpipe/i.test(t?.vendor||``)||/apple|swiftshader/i.test(t?.architecture||``),r=t?.device?.toLowerCase?.()?.includes(`integrated`)||/intel.*iris|intel.*uhd|intel.*hd|amd.*vega|radeon.*graphics/i.test(t?.description||``);s=n?128:r?256:512,console.log(`AI Upscaler Worker: GPU="${t?.description||t?.device||`unknown`}", tileSize=${s}`)}catch{}let c=(r.byteLength/1024/1024).toFixed(1);console.log(`AI Upscaler Worker: model loaded (${c}MB), backend: webgpu`),self.postMessage({type:`loaded`,backend:`webgpu`,tileSize:s})}async function f(e,t,r,i){let o=await n(),s=a.inputNames[0],c=a.outputNames[0],l=new o.Tensor(`float32`,e,[1,3,r,t]),u=(await a.run({[s]:l}))[c].data;self.postMessage({type:`inferred`,outputData:u,id:i},[u.buffer])}self.onmessage=async t=>{let{type:n}=t.data;try{n===`load`?(t.data.ortRuntimeUrl&&(e.ortRuntimeUrl=t.data.ortRuntimeUrl),t.data.ortWasmPaths&&(e.ortWasmPaths=t.data.ortWasmPaths),t.data.cacheNamespace&&(e.cacheNamespace=t.data.cacheNamespace),await d(t.data.url,t.data.sessionOptions)):n===`infer`?await f(t.data.tileData,t.data.width,t.data.height,t.data.id):n===`dispose`&&a&&(await a.release(),a=null,o=null)}catch(e){self.postMessage({type:`error`,message:e.message,id:t.data?.id})}}})();
|
|
2
|
+
//# sourceMappingURL=AIUpscalerWorker-AXN-lKWN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AIUpscalerWorker-AXN-lKWN.js","names":[],"sources":["../../src/Processor/Workers/AIUpscalerWorker.js"],"sourcesContent":["/**\n * Web Worker for AI Upscaler inference.\n * Handles ONNX model loading and tile-based inference off the main thread.\n *\n * Messages:\n * Main → Worker:\n * { type: 'load', url, sessionOptions } — load/switch model\n * { type: 'infer', tileData, width, height, id } — run inference on a tile\n * { type: 'dispose' } — release session\n *\n * Worker → Main:\n * { type: 'loaded', backend }\n * { type: 'inferred', outputData, id }\n * { type: 'error', message, id? }\n */\n\n// Asset config supplied via 'load' message from the main thread.\n// Defaults match the upstream Rayzee deployment; override via configureAssets().\nlet _assetConfig = {\n\tortRuntimeUrl: 'https://cdn.jsdelivr.net/npm/onnxruntime-web@1.24.3/dist/ort.webgpu.bundle.min.mjs',\n\tortWasmPaths: 'https://cdn.jsdelivr.net/npm/onnxruntime-web@1.24.3/dist/',\n\tcacheNamespace: 'rayzee',\n};\n\nlet ort = null;\n\nasync function getOrt() {\n\n\tif ( ort ) return ort;\n\n\tort = await import( /* @vite-ignore */ _assetConfig.ortRuntimeUrl );\n\n\t// WASM paths for CDN delivery — WebGPU EP still uses WASM for lightweight shape ops\n\tort.env.wasm.wasmPaths = _assetConfig.ortWasmPaths;\n\tort.env.logLevel = 'error';\n\n\treturn ort;\n\n}\n\n// IndexedDB names are namespaced so multiple consumers on the same origin don't collide.\nfunction getIdbName() {\n\n\treturn `${_assetConfig.cacheNamespace}:ai-upscaler-models`;\n\n}\n\nconst IDB_STORE = 'models';\n\nlet session = null;\nlet currentModelUrl = null;\n\n// ─── IndexedDB Model Cache ───────────────────────────────────────────────────\n\nfunction openDB() {\n\n\treturn new Promise( ( resolve, reject ) => {\n\n\t\tconst req = indexedDB.open( getIdbName(), 1 );\n\t\treq.onupgradeneeded = () => req.result.createObjectStore( IDB_STORE );\n\t\treq.onsuccess = () => resolve( req.result );\n\t\treq.onerror = () => reject( req.error );\n\n\t} );\n\n}\n\nasync function getCachedModel( url ) {\n\n\ttry {\n\n\t\tconst db = await openDB();\n\t\treturn await new Promise( ( resolve, reject ) => {\n\n\t\t\tconst tx = db.transaction( IDB_STORE, 'readonly' );\n\t\t\tconst req = tx.objectStore( IDB_STORE ).get( url );\n\t\t\treq.onsuccess = () => resolve( req.result || null );\n\t\t\treq.onerror = () => reject( req.error );\n\n\t\t} );\n\n\t} catch {\n\n\t\treturn null;\n\n\t}\n\n}\n\nasync function cacheModel( url, buffer ) {\n\n\ttry {\n\n\t\tconst db = await openDB();\n\t\tawait new Promise( ( resolve, reject ) => {\n\n\t\t\tconst tx = db.transaction( IDB_STORE, 'readwrite' );\n\t\t\ttx.objectStore( IDB_STORE ).put( buffer, url );\n\t\t\ttx.oncomplete = () => resolve();\n\t\t\ttx.onerror = () => reject( tx.error );\n\n\t\t} );\n\n\t} catch {\n\n\t\t// Cache write failure is non-fatal\n\t}\n\n}\n\n// ─── Model Loading ───────────────────────────────────────────────────────────\n\nasync function fetchModel( url ) {\n\n\t// Try IndexedDB cache first\n\tconst cached = await getCachedModel( url );\n\tif ( cached ) {\n\n\t\tconsole.log( `AI Upscaler Worker: model loaded from cache (${( cached.byteLength / 1024 / 1024 ).toFixed( 1 )}MB)` );\n\t\treturn cached;\n\n\t}\n\n\t// Network fetch + cache\n\tconst response = await fetch( url );\n\tif ( ! response.ok ) throw new Error( `Failed to fetch model: ${response.status}` );\n\tconst buffer = await response.arrayBuffer();\n\n\t// Cache in background (don't block session creation)\n\tcacheModel( url, buffer.slice( 0 ) );\n\n\treturn buffer;\n\n}\n\nasync function loadModel( url, sessionOptions ) {\n\n\tif ( session && currentModelUrl === url ) {\n\n\t\tconst backend = 'webgpu';\n\t\tself.postMessage( { type: 'loaded', backend } );\n\t\treturn;\n\n\t}\n\n\t// Dispose previous session\n\tif ( session ) {\n\n\t\tawait session.release();\n\t\tsession = null;\n\n\t}\n\n\tconst [ modelBuffer, ortLib ] = await Promise.all( [ fetchModel( url ), getOrt() ] );\n\n\tsession = await ortLib.InferenceSession.create( modelBuffer, sessionOptions );\n\tcurrentModelUrl = url;\n\n\t// Detect GPU and recommend tile size based on device type\n\tlet tileSize = 512; // default\n\ttry {\n\n\t\tconst adapter = await navigator.gpu?.requestAdapter();\n\t\tconst info = await adapter?.requestAdapterInfo?.() || adapter?.info;\n\t\tconst isMobile = /apple|swiftshader|llvmpipe/i.test( info?.vendor || '' )\n\t\t\t|| /apple|swiftshader/i.test( info?.architecture || '' );\n\t\tconst isIntegrated = info?.device?.toLowerCase?.()?.includes( 'integrated' )\n\t\t\t|| /intel.*iris|intel.*uhd|intel.*hd|amd.*vega|radeon.*graphics/i.test( info?.description || '' );\n\n\t\tif ( isMobile ) {\n\n\t\t\ttileSize = 128;\n\n\t\t} else if ( isIntegrated ) {\n\n\t\t\ttileSize = 256;\n\n\t\t} else {\n\n\t\t\ttileSize = 512;\n\n\t\t}\n\n\t\tconsole.log( `AI Upscaler Worker: GPU=\"${info?.description || info?.device || 'unknown'}\", tileSize=${tileSize}` );\n\n\t} catch { /* fallback to default */ }\n\n\tconst sizeMB = ( modelBuffer.byteLength / 1024 / 1024 ).toFixed( 1 );\n\tconsole.log( `AI Upscaler Worker: model loaded (${sizeMB}MB), backend: webgpu` );\n\n\tself.postMessage( { type: 'loaded', backend: 'webgpu', tileSize } );\n\n}\n\nasync function inferTile( tileData, width, height, id ) {\n\n\tconst ortLib = await getOrt();\n\tconst inputName = session.inputNames[ 0 ];\n\tconst outputName = session.outputNames[ 0 ];\n\tconst inputTensor = new ortLib.Tensor( 'float32', tileData, [ 1, 3, height, width ] );\n\n\tconst results = await session.run( { [ inputName ]: inputTensor } );\n\tconst outputData = results[ outputName ].data;\n\n\t// Transfer the output buffer (zero-copy)\n\tself.postMessage( { type: 'inferred', outputData, id }, [ outputData.buffer ] );\n\n}\n\nself.onmessage = async ( e ) => {\n\n\tconst { type } = e.data;\n\n\ttry {\n\n\t\tif ( type === 'load' ) {\n\n\t\t\t// Apply asset overrides from main thread before any network or cache access\n\t\t\tif ( e.data.ortRuntimeUrl ) _assetConfig.ortRuntimeUrl = e.data.ortRuntimeUrl;\n\t\t\tif ( e.data.ortWasmPaths ) _assetConfig.ortWasmPaths = e.data.ortWasmPaths;\n\t\t\tif ( e.data.cacheNamespace ) _assetConfig.cacheNamespace = e.data.cacheNamespace;\n\t\t\tawait loadModel( e.data.url, e.data.sessionOptions );\n\n\t\t} else if ( type === 'infer' ) {\n\n\t\t\tawait inferTile( e.data.tileData, e.data.width, e.data.height, e.data.id );\n\n\t\t} else if ( type === 'dispose' ) {\n\n\t\t\tif ( session ) {\n\n\t\t\t\tawait session.release();\n\t\t\t\tsession = null;\n\t\t\t\tcurrentModelUrl = null;\n\n\t\t\t}\n\n\t\t}\n\n\t} catch ( error ) {\n\n\t\tself.postMessage( { type: 'error', message: error.message, id: e.data?.id } );\n\n\t}\n\n};\n"],"mappings":"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"}
|