longpipe 0.0.2 → 0.0.3
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/index.cjs +92 -92
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +92 -92
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
'use strict';var v=[{model:"xxs",dtype:"f16",resolution:{w:128,h:72},skipFrames:3},{model:"xs",dtype:"f16",resolution:{w:192,h:108},skipFrames:1},{model:"small",dtype:"f16",resolution:{w:256,h:144},skipFrames:1},{model:"compact",dtype:"f16",resolution:{w:256,h:144},skipFrames:1},{model:"medium",dtype:"f16",resolution:{w:256,h:144},skipFrames:1},{model:"large",dtype:"f32",resolution:{w:256,h:144},skipFrames:0},{model:"xl",dtype:"f32",resolution:{w:512,h:288},skipFrames:0}];var x=(...i)=>console.log("[longpipe/adaptive]",...i),Ze=2e3,et=1e4,tt=30,rt=20,nt=5e3,it=.3,at=15e3,E=class{constructor(t){this.opts=t;this.currentPresetIdx=v.findIndex(e=>e.model===t.initialModel),this.lastSwapAt=performance.now();}opts;timer=null;currentPresetIdx;lastSwapAt=0;overshootStart=0;headroomStart=0;start(){x(`started; backend=${this.opts.backendKind} initial=${this.opts.initialModel} idx=${this.currentPresetIdx}`),this.timer=setInterval(()=>{this.tick().catch(t=>x("tick failed:",t));},Ze);}stop(){this.timer&&clearInterval(this.timer),this.timer=null;}async tick(){if(typeof document<"u"&&document.hidden)return;let t=performance.now();if(t-this.lastSwapAt<et)return;let e=await this.opts.getStats();if(e.fps<rt?(this.overshootStart===0&&(this.overshootStart=t),t-this.overshootStart>=nt&&this.tryDowngrade(e.fps)):this.overshootStart=0,this.opts.backendKind==="webgpu"&&e.modelMs>0){let r=1e3/tt*it;e.modelMs<r?(this.headroomStart===0&&(this.headroomStart=t),t-this.headroomStart>=at&&this.tryUpgrade(e.modelMs,r)):this.headroomStart=0;}}tryDowngrade(t){if(this.currentPresetIdx<=0)return;let e=this.currentPresetIdx-1;x(`downgrade ${v[this.currentPresetIdx].model} \u2192 ${v[e].model} (fps=${t})`),this.swap(e);}tryUpgrade(t,e){if(this.currentPresetIdx>=v.length-1)return;let r=this.currentPresetIdx+1;x(`upgrade ${v[this.currentPresetIdx].model} \u2192 ${v[r].model} (modelMs=${t.toFixed(1)} < ${e.toFixed(1)})`),this.swap(r);}async swap(t){let e=v[t];this.lastSwapAt=performance.now(),this.overshootStart=0,this.headroomStart=0;try{let r=this.opts.buildWeightsUrl(this.opts.weightsBaseUrl,e.model),n=await fetch(r);if(!n.ok)throw new Error(`weights fetch failed: ${n.status} ${r}`);let a=await n.arrayBuffer();await this.opts.swapPreset(e.model,a),this.currentPresetIdx=t,x(`swap to ${e.model} done`);}catch(r){x("swap failed:",r),this.opts.onError?.({message:`adaptive preset swap failed: ${r.message??String(r)}`,source:"adaptive",recoverable:true,cause:r});}}};async function ne(i){let t,e=false;if(i instanceof HTMLVideoElement){if(t=i.currentSrc||i.src,!t)throw new Error("background video: HTMLVideoElement has no src")}else if(i instanceof Blob)t=URL.createObjectURL(i),e=true;else if(typeof i=="string")t=i;else throw new Error("background video: unsupported input shape");let r=document.createElement("video");r.crossOrigin="anonymous",r.muted=true,r.loop=true,r.playsInline=true,r.src=t,await new Promise((p,l)=>{r.addEventListener("loadeddata",()=>p(),{once:true}),r.addEventListener("error",()=>l(new Error(`background video: failed to load ${t}`)),{once:true});});try{await r.play();}catch(p){throw new Error(`background video: play() rejected \u2014 ${p.message}`)}let n=new MessageChannel,a=n.port1,s=n.port2,o=false,u=r.requestVideoFrameCallback?.bind(r);if(u){let p=(l,h)=>{if(!o){try{let g=new VideoFrame(r,{timestamp:h.mediaTime*1e6});a.postMessage({frame:g},[g]);}catch{}u(p);}};u(p);}else {let p=()=>{if(!o){try{let l=new VideoFrame(r,{timestamp:performance.now()*1e3});a.postMessage({frame:l},[l]);}catch{}requestAnimationFrame(p);}};requestAnimationFrame(p);}return {port:s,transferList:[s],cleanup:()=>{o=true,a.close(),r.pause(),r.removeAttribute("src"),r.load(),e&&URL.revokeObjectURL(t);}}}var Y=4,Q=8,ie=16;async function J(i){if(typeof i=="string")return i==="none"?{background:{kind:"none"}}:i==="blur"?{background:{kind:"blur",sigma:Q}}:{background:{kind:"image",bitmap:await se(i)}};if(i instanceof ImageBitmap)return {background:{kind:"image",bitmap:i}};if(typeof HTMLImageElement<"u"&&i instanceof HTMLImageElement)return {background:{kind:"image",bitmap:await createImageBitmap(i)}};if(typeof HTMLVideoElement<"u"&&i instanceof HTMLVideoElement)return await ae(i);let t=i;if(t.color)return {background:{kind:"color",rgb:t.color}};if(t.blur!==void 0)return {background:{kind:"blur",sigma:st(t.blur)}};if(t.image!==void 0)return {background:{kind:"image",bitmap:await ot(t.image)}};if(t.video!==void 0)return await ae(t.video);throw new Error(`background: unrecognized input shape \u2014 ${k(i)}`)}async function ae(i){let t;if(typeof i=="string")t=i;else if(typeof HTMLVideoElement<"u"&&i instanceof HTMLVideoElement)t=i;else if(i&&typeof i=="object"&&"data"in i&&"type"in i)t=i.data instanceof Blob?i.data:new Blob([i.data],{type:i.type});else throw new Error(`background.video: unrecognized shape \u2014 ${k(i)}`);let e=await ne(t);return {background:{kind:"video",port:e.port},transferList:e.transferList,cleanup:e.cleanup}}function st(i){if(i===true)return Q;if("sigma"in i){if(typeof i.sigma!="number"||!Number.isFinite(i.sigma)||i.sigma<0)throw new Error(`background.blur.sigma must be a non-negative number, got ${i.sigma}`);return i.sigma}if("strength"in i){let t=i.strength;if(typeof t=="number"){let e=Math.max(0,Math.min(1,t));return Y+(ie-Y)*e}if(t==="low")return Y;if(t==="medium")return Q;if(t==="high")return ie;throw new Error(`background.blur.strength must be 'low' | 'medium' | 'high' | number, got ${k(t)}`)}throw new Error(`background.blur: must be true, { strength }, or { sigma } \u2014 got ${k(i)}`)}async function ot(i){if(i instanceof ImageBitmap)return i;if(typeof HTMLImageElement<"u"&&i instanceof HTMLImageElement)return createImageBitmap(i);if(typeof i=="string")return se(i);if(i&&typeof i=="object"&&"data"in i&&"type"in i){let t=i.data instanceof Blob?i.data:new Blob([i.data],{type:i.type});return createImageBitmap(t)}throw new Error(`background.image: unrecognized shape \u2014 ${k(i)}`)}async function se(i){let t=await fetch(i);if(!t.ok)throw new Error(`background: failed to load image from ${i} (HTTP ${t.status})`);let e=await t.blob();return createImageBitmap(e)}function k(i){return i===null?"null":typeof i!="object"?typeof i+"("+String(i)+")":`${i.constructor?.name??"Object"} ${JSON.stringify(i).slice(0,80)}`}function oe(){return {input:"MediaStreamTrackProcessor"in self?"mstp":"rvfc-postmessage",output:"MediaStreamTrackGenerator"in self?"mstg":ut()?"transfer-capture":"bitmap-shuttle"}}var W=null;function ut(){return W!==null||(W=!/Firefox/.test(navigator.userAgent)),W}function ue(i,t,e){let r=[i];return e==="passthrough"&&r.push(...t.getAudioTracks()),new MediaStream(r)}var S=(...i)=>console.log("[longpipe/worker_controller]",...i),B=class{worker;listeners=new Map;persistentEvents=new Set;constructor(t){this.worker=t,this.worker.addEventListener("message",this.handleMessage.bind(this)),S("constructed; message listener attached");}handleMessage(t){let{request_id:e,res:r}=t.data,n=this.listeners.get(e);S("msg received: request_id=",e,"handler?",!!n,"persistent?",this.persistentEvents.has(e)),n&&(n(r),this.persistentEvents.has(e)||this.listeners.delete(e));}addPersistentListener(t,e){this.persistentEvents.add(t),this.listeners.set(t,e),S("addPersistentListener:",t);}removePersistentListener(t){this.persistentEvents.delete(t),this.listeners.delete(t);}sendMessage(t,e,r=[]){let n=crypto.randomUUID();return S("sendMessage:",t,"request_id=",n,"transferables=",r.length),new Promise(a=>{this.listeners.set(n,o=>a(o));let s={cmd:t,data:e,request_id:n};this.worker.postMessage(s,r);})}terminate(){this.worker.terminate(),this.listeners.clear(),this.persistentEvents.clear();}};function pe(i){let t=document.createElement("video");t.srcObject=i,t.muted=true,t.autoplay=true,t.playsInline=true,t.play().catch(c=>{console.warn("[input-postmessage/main] video.play() rejected:",c);});let e=t.requestVideoFrameCallback?.bind(t);if(!e)throw new Error("setupPostMessageInput: requestVideoFrameCallback not supported on this browser");let r=new MessageChannel,n=r.port1,a=r.port2,s=false,o=(c,p)=>{if(!s){try{let l=new VideoFrame(t,{timestamp:p.mediaTime*1e6});n.postMessage({frame:l},[l]);}catch(l){console.warn("[input-postmessage/main] VideoFrame() failed; skipping frame:",l);}e(o);}};return e(o),{port:a,transferList:[a],cleanup:()=>{s=true,n.close(),t.srcObject=null,t.pause();}}}function le(i){let t=i.getVideoTracks();if(t.length===0)throw new Error("setupMstpInput: input MediaStream has no video tracks");let e=t[0],r=self.MediaStreamTrackProcessor;if(!r)throw new Error("setupMstpInput: MediaStreamTrackProcessor not supported on this browser");let a=new r({track:e}).readable;return {readable:a,transferList:[a],cleanup:()=>{a.cancel().catch(()=>{});}}}function ce(i,t){switch(i){case "mstp":{let e=le(t);return {initFields:{inputReadable:e.readable},transferList:e.transferList,cleanup:e.cleanup}}case "rvfc-postmessage":{let e=pe(t);return {initFields:{inputPort:e.port},transferList:e.transferList,cleanup:e.cleanup}}}}function de(i,t=30){let e=document.createElement("canvas");e.width=i.w,e.height=i.h;let r=e.getContext("bitmaprenderer");if(!r)throw new Error("setupBitmapShuttleOutput: bitmaprenderer context not available");let a=e.captureStream(t).getVideoTracks();if(a.length===0)throw new Error("setupBitmapShuttleOutput: captureStream produced no video tracks");let s=a[0],o=new MessageChannel,u=o.port1,c=o.port2,p=false,l=null,h=()=>{},g=3,P=0;return u.onmessage=I=>{if(p){if(P++,P<g){I.data.bmp.close();return}h();}try{r.transferFromImageBitmap(I.data.bmp);}catch(m){console.warn("[bitmap-shuttle/main] transferFromImageBitmap failed:",m);}},u.start(),{videoTrack:s,port:c,transferList:[c],startPassthrough:I=>{if(p)return;p=true;let m=document.createElement("video");m.srcObject=I,m.muted=true,m.playsInline=true,m.play().catch(()=>{}),l=m;let T="requestVideoFrameCallback"in m?w=>{m.requestVideoFrameCallback(w);}:w=>{requestAnimationFrame(w);},U=()=>{if(p){if(m.videoWidth===0){T(U);return}createImageBitmap(m,{resizeWidth:e.width,resizeHeight:e.height,resizeQuality:"medium"}).then(w=>{if(!p){w.close();return}try{r.transferFromImageBitmap(w);}catch{}T(U);}).catch(()=>{T(U);});}};T(U),h=()=>{p=false,l&&(l.srcObject=null,l.pause(),l=null);};},cleanup:()=>{h(),u.onmessage=null,u.close(),s.stop();}}}function he(){let i=self.MediaStreamTrackGenerator;if(!i)throw new Error("setupMstgOutput: MediaStreamTrackGenerator not supported on this browser");let t=new i({kind:"video"}),e=t.writable;return {videoTrack:t,writable:e,transferList:[e],cleanup:()=>{e.abort().catch(()=>{}),t.stop();}}}function fe(i,t=30){let e=document.createElement("canvas");e.width=i.w,e.height=i.h;let n=e.captureStream(t).getVideoTracks();if(n.length===0)throw new Error("setupTransferCaptureOutput: captureStream produced no video tracks");let a=n[0],s=e.transferControlToOffscreen();return {videoTrack:a,canvas:s,transferList:[s],cleanup:()=>{a.stop();}}}function me(i,t){switch(i){case "mstg":{let e=he();return {videoTrack:e.videoTrack,initFields:{outputWritable:e.writable},transferList:e.transferList,cleanup:e.cleanup}}case "transfer-capture":{let e=fe(t);return {videoTrack:e.videoTrack,initFields:{outputCanvas:e.canvas},transferList:e.transferList,cleanup:e.cleanup}}case "bitmap-shuttle":{let e=de(t);return {videoTrack:e.videoTrack,initFields:{outputPort:e.port},transferList:e.transferList,startPassthrough:e.startPassthrough,cleanup:e.cleanup}}}}var Z=`var zt=Object.defineProperty;var Xt=(s,e,o)=>e in s?zt(s,e,{enumerable:!0,configurable:!0,writable:!0,value:o}):s[e]=o;var n=(s,e,o)=>Xt(s,typeof e!="symbol"?e+"":e,o);var Se=[{model:"xxs",dtype:"f16",resolution:{w:128,h:72},skipFrames:3},{model:"xs",dtype:"f16",resolution:{w:192,h:108},skipFrames:1},{model:"small",dtype:"f16",resolution:{w:256,h:144},skipFrames:1},{model:"compact",dtype:"f16",resolution:{w:256,h:144},skipFrames:1},{model:"medium",dtype:"f16",resolution:{w:256,h:144},skipFrames:1},{model:"large",dtype:"f32",resolution:{w:256,h:144},skipFrames:0},{model:"xl",dtype:"f32",resolution:{w:512,h:288},skipFrames:0}],$t={fast:1,balanced:4,quality:6};function H(s){return s==="auto"?null:Se[$t[s]]}var V=class{constructor(e,o,t,r){n(this,"op");this.op=e.ops.BilinearUpsample(o,{outH:t,outW:r})}get output(){return this.op.output}run(){this.op.run()}};var N=class{constructor(e,o,t,r){n(this,"op");this.op=e.ops.BicubicUpsample(o,{outH:t,outW:r})}get output(){return this.op.output}run(){this.op.run()}};var z=class{constructor(e,o,t,r){n(this,"presenter");this.presenter=e.presenters.CompositeSolid(o,t,r)}run(){this.presenter.run()}};var X=class{constructor(e,o,t,r){n(this,"presenter");this.presenter=e.presenters.CompositeImage(o,t,r)}run(){this.presenter.run()}};var $=class{constructor(e,o,t){n(this,"downs",[]);n(this,"ups",[]);let r=qt(t),i=o;for(let a=0;a<r;a++){let u=e.ops.BilinearUpsample(i,{outH:Math.max(1,Math.floor(i.h/2)),outW:Math.max(1,Math.floor(i.w/2))});this.downs.push(u),i=u.output}for(let a=r-1;a>=1;a--){let u=this.downs[a-1].output,p=e.ops.BilinearUpsample(i,{outH:u.h,outW:u.w});this.ups.push(p),i=p.output}}get output(){return this.ups.length>0?this.ups[this.ups.length-1].output:this.downs[0].output}run(){for(let e of this.downs)e.run();for(let e of this.ups)e.run()}};function qt(s){let e=Math.max(1,3*s);return Math.max(2,Math.min(6,Math.round(Math.log2(e))))}var q=class{constructor(e,o,t,r){n(this,"blur");n(this,"presenter");this.blur=new $(e,o,r),this.presenter=e.presenters.CompositeImageBilinear(o,t,this.blur.output)}run(){this.blur.run(),this.presenter.run()}};var j=class{constructor(e){n(this,"backend",e);n(this,"displayInput");n(this,"image");n(this,"passthroughCompositor");n(this,"network",null);n(this,"networkInput",null);n(this,"upscaler",null);n(this,"compositor",null);n(this,"upscalerMode","bilinear");n(this,"bgConfig",{mode:"solid",color:[0,0,0]});let o=e.canvas;this.displayInput=e.ops.Input(o.height,o.width),this.image=this.displayInput.output,this.passthroughCompositor=e.presenters.CompositePassthrough(this.image)}attachNetwork(e,o,t){this.network=e,this.networkInput=o,this.upscalerMode=t.upscaler,this.bgConfig=t.background,this.upscaler=this.makeUpscaler(),this.compositor=this.makeCompositor()}hasNetwork(){return this.network!==null}setSource(e){this.networkInput?.setSource(e),this.displayInput.setSource(e)}setUpscaler(e){e!==this.upscalerMode&&(this.upscalerMode=e,this.network&&(this.upscaler=this.makeUpscaler(),this.compositor=this.makeCompositor()))}setBackground(e){this.bgConfig=e,this.network&&(this.compositor=this.makeCompositor())}run(){this.runModel(),this.runDisplay()}runDisplay(){if(!this.compositor)throw new Error("RenderOp.runDisplay called before attachNetwork");this.displayInput.run(),this.compositor.run()}runPassthrough(){this.displayInput.run(),this.passthroughCompositor.run()}runModel(){if(!this.network||!this.networkInput||!this.upscaler)throw new Error("RenderOp.runModel called before attachNetwork");this.networkInput.run(),this.network.run(),this.upscaler.run()}makeUpscaler(){if(!this.network)throw new Error("makeUpscaler called with no network");let{backend:e,network:o,image:t}=this;return this.upscalerMode==="bicubic"?new N(e,o.output,t.h,t.w):new V(e,o.output,t.h,t.w)}makeCompositor(){if(!this.upscaler)throw new Error("makeCompositor called before upscaler exists");let{backend:e,image:o,upscaler:t,bgConfig:r}=this;switch(r.mode){case"solid":return new z(e,o,t.output,r.color);case"image":return new X(e,o,t.output,r.image);case"blur":return new q(e,o,t.output,r.sigma)}}};var jt=s=>typeof s=="object"&&s!==null&&typeof s.offset=="number"&&typeof s.length=="number";function Ee(s){if(s.byteLength<4)throw new Error("weights buffer too small");let e=new DataView(s,0,4).getUint32(0,!0),o=4+e;if(s.byteLength<o)throw new Error("weights buffer truncated (header)");let t=new Uint8Array(s,4,e),r=JSON.parse(new TextDecoder().decode(t)),i=r.__dtype__??"f32",a=i==="f16"?2:4;if(o%a!==0)throw new Error(\`payload not \${a}-byte aligned (header=\${e})\`);let u=(s.byteLength-o)/a,p=l=>{if(jt(l)){let{offset:d,length:m}=l;if(d+m>u)throw new Error(\`array ref out of range: offset=\${d} length=\${m}\`);let x=o+d*a;return i==="f16"?new Uint16Array(s,x,m):new Float32Array(s,x,m)}if(Array.isArray(l))return l.map(p);if(typeof l=="object"&&l!==null){let d={};for(let m of Object.keys(l))m!=="__dtype__"&&(d[m]=p(l[m]));return d}return l};return p(r)}var C=class{constructor(e,o,t,r){n(this,"inputs");n(this,"output");n(this,"dwOp");n(this,"pwOp");this.inputs=[o],this.dwOp=e.ops.DepthwiseConv2d(o,t.dw,{kernel:r.kernel,stride:r.stride,padding:r.padding,activation:"relu6"}),this.pwOp=e.ops.Conv2d(this.dwOp.output,t.pw,{outChannels:r.outChannels,kernel:1,stride:1,padding:0,activation:"none"}),this.output=this.pwOp.output}run(){this.dwOp.run(),this.pwOp.run()}};var c=class{constructor(e,o,t,r){n(this,"inputs");n(this,"output");n(this,"expandOp");n(this,"dwOp");n(this,"projOp");n(this,"addOp");this.inputs=[o];let i=r.midChannels!==r.inChannels,a=r.stride===1&&r.inChannels===r.outChannels;this.expandOp=i?e.ops.Conv2d(o,t.expand,{outChannels:r.midChannels,kernel:1,stride:1,padding:0,activation:"relu6"}):null;let u=this.expandOp?this.expandOp.output:o;this.dwOp=e.ops.DepthwiseConv2d(u,t.dw,{kernel:r.kernel,stride:r.stride,padding:r.padding,activation:"relu6"}),this.projOp=e.ops.Conv2d(this.dwOp.output,t.proj,{outChannels:r.outChannels,kernel:1,stride:1,padding:0,activation:"none"}),this.addOp=a?e.ops.Add(o,this.projOp.output):null,this.output=this.addOp?this.addOp.output:this.projOp.output}run(){this.expandOp?.run(),this.dwOp.run(),this.projOp.run(),this.addOp?.run()}};var y=class{constructor(e,o,t,r,i){n(this,"inputs");n(this,"output");n(this,"upConcatOp");n(this,"conv1Op");n(this,"conv2Op");this.inputs=[o,t],this.upConcatOp=e.ops.UpsampleConcat(o,t,{outH:t.h,outW:t.w}),this.conv1Op=e.ops.Conv2d(this.upConcatOp.output,r.conv1,{outChannels:i.outChannels,kernel:3,stride:1,padding:1,activation:"relu6"}),this.conv2Op=e.ops.Conv2d(this.conv1Op.output,r.conv2,{outChannels:i.outChannels,kernel:3,stride:1,padding:1,activation:"relu6"}),this.output=this.conv2Op.output}run(){this.upConcatOp.run(),this.conv1Op.run(),this.conv2Op.run()}};var P=class{constructor(e,o,t){n(this,"output");n(this,"stem");n(this,"s0");n(this,"s1b0");n(this,"s1b1");n(this,"s2b0");n(this,"s2b1");n(this,"s3b0");n(this,"s3b1");n(this,"s3b2");n(this,"s4b0");n(this,"s4b1");n(this,"s4b2");n(this,"s5b0");n(this,"s5b1");n(this,"s5b2");n(this,"s5b3");n(this,"s6b0");n(this,"bottleneck");n(this,"dec0");n(this,"dec1");n(this,"dec2");n(this,"finalUp");n(this,"outConv");n(this,"alpha");this.stem=e.ops.Conv2d(o,t.encoder.stem,{outChannels:32,kernel:3,stride:2,padding:"same",activation:"relu6"}),this.s0=new C(e,this.stem.output,t.encoder.s0,{outChannels:16,kernel:3,stride:1,padding:1}),this.s1b0=new c(e,this.s0.output,t.encoder.s1[0],{inChannels:16,midChannels:96,outChannels:24,kernel:3,stride:2,padding:"same"}),this.s1b1=new c(e,this.s1b0.output,t.encoder.s1[1],{inChannels:24,midChannels:144,outChannels:24,kernel:3,stride:1,padding:1}),this.s2b0=new c(e,this.s1b1.output,t.encoder.s2[0],{inChannels:24,midChannels:144,outChannels:40,kernel:5,stride:2,padding:"same"}),this.s2b1=new c(e,this.s2b0.output,t.encoder.s2[1],{inChannels:40,midChannels:240,outChannels:40,kernel:5,stride:1,padding:2}),this.s3b0=new c(e,this.s2b1.output,t.encoder.s3[0],{inChannels:40,midChannels:240,outChannels:80,kernel:3,stride:2,padding:"same"}),this.s3b1=new c(e,this.s3b0.output,t.encoder.s3[1],{inChannels:80,midChannels:480,outChannels:80,kernel:3,stride:1,padding:1}),this.s3b2=new c(e,this.s3b1.output,t.encoder.s3[2],{inChannels:80,midChannels:480,outChannels:80,kernel:3,stride:1,padding:1}),this.s4b0=new c(e,this.s3b2.output,t.encoder.s4[0],{inChannels:80,midChannels:480,outChannels:112,kernel:5,stride:1,padding:2}),this.s4b1=new c(e,this.s4b0.output,t.encoder.s4[1],{inChannels:112,midChannels:672,outChannels:112,kernel:5,stride:1,padding:2}),this.s4b2=new c(e,this.s4b1.output,t.encoder.s4[2],{inChannels:112,midChannels:672,outChannels:112,kernel:5,stride:1,padding:2}),this.s5b0=new c(e,this.s4b2.output,t.encoder.s5[0],{inChannels:112,midChannels:672,outChannels:192,kernel:5,stride:2,padding:"same"}),this.s5b1=new c(e,this.s5b0.output,t.encoder.s5[1],{inChannels:192,midChannels:1152,outChannels:192,kernel:5,stride:1,padding:2}),this.s5b2=new c(e,this.s5b1.output,t.encoder.s5[2],{inChannels:192,midChannels:1152,outChannels:192,kernel:5,stride:1,padding:2}),this.s5b3=new c(e,this.s5b2.output,t.encoder.s5[3],{inChannels:192,midChannels:1152,outChannels:192,kernel:5,stride:1,padding:2}),this.s6b0=new c(e,this.s5b3.output,t.encoder.s6[0],{inChannels:192,midChannels:1152,outChannels:320,kernel:3,stride:1,padding:1}),this.bottleneck=e.ops.Conv2d(this.s6b0.output,t.bottleneck,{outChannels:128,kernel:1,stride:1,padding:0,activation:"relu6"}),this.dec0=new y(e,this.bottleneck.output,this.s4b2.output,t.decoder.blocks[0],{outChannels:64}),this.dec1=new y(e,this.dec0.output,this.s2b1.output,t.decoder.blocks[1],{outChannels:32}),this.dec2=new y(e,this.dec1.output,this.s1b1.output,t.decoder.blocks[2],{outChannels:16}),this.finalUp=e.ops.UpsampleConv1x1(this.dec2.output,t.decoder.finalUpsample,{outH:this.dec2.output.h*2,outW:this.dec2.output.w*2,outChannels:16,activation:"relu6"}),this.outConv=e.ops.Conv2d(this.finalUp.output,t.decoder.outputConv,{outChannels:4,kernel:1,stride:1,padding:0,activation:"none"}),this.alpha=e.ops.UpsampleSigmoid(this.outConv.output,{outH:this.outConv.output.h*2,outW:this.outConv.output.w*2}),this.output=this.alpha.output}run(){this.stem.run(),this.s0.run(),this.s1b0.run(),this.s1b1.run(),this.s2b0.run(),this.s2b1.run(),this.s3b0.run(),this.s3b1.run(),this.s3b2.run(),this.s4b0.run(),this.s4b1.run(),this.s4b2.run(),this.s5b0.run(),this.s5b1.run(),this.s5b2.run(),this.s5b3.run(),this.s6b0.run(),this.bottleneck.run(),this.dec0.run(),this.dec1.run(),this.dec2.run(),this.finalUp.run(),this.outConv.run(),this.alpha.run()}};var S=class{constructor(e,o,t){n(this,"output");n(this,"stem");n(this,"s0");n(this,"s1b0");n(this,"s1b1");n(this,"s2b0");n(this,"s2b1");n(this,"s3b0");n(this,"s3b1");n(this,"s3b2");n(this,"s4b0");n(this,"s4b1");n(this,"s4b2");n(this,"s5b0");n(this,"s5b1");n(this,"s5b2");n(this,"s5b3");n(this,"s6b0");n(this,"bottleneck");n(this,"dec0");n(this,"dec1");n(this,"dec2");n(this,"finalUp");n(this,"outConv");n(this,"alpha");this.stem=e.ops.Conv2d(o,t.encoder.stem,{outChannels:32,kernel:3,stride:2,padding:"same",activation:"relu6"}),this.s0=new C(e,this.stem.output,t.encoder.s0,{outChannels:16,kernel:3,stride:1,padding:1}),this.s1b0=new c(e,this.s0.output,t.encoder.s1[0],{inChannels:16,midChannels:96,outChannels:24,kernel:3,stride:2,padding:"same"}),this.s1b1=new c(e,this.s1b0.output,t.encoder.s1[1],{inChannels:24,midChannels:144,outChannels:24,kernel:3,stride:1,padding:1}),this.s2b0=new c(e,this.s1b1.output,t.encoder.s2[0],{inChannels:24,midChannels:144,outChannels:40,kernel:5,stride:2,padding:"same"}),this.s2b1=new c(e,this.s2b0.output,t.encoder.s2[1],{inChannels:40,midChannels:240,outChannels:40,kernel:5,stride:1,padding:2}),this.s3b0=new c(e,this.s2b1.output,t.encoder.s3[0],{inChannels:40,midChannels:240,outChannels:80,kernel:3,stride:2,padding:"same"}),this.s3b1=new c(e,this.s3b0.output,t.encoder.s3[1],{inChannels:80,midChannels:480,outChannels:80,kernel:3,stride:1,padding:1}),this.s3b2=new c(e,this.s3b1.output,t.encoder.s3[2],{inChannels:80,midChannels:480,outChannels:80,kernel:3,stride:1,padding:1}),this.s4b0=new c(e,this.s3b2.output,t.encoder.s4[0],{inChannels:80,midChannels:480,outChannels:112,kernel:5,stride:1,padding:2}),this.s4b1=new c(e,this.s4b0.output,t.encoder.s4[1],{inChannels:112,midChannels:672,outChannels:112,kernel:5,stride:1,padding:2}),this.s4b2=new c(e,this.s4b1.output,t.encoder.s4[2],{inChannels:112,midChannels:672,outChannels:112,kernel:5,stride:1,padding:2}),this.s5b0=new c(e,this.s4b2.output,t.encoder.s5[0],{inChannels:112,midChannels:672,outChannels:192,kernel:5,stride:2,padding:"same"}),this.s5b1=new c(e,this.s5b0.output,t.encoder.s5[1],{inChannels:192,midChannels:1152,outChannels:192,kernel:5,stride:1,padding:2}),this.s5b2=new c(e,this.s5b1.output,t.encoder.s5[2],{inChannels:192,midChannels:1152,outChannels:192,kernel:5,stride:1,padding:2}),this.s5b3=new c(e,this.s5b2.output,t.encoder.s5[3],{inChannels:192,midChannels:1152,outChannels:192,kernel:5,stride:1,padding:2}),this.s6b0=new c(e,this.s5b3.output,t.encoder.s6[0],{inChannels:192,midChannels:1152,outChannels:320,kernel:3,stride:1,padding:1}),this.bottleneck=e.ops.Conv2d(this.s6b0.output,t.bottleneck,{outChannels:64,kernel:1,stride:1,padding:0,activation:"relu6"}),this.dec0=new y(e,this.bottleneck.output,this.s4b2.output,t.decoder.blocks[0],{outChannels:32}),this.dec1=new y(e,this.dec0.output,this.s2b1.output,t.decoder.blocks[1],{outChannels:16}),this.dec2=new y(e,this.dec1.output,this.s1b1.output,t.decoder.blocks[2],{outChannels:8}),this.finalUp=e.ops.UpsampleConv1x1(this.dec2.output,t.decoder.finalUpsample,{outH:this.dec2.output.h*2,outW:this.dec2.output.w*2,outChannels:8,activation:"relu6"}),this.outConv=e.ops.Conv2d(this.finalUp.output,t.decoder.outputConv,{outChannels:4,kernel:1,stride:1,padding:0,activation:"none"}),this.alpha=e.ops.UpsampleSigmoid(this.outConv.output,{outH:this.outConv.output.h*2,outW:this.outConv.output.w*2}),this.output=this.alpha.output}run(){this.stem.run(),this.s0.run(),this.s1b0.run(),this.s1b1.run(),this.s2b0.run(),this.s2b1.run(),this.s3b0.run(),this.s3b1.run(),this.s3b2.run(),this.s4b0.run(),this.s4b1.run(),this.s4b2.run(),this.s5b0.run(),this.s5b1.run(),this.s5b2.run(),this.s5b3.run(),this.s6b0.run(),this.bottleneck.run(),this.dec0.run(),this.dec1.run(),this.dec2.run(),this.finalUp.run(),this.outConv.run(),this.alpha.run()}};var k=class{constructor(e,o,t){n(this,"output");n(this,"stem");n(this,"s0");n(this,"s1b0");n(this,"s1b1");n(this,"s2b0");n(this,"s2b1");n(this,"s3b0");n(this,"s3b1");n(this,"s3b2");n(this,"s4b0");n(this,"s4b1");n(this,"s4b2");n(this,"bottleneck");n(this,"dec0");n(this,"dec1");n(this,"finalUp");n(this,"outConv");n(this,"alpha");this.stem=e.ops.Conv2d(o,t.encoder.stem,{outChannels:32,kernel:3,stride:2,padding:"same",activation:"relu6"}),this.s0=new C(e,this.stem.output,t.encoder.s0,{outChannels:16,kernel:3,stride:1,padding:1}),this.s1b0=new c(e,this.s0.output,t.encoder.s1[0],{inChannels:16,midChannels:96,outChannels:24,kernel:3,stride:2,padding:"same"}),this.s1b1=new c(e,this.s1b0.output,t.encoder.s1[1],{inChannels:24,midChannels:144,outChannels:24,kernel:3,stride:1,padding:1}),this.s2b0=new c(e,this.s1b1.output,t.encoder.s2[0],{inChannels:24,midChannels:144,outChannels:40,kernel:5,stride:2,padding:"same"}),this.s2b1=new c(e,this.s2b0.output,t.encoder.s2[1],{inChannels:40,midChannels:240,outChannels:40,kernel:5,stride:1,padding:2}),this.s3b0=new c(e,this.s2b1.output,t.encoder.s3[0],{inChannels:40,midChannels:240,outChannels:80,kernel:3,stride:2,padding:"same"}),this.s3b1=new c(e,this.s3b0.output,t.encoder.s3[1],{inChannels:80,midChannels:480,outChannels:80,kernel:3,stride:1,padding:1}),this.s3b2=new c(e,this.s3b1.output,t.encoder.s3[2],{inChannels:80,midChannels:480,outChannels:80,kernel:3,stride:1,padding:1}),this.s4b0=new c(e,this.s3b2.output,t.encoder.s4[0],{inChannels:80,midChannels:480,outChannels:112,kernel:5,stride:1,padding:2}),this.s4b1=new c(e,this.s4b0.output,t.encoder.s4[1],{inChannels:112,midChannels:672,outChannels:112,kernel:5,stride:1,padding:2}),this.s4b2=new c(e,this.s4b1.output,t.encoder.s4[2],{inChannels:112,midChannels:672,outChannels:112,kernel:5,stride:1,padding:2}),this.bottleneck=e.ops.Conv2d(this.s4b2.output,t.bottleneck,{outChannels:128,kernel:1,stride:1,padding:0,activation:"relu6"}),this.dec0=new y(e,this.bottleneck.output,this.s2b1.output,t.decoder.blocks[0],{outChannels:64}),this.dec1=new y(e,this.dec0.output,this.s1b1.output,t.decoder.blocks[1],{outChannels:32}),this.finalUp=e.ops.UpsampleConv1x1(this.dec1.output,t.decoder.finalUpsample,{outH:this.dec1.output.h*2,outW:this.dec1.output.w*2,outChannels:32,activation:"relu6"}),this.outConv=e.ops.Conv2d(this.finalUp.output,t.decoder.outputConv,{outChannels:4,kernel:1,stride:1,padding:0,activation:"none"}),this.alpha=e.ops.UpsampleSigmoid(this.outConv.output,{outH:this.outConv.output.h*2,outW:this.outConv.output.w*2}),this.output=this.alpha.output}run(){this.stem.run(),this.s0.run(),this.s1b0.run(),this.s1b1.run(),this.s2b0.run(),this.s2b1.run(),this.s3b0.run(),this.s3b1.run(),this.s3b2.run(),this.s4b0.run(),this.s4b1.run(),this.s4b2.run(),this.bottleneck.run(),this.dec0.run(),this.dec1.run(),this.finalUp.run(),this.outConv.run(),this.alpha.run()}};var E=class{constructor(e,o,t){n(this,"output");n(this,"stem");n(this,"s0");n(this,"s1b0");n(this,"s1b1");n(this,"s2b0");n(this,"s2b1");n(this,"s3b0");n(this,"s3b1");n(this,"s3b2");n(this,"s4b0");n(this,"s4b1");n(this,"s4b2");n(this,"s5b0");n(this,"s5b1");n(this,"s5b2");n(this,"s5b3");n(this,"s6b0");n(this,"bottleneck");n(this,"dec0");n(this,"dec1");n(this,"dec2");n(this,"finalUp");n(this,"outConv");n(this,"alpha");this.stem=e.ops.Conv2d(o,t.encoder.stem,{outChannels:32,kernel:3,stride:2,padding:"same",activation:"relu6"}),this.s0=new C(e,this.stem.output,t.encoder.s0,{outChannels:16,kernel:3,stride:1,padding:1}),this.s1b0=new c(e,this.s0.output,t.encoder.s1[0],{inChannels:16,midChannels:96,outChannels:24,kernel:3,stride:2,padding:"same"}),this.s1b1=new c(e,this.s1b0.output,t.encoder.s1[1],{inChannels:24,midChannels:144,outChannels:24,kernel:3,stride:1,padding:1}),this.s2b0=new c(e,this.s1b1.output,t.encoder.s2[0],{inChannels:24,midChannels:144,outChannels:40,kernel:5,stride:2,padding:"same"}),this.s2b1=new c(e,this.s2b0.output,t.encoder.s2[1],{inChannels:40,midChannels:240,outChannels:40,kernel:5,stride:1,padding:2}),this.s3b0=new c(e,this.s2b1.output,t.encoder.s3[0],{inChannels:40,midChannels:240,outChannels:80,kernel:3,stride:2,padding:"same"}),this.s3b1=new c(e,this.s3b0.output,t.encoder.s3[1],{inChannels:80,midChannels:480,outChannels:80,kernel:3,stride:1,padding:1}),this.s3b2=new c(e,this.s3b1.output,t.encoder.s3[2],{inChannels:80,midChannels:480,outChannels:80,kernel:3,stride:1,padding:1}),this.s4b0=new c(e,this.s3b2.output,t.encoder.s4[0],{inChannels:80,midChannels:480,outChannels:112,kernel:5,stride:1,padding:2}),this.s4b1=new c(e,this.s4b0.output,t.encoder.s4[1],{inChannels:112,midChannels:672,outChannels:112,kernel:5,stride:1,padding:2}),this.s4b2=new c(e,this.s4b1.output,t.encoder.s4[2],{inChannels:112,midChannels:672,outChannels:112,kernel:5,stride:1,padding:2}),this.s5b0=new c(e,this.s4b2.output,t.encoder.s5[0],{inChannels:112,midChannels:672,outChannels:192,kernel:5,stride:2,padding:"same"}),this.s5b1=new c(e,this.s5b0.output,t.encoder.s5[1],{inChannels:192,midChannels:1152,outChannels:192,kernel:5,stride:1,padding:2}),this.s5b2=new c(e,this.s5b1.output,t.encoder.s5[2],{inChannels:192,midChannels:1152,outChannels:192,kernel:5,stride:1,padding:2}),this.s5b3=new c(e,this.s5b2.output,t.encoder.s5[3],{inChannels:192,midChannels:1152,outChannels:192,kernel:5,stride:1,padding:2}),this.s6b0=new c(e,this.s5b3.output,t.encoder.s6[0],{inChannels:192,midChannels:1152,outChannels:320,kernel:3,stride:1,padding:1}),this.bottleneck=e.ops.Conv2d(this.s6b0.output,t.bottleneck,{outChannels:256,kernel:1,stride:1,padding:0,activation:"relu6"}),this.dec0=new y(e,this.bottleneck.output,this.s4b2.output,t.decoder.blocks[0],{outChannels:128}),this.dec1=new y(e,this.dec0.output,this.s2b1.output,t.decoder.blocks[1],{outChannels:64}),this.dec2=new y(e,this.dec1.output,this.s1b1.output,t.decoder.blocks[2],{outChannels:32}),this.finalUp=e.ops.UpsampleConv1x1(this.dec2.output,t.decoder.finalUpsample,{outH:this.dec2.output.h*2,outW:this.dec2.output.w*2,outChannels:32,activation:"relu6"}),this.outConv=e.ops.Conv2d(this.finalUp.output,t.decoder.outputConv,{outChannels:4,kernel:1,stride:1,padding:0,activation:"none"}),this.alpha=e.ops.UpsampleSigmoid(this.outConv.output,{outH:this.outConv.output.h*2,outW:this.outConv.output.w*2}),this.output=this.alpha.output}run(){this.stem.run(),this.s0.run(),this.s1b0.run(),this.s1b1.run(),this.s2b0.run(),this.s2b1.run(),this.s3b0.run(),this.s3b1.run(),this.s3b2.run(),this.s4b0.run(),this.s4b1.run(),this.s4b2.run(),this.s5b0.run(),this.s5b1.run(),this.s5b2.run(),this.s5b3.run(),this.s6b0.run(),this.bottleneck.run(),this.dec0.run(),this.dec1.run(),this.dec2.run(),this.finalUp.run(),this.outConv.run(),this.alpha.run()}};var Kt=5,Yt={xxs:k,xs:k,small:k,compact:S,medium:P,large:P,xl:E},Ie=1e3,K=class{constructor(e){n(this,"canvas");n(this,"backend");n(this,"backendKind");n(this,"topology");n(this,"preset",null);n(this,"enabled");n(this,"currentBackground");n(this,"modelTimingCounter",0);n(this,"renderOp");n(this,"bgImageInput",null);n(this,"bgVideoInput",null);n(this,"bgVideoPort",null);n(this,"skipCounter",0);n(this,"framesRenderedAt",[]);n(this,"modelRunSamples",[]);n(this,"displayRunSamples",[]);n(this,"skippedCount",0);this.backend=e.backend,this.backendKind=e.backendKind,this.canvas=e.canvas,this.enabled=e.enabled,this.currentBackground=e.background,this.topology=e.topology,this.renderOp=new j(this.backend)}process(e){if(this.renderOp.setSource(e),!this.enabled||this.currentBackground.kind==="none"||!this.renderOp.hasNetwork()){this.renderOp.runPassthrough(),this.framesRenderedAt.push(performance.now()),this.trim(this.framesRenderedAt);return}if(this.shouldRunModel()){let t=performance.now();this.renderOp.runModel(),this.backendKind==="webgpu"&&this.modelTimingCounter%Kt===0&&this.backend.sync().then(()=>{this.modelRunSamples.push({ts:performance.now(),ms:performance.now()-t}),this.trimSamples(this.modelRunSamples)}).catch(()=>{}),this.modelTimingCounter++}else this.skippedCount++;let o=performance.now();this.renderOp.runDisplay(),this.displayRunSamples.push({ts:performance.now(),ms:performance.now()-o}),this.trimSamples(this.displayRunSamples),this.framesRenderedAt.push(performance.now()),this.trim(this.framesRenderedAt)}shouldRunModel(){return this.skipCounter===0?(this.skipCounter=this.preset?.skipFrames??0,!0):(this.skipCounter--,!1)}setBackground(e){this.currentBackground=e,this.renderOp.setBackground(this.translateBackground(e))}setEnabled(e){this.enabled=e}setPreset(e,o){let t=Yt[e.model];if(!t)throw new Error(\`renderer: model '\${e.model}' not implemented in src/model/networks/\`);let r=Ee(o),i=this.backend.ops.Input(e.resolution.h,e.resolution.w),a=new t(this.backend,i.output,r);this.renderOp.attachNetwork(a,i,{upscaler:"bilinear",background:this.translateBackground(this.currentBackground)}),this.preset=e,this.skipCounter=0}destroy(){this.bgVideoPort&&(this.bgVideoPort.close(),this.bgVideoPort=null),this.backend.destroy()}getStats(){let e=performance.now();return this.trimRecent(this.framesRenderedAt,e),this.trimSamplesAt(this.modelRunSamples,e),this.trimSamplesAt(this.displayRunSamples,e),{fps:this.framesRenderedAt.length,modelFps:this.modelRunSamples.length,modelMs:Le(this.modelRunSamples.map(o=>o.ms)),displayMs:Le(this.displayRunSamples.map(o=>o.ms)),skipped:this.skippedCount,preset:this.preset?.model??"boot",skipFrames:this.preset?.skipFrames??0,enabled:this.enabled,inputPath:this.topology.input,outputPath:this.topology.output}}translateBackground(e){switch(e.kind!=="video"&&this.bgVideoPort&&(this.bgVideoPort.close(),this.bgVideoPort=null),e.kind){case"none":return{mode:"solid",color:[0,0,0]};case"color":return{mode:"solid",color:e.rgb};case"blur":return{mode:"blur",sigma:e.sigma};case"image":return this.bgImageInput||(this.bgImageInput=this.backend.ops.Input(this.canvas.height,this.canvas.width)),this.bgImageInput.setSource(e.bitmap),this.bgImageInput.run(),{mode:"image",image:this.bgImageInput.output};case"video":{this.bgVideoInput||(this.bgVideoInput=this.backend.ops.Input(this.canvas.height,this.canvas.width)),this.bgVideoPort&&this.bgVideoPort.close(),this.bgVideoPort=e.port;let o=this.bgVideoInput;return e.port.onmessage=t=>{let r=t.data.frame;try{o.setSource(r),o.run()}finally{r.close()}},e.port.start?.(),{mode:"image",image:this.bgVideoInput.output}}}}trim(e){e.length>240&&e.splice(0,e.length-240)}trimSamples(e){e.length>240&&e.splice(0,e.length-240)}trimRecent(e,o){let t=o-Ie,r=0;for(;r<e.length&&e[r]<t;)r++;r>0&&e.splice(0,r)}trimSamplesAt(e,o){let t=o-Ie,r=0;for(;r<e.length&&e[r].ts<t;)r++;r>0&&e.splice(0,r)}};function Le(s){if(s.length===0)return 0;let e=s.slice().sort((t,r)=>t-r),o=e.length>>1;return e.length%2?e[o]:(e[o-1]+e[o])/2}var I=new Float32Array(1),R=new Uint32Array(I.buffer);function Qt(s){I[0]=s;let e=R[0],o=e>>>16&32768,t=e&2147483647,r=(t>>>23)-127+15;if((e&2139095040)===2139095040)return(e&8388607)!==0?o|32256:o|31744;if(r>=31)return o|31744;if(r<=0){if(r<-10)return o;let l=t&8388607|8388608,d=14-r,m=l>>>d,x=l>>>d-1&1,T=(l&(1<<d-1)-1)!==0?1:0;return x&&(T||m&1)&&(m+=1),o|m}let i=t>>>13&1023,a=t>>>12&1,u=(t&4095)!==0?1:0,p=r<<10|i;return a&&(u||i&1)&&(p+=1,(p>>>10&31)===31)?o|31744:o|p}function Jt(s){let e=(s&32768)<<16,o=(s&31744)>>>10,t=s&1023;if(o===0){if(t===0)return R[0]=e,I[0];let r=t,i=1;for(;(r&1024)===0;)r<<=1,i-=1;return r&=1023,R[0]=e|i+127-15<<23|r<<13,I[0]}return o===31?(R[0]=e|2139095040|t<<13,I[0]):(R[0]=e|o+127-15<<23|t<<13,I[0])}function Y(s){let e=new Uint16Array(s.length);for(let o=0;o<s.length;o++)e[o]=Qt(s[o]);return e}function L(s){let e=new Float32Array(s.length);for(let o=0;o<s.length;o++)e[o]=Jt(s[o]);return e}var h=class{constructor(e){n(this,"backend",e);n(this,"shader","");n(this,"pipeline");n(this,"bindGroup");n(this,"uniformDefs",[]);n(this,"uniformBuffers",{})}createUniform(e,o){this.uniformDefs.push({name:e,type:o})}setUniform(e,o){let t=this.backend.device.createBuffer({size:o.byteLength,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST,mappedAtCreation:!0});o instanceof Uint32Array?new Uint32Array(t.getMappedRange()).set(o):new Float32Array(t.getMappedRange()).set(o),t.unmap(),this.uniformBuffers[e]=t}defaultBindGroup(){let e=[],o=0;for(let t of this.inputs)e.push({binding:o++,resource:{buffer:t.buffer}});for(let t of this.weights)e.push({binding:o++,resource:{buffer:t.buffer}});for(let t of this.uniformDefs)e.push({binding:o++,resource:{buffer:this.uniformBuffers[t.name]}});return e.push({binding:o,resource:{buffer:this.output.buffer}}),this.backend.device.createBindGroup({layout:this.pipeline.getBindGroupLayout(0),entries:e})}defaultSetup(){let e=this.backend.device.createShaderModule({code:this.shader});this.pipeline=this.backend.device.createComputePipeline({layout:"auto",compute:{module:e,entryPoint:"main"}}),this.bindGroup=this.defaultBindGroup()}run(){let e=this.backend.device.createCommandEncoder(),o=e.beginComputePass();o.setPipeline(this.pipeline),o.setBindGroup(0,this.bindGroup),o.dispatchWorkgroups(...this.dispatch),o.end(),this.backend.device.queue.submit([e.finish()])}};var Ae=\`// Conv2d compute shader \\u2014 handles all variants:
|
|
1
|
+
'use strict';var w=[{model:"xxs",dtype:"f16",resolution:{w:128,h:72},skipFrames:3},{model:"xs",dtype:"f16",resolution:{w:192,h:108},skipFrames:1},{model:"small",dtype:"f16",resolution:{w:256,h:144},skipFrames:1},{model:"compact",dtype:"f16",resolution:{w:256,h:144},skipFrames:1},{model:"medium",dtype:"f16",resolution:{w:256,h:144},skipFrames:1},{model:"large",dtype:"f32",resolution:{w:256,h:144},skipFrames:0},{model:"xl",dtype:"f32",resolution:{w:512,h:288},skipFrames:0}];var Q=false;function se(i){Q=i;}function _(i){let t=`[longpipe/${i}]`,e=((...r)=>{Q&&console.log(t,...r);});return e.warn=(...r)=>{Q&&console.warn(t,...r);},e}var k=_("adaptive"),it=2e3,at=1e4,st=30,ot=20,ut=5e3,pt=.3,lt=15e3,W=class{constructor(t){this.opts=t;this.currentPresetIdx=w.findIndex(e=>e.model===t.initialModel),this.lastSwapAt=performance.now();}opts;timer=null;currentPresetIdx;lastSwapAt=0;overshootStart=0;headroomStart=0;start(){k(`started; backend=${this.opts.backendKind} initial=${this.opts.initialModel} idx=${this.currentPresetIdx}`),this.timer=setInterval(()=>{this.tick().catch(t=>k("tick failed:",t));},it);}stop(){this.timer&&clearInterval(this.timer),this.timer=null;}async tick(){if(typeof document<"u"&&document.hidden)return;let t=performance.now();if(t-this.lastSwapAt<at)return;let e=await this.opts.getStats();if(e.fps<ot?(this.overshootStart===0&&(this.overshootStart=t),t-this.overshootStart>=ut&&this.tryDowngrade(e.fps)):this.overshootStart=0,this.opts.backendKind==="webgpu"&&e.modelMs>0){let r=1e3/st*pt;e.modelMs<r?(this.headroomStart===0&&(this.headroomStart=t),t-this.headroomStart>=lt&&this.tryUpgrade(e.modelMs,r)):this.headroomStart=0;}}tryDowngrade(t){if(this.currentPresetIdx<=0)return;let e=this.currentPresetIdx-1;k(`downgrade ${w[this.currentPresetIdx].model} \u2192 ${w[e].model} (fps=${t})`),this.swap(e);}tryUpgrade(t,e){if(this.currentPresetIdx>=w.length-1)return;let r=this.currentPresetIdx+1;k(`upgrade ${w[this.currentPresetIdx].model} \u2192 ${w[r].model} (modelMs=${t.toFixed(1)} < ${e.toFixed(1)})`),this.swap(r);}async swap(t){let e=w[t];this.lastSwapAt=performance.now(),this.overshootStart=0,this.headroomStart=0;try{let r=this.opts.buildWeightsUrl(this.opts.weightsBaseUrl,e.model),n=await fetch(r);if(!n.ok)throw new Error(`weights fetch failed: ${n.status} ${r}`);let a=await n.arrayBuffer();await this.opts.swapPreset(e.model,a),this.currentPresetIdx=t,k(`swap to ${e.model} done`);}catch(r){k("swap failed:",r),this.opts.onError?.({message:`adaptive preset swap failed: ${r.message??String(r)}`,source:"adaptive",recoverable:true,cause:r});}}};async function oe(i){let t,e=false;if(i instanceof HTMLVideoElement){if(t=i.currentSrc||i.src,!t)throw new Error("background video: HTMLVideoElement has no src")}else if(i instanceof Blob)t=URL.createObjectURL(i),e=true;else if(typeof i=="string")t=i;else throw new Error("background video: unsupported input shape");let r=document.createElement("video");r.crossOrigin="anonymous",r.muted=true,r.loop=true,r.playsInline=true,r.src=t,await new Promise((p,l)=>{r.addEventListener("loadeddata",()=>p(),{once:true}),r.addEventListener("error",()=>l(new Error(`background video: failed to load ${t}`)),{once:true});});try{await r.play();}catch(p){throw new Error(`background video: play() rejected \u2014 ${p.message}`)}let n=new MessageChannel,a=n.port1,s=n.port2,o=false,u=r.requestVideoFrameCallback?.bind(r);if(u){let p=(l,h)=>{if(!o){try{let g=new VideoFrame(r,{timestamp:h.mediaTime*1e6});a.postMessage({frame:g},[g]);}catch{}u(p);}};u(p);}else {let p=()=>{if(!o){try{let l=new VideoFrame(r,{timestamp:performance.now()*1e3});a.postMessage({frame:l},[l]);}catch{}requestAnimationFrame(p);}};requestAnimationFrame(p);}return {port:s,transferList:[s],cleanup:()=>{o=true,a.close(),r.pause(),r.removeAttribute("src"),r.load(),e&&URL.revokeObjectURL(t);}}}var Z=4,ee=8,ue=16;async function te(i){if(typeof i=="string")return i==="none"?{background:{kind:"none"}}:i==="blur"?{background:{kind:"blur",sigma:ee}}:{background:{kind:"image",bitmap:await le(i)}};if(i instanceof ImageBitmap)return {background:{kind:"image",bitmap:i}};if(typeof HTMLImageElement<"u"&&i instanceof HTMLImageElement)return {background:{kind:"image",bitmap:await createImageBitmap(i)}};if(typeof HTMLVideoElement<"u"&&i instanceof HTMLVideoElement)return await pe(i);let t=i;if(t.color)return {background:{kind:"color",rgb:t.color}};if(t.blur!==void 0)return {background:{kind:"blur",sigma:ct(t.blur)}};if(t.image!==void 0)return {background:{kind:"image",bitmap:await dt(t.image)}};if(t.video!==void 0)return await pe(t.video);throw new Error(`background: unrecognized input shape \u2014 ${P(i)}`)}async function pe(i){let t;if(typeof i=="string")t=i;else if(typeof HTMLVideoElement<"u"&&i instanceof HTMLVideoElement)t=i;else if(i&&typeof i=="object"&&"data"in i&&"type"in i)t=i.data instanceof Blob?i.data:new Blob([i.data],{type:i.type});else throw new Error(`background.video: unrecognized shape \u2014 ${P(i)}`);let e=await oe(t);return {background:{kind:"video",port:e.port},transferList:e.transferList,cleanup:e.cleanup}}function ct(i){if(i===true)return ee;if("sigma"in i){if(typeof i.sigma!="number"||!Number.isFinite(i.sigma)||i.sigma<0)throw new Error(`background.blur.sigma must be a non-negative number, got ${i.sigma}`);return i.sigma}if("strength"in i){let t=i.strength;if(typeof t=="number"){let e=Math.max(0,Math.min(1,t));return Z+(ue-Z)*e}if(t==="low")return Z;if(t==="medium")return ee;if(t==="high")return ue;throw new Error(`background.blur.strength must be 'low' | 'medium' | 'high' | number, got ${P(t)}`)}throw new Error(`background.blur: must be true, { strength }, or { sigma } \u2014 got ${P(i)}`)}async function dt(i){if(i instanceof ImageBitmap)return i;if(typeof HTMLImageElement<"u"&&i instanceof HTMLImageElement)return createImageBitmap(i);if(typeof i=="string")return le(i);if(i&&typeof i=="object"&&"data"in i&&"type"in i){let t=i.data instanceof Blob?i.data:new Blob([i.data],{type:i.type});return createImageBitmap(t)}throw new Error(`background.image: unrecognized shape \u2014 ${P(i)}`)}async function le(i){let t=await fetch(i);if(!t.ok)throw new Error(`background: failed to load image from ${i} (HTTP ${t.status})`);let e=await t.blob();return createImageBitmap(e)}function P(i){return i===null?"null":typeof i!="object"?typeof i+"("+String(i)+")":`${i.constructor?.name??"Object"} ${JSON.stringify(i).slice(0,80)}`}function ce(){return {input:"MediaStreamTrackProcessor"in self?"mstp":"rvfc-postmessage",output:"MediaStreamTrackGenerator"in self?"mstg":ht()?"transfer-capture":"bitmap-shuttle"}}var B=null;function ht(){return B!==null||(B=!/Firefox/.test(navigator.userAgent)),B}function de(i,t,e){let r=[i];return e==="passthrough"&&r.push(...t.getAudioTracks()),new MediaStream(r)}var G=_("worker_controller"),A=class{worker;listeners=new Map;persistentEvents=new Set;constructor(t){this.worker=t,this.worker.addEventListener("message",this.handleMessage.bind(this)),G("constructed; message listener attached");}handleMessage(t){let{request_id:e,res:r}=t.data,n=this.listeners.get(e);G("msg received: request_id=",e,"handler?",!!n,"persistent?",this.persistentEvents.has(e)),n&&(n(r),this.persistentEvents.has(e)||this.listeners.delete(e));}addPersistentListener(t,e){this.persistentEvents.add(t),this.listeners.set(t,e),G("addPersistentListener:",t);}removePersistentListener(t){this.persistentEvents.delete(t),this.listeners.delete(t);}sendMessage(t,e,r=[]){let n=crypto.randomUUID();return G("sendMessage:",t,"request_id=",n,"transferables=",r.length),new Promise(a=>{this.listeners.set(n,o=>a(o));let s={cmd:t,data:e,request_id:n};this.worker.postMessage(s,r);})}terminate(){this.worker.terminate(),this.listeners.clear(),this.persistentEvents.clear();}};var he=_("input-postmessage/main");function fe(i){let t=document.createElement("video");t.srcObject=i,t.muted=true,t.autoplay=true,t.playsInline=true,t.play().catch(c=>{he.warn("video.play() rejected:",c);});let e=t.requestVideoFrameCallback?.bind(t);if(!e)throw new Error("setupPostMessageInput: requestVideoFrameCallback not supported on this browser");let r=new MessageChannel,n=r.port1,a=r.port2,s=false,o=(c,p)=>{if(!s){try{let l=new VideoFrame(t,{timestamp:p.mediaTime*1e6});n.postMessage({frame:l},[l]);}catch(l){he.warn("VideoFrame() failed; skipping frame:",l);}e(o);}};return e(o),{port:a,transferList:[a],cleanup:()=>{s=true,n.close(),t.srcObject=null,t.pause();}}}function me(i){let t=i.getVideoTracks();if(t.length===0)throw new Error("setupMstpInput: input MediaStream has no video tracks");let e=t[0],r=self.MediaStreamTrackProcessor;if(!r)throw new Error("setupMstpInput: MediaStreamTrackProcessor not supported on this browser");let a=new r({track:e}).readable;return {readable:a,transferList:[a],cleanup:()=>{a.cancel().catch(()=>{});}}}function ge(i,t){switch(i){case "mstp":{let e=me(t);return {initFields:{inputReadable:e.readable},transferList:e.transferList,cleanup:e.cleanup}}case "rvfc-postmessage":{let e=fe(t);return {initFields:{inputPort:e.port},transferList:e.transferList,cleanup:e.cleanup}}}}var ft=_("bitmap-shuttle/main"),mt=30;function _e(i,t=mt){let e=document.createElement("canvas");e.width=i.w,e.height=i.h;let r=e.getContext("bitmaprenderer");if(!r)throw new Error("setupBitmapShuttleOutput: bitmaprenderer context not available");let a=e.captureStream(t).getVideoTracks();if(a.length===0)throw new Error("setupBitmapShuttleOutput: captureStream produced no video tracks");let s=a[0],o=new MessageChannel,u=o.port1,c=o.port2,p=false,l=null,h=()=>{},g=3,T=0;return u.onmessage=U=>{if(p){if(T++,T<g){U.data.bmp.close();return}h();}try{r.transferFromImageBitmap(U.data.bmp);}catch(m){ft.warn("transferFromImageBitmap failed:",m);}},u.start(),{videoTrack:s,port:c,transferList:[c],startPassthrough:U=>{if(p)return;p=true;let m=document.createElement("video");m.srcObject=U,m.muted=true,m.playsInline=true,m.play().catch(()=>{}),l=m;let S="requestVideoFrameCallback"in m?y=>{m.requestVideoFrameCallback(y);}:y=>{requestAnimationFrame(y);},E=()=>{if(p){if(m.videoWidth===0){S(E);return}createImageBitmap(m,{resizeWidth:e.width,resizeHeight:e.height,resizeQuality:"medium"}).then(y=>{if(!p){y.close();return}try{r.transferFromImageBitmap(y);}catch{}S(E);}).catch(()=>{S(E);});}};S(E),h=()=>{p=false,l&&(l.srcObject=null,l.pause(),l=null);};},cleanup:()=>{h(),u.onmessage=null,u.close(),s.stop();}}}function be(){let i=self.MediaStreamTrackGenerator;if(!i)throw new Error("setupMstgOutput: MediaStreamTrackGenerator not supported on this browser");let t=new i({kind:"video"}),e=t.writable;return {videoTrack:t,writable:e,transferList:[e],cleanup:()=>{e.abort().catch(()=>{}),t.stop();}}}function ve(i,t=30){let e=document.createElement("canvas");e.width=i.w,e.height=i.h;let n=e.captureStream(t).getVideoTracks();if(n.length===0)throw new Error("setupTransferCaptureOutput: captureStream produced no video tracks");let a=n[0],s=e.transferControlToOffscreen();return {videoTrack:a,canvas:s,transferList:[s],cleanup:()=>{a.stop();}}}function we(i,t){switch(i){case "mstg":{let e=be();return {videoTrack:e.videoTrack,initFields:{outputWritable:e.writable},transferList:e.transferList,cleanup:e.cleanup}}case "transfer-capture":{let e=ve(t);return {videoTrack:e.videoTrack,initFields:{outputCanvas:e.canvas},transferList:e.transferList,cleanup:e.cleanup}}case "bitmap-shuttle":{let e=_e(t);return {videoTrack:e.videoTrack,initFields:{outputPort:e.port},transferList:e.transferList,startPassthrough:e.startPassthrough,cleanup:e.cleanup}}}}var re=`var jt=Object.defineProperty;var Kt=(s,e,r)=>e in s?jt(s,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):s[e]=r;var n=(s,e,r)=>Kt(s,typeof e!="symbol"?e+"":e,r);var Ee=!1;function Ae(s){Ee=s}function P(s){let e=\`[longpipe/\${s}]\`,r=((...t)=>{Ee&&console.log(e,...t)});return r.warn=(...t)=>{Ee&&console.warn(e,...t)},r}var Ie=[{model:"xxs",dtype:"f16",resolution:{w:128,h:72},skipFrames:3},{model:"xs",dtype:"f16",resolution:{w:192,h:108},skipFrames:1},{model:"small",dtype:"f16",resolution:{w:256,h:144},skipFrames:1},{model:"compact",dtype:"f16",resolution:{w:256,h:144},skipFrames:1},{model:"medium",dtype:"f16",resolution:{w:256,h:144},skipFrames:1},{model:"large",dtype:"f32",resolution:{w:256,h:144},skipFrames:0},{model:"xl",dtype:"f32",resolution:{w:512,h:288},skipFrames:0}],Yt={fast:1,balanced:4,quality:6};function V(s){return s==="auto"?null:Ie[Yt[s]]}var N=class{constructor(e,r,t,o){n(this,"op");this.op=e.ops.BilinearUpsample(r,{outH:t,outW:o})}get output(){return this.op.output}run(){this.op.run()}};var z=class{constructor(e,r,t,o){n(this,"op");this.op=e.ops.BicubicUpsample(r,{outH:t,outW:o})}get output(){return this.op.output}run(){this.op.run()}};var X=class{constructor(e,r,t,o){n(this,"presenter");this.presenter=e.presenters.CompositeSolid(r,t,o)}run(){this.presenter.run()}};var $=class{constructor(e,r,t,o){n(this,"presenter");this.presenter=e.presenters.CompositeImage(r,t,o)}run(){this.presenter.run()}};var q=class{constructor(e,r,t){n(this,"downs",[]);n(this,"ups",[]);let o=Qt(t),i=r;for(let a=0;a<o;a++){let u=e.ops.BilinearUpsample(i,{outH:Math.max(1,Math.floor(i.h/2)),outW:Math.max(1,Math.floor(i.w/2))});this.downs.push(u),i=u.output}for(let a=o-1;a>=1;a--){let u=this.downs[a-1].output,p=e.ops.BilinearUpsample(i,{outH:u.h,outW:u.w});this.ups.push(p),i=p.output}}get output(){return this.ups.length>0?this.ups[this.ups.length-1].output:this.downs[0].output}run(){for(let e of this.downs)e.run();for(let e of this.ups)e.run()}};function Qt(s){let e=Math.max(1,3*s);return Math.max(2,Math.min(6,Math.round(Math.log2(e))))}var j=class{constructor(e,r,t,o){n(this,"blur");n(this,"presenter");this.blur=new q(e,r,o),this.presenter=e.presenters.CompositeImageBilinear(r,t,this.blur.output)}run(){this.blur.run(),this.presenter.run()}};var K=class{constructor(e){n(this,"backend",e);n(this,"displayInput");n(this,"image");n(this,"passthroughCompositor");n(this,"network",null);n(this,"networkInput",null);n(this,"upscaler",null);n(this,"compositor",null);n(this,"upscalerMode","bilinear");n(this,"bgConfig",{mode:"solid",color:[0,0,0]});let r=e.canvas;this.displayInput=e.ops.Input(r.height,r.width),this.image=this.displayInput.output,this.passthroughCompositor=e.presenters.CompositePassthrough(this.image)}attachNetwork(e,r,t){this.network=e,this.networkInput=r,this.upscalerMode=t.upscaler,this.bgConfig=t.background,this.upscaler=this.makeUpscaler(),this.compositor=this.makeCompositor()}hasNetwork(){return this.network!==null}setSource(e){this.networkInput?.setSource(e),this.displayInput.setSource(e)}setUpscaler(e){e!==this.upscalerMode&&(this.upscalerMode=e,this.network&&(this.upscaler=this.makeUpscaler(),this.compositor=this.makeCompositor()))}setBackground(e){this.bgConfig=e,this.network&&(this.compositor=this.makeCompositor())}run(){this.runModel(),this.runDisplay()}runDisplay(){if(!this.compositor)throw new Error("RenderOp.runDisplay called before attachNetwork");this.displayInput.run(),this.compositor.run()}runPassthrough(){this.displayInput.run(),this.passthroughCompositor.run()}runModel(){if(!this.network||!this.networkInput||!this.upscaler)throw new Error("RenderOp.runModel called before attachNetwork");this.networkInput.run(),this.network.run(),this.upscaler.run()}makeUpscaler(){if(!this.network)throw new Error("makeUpscaler called with no network");let{backend:e,network:r,image:t}=this;return this.upscalerMode==="bicubic"?new z(e,r.output,t.h,t.w):new N(e,r.output,t.h,t.w)}makeCompositor(){if(!this.upscaler)throw new Error("makeCompositor called before upscaler exists");let{backend:e,image:r,upscaler:t,bgConfig:o}=this;switch(o.mode){case"solid":return new X(e,r,t.output,o.color);case"image":return new $(e,r,t.output,o.image);case"blur":return new j(e,r,t.output,o.sigma)}}};var Jt=s=>typeof s=="object"&&s!==null&&typeof s.offset=="number"&&typeof s.length=="number";function Fe(s){if(s.byteLength<4)throw new Error("weights buffer too small");let e=new DataView(s,0,4).getUint32(0,!0),r=4+e;if(s.byteLength<r)throw new Error("weights buffer truncated (header)");let t=new Uint8Array(s,4,e),o=JSON.parse(new TextDecoder().decode(t)),i=o.__dtype__??"f32",a=i==="f16"?2:4;if(r%a!==0)throw new Error(\`payload not \${a}-byte aligned (header=\${e})\`);let u=(s.byteLength-r)/a,p=l=>{if(Jt(l)){let{offset:d,length:m}=l;if(d+m>u)throw new Error(\`array ref out of range: offset=\${d} length=\${m}\`);let x=r+d*a;return i==="f16"?new Uint16Array(s,x,m):new Float32Array(s,x,m)}if(Array.isArray(l))return l.map(p);if(typeof l=="object"&&l!==null){let d={};for(let m of Object.keys(l))m!=="__dtype__"&&(d[m]=p(l[m]));return d}return l};return p(o)}var C=class{constructor(e,r,t,o){n(this,"inputs");n(this,"output");n(this,"dwOp");n(this,"pwOp");this.inputs=[r],this.dwOp=e.ops.DepthwiseConv2d(r,t.dw,{kernel:o.kernel,stride:o.stride,padding:o.padding,activation:"relu6"}),this.pwOp=e.ops.Conv2d(this.dwOp.output,t.pw,{outChannels:o.outChannels,kernel:1,stride:1,padding:0,activation:"none"}),this.output=this.pwOp.output}run(){this.dwOp.run(),this.pwOp.run()}};var c=class{constructor(e,r,t,o){n(this,"inputs");n(this,"output");n(this,"expandOp");n(this,"dwOp");n(this,"projOp");n(this,"addOp");this.inputs=[r];let i=o.midChannels!==o.inChannels,a=o.stride===1&&o.inChannels===o.outChannels;this.expandOp=i?e.ops.Conv2d(r,t.expand,{outChannels:o.midChannels,kernel:1,stride:1,padding:0,activation:"relu6"}):null;let u=this.expandOp?this.expandOp.output:r;this.dwOp=e.ops.DepthwiseConv2d(u,t.dw,{kernel:o.kernel,stride:o.stride,padding:o.padding,activation:"relu6"}),this.projOp=e.ops.Conv2d(this.dwOp.output,t.proj,{outChannels:o.outChannels,kernel:1,stride:1,padding:0,activation:"none"}),this.addOp=a?e.ops.Add(r,this.projOp.output):null,this.output=this.addOp?this.addOp.output:this.projOp.output}run(){this.expandOp?.run(),this.dwOp.run(),this.projOp.run(),this.addOp?.run()}};var y=class{constructor(e,r,t,o,i){n(this,"inputs");n(this,"output");n(this,"upConcatOp");n(this,"conv1Op");n(this,"conv2Op");this.inputs=[r,t],this.upConcatOp=e.ops.UpsampleConcat(r,t,{outH:t.h,outW:t.w}),this.conv1Op=e.ops.Conv2d(this.upConcatOp.output,o.conv1,{outChannels:i.outChannels,kernel:3,stride:1,padding:1,activation:"relu6"}),this.conv2Op=e.ops.Conv2d(this.conv1Op.output,o.conv2,{outChannels:i.outChannels,kernel:3,stride:1,padding:1,activation:"relu6"}),this.output=this.conv2Op.output}run(){this.upConcatOp.run(),this.conv1Op.run(),this.conv2Op.run()}};var W=class{constructor(e,r,t){n(this,"output");n(this,"stem");n(this,"s0");n(this,"s1b0");n(this,"s1b1");n(this,"s2b0");n(this,"s2b1");n(this,"s3b0");n(this,"s3b1");n(this,"s3b2");n(this,"s4b0");n(this,"s4b1");n(this,"s4b2");n(this,"s5b0");n(this,"s5b1");n(this,"s5b2");n(this,"s5b3");n(this,"s6b0");n(this,"bottleneck");n(this,"dec0");n(this,"dec1");n(this,"dec2");n(this,"finalUp");n(this,"outConv");n(this,"alpha");this.stem=e.ops.Conv2d(r,t.encoder.stem,{outChannels:32,kernel:3,stride:2,padding:"same",activation:"relu6"}),this.s0=new C(e,this.stem.output,t.encoder.s0,{outChannels:16,kernel:3,stride:1,padding:1}),this.s1b0=new c(e,this.s0.output,t.encoder.s1[0],{inChannels:16,midChannels:96,outChannels:24,kernel:3,stride:2,padding:"same"}),this.s1b1=new c(e,this.s1b0.output,t.encoder.s1[1],{inChannels:24,midChannels:144,outChannels:24,kernel:3,stride:1,padding:1}),this.s2b0=new c(e,this.s1b1.output,t.encoder.s2[0],{inChannels:24,midChannels:144,outChannels:40,kernel:5,stride:2,padding:"same"}),this.s2b1=new c(e,this.s2b0.output,t.encoder.s2[1],{inChannels:40,midChannels:240,outChannels:40,kernel:5,stride:1,padding:2}),this.s3b0=new c(e,this.s2b1.output,t.encoder.s3[0],{inChannels:40,midChannels:240,outChannels:80,kernel:3,stride:2,padding:"same"}),this.s3b1=new c(e,this.s3b0.output,t.encoder.s3[1],{inChannels:80,midChannels:480,outChannels:80,kernel:3,stride:1,padding:1}),this.s3b2=new c(e,this.s3b1.output,t.encoder.s3[2],{inChannels:80,midChannels:480,outChannels:80,kernel:3,stride:1,padding:1}),this.s4b0=new c(e,this.s3b2.output,t.encoder.s4[0],{inChannels:80,midChannels:480,outChannels:112,kernel:5,stride:1,padding:2}),this.s4b1=new c(e,this.s4b0.output,t.encoder.s4[1],{inChannels:112,midChannels:672,outChannels:112,kernel:5,stride:1,padding:2}),this.s4b2=new c(e,this.s4b1.output,t.encoder.s4[2],{inChannels:112,midChannels:672,outChannels:112,kernel:5,stride:1,padding:2}),this.s5b0=new c(e,this.s4b2.output,t.encoder.s5[0],{inChannels:112,midChannels:672,outChannels:192,kernel:5,stride:2,padding:"same"}),this.s5b1=new c(e,this.s5b0.output,t.encoder.s5[1],{inChannels:192,midChannels:1152,outChannels:192,kernel:5,stride:1,padding:2}),this.s5b2=new c(e,this.s5b1.output,t.encoder.s5[2],{inChannels:192,midChannels:1152,outChannels:192,kernel:5,stride:1,padding:2}),this.s5b3=new c(e,this.s5b2.output,t.encoder.s5[3],{inChannels:192,midChannels:1152,outChannels:192,kernel:5,stride:1,padding:2}),this.s6b0=new c(e,this.s5b3.output,t.encoder.s6[0],{inChannels:192,midChannels:1152,outChannels:320,kernel:3,stride:1,padding:1}),this.bottleneck=e.ops.Conv2d(this.s6b0.output,t.bottleneck,{outChannels:128,kernel:1,stride:1,padding:0,activation:"relu6"}),this.dec0=new y(e,this.bottleneck.output,this.s4b2.output,t.decoder.blocks[0],{outChannels:64}),this.dec1=new y(e,this.dec0.output,this.s2b1.output,t.decoder.blocks[1],{outChannels:32}),this.dec2=new y(e,this.dec1.output,this.s1b1.output,t.decoder.blocks[2],{outChannels:16}),this.finalUp=e.ops.UpsampleConv1x1(this.dec2.output,t.decoder.finalUpsample,{outH:this.dec2.output.h*2,outW:this.dec2.output.w*2,outChannels:16,activation:"relu6"}),this.outConv=e.ops.Conv2d(this.finalUp.output,t.decoder.outputConv,{outChannels:4,kernel:1,stride:1,padding:0,activation:"none"}),this.alpha=e.ops.UpsampleSigmoid(this.outConv.output,{outH:this.outConv.output.h*2,outW:this.outConv.output.w*2}),this.output=this.alpha.output}run(){this.stem.run(),this.s0.run(),this.s1b0.run(),this.s1b1.run(),this.s2b0.run(),this.s2b1.run(),this.s3b0.run(),this.s3b1.run(),this.s3b2.run(),this.s4b0.run(),this.s4b1.run(),this.s4b2.run(),this.s5b0.run(),this.s5b1.run(),this.s5b2.run(),this.s5b3.run(),this.s6b0.run(),this.bottleneck.run(),this.dec0.run(),this.dec1.run(),this.dec2.run(),this.finalUp.run(),this.outConv.run(),this.alpha.run()}};var E=class{constructor(e,r,t){n(this,"output");n(this,"stem");n(this,"s0");n(this,"s1b0");n(this,"s1b1");n(this,"s2b0");n(this,"s2b1");n(this,"s3b0");n(this,"s3b1");n(this,"s3b2");n(this,"s4b0");n(this,"s4b1");n(this,"s4b2");n(this,"s5b0");n(this,"s5b1");n(this,"s5b2");n(this,"s5b3");n(this,"s6b0");n(this,"bottleneck");n(this,"dec0");n(this,"dec1");n(this,"dec2");n(this,"finalUp");n(this,"outConv");n(this,"alpha");this.stem=e.ops.Conv2d(r,t.encoder.stem,{outChannels:32,kernel:3,stride:2,padding:"same",activation:"relu6"}),this.s0=new C(e,this.stem.output,t.encoder.s0,{outChannels:16,kernel:3,stride:1,padding:1}),this.s1b0=new c(e,this.s0.output,t.encoder.s1[0],{inChannels:16,midChannels:96,outChannels:24,kernel:3,stride:2,padding:"same"}),this.s1b1=new c(e,this.s1b0.output,t.encoder.s1[1],{inChannels:24,midChannels:144,outChannels:24,kernel:3,stride:1,padding:1}),this.s2b0=new c(e,this.s1b1.output,t.encoder.s2[0],{inChannels:24,midChannels:144,outChannels:40,kernel:5,stride:2,padding:"same"}),this.s2b1=new c(e,this.s2b0.output,t.encoder.s2[1],{inChannels:40,midChannels:240,outChannels:40,kernel:5,stride:1,padding:2}),this.s3b0=new c(e,this.s2b1.output,t.encoder.s3[0],{inChannels:40,midChannels:240,outChannels:80,kernel:3,stride:2,padding:"same"}),this.s3b1=new c(e,this.s3b0.output,t.encoder.s3[1],{inChannels:80,midChannels:480,outChannels:80,kernel:3,stride:1,padding:1}),this.s3b2=new c(e,this.s3b1.output,t.encoder.s3[2],{inChannels:80,midChannels:480,outChannels:80,kernel:3,stride:1,padding:1}),this.s4b0=new c(e,this.s3b2.output,t.encoder.s4[0],{inChannels:80,midChannels:480,outChannels:112,kernel:5,stride:1,padding:2}),this.s4b1=new c(e,this.s4b0.output,t.encoder.s4[1],{inChannels:112,midChannels:672,outChannels:112,kernel:5,stride:1,padding:2}),this.s4b2=new c(e,this.s4b1.output,t.encoder.s4[2],{inChannels:112,midChannels:672,outChannels:112,kernel:5,stride:1,padding:2}),this.s5b0=new c(e,this.s4b2.output,t.encoder.s5[0],{inChannels:112,midChannels:672,outChannels:192,kernel:5,stride:2,padding:"same"}),this.s5b1=new c(e,this.s5b0.output,t.encoder.s5[1],{inChannels:192,midChannels:1152,outChannels:192,kernel:5,stride:1,padding:2}),this.s5b2=new c(e,this.s5b1.output,t.encoder.s5[2],{inChannels:192,midChannels:1152,outChannels:192,kernel:5,stride:1,padding:2}),this.s5b3=new c(e,this.s5b2.output,t.encoder.s5[3],{inChannels:192,midChannels:1152,outChannels:192,kernel:5,stride:1,padding:2}),this.s6b0=new c(e,this.s5b3.output,t.encoder.s6[0],{inChannels:192,midChannels:1152,outChannels:320,kernel:3,stride:1,padding:1}),this.bottleneck=e.ops.Conv2d(this.s6b0.output,t.bottleneck,{outChannels:64,kernel:1,stride:1,padding:0,activation:"relu6"}),this.dec0=new y(e,this.bottleneck.output,this.s4b2.output,t.decoder.blocks[0],{outChannels:32}),this.dec1=new y(e,this.dec0.output,this.s2b1.output,t.decoder.blocks[1],{outChannels:16}),this.dec2=new y(e,this.dec1.output,this.s1b1.output,t.decoder.blocks[2],{outChannels:8}),this.finalUp=e.ops.UpsampleConv1x1(this.dec2.output,t.decoder.finalUpsample,{outH:this.dec2.output.h*2,outW:this.dec2.output.w*2,outChannels:8,activation:"relu6"}),this.outConv=e.ops.Conv2d(this.finalUp.output,t.decoder.outputConv,{outChannels:4,kernel:1,stride:1,padding:0,activation:"none"}),this.alpha=e.ops.UpsampleSigmoid(this.outConv.output,{outH:this.outConv.output.h*2,outW:this.outConv.output.w*2}),this.output=this.alpha.output}run(){this.stem.run(),this.s0.run(),this.s1b0.run(),this.s1b1.run(),this.s2b0.run(),this.s2b1.run(),this.s3b0.run(),this.s3b1.run(),this.s3b2.run(),this.s4b0.run(),this.s4b1.run(),this.s4b2.run(),this.s5b0.run(),this.s5b1.run(),this.s5b2.run(),this.s5b3.run(),this.s6b0.run(),this.bottleneck.run(),this.dec0.run(),this.dec1.run(),this.dec2.run(),this.finalUp.run(),this.outConv.run(),this.alpha.run()}};var k=class{constructor(e,r,t){n(this,"output");n(this,"stem");n(this,"s0");n(this,"s1b0");n(this,"s1b1");n(this,"s2b0");n(this,"s2b1");n(this,"s3b0");n(this,"s3b1");n(this,"s3b2");n(this,"s4b0");n(this,"s4b1");n(this,"s4b2");n(this,"bottleneck");n(this,"dec0");n(this,"dec1");n(this,"finalUp");n(this,"outConv");n(this,"alpha");this.stem=e.ops.Conv2d(r,t.encoder.stem,{outChannels:32,kernel:3,stride:2,padding:"same",activation:"relu6"}),this.s0=new C(e,this.stem.output,t.encoder.s0,{outChannels:16,kernel:3,stride:1,padding:1}),this.s1b0=new c(e,this.s0.output,t.encoder.s1[0],{inChannels:16,midChannels:96,outChannels:24,kernel:3,stride:2,padding:"same"}),this.s1b1=new c(e,this.s1b0.output,t.encoder.s1[1],{inChannels:24,midChannels:144,outChannels:24,kernel:3,stride:1,padding:1}),this.s2b0=new c(e,this.s1b1.output,t.encoder.s2[0],{inChannels:24,midChannels:144,outChannels:40,kernel:5,stride:2,padding:"same"}),this.s2b1=new c(e,this.s2b0.output,t.encoder.s2[1],{inChannels:40,midChannels:240,outChannels:40,kernel:5,stride:1,padding:2}),this.s3b0=new c(e,this.s2b1.output,t.encoder.s3[0],{inChannels:40,midChannels:240,outChannels:80,kernel:3,stride:2,padding:"same"}),this.s3b1=new c(e,this.s3b0.output,t.encoder.s3[1],{inChannels:80,midChannels:480,outChannels:80,kernel:3,stride:1,padding:1}),this.s3b2=new c(e,this.s3b1.output,t.encoder.s3[2],{inChannels:80,midChannels:480,outChannels:80,kernel:3,stride:1,padding:1}),this.s4b0=new c(e,this.s3b2.output,t.encoder.s4[0],{inChannels:80,midChannels:480,outChannels:112,kernel:5,stride:1,padding:2}),this.s4b1=new c(e,this.s4b0.output,t.encoder.s4[1],{inChannels:112,midChannels:672,outChannels:112,kernel:5,stride:1,padding:2}),this.s4b2=new c(e,this.s4b1.output,t.encoder.s4[2],{inChannels:112,midChannels:672,outChannels:112,kernel:5,stride:1,padding:2}),this.bottleneck=e.ops.Conv2d(this.s4b2.output,t.bottleneck,{outChannels:128,kernel:1,stride:1,padding:0,activation:"relu6"}),this.dec0=new y(e,this.bottleneck.output,this.s2b1.output,t.decoder.blocks[0],{outChannels:64}),this.dec1=new y(e,this.dec0.output,this.s1b1.output,t.decoder.blocks[1],{outChannels:32}),this.finalUp=e.ops.UpsampleConv1x1(this.dec1.output,t.decoder.finalUpsample,{outH:this.dec1.output.h*2,outW:this.dec1.output.w*2,outChannels:32,activation:"relu6"}),this.outConv=e.ops.Conv2d(this.finalUp.output,t.decoder.outputConv,{outChannels:4,kernel:1,stride:1,padding:0,activation:"none"}),this.alpha=e.ops.UpsampleSigmoid(this.outConv.output,{outH:this.outConv.output.h*2,outW:this.outConv.output.w*2}),this.output=this.alpha.output}run(){this.stem.run(),this.s0.run(),this.s1b0.run(),this.s1b1.run(),this.s2b0.run(),this.s2b1.run(),this.s3b0.run(),this.s3b1.run(),this.s3b2.run(),this.s4b0.run(),this.s4b1.run(),this.s4b2.run(),this.bottleneck.run(),this.dec0.run(),this.dec1.run(),this.finalUp.run(),this.outConv.run(),this.alpha.run()}};var I=class{constructor(e,r,t){n(this,"output");n(this,"stem");n(this,"s0");n(this,"s1b0");n(this,"s1b1");n(this,"s2b0");n(this,"s2b1");n(this,"s3b0");n(this,"s3b1");n(this,"s3b2");n(this,"s4b0");n(this,"s4b1");n(this,"s4b2");n(this,"s5b0");n(this,"s5b1");n(this,"s5b2");n(this,"s5b3");n(this,"s6b0");n(this,"bottleneck");n(this,"dec0");n(this,"dec1");n(this,"dec2");n(this,"finalUp");n(this,"outConv");n(this,"alpha");this.stem=e.ops.Conv2d(r,t.encoder.stem,{outChannels:32,kernel:3,stride:2,padding:"same",activation:"relu6"}),this.s0=new C(e,this.stem.output,t.encoder.s0,{outChannels:16,kernel:3,stride:1,padding:1}),this.s1b0=new c(e,this.s0.output,t.encoder.s1[0],{inChannels:16,midChannels:96,outChannels:24,kernel:3,stride:2,padding:"same"}),this.s1b1=new c(e,this.s1b0.output,t.encoder.s1[1],{inChannels:24,midChannels:144,outChannels:24,kernel:3,stride:1,padding:1}),this.s2b0=new c(e,this.s1b1.output,t.encoder.s2[0],{inChannels:24,midChannels:144,outChannels:40,kernel:5,stride:2,padding:"same"}),this.s2b1=new c(e,this.s2b0.output,t.encoder.s2[1],{inChannels:40,midChannels:240,outChannels:40,kernel:5,stride:1,padding:2}),this.s3b0=new c(e,this.s2b1.output,t.encoder.s3[0],{inChannels:40,midChannels:240,outChannels:80,kernel:3,stride:2,padding:"same"}),this.s3b1=new c(e,this.s3b0.output,t.encoder.s3[1],{inChannels:80,midChannels:480,outChannels:80,kernel:3,stride:1,padding:1}),this.s3b2=new c(e,this.s3b1.output,t.encoder.s3[2],{inChannels:80,midChannels:480,outChannels:80,kernel:3,stride:1,padding:1}),this.s4b0=new c(e,this.s3b2.output,t.encoder.s4[0],{inChannels:80,midChannels:480,outChannels:112,kernel:5,stride:1,padding:2}),this.s4b1=new c(e,this.s4b0.output,t.encoder.s4[1],{inChannels:112,midChannels:672,outChannels:112,kernel:5,stride:1,padding:2}),this.s4b2=new c(e,this.s4b1.output,t.encoder.s4[2],{inChannels:112,midChannels:672,outChannels:112,kernel:5,stride:1,padding:2}),this.s5b0=new c(e,this.s4b2.output,t.encoder.s5[0],{inChannels:112,midChannels:672,outChannels:192,kernel:5,stride:2,padding:"same"}),this.s5b1=new c(e,this.s5b0.output,t.encoder.s5[1],{inChannels:192,midChannels:1152,outChannels:192,kernel:5,stride:1,padding:2}),this.s5b2=new c(e,this.s5b1.output,t.encoder.s5[2],{inChannels:192,midChannels:1152,outChannels:192,kernel:5,stride:1,padding:2}),this.s5b3=new c(e,this.s5b2.output,t.encoder.s5[3],{inChannels:192,midChannels:1152,outChannels:192,kernel:5,stride:1,padding:2}),this.s6b0=new c(e,this.s5b3.output,t.encoder.s6[0],{inChannels:192,midChannels:1152,outChannels:320,kernel:3,stride:1,padding:1}),this.bottleneck=e.ops.Conv2d(this.s6b0.output,t.bottleneck,{outChannels:256,kernel:1,stride:1,padding:0,activation:"relu6"}),this.dec0=new y(e,this.bottleneck.output,this.s4b2.output,t.decoder.blocks[0],{outChannels:128}),this.dec1=new y(e,this.dec0.output,this.s2b1.output,t.decoder.blocks[1],{outChannels:64}),this.dec2=new y(e,this.dec1.output,this.s1b1.output,t.decoder.blocks[2],{outChannels:32}),this.finalUp=e.ops.UpsampleConv1x1(this.dec2.output,t.decoder.finalUpsample,{outH:this.dec2.output.h*2,outW:this.dec2.output.w*2,outChannels:32,activation:"relu6"}),this.outConv=e.ops.Conv2d(this.finalUp.output,t.decoder.outputConv,{outChannels:4,kernel:1,stride:1,padding:0,activation:"none"}),this.alpha=e.ops.UpsampleSigmoid(this.outConv.output,{outH:this.outConv.output.h*2,outW:this.outConv.output.w*2}),this.output=this.alpha.output}run(){this.stem.run(),this.s0.run(),this.s1b0.run(),this.s1b1.run(),this.s2b0.run(),this.s2b1.run(),this.s3b0.run(),this.s3b1.run(),this.s3b2.run(),this.s4b0.run(),this.s4b1.run(),this.s4b2.run(),this.s5b0.run(),this.s5b1.run(),this.s5b2.run(),this.s5b3.run(),this.s6b0.run(),this.bottleneck.run(),this.dec0.run(),this.dec1.run(),this.dec2.run(),this.finalUp.run(),this.outConv.run(),this.alpha.run()}};var Zt=5,er={xxs:k,xs:k,small:k,compact:E,medium:W,large:W,xl:I},Oe=1e3,Y=class{constructor(e){n(this,"canvas");n(this,"backend");n(this,"backendKind");n(this,"topology");n(this,"preset",null);n(this,"enabled");n(this,"currentBackground");n(this,"modelTimingCounter",0);n(this,"renderOp");n(this,"bgImageInput",null);n(this,"bgVideoInput",null);n(this,"bgVideoPort",null);n(this,"skipCounter",0);n(this,"framesRenderedAt",[]);n(this,"modelRunSamples",[]);n(this,"displayRunSamples",[]);n(this,"skippedCount",0);this.backend=e.backend,this.backendKind=e.backendKind,this.canvas=e.canvas,this.enabled=e.enabled,this.currentBackground=e.background,this.topology=e.topology,this.renderOp=new K(this.backend)}process(e){if(this.renderOp.setSource(e),!this.enabled||this.currentBackground.kind==="none"||!this.renderOp.hasNetwork()){this.renderOp.runPassthrough(),this.framesRenderedAt.push(performance.now()),this.trim(this.framesRenderedAt);return}if(this.shouldRunModel()){let t=performance.now();this.renderOp.runModel(),this.backendKind==="webgpu"&&this.modelTimingCounter%Zt===0&&this.backend.sync().then(()=>{this.modelRunSamples.push({ts:performance.now(),ms:performance.now()-t}),this.trimSamples(this.modelRunSamples)}).catch(()=>{}),this.modelTimingCounter++}else this.skippedCount++;let r=performance.now();this.renderOp.runDisplay(),this.displayRunSamples.push({ts:performance.now(),ms:performance.now()-r}),this.trimSamples(this.displayRunSamples),this.framesRenderedAt.push(performance.now()),this.trim(this.framesRenderedAt)}shouldRunModel(){return this.skipCounter===0?(this.skipCounter=this.preset?.skipFrames??0,!0):(this.skipCounter--,!1)}setBackground(e){this.currentBackground=e,this.renderOp.setBackground(this.translateBackground(e))}setEnabled(e){this.enabled=e}setPreset(e,r){let t=er[e.model];if(!t)throw new Error(\`renderer: model '\${e.model}' not implemented in src/model/networks/\`);let o=Fe(r),i=this.backend.ops.Input(e.resolution.h,e.resolution.w),a=new t(this.backend,i.output,o);this.renderOp.attachNetwork(a,i,{upscaler:"bilinear",background:this.translateBackground(this.currentBackground)}),this.preset=e,this.skipCounter=0}destroy(){this.bgVideoPort&&(this.bgVideoPort.close(),this.bgVideoPort=null),this.backend.destroy()}getStats(){let e=performance.now();return this.trimRecent(this.framesRenderedAt,e),this.trimSamplesAt(this.modelRunSamples,e),this.trimSamplesAt(this.displayRunSamples,e),{fps:this.framesRenderedAt.length,modelFps:this.modelRunSamples.length,modelMs:Me(this.modelRunSamples.map(r=>r.ms)),displayMs:Me(this.displayRunSamples.map(r=>r.ms)),skipped:this.skippedCount,preset:this.preset?.model??"boot",skipFrames:this.preset?.skipFrames??0,enabled:this.enabled,inputPath:this.topology.input,outputPath:this.topology.output}}translateBackground(e){switch(e.kind!=="video"&&this.bgVideoPort&&(this.bgVideoPort.close(),this.bgVideoPort=null),e.kind){case"none":return{mode:"solid",color:[0,0,0]};case"color":return{mode:"solid",color:e.rgb};case"blur":return{mode:"blur",sigma:e.sigma};case"image":return this.bgImageInput||(this.bgImageInput=this.backend.ops.Input(this.canvas.height,this.canvas.width)),this.bgImageInput.setSource(e.bitmap),this.bgImageInput.run(),{mode:"image",image:this.bgImageInput.output};case"video":{this.bgVideoInput||(this.bgVideoInput=this.backend.ops.Input(this.canvas.height,this.canvas.width)),this.bgVideoPort&&this.bgVideoPort.close(),this.bgVideoPort=e.port;let r=this.bgVideoInput;return e.port.onmessage=t=>{let o=t.data.frame;try{r.setSource(o),r.run()}finally{o.close()}},e.port.start?.(),{mode:"image",image:this.bgVideoInput.output}}}}trim(e){e.length>240&&e.splice(0,e.length-240)}trimSamples(e){e.length>240&&e.splice(0,e.length-240)}trimRecent(e,r){let t=r-Oe,o=0;for(;o<e.length&&e[o]<t;)o++;o>0&&e.splice(0,o)}trimSamplesAt(e,r){let t=r-Oe,o=0;for(;o<e.length&&e[o].ts<t;)o++;o>0&&e.splice(0,o)}};function Me(s){if(s.length===0)return 0;let e=s.slice().sort((t,o)=>t-o),r=e.length>>1;return e.length%2?e[r]:(e[r-1]+e[r])/2}var L=new Float32Array(1),D=new Uint32Array(L.buffer);function tr(s){L[0]=s;let e=D[0],r=e>>>16&32768,t=e&2147483647,o=(t>>>23)-127+15;if((e&2139095040)===2139095040)return(e&8388607)!==0?r|32256:r|31744;if(o>=31)return r|31744;if(o<=0){if(o<-10)return r;let l=t&8388607|8388608,d=14-o,m=l>>>d,x=l>>>d-1&1,T=(l&(1<<d-1)-1)!==0?1:0;return x&&(T||m&1)&&(m+=1),r|m}let i=t>>>13&1023,a=t>>>12&1,u=(t&4095)!==0?1:0,p=o<<10|i;return a&&(u||i&1)&&(p+=1,(p>>>10&31)===31)?r|31744:r|p}function rr(s){let e=(s&32768)<<16,r=(s&31744)>>>10,t=s&1023;if(r===0){if(t===0)return D[0]=e,L[0];let o=t,i=1;for(;(o&1024)===0;)o<<=1,i-=1;return o&=1023,D[0]=e|i+127-15<<23|o<<13,L[0]}return r===31?(D[0]=e|2139095040|t<<13,L[0]):(D[0]=e|r+127-15<<23|t<<13,L[0])}function Q(s){let e=new Uint16Array(s.length);for(let r=0;r<s.length;r++)e[r]=tr(s[r]);return e}function A(s){let e=new Float32Array(s.length);for(let r=0;r<s.length;r++)e[r]=rr(s[r]);return e}var h=class{constructor(e){n(this,"backend",e);n(this,"shader","");n(this,"pipeline");n(this,"bindGroup");n(this,"uniformDefs",[]);n(this,"uniformBuffers",{})}createUniform(e,r){this.uniformDefs.push({name:e,type:r})}setUniform(e,r){let t=this.backend.device.createBuffer({size:r.byteLength,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST,mappedAtCreation:!0});r instanceof Uint32Array?new Uint32Array(t.getMappedRange()).set(r):new Float32Array(t.getMappedRange()).set(r),t.unmap(),this.uniformBuffers[e]=t}defaultBindGroup(){let e=[],r=0;for(let t of this.inputs)e.push({binding:r++,resource:{buffer:t.buffer}});for(let t of this.weights)e.push({binding:r++,resource:{buffer:t.buffer}});for(let t of this.uniformDefs)e.push({binding:r++,resource:{buffer:this.uniformBuffers[t.name]}});return e.push({binding:r,resource:{buffer:this.output.buffer}}),this.backend.device.createBindGroup({layout:this.pipeline.getBindGroupLayout(0),entries:e})}defaultSetup(){let e=this.backend.device.createShaderModule({code:this.shader});this.pipeline=this.backend.device.createComputePipeline({layout:"auto",compute:{module:e,entryPoint:"main"}}),this.bindGroup=this.defaultBindGroup()}run(){let e=this.backend.device.createCommandEncoder(),r=e.beginComputePass();r.setPipeline(this.pipeline),r.setBindGroup(0,this.bindGroup),r.dispatchWorkgroups(...this.dispatch),r.end(),this.backend.device.queue.submit([e.finish()])}};var Re=\`// Conv2d compute shader \\u2014 handles all variants:
|
|
2
2
|
// 1\\xD71 (pointwise), 3\\xD73, 5\\xD75, strided, BN-fused
|
|
3
3
|
//
|
|
4
4
|
// Tensor layout: NHWC with channels in vec4 groups
|
|
@@ -81,7 +81,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
81
81
|
let out_idx = y * params.out_w * O + x * O + o;
|
|
82
82
|
output_buf[out_idx] = result;
|
|
83
83
|
}
|
|
84
|
-
\`;var
|
|
84
|
+
\`;var De=\`enable f16;
|
|
85
85
|
|
|
86
86
|
// Conv2d \\u2014 full f16 variant.
|
|
87
87
|
// All buffers (input, output, weights, bias) are f16. Weights are converted
|
|
@@ -154,7 +154,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
154
154
|
|
|
155
155
|
output_buf[y * params.out_w * O + x * O + o] = result;
|
|
156
156
|
}
|
|
157
|
-
\`;function b(s,e,
|
|
157
|
+
\`;function b(s,e,r,t){return typeof t=="number"?Math.floor((s+2*t-e)/r)+1:t==="same"?Math.ceil(s/r):Math.floor((s-e)/r)+1}function ir(s,e,r,t){return Math.floor(Math.max((e-1)*t+r-s,0)/2)}function v(s,e,r,t,o){return typeof s=="number"?s:s==="same"?ir(e,r,t,o):0}function f(s){return s instanceof Float32Array||s instanceof Uint16Array?s:new Float32Array(s)}var J=class extends h{constructor(r,t,o,i){super(r);n(this,"inputs");n(this,"weights");n(this,"output");n(this,"dispatch");n(this,"shader");this.shader=r.dtype==="f16"?De:Re;let a=b(t.h,i.kernel,i.stride,i.padding),u=b(t.w,i.kernel,i.stride,i.padding),p=t.c/4,l=i.outChannels/4,d=v(i.padding,t.h,a,i.kernel,i.stride),m=v(i.padding,t.w,u,i.kernel,i.stride);this.output=r.tensor(a,u,i.outChannels),this.inputs=[t],this.weights=[r.upload(f(o.weights)),r.upload(f(o.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([t.h,t.w,a,u,p,l,i.kernel,i.kernel,i.stride,d,m,i.activation==="relu6"?1:0])),this.defaultSetup(),this.dispatch=[Math.ceil(u/8),Math.ceil(a/8),l]}};var He=\`// Depthwise Conv2d \\u2014 groups = in_channels (each channel convolved independently).
|
|
158
158
|
//
|
|
159
159
|
// Weight layout: [K*K][channel_groups] array of vec4
|
|
160
160
|
// weight index = (ky*kernel_w + kx) * channel_groups + c
|
|
@@ -229,7 +229,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
229
229
|
let out_idx = y * params.out_w * C + x * C + c;
|
|
230
230
|
output_buf[out_idx] = result;
|
|
231
231
|
}
|
|
232
|
-
\`;var
|
|
232
|
+
\`;var Ve=\`enable f16;
|
|
233
233
|
|
|
234
234
|
// Depthwise conv2d \\u2014 full f16 variant. All buffers f16.
|
|
235
235
|
|
|
@@ -294,7 +294,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
294
294
|
|
|
295
295
|
output_buf[y * params.out_w * C + x * C + c] = result;
|
|
296
296
|
}
|
|
297
|
-
\`;var
|
|
297
|
+
\`;var Z=class extends h{constructor(r,t,o,i){super(r);n(this,"inputs");n(this,"weights");n(this,"output");n(this,"dispatch");n(this,"shader");this.shader=r.dtype==="f16"?Ve:He;let a=b(t.h,i.kernel,i.stride,i.padding),u=b(t.w,i.kernel,i.stride,i.padding),p=t.c/4,l=v(i.padding,t.h,a,i.kernel,i.stride),d=v(i.padding,t.w,u,i.kernel,i.stride);this.output=r.tensor(a,u,t.c),this.inputs=[t],this.weights=[r.upload(f(o.weights)),r.upload(f(o.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([t.h,t.w,a,u,p,i.kernel,i.kernel,i.stride,l,d,i.activation==="relu6"?1:0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(u/8),Math.ceil(a/8),p]}};var Ne=\`// Element-wise add of two tensors \\u2014 used for residual connections in MBConv blocks.
|
|
298
298
|
// Operates on the flat float buffer directly; layout is irrelevant for a pure element-wise op.
|
|
299
299
|
|
|
300
300
|
struct Params {
|
|
@@ -315,7 +315,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
315
315
|
if (idx >= params.size) { return; }
|
|
316
316
|
output[idx] = input_a[idx] + input_b[idx];
|
|
317
317
|
}
|
|
318
|
-
\`;var
|
|
318
|
+
\`;var ze=\`enable f16;
|
|
319
319
|
|
|
320
320
|
// Element-wise add \\u2014 full f16 variant.
|
|
321
321
|
// array<f16> is binary-compatible with array<vec4<f16>> written by the f16 conv shaders.
|
|
@@ -338,7 +338,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
338
338
|
if (idx >= params.size) { return; }
|
|
339
339
|
output[idx] = input_a[idx] + input_b[idx];
|
|
340
340
|
}
|
|
341
|
-
\`;var
|
|
341
|
+
\`;var ee=class extends h{constructor(r,t,o){super(r);n(this,"inputs");n(this,"weights",[]);n(this,"output");n(this,"dispatch");n(this,"shader");this.shader=r.dtype==="f16"?ze:Ne;let i=t.h*t.w*t.c;this.output=r.tensor(t.h,t.w,t.c),this.inputs=[t,o],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([i,0,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(i/256),1,1]}};var Xe=\`// Element-wise sigmoid: output = 1 / (1 + exp(-x)).
|
|
342
342
|
// Operates on packed vec4 buffers (NHWC layout). exp() and arithmetic are element-wise on vec4.
|
|
343
343
|
|
|
344
344
|
struct Params {
|
|
@@ -358,7 +358,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
358
358
|
if (idx >= params.n_groups) { return; }
|
|
359
359
|
output_buf[idx] = 1.0 / (1.0 + exp(-input_buf[idx]));
|
|
360
360
|
}
|
|
361
|
-
\`;var
|
|
361
|
+
\`;var $e=\`enable f16;
|
|
362
362
|
|
|
363
363
|
// Sigmoid \\u2014 full f16 variant.
|
|
364
364
|
|
|
@@ -380,7 +380,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
380
380
|
let x = vec4<f32>(input_buf[idx]);
|
|
381
381
|
output_buf[idx] = vec4<f16>(1.0 / (1.0 + exp(-x)));
|
|
382
382
|
}
|
|
383
|
-
\`;var
|
|
383
|
+
\`;var te=class extends h{constructor(r,t){super(r);n(this,"inputs");n(this,"weights",[]);n(this,"output");n(this,"dispatch");n(this,"shader");this.shader=r.dtype==="f16"?$e:Xe;let o=t.h*t.w*(t.c/4);this.output=r.tensor(t.h,t.w,t.c),this.inputs=[t],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([o,0,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(o/256),1,1]}};var qe=\`// Bilinear upsample (arbitrary ratio), align_corners=False (matches PyTorch default).
|
|
384
384
|
// Input/output in NHWC vec4 format: index = y*W*(C/4) + x*(C/4) + c_group.
|
|
385
385
|
// Each thread computes one output pixel for one channel group (vec4 = 4 channels).
|
|
386
386
|
|
|
@@ -438,7 +438,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
438
438
|
|
|
439
439
|
output_buf[oy * params.out_w * C + ox * C + c] = result;
|
|
440
440
|
}
|
|
441
|
-
\`;var
|
|
441
|
+
\`;var je=\`enable f16;
|
|
442
442
|
|
|
443
443
|
// Bilinear upsample 2\\xD7 \\u2014 full f16 variant.
|
|
444
444
|
// Interpolation weights (wx, wy) and intermediate blends computed in f32 for
|
|
@@ -494,7 +494,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
494
494
|
|
|
495
495
|
output_buf[oy * params.out_w * C + ox * C + c] = vec4<f16>(result);
|
|
496
496
|
}
|
|
497
|
-
\`;var
|
|
497
|
+
\`;var re=class extends h{constructor(r,t,o){super(r);n(this,"inputs");n(this,"weights",[]);n(this,"output");n(this,"dispatch");n(this,"shader");this.shader=r.dtype==="f16"?je:qe;let i=t.c/4;this.output=r.tensor(o.outH,o.outW,t.c),this.inputs=[t],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([t.h,t.w,o.outH,o.outW,i,0,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(o.outW/8),Math.ceil(o.outH/8),i]}};var Ke=\`// Bicubic upsample (arbitrary scale) \\u2014 Keys cubic, a=-0.75 (PyTorch default
|
|
498
498
|
// for mode='bicubic', align_corners=False). Direct 2D, 4\\xD74 = 16 taps per
|
|
499
499
|
// output pixel. NHWC vec4 layout: index = y*W*(C/4) + x*(C/4) + c_group.
|
|
500
500
|
|
|
@@ -561,7 +561,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
561
561
|
|
|
562
562
|
output_buf[oy * params.out_w * C + ox * C + c] = acc;
|
|
563
563
|
}
|
|
564
|
-
\`;var
|
|
564
|
+
\`;var Ye=\`enable f16;
|
|
565
565
|
|
|
566
566
|
// Bicubic upsample \\u2014 full f16 storage variant. Bicubic weights and the per-
|
|
567
567
|
// pixel accumulator are computed in f32 (cheap to keep precision around the
|
|
@@ -630,7 +630,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
630
630
|
|
|
631
631
|
output_buf[oy * params.out_w * C + ox * C + c] = vec4<f16>(acc);
|
|
632
632
|
}
|
|
633
|
-
\`;var
|
|
633
|
+
\`;var oe=class extends h{constructor(r,t,o){super(r);n(this,"inputs");n(this,"weights",[]);n(this,"output");n(this,"dispatch");n(this,"shader");this.shader=r.dtype==="f16"?Ye:Ke;let i=t.c/4;this.output=r.tensor(o.outH,o.outW,t.c),this.inputs=[t],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([t.h,t.w,o.outH,o.outW,i,0,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(o.outW/8),Math.ceil(o.outH/8),i]}};var Qe=\`// Channel concatenation: output = cat(A, B, dim=channel).
|
|
634
634
|
// Both A and B must share the same H\\xD7W and be in NHWC vec4 format.
|
|
635
635
|
// Output layout: for each (y, x), the first a_groups vec4s come from A,
|
|
636
636
|
// followed by b_groups vec4s from B.
|
|
@@ -675,7 +675,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
675
675
|
output_buf[out_idx] = input_b[y * W * Bg + x * Bg + c_b];
|
|
676
676
|
}
|
|
677
677
|
}
|
|
678
|
-
\`;var
|
|
678
|
+
\`;var Je=\`enable f16;
|
|
679
679
|
|
|
680
680
|
// Channel concatenation \\u2014 full f16 variant.
|
|
681
681
|
|
|
@@ -716,7 +716,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
716
716
|
output_buf[out_idx] = input_b[y * W * Bg + x * Bg + c_b];
|
|
717
717
|
}
|
|
718
718
|
}
|
|
719
|
-
\`;var
|
|
719
|
+
\`;var ne=class extends h{constructor(r,t,o){super(r);n(this,"inputs");n(this,"weights",[]);n(this,"output");n(this,"dispatch");n(this,"shader");this.shader=r.dtype==="f16"?Je:Qe;let i=t.c/4,a=o.c/4,u=i+a;this.output=r.tensor(t.h,t.w,t.c+o.c),this.inputs=[t,o],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([t.h,t.w,i,a,u,0,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(t.w/8),Math.ceil(t.h/8),u]}};var Ze=\`// Conv2d + skip add fused.
|
|
720
720
|
// Identical to conv2d.wgsl except skip is an activation input (binding 1),
|
|
721
721
|
// added element-wise to the conv result at write time.
|
|
722
722
|
// Eliminates the separate add dispatch and its intermediate buffer round-trip.
|
|
@@ -790,7 +790,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
790
790
|
let out_idx = y * params.out_w * O + x * O + o;
|
|
791
791
|
output_buf[out_idx] = result + skip_buf[out_idx];
|
|
792
792
|
}
|
|
793
|
-
\`;var
|
|
793
|
+
\`;var et=\`enable f16;
|
|
794
794
|
|
|
795
795
|
// Conv2d + skip add fused \\u2014 full f16 variant.
|
|
796
796
|
|
|
@@ -864,7 +864,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
864
864
|
let out_idx = y * params.out_w * O + x * O + o;
|
|
865
865
|
output_buf[out_idx] = result + skip_buf[out_idx];
|
|
866
866
|
}
|
|
867
|
-
\`;var
|
|
867
|
+
\`;var ie=class extends h{constructor(r,t,o,i,a){super(r);n(this,"inputs");n(this,"weights");n(this,"output");n(this,"dispatch");n(this,"shader");this.shader=r.dtype==="f16"?et:Ze;let u=b(t.h,a.kernel,a.stride,a.padding),p=b(t.w,a.kernel,a.stride,a.padding),l=t.c/4,d=a.outChannels/4,m=v(a.padding,t.h,u,a.kernel,a.stride),x=v(a.padding,t.w,p,a.kernel,a.stride);this.output=r.tensor(u,p,a.outChannels),this.inputs=[t,o],this.weights=[r.upload(f(i.weights)),r.upload(f(i.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([t.h,t.w,u,p,l,d,a.kernel,a.kernel,a.stride,m,x,a.activation==="relu6"?1:0])),this.defaultSetup(),this.dispatch=[Math.ceil(p/8),Math.ceil(u/8),d]}};var tt=\`// Bilinear upsample + channel concat fused.
|
|
868
868
|
// input_a is the decoder tensor at small spatial resolution (in_h \\xD7 in_w).
|
|
869
869
|
// input_b is the encoder skip feature already at output resolution (out_h \\xD7 out_w).
|
|
870
870
|
// For output channels 0..a_groups-1: bilinearly interpolate from input_a.
|
|
@@ -925,7 +925,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
925
925
|
output_buf[out_idx] = input_b[oy * params.out_w * params.b_groups + ox * params.b_groups + c_b];
|
|
926
926
|
}
|
|
927
927
|
}
|
|
928
|
-
\`;var
|
|
928
|
+
\`;var rt=\`enable f16;
|
|
929
929
|
|
|
930
930
|
// Bilinear upsample + channel concat fused \\u2014 full f16 variant.
|
|
931
931
|
// Bilinear weights (wx, wy) and intermediate blends computed in f32; result cast to f16.
|
|
@@ -985,7 +985,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
985
985
|
output_buf[out_idx] = input_b[oy * params.out_w * params.b_groups + ox * params.b_groups + c_b];
|
|
986
986
|
}
|
|
987
987
|
}
|
|
988
|
-
\`;var
|
|
988
|
+
\`;var se=class extends h{constructor(r,t,o,i){super(r);n(this,"inputs");n(this,"weights",[]);n(this,"output");n(this,"dispatch");n(this,"shader");this.shader=r.dtype==="f16"?rt:tt;let a=t.c/4,u=o.c/4,p=a+u;this.output=r.tensor(i.outH,i.outW,t.c+o.c),this.inputs=[t,o],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([t.h,t.w,i.outH,i.outW,a,u,p,0])),this.defaultSetup(),this.dispatch=[Math.ceil(i.outW/8),Math.ceil(i.outH/8),p]}};var ot=\`// Bilinear upsample + 1\\xD71 pointwise conv fused.
|
|
989
989
|
// For each output pixel, bilinearly samples the small input for each in_group,
|
|
990
990
|
// immediately applies the 1\\xD71 conv weights, and writes the activated result.
|
|
991
991
|
// Eliminates the intermediate full-resolution upsample buffer.
|
|
@@ -1052,7 +1052,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1052
1052
|
|
|
1053
1053
|
output_buf[oy * params.out_w * params.out_groups + ox * params.out_groups + og] = result;
|
|
1054
1054
|
}
|
|
1055
|
-
\`;var
|
|
1055
|
+
\`;var nt=\`enable f16;
|
|
1056
1056
|
|
|
1057
1057
|
// Bilinear upsample + 1\\xD71 pointwise conv fused \\u2014 full f16 variant.
|
|
1058
1058
|
// Bilinear weights and intermediate blends computed in f32; conv accumulation in f16.
|
|
@@ -1119,7 +1119,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1119
1119
|
|
|
1120
1120
|
output_buf[oy * params.out_w * params.out_groups + ox * params.out_groups + og] = result;
|
|
1121
1121
|
}
|
|
1122
|
-
\`;var
|
|
1122
|
+
\`;var ae=class extends h{constructor(r,t,o,i){super(r);n(this,"inputs");n(this,"weights");n(this,"output");n(this,"dispatch");n(this,"shader");this.shader=r.dtype==="f16"?nt:ot;let a=t.c/4,u=i.outChannels/4;this.output=r.tensor(i.outH,i.outW,i.outChannels),this.inputs=[t],this.weights=[r.upload(f(o.weights)),r.upload(f(o.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([t.h,t.w,i.outH,i.outW,a,u,i.activation==="relu6"?1:0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(i.outW/8),Math.ceil(i.outH/8),u]}};var it=\`// Bilinear upsample + sigmoid fused.
|
|
1123
1123
|
// Identical to bilinear_upsample.wgsl except sigmoid is applied at write time.
|
|
1124
1124
|
// Eliminates the intermediate full-resolution buffer and the separate sigmoid dispatch.
|
|
1125
1125
|
|
|
@@ -1173,7 +1173,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1173
1173
|
|
|
1174
1174
|
output_buf[oy * params.out_w * C + ox * C + c] = 1.0 / (1.0 + exp(-result));
|
|
1175
1175
|
}
|
|
1176
|
-
\`;var
|
|
1176
|
+
\`;var st=\`enable f16;
|
|
1177
1177
|
|
|
1178
1178
|
// Bilinear upsample + sigmoid fused \\u2014 full f16 variant.
|
|
1179
1179
|
// Interpolation computed in f32 for accuracy; sigmoid and result cast to f16.
|
|
@@ -1228,7 +1228,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1228
1228
|
|
|
1229
1229
|
output_buf[oy * params.out_w * C + ox * C + c] = vec4<f16>(1.0 / (1.0 + exp(-result)));
|
|
1230
1230
|
}
|
|
1231
|
-
\`;var
|
|
1231
|
+
\`;var ue=class extends h{constructor(r,t,o){super(r);n(this,"inputs");n(this,"weights",[]);n(this,"output");n(this,"dispatch");n(this,"shader");this.shader=r.dtype==="f16"?st:it;let i=t.c/4;this.output=r.tensor(o.outH,o.outW,t.c),this.inputs=[t],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([t.h,t.w,o.outH,o.outW,i,0,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(o.outW/8),Math.ceil(o.outH/8),i]}};var at=\`// Composite an RGBA image over a solid background, gated by a 1-ch alpha.
|
|
1232
1232
|
// Fragment writes the canvas's swapchain texture (premultiplied output).
|
|
1233
1233
|
//
|
|
1234
1234
|
// Caller invariants (matched in CompositeSolidWebGPU):
|
|
@@ -1273,7 +1273,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
1273
1273
|
let rgb = fg * a + params.bgColor.rgb * (1.0 - a);
|
|
1274
1274
|
return vec4<f32>(rgb, 1.0);
|
|
1275
1275
|
}
|
|
1276
|
-
\`;var
|
|
1276
|
+
\`;var ut=\`enable f16;
|
|
1277
1277
|
|
|
1278
1278
|
// Composite an RGBA image over a solid background, gated by a 1-ch alpha.
|
|
1279
1279
|
// f16 variant: image and alpha are stored as f16; values promote to f32 on
|
|
@@ -1322,7 +1322,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
1322
1322
|
let rgb = fg * a + params.bgColor.rgb * (1.0 - a);
|
|
1323
1323
|
return vec4<f32>(rgb, 1.0);
|
|
1324
1324
|
}
|
|
1325
|
-
\`;var
|
|
1325
|
+
\`;var pe=class{constructor(e,r,t,o){n(this,"backend",e);n(this,"pipeline");n(this,"bindGroup");n(this,"uniformBuffer");n(this,"outputView",null);if(r.h!==t.h||r.w!==t.w)throw new Error(\`CompositeSolid: image (\${r.h}\\xD7\${r.w}) and alpha (\${t.h}\\xD7\${t.w}) must match. Run the upscaler first.\`);let i=e.device;this.uniformBuffer=i.createBuffer({size:32,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});let a=new ArrayBuffer(32);new Uint32Array(a,0,1)[0]=r.w,new Float32Array(a,16,4).set([o[0],o[1],o[2],0]),i.queue.writeBuffer(this.uniformBuffer,0,a);let u=e.dtype==="f16"?ut:at,p=i.createShaderModule({code:u});this.pipeline=i.createRenderPipeline({layout:"auto",vertex:{module:p,entryPoint:"vs"},fragment:{module:p,entryPoint:"fs",targets:[{format:e.canvasFormat}]},primitive:{topology:"triangle-list"}}),this.bindGroup=i.createBindGroup({layout:this.pipeline.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:r.buffer}},{binding:1,resource:{buffer:t.buffer}},{binding:2,resource:{buffer:this.uniformBuffer}}]})}setOutput(e){this.outputView=e.createView()}run(){if(!this.outputView)throw new Error("CompositeSolidWebGPU.run() called before setOutput()");let e=this.backend.device.createCommandEncoder(),r=e.beginRenderPass({colorAttachments:[{view:this.outputView,clearValue:[0,0,0,1],loadOp:"clear",storeOp:"store"}]});r.setPipeline(this.pipeline),r.setBindGroup(0,this.bindGroup),r.draw(6),r.end(),this.backend.device.queue.submit([e.finish()]),this.outputView=null}};var pt=\`// Like composite_solid but bg is an NHWC vec4 storage buffer (e.g. virtual
|
|
1326
1326
|
// background image, or a blurred copy of the input).
|
|
1327
1327
|
|
|
1328
1328
|
struct VertexOut {
|
|
@@ -1364,7 +1364,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
1364
1364
|
let rgb = fg * a + bgc * (1.0 - a);
|
|
1365
1365
|
return vec4<f32>(rgb, 1.0);
|
|
1366
1366
|
}
|
|
1367
|
-
\`;var
|
|
1367
|
+
\`;var lt=\`enable f16;
|
|
1368
1368
|
|
|
1369
1369
|
// Like composite_solid_f16 but bg is an NHWC vec4<f16> storage buffer (e.g. a
|
|
1370
1370
|
// virtual background image, or a blurred copy of the input).
|
|
@@ -1408,7 +1408,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
1408
1408
|
let rgb = fg * a + bgc * (1.0 - a);
|
|
1409
1409
|
return vec4<f32>(rgb, 1.0);
|
|
1410
1410
|
}
|
|
1411
|
-
\`;var
|
|
1411
|
+
\`;var le=class{constructor(e,r,t,o){n(this,"backend",e);n(this,"pipeline");n(this,"bindGroup");n(this,"uniformBuffer");n(this,"outputView",null);if(r.h!==t.h||r.w!==t.w||r.h!==o.h||r.w!==o.w)throw new Error(\`CompositeImage: image (\${r.h}\\xD7\${r.w}), alpha (\${t.h}\\xD7\${t.w}), and bg (\${o.h}\\xD7\${o.w}) must all match. Run upscaler / resizer first.\`);let i=e.device;this.uniformBuffer=i.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});let a=new ArrayBuffer(16);new Uint32Array(a,0,1)[0]=r.w,i.queue.writeBuffer(this.uniformBuffer,0,a);let u=e.dtype==="f16"?lt:pt,p=i.createShaderModule({code:u});this.pipeline=i.createRenderPipeline({layout:"auto",vertex:{module:p,entryPoint:"vs"},fragment:{module:p,entryPoint:"fs",targets:[{format:e.canvasFormat}]},primitive:{topology:"triangle-list"}}),this.bindGroup=i.createBindGroup({layout:this.pipeline.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:r.buffer}},{binding:1,resource:{buffer:t.buffer}},{binding:2,resource:{buffer:this.uniformBuffer}},{binding:3,resource:{buffer:o.buffer}}]})}setOutput(e){this.outputView=e.createView()}run(){if(!this.outputView)throw new Error("CompositeImageWebGPU.run() called before setOutput()");let e=this.backend.device.createCommandEncoder(),r=e.beginRenderPass({colorAttachments:[{view:this.outputView,clearValue:[0,0,0,1],loadOp:"clear",storeOp:"store"}]});r.setPipeline(this.pipeline),r.setBindGroup(0,this.bindGroup),r.draw(6),r.end(),this.backend.device.queue.submit([e.finish()]),this.outputView=null}};var ct=\`// Like composite_image but bg is sampled bilinearly \\u2014 bg may be smaller than
|
|
1412
1412
|
// (image, alpha). Used by CompositorBlur to skip the final full-res upsample
|
|
1413
1413
|
// in the blur pyramid and let this shader's own per-pixel scan do the
|
|
1414
1414
|
// expansion (the work is already happening here for the composite anyway).
|
|
@@ -1473,7 +1473,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
1473
1473
|
let rgb = fg * a + bgc * (1.0 - a);
|
|
1474
1474
|
return vec4<f32>(rgb, 1.0);
|
|
1475
1475
|
}
|
|
1476
|
-
\`;var
|
|
1476
|
+
\`;var dt=\`enable f16;
|
|
1477
1477
|
|
|
1478
1478
|
// f16 storage variant of composite_image_bilinear. bg is at a smaller
|
|
1479
1479
|
// resolution and is bilinearly sampled to match (image, alpha) at full res.
|
|
@@ -1534,7 +1534,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
1534
1534
|
let rgb = fg * a + bgc * (1.0 - a);
|
|
1535
1535
|
return vec4<f32>(rgb, 1.0);
|
|
1536
1536
|
}
|
|
1537
|
-
\`;var
|
|
1537
|
+
\`;var ce=class{constructor(e,r,t,o){n(this,"backend",e);n(this,"pipeline");n(this,"bindGroup");n(this,"uniformBuffer");n(this,"outputView",null);if(r.h!==t.h||r.w!==t.w)throw new Error(\`CompositeImageBilinear: image (\${r.h}\\xD7\${r.w}) and alpha (\${t.h}\\xD7\${t.w}) must match.\`);let i=e.device;this.uniformBuffer=i.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});let a=new ArrayBuffer(16),u=new Uint32Array(a);u[0]=r.w,u[1]=r.h,u[2]=o.w,u[3]=o.h,i.queue.writeBuffer(this.uniformBuffer,0,a);let p=e.dtype==="f16"?dt:ct,l=i.createShaderModule({code:p});this.pipeline=i.createRenderPipeline({layout:"auto",vertex:{module:l,entryPoint:"vs"},fragment:{module:l,entryPoint:"fs",targets:[{format:e.canvasFormat}]},primitive:{topology:"triangle-list"}}),this.bindGroup=i.createBindGroup({layout:this.pipeline.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:r.buffer}},{binding:1,resource:{buffer:t.buffer}},{binding:2,resource:{buffer:this.uniformBuffer}},{binding:3,resource:{buffer:o.buffer}}]})}setOutput(e){this.outputView=e.createView()}run(){if(!this.outputView)throw new Error("CompositeImageBilinearWebGPU.run() called before setOutput()");let e=this.backend.device.createCommandEncoder(),r=e.beginRenderPass({colorAttachments:[{view:this.outputView,clearValue:[0,0,0,1],loadOp:"clear",storeOp:"store"}]});r.setPipeline(this.pipeline),r.setBindGroup(0,this.bindGroup),r.draw(6),r.end(),this.backend.device.queue.submit([e.finish()]),this.outputView=null}};var mt=\`// Passthrough "compositor" \\u2014 writes the image directly to the canvas
|
|
1538
1538
|
// swapchain texture with no alpha math and no background. Used by RenderOp
|
|
1539
1539
|
// when the renderer is in disabled state, so the output canvas reflects
|
|
1540
1540
|
// the unmodified input frame instead of a stale matted result.
|
|
@@ -1572,7 +1572,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
1572
1572
|
let i = y * params.width + x;
|
|
1573
1573
|
return vec4<f32>(image[i].rgb, 1.0);
|
|
1574
1574
|
}
|
|
1575
|
-
\`;var
|
|
1575
|
+
\`;var ht=\`enable f16;
|
|
1576
1576
|
|
|
1577
1577
|
// Passthrough "compositor" \\u2014 f16 variant. Image is stored as f16; values
|
|
1578
1578
|
// promote to f32 on read and the fragment writes f32 to the canvas
|
|
@@ -1608,7 +1608,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
1608
1608
|
let i = y * params.width + x;
|
|
1609
1609
|
return vec4<f32>(vec3<f32>(image[i].rgb), 1.0);
|
|
1610
1610
|
}
|
|
1611
|
-
\`;var
|
|
1611
|
+
\`;var de=class{constructor(e,r){n(this,"backend",e);n(this,"pipeline");n(this,"bindGroup");n(this,"uniformBuffer");n(this,"outputView",null);let t=e.device;this.uniformBuffer=t.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});let o=new ArrayBuffer(16);new Uint32Array(o,0,1)[0]=r.w,t.queue.writeBuffer(this.uniformBuffer,0,o);let i=e.dtype==="f16"?ht:mt,a=t.createShaderModule({code:i});this.pipeline=t.createRenderPipeline({layout:"auto",vertex:{module:a,entryPoint:"vs"},fragment:{module:a,entryPoint:"fs",targets:[{format:e.canvasFormat}]},primitive:{topology:"triangle-list"}}),this.bindGroup=t.createBindGroup({layout:this.pipeline.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:r.buffer}},{binding:1,resource:{buffer:this.uniformBuffer}}]})}setOutput(e){this.outputView=e.createView()}run(){if(!this.outputView)throw new Error("CompositePassthroughWebGPU.run() called before setOutput()");let e=this.backend.device.createCommandEncoder(),r=e.beginRenderPass({colorAttachments:[{view:this.outputView,clearValue:[0,0,0,1],loadOp:"clear",storeOp:"store"}]});r.setPipeline(this.pipeline),r.setBindGroup(0,this.bindGroup),r.draw(6),r.end(),this.backend.device.queue.submit([e.finish()]),this.outputView=null}};var ft=\`// Input op \\u2014 sample a regular 2D source texture (RGBA8 unorm) into the NHWC
|
|
1612
1612
|
// vec4<f32> output buffer at the target resolution. Used for ImageBitmap
|
|
1613
1613
|
// sources, which are uploaded into a persistent staging texture via
|
|
1614
1614
|
// copyExternalImageToTexture before each dispatch.
|
|
@@ -1638,7 +1638,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1638
1638
|
let rgba = textureSampleLevel(src_tex, src_sampler, uv, 0.0);
|
|
1639
1639
|
output_buf[y * params.out_w + x] = rgba;
|
|
1640
1640
|
}
|
|
1641
|
-
\`;var
|
|
1641
|
+
\`;var gt=\`enable f16;
|
|
1642
1642
|
|
|
1643
1643
|
// Input op \\u2014 f16 storage variant. Source is sampled as vec4<f32>; only the
|
|
1644
1644
|
// store is demoted to vec4<f16>.
|
|
@@ -1668,7 +1668,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1668
1668
|
let rgba = textureSampleLevel(src_tex, src_sampler, uv, 0.0);
|
|
1669
1669
|
output_buf[y * params.out_w + x] = vec4<f16>(rgba);
|
|
1670
1670
|
}
|
|
1671
|
-
\`;var
|
|
1671
|
+
\`;var _t=\`// Input op \\u2014 sample a GPUExternalTexture (zero-copy VideoFrame import) into
|
|
1672
1672
|
// the NHWC vec4<f32> output buffer at the target resolution. Used when the
|
|
1673
1673
|
// caller passes a VideoFrame to setSource(); requires importExternalTexture
|
|
1674
1674
|
// to be called in the same task as the dispatch (the texture is invalidated
|
|
@@ -1699,7 +1699,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1699
1699
|
let rgba = textureSampleBaseClampToEdge(src_tex, src_sampler, uv);
|
|
1700
1700
|
output_buf[y * params.out_w + x] = rgba;
|
|
1701
1701
|
}
|
|
1702
|
-
\`;var
|
|
1702
|
+
\`;var bt=\`enable f16;
|
|
1703
1703
|
|
|
1704
1704
|
// Input op \\u2014 texture_external + f16 storage. Sample in f32, store as f16.
|
|
1705
1705
|
|
|
@@ -1728,12 +1728,12 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1728
1728
|
let rgba = textureSampleBaseClampToEdge(src_tex, src_sampler, uv);
|
|
1729
1729
|
output_buf[y * params.out_w + x] = vec4<f16>(rgba);
|
|
1730
1730
|
}
|
|
1731
|
-
\`;var
|
|
1731
|
+
\`;var Mr=s=>typeof VideoFrame<"u"&&s instanceof VideoFrame,me=class{constructor(e,r,t){n(this,"output");n(this,"device");n(this,"dtype");n(this,"sampler");n(this,"uniformBuffer");n(this,"dispatch");n(this,"pipeline2d",null);n(this,"pipelineExternal",null);n(this,"stagingTex",null);n(this,"stagingW",0);n(this,"stagingH",0);n(this,"source",null);this.device=e.device,this.dtype=e.dtype,this.output=e.tensor(r,t,4),this.sampler=this.device.createSampler({magFilter:"linear",minFilter:"linear",addressModeU:"clamp-to-edge",addressModeV:"clamp-to-edge"}),this.uniformBuffer=this.device.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});let o=new ArrayBuffer(16);new Uint32Array(o,0,2).set([t,r]),this.device.queue.writeBuffer(this.uniformBuffer,0,o),this.dispatch=[Math.ceil(t/8),Math.ceil(r/8),1],this.pipeline2d=this.buildPipeline(this.dtype==="f16"?gt:ft)}setSource(e){this.source=e}run(){if(!this.source)throw new Error("InputWebGPU.run() called before setSource()");Mr(this.source)?this.runExternal(this.source):this.run2d(this.source)}run2d(e){this.ensureStagingTexture(e.width,e.height),this.device.queue.copyExternalImageToTexture({source:e,flipY:!1},{texture:this.stagingTex},[e.width,e.height]);let r=this.device.createBindGroup({layout:this.pipeline2d.getBindGroupLayout(0),entries:[{binding:0,resource:this.stagingTex.createView()},{binding:1,resource:this.sampler},{binding:2,resource:{buffer:this.uniformBuffer}},{binding:3,resource:{buffer:this.output.buffer}}]});this.dispatchOnce(this.pipeline2d,r)}runExternal(e){this.pipelineExternal||(this.pipelineExternal=this.buildPipeline(this.dtype==="f16"?bt:_t));let r=this.device.importExternalTexture({source:e}),t=this.device.createBindGroup({layout:this.pipelineExternal.getBindGroupLayout(0),entries:[{binding:0,resource:r},{binding:1,resource:this.sampler},{binding:2,resource:{buffer:this.uniformBuffer}},{binding:3,resource:{buffer:this.output.buffer}}]});this.dispatchOnce(this.pipelineExternal,t)}ensureStagingTexture(e,r){this.stagingTex&&this.stagingW===e&&this.stagingH===r||(this.stagingTex?.destroy(),this.stagingTex=this.device.createTexture({size:[e,r,1],format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT}),this.stagingW=e,this.stagingH=r)}buildPipeline(e){let r=this.device.createShaderModule({code:e});return this.device.createComputePipeline({layout:"auto",compute:{module:r,entryPoint:"main"}})}dispatchOnce(e,r){let t=this.device.createCommandEncoder(),o=t.beginComputePass();o.setPipeline(e),o.setBindGroup(0,r),o.dispatchWorkgroups(...this.dispatch),o.end(),this.device.queue.submit([t.finish()])}};var Rr=navigator.gpu?GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST:0,F=class s{constructor(e,r,t){n(this,"device",e);n(this,"canvas",r);n(this,"dtype",t);n(this,"ops");n(this,"presenters");n(this,"canvasContext");n(this,"canvasFormat");n(this,"bytesPerElement");this.bytesPerElement=t==="f16"?2:4;let o=r.getContext("webgpu");if(!o)throw new Error("Failed to get WebGPU context from canvas");this.canvasContext=o,this.canvasFormat=navigator.gpu.getPreferredCanvasFormat(),this.canvasContext.configure({device:e,format:this.canvasFormat,alphaMode:"premultiplied"}),this.ops={Conv2d:(i,a,u)=>new J(this,i,a,u),DepthwiseConv2d:(i,a,u)=>new Z(this,i,a,u),Add:(i,a)=>new ee(this,i,a),Sigmoid:i=>new te(this,i),BilinearUpsample:(i,a)=>new re(this,i,a),BicubicUpsample:(i,a)=>new oe(this,i,a),ChannelConcat:(i,a)=>new ne(this,i,a),Conv2dAdd:(i,a,u,p)=>new ie(this,i,a,u,p),UpsampleConcat:(i,a,u)=>new se(this,i,a,u),UpsampleConv1x1:(i,a,u)=>new ae(this,i,a,u),UpsampleSigmoid:(i,a)=>new ue(this,i,a),Input:(i,a)=>new me(this,i,a)},this.presenters={CompositeSolid:(i,a,u)=>{let p=new pe(this,i,a,u);return{run:()=>{p.setOutput(this.getCurrentDisplayTexture()),p.run()}}},CompositeImage:(i,a,u)=>{let p=new le(this,i,a,u);return{run:()=>{p.setOutput(this.getCurrentDisplayTexture()),p.run()}}},CompositeImageBilinear:(i,a,u)=>{let p=new ce(this,i,a,u);return{run:()=>{p.setOutput(this.getCurrentDisplayTexture()),p.run()}}},CompositePassthrough:i=>{let a=new de(this,i);return{run:()=>{a.setOutput(this.getCurrentDisplayTexture()),a.run()}}}}}static async isAvailable(){return navigator.gpu?await navigator.gpu.requestAdapter()!==null:!1}static async hasF16Support(){if(!navigator.gpu)return!1;let e=await navigator.gpu.requestAdapter();return e?e.features.has("shader-f16"):!1}static async create(e){let r=e.dtype??"f32",t=e.device;if(t){if(r==="f16"&&!t.features.has("shader-f16"))throw new Error("WebGPU dtype='f16' requested but supplied device lacks \`shader-f16\`")}else{let o=await navigator.gpu.requestAdapter();if(!o)throw new Error("WebGPU adapter not available");if(r==="f16"&&!o.features.has("shader-f16"))throw new Error("WebGPU dtype='f16' requested but adapter lacks \`shader-f16\` feature");t=await o.requestDevice({requiredFeatures:r==="f16"?["shader-f16"]:[]})}return new s(t,e.canvas,r)}getCurrentDisplayTexture(){return this.canvasContext.getCurrentTexture()}tensor(e,r,t,o){let a=e*r*t*this.bytesPerElement,u=this.device.createBuffer({size:a,usage:Rr,mappedAtCreation:o!==void 0});if(o!==void 0){let p=u.getMappedRange();this.writeView(p,o),u.unmap()}return{h:e,w:r,c:t,buffer:u}}upload(e){let t=e.length*this.bytesPerElement,o=this.device.createBuffer({size:t,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,mappedAtCreation:!0});return this.writeView(o.getMappedRange(),e),o.unmap(),{buffer:o}}writeView(e,r){let t=this.dtype==="f16",o=r instanceof Uint16Array;if(t===o){t?new Uint16Array(e).set(r):new Float32Array(e).set(r);return}t?new Uint16Array(e).set(Q(r)):new Float32Array(e).set(A(r))}async readback(e){let r=this.device.createBuffer({size:e.buffer.size,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ}),t=this.device.createCommandEncoder();t.copyBufferToBuffer(e.buffer,0,r,0,e.buffer.size),this.device.queue.submit([t.finish()]),await r.mapAsync(GPUMapMode.READ);let o=r.getMappedRange(),i=this.dtype==="f16"?A(new Uint16Array(o.slice(0))):new Float32Array(o.slice(0));return r.unmap(),r.destroy(),i}async sync(){await this.device.queue.onSubmittedWorkDone()}destroy(){this.device.destroy()}};var Dr=\`#version 300 es
|
|
1732
1732
|
const vec2 VERTS[6] = vec2[6](
|
|
1733
1733
|
vec2(-1.0,-1.0), vec2(1.0,-1.0), vec2(-1.0,1.0),
|
|
1734
1734
|
vec2(-1.0,1.0), vec2(1.0,-1.0), vec2(1.0,1.0)
|
|
1735
1735
|
);
|
|
1736
|
-
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }\`,g=class{constructor(e){n(this,"backend",e);n(this,"shader","");n(this,"program");n(this,"samplers",[]);n(this,"uniformInts",{})}makeTexture(e,
|
|
1736
|
+
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }\`,g=class{constructor(e){n(this,"backend",e);n(this,"shader","");n(this,"program");n(this,"samplers",[]);n(this,"uniformInts",{})}makeTexture(e,r,t){let o=this.backend.gl,i=this.backend.textureFormat,a=this.backend.toTextureView(e),u=o.createTexture();return o.bindTexture(o.TEXTURE_2D,u),o.texImage2D(o.TEXTURE_2D,0,i.internalFormat,r,t,0,i.format,i.type,a),o.texParameteri(o.TEXTURE_2D,o.TEXTURE_MIN_FILTER,o.NEAREST),o.texParameteri(o.TEXTURE_2D,o.TEXTURE_MAG_FILTER,o.NEAREST),o.texParameteri(o.TEXTURE_2D,o.TEXTURE_WRAP_S,o.CLAMP_TO_EDGE),o.texParameteri(o.TEXTURE_2D,o.TEXTURE_WRAP_T,o.CLAMP_TO_EDGE),u}defaultSetup(){let e=this.backend.gl,r=e.createShader(e.VERTEX_SHADER);e.shaderSource(r,Dr),e.compileShader(r);let t=e.createShader(e.FRAGMENT_SHADER);if(e.shaderSource(t,this.shader),e.compileShader(t),!e.getShaderParameter(t,e.COMPILE_STATUS))throw new Error(\`GLSL compile error: \${e.getShaderInfoLog(t)}\`);if(this.program=e.createProgram(),e.attachShader(this.program,r),e.attachShader(this.program,t),e.linkProgram(this.program),!e.getProgramParameter(this.program,e.LINK_STATUS))throw new Error(\`GLSL link error: \${e.getProgramInfoLog(this.program)}\`)}run(){let e=this.backend.gl;e.useProgram(this.program),this.samplers.forEach(({name:r,texture:t},o)=>{e.activeTexture(e.TEXTURE0+o),e.bindTexture(e.TEXTURE_2D,t),e.uniform1i(e.getUniformLocation(this.program,r),o)});for(let[r,t]of Object.entries(this.uniformInts))e.uniform1i(e.getUniformLocation(this.program,r),t);e.bindFramebuffer(e.FRAMEBUFFER,this.backend.fbo),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,this.output.texture,0),e.viewport(0,0,this.dispatch[0],this.dispatch[1]),e.bindVertexArray(null),e.drawArrays(e.TRIANGLES,0,6)}};var vt=\`#version 300 es
|
|
1737
1737
|
// Conv2d \\u2014 handles all variants: 1\\xD71 (pointwise), 3\\xD73, 5\\xD75, strided, BN-fused.
|
|
1738
1738
|
//
|
|
1739
1739
|
// Tensor layout: NHWC vec4 \\u2014 texture dimensions (W * C/4, H).
|
|
@@ -1809,7 +1809,7 @@ void main() {
|
|
|
1809
1809
|
|
|
1810
1810
|
fragColor = result;
|
|
1811
1811
|
}
|
|
1812
|
-
\`;var
|
|
1812
|
+
\`;var he=class extends g{constructor(r,t,o,i){super(r);n(this,"inputs");n(this,"weights");n(this,"output");n(this,"dispatch");n(this,"shader",vt);let a=b(t.h,i.kernel,i.stride,i.padding),u=b(t.w,i.kernel,i.stride,i.padding),p=t.c/4,l=i.outChannels/4,d=v(i.padding,t.h,a,i.kernel,i.stride),m=v(i.padding,t.w,u,i.kernel,i.stride),x=f(o.weights),T=f(o.bias),M=this.makeTexture(x,p*4,i.kernel*i.kernel*l),G=this.makeTexture(T,l,1),B=u*l,R=this.makeTexture(null,B,a);this.output={h:a,w:u,c:i.outChannels,texture:R,texW:B,texH:a},this.inputs=[t],this.weights=[],this.samplers=[{name:"u_input",texture:t.texture},{name:"u_weights",texture:M},{name:"u_bias",texture:G}],this.uniformInts={u_in_w:t.w,u_in_h:t.h,u_in_c_groups:p,u_out_c_groups:l,u_kernel_h:i.kernel,u_kernel_w:i.kernel,u_stride:i.stride,u_pad_top:d,u_pad_left:m,u_activation:i.activation==="relu6"?1:0},this.defaultSetup(),this.dispatch=[B,a]}};var yt=\`#version 300 es
|
|
1813
1813
|
// Depthwise Conv2d \\u2014 groups = in_channels (each channel convolved independently).
|
|
1814
1814
|
//
|
|
1815
1815
|
// Weight layout: (C_groups, K\\xB2) RGBA32F texture \\u2014 contrast with conv2d which uses mat4.
|
|
@@ -1866,7 +1866,7 @@ void main() {
|
|
|
1866
1866
|
|
|
1867
1867
|
fragColor = result;
|
|
1868
1868
|
}
|
|
1869
|
-
\`;var
|
|
1869
|
+
\`;var fe=class extends g{constructor(r,t,o,i){super(r);n(this,"inputs");n(this,"weights");n(this,"output");n(this,"dispatch");n(this,"shader",yt);let a=b(t.h,i.kernel,i.stride,i.padding),u=b(t.w,i.kernel,i.stride,i.padding),p=t.c/4,l=v(i.padding,t.h,a,i.kernel,i.stride),d=v(i.padding,t.w,u,i.kernel,i.stride),m=f(o.weights),x=f(o.bias),T=this.makeTexture(m,p,i.kernel*i.kernel),M=this.makeTexture(x,p,1),G=u*p,B=this.makeTexture(null,G,a);this.output={h:a,w:u,c:t.c,texture:B,texW:G,texH:a},this.inputs=[t],this.weights=[],this.samplers=[{name:"u_input",texture:t.texture},{name:"u_weights",texture:T},{name:"u_bias",texture:M}],this.uniformInts={u_in_w:t.w,u_in_h:t.h,u_c_groups:p,u_kernel_h:i.kernel,u_kernel_w:i.kernel,u_stride:i.stride,u_pad_top:l,u_pad_left:d,u_apply_relu6:i.activation==="relu6"?1:0},this.defaultSetup(),this.dispatch=[G,a]}};var xt=\`#version 300 es
|
|
1870
1870
|
// Element-wise add \\u2014 both inputs and output share the same texture dimensions.
|
|
1871
1871
|
// Works for any 2D layout; used here with a flat (nVec4, 1) texture.
|
|
1872
1872
|
|
|
@@ -1881,7 +1881,7 @@ void main() {
|
|
|
1881
1881
|
ivec2 fc = ivec2(gl_FragCoord.xy);
|
|
1882
1882
|
fragColor = texelFetch(u_input_a, fc, 0) + texelFetch(u_input_b, fc, 0);
|
|
1883
1883
|
}
|
|
1884
|
-
\`;var
|
|
1884
|
+
\`;var ge=class extends g{constructor(r,t,o){super(r);n(this,"inputs");n(this,"weights",[]);n(this,"output");n(this,"dispatch");n(this,"shader",xt);let i=t,a=this.makeTexture(null,i.texW,i.texH);this.output={h:t.h,w:t.w,c:t.c,texture:a,texW:i.texW,texH:i.texH},this.inputs=[t,o],this.samplers=[{name:"u_input_a",texture:t.texture},{name:"u_input_b",texture:o.texture}],this.defaultSetup(),this.dispatch=[i.texW,i.texH]}};var wt=\`#version 300 es
|
|
1885
1885
|
// Element-wise sigmoid \\u2014 works on any texture layout (flat or spatial).
|
|
1886
1886
|
|
|
1887
1887
|
precision highp float;
|
|
@@ -1894,7 +1894,7 @@ void main() {
|
|
|
1894
1894
|
vec4 x = texelFetch(u_input, ivec2(gl_FragCoord.xy), 0);
|
|
1895
1895
|
fragColor = 1.0 / (1.0 + exp(-x));
|
|
1896
1896
|
}
|
|
1897
|
-
\`;var
|
|
1897
|
+
\`;var _e=class extends g{constructor(r,t){super(r);n(this,"inputs");n(this,"weights",[]);n(this,"output");n(this,"dispatch");n(this,"shader",wt);let o=t,i=this.makeTexture(null,o.texW,o.texH);this.output={h:t.h,w:t.w,c:t.c,texture:i,texW:o.texW,texH:o.texH},this.inputs=[t],this.samplers=[{name:"u_input",texture:o.texture}],this.defaultSetup(),this.dispatch=[o.texW,o.texH]}};var Ct=\`#version 300 es
|
|
1898
1898
|
// Bilinear upsample (arbitrary scale) \\u2014 align_corners=False.
|
|
1899
1899
|
//
|
|
1900
1900
|
// Hardware texture filtering can't be used: adjacent texels in x belong to
|
|
@@ -1945,7 +1945,7 @@ void main() {
|
|
|
1945
1945
|
|
|
1946
1946
|
fragColor = mix(mix(v00, v10, fx), mix(v01, v11, fx), fy);
|
|
1947
1947
|
}
|
|
1948
|
-
\`;var
|
|
1948
|
+
\`;var be=class extends g{constructor(r,t,o){super(r);n(this,"inputs");n(this,"weights",[]);n(this,"output");n(this,"dispatch");n(this,"shader",Ct);let i=t.c/4,a=o.outW*i,u=this.makeTexture(null,a,o.outH);this.output={h:o.outH,w:o.outW,c:t.c,texture:u,texW:a,texH:o.outH},this.inputs=[t],this.samplers=[{name:"u_input",texture:t.texture}],this.uniformInts={u_in_w:t.w,u_in_h:t.h,u_out_w:o.outW,u_out_h:o.outH,u_c_groups:i},this.defaultSetup(),this.dispatch=[a,o.outH]}};var kt=\`#version 300 es
|
|
1949
1949
|
// Bicubic upsample (arbitrary scale) \\u2014 Keys cubic, a=-0.75 (PyTorch default
|
|
1950
1950
|
// for mode='bicubic', align_corners=False).
|
|
1951
1951
|
//
|
|
@@ -2005,7 +2005,7 @@ void main() {
|
|
|
2005
2005
|
}
|
|
2006
2006
|
fragColor = acc;
|
|
2007
2007
|
}
|
|
2008
|
-
\`;var
|
|
2008
|
+
\`;var ve=class extends g{constructor(r,t,o){super(r);n(this,"inputs");n(this,"weights",[]);n(this,"output");n(this,"dispatch");n(this,"shader",kt);let i=t.c/4,a=o.outW*i,u=this.makeTexture(null,a,o.outH);this.output={h:o.outH,w:o.outW,c:t.c,texture:u,texW:a,texH:o.outH},this.inputs=[t],this.samplers=[{name:"u_input",texture:t.texture}],this.uniformInts={u_in_w:t.w,u_in_h:t.h,u_out_w:o.outW,u_out_h:o.outH,u_c_groups:i},this.defaultSetup(),this.dispatch=[a,o.outH]}};var Tt=\`#version 300 es
|
|
2009
2009
|
// Channel concat \\u2014 concatenates two NHWC textures along the channel dimension.
|
|
2010
2010
|
// Both inputs must share the same spatial dimensions (W, H). Channel counts are
|
|
2011
2011
|
// multiples of 4 so each "group" is one vec4 texel.
|
|
@@ -2038,7 +2038,7 @@ void main() {
|
|
|
2038
2038
|
fragColor = texelFetch(u_input_b, ivec2(x_spatial * u_b_c_groups + c_b, y), 0);
|
|
2039
2039
|
}
|
|
2040
2040
|
}
|
|
2041
|
-
\`;var
|
|
2041
|
+
\`;var ye=class extends g{constructor(r,t,o){super(r);n(this,"inputs");n(this,"weights",[]);n(this,"output");n(this,"dispatch");n(this,"shader",Tt);let i=t.c/4,a=o.c/4,u=i+a,p=t.c+o.c,l=t.w*u,d=this.makeTexture(null,l,t.h);this.output={h:t.h,w:t.w,c:p,texture:d,texW:l,texH:t.h},this.inputs=[t,o],this.samplers=[{name:"u_input_a",texture:t.texture},{name:"u_input_b",texture:o.texture}],this.uniformInts={u_a_c_groups:i,u_b_c_groups:a},this.defaultSetup(),this.dispatch=[l,t.h]}};var Pt=\`#version 300 es
|
|
2042
2042
|
// Bilinear upsample + sigmoid fused \\u2014 sigmoid applied at write time, no intermediate buffer.
|
|
2043
2043
|
// See bilinear_upsample.glsl for the manual 4-tap blend rationale.
|
|
2044
2044
|
//
|
|
@@ -2088,7 +2088,7 @@ void main() {
|
|
|
2088
2088
|
vec4 result = mix(mix(v00, v10, fx), mix(v01, v11, fx), fy);
|
|
2089
2089
|
fragColor = 1.0 / (1.0 + exp(-result));
|
|
2090
2090
|
}
|
|
2091
|
-
\`;var
|
|
2091
|
+
\`;var xe=class extends g{constructor(r,t,o){super(r);n(this,"inputs");n(this,"weights",[]);n(this,"output");n(this,"dispatch");n(this,"shader",Pt);let i=t.c/4,a=o.outW*i,u=this.makeTexture(null,a,o.outH);this.output={h:o.outH,w:o.outW,c:t.c,texture:u,texW:a,texH:o.outH},this.inputs=[t],this.samplers=[{name:"u_input",texture:t.texture}],this.uniformInts={u_in_w:t.w,u_in_h:t.h,u_out_w:o.outW,u_out_h:o.outH,u_c_groups:i},this.defaultSetup(),this.dispatch=[a,o.outH]}};var Wt=\`#version 300 es
|
|
2092
2092
|
// Bilinear upsample (input_a) + channel concat (with input_b) fused.
|
|
2093
2093
|
// input_a is the decoder tensor at small spatial res (in_h \\xD7 in_w), bilinearly resized to (out_h \\xD7 out_w).
|
|
2094
2094
|
// input_b is the encoder skip feature already at output resolution.
|
|
@@ -2146,7 +2146,7 @@ void main() {
|
|
|
2146
2146
|
fragColor = texelFetch(u_input_b, ivec2(x_out * u_b_c_groups + c_b, y_out), 0);
|
|
2147
2147
|
}
|
|
2148
2148
|
}
|
|
2149
|
-
\`;var
|
|
2149
|
+
\`;var we=class extends g{constructor(r,t,o,i){super(r);n(this,"inputs");n(this,"weights",[]);n(this,"output");n(this,"dispatch");n(this,"shader",Wt);let a=t.c/4,u=o.c/4,p=a+u,l=t.c+o.c,d=i.outW*p,m=this.makeTexture(null,d,i.outH);this.output={h:i.outH,w:i.outW,c:l,texture:m,texW:d,texH:i.outH},this.inputs=[t,o],this.samplers=[{name:"u_input_a",texture:t.texture},{name:"u_input_b",texture:o.texture}],this.uniformInts={u_in_w:t.w,u_in_h:t.h,u_out_w:i.outW,u_out_h:i.outH,u_a_c_groups:a,u_b_c_groups:u},this.defaultSetup(),this.dispatch=[d,i.outH]}};var Gt=\`#version 300 es
|
|
2150
2150
|
// Bilinear upsample + 1\\xD71 pointwise conv fused.
|
|
2151
2151
|
// For each output pixel + out group, bilinearly samples each in_group from input,
|
|
2152
2152
|
// applies the 1\\xD71 conv weight, and writes the activated result.
|
|
@@ -2223,7 +2223,7 @@ void main() {
|
|
|
2223
2223
|
|
|
2224
2224
|
fragColor = result;
|
|
2225
2225
|
}
|
|
2226
|
-
\`;var
|
|
2226
|
+
\`;var Ce=class extends g{constructor(r,t,o,i){super(r);n(this,"inputs");n(this,"weights");n(this,"output");n(this,"dispatch");n(this,"shader",Gt);let a=t.c/4,u=i.outChannels/4,p=f(o.weights),l=f(o.bias),d=this.makeTexture(p,a*4,u),m=this.makeTexture(l,u,1),x=i.outW*u,T=this.makeTexture(null,x,i.outH);this.output={h:i.outH,w:i.outW,c:i.outChannels,texture:T,texW:x,texH:i.outH},this.inputs=[t],this.weights=[],this.samplers=[{name:"u_input",texture:t.texture},{name:"u_weights",texture:d},{name:"u_bias",texture:m}],this.uniformInts={u_in_w:t.w,u_in_h:t.h,u_out_w:i.outW,u_out_h:i.outH,u_in_c_groups:a,u_out_c_groups:u,u_activation:i.activation==="relu6"?1:0},this.defaultSetup(),this.dispatch=[x,i.outH]}};var Bt=\`#version 300 es
|
|
2227
2227
|
// Conv2d + skip add fused \\u2014 identical to conv2d.glsl with a skip texture added at write time.
|
|
2228
2228
|
// See conv2d.glsl for tensor/weight layout details.
|
|
2229
2229
|
|
|
@@ -2287,7 +2287,7 @@ void main() {
|
|
|
2287
2287
|
|
|
2288
2288
|
fragColor = result + texelFetch(u_skip, ivec2(fx, fy), 0);
|
|
2289
2289
|
}
|
|
2290
|
-
\`;var
|
|
2290
|
+
\`;var ke=class extends g{constructor(r,t,o,i,a){super(r);n(this,"inputs");n(this,"weights");n(this,"output");n(this,"dispatch");n(this,"shader",Bt);let u=b(t.h,a.kernel,a.stride,a.padding),p=b(t.w,a.kernel,a.stride,a.padding),l=t.c/4,d=a.outChannels/4,m=v(a.padding,t.h,u,a.kernel,a.stride),x=v(a.padding,t.w,p,a.kernel,a.stride),T=f(i.weights),M=f(i.bias),G=this.makeTexture(T,l*4,a.kernel*a.kernel*d),B=this.makeTexture(M,d,1),R=p*d,qt=this.makeTexture(null,R,u);this.output={h:u,w:p,c:a.outChannels,texture:qt,texW:R,texH:u},this.inputs=[t,o],this.weights=[],this.samplers=[{name:"u_input",texture:t.texture},{name:"u_skip",texture:o.texture},{name:"u_weights",texture:G},{name:"u_bias",texture:B}],this.uniformInts={u_in_w:t.w,u_in_h:t.h,u_in_c_groups:l,u_out_c_groups:d,u_kernel_h:a.kernel,u_kernel_w:a.kernel,u_stride:a.stride,u_pad_top:m,u_pad_left:x,u_activation:a.activation==="relu6"?1:0},this.defaultSetup(),this.dispatch=[R,u]}};var Ut=\`#version 300 es
|
|
2291
2291
|
// Composite an RGBA image over a solid background color, gated by a
|
|
2292
2292
|
// 1-channel alpha mask. Output: premultiplied RGBA.
|
|
2293
2293
|
//
|
|
@@ -2318,12 +2318,12 @@ void main() {
|
|
|
2318
2318
|
vec3 rgb = fg * a + u_bgColor * (1.0 - a);
|
|
2319
2319
|
fragColor = vec4(rgb, 1.0);
|
|
2320
2320
|
}
|
|
2321
|
-
\`;var
|
|
2321
|
+
\`;var Zr=\`#version 300 es
|
|
2322
2322
|
const vec2 VERTS[6] = vec2[6](
|
|
2323
2323
|
vec2(-1.0,-1.0), vec2(1.0,-1.0), vec2(-1.0,1.0),
|
|
2324
2324
|
vec2(-1.0,1.0), vec2(1.0,-1.0), vec2(1.0,1.0)
|
|
2325
2325
|
);
|
|
2326
|
-
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }\`,
|
|
2326
|
+
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }\`,Te=class{constructor(e,r,t,o){n(this,"backend",e);n(this,"program");n(this,"imageTex");n(this,"alphaTex");n(this,"bgColor");if(r.h!==t.h||r.w!==t.w)throw new Error(\`CompositeSolid: image (\${r.h}\\xD7\${r.w}) and alpha (\${t.h}\\xD7\${t.w}) must match. Run the upscaler first.\`);let i=r,a=t;this.imageTex=i.texture,this.alphaTex=a.texture,this.bgColor=o;let u=e.gl,p=u.createShader(u.VERTEX_SHADER);u.shaderSource(p,Zr),u.compileShader(p);let l=u.createShader(u.FRAGMENT_SHADER);if(u.shaderSource(l,Ut),u.compileShader(l),!u.getShaderParameter(l,u.COMPILE_STATUS))throw new Error(\`composite_solid GLSL compile error: \${u.getShaderInfoLog(l)}\`);if(this.program=u.createProgram(),u.attachShader(this.program,p),u.attachShader(this.program,l),u.linkProgram(this.program),!u.getProgramParameter(this.program,u.LINK_STATUS))throw new Error(\`composite_solid GLSL link error: \${u.getProgramInfoLog(this.program)}\`)}run(){let e=this.backend.gl;e.useProgram(this.program),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.imageTex),e.uniform1i(e.getUniformLocation(this.program,"u_image"),0),e.activeTexture(e.TEXTURE1),e.bindTexture(e.TEXTURE_2D,this.alphaTex),e.uniform1i(e.getUniformLocation(this.program,"u_alpha"),1),e.uniform3f(e.getUniformLocation(this.program,"u_bgColor"),this.bgColor[0],this.bgColor[1],this.bgColor[2]),this.backend.bindDisplayFramebuffer(),e.bindVertexArray(null),e.drawArrays(e.TRIANGLES,0,6)}};var St=\`#version 300 es
|
|
2327
2327
|
// Same as composite_solid but bg is a texture (NHWC vec4 tensor) instead of
|
|
2328
2328
|
// a uniform color. Caller invariants: image, alpha, bg all share h \\xD7 w, and
|
|
2329
2329
|
// canvas dimensions match.
|
|
@@ -2349,12 +2349,12 @@ void main() {
|
|
|
2349
2349
|
vec3 rgb = fg * a + bg * (1.0 - a);
|
|
2350
2350
|
fragColor = vec4(rgb, 1.0);
|
|
2351
2351
|
}
|
|
2352
|
-
\`;var
|
|
2352
|
+
\`;var to=\`#version 300 es
|
|
2353
2353
|
const vec2 VERTS[6] = vec2[6](
|
|
2354
2354
|
vec2(-1.0,-1.0), vec2(1.0,-1.0), vec2(-1.0,1.0),
|
|
2355
2355
|
vec2(-1.0,1.0), vec2(1.0,-1.0), vec2(1.0,1.0)
|
|
2356
2356
|
);
|
|
2357
|
-
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }\`,
|
|
2357
|
+
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }\`,Pe=class{constructor(e,r,t,o){n(this,"backend",e);n(this,"program");n(this,"imageTex");n(this,"alphaTex");n(this,"bgTex");if(r.h!==t.h||r.w!==t.w||r.h!==o.h||r.w!==o.w)throw new Error(\`CompositeImage: image (\${r.h}\\xD7\${r.w}), alpha (\${t.h}\\xD7\${t.w}), and bg (\${o.h}\\xD7\${o.w}) must all match. Run upscaler / resizer first.\`);this.imageTex=r.texture,this.alphaTex=t.texture,this.bgTex=o.texture;let i=e.gl,a=i.createShader(i.VERTEX_SHADER);i.shaderSource(a,to),i.compileShader(a);let u=i.createShader(i.FRAGMENT_SHADER);if(i.shaderSource(u,St),i.compileShader(u),!i.getShaderParameter(u,i.COMPILE_STATUS))throw new Error(\`composite_image GLSL compile error: \${i.getShaderInfoLog(u)}\`);if(this.program=i.createProgram(),i.attachShader(this.program,a),i.attachShader(this.program,u),i.linkProgram(this.program),!i.getProgramParameter(this.program,i.LINK_STATUS))throw new Error(\`composite_image GLSL link error: \${i.getProgramInfoLog(this.program)}\`)}run(){let e=this.backend.gl;e.useProgram(this.program),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.imageTex),e.uniform1i(e.getUniformLocation(this.program,"u_image"),0),e.activeTexture(e.TEXTURE1),e.bindTexture(e.TEXTURE_2D,this.alphaTex),e.uniform1i(e.getUniformLocation(this.program,"u_alpha"),1),e.activeTexture(e.TEXTURE2),e.bindTexture(e.TEXTURE_2D,this.bgTex),e.uniform1i(e.getUniformLocation(this.program,"u_bg"),2),this.backend.bindDisplayFramebuffer(),e.bindVertexArray(null),e.drawArrays(e.TRIANGLES,0,6)}};var Et=\`#version 300 es
|
|
2358
2358
|
// Like composite_image but bg is bilinearly sampled \\u2014 bg is at a smaller
|
|
2359
2359
|
// resolution than (image, alpha) at canvas h \\xD7 w. Used by CompositorBlur to
|
|
2360
2360
|
// skip the final full-res upsample in the blur pyramid.
|
|
@@ -2403,12 +2403,12 @@ void main() {
|
|
|
2403
2403
|
vec3 rgb = fg * a + bg * (1.0 - a);
|
|
2404
2404
|
fragColor = vec4(rgb, 1.0);
|
|
2405
2405
|
}
|
|
2406
|
-
\`;var
|
|
2406
|
+
\`;var oo=\`#version 300 es
|
|
2407
2407
|
const vec2 VERTS[6] = vec2[6](
|
|
2408
2408
|
vec2(-1.0,-1.0), vec2(1.0,-1.0), vec2(-1.0,1.0),
|
|
2409
2409
|
vec2(-1.0,1.0), vec2(1.0,-1.0), vec2(1.0,1.0)
|
|
2410
2410
|
);
|
|
2411
|
-
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }\`,
|
|
2411
|
+
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }\`,We=class{constructor(e,r,t,o){n(this,"backend",e);n(this,"program");n(this,"imageTex");n(this,"alphaTex");n(this,"bgTex");n(this,"outW");n(this,"outH");n(this,"bgW");n(this,"bgH");if(r.h!==t.h||r.w!==t.w)throw new Error(\`CompositeImageBilinear: image (\${r.h}\\xD7\${r.w}) and alpha (\${t.h}\\xD7\${t.w}) must match.\`);this.imageTex=r.texture,this.alphaTex=t.texture,this.bgTex=o.texture,this.outW=r.w,this.outH=r.h,this.bgW=o.w,this.bgH=o.h;let i=e.gl,a=i.createShader(i.VERTEX_SHADER);i.shaderSource(a,oo),i.compileShader(a);let u=i.createShader(i.FRAGMENT_SHADER);if(i.shaderSource(u,Et),i.compileShader(u),!i.getShaderParameter(u,i.COMPILE_STATUS))throw new Error(\`composite_image_bilinear GLSL compile error: \${i.getShaderInfoLog(u)}\`);if(this.program=i.createProgram(),i.attachShader(this.program,a),i.attachShader(this.program,u),i.linkProgram(this.program),!i.getProgramParameter(this.program,i.LINK_STATUS))throw new Error(\`composite_image_bilinear GLSL link error: \${i.getProgramInfoLog(this.program)}\`)}run(){let e=this.backend.gl;e.useProgram(this.program),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.imageTex),e.uniform1i(e.getUniformLocation(this.program,"u_image"),0),e.activeTexture(e.TEXTURE1),e.bindTexture(e.TEXTURE_2D,this.alphaTex),e.uniform1i(e.getUniformLocation(this.program,"u_alpha"),1),e.activeTexture(e.TEXTURE2),e.bindTexture(e.TEXTURE_2D,this.bgTex),e.uniform1i(e.getUniformLocation(this.program,"u_bg"),2),e.uniform1i(e.getUniformLocation(this.program,"u_out_w"),this.outW),e.uniform1i(e.getUniformLocation(this.program,"u_out_h"),this.outH),e.uniform1i(e.getUniformLocation(this.program,"u_bg_w"),this.bgW),e.uniform1i(e.getUniformLocation(this.program,"u_bg_h"),this.bgH),this.backend.bindDisplayFramebuffer(),e.bindVertexArray(null),e.drawArrays(e.TRIANGLES,0,6)}};var It=\`#version 300 es
|
|
2412
2412
|
// Passthrough "compositor": writes the image directly to the canvas
|
|
2413
2413
|
// (default framebuffer). No alpha math, no background. Used by RenderOp
|
|
2414
2414
|
// when the renderer is in disabled state.
|
|
@@ -2431,12 +2431,12 @@ void main() {
|
|
|
2431
2431
|
vec3 rgb = texelFetch(u_image, px, 0).rgb;
|
|
2432
2432
|
fragColor = vec4(rgb, 1.0);
|
|
2433
2433
|
}
|
|
2434
|
-
\`;var
|
|
2434
|
+
\`;var io=\`#version 300 es
|
|
2435
2435
|
const vec2 VERTS[6] = vec2[6](
|
|
2436
2436
|
vec2(-1.0,-1.0), vec2(1.0,-1.0), vec2(-1.0,1.0),
|
|
2437
2437
|
vec2(-1.0,1.0), vec2(1.0,-1.0), vec2(1.0,1.0)
|
|
2438
2438
|
);
|
|
2439
|
-
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }\`,
|
|
2439
|
+
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }\`,Ge=class{constructor(e,r){n(this,"backend",e);n(this,"program");n(this,"imageTex");this.imageTex=r.texture;let t=e.gl,o=t.createShader(t.VERTEX_SHADER);t.shaderSource(o,io),t.compileShader(o);let i=t.createShader(t.FRAGMENT_SHADER);if(t.shaderSource(i,It),t.compileShader(i),!t.getShaderParameter(i,t.COMPILE_STATUS))throw new Error(\`composite_passthrough GLSL compile error: \${t.getShaderInfoLog(i)}\`);if(this.program=t.createProgram(),t.attachShader(this.program,o),t.attachShader(this.program,i),t.linkProgram(this.program),!t.getProgramParameter(this.program,t.LINK_STATUS))throw new Error(\`composite_passthrough GLSL link error: \${t.getProgramInfoLog(this.program)}\`)}run(){let e=this.backend.gl;e.useProgram(this.program),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.imageTex),e.uniform1i(e.getUniformLocation(this.program,"u_image"),0),this.backend.bindDisplayFramebuffer(),e.bindVertexArray(null),e.drawArrays(e.TRIANGLES,0,6)}};var Lt=\`#version 300 es
|
|
2440
2440
|
precision highp float;
|
|
2441
2441
|
|
|
2442
2442
|
// Input op \\u2014 bilinear-sample a source texture (RGBA8 unorm uploaded from an
|
|
@@ -2454,13 +2454,13 @@ void main() {
|
|
|
2454
2454
|
vec2 uv = (gl_FragCoord.xy + vec2(0.5)) / vec2(float(u_out_w), float(u_out_h));
|
|
2455
2455
|
fragColor = texture(u_src, uv);
|
|
2456
2456
|
}
|
|
2457
|
-
\`;var
|
|
2457
|
+
\`;var ao=\`#version 300 es
|
|
2458
2458
|
const vec2 VERTS[6] = vec2[6](
|
|
2459
2459
|
vec2(-1.0,-1.0), vec2(1.0,-1.0), vec2(-1.0,1.0),
|
|
2460
2460
|
vec2(-1.0,1.0), vec2(1.0,-1.0), vec2(1.0,1.0)
|
|
2461
2461
|
);
|
|
2462
|
-
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }\`,Ge=class{constructor(e,o,t){n(this,"backend",e);n(this,"output");n(this,"gl");n(this,"program");n(this,"srcTex");n(this,"uOutW");n(this,"uOutH");n(this,"uSrc");n(this,"source",null);let r=e.gl;this.gl=r,this.output=e.tensor(o,t,4),this.srcTex=r.createTexture(),r.bindTexture(r.TEXTURE_2D,this.srcTex),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_MIN_FILTER,r.LINEAR),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_MAG_FILTER,r.LINEAR),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_WRAP_S,r.CLAMP_TO_EDGE),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_WRAP_T,r.CLAMP_TO_EDGE);let i=r.createShader(r.VERTEX_SHADER);r.shaderSource(i,oo),r.compileShader(i);let a=r.createShader(r.FRAGMENT_SHADER);if(r.shaderSource(a,Ut),r.compileShader(a),!r.getShaderParameter(a,r.COMPILE_STATUS))throw new Error(\`Input GLSL compile error: \${r.getShaderInfoLog(a)}\`);if(this.program=r.createProgram(),r.attachShader(this.program,i),r.attachShader(this.program,a),r.linkProgram(this.program),!r.getProgramParameter(this.program,r.LINK_STATUS))throw new Error(\`Input GLSL link error: \${r.getProgramInfoLog(this.program)}\`);this.uSrc=r.getUniformLocation(this.program,"u_src"),this.uOutW=r.getUniformLocation(this.program,"u_out_w"),this.uOutH=r.getUniformLocation(this.program,"u_out_h")}setSource(e){this.source=e}run(){if(!this.source)throw new Error("InputWebGL.run() called before setSource()");let e=this.gl;e.bindTexture(e.TEXTURE_2D,this.srcTex),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,e.RGBA,e.UNSIGNED_BYTE,this.source),e.useProgram(this.program),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.srcTex),e.uniform1i(this.uSrc,0),e.uniform1i(this.uOutW,this.output.w),e.uniform1i(this.uOutH,this.output.h),e.bindFramebuffer(e.FRAMEBUFFER,this.backend.fbo),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,this.output.texture,0),e.viewport(0,0,this.output.texW,this.output.texH),e.bindVertexArray(null),e.drawArrays(e.TRIANGLES,0,6)}};var B=class s{constructor(e,o,t){n(this,"gl",e);n(this,"canvas",o);n(this,"dtype",t);n(this,"ops");n(this,"presenters");n(this,"fbo");n(this,"textureFormat");this.fbo=e.createFramebuffer(),this.textureFormat=t==="f16"?{internalFormat:e.RGBA16F,format:e.RGBA,type:e.HALF_FLOAT,bytesPerElement:2}:{internalFormat:e.RGBA32F,format:e.RGBA,type:e.FLOAT,bytesPerElement:4},this.ops={Conv2d:(r,i,a)=>new me(this,r,i,a),DepthwiseConv2d:(r,i,a)=>new he(this,r,i,a),Add:(r,i)=>new fe(this,r,i),Sigmoid:r=>new ge(this,r),BilinearUpsample:(r,i)=>new _e(this,r,i),BicubicUpsample:(r,i)=>new be(this,r,i),ChannelConcat:(r,i)=>new ve(this,r,i),Conv2dAdd:(r,i,a,u)=>new Ce(this,r,i,a,u),UpsampleConcat:(r,i,a)=>new xe(this,r,i,a),UpsampleConv1x1:(r,i,a)=>new we(this,r,i,a),UpsampleSigmoid:(r,i)=>new ye(this,r,i),Input:(r,i)=>new Ge(this,r,i)},this.presenters={CompositeSolid:(r,i,a)=>new ke(this,r,i,a),CompositeImage:(r,i,a)=>new Te(this,r,i,a),CompositeImageBilinear:(r,i,a)=>new Pe(this,r,i,a),CompositePassthrough:r=>new We(this,r)}}static isAvailable(){let e=null;try{return e=new OffscreenCanvas(1,1).getContext("webgl2"),!(!e||!e.getExtension("EXT_color_buffer_float"))}catch{return!1}finally{e?.getExtension("WEBGL_lose_context")?.loseContext()}}static create(e){let o=e.canvas.getContext("webgl2");if(!o)throw new Error("WebGL2 not available");if(!o.getExtension("EXT_color_buffer_float"))throw new Error("EXT_color_buffer_float not available");return new s(o,e.canvas,e.dtype??"f32")}bindDisplayFramebuffer(){this.gl.bindFramebuffer(this.gl.FRAMEBUFFER,null),this.gl.viewport(0,0,this.canvas.width,this.canvas.height)}toTextureView(e){if(e===null)return null;let o=this.dtype==="f16",t=e instanceof Uint16Array;return o===t?e:o?Y(e):L(e)}tensor(e,o,t,r){let i=o*(t/4),a=e,u=this.gl,p=u.createTexture(),l=this.textureFormat,d=this.toTextureView(r??null);return u.bindTexture(u.TEXTURE_2D,p),u.texImage2D(u.TEXTURE_2D,0,l.internalFormat,i,a,0,l.format,l.type,d),u.texParameteri(u.TEXTURE_2D,u.TEXTURE_MIN_FILTER,u.NEAREST),u.texParameteri(u.TEXTURE_2D,u.TEXTURE_MAG_FILTER,u.NEAREST),u.texParameteri(u.TEXTURE_2D,u.TEXTURE_WRAP_S,u.CLAMP_TO_EDGE),u.texParameteri(u.TEXTURE_2D,u.TEXTURE_WRAP_T,u.CLAMP_TO_EDGE),{h:e,w:o,c:t,texture:p,texW:i,texH:a}}upload(e){return{data:e}}async readback(e){let o=this.gl,t=this.textureFormat;if(o.bindFramebuffer(o.FRAMEBUFFER,this.fbo),o.framebufferTexture2D(o.FRAMEBUFFER,o.COLOR_ATTACHMENT0,o.TEXTURE_2D,e.texture,0),this.dtype==="f16"){let i=new Uint16Array(e.texW*e.texH*4);return o.readPixels(0,0,e.texW,e.texH,t.format,o.HALF_FLOAT,i),o.bindFramebuffer(o.FRAMEBUFFER,null),L(i)}let r=new Float32Array(e.texW*e.texH*4);return o.readPixels(0,0,e.texW,e.texH,t.format,o.FLOAT,r),o.bindFramebuffer(o.FRAMEBUFFER,null),r}async sync(){let e=this.gl,o=e.fenceSync(e.SYNC_GPU_COMMANDS_COMPLETE,0);if(!o){e.finish();return}for(e.flush();;){let t=e.clientWaitSync(o,0,0);if(t===e.ALREADY_SIGNALED||t===e.CONDITION_SATISFIED){e.deleteSync(o);return}if(t===e.WAIT_FAILED)throw e.deleteSync(o),new Error("WebGLBackend.sync: clientWaitSync returned WAIT_FAILED");await new Promise(r=>setTimeout(r,1))}}destroy(){this.gl.deleteFramebuffer(this.fbo),this.gl.getExtension("WEBGL_lose_context")?.loseContext()}};async function St(s,e,o={}){let t=s.backend==="webgpu"||s.backend==="auto",r=!!s.outputCanvas,i=()=>s.outputCanvas??new OffscreenCanvas(e.w,e.h),a=null;if(t&&await A.isAvailable()){let p=s.dtype==="f16"&&!await A.hasF16Support()?"f32":s.dtype,l=i();try{let d=await A.create({canvas:l,dtype:p});return d.device.lost.then(m=>{m.reason!=="destroyed"&&o.onContextLost?.({message:\`WebGPU device lost: \${m.reason}\${m.message?" \\u2014 "+m.message:""}\`,source:"backend-lost",recoverable:!1,cause:m})}).catch(()=>{}),{backend:d,resolvedBackend:"webgpu",resolvedDtype:p,canvas:l}}catch(d){console.warn("[setup_backend] WebGPU isAvailable but create() threw; trying WebGL fallback:",d),a=d,r&&console.warn("[setup_backend] transfer-capture topology: WebGL fallback may also fail on the same canvas")}}if(B.isAvailable()){let p=i();try{let l=B.create({canvas:p,dtype:s.dtype});return p.addEventListener("webglcontextlost",d=>{o.onContextLost?.({message:"WebGL context lost",source:"backend-lost",recoverable:!1,cause:d})}),{backend:l,resolvedBackend:"webgl",resolvedDtype:s.dtype,canvas:p}}catch(l){console.warn("[setup_backend] WebGL create() threw:",l),a=l}}let u=a?\` (last error: \${a.message??a})\`:"";throw new Error(\`setup_backend: no usable GPU backend\${u}\`)}var Be=.5,no=3,Et=10,io=30,U=(...s)=>console.log("[longpipe/autotune]",...s),It={xxs:k,xs:k,small:k,compact:S,medium:P,large:P,xl:E};async function Lt(s,e=io){s instanceof B&&(Be=Be*.5);let o=1e3/e*Be;U(\`start; budget per source frame: \${o.toFixed(1)}ms (source \${e}fps \\xD7 \${Be} safety)\`),U("backend dtype:",s.dtype);let t=null;for(let r of Se){if(!It[r.model]){U("skip",r.model,"(network class not implemented in TS yet)");continue}try{U(\`bench \${r.model} @ \${r.resolution.w}\\xD7\${r.resolution.h} skipFrames=\${r.skipFrames} \\u2026\`);let i=await uo(s,r),a=i<=o;if(U(\` \${r.model}: \${i.toFixed(1)}ms / source frame \${a?"\\u2713 within budget":"\\u2717 over budget"}\`),(a||t===null)&&(t=r),!a)break}catch(i){U(" bench failed for",r.model,":",i);break}}if(!t)throw new Error("autotune: no implementable preset available");return U("picked",t.model),t}function so(s){let e=Object.create(s);return e.ops={...s.ops,Conv2d:(o,t,r)=>{let i={weights:new Float32Array(r.kernel*r.kernel*o.c*r.outChannels),bias:new Float32Array(r.outChannels)};return s.ops.Conv2d(o,i,r)},DepthwiseConv2d:(o,t,r)=>{let i={weights:new Float32Array(r.kernel*r.kernel*o.c),bias:new Float32Array(o.c)};return s.ops.DepthwiseConv2d(o,i,r)},Conv2dAdd:(o,t,r,i)=>{let a={weights:new Float32Array(i.kernel*i.kernel*o.c*i.outChannels),bias:new Float32Array(i.outChannels)};return s.ops.Conv2dAdd(o,t,a,i)},UpsampleConv1x1:(o,t,r)=>{let i={weights:new Float32Array(o.c*r.outChannels),bias:new Float32Array(r.outChannels)};return s.ops.UpsampleConv1x1(o,i,r)}},e}function ao(){let s=new Proxy({},{get:()=>s});return s}async function uo(s,e){let o=It[e.model];if(!o)throw new Error(\`microbench: no network class for '\${e.model}'\`);let t=so(s),r=t.tensor(e.resolution.h,e.resolution.w,4),i=new o(t,r,ao());for(let l=0;l<no;l++)i.run(),await s.sync();let a=e.skipFrames+1,u=performance.now();for(let l=0;l<Et;l++)l%a===0&&i.run();return await s.sync(),(performance.now()-u)/Et}async function At(s,e,o){let t;if(s==="auto")t=await Lt(o);else if(typeof s=="string"){let r=H(s);if(!r)throw new Error(\`resolve_preset: unknown preset name '\${s}'\`);t=r}else t=s;return t.dtype!==e?{...t,dtype:e}:t}function Ft(s){let e=null,o=null;return s.onmessage=t=>{let{frame:r}=t.data;if(o){let i=o;o=null,i(r)}else e&&e.close(),e=r},s.start?.(),new ReadableStream({pull(t){if(e){t.enqueue(e),e=null;return}return new Promise(r=>{o=i=>{t.enqueue(i),r()}})},cancel(){e&&(e.close(),e=null),s.close()}},{highWaterMark:0})}function Ot(s){switch(s.topology.input){case"mstp":if(!s.inputReadable)throw new Error("create_input: topology.input='mstp' but InitData.inputReadable missing");return s.inputReadable;case"rvfc-postmessage":if(!s.inputPort)throw new Error("create_input: topology.input='rvfc-postmessage' but InitData.inputPort missing");return Ft(s.inputPort)}}function Mt(s){return new TransformStream({transform(e,o){s.process(e);let t=new VideoFrame(s.canvas,{timestamp:e.timestamp});e.close(),o.enqueue(t)}})}function Rt(s){return new WritableStream({write(e){s.process(e),e.close()}})}function Dt(s,e){return new WritableStream({write(o){s.process(o),o.close();let t=s.canvas.transferToImageBitmap();e.postMessage({bmp:t},[t])},close(){e.close()}})}function Ht(s,e,o){switch(s.topology.output){case"mstg":{if(!s.outputWritable)throw new Error("create_output: topology.output='mstg' but InitData.outputWritable missing");let t=Mt(e);return t.readable.pipeTo(s.outputWritable,{signal:o}).catch(r=>{o.aborted||console.warn("[create_output] mstg downstream pipe failed:",r)}),t.writable}case"transfer-capture":return Rt(e);case"bitmap-shuttle":{if(!s.outputPort)throw new Error("create_output: topology.output='bitmap-shuttle' but InitData.outputPort missing");return Dt(e,s.outputPort)}}}function Vt(s){if(!s.onFirstFrame)return s.input.pipeTo(s.output,{signal:s.signal});let e=!1,o=s.onFirstFrame,t=new TransformStream({transform(r,i){i.enqueue(r),e||(e=!0,queueMicrotask(o))}});return s.input.pipeThrough(t,{signal:s.signal}).pipeTo(s.output,{signal:s.signal})}var _=(...s)=>console.log("[longpipe/worker]",...s);_("script loaded");var w=null,F=null,Ue=null;self.onmessage=async function(s){let{cmd:e,data:o,request_id:t}=s.data;_("cmd received:",e,"request_id:",t);try{let r=await po(e,o);_("cmd ok:",e),bo(t,r)}catch(r){_("cmd FAILED:",e,r),D("error",{message:\`\${e} failed: \${r.message??String(r)}\`,source:"worker",recoverable:!1,cause:r})}};async function po(s,e){switch(s){case"init":return lo(e);case"startRender":return co(e.weights);case"setBackground":return mo(e);case"setEnabled":return ho(e.enabled);case"setPreset":return fo(e);case"getStats":return w?.getStats()??null;case"destroy":return go();default:throw new Error(\`unknown cmd: \${s}\`)}}async function lo(s){if(_("handleInit: start; topology=",s.topology,"preset=",s.preset,"backend=",s.backend,"dtype=",s.dtype),w)throw new Error("handleInit: already initialized");_("handleInit: setupBackend\\u2026");let e=await St(s,s.canvasSize,{onContextLost:i=>{_("GPU context lost:",i.message),D("error",i)}});_("handleInit: backend ready:",e.resolvedBackend,e.resolvedDtype,"canvas:",e.canvas.width,"x",e.canvas.height),_("handleInit: constructing Renderer (boot mode)\\u2026"),w=new K({backend:e.backend,backendKind:e.resolvedBackend,canvas:e.canvas,background:s.background,enabled:s.enabled,topology:s.topology}),F=new AbortController,_("handleInit: createInputStream\\u2026");let o=Ot(s);_("handleInit: createOutputSink\\u2026");let t=Ht(s,w,F.signal);_("handleInit: starting pipe (passthrough)\\u2026"),Vt({input:o,output:t,signal:F.signal}).then(()=>{_("pipe completed (input ended)")}).catch(i=>{if(F?.signal.aborted){_("pipe aborted (expected on destroy)");return}_("pipe FAILED:",i),D("error",{message:\`pipe failed: \${i.message}\`,source:"worker",recoverable:!1,cause:i})}),_("handleInit: resolvePreset\\u2026");let r=await At(s.preset,e.resolvedDtype,e.backend);return _("handleInit: preset resolved:",r),Ue=r,_("handleInit: done; returning InitResponse, awaiting startRender"),{resolvedPreset:r,resolvedBackend:e.resolvedBackend,resolvedDtype:e.resolvedDtype}}async function co(s){if(_("handleStartRender: start; weights bytes:",s.byteLength),!w||!Ue)throw new Error("handleStartRender: handleInit not completed");_("handleStartRender: attaching network via setPreset\\u2026"),w.setPreset(Ue,s),_("handleStartRender: ready (effect mode active)"),D("ready",void 0)}async function mo(s){w?.setBackground(s)}async function ho(s){w?.setEnabled(s)}async function fo(s){if(!w)throw new Error("handleSetPreset: not initialized");if(!s.weights)throw new Error("handleSetPreset: weights required for runtime preset swap");if(s.preset==="auto")throw new Error("handleSetPreset: 'auto' not supported on runtime swap (use at init for autotune)");let e=typeof s.preset=="string"?H(s.preset)??_o(s.preset):s.preset;return w.setPreset(e,s.weights),{resolvedPreset:e}}async function go(){F?.abort(),F=null,w?.destroy(),w=null,Ue=null}function _o(s){throw new Error(\`handleSetPreset: unknown preset '\${s}'\`)}function bo(s,e){let o={request_id:s,res:e};self.postMessage(o)}function D(s,e){let o={request_id:s,res:e};self.postMessage(o)}function Qp(s){D("stats",s)}export{Qp as emitStats};
|
|
2463
|
-
`;function
|
|
2462
|
+
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }\`,Be=class{constructor(e,r,t){n(this,"backend",e);n(this,"output");n(this,"gl");n(this,"program");n(this,"srcTex");n(this,"uOutW");n(this,"uOutH");n(this,"uSrc");n(this,"source",null);let o=e.gl;this.gl=o,this.output=e.tensor(r,t,4),this.srcTex=o.createTexture(),o.bindTexture(o.TEXTURE_2D,this.srcTex),o.texParameteri(o.TEXTURE_2D,o.TEXTURE_MIN_FILTER,o.LINEAR),o.texParameteri(o.TEXTURE_2D,o.TEXTURE_MAG_FILTER,o.LINEAR),o.texParameteri(o.TEXTURE_2D,o.TEXTURE_WRAP_S,o.CLAMP_TO_EDGE),o.texParameteri(o.TEXTURE_2D,o.TEXTURE_WRAP_T,o.CLAMP_TO_EDGE);let i=o.createShader(o.VERTEX_SHADER);o.shaderSource(i,ao),o.compileShader(i);let a=o.createShader(o.FRAGMENT_SHADER);if(o.shaderSource(a,Lt),o.compileShader(a),!o.getShaderParameter(a,o.COMPILE_STATUS))throw new Error(\`Input GLSL compile error: \${o.getShaderInfoLog(a)}\`);if(this.program=o.createProgram(),o.attachShader(this.program,i),o.attachShader(this.program,a),o.linkProgram(this.program),!o.getProgramParameter(this.program,o.LINK_STATUS))throw new Error(\`Input GLSL link error: \${o.getProgramInfoLog(this.program)}\`);this.uSrc=o.getUniformLocation(this.program,"u_src"),this.uOutW=o.getUniformLocation(this.program,"u_out_w"),this.uOutH=o.getUniformLocation(this.program,"u_out_h")}setSource(e){this.source=e}run(){if(!this.source)throw new Error("InputWebGL.run() called before setSource()");let e=this.gl;e.bindTexture(e.TEXTURE_2D,this.srcTex),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,e.RGBA,e.UNSIGNED_BYTE,this.source),e.useProgram(this.program),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.srcTex),e.uniform1i(this.uSrc,0),e.uniform1i(this.uOutW,this.output.w),e.uniform1i(this.uOutH,this.output.h),e.bindFramebuffer(e.FRAMEBUFFER,this.backend.fbo),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,this.output.texture,0),e.viewport(0,0,this.output.texW,this.output.texH),e.bindVertexArray(null),e.drawArrays(e.TRIANGLES,0,6)}};var U=class s{constructor(e,r,t){n(this,"gl",e);n(this,"canvas",r);n(this,"dtype",t);n(this,"ops");n(this,"presenters");n(this,"fbo");n(this,"textureFormat");this.fbo=e.createFramebuffer(),this.textureFormat=t==="f16"?{internalFormat:e.RGBA16F,format:e.RGBA,type:e.HALF_FLOAT,bytesPerElement:2}:{internalFormat:e.RGBA32F,format:e.RGBA,type:e.FLOAT,bytesPerElement:4},this.ops={Conv2d:(o,i,a)=>new he(this,o,i,a),DepthwiseConv2d:(o,i,a)=>new fe(this,o,i,a),Add:(o,i)=>new ge(this,o,i),Sigmoid:o=>new _e(this,o),BilinearUpsample:(o,i)=>new be(this,o,i),BicubicUpsample:(o,i)=>new ve(this,o,i),ChannelConcat:(o,i)=>new ye(this,o,i),Conv2dAdd:(o,i,a,u)=>new ke(this,o,i,a,u),UpsampleConcat:(o,i,a)=>new we(this,o,i,a),UpsampleConv1x1:(o,i,a)=>new Ce(this,o,i,a),UpsampleSigmoid:(o,i)=>new xe(this,o,i),Input:(o,i)=>new Be(this,o,i)},this.presenters={CompositeSolid:(o,i,a)=>new Te(this,o,i,a),CompositeImage:(o,i,a)=>new Pe(this,o,i,a),CompositeImageBilinear:(o,i,a)=>new We(this,o,i,a),CompositePassthrough:o=>new Ge(this,o)}}static isAvailable(){let e=null;try{return e=new OffscreenCanvas(1,1).getContext("webgl2"),!(!e||!e.getExtension("EXT_color_buffer_float"))}catch{return!1}finally{e?.getExtension("WEBGL_lose_context")?.loseContext()}}static create(e){let r=e.canvas.getContext("webgl2");if(!r)throw new Error("WebGL2 not available");if(!r.getExtension("EXT_color_buffer_float"))throw new Error("EXT_color_buffer_float not available");return new s(r,e.canvas,e.dtype??"f32")}bindDisplayFramebuffer(){this.gl.bindFramebuffer(this.gl.FRAMEBUFFER,null),this.gl.viewport(0,0,this.canvas.width,this.canvas.height)}toTextureView(e){if(e===null)return null;let r=this.dtype==="f16",t=e instanceof Uint16Array;return r===t?e:r?Q(e):A(e)}tensor(e,r,t,o){let i=r*(t/4),a=e,u=this.gl,p=u.createTexture(),l=this.textureFormat,d=this.toTextureView(o??null);return u.bindTexture(u.TEXTURE_2D,p),u.texImage2D(u.TEXTURE_2D,0,l.internalFormat,i,a,0,l.format,l.type,d),u.texParameteri(u.TEXTURE_2D,u.TEXTURE_MIN_FILTER,u.NEAREST),u.texParameteri(u.TEXTURE_2D,u.TEXTURE_MAG_FILTER,u.NEAREST),u.texParameteri(u.TEXTURE_2D,u.TEXTURE_WRAP_S,u.CLAMP_TO_EDGE),u.texParameteri(u.TEXTURE_2D,u.TEXTURE_WRAP_T,u.CLAMP_TO_EDGE),{h:e,w:r,c:t,texture:p,texW:i,texH:a}}upload(e){return{data:e}}async readback(e){let r=this.gl,t=this.textureFormat;if(r.bindFramebuffer(r.FRAMEBUFFER,this.fbo),r.framebufferTexture2D(r.FRAMEBUFFER,r.COLOR_ATTACHMENT0,r.TEXTURE_2D,e.texture,0),this.dtype==="f16"){let i=new Uint16Array(e.texW*e.texH*4);return r.readPixels(0,0,e.texW,e.texH,t.format,r.HALF_FLOAT,i),r.bindFramebuffer(r.FRAMEBUFFER,null),A(i)}let o=new Float32Array(e.texW*e.texH*4);return r.readPixels(0,0,e.texW,e.texH,t.format,r.FLOAT,o),r.bindFramebuffer(r.FRAMEBUFFER,null),o}async sync(){let e=this.gl,r=e.fenceSync(e.SYNC_GPU_COMMANDS_COMPLETE,0);if(!r){e.finish();return}for(e.flush();;){let t=e.clientWaitSync(r,0,0);if(t===e.ALREADY_SIGNALED||t===e.CONDITION_SATISFIED){e.deleteSync(r);return}if(t===e.WAIT_FAILED)throw e.deleteSync(r),new Error("WebGLBackend.sync: clientWaitSync returned WAIT_FAILED");await new Promise(o=>setTimeout(o,1))}}destroy(){this.gl.deleteFramebuffer(this.fbo),this.gl.getExtension("WEBGL_lose_context")?.loseContext()}};var Le=P("setup_backend");async function At(s,e,r={}){let t=s.backend==="webgpu"||s.backend==="auto",o=!!s.outputCanvas,i=()=>s.outputCanvas??new OffscreenCanvas(e.w,e.h),a=null;if(t&&await F.isAvailable()){let p=s.dtype==="f16"&&!await F.hasF16Support()?"f32":s.dtype,l=i();try{let d=await F.create({canvas:l,dtype:p});return d.device.lost.then(m=>{m.reason!=="destroyed"&&r.onContextLost?.({message:\`WebGPU device lost: \${m.reason}\${m.message?" \\u2014 "+m.message:""}\`,source:"backend-lost",recoverable:!1,cause:m})}).catch(()=>{}),{backend:d,resolvedBackend:"webgpu",resolvedDtype:p,canvas:l}}catch(d){Le.warn("WebGPU isAvailable but create() threw; trying WebGL fallback:",d),a=d,o&&Le.warn("transfer-capture topology: WebGL fallback may also fail on the same canvas")}}if(U.isAvailable()){let p=i();try{let l=U.create({canvas:p,dtype:s.dtype});return p.addEventListener("webglcontextlost",d=>{r.onContextLost?.({message:"WebGL context lost",source:"backend-lost",recoverable:!1,cause:d})}),{backend:l,resolvedBackend:"webgl",resolvedDtype:s.dtype,canvas:p}}catch(l){Le.warn("WebGL create() threw:",l),a=l}}let u=a?\` (last error: \${a.message??a})\`:"";throw new Error(\`setup_backend: no usable GPU backend\${u}\`)}var Ue=.5,uo=3,Ft=10,po=30,S=P("autotune"),Ot={xxs:k,xs:k,small:k,compact:E,medium:W,large:W,xl:I};async function Mt(s,e=po){s instanceof U&&(Ue=Ue*.5);let r=1e3/e*Ue;S(\`start; budget per source frame: \${r.toFixed(1)}ms (source \${e}fps \\xD7 \${Ue} safety)\`),S("backend dtype:",s.dtype);let t=null;for(let o of Ie){if(!Ot[o.model]){S("skip",o.model,"(network class not implemented in TS yet)");continue}try{S(\`bench \${o.model} @ \${o.resolution.w}\\xD7\${o.resolution.h} skipFrames=\${o.skipFrames} \\u2026\`);let i=await mo(s,o),a=i<=r;if(S(\` \${o.model}: \${i.toFixed(1)}ms / source frame \${a?"\\u2713 within budget":"\\u2717 over budget"}\`),(a||t===null)&&(t=o),!a)break}catch(i){S(" bench failed for",o.model,":",i);break}}if(!t)throw new Error("autotune: no implementable preset available");return S("picked",t.model),t}function lo(s){let e=Object.create(s);return e.ops={...s.ops,Conv2d:(r,t,o)=>{let i={weights:new Float32Array(o.kernel*o.kernel*r.c*o.outChannels),bias:new Float32Array(o.outChannels)};return s.ops.Conv2d(r,i,o)},DepthwiseConv2d:(r,t,o)=>{let i={weights:new Float32Array(o.kernel*o.kernel*r.c),bias:new Float32Array(r.c)};return s.ops.DepthwiseConv2d(r,i,o)},Conv2dAdd:(r,t,o,i)=>{let a={weights:new Float32Array(i.kernel*i.kernel*r.c*i.outChannels),bias:new Float32Array(i.outChannels)};return s.ops.Conv2dAdd(r,t,a,i)},UpsampleConv1x1:(r,t,o)=>{let i={weights:new Float32Array(r.c*o.outChannels),bias:new Float32Array(o.outChannels)};return s.ops.UpsampleConv1x1(r,i,o)}},e}function co(){let s=new Proxy({},{get:()=>s});return s}async function mo(s,e){let r=Ot[e.model];if(!r)throw new Error(\`microbench: no network class for '\${e.model}'\`);let t=lo(s),o=t.tensor(e.resolution.h,e.resolution.w,4),i=new r(t,o,co());for(let l=0;l<uo;l++)i.run(),await s.sync();let a=e.skipFrames+1,u=performance.now();for(let l=0;l<Ft;l++)l%a===0&&i.run();return await s.sync(),(performance.now()-u)/Ft}async function Rt(s,e,r){let t;if(s==="auto")t=await Mt(r);else if(typeof s=="string"){let o=V(s);if(!o)throw new Error(\`resolve_preset: unknown preset name '\${s}'\`);t=o}else t=s;return t.dtype!==e?{...t,dtype:e}:t}function Dt(s){let e=null,r=null;return s.onmessage=t=>{let{frame:o}=t.data;if(r){let i=r;r=null,i(o)}else e&&e.close(),e=o},s.start?.(),new ReadableStream({pull(t){if(e){t.enqueue(e),e=null;return}return new Promise(o=>{r=i=>{t.enqueue(i),o()}})},cancel(){e&&(e.close(),e=null),s.close()}},{highWaterMark:0})}function Ht(s){switch(s.topology.input){case"mstp":if(!s.inputReadable)throw new Error("create_input: topology.input='mstp' but InitData.inputReadable missing");return s.inputReadable;case"rvfc-postmessage":if(!s.inputPort)throw new Error("create_input: topology.input='rvfc-postmessage' but InitData.inputPort missing");return Dt(s.inputPort)}}function Vt(s){return new TransformStream({transform(e,r){s.process(e);let t=new VideoFrame(s.canvas,{timestamp:e.timestamp});e.close(),r.enqueue(t)}})}function Nt(s){return new WritableStream({write(e){s.process(e),e.close()}})}function zt(s,e){return new WritableStream({write(r){s.process(r),r.close();let t=s.canvas.transferToImageBitmap();e.postMessage({bmp:t},[t])},close(){e.close()}})}var ho=P("create_output");function Xt(s,e,r){switch(s.topology.output){case"mstg":{if(!s.outputWritable)throw new Error("create_output: topology.output='mstg' but InitData.outputWritable missing");let t=Vt(e);return t.readable.pipeTo(s.outputWritable,{signal:r}).catch(o=>{r.aborted||ho.warn("mstg downstream pipe failed:",o)}),t.writable}case"transfer-capture":return Nt(e);case"bitmap-shuttle":{if(!s.outputPort)throw new Error("create_output: topology.output='bitmap-shuttle' but InitData.outputPort missing");return zt(e,s.outputPort)}}}function $t(s){if(!s.onFirstFrame)return s.input.pipeTo(s.output,{signal:s.signal});let e=!1,r=s.onFirstFrame,t=new TransformStream({transform(o,i){i.enqueue(o),e||(e=!0,queueMicrotask(r))}});return s.input.pipeThrough(t,{signal:s.signal}).pipeTo(s.output,{signal:s.signal})}var _=P("worker");_("script loaded");var w=null,O=null,Se=null;self.onmessage=async function(s){let{cmd:e,data:r,request_id:t}=s.data;_("cmd received:",e,"request_id:",t);try{let o=await fo(e,r);_("cmd ok:",e),Co(t,o)}catch(o){_("cmd FAILED:",e,o),H("error",{message:\`\${e} failed: \${o.message??String(o)}\`,source:"worker",recoverable:!1,cause:o})}};async function fo(s,e){switch(s){case"init":return go(e);case"startRender":return _o(e.weights);case"setBackground":return bo(e);case"setEnabled":return vo(e.enabled);case"setPreset":return yo(e);case"getStats":return w?.getStats()??null;case"destroy":return xo();default:throw new Error(\`unknown cmd: \${s}\`)}}async function go(s){if(Ae(!!s.debug),_("handleInit: start; topology=",s.topology,"preset=",s.preset,"backend=",s.backend,"dtype=",s.dtype),w)throw new Error("handleInit: already initialized");_("handleInit: setupBackend\\u2026");let e=await At(s,s.canvasSize,{onContextLost:i=>{_("GPU context lost:",i.message),H("error",i)}});_("handleInit: backend ready:",e.resolvedBackend,e.resolvedDtype,"canvas:",e.canvas.width,"x",e.canvas.height),_("handleInit: constructing Renderer (boot mode)\\u2026"),w=new Y({backend:e.backend,backendKind:e.resolvedBackend,canvas:e.canvas,background:s.background,enabled:s.enabled,topology:s.topology}),O=new AbortController,_("handleInit: createInputStream\\u2026");let r=Ht(s);_("handleInit: createOutputSink\\u2026");let t=Xt(s,w,O.signal);_("handleInit: starting pipe (passthrough)\\u2026"),$t({input:r,output:t,signal:O.signal}).then(()=>{_("pipe completed (input ended)")}).catch(i=>{if(O?.signal.aborted){_("pipe aborted (expected on destroy)");return}_("pipe FAILED:",i),H("error",{message:\`pipe failed: \${i.message}\`,source:"worker",recoverable:!1,cause:i})}),_("handleInit: resolvePreset\\u2026");let o=await Rt(s.preset,e.resolvedDtype,e.backend);return _("handleInit: preset resolved:",o),Se=o,_("handleInit: done; returning InitResponse, awaiting startRender"),{resolvedPreset:o,resolvedBackend:e.resolvedBackend,resolvedDtype:e.resolvedDtype}}async function _o(s){if(_("handleStartRender: start; weights bytes:",s.byteLength),!w||!Se)throw new Error("handleStartRender: handleInit not completed");_("handleStartRender: attaching network via setPreset\\u2026"),w.setPreset(Se,s),_("handleStartRender: ready (effect mode active)"),H("ready",void 0)}async function bo(s){w?.setBackground(s)}async function vo(s){w?.setEnabled(s)}async function yo(s){if(!w)throw new Error("handleSetPreset: not initialized");if(!s.weights)throw new Error("handleSetPreset: weights required for runtime preset swap");if(s.preset==="auto")throw new Error("handleSetPreset: 'auto' not supported on runtime swap (use at init for autotune)");let e=typeof s.preset=="string"?V(s.preset)??wo(s.preset):s.preset;return w.setPreset(e,s.weights),{resolvedPreset:e}}async function xo(){O?.abort(),O=null,w?.destroy(),w=null,Se=null}function wo(s){throw new Error(\`handleSetPreset: unknown preset '\${s}'\`)}function Co(s,e){let r={request_id:s,res:e};self.postMessage(r)}function H(s,e){let r={request_id:s,res:e};self.postMessage(r)}function al(s){H("stats",s)}export{al as emitStats};
|
|
2463
|
+
`;var x=_("pipeline");function gt(){{let i=new Blob([re],{type:"application/javascript"}),t=URL.createObjectURL(i),e=new Worker(t,{type:"module"});return URL.revokeObjectURL(t),e}}var _t="https://cdn.longpipe.dev/models/v/0.0.1/",bt={background:"blur",preset:"auto",weightsBaseUrl:_t,audio:"passthrough",enabled:true,adaptive:true,debug:false},xe={w:1280,h:720};function vt(i,t){if(t)return t;let r=i.getVideoTracks()[0]?.getSettings()??{};return {w:r.width||xe.w,h:r.height||xe.h}}function ye(i,t){return `${i.replace(/\/$/,"")}/model_${t}.bin`}var ne=class{stream;ready;controller;worker;inputCleanup;outputCleanup;adaptive=null;bgCleanup=null;constructor(t,e){let r={...bt,...e};se(r.debug);let n=ce(),a=ge(n.input,t),s=vt(t,r.outputResolution),o=we(n.output,s);this.inputCleanup=a.cleanup,this.outputCleanup=o.cleanup,this.stream=de(o.videoTrack,t,r.audio),o.startPassthrough?.(t),this.worker=gt(),this.controller=new A(this.worker),this.ready=new Promise((p,l)=>{this.controller.addPersistentListener("ready",()=>{x("ready handler invoked; resolving .ready"),r.onReady?.(),p();}),this.controller.addPersistentListener("error",h=>{console.error(`[longpipe/pipeline] error (${h.source}):`,h.message),h.recoverable||l(new Error(h.message)),r.onError?.(h);});});let u={topology:n,preset:r.preset,enabled:r.enabled,backend:"auto",dtype:"f16",canvasSize:s,debug:r.debug,...a.initFields,...o.initFields},c=[...a.transferList,...o.transferList];this.bootstrap(u,r.background,c,r.weightsBaseUrl,r.adaptive,r.onError);}async bootstrap(t,e,r,n,a,s){try{x("normalizing background\u2026");let o=await te(e);this.bgCleanup=o.cleanup??null;let u={...t,background:o.background},c=[...r,...o.transferList??[]];x("sending init\u2026");let p=await this.controller.sendMessage("init",u,c);x("init resolved:",p);let l=ye(n,p.resolvedPreset.model);x("fetching weights:",l);let h=await fetch(l);if(!h.ok)throw new Error(`weights fetch failed: ${h.status} ${l}`);let g=await h.arrayBuffer();x("weights bytes:",g.byteLength),x("sending startRender\u2026"),await this.controller.sendMessage("startRender",{weights:g},[g]),x("startRender resolved; awaiting first frame"),u.preset==="auto"&&a&&(this.adaptive=new W({backendKind:p.resolvedBackend,initialModel:p.resolvedPreset.model,weightsBaseUrl:n,buildWeightsUrl:ye,getStats:()=>this.getStats(),swapPreset:async(T,J)=>{await this.controller.sendMessage("setPreset",{preset:T,weights:J},[J]);},onError:s}),this.adaptive.start());}catch(o){console.error("[longpipe/pipeline] bootstrap failed:",o),this.controller.handleMessage.call(this.controller,{data:{request_id:"error",res:{message:o.message??String(o),source:"worker",recoverable:false,cause:o}}});}}then(t,e){return this.ready.then(()=>t?t(this):this,e)}async setBackground(t){let e=await te(t),r=this.bgCleanup;this.bgCleanup=e.cleanup??null,await this.controller.sendMessage("setBackground",e.background,e.transferList),r?.();}setPreset(t,e){this.controller.sendMessage("setPreset",{preset:t,weights:e});}setEnabled(t){this.controller.sendMessage("setEnabled",{enabled:t});}async getStats(){return this.controller.sendMessage("getStats",{})}destroy(){this.adaptive?.stop(),this.adaptive=null,this.bgCleanup?.(),this.bgCleanup=null,this.controller.sendMessage("destroy",{}),this.controller.terminate(),this.inputCleanup(),this.outputCleanup();}};var C=new Float32Array(1),I=new Uint32Array(C.buffer);function wt(i){C[0]=i;let t=I[0],e=t>>>16&32768,r=t&2147483647,n=(r>>>23)-127+15;if((t&2139095040)===2139095040)return (t&8388607)!==0?e|32256:e|31744;if(n>=31)return e|31744;if(n<=0){if(n<-10)return e;let c=r&8388607|8388608,p=14-n,l=c>>>p,h=c>>>p-1&1,g=(c&(1<<p-1)-1)!==0?1:0;return h&&(g||l&1)&&(l+=1),e|l}let a=r>>>13&1023,s=r>>>12&1,o=(r&4095)!==0?1:0,u=n<<10|a;return s&&(o||a&1)&&(u+=1,(u>>>10&31)===31)?e|31744:e|u}function xt(i){let t=(i&32768)<<16,e=(i&31744)>>>10,r=i&1023;if(e===0){if(r===0)return I[0]=t,C[0];let n=r,a=1;for(;(n&1024)===0;)n<<=1,a-=1;return n&=1023,I[0]=t|a+127-15<<23|n<<13,C[0]}return e===31?(I[0]=t|2139095040|r<<13,C[0]):(I[0]=t|e+127-15<<23|r<<13,C[0])}function ke(i){let t=new Uint16Array(i.length);for(let e=0;e<i.length;e++)t[e]=wt(i[e]);return t}function ie(i){let t=new Float32Array(i.length);for(let e=0;e<i.length;e++)t[e]=xt(i[e]);return t}var d=class{constructor(t){this.backend=t;}backend;shader="";pipeline;bindGroup;uniformDefs=[];uniformBuffers={};createUniform(t,e){this.uniformDefs.push({name:t,type:e});}setUniform(t,e){let r=this.backend.device.createBuffer({size:e.byteLength,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST,mappedAtCreation:true});e instanceof Uint32Array?new Uint32Array(r.getMappedRange()).set(e):new Float32Array(r.getMappedRange()).set(e),r.unmap(),this.uniformBuffers[t]=r;}defaultBindGroup(){let t=[],e=0;for(let r of this.inputs)t.push({binding:e++,resource:{buffer:r.buffer}});for(let r of this.weights)t.push({binding:e++,resource:{buffer:r.buffer}});for(let r of this.uniformDefs)t.push({binding:e++,resource:{buffer:this.uniformBuffers[r.name]}});return t.push({binding:e,resource:{buffer:this.output.buffer}}),this.backend.device.createBindGroup({layout:this.pipeline.getBindGroupLayout(0),entries:t})}defaultSetup(){let t=this.backend.device.createShaderModule({code:this.shader});this.pipeline=this.backend.device.createComputePipeline({layout:"auto",compute:{module:t,entryPoint:"main"}}),this.bindGroup=this.defaultBindGroup();}run(){let t=this.backend.device.createCommandEncoder(),e=t.beginComputePass();e.setPipeline(this.pipeline),e.setBindGroup(0,this.bindGroup),e.dispatchWorkgroups(...this.dispatch),e.end(),this.backend.device.queue.submit([t.finish()]);}};var Ce=`// Conv2d compute shader \u2014 handles all variants:
|
|
2464
2464
|
// 1\xD71 (pointwise), 3\xD73, 5\xD75, strided, BN-fused
|
|
2465
2465
|
//
|
|
2466
2466
|
// Tensor layout: NHWC with channels in vec4 groups
|
|
@@ -2543,7 +2543,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
2543
2543
|
let out_idx = y * params.out_w * O + x * O + o;
|
|
2544
2544
|
output_buf[out_idx] = result;
|
|
2545
2545
|
}
|
|
2546
|
-
`;var
|
|
2546
|
+
`;var Pe=`enable f16;
|
|
2547
2547
|
|
|
2548
2548
|
// Conv2d \u2014 full f16 variant.
|
|
2549
2549
|
// All buffers (input, output, weights, bias) are f16. Weights are converted
|
|
@@ -2616,7 +2616,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
2616
2616
|
|
|
2617
2617
|
output_buf[y * params.out_w * O + x * O + o] = result;
|
|
2618
2618
|
}
|
|
2619
|
-
`;function
|
|
2619
|
+
`;function b(i,t,e,r){return typeof r=="number"?Math.floor((i+2*r-t)/e)+1:r==="same"?Math.ceil(i/e):Math.floor((i-t)/e)+1}function Ct(i,t,e,r){return Math.floor(Math.max((t-1)*r+e-i,0)/2)}function v(i,t,e,r,n){return typeof i=="number"?i:i==="same"?Ct(t,e,r,n):0}function f(i){return i instanceof Float32Array||i instanceof Uint16Array?i:new Float32Array(i)}var F=class extends d{inputs;weights;output;dispatch;shader;constructor(t,e,r,n){super(t),this.shader=t.dtype==="f16"?Pe:Ce;let a=b(e.h,n.kernel,n.stride,n.padding),s=b(e.w,n.kernel,n.stride,n.padding),o=e.c/4,u=n.outChannels/4,c=v(n.padding,e.h,a,n.kernel,n.stride),p=v(n.padding,e.w,s,n.kernel,n.stride);this.output=t.tensor(a,s,n.outChannels),this.inputs=[e],this.weights=[t.upload(f(r.weights)),t.upload(f(r.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,a,s,o,u,n.kernel,n.kernel,n.stride,c,p,n.activation==="relu6"?1:0])),this.defaultSetup(),this.dispatch=[Math.ceil(s/8),Math.ceil(a/8),u];}};var Ie=`// Depthwise Conv2d \u2014 groups = in_channels (each channel convolved independently).
|
|
2620
2620
|
//
|
|
2621
2621
|
// Weight layout: [K*K][channel_groups] array of vec4
|
|
2622
2622
|
// weight index = (ky*kernel_w + kx) * channel_groups + c
|
|
@@ -2691,7 +2691,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
2691
2691
|
let out_idx = y * params.out_w * C + x * C + c;
|
|
2692
2692
|
output_buf[out_idx] = result;
|
|
2693
2693
|
}
|
|
2694
|
-
`;var
|
|
2694
|
+
`;var Te=`enable f16;
|
|
2695
2695
|
|
|
2696
2696
|
// Depthwise conv2d \u2014 full f16 variant. All buffers f16.
|
|
2697
2697
|
|
|
@@ -2756,7 +2756,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
2756
2756
|
|
|
2757
2757
|
output_buf[y * params.out_w * C + x * C + c] = result;
|
|
2758
2758
|
}
|
|
2759
|
-
`;var
|
|
2759
|
+
`;var O=class extends d{inputs;weights;output;dispatch;shader;constructor(t,e,r,n){super(t),this.shader=t.dtype==="f16"?Te:Ie;let a=b(e.h,n.kernel,n.stride,n.padding),s=b(e.w,n.kernel,n.stride,n.padding),o=e.c/4,u=v(n.padding,e.h,a,n.kernel,n.stride),c=v(n.padding,e.w,s,n.kernel,n.stride);this.output=t.tensor(a,s,e.c),this.inputs=[e],this.weights=[t.upload(f(r.weights)),t.upload(f(r.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,a,s,o,n.kernel,n.kernel,n.stride,u,c,n.activation==="relu6"?1:0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(s/8),Math.ceil(a/8),o];}};var Ue=`// Element-wise add of two tensors \u2014 used for residual connections in MBConv blocks.
|
|
2760
2760
|
// Operates on the flat float buffer directly; layout is irrelevant for a pure element-wise op.
|
|
2761
2761
|
|
|
2762
2762
|
struct Params {
|
|
@@ -2777,7 +2777,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
2777
2777
|
if (idx >= params.size) { return; }
|
|
2778
2778
|
output[idx] = input_a[idx] + input_b[idx];
|
|
2779
2779
|
}
|
|
2780
|
-
`;var
|
|
2780
|
+
`;var Se=`enable f16;
|
|
2781
2781
|
|
|
2782
2782
|
// Element-wise add \u2014 full f16 variant.
|
|
2783
2783
|
// array<f16> is binary-compatible with array<vec4<f16>> written by the f16 conv shaders.
|
|
@@ -2800,7 +2800,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
2800
2800
|
if (idx >= params.size) { return; }
|
|
2801
2801
|
output[idx] = input_a[idx] + input_b[idx];
|
|
2802
2802
|
}
|
|
2803
|
-
`;var
|
|
2803
|
+
`;var M=class extends d{inputs;weights=[];output;dispatch;shader;constructor(t,e,r){super(t),this.shader=t.dtype==="f16"?Se:Ue;let n=e.h*e.w*e.c;this.output=t.tensor(e.h,e.w,e.c),this.inputs=[e,r],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([n,0,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(n/256),1,1];}};var Ee=`// Element-wise sigmoid: output = 1 / (1 + exp(-x)).
|
|
2804
2804
|
// Operates on packed vec4 buffers (NHWC layout). exp() and arithmetic are element-wise on vec4.
|
|
2805
2805
|
|
|
2806
2806
|
struct Params {
|
|
@@ -2820,7 +2820,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
2820
2820
|
if (idx >= params.n_groups) { return; }
|
|
2821
2821
|
output_buf[idx] = 1.0 / (1.0 + exp(-input_buf[idx]));
|
|
2822
2822
|
}
|
|
2823
|
-
`;var
|
|
2823
|
+
`;var We=`enable f16;
|
|
2824
2824
|
|
|
2825
2825
|
// Sigmoid \u2014 full f16 variant.
|
|
2826
2826
|
|
|
@@ -2842,7 +2842,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
2842
2842
|
let x = vec4<f32>(input_buf[idx]);
|
|
2843
2843
|
output_buf[idx] = vec4<f16>(1.0 / (1.0 + exp(-x)));
|
|
2844
2844
|
}
|
|
2845
|
-
`;var
|
|
2845
|
+
`;var R=class extends d{inputs;weights=[];output;dispatch;shader;constructor(t,e){super(t),this.shader=t.dtype==="f16"?We:Ee;let r=e.h*e.w*(e.c/4);this.output=t.tensor(e.h,e.w,e.c),this.inputs=[e],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([r,0,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(r/256),1,1];}};var Be=`// Bilinear upsample (arbitrary ratio), align_corners=False (matches PyTorch default).
|
|
2846
2846
|
// Input/output in NHWC vec4 format: index = y*W*(C/4) + x*(C/4) + c_group.
|
|
2847
2847
|
// Each thread computes one output pixel for one channel group (vec4 = 4 channels).
|
|
2848
2848
|
|
|
@@ -2900,7 +2900,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
2900
2900
|
|
|
2901
2901
|
output_buf[oy * params.out_w * C + ox * C + c] = result;
|
|
2902
2902
|
}
|
|
2903
|
-
`;var
|
|
2903
|
+
`;var Ge=`enable f16;
|
|
2904
2904
|
|
|
2905
2905
|
// Bilinear upsample 2\xD7 \u2014 full f16 variant.
|
|
2906
2906
|
// Interpolation weights (wx, wy) and intermediate blends computed in f32 for
|
|
@@ -2956,7 +2956,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
2956
2956
|
|
|
2957
2957
|
output_buf[oy * params.out_w * C + ox * C + c] = vec4<f16>(result);
|
|
2958
2958
|
}
|
|
2959
|
-
`;var
|
|
2959
|
+
`;var D=class extends d{inputs;weights=[];output;dispatch;shader;constructor(t,e,r){super(t),this.shader=t.dtype==="f16"?Ge:Be;let n=e.c/4;this.output=t.tensor(r.outH,r.outW,e.c),this.inputs=[e],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,r.outH,r.outW,n,0,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(r.outW/8),Math.ceil(r.outH/8),n];}};var Ae=`// Bicubic upsample (arbitrary scale) \u2014 Keys cubic, a=-0.75 (PyTorch default
|
|
2960
2960
|
// for mode='bicubic', align_corners=False). Direct 2D, 4\xD74 = 16 taps per
|
|
2961
2961
|
// output pixel. NHWC vec4 layout: index = y*W*(C/4) + x*(C/4) + c_group.
|
|
2962
2962
|
|
|
@@ -3023,7 +3023,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
3023
3023
|
|
|
3024
3024
|
output_buf[oy * params.out_w * C + ox * C + c] = acc;
|
|
3025
3025
|
}
|
|
3026
|
-
`;var
|
|
3026
|
+
`;var Fe=`enable f16;
|
|
3027
3027
|
|
|
3028
3028
|
// Bicubic upsample \u2014 full f16 storage variant. Bicubic weights and the per-
|
|
3029
3029
|
// pixel accumulator are computed in f32 (cheap to keep precision around the
|
|
@@ -3092,7 +3092,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
3092
3092
|
|
|
3093
3093
|
output_buf[oy * params.out_w * C + ox * C + c] = vec4<f16>(acc);
|
|
3094
3094
|
}
|
|
3095
|
-
`;var
|
|
3095
|
+
`;var H=class extends d{inputs;weights=[];output;dispatch;shader;constructor(t,e,r){super(t),this.shader=t.dtype==="f16"?Fe:Ae;let n=e.c/4;this.output=t.tensor(r.outH,r.outW,e.c),this.inputs=[e],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,r.outH,r.outW,n,0,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(r.outW/8),Math.ceil(r.outH/8),n];}};var Oe=`// Channel concatenation: output = cat(A, B, dim=channel).
|
|
3096
3096
|
// Both A and B must share the same H\xD7W and be in NHWC vec4 format.
|
|
3097
3097
|
// Output layout: for each (y, x), the first a_groups vec4s come from A,
|
|
3098
3098
|
// followed by b_groups vec4s from B.
|
|
@@ -3137,7 +3137,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
3137
3137
|
output_buf[out_idx] = input_b[y * W * Bg + x * Bg + c_b];
|
|
3138
3138
|
}
|
|
3139
3139
|
}
|
|
3140
|
-
`;var
|
|
3140
|
+
`;var Me=`enable f16;
|
|
3141
3141
|
|
|
3142
3142
|
// Channel concatenation \u2014 full f16 variant.
|
|
3143
3143
|
|
|
@@ -3178,7 +3178,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
3178
3178
|
output_buf[out_idx] = input_b[y * W * Bg + x * Bg + c_b];
|
|
3179
3179
|
}
|
|
3180
3180
|
}
|
|
3181
|
-
`;var
|
|
3181
|
+
`;var L=class extends d{inputs;weights=[];output;dispatch;shader;constructor(t,e,r){super(t),this.shader=t.dtype==="f16"?Me:Oe;let n=e.c/4,a=r.c/4,s=n+a;this.output=t.tensor(e.h,e.w,e.c+r.c),this.inputs=[e,r],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,n,a,s,0,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(e.w/8),Math.ceil(e.h/8),s];}};var Re=`// Conv2d + skip add fused.
|
|
3182
3182
|
// Identical to conv2d.wgsl except skip is an activation input (binding 1),
|
|
3183
3183
|
// added element-wise to the conv result at write time.
|
|
3184
3184
|
// Eliminates the separate add dispatch and its intermediate buffer round-trip.
|
|
@@ -3252,7 +3252,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
3252
3252
|
let out_idx = y * params.out_w * O + x * O + o;
|
|
3253
3253
|
output_buf[out_idx] = result + skip_buf[out_idx];
|
|
3254
3254
|
}
|
|
3255
|
-
`;var
|
|
3255
|
+
`;var De=`enable f16;
|
|
3256
3256
|
|
|
3257
3257
|
// Conv2d + skip add fused \u2014 full f16 variant.
|
|
3258
3258
|
|
|
@@ -3326,7 +3326,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
3326
3326
|
let out_idx = y * params.out_w * O + x * O + o;
|
|
3327
3327
|
output_buf[out_idx] = result + skip_buf[out_idx];
|
|
3328
3328
|
}
|
|
3329
|
-
`;var
|
|
3329
|
+
`;var V=class extends d{inputs;weights;output;dispatch;shader;constructor(t,e,r,n,a){super(t),this.shader=t.dtype==="f16"?De:Re;let s=b(e.h,a.kernel,a.stride,a.padding),o=b(e.w,a.kernel,a.stride,a.padding),u=e.c/4,c=a.outChannels/4,p=v(a.padding,e.h,s,a.kernel,a.stride),l=v(a.padding,e.w,o,a.kernel,a.stride);this.output=t.tensor(s,o,a.outChannels),this.inputs=[e,r],this.weights=[t.upload(f(n.weights)),t.upload(f(n.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,s,o,u,c,a.kernel,a.kernel,a.stride,p,l,a.activation==="relu6"?1:0])),this.defaultSetup(),this.dispatch=[Math.ceil(o/8),Math.ceil(s/8),c];}};var He=`// Bilinear upsample + channel concat fused.
|
|
3330
3330
|
// input_a is the decoder tensor at small spatial resolution (in_h \xD7 in_w).
|
|
3331
3331
|
// input_b is the encoder skip feature already at output resolution (out_h \xD7 out_w).
|
|
3332
3332
|
// For output channels 0..a_groups-1: bilinearly interpolate from input_a.
|
|
@@ -3387,7 +3387,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
3387
3387
|
output_buf[out_idx] = input_b[oy * params.out_w * params.b_groups + ox * params.b_groups + c_b];
|
|
3388
3388
|
}
|
|
3389
3389
|
}
|
|
3390
|
-
`;var
|
|
3390
|
+
`;var Le=`enable f16;
|
|
3391
3391
|
|
|
3392
3392
|
// Bilinear upsample + channel concat fused \u2014 full f16 variant.
|
|
3393
3393
|
// Bilinear weights (wx, wy) and intermediate blends computed in f32; result cast to f16.
|
|
@@ -3447,7 +3447,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
3447
3447
|
output_buf[out_idx] = input_b[oy * params.out_w * params.b_groups + ox * params.b_groups + c_b];
|
|
3448
3448
|
}
|
|
3449
3449
|
}
|
|
3450
|
-
`;var
|
|
3450
|
+
`;var z=class extends d{inputs;weights=[];output;dispatch;shader;constructor(t,e,r,n){super(t),this.shader=t.dtype==="f16"?Le:He;let a=e.c/4,s=r.c/4,o=a+s;this.output=t.tensor(n.outH,n.outW,e.c+r.c),this.inputs=[e,r],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,n.outH,n.outW,a,s,o,0])),this.defaultSetup(),this.dispatch=[Math.ceil(n.outW/8),Math.ceil(n.outH/8),o];}};var Ve=`// Bilinear upsample + 1\xD71 pointwise conv fused.
|
|
3451
3451
|
// For each output pixel, bilinearly samples the small input for each in_group,
|
|
3452
3452
|
// immediately applies the 1\xD71 conv weights, and writes the activated result.
|
|
3453
3453
|
// Eliminates the intermediate full-resolution upsample buffer.
|
|
@@ -3514,7 +3514,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
3514
3514
|
|
|
3515
3515
|
output_buf[oy * params.out_w * params.out_groups + ox * params.out_groups + og] = result;
|
|
3516
3516
|
}
|
|
3517
|
-
`;var
|
|
3517
|
+
`;var ze=`enable f16;
|
|
3518
3518
|
|
|
3519
3519
|
// Bilinear upsample + 1\xD71 pointwise conv fused \u2014 full f16 variant.
|
|
3520
3520
|
// Bilinear weights and intermediate blends computed in f32; conv accumulation in f16.
|
|
@@ -3581,7 +3581,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
3581
3581
|
|
|
3582
3582
|
output_buf[oy * params.out_w * params.out_groups + ox * params.out_groups + og] = result;
|
|
3583
3583
|
}
|
|
3584
|
-
`;var
|
|
3584
|
+
`;var N=class extends d{inputs;weights;output;dispatch;shader;constructor(t,e,r,n){super(t),this.shader=t.dtype==="f16"?ze:Ve;let a=e.c/4,s=n.outChannels/4;this.output=t.tensor(n.outH,n.outW,n.outChannels),this.inputs=[e],this.weights=[t.upload(f(r.weights)),t.upload(f(r.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,n.outH,n.outW,a,s,n.activation==="relu6"?1:0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(n.outW/8),Math.ceil(n.outH/8),s];}};var Ne=`// Bilinear upsample + sigmoid fused.
|
|
3585
3585
|
// Identical to bilinear_upsample.wgsl except sigmoid is applied at write time.
|
|
3586
3586
|
// Eliminates the intermediate full-resolution buffer and the separate sigmoid dispatch.
|
|
3587
3587
|
|
|
@@ -3635,7 +3635,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
3635
3635
|
|
|
3636
3636
|
output_buf[oy * params.out_w * C + ox * C + c] = 1.0 / (1.0 + exp(-result));
|
|
3637
3637
|
}
|
|
3638
|
-
`;var
|
|
3638
|
+
`;var $e=`enable f16;
|
|
3639
3639
|
|
|
3640
3640
|
// Bilinear upsample + sigmoid fused \u2014 full f16 variant.
|
|
3641
3641
|
// Interpolation computed in f32 for accuracy; sigmoid and result cast to f16.
|
|
@@ -3690,7 +3690,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
3690
3690
|
|
|
3691
3691
|
output_buf[oy * params.out_w * C + ox * C + c] = vec4<f16>(1.0 / (1.0 + exp(-result)));
|
|
3692
3692
|
}
|
|
3693
|
-
`;var
|
|
3693
|
+
`;var $=class extends d{inputs;weights=[];output;dispatch;shader;constructor(t,e,r){super(t),this.shader=t.dtype==="f16"?$e:Ne;let n=e.c/4;this.output=t.tensor(r.outH,r.outW,e.c),this.inputs=[e],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,r.outH,r.outW,n,0,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(r.outW/8),Math.ceil(r.outH/8),n];}};var qe=`// Composite an RGBA image over a solid background, gated by a 1-ch alpha.
|
|
3694
3694
|
// Fragment writes the canvas's swapchain texture (premultiplied output).
|
|
3695
3695
|
//
|
|
3696
3696
|
// Caller invariants (matched in CompositeSolidWebGPU):
|
|
@@ -3735,7 +3735,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
3735
3735
|
let rgb = fg * a + params.bgColor.rgb * (1.0 - a);
|
|
3736
3736
|
return vec4<f32>(rgb, 1.0);
|
|
3737
3737
|
}
|
|
3738
|
-
`;var
|
|
3738
|
+
`;var Xe=`enable f16;
|
|
3739
3739
|
|
|
3740
3740
|
// Composite an RGBA image over a solid background, gated by a 1-ch alpha.
|
|
3741
3741
|
// f16 variant: image and alpha are stored as f16; values promote to f32 on
|
|
@@ -3784,7 +3784,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
3784
3784
|
let rgb = fg * a + params.bgColor.rgb * (1.0 - a);
|
|
3785
3785
|
return vec4<f32>(rgb, 1.0);
|
|
3786
3786
|
}
|
|
3787
|
-
`;var
|
|
3787
|
+
`;var q=class{constructor(t,e,r,n){this.backend=t;if(e.h!==r.h||e.w!==r.w)throw new Error(`CompositeSolid: image (${e.h}\xD7${e.w}) and alpha (${r.h}\xD7${r.w}) must match. Run the upscaler first.`);let a=t.device;this.uniformBuffer=a.createBuffer({size:32,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});let s=new ArrayBuffer(32);new Uint32Array(s,0,1)[0]=e.w,new Float32Array(s,16,4).set([n[0],n[1],n[2],0]),a.queue.writeBuffer(this.uniformBuffer,0,s);let o=t.dtype==="f16"?Xe:qe,u=a.createShaderModule({code:o});this.pipeline=a.createRenderPipeline({layout:"auto",vertex:{module:u,entryPoint:"vs"},fragment:{module:u,entryPoint:"fs",targets:[{format:t.canvasFormat}]},primitive:{topology:"triangle-list"}}),this.bindGroup=a.createBindGroup({layout:this.pipeline.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:e.buffer}},{binding:1,resource:{buffer:r.buffer}},{binding:2,resource:{buffer:this.uniformBuffer}}]});}backend;pipeline;bindGroup;uniformBuffer;outputView=null;setOutput(t){this.outputView=t.createView();}run(){if(!this.outputView)throw new Error("CompositeSolidWebGPU.run() called before setOutput()");let t=this.backend.device.createCommandEncoder(),e=t.beginRenderPass({colorAttachments:[{view:this.outputView,clearValue:[0,0,0,1],loadOp:"clear",storeOp:"store"}]});e.setPipeline(this.pipeline),e.setBindGroup(0,this.bindGroup),e.draw(6),e.end(),this.backend.device.queue.submit([t.finish()]),this.outputView=null;}};var je=`// Like composite_solid but bg is an NHWC vec4 storage buffer (e.g. virtual
|
|
3788
3788
|
// background image, or a blurred copy of the input).
|
|
3789
3789
|
|
|
3790
3790
|
struct VertexOut {
|
|
@@ -3826,7 +3826,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
3826
3826
|
let rgb = fg * a + bgc * (1.0 - a);
|
|
3827
3827
|
return vec4<f32>(rgb, 1.0);
|
|
3828
3828
|
}
|
|
3829
|
-
`;var
|
|
3829
|
+
`;var Ke=`enable f16;
|
|
3830
3830
|
|
|
3831
3831
|
// Like composite_solid_f16 but bg is an NHWC vec4<f16> storage buffer (e.g. a
|
|
3832
3832
|
// virtual background image, or a blurred copy of the input).
|
|
@@ -3870,7 +3870,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
3870
3870
|
let rgb = fg * a + bgc * (1.0 - a);
|
|
3871
3871
|
return vec4<f32>(rgb, 1.0);
|
|
3872
3872
|
}
|
|
3873
|
-
`;var
|
|
3873
|
+
`;var X=class{constructor(t,e,r,n){this.backend=t;if(e.h!==r.h||e.w!==r.w||e.h!==n.h||e.w!==n.w)throw new Error(`CompositeImage: image (${e.h}\xD7${e.w}), alpha (${r.h}\xD7${r.w}), and bg (${n.h}\xD7${n.w}) must all match. Run upscaler / resizer first.`);let a=t.device;this.uniformBuffer=a.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});let s=new ArrayBuffer(16);new Uint32Array(s,0,1)[0]=e.w,a.queue.writeBuffer(this.uniformBuffer,0,s);let o=t.dtype==="f16"?Ke:je,u=a.createShaderModule({code:o});this.pipeline=a.createRenderPipeline({layout:"auto",vertex:{module:u,entryPoint:"vs"},fragment:{module:u,entryPoint:"fs",targets:[{format:t.canvasFormat}]},primitive:{topology:"triangle-list"}}),this.bindGroup=a.createBindGroup({layout:this.pipeline.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:e.buffer}},{binding:1,resource:{buffer:r.buffer}},{binding:2,resource:{buffer:this.uniformBuffer}},{binding:3,resource:{buffer:n.buffer}}]});}backend;pipeline;bindGroup;uniformBuffer;outputView=null;setOutput(t){this.outputView=t.createView();}run(){if(!this.outputView)throw new Error("CompositeImageWebGPU.run() called before setOutput()");let t=this.backend.device.createCommandEncoder(),e=t.beginRenderPass({colorAttachments:[{view:this.outputView,clearValue:[0,0,0,1],loadOp:"clear",storeOp:"store"}]});e.setPipeline(this.pipeline),e.setBindGroup(0,this.bindGroup),e.draw(6),e.end(),this.backend.device.queue.submit([t.finish()]),this.outputView=null;}};var Ye=`// Like composite_image but bg is sampled bilinearly \u2014 bg may be smaller than
|
|
3874
3874
|
// (image, alpha). Used by CompositorBlur to skip the final full-res upsample
|
|
3875
3875
|
// in the blur pyramid and let this shader's own per-pixel scan do the
|
|
3876
3876
|
// expansion (the work is already happening here for the composite anyway).
|
|
@@ -3935,7 +3935,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
3935
3935
|
let rgb = fg * a + bgc * (1.0 - a);
|
|
3936
3936
|
return vec4<f32>(rgb, 1.0);
|
|
3937
3937
|
}
|
|
3938
|
-
`;var
|
|
3938
|
+
`;var Je=`enable f16;
|
|
3939
3939
|
|
|
3940
3940
|
// f16 storage variant of composite_image_bilinear. bg is at a smaller
|
|
3941
3941
|
// resolution and is bilinearly sampled to match (image, alpha) at full res.
|
|
@@ -3996,7 +3996,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
3996
3996
|
let rgb = fg * a + bgc * (1.0 - a);
|
|
3997
3997
|
return vec4<f32>(rgb, 1.0);
|
|
3998
3998
|
}
|
|
3999
|
-
`;var
|
|
3999
|
+
`;var j=class{constructor(t,e,r,n){this.backend=t;if(e.h!==r.h||e.w!==r.w)throw new Error(`CompositeImageBilinear: image (${e.h}\xD7${e.w}) and alpha (${r.h}\xD7${r.w}) must match.`);let a=t.device;this.uniformBuffer=a.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});let s=new ArrayBuffer(16),o=new Uint32Array(s);o[0]=e.w,o[1]=e.h,o[2]=n.w,o[3]=n.h,a.queue.writeBuffer(this.uniformBuffer,0,s);let u=t.dtype==="f16"?Je:Ye,c=a.createShaderModule({code:u});this.pipeline=a.createRenderPipeline({layout:"auto",vertex:{module:c,entryPoint:"vs"},fragment:{module:c,entryPoint:"fs",targets:[{format:t.canvasFormat}]},primitive:{topology:"triangle-list"}}),this.bindGroup=a.createBindGroup({layout:this.pipeline.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:e.buffer}},{binding:1,resource:{buffer:r.buffer}},{binding:2,resource:{buffer:this.uniformBuffer}},{binding:3,resource:{buffer:n.buffer}}]});}backend;pipeline;bindGroup;uniformBuffer;outputView=null;setOutput(t){this.outputView=t.createView();}run(){if(!this.outputView)throw new Error("CompositeImageBilinearWebGPU.run() called before setOutput()");let t=this.backend.device.createCommandEncoder(),e=t.beginRenderPass({colorAttachments:[{view:this.outputView,clearValue:[0,0,0,1],loadOp:"clear",storeOp:"store"}]});e.setPipeline(this.pipeline),e.setBindGroup(0,this.bindGroup),e.draw(6),e.end(),this.backend.device.queue.submit([t.finish()]),this.outputView=null;}};var Qe=`// Passthrough "compositor" \u2014 writes the image directly to the canvas
|
|
4000
4000
|
// swapchain texture with no alpha math and no background. Used by RenderOp
|
|
4001
4001
|
// when the renderer is in disabled state, so the output canvas reflects
|
|
4002
4002
|
// the unmodified input frame instead of a stale matted result.
|
|
@@ -4034,7 +4034,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
4034
4034
|
let i = y * params.width + x;
|
|
4035
4035
|
return vec4<f32>(image[i].rgb, 1.0);
|
|
4036
4036
|
}
|
|
4037
|
-
`;var
|
|
4037
|
+
`;var Ze=`enable f16;
|
|
4038
4038
|
|
|
4039
4039
|
// Passthrough "compositor" \u2014 f16 variant. Image is stored as f16; values
|
|
4040
4040
|
// promote to f32 on read and the fragment writes f32 to the canvas
|
|
@@ -4070,7 +4070,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
4070
4070
|
let i = y * params.width + x;
|
|
4071
4071
|
return vec4<f32>(vec3<f32>(image[i].rgb), 1.0);
|
|
4072
4072
|
}
|
|
4073
|
-
`;var
|
|
4073
|
+
`;var K=class{constructor(t,e){this.backend=t;let r=t.device;this.uniformBuffer=r.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});let n=new ArrayBuffer(16);new Uint32Array(n,0,1)[0]=e.w,r.queue.writeBuffer(this.uniformBuffer,0,n);let a=t.dtype==="f16"?Ze:Qe,s=r.createShaderModule({code:a});this.pipeline=r.createRenderPipeline({layout:"auto",vertex:{module:s,entryPoint:"vs"},fragment:{module:s,entryPoint:"fs",targets:[{format:t.canvasFormat}]},primitive:{topology:"triangle-list"}}),this.bindGroup=r.createBindGroup({layout:this.pipeline.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:e.buffer}},{binding:1,resource:{buffer:this.uniformBuffer}}]});}backend;pipeline;bindGroup;uniformBuffer;outputView=null;setOutput(t){this.outputView=t.createView();}run(){if(!this.outputView)throw new Error("CompositePassthroughWebGPU.run() called before setOutput()");let t=this.backend.device.createCommandEncoder(),e=t.beginRenderPass({colorAttachments:[{view:this.outputView,clearValue:[0,0,0,1],loadOp:"clear",storeOp:"store"}]});e.setPipeline(this.pipeline),e.setBindGroup(0,this.bindGroup),e.draw(6),e.end(),this.backend.device.queue.submit([t.finish()]),this.outputView=null;}};var et=`// Input op \u2014 sample a regular 2D source texture (RGBA8 unorm) into the NHWC
|
|
4074
4074
|
// vec4<f32> output buffer at the target resolution. Used for ImageBitmap
|
|
4075
4075
|
// sources, which are uploaded into a persistent staging texture via
|
|
4076
4076
|
// copyExternalImageToTexture before each dispatch.
|
|
@@ -4100,7 +4100,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4100
4100
|
let rgba = textureSampleLevel(src_tex, src_sampler, uv, 0.0);
|
|
4101
4101
|
output_buf[y * params.out_w + x] = rgba;
|
|
4102
4102
|
}
|
|
4103
|
-
`;var
|
|
4103
|
+
`;var tt=`enable f16;
|
|
4104
4104
|
|
|
4105
4105
|
// Input op \u2014 f16 storage variant. Source is sampled as vec4<f32>; only the
|
|
4106
4106
|
// store is demoted to vec4<f16>.
|
|
@@ -4130,7 +4130,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4130
4130
|
let rgba = textureSampleLevel(src_tex, src_sampler, uv, 0.0);
|
|
4131
4131
|
output_buf[y * params.out_w + x] = vec4<f16>(rgba);
|
|
4132
4132
|
}
|
|
4133
|
-
`;var
|
|
4133
|
+
`;var rt=`// Input op \u2014 sample a GPUExternalTexture (zero-copy VideoFrame import) into
|
|
4134
4134
|
// the NHWC vec4<f32> output buffer at the target resolution. Used when the
|
|
4135
4135
|
// caller passes a VideoFrame to setSource(); requires importExternalTexture
|
|
4136
4136
|
// to be called in the same task as the dispatch (the texture is invalidated
|
|
@@ -4161,7 +4161,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4161
4161
|
let rgba = textureSampleBaseClampToEdge(src_tex, src_sampler, uv);
|
|
4162
4162
|
output_buf[y * params.out_w + x] = rgba;
|
|
4163
4163
|
}
|
|
4164
|
-
`;var
|
|
4164
|
+
`;var nt=`enable f16;
|
|
4165
4165
|
|
|
4166
4166
|
// Input op \u2014 texture_external + f16 storage. Sample in f32, store as f16.
|
|
4167
4167
|
|
|
@@ -4190,4 +4190,4 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4190
4190
|
let rgba = textureSampleBaseClampToEdge(src_tex, src_sampler, uv);
|
|
4191
4191
|
output_buf[y * params.out_w + x] = vec4<f16>(rgba);
|
|
4192
4192
|
}
|
|
4193
|
-
`;var
|
|
4193
|
+
`;var nr=i=>typeof VideoFrame<"u"&&i instanceof VideoFrame,Y=class{output;device;dtype;sampler;uniformBuffer;dispatch;pipeline2d=null;pipelineExternal=null;stagingTex=null;stagingW=0;stagingH=0;source=null;constructor(t,e,r){this.device=t.device,this.dtype=t.dtype,this.output=t.tensor(e,r,4),this.sampler=this.device.createSampler({magFilter:"linear",minFilter:"linear",addressModeU:"clamp-to-edge",addressModeV:"clamp-to-edge"}),this.uniformBuffer=this.device.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});let n=new ArrayBuffer(16);new Uint32Array(n,0,2).set([r,e]),this.device.queue.writeBuffer(this.uniformBuffer,0,n),this.dispatch=[Math.ceil(r/8),Math.ceil(e/8),1],this.pipeline2d=this.buildPipeline(this.dtype==="f16"?tt:et);}setSource(t){this.source=t;}run(){if(!this.source)throw new Error("InputWebGPU.run() called before setSource()");nr(this.source)?this.runExternal(this.source):this.run2d(this.source);}run2d(t){this.ensureStagingTexture(t.width,t.height),this.device.queue.copyExternalImageToTexture({source:t,flipY:false},{texture:this.stagingTex},[t.width,t.height]);let e=this.device.createBindGroup({layout:this.pipeline2d.getBindGroupLayout(0),entries:[{binding:0,resource:this.stagingTex.createView()},{binding:1,resource:this.sampler},{binding:2,resource:{buffer:this.uniformBuffer}},{binding:3,resource:{buffer:this.output.buffer}}]});this.dispatchOnce(this.pipeline2d,e);}runExternal(t){this.pipelineExternal||(this.pipelineExternal=this.buildPipeline(this.dtype==="f16"?nt:rt));let e=this.device.importExternalTexture({source:t}),r=this.device.createBindGroup({layout:this.pipelineExternal.getBindGroupLayout(0),entries:[{binding:0,resource:e},{binding:1,resource:this.sampler},{binding:2,resource:{buffer:this.uniformBuffer}},{binding:3,resource:{buffer:this.output.buffer}}]});this.dispatchOnce(this.pipelineExternal,r);}ensureStagingTexture(t,e){this.stagingTex&&this.stagingW===t&&this.stagingH===e||(this.stagingTex?.destroy(),this.stagingTex=this.device.createTexture({size:[t,e,1],format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT}),this.stagingW=t,this.stagingH=e);}buildPipeline(t){let e=this.device.createShaderModule({code:t});return this.device.createComputePipeline({layout:"auto",compute:{module:e,entryPoint:"main"}})}dispatchOnce(t,e){let r=this.device.createCommandEncoder(),n=r.beginComputePass();n.setPipeline(t),n.setBindGroup(0,e),n.dispatchWorkgroups(...this.dispatch),n.end(),this.device.queue.submit([r.finish()]);}};var ir=navigator.gpu?GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST:0,ae=class i{constructor(t,e,r){this.device=t;this.canvas=e;this.dtype=r;this.bytesPerElement=r==="f16"?2:4;let n=e.getContext("webgpu");if(!n)throw new Error("Failed to get WebGPU context from canvas");this.canvasContext=n,this.canvasFormat=navigator.gpu.getPreferredCanvasFormat(),this.canvasContext.configure({device:t,format:this.canvasFormat,alphaMode:"premultiplied"}),this.ops={Conv2d:(a,s,o)=>new F(this,a,s,o),DepthwiseConv2d:(a,s,o)=>new O(this,a,s,o),Add:(a,s)=>new M(this,a,s),Sigmoid:a=>new R(this,a),BilinearUpsample:(a,s)=>new D(this,a,s),BicubicUpsample:(a,s)=>new H(this,a,s),ChannelConcat:(a,s)=>new L(this,a,s),Conv2dAdd:(a,s,o,u)=>new V(this,a,s,o,u),UpsampleConcat:(a,s,o)=>new z(this,a,s,o),UpsampleConv1x1:(a,s,o)=>new N(this,a,s,o),UpsampleSigmoid:(a,s)=>new $(this,a,s),Input:(a,s)=>new Y(this,a,s)},this.presenters={CompositeSolid:(a,s,o)=>{let u=new q(this,a,s,o);return {run:()=>{u.setOutput(this.getCurrentDisplayTexture()),u.run();}}},CompositeImage:(a,s,o)=>{let u=new X(this,a,s,o);return {run:()=>{u.setOutput(this.getCurrentDisplayTexture()),u.run();}}},CompositeImageBilinear:(a,s,o)=>{let u=new j(this,a,s,o);return {run:()=>{u.setOutput(this.getCurrentDisplayTexture()),u.run();}}},CompositePassthrough:a=>{let s=new K(this,a);return {run:()=>{s.setOutput(this.getCurrentDisplayTexture()),s.run();}}}};}device;canvas;dtype;ops;presenters;canvasContext;canvasFormat;bytesPerElement;static async isAvailable(){return navigator.gpu?await navigator.gpu.requestAdapter()!==null:false}static async hasF16Support(){if(!navigator.gpu)return false;let t=await navigator.gpu.requestAdapter();return t?t.features.has("shader-f16"):false}static async create(t){let e=t.dtype??"f32",r=t.device;if(r){if(e==="f16"&&!r.features.has("shader-f16"))throw new Error("WebGPU dtype='f16' requested but supplied device lacks `shader-f16`")}else {let n=await navigator.gpu.requestAdapter();if(!n)throw new Error("WebGPU adapter not available");if(e==="f16"&&!n.features.has("shader-f16"))throw new Error("WebGPU dtype='f16' requested but adapter lacks `shader-f16` feature");r=await n.requestDevice({requiredFeatures:e==="f16"?["shader-f16"]:[]});}return new i(r,t.canvas,e)}getCurrentDisplayTexture(){return this.canvasContext.getCurrentTexture()}tensor(t,e,r,n){let s=t*e*r*this.bytesPerElement,o=this.device.createBuffer({size:s,usage:ir,mappedAtCreation:n!==void 0});if(n!==void 0){let u=o.getMappedRange();this.writeView(u,n),o.unmap();}return {h:t,w:e,c:r,buffer:o}}upload(t){let r=t.length*this.bytesPerElement,n=this.device.createBuffer({size:r,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,mappedAtCreation:true});return this.writeView(n.getMappedRange(),t),n.unmap(),{buffer:n}}writeView(t,e){let r=this.dtype==="f16",n=e instanceof Uint16Array;if(r===n){r?new Uint16Array(t).set(e):new Float32Array(t).set(e);return}r?new Uint16Array(t).set(ke(e)):new Float32Array(t).set(ie(e));}async readback(t){let e=this.device.createBuffer({size:t.buffer.size,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ}),r=this.device.createCommandEncoder();r.copyBufferToBuffer(t.buffer,0,e,0,t.buffer.size),this.device.queue.submit([r.finish()]),await e.mapAsync(GPUMapMode.READ);let n=e.getMappedRange(),a=this.dtype==="f16"?ie(new Uint16Array(n.slice(0))):new Float32Array(n.slice(0));return e.unmap(),e.destroy(),a}async sync(){await this.device.queue.onSubmittedWorkDone();}destroy(){this.device.destroy();}};exports.EffectsPipeline=ne;exports.WebGPUBackend=ae;
|