longpipe 0.0.10 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.cjs +1161 -240
- package/dist/index.d.cts +25 -1
- package/dist/index.d.ts +25 -1
- package/dist/index.js +1161 -240
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
var w=[{model:"xs",dtype:"f16",resolution:{w:384,h:216},skipFrames:2},{model:"small",dtype:"f16",resolution:{w:384,h:216},skipFrames:1},{model:"medium",dtype:"f16",resolution:{w:512,h:288},skipFrames:1},{model:"large",dtype:"f32",resolution:{w:640,h:360},skipFrames:0},{model:"xl",dtype:"f32",resolution:{w:1280,h:720},skipFrames:0}];var ce=false;function me(a){ce=a;}function x(a){let t=`[longpipe/${a}]`,e=((...r)=>{ce&&console.log(t,...r);});return e.warn=(...r)=>{ce&&console.warn(t,...r);},e}var P=x("adaptive"),Mt=2e3,zt=1e4,Dt=30,Rt=20,Ht=5e3,Lt=.3,Vt=15e3,G=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(){P(`started; backend=${this.opts.backendKind} initial=${this.opts.initialModel} idx=${this.currentPresetIdx}`),this.timer=setInterval(()=>{this.tick().catch(t=>P("tick failed:",t));},Mt);}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<zt)return;let e=await this.opts.getStats();if(e.fps<Rt?(this.overshootStart===0&&(this.overshootStart=t),t-this.overshootStart>=Ht&&this.tryDowngrade(e.fps)):this.overshootStart=0,this.opts.backendKind==="webgpu"&&e.modelMs>0){let r=1e3/Dt*Lt;e.modelMs<r?(this.headroomStart===0&&(this.headroomStart=t),t-this.headroomStart>=Vt&&this.tryUpgrade(e.modelMs,r)):this.headroomStart=0;}}tryDowngrade(t){if(this.currentPresetIdx<=0)return;let e=this.currentPresetIdx-1;P(`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;P(`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 i=await n.arrayBuffer();await this.opts.swapPreset(e.model,i),this.currentPresetIdx=t,P(`swap to ${e.model} done`);}catch(r){P("swap failed:",r),this.opts.onError?.({message:`adaptive preset swap failed: ${r.message??String(r)}`,source:"adaptive",recoverable:true,cause:r});}}};async function be(a){let t,e=false;if(a instanceof HTMLVideoElement){if(t=a.currentSrc||a.src,!t)throw new Error("background video: HTMLVideoElement has no src")}else if(a instanceof Blob)t=URL.createObjectURL(a),e=true;else if(typeof a=="string")t=a;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((c,h)=>{r.addEventListener("loadeddata",()=>c(),{once:true}),r.addEventListener("error",()=>h(new Error(`background video: failed to load ${t}`)),{once:true});});try{await r.play();}catch(c){throw new Error(`background video: play() rejected \u2014 ${c.message}`)}let n=new MessageChannel,i=n.port1,o=n.port2,u=false,s=r.requestVideoFrameCallback?.bind(r);if(s){let c=(h,f)=>{if(!u){try{let v=new VideoFrame(r,{timestamp:f.mediaTime*1e6});i.postMessage({frame:v},[v]);}catch{}s(c);}};s(c);}else {let c=()=>{if(!u){try{let h=new VideoFrame(r,{timestamp:performance.now()*1e3});i.postMessage({frame:h},[h]);}catch{}requestAnimationFrame(c);}};requestAnimationFrame(c);}return {port:o,transferList:[o],cleanup:()=>{u=true,i.close(),r.pause(),r.removeAttribute("src"),r.load(),e&&URL.revokeObjectURL(t);}}}var Nt=4,de=8,ve=16;async function E(a){if(typeof a=="string")return a==="none"?{background:{kind:"none"}}:a==="blur"?{background:{kind:"blur",sigma:de}}:{background:{kind:"image",bitmap:await we(a)}};if(a instanceof ImageBitmap)return {background:{kind:"image",bitmap:a}};if(typeof HTMLImageElement<"u"&&a instanceof HTMLImageElement)return {background:{kind:"image",bitmap:await createImageBitmap(a)}};if(typeof HTMLVideoElement<"u"&&a instanceof HTMLVideoElement)return await xe(a);let t=a;if(t.color!==void 0)return {background:{kind:"color",rgb:$t(t.color)}};if(t.blur!==void 0)return {background:{kind:"blur",sigma:jt(t.blur)}};if(t.image!==void 0)return {background:{kind:"image",bitmap:await qt(t.image)}};if(t.video!==void 0)return await xe(t.video);throw new Error(`background: unrecognized input shape \u2014 ${k(a)}`)}async function xe(a){let t;if(typeof a=="string")t=a;else if(typeof HTMLVideoElement<"u"&&a instanceof HTMLVideoElement)t=a;else if(a&&typeof a=="object"&&"data"in a&&"type"in a)t=a.data instanceof Blob?a.data:new Blob([a.data],{type:a.type});else throw new Error(`background.video: unrecognized shape \u2014 ${k(a)}`);let e=await be(t);return {background:{kind:"video",port:e.port},transferList:e.transferList,cleanup:e.cleanup}}function $t(a){if(typeof a=="string"){let t=a.trim().replace(/^#/,"");if(/^[0-9a-fA-F]{6}$/.test(t))return [parseInt(t.slice(0,2),16)/255,parseInt(t.slice(2,4),16)/255,parseInt(t.slice(4,6),16)/255];if(/^[0-9a-fA-F]{3}$/.test(t))return [parseInt(t[0]+t[0],16)/255,parseInt(t[1]+t[1],16)/255,parseInt(t[2]+t[2],16)/255];throw new Error(`background.color: hex must be #rgb or #rrggbb, got ${k(a)}`)}if(!Array.isArray(a)||a.length!==3||!a.every(t=>typeof t=="number"&&Number.isFinite(t)&&t>=0&&t<=1))throw new Error(`background.color: expected hex string or [r, g, b] floats in [0, 1], got ${k(a)}`);return [a[0],a[1],a[2]]}function jt(a){if(a===true)return de;if("sigma"in a){if(typeof a.sigma!="number"||!Number.isFinite(a.sigma)||a.sigma<0)throw new Error(`background.blur.sigma must be a non-negative number, got ${a.sigma}`);return a.sigma}if("strength"in a){let t=a.strength;if(typeof t=="number"){let e=Math.max(0,Math.min(1,t));return ve*e}if(t==="low")return Nt;if(t==="medium")return de;if(t==="high")return ve;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(a)}`)}async function qt(a){if(a instanceof ImageBitmap)return a;if(typeof HTMLImageElement<"u"&&a instanceof HTMLImageElement)return createImageBitmap(a);if(typeof a=="string")return we(a);if(a&&typeof a=="object"&&"data"in a&&"type"in a){let t=a.data instanceof Blob?a.data:new Blob([a.data],{type:a.type});return createImageBitmap(t)}throw new Error(`background.image: unrecognized shape \u2014 ${k(a)}`)}async function we(a){let t=await fetch(a);if(!t.ok)throw new Error(`background: failed to load image from ${a} (HTTP ${t.status})`);let e=await t.blob();return createImageBitmap(e)}function k(a){return a===null?"null":typeof a!="object"?typeof a+"("+String(a)+")":`${a.constructor?.name??"Object"} ${JSON.stringify(a).slice(0,80)}`}function ye(){return {input:"MediaStreamTrackProcessor"in self?"mstp":"rvfc-postmessage",output:"MediaStreamTrackGenerator"in self?"mstg":Xt()?"transfer-capture":"bitmap-shuttle"}}var F=null;function Xt(){return F!==null||(F=!/Firefox/.test(navigator.userAgent)),F}function ke(a,t,e){let r=[a];return e==="passthrough"&&r.push(...t.getAudioTracks()),new MediaStream(r)}var A=x("worker_controller"),O=class{worker;listeners=new Map;persistentEvents=new Set;constructor(t){this.worker=t,this.worker.addEventListener("message",this.handleMessage.bind(this)),A("constructed; message listener attached");}handleMessage(t){let{request_id:e,res:r}=t.data,n=this.listeners.get(e);A("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),A("addPersistentListener:",t);}removePersistentListener(t){this.persistentEvents.delete(t),this.listeners.delete(t);}sendMessage(t,e,r=[]){let n=crypto.randomUUID();return A("sendMessage:",t,"request_id=",n,"transferables=",r.length),new Promise(i=>{this.listeners.set(n,u=>i(u));let o={cmd:t,data:e,request_id:n};this.worker.postMessage(o,r);})}terminate(){this.worker.terminate(),this.listeners.clear(),this.persistentEvents.clear();}};var Ce=x("input-postmessage/main");function Pe(a){let t=document.createElement("video");t.srcObject=a,t.muted=true,t.autoplay=true,t.playsInline=true,t.play().catch(l=>{Ce.warn("video.play() rejected:",l);});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,i=r.port2,o=false,u=(l,c)=>{if(!o){try{let h=new VideoFrame(t,{timestamp:c.mediaTime*1e6});n.postMessage({frame:h},[h]);}catch(h){Ce.warn("VideoFrame() failed; skipping frame:",h);}e(u);}};return e(u),{port:i,transferList:[i],cleanup:()=>{o=true,n.close(),t.srcObject=null,t.pause();}}}function Te(a){let t=a.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 i=new r({track:e}).readable;return {readable:i,transferList:[i],cleanup:()=>{i.cancel().catch(()=>{});}}}function Ue(a,t){switch(a){case "mstp":{let e=Te(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}}}}var Kt=x("bitmap-shuttle/main"),Yt=30;function Ie(a,t=Yt){let e=document.createElement("canvas");e.width=a.w,e.height=a.h;let r=e.getContext("bitmaprenderer");if(!r)throw new Error("setupBitmapShuttleOutput: bitmaprenderer context not available");let i=e.captureStream(t).getVideoTracks();if(i.length===0)throw new Error("setupBitmapShuttleOutput: captureStream produced no video tracks");let o=i[0],u=new MessageChannel,s=u.port1,l=u.port2,c=false,h=null,f=()=>{},v=3,I=0;return s.onmessage=B=>{if(c){if(I++,I<v){B.data.bmp.close();return}f();}try{r.transferFromImageBitmap(B.data.bmp);}catch(b){Kt.warn("transferFromImageBitmap failed:",b);}},s.start(),{videoTrack:o,port:l,transferList:[l],startPassthrough:B=>{if(c)return;c=true;let b=document.createElement("video");b.srcObject=B,b.muted=true,b.playsInline=true,b.play().catch(()=>{}),h=b;let W="requestVideoFrameCallback"in b?C=>{b.requestVideoFrameCallback(C);}:C=>{requestAnimationFrame(C);},S=()=>{if(c){if(b.videoWidth===0){W(S);return}createImageBitmap(b,{resizeWidth:e.width,resizeHeight:e.height,resizeQuality:"medium"}).then(C=>{if(!c){C.close();return}try{r.transferFromImageBitmap(C);}catch{}W(S);}).catch(()=>{W(S);});}};W(S),f=()=>{c=false,h&&(h.srcObject=null,h.pause(),h=null);};},cleanup:()=>{f(),s.onmessage=null,s.close(),o.stop();}}}function Be(){let a=self.MediaStreamTrackGenerator;if(!a)throw new Error("setupMstgOutput: MediaStreamTrackGenerator not supported on this browser");let t=new a({kind:"video"}),e=t.writable;return {videoTrack:t,writable:e,transferList:[e],cleanup:()=>{e.abort().catch(()=>{}),t.stop();}}}function We(a,t=30){let e=document.createElement("canvas");e.width=a.w,e.height=a.h;let n=e.captureStream(t).getVideoTracks();if(n.length===0)throw new Error("setupTransferCaptureOutput: captureStream produced no video tracks");let i=n[0],o=e.transferControlToOffscreen();return {videoTrack:i,canvas:o,transferList:[o],cleanup:()=>{i.stop();}}}function Se(a,t){switch(a){case "mstg":{let e=Be();return {videoTrack:e.videoTrack,initFields:{outputWritable:e.writable},transferList:e.transferList,cleanup:e.cleanup}}case "transfer-capture":{let e=We(t);return {videoTrack:e.videoTrack,initFields:{outputCanvas:e.canvas},transferList:e.transferList,cleanup:e.cleanup}}case "bitmap-shuttle":{let e=Ie(t);return {videoTrack:e.videoTrack,initFields:{outputPort:e.port},transferList:e.transferList,startPassthrough:e.startPassthrough,cleanup:e.cleanup}}}}var he=`var ao=Object.defineProperty;var no=(s,t,r)=>t in s?ao(s,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):s[t]=r;var i=(s,t,r)=>no(s,typeof t!="symbol"?t+"":t,r);var it=!1;function lt(s){it=s}function U(s){let t=\`[longpipe/\${s}]\`,r=((...e)=>{it&&console.log(t,...e)});return r.warn=(...e)=>{it&&console.warn(t,...e)},r}var at=[{model:"xs",dtype:"f16",resolution:{w:384,h:216},skipFrames:2},{model:"small",dtype:"f16",resolution:{w:384,h:216},skipFrames:1},{model:"medium",dtype:"f16",resolution:{w:512,h:288},skipFrames:1},{model:"large",dtype:"f32",resolution:{w:640,h:360},skipFrames:0},{model:"xl",dtype:"f32",resolution:{w:1280,h:720},skipFrames:0}],so={fast:0,balanced:2,quality:4};function V(s){return s==="auto"?null:at[so[s]]}var N=class{constructor(t,r,e,o){i(this,"op");this.op=t.ops.BilinearUpsample(r,{outH:e,outW:o})}get output(){return this.op.output}run(){this.op.run()}};var $=class{constructor(t,r,e,o){i(this,"op");this.op=t.ops.BicubicUpsample(r,{outH:e,outW:o})}get output(){return this.op.output}run(){this.op.run()}};var X=class{constructor(t,r,e,o,a="main"){i(this,"presenter");this.presenter=t.presenters.CompositeSolid(r,e,o,a)}run(){this.presenter.run()}};var j=class{constructor(t,r,e,o,a="main"){i(this,"presenter");this.presenter=t.presenters.CompositeImage(r,e,o,a)}run(){this.presenter.run()}};var q=class{constructor(t,r,e){i(this,"downs",[]);i(this,"ups",[]);let o=uo(e),a=r;for(let n=0;n<o;n++){let u=t.ops.BilinearUpsample(a,{outH:Math.max(1,Math.floor(a.h/2)),outW:Math.max(1,Math.floor(a.w/2))});this.downs.push(u),a=u.output}for(let n=o-1;n>=1;n--){let u=this.downs[n-1].output,p=t.ops.BilinearUpsample(a,{outH:u.h,outW:u.w});this.ups.push(p),a=p.output}}get output(){return this.ups.length>0?this.ups[this.ups.length-1].output:this.downs[0].output}run(){for(let t of this.downs)t.run();for(let t of this.ups)t.run()}};function uo(s){let t=Math.max(1,3*s);return Math.max(2,Math.min(6,Math.round(Math.log2(t))))}var po=.05,K=class{constructor(t,r,e,o,a="main"){i(this,"blur");i(this,"presenter");o<=po?(this.blur=null,this.presenter=t.presenters.CompositeImage(r,e,r,a)):(this.blur=new q(t,r,o),this.presenter=t.presenters.CompositeImageBilinear(r,e,this.blur.output,a))}run(){this.blur?.run(),this.presenter.run()}};var Y=class{constructor(t){i(this,"backend",t);i(this,"displayInput");i(this,"image");i(this,"network",null);i(this,"networkInput",null);i(this,"upscaler",null);i(this,"upscalerMode","bilinear");i(this,"bgConfig",{mode:"solid",color:[0,0,0]});i(this,"compositors",new Map);let r=t.canvas;this.displayInput=t.ops.Input(r.height,r.width),this.image=this.displayInput.output}attachNetwork(t,r,e){this.network=t,this.networkInput=r,this.upscalerMode=e.upscaler,this.bgConfig=e.background,this.upscaler=this.makeUpscaler(),this.compositors.clear()}hasNetwork(){return this.network!==null}setSource(t){this.networkInput?.setSource(t),this.displayInput.setSource(t)}setUpscaler(t){t!==this.upscalerMode&&(this.upscalerMode=t,this.network&&(this.upscaler=this.makeUpscaler(),this.compositors.clear()))}setBackground(t){this.bgConfig=t}run(){this.runModel(),this.runDisplay()}runDisplay(){this.refreshDisplayInput(),this.compositeMain(!1)}runPassthrough(){this.refreshDisplayInput(),this.compositeMain(!0)}compositeMain(t){this.compositeTo("main",t?{mode:"passthrough"}:this.bgConfig)}refreshDisplayInput(){this.displayInput.run()}compositeTo(t,r){let e=this.compositors.get(t);if(e&&lo(e.spec,r)){e.handle.run();return}let o=this.buildCompositor(t,r);this.compositors.set(t,{spec:r,handle:o}),o.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:t,network:r,image:e}=this;return this.upscalerMode==="bicubic"?new $(t,r.output,e.h,e.w):new N(t,r.output,e.h,e.w)}buildCompositor(t,r){let{backend:e,image:o}=this;if(r.mode==="passthrough")return e.presenters.CompositePassthrough(o,t);if(!this.upscaler)throw new Error("RenderOp.compositeTo (effect spec) called before attachNetwork");let a=this.upscaler.output;switch(r.mode){case"solid":return new X(e,o,a,r.color,t);case"image":return new j(e,o,a,r.image,t);case"blur":return new K(e,o,a,r.sigma,t)}}};function lo(s,t){if(s.mode!==t.mode)return!1;switch(t.mode){case"passthrough":return!0;case"solid":{let r=s.color;return r[0]===t.color[0]&&r[1]===t.color[1]&&r[2]===t.color[2]}case"blur":return s.sigma===t.sigma;case"image":return s.image===t.image}}var co=s=>typeof s=="object"&&s!==null&&typeof s.offset=="number"&&typeof s.length=="number";function ct(s){if(s.byteLength<4)throw new Error("weights buffer too small");let t=new DataView(s,0,4).getUint32(0,!0),r=4+t;if(s.byteLength<r)throw new Error("weights buffer truncated (header)");let e=new Uint8Array(s,4,t),o=JSON.parse(new TextDecoder().decode(e)),a=o.__dtype__??"f32",n=a==="f16"?2:4;if(r%n!==0)throw new Error(\`payload not \${n}-byte aligned (header=\${t})\`);let u=(s.byteLength-r)/n,p=l=>{if(co(l)){let{offset:c,length:m}=l;if(c+m>u)throw new Error(\`array ref out of range: offset=\${c} length=\${m}\`);let _=r+c*n;return a==="f16"?new Uint16Array(s,_,m):new Float32Array(s,_,m)}if(Array.isArray(l))return l.map(p);if(typeof l=="object"&&l!==null){let c={};for(let m of Object.keys(l))m!=="__dtype__"&&(c[m]=p(l[m]));return c}return l};return p(o)}var R=class{constructor(t,r,e,o){i(this,"inputs");i(this,"output");i(this,"gatesOp");i(this,"candOp");this.inputs=[r,e],this.gatesOp=t.ops.GatesFused(r,e,{weights:o.gates,bias:o.gatesBias}),this.candOp=t.ops.CandUpdateFused(r,e,this.gatesOp.output,{weights:o.cand,bias:o.candBias},o.gamma),this.output=this.candOp.output}run(){this.gatesOp.run(),this.candOp.run()}};function dt(s,t,r,e){let o=e.variant,a=o==="E"||o==="D",n=o==="D",u=t.h,p=t.w,l=[],c=null,m=null,_=0,g=0,x;if(a)if(n){if(!r.down2)throw new Error("variant D requires w.down2");_=Math.round(u/1.25),g=Math.round(p/1.25);let y=s.ops.Conv2d(t,r.down1,{outChannels:e.cHigh,kernel:3,stride:1,padding:1,activation:"relu"});l.push(y),m=y.output;let T=s.ops.BilinearUpsample(m,{outH:_,outW:g});l.push(T),c=T.output;let P=s.ops.DownAdapter(c,r.down2,r.adapter,{stride:2});l.push(P),x=P.output}else{if(!r.down2)throw new Error("variant E requires w.down2");let y=s.ops.Conv2d(t,r.down1,{outChannels:e.cHigh,kernel:3,stride:2,padding:1,activation:"relu"});l.push(y),c=y.output,_=c.h,g=c.w;let T=s.ops.DownAdapter(c,r.down2,r.adapter,{stride:2});l.push(T),x=T.output}else{let y=o==="A"?2:3,T=s.ops.DownAdapter(t,r.down1,r.adapter,{stride:y});l.push(T),x=T.output}return{steps:l,adapted:x,d1:c,dFull:m,midH:_,midW:g}}function mt(s,t,r,e,o,a,n,u,p,l){let c=p.variant,m=c==="E"||c==="D",_=c==="D",g=[],x=s.ops.ConvExpand(r,u.expandFeat);g.push(x);let y=x.output,T=null;if(l&&p.gruAtBase){let G=new R(s,y,l.hPrev,l.weights);g.push(G),y=G.output,T=G.output}let P;if(m){if(!u.up1Combine)throw new Error("two-stage variant requires w.up1Combine");let G=s.ops.BilinearUpsample(y,{outH:a,outW:n});g.push(G);let ut=s.ops.CatConv6to2(G.output,e,u.up1Combine);g.push(ut);let pt=s.ops.BilinearUpsample(ut.output,{outH:t.h,outW:t.w});g.push(pt),P=pt.output}else{let G=s.ops.BilinearUpsample(y,{outH:t.h,outW:t.w});g.push(G),P=G.output}if(l&&!p.gruAtBase){let G=new R(s,P,l.hPrev,l.weights);g.push(G),P=G.output,T=G.output}let z=_?s.ops.UpFinalSkip(P,o,t,u.upCombine):s.ops.UpFinal(P,t,u.upCombine);return g.push(z),{steps:g,alpha:z.output,hiddenState:T}}var Q=class{constructor(t,r,e,o,a,n,u){i(this,"inputs");i(this,"output");i(this,"hiddenState");i(this,"steps");this.inputs=[r];let p=dt(t,r,o,a),l=new n(t,p.adapted,e),c=t.ops.BilinearUpsample(l.featLowRes,{outH:p.adapted.h,outW:p.adapted.w}),m=mt(t,r,c.output,p.d1,p.dFull,p.midH,p.midW,o,a,u);this.steps=[...p.steps,l,c,...m.steps],this.output=m.alpha,this.hiddenState=m.hiddenState}run(){for(let t of this.steps)t.run()}};var S=class{constructor(t,r,e,o){i(this,"inputs");i(this,"output");i(this,"dwOp");i(this,"pwOp");this.inputs=[r],this.dwOp=t.ops.DepthwiseConv2d(r,e.dw,{kernel:o.kernel,stride:o.stride,padding:o.padding,activation:"relu6"}),this.pwOp=t.ops.Conv2d(this.dwOp.output,e.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 v=class{constructor(t,r,e,o){i(this,"inputs");i(this,"output");i(this,"expandOp");i(this,"dwOp");i(this,"projOp");this.inputs=[r];let a=o.midChannels!==o.inChannels,n=o.stride===1&&o.inChannels===o.outChannels;this.expandOp=a?t.ops.Conv2d(r,e.expand,{outChannels:o.midChannels,kernel:1,stride:1,padding:0,activation:"relu6"}):null;let u=this.expandOp?this.expandOp.output:r;this.dwOp=t.ops.DepthwiseConv2d(u,e.dw,{kernel:o.kernel,stride:o.stride,padding:o.padding,activation:"relu6"}),this.projOp=n?t.ops.ProjResidual(this.dwOp.output,r,e.proj,{outChannels:o.outChannels}):t.ops.Conv2d(this.dwOp.output,e.proj,{outChannels:o.outChannels,kernel:1,stride:1,padding:0,activation:"none"}),this.output=this.projOp.output}run(){this.expandOp?.run(),this.dwOp.run(),this.projOp.run()}};var B=class{constructor(t,r,e,o,a){i(this,"inputs");i(this,"output");i(this,"upOp");i(this,"concatConvOp");i(this,"conv2Op");this.inputs=[r,e],this.upOp=t.ops.BilinearUpsample(r,{outH:e.h,outW:e.w}),this.concatConvOp=t.ops.ConcatConv2d(this.upOp.output,e,o.conv1,{outChannels:a.outChannels}),this.conv2Op=t.ops.Conv2d(this.concatConvOp.output,o.conv2,{outChannels:a.outChannels,kernel:3,stride:1,padding:1,activation:"relu6"}),this.output=this.conv2Op.output}run(){this.upOp.run(),this.concatConvOp.run(),this.conv2Op.run()}};var J=class{constructor(t,r,e){i(this,"output");i(this,"featLowRes");i(this,"stem");i(this,"s0");i(this,"s1b0");i(this,"s1b1");i(this,"s2b0");i(this,"s2b1");i(this,"s3b0");i(this,"s3b1");i(this,"s3b2");i(this,"s4b0");i(this,"s4b1");i(this,"s4b2");i(this,"bottleneck");i(this,"dec0");i(this,"dec1");i(this,"finalUp");i(this,"outConv");i(this,"alpha");this.stem=t.ops.Conv2d(r,e.encoder.stem,{outChannels:32,kernel:3,stride:2,padding:"same",activation:"relu6"}),this.s0=new S(t,this.stem.output,e.encoder.s0,{outChannels:16,kernel:3,stride:1,padding:1}),this.s1b0=new v(t,this.s0.output,e.encoder.s1[0],{inChannels:16,midChannels:96,outChannels:24,kernel:3,stride:2,padding:"same"}),this.s1b1=new v(t,this.s1b0.output,e.encoder.s1[1],{inChannels:24,midChannels:144,outChannels:24,kernel:3,stride:1,padding:1}),this.s2b0=new v(t,this.s1b1.output,e.encoder.s2[0],{inChannels:24,midChannels:144,outChannels:40,kernel:5,stride:2,padding:"same"}),this.s2b1=new v(t,this.s2b0.output,e.encoder.s2[1],{inChannels:40,midChannels:240,outChannels:40,kernel:5,stride:1,padding:2}),this.s3b0=new v(t,this.s2b1.output,e.encoder.s3[0],{inChannels:40,midChannels:240,outChannels:80,kernel:3,stride:2,padding:"same"}),this.s3b1=new v(t,this.s3b0.output,e.encoder.s3[1],{inChannels:80,midChannels:480,outChannels:80,kernel:3,stride:1,padding:1}),this.s3b2=new v(t,this.s3b1.output,e.encoder.s3[2],{inChannels:80,midChannels:480,outChannels:80,kernel:3,stride:1,padding:1}),this.s4b0=new v(t,this.s3b2.output,e.encoder.s4[0],{inChannels:80,midChannels:480,outChannels:112,kernel:5,stride:1,padding:2}),this.s4b1=new v(t,this.s4b0.output,e.encoder.s4[1],{inChannels:112,midChannels:672,outChannels:112,kernel:5,stride:1,padding:2}),this.s4b2=new v(t,this.s4b1.output,e.encoder.s4[2],{inChannels:112,midChannels:672,outChannels:112,kernel:5,stride:1,padding:2}),this.bottleneck=t.ops.Conv2d(this.s4b2.output,e.bottleneck,{outChannels:128,kernel:1,stride:1,padding:0,activation:"relu6"}),this.dec0=new B(t,this.bottleneck.output,this.s2b1.output,e.decoder.blocks[0],{outChannels:64}),this.dec1=new B(t,this.dec0.output,this.s1b1.output,e.decoder.blocks[1],{outChannels:32}),this.finalUp=t.ops.UpsampleConv1x1(this.dec1.output,e.decoder.finalUpsample,{outH:this.dec1.output.h*2,outW:this.dec1.output.w*2,outChannels:32,activation:"relu6"}),this.featLowRes=this.finalUp.output,this.outConv=t.ops.Conv2d(this.finalUp.output,e.decoder.outputConv,{outChannels:4,kernel:1,stride:1,padding:0,activation:"none"}),this.alpha=t.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 Z=class{constructor(t,r,e){i(this,"output");i(this,"featLowRes");i(this,"stem");i(this,"s0");i(this,"s1b0");i(this,"s1b1");i(this,"s2b0");i(this,"s2b1");i(this,"s3b0");i(this,"s3b1");i(this,"s3b2");i(this,"s4b0");i(this,"s4b1");i(this,"s4b2");i(this,"s5b0");i(this,"s5b1");i(this,"s5b2");i(this,"s5b3");i(this,"s6b0");i(this,"bottleneck");i(this,"dec0");i(this,"dec1");i(this,"dec2");i(this,"finalUp");i(this,"outConv");i(this,"alpha");this.stem=t.ops.Conv2d(r,e.encoder.stem,{outChannels:32,kernel:3,stride:2,padding:"same",activation:"relu6"}),this.s0=new S(t,this.stem.output,e.encoder.s0,{outChannels:16,kernel:3,stride:1,padding:1}),this.s1b0=new v(t,this.s0.output,e.encoder.s1[0],{inChannels:16,midChannels:96,outChannels:24,kernel:3,stride:2,padding:"same"}),this.s1b1=new v(t,this.s1b0.output,e.encoder.s1[1],{inChannels:24,midChannels:144,outChannels:24,kernel:3,stride:1,padding:1}),this.s2b0=new v(t,this.s1b1.output,e.encoder.s2[0],{inChannels:24,midChannels:144,outChannels:40,kernel:5,stride:2,padding:"same"}),this.s2b1=new v(t,this.s2b0.output,e.encoder.s2[1],{inChannels:40,midChannels:240,outChannels:40,kernel:5,stride:1,padding:2}),this.s3b0=new v(t,this.s2b1.output,e.encoder.s3[0],{inChannels:40,midChannels:240,outChannels:80,kernel:3,stride:2,padding:"same"}),this.s3b1=new v(t,this.s3b0.output,e.encoder.s3[1],{inChannels:80,midChannels:480,outChannels:80,kernel:3,stride:1,padding:1}),this.s3b2=new v(t,this.s3b1.output,e.encoder.s3[2],{inChannels:80,midChannels:480,outChannels:80,kernel:3,stride:1,padding:1}),this.s4b0=new v(t,this.s3b2.output,e.encoder.s4[0],{inChannels:80,midChannels:480,outChannels:112,kernel:5,stride:1,padding:2}),this.s4b1=new v(t,this.s4b0.output,e.encoder.s4[1],{inChannels:112,midChannels:672,outChannels:112,kernel:5,stride:1,padding:2}),this.s4b2=new v(t,this.s4b1.output,e.encoder.s4[2],{inChannels:112,midChannels:672,outChannels:112,kernel:5,stride:1,padding:2}),this.s5b0=new v(t,this.s4b2.output,e.encoder.s5[0],{inChannels:112,midChannels:672,outChannels:192,kernel:5,stride:2,padding:"same"}),this.s5b1=new v(t,this.s5b0.output,e.encoder.s5[1],{inChannels:192,midChannels:1152,outChannels:192,kernel:5,stride:1,padding:2}),this.s5b2=new v(t,this.s5b1.output,e.encoder.s5[2],{inChannels:192,midChannels:1152,outChannels:192,kernel:5,stride:1,padding:2}),this.s5b3=new v(t,this.s5b2.output,e.encoder.s5[3],{inChannels:192,midChannels:1152,outChannels:192,kernel:5,stride:1,padding:2}),this.s6b0=new v(t,this.s5b3.output,e.encoder.s6[0],{inChannels:192,midChannels:1152,outChannels:320,kernel:3,stride:1,padding:1}),this.bottleneck=t.ops.Conv2d(this.s6b0.output,e.bottleneck,{outChannels:128,kernel:1,stride:1,padding:0,activation:"relu6"}),this.dec0=new B(t,this.bottleneck.output,this.s4b2.output,e.decoder.blocks[0],{outChannels:64}),this.dec1=new B(t,this.dec0.output,this.s2b1.output,e.decoder.blocks[1],{outChannels:32}),this.dec2=new B(t,this.dec1.output,this.s1b1.output,e.decoder.blocks[2],{outChannels:16}),this.finalUp=t.ops.UpsampleConv1x1(this.dec2.output,e.decoder.finalUpsample,{outH:this.dec2.output.h*2,outW:this.dec2.output.w*2,outChannels:16,activation:"relu6"}),this.featLowRes=this.finalUp.output,this.outConv=t.ops.Conv2d(this.finalUp.output,e.decoder.outputConv,{outChannels:4,kernel:1,stride:1,padding:0,activation:"none"}),this.alpha=t.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 nt=[[{in:24,mid:144,out:32,k:3,s:2},{in:32,mid:192,out:32,k:3,s:1},{in:32,mid:192,out:32,k:3,s:1},{in:32,mid:192,out:32,k:3,s:1}],[{in:32,mid:192,out:56,k:5,s:2},{in:56,mid:336,out:56,k:5,s:1},{in:56,mid:336,out:56,k:5,s:1},{in:56,mid:336,out:56,k:5,s:1}],[{in:56,mid:336,out:112,k:3,s:2},{in:112,mid:672,out:112,k:3,s:1},{in:112,mid:672,out:112,k:3,s:1},{in:112,mid:672,out:112,k:3,s:1},{in:112,mid:672,out:112,k:3,s:1},{in:112,mid:672,out:112,k:3,s:1}],[{in:112,mid:672,out:160,k:5,s:1},{in:160,mid:960,out:160,k:5,s:1},{in:160,mid:960,out:160,k:5,s:1},{in:160,mid:960,out:160,k:5,s:1},{in:160,mid:960,out:160,k:5,s:1},{in:160,mid:960,out:160,k:5,s:1}],[{in:160,mid:960,out:272,k:5,s:2},{in:272,mid:1632,out:272,k:5,s:1},{in:272,mid:1632,out:272,k:5,s:1},{in:272,mid:1632,out:272,k:5,s:1},{in:272,mid:1632,out:272,k:5,s:1},{in:272,mid:1632,out:272,k:5,s:1},{in:272,mid:1632,out:272,k:5,s:1},{in:272,mid:1632,out:272,k:5,s:1}],[{in:272,mid:1632,out:448,k:3,s:1}]],ee=class{constructor(t,r,e){i(this,"output");i(this,"featLowRes");i(this,"stem");i(this,"s0");i(this,"stages");i(this,"bottleneck");i(this,"dec0");i(this,"dec1");i(this,"dec2");i(this,"finalUp");i(this,"outConv");i(this,"alpha");this.stem=t.ops.Conv2d(r,e.encoder.stem,{outChannels:32,kernel:3,stride:2,padding:"same",activation:"relu6"}),this.s0=new S(t,this.stem.output,e.encoder.s0,{outChannels:24,kernel:3,stride:1,padding:1});let o=[e.encoder.s1,e.encoder.s2,e.encoder.s3,e.encoder.s4,e.encoder.s5,e.encoder.s6];this.stages=[];let a=this.s0.output;for(let m=0;m<nt.length;m++){let _=[];for(let g=0;g<nt[m].length;g++){let x=nt[m][g],y=new v(t,a,o[m][g],{inChannels:x.in,midChannels:x.mid,outChannels:x.out,kernel:x.k,stride:x.s,padding:x.s===2?"same":(x.k-1)/2});_.push(y),a=y.output}this.stages.push(_)}let n=m=>this.stages[m][this.stages[m].length-1].output,u=n(0),p=n(1),l=n(3),c=n(5);this.bottleneck=t.ops.Conv2d(c,e.bottleneck,{outChannels:256,kernel:1,stride:1,padding:0,activation:"relu6"}),this.dec0=new B(t,this.bottleneck.output,l,e.decoder.blocks[0],{outChannels:128}),this.dec1=new B(t,this.dec0.output,p,e.decoder.blocks[1],{outChannels:64}),this.dec2=new B(t,this.dec1.output,u,e.decoder.blocks[2],{outChannels:32}),this.finalUp=t.ops.UpsampleConv1x1(this.dec2.output,e.decoder.finalUpsample,{outH:this.dec2.output.h*2,outW:this.dec2.output.w*2,outChannels:32,activation:"relu6"}),this.featLowRes=this.finalUp.output,this.outConv=t.ops.Conv2d(this.finalUp.output,e.decoder.outputConv,{outChannels:4,kernel:1,stride:1,padding:0,activation:"none"}),this.alpha=t.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();for(let t of this.stages)for(let r of t)r.run();this.bottleneck.run(),this.dec0.run(),this.dec1.run(),this.dec2.run(),this.finalUp.run(),this.outConv.run(),this.alpha.run()}};var ft=J,ht=Z,mo=ee,E={xs:{base:ft,wrapper:{variant:"B",cHigh:4,cLow:4,cUp:2,gruAtBase:!0},hasGru:!0,canvasRes:{w:384,h:216},baseRes:{w:128,h:72}},small:{base:ft,wrapper:{variant:"A",cHigh:4,cLow:4,cUp:2,gruAtBase:!0},hasGru:!0,canvasRes:{w:384,h:216},baseRes:{w:192,h:108}},medium:{base:ht,wrapper:{variant:"A",cHigh:4,cLow:4,cUp:2,gruAtBase:!0},hasGru:!0,canvasRes:{w:512,h:288},baseRes:{w:256,h:144}},large:{base:ht,wrapper:{variant:"D",cHigh:4,cLow:4,cUp:2,gruAtBase:!0},hasGru:!0,canvasRes:{w:640,h:360},baseRes:{w:256,h:144}},xl:{base:mo,wrapper:{variant:"E",cHigh:4,cLow:4,cUp:2,gruAtBase:!0},hasGru:!0,canvasRes:{w:1280,h:720},baseRes:{w:320,h:180}}};var fo=15,ho=5,gt=1e3,te=class{constructor(t){i(this,"canvas");i(this,"backend");i(this,"backendKind");i(this,"topology");i(this,"preset",null);i(this,"enabled");i(this,"currentBackground");i(this,"modelTimingCounter",0);i(this,"renderOp");i(this,"tierModel",null);i(this,"hPrev",null);i(this,"bgImageInputs",new Map);i(this,"bgVideoInputs",new Map);i(this,"bgVideoPorts",new Map);i(this,"previewCanvas",null);i(this,"previewCtx",null);i(this,"previewBg",null);i(this,"previewEffectSpec",null);i(this,"previewIntervalMs",1e3/fo);i(this,"lastPreviewAt",0);i(this,"skipCounter",0);i(this,"framesRenderedAt",[]);i(this,"modelRunSamples",[]);i(this,"displayRunSamples",[]);i(this,"skippedCount",0);this.backend=t.backend,this.backendKind=t.backendKind,this.canvas=t.canvas,this.enabled=t.enabled,this.currentBackground=t.background,this.topology=t.topology,this.renderOp=new Y(this.backend)}process(t){this.renderOp.setSource(t);let r=performance.now(),e=this.renderOp.hasNetwork(),o=this.enabled&&e&&this.currentBackground.kind!=="none",a=this.isPreviewTick(r),n=a&&e&&this.previewBg!==null&&this.previewBg.kind!=="none",u=!1;o&&(this.shouldRunModel()?(this.runModelOnce(),u=!0):this.skippedCount++),!u&&n&&(this.runModelOnce(),u=!0);let p=performance.now();a&&this.previewCanvas?(this.backendKind==="webgl"?this.compositePreviewWebGL(o,n):(this.compositeMain(o),this.renderOp.compositeTo("preview",this.previewSpec(n))),this.lastPreviewAt=r):this.compositeMain(o),this.displayRunSamples.push({ts:performance.now(),ms:performance.now()-p}),this.trimSamples(this.displayRunSamples),this.framesRenderedAt.push(performance.now()),this.trim(this.framesRenderedAt)}compositeMain(t){t?this.renderOp.runDisplay():this.renderOp.runPassthrough()}compositePreviewWebGL(t,r){this.renderOp.refreshDisplayInput(),this.renderOp.compositeTo("preview",this.previewSpec(r));let e=this.canvas.transferToImageBitmap();this.previewCtx.transferFromImageBitmap(e),this.renderOp.compositeMain(!t)}previewSpec(t){return t&&this.previewEffectSpec?this.previewEffectSpec:{mode:"passthrough"}}runModelOnce(){let t=performance.now();this.renderOp.runModel(),this.hPrev&&this.tierModel?.hiddenState&&this.backend.copyTensor(this.tierModel.hiddenState,this.hPrev),this.backendKind==="webgpu"&&this.modelTimingCounter%ho===0&&this.backend.sync().then(()=>{this.modelRunSamples.push({ts:performance.now(),ms:performance.now()-t}),this.trimSamples(this.modelRunSamples)}).catch(()=>{}),this.modelTimingCounter++}isPreviewTick(t){return!this.previewCanvas||this.previewBg===null||!this.enabled?!1:t-this.lastPreviewAt>=this.previewIntervalMs}shouldRunModel(){return this.skipCounter===0?(this.skipCounter=this.preset?.skipFrames??0,!0):(this.skipCounter--,!1)}setBackground(t){this.currentBackground=t,this.renderOp.setBackground(this.translateBackgroundFor("main",t))}setEnabled(t){this.enabled=t}attachPreview(t){if(t.width=this.canvas.width,t.height=this.canvas.height,this.previewCanvas=t,this.backendKind==="webgpu")this.backend.attachCanvas("preview",t);else{let r=t.getContext("bitmaprenderer");if(!r)throw new Error("renderer: failed to get bitmaprenderer context for preview canvas");this.previewCtx=r}}setPreview(t,r){this.previewBg=t,this.previewEffectSpec=t.kind==="none"?null:this.translateBackgroundFor("preview",t),r?.fps&&r.fps>0&&(this.previewIntervalMs=1e3/r.fps),this.lastPreviewAt=0}clearPreview(){this.previewBg=null,this.previewEffectSpec=null;let t=this.bgVideoPorts.get("preview");t&&(t.close(),this.bgVideoPorts.delete("preview"))}setPreset(t,r){let e=E[t.model];if(!e)throw new Error(\`renderer: no TIER_CONFIG entry for model '\${t.model}'\`);let o=ct(r),a=this.backend.ops.Input(e.canvasRes.h,e.canvasRes.w),n,u=null;if(e.hasGru){let l=e.wrapper.gruAtBase?e.baseRes:e.canvasRes;u=this.backend.tensor(l.h,l.w,4,new Float32Array(l.h*l.w*4)),n={weights:o.gru,hPrev:u}}let p=new Q(this.backend,a.output,o.base,o.wrapper,e.wrapper,e.base,n);this.renderOp.attachNetwork(p,a,{upscaler:"bilinear",background:this.translateBackgroundFor("main",this.currentBackground)}),this.tierModel=p,this.hPrev=u,this.preset=t,this.skipCounter=0}destroy(){for(let t of this.bgVideoPorts.values())t.close();this.bgVideoPorts.clear(),this.backend.destroy()}getStats(){let t=performance.now();return this.trimRecent(this.framesRenderedAt,t),this.trimSamplesAt(this.modelRunSamples,t),this.trimSamplesAt(this.displayRunSamples,t),{fps:this.framesRenderedAt.length,modelFps:this.modelRunSamples.length,modelMs:_t(this.modelRunSamples.map(r=>r.ms)),displayMs:_t(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}}translateBackgroundFor(t,r){let e=this.bgVideoPorts.get(t);switch(r.kind!=="video"&&e&&(e.close(),this.bgVideoPorts.delete(t)),r.kind){case"none":return{mode:"solid",color:[0,0,0]};case"color":return{mode:"solid",color:r.rgb};case"blur":return{mode:"blur",sigma:r.sigma};case"image":{let o=this.bgInputFor(this.bgImageInputs,t);return o.setSource(r.bitmap),o.run(),{mode:"image",image:o.output}}case"video":{let o=this.bgInputFor(this.bgVideoInputs,t);return e&&e.close(),this.bgVideoPorts.set(t,r.port),r.port.onmessage=a=>{let n=a.data.frame;try{o.setSource(n),o.run()}finally{n.close()}},r.port.start?.(),{mode:"image",image:o.output}}}}bgInputFor(t,r){let e=t.get(r);return e||(e=this.backend.ops.Input(this.canvas.height,this.canvas.width),t.set(r,e)),e}trim(t){t.length>240&&t.splice(0,t.length-240)}trimSamples(t){t.length>240&&t.splice(0,t.length-240)}trimRecent(t,r){let e=r-gt,o=0;for(;o<t.length&&t[o]<e;)o++;o>0&&t.splice(0,o)}trimSamplesAt(t,r){let e=r-gt,o=0;for(;o<t.length&&t[o].ts<e;)o++;o>0&&t.splice(0,o)}};function _t(s){if(s.length===0)return 0;let t=s.slice().sort((e,o)=>e-o),r=t.length>>1;return t.length%2?t[r]:(t[r-1]+t[r])/2}var O=new Float32Array(1),M=new Uint32Array(O.buffer);function go(s){O[0]=s;let t=M[0],r=t>>>16&32768,e=t&2147483647,o=(e>>>23)-127+15;if((t&2139095040)===2139095040)return(t&8388607)!==0?r|32256:r|31744;if(o>=31)return r|31744;if(o<=0){if(o<-10)return r;let l=e&8388607|8388608,c=14-o,m=l>>>c,_=l>>>c-1&1,g=(l&(1<<c-1)-1)!==0?1:0;return _&&(g||m&1)&&(m+=1),r|m}let a=e>>>13&1023,n=e>>>12&1,u=(e&4095)!==0?1:0,p=o<<10|a;return n&&(u||a&1)&&(p+=1,(p>>>10&31)===31)?r|31744:r|p}function _o(s){let t=(s&32768)<<16,r=(s&31744)>>>10,e=s&1023;if(r===0){if(e===0)return M[0]=t,O[0];let o=e,a=1;for(;(o&1024)===0;)o<<=1,a-=1;return o&=1023,M[0]=t|a+127-15<<23|o<<13,O[0]}return r===31?(M[0]=t|2139095040|e<<13,O[0]):(M[0]=t|r+127-15<<23|e<<13,O[0])}function re(s){let t=new Uint16Array(s.length);for(let r=0;r<s.length;r++)t[r]=go(s[r]);return t}function I(s){let t=new Float32Array(s.length);for(let r=0;r<s.length;r++)t[r]=_o(s[r]);return t}var f=class{constructor(t){i(this,"backend",t);i(this,"shader","");i(this,"pipeline");i(this,"bindGroup");i(this,"uniformDefs",[]);i(this,"uniformBuffers",{})}createUniform(t,r){this.uniformDefs.push({name:t,type:r})}setUniform(t,r){let e=this.backend.device.createBuffer({size:r.byteLength,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST,mappedAtCreation:!0});r instanceof Uint32Array?new Uint32Array(e.getMappedRange()).set(r):new Float32Array(e.getMappedRange()).set(r),e.unmap(),this.uniformBuffers[t]=e}defaultBindGroup(){let t=[],r=0;for(let e of this.inputs)t.push({binding:r++,resource:{buffer:e.buffer}});for(let e of this.weights)t.push({binding:r++,resource:{buffer:e.buffer}});for(let e of this.uniformDefs)t.push({binding:r++,resource:{buffer:this.uniformBuffers[e.name]}});return t.push({binding:r,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(),r=t.beginComputePass();r.setPipeline(this.pipeline),r.setBindGroup(0,this.bindGroup),r.dispatchWorkgroups(...this.dispatch),r.end(),this.backend.device.queue.submit([t.finish()])}};var bt=\`// Conv2d, output-channel-blocked (K=4) \\u2014 drop-in replacement for conv2d.wgsl.
|
|
1
|
+
var w=[{model:"xs",dtype:"f16",resolution:{w:384,h:216},skipFrames:2},{model:"small",dtype:"f16",resolution:{w:384,h:216},skipFrames:1},{model:"medium",dtype:"f16",resolution:{w:512,h:288},skipFrames:1},{model:"large",dtype:"f32",resolution:{w:640,h:360},skipFrames:0},{model:"xl",dtype:"f32",resolution:{w:1280,h:720},skipFrames:0}];var fe=false;function ye(a){fe=a;}function v(a){let t=`[longpipe/${a}]`,e=((...r)=>{fe&&console.log(t,...r);});return e.warn=(...r)=>{fe&&console.warn(t,...r);},e}var P=v("adaptive"),Jt=2e3,Qt=1e4,Zt=30,er=20,tr=5e3,rr=.3,nr=15e3,S=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(){P(`started; backend=${this.opts.backendKind} initial=${this.opts.initialModel} idx=${this.currentPresetIdx}`),this.timer=setInterval(()=>{this.tick().catch(t=>P("tick failed:",t));},Jt);}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<Qt)return;let e=await this.opts.getStats();if(e.fps<er?(this.overshootStart===0&&(this.overshootStart=t),t-this.overshootStart>=tr&&this.tryDowngrade(e.fps)):this.overshootStart=0,this.opts.backendKind==="webgpu"&&e.modelMs>0){let r=1e3/Zt*rr;e.modelMs<r?(this.headroomStart===0&&(this.headroomStart=t),t-this.headroomStart>=nr&&this.tryUpgrade(e.modelMs,r)):this.headroomStart=0;}}tryDowngrade(t){if(this.currentPresetIdx<=0)return;let e=this.currentPresetIdx-1;P(`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;P(`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=await this.opts.fetchWeights(e.model);await this.opts.swapPreset(e.model,r),this.currentPresetIdx=t,P(`swap to ${e.model} done`);}catch(r){P("swap failed:",r),this.opts.onError?.({message:`adaptive preset swap failed: ${r.message??String(r)}`,source:"adaptive",recoverable:true,cause:r});}}};async function ke(a){let t,e=false;if(a instanceof HTMLVideoElement){if(t=a.currentSrc||a.src,!t)throw new Error("background video: HTMLVideoElement has no src")}else if(a instanceof Blob)t=URL.createObjectURL(a),e=true;else if(typeof a=="string")t=a;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((c,f)=>{r.addEventListener("loadeddata",()=>c(),{once:true}),r.addEventListener("error",()=>f(new Error(`background video: failed to load ${t}`)),{once:true});});try{await r.play();}catch(c){throw new Error(`background video: play() rejected \u2014 ${c.message}`)}let n=new MessageChannel,i=n.port1,o=n.port2,s=false,u=r.requestVideoFrameCallback?.bind(r);if(u){let c=(f,h)=>{if(!s){try{let x=new VideoFrame(r,{timestamp:h.mediaTime*1e6});i.postMessage({frame:x},[x]);}catch{}u(c);}};u(c);}else {let c=()=>{if(!s){try{let f=new VideoFrame(r,{timestamp:performance.now()*1e3});i.postMessage({frame:f},[f]);}catch{}requestAnimationFrame(c);}};requestAnimationFrame(c);}return {port:o,transferList:[o],cleanup:()=>{s=true,i.close(),r.pause(),r.removeAttribute("src"),r.load(),e&&URL.revokeObjectURL(t);}}}var ar=4,he=8,Ce=16;async function G(a){if(typeof a=="string")return a==="none"?{background:{kind:"none"}}:a==="blur"?{background:{kind:"blur",sigma:he}}:{background:{kind:"image",bitmap:await Te(a)}};if(a instanceof ImageBitmap)return {background:{kind:"image",bitmap:a}};if(typeof HTMLImageElement<"u"&&a instanceof HTMLImageElement)return {background:{kind:"image",bitmap:await createImageBitmap(a)}};if(typeof HTMLVideoElement<"u"&&a instanceof HTMLVideoElement)return await Pe(a);let t=a;if(t.color!==void 0)return {background:{kind:"color",rgb:ir(t.color)}};if(t.blur!==void 0)return {background:{kind:"blur",sigma:or(t.blur)}};if(t.image!==void 0)return {background:{kind:"image",bitmap:await sr(t.image)}};if(t.video!==void 0)return await Pe(t.video);throw new Error(`background: unrecognized input shape \u2014 ${k(a)}`)}async function Pe(a){let t;if(typeof a=="string")t=a;else if(typeof HTMLVideoElement<"u"&&a instanceof HTMLVideoElement)t=a;else if(a&&typeof a=="object"&&"data"in a&&"type"in a)t=a.data instanceof Blob?a.data:new Blob([a.data],{type:a.type});else throw new Error(`background.video: unrecognized shape \u2014 ${k(a)}`);let e=await ke(t);return {background:{kind:"video",port:e.port},transferList:e.transferList,cleanup:e.cleanup}}function ir(a){if(typeof a=="string"){let t=a.trim().replace(/^#/,"");if(/^[0-9a-fA-F]{6}$/.test(t))return [parseInt(t.slice(0,2),16)/255,parseInt(t.slice(2,4),16)/255,parseInt(t.slice(4,6),16)/255];if(/^[0-9a-fA-F]{3}$/.test(t))return [parseInt(t[0]+t[0],16)/255,parseInt(t[1]+t[1],16)/255,parseInt(t[2]+t[2],16)/255];throw new Error(`background.color: hex must be #rgb or #rrggbb, got ${k(a)}`)}if(!Array.isArray(a)||a.length!==3||!a.every(t=>typeof t=="number"&&Number.isFinite(t)&&t>=0&&t<=1))throw new Error(`background.color: expected hex string or [r, g, b] floats in [0, 1], got ${k(a)}`);return [a[0],a[1],a[2]]}function or(a){if(a===true)return he;if("sigma"in a){if(typeof a.sigma!="number"||!Number.isFinite(a.sigma)||a.sigma<0)throw new Error(`background.blur.sigma must be a non-negative number, got ${a.sigma}`);return a.sigma}if("strength"in a){let t=a.strength;if(typeof t=="number"){let e=Math.max(0,Math.min(1,t));return Ce*e}if(t==="low")return ar;if(t==="medium")return he;if(t==="high")return Ce;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(a)}`)}async function sr(a){if(a instanceof ImageBitmap)return a;if(typeof HTMLImageElement<"u"&&a instanceof HTMLImageElement)return createImageBitmap(a);if(typeof a=="string")return Te(a);if(a&&typeof a=="object"&&"data"in a&&"type"in a){let t=a.data instanceof Blob?a.data:new Blob([a.data],{type:a.type});return createImageBitmap(t)}throw new Error(`background.image: unrecognized shape \u2014 ${k(a)}`)}async function Te(a){let t=await fetch(a);if(!t.ok)throw new Error(`background: failed to load image from ${a} (HTTP ${t.status})`);let e=await t.blob();return createImageBitmap(e)}function k(a){return a===null?"null":typeof a!="object"?typeof a+"("+String(a)+")":`${a.constructor?.name??"Object"} ${JSON.stringify(a).slice(0,80)}`}function Ue(){return {input:"MediaStreamTrackProcessor"in self?"mstp":"rvfc-postmessage",output:"MediaStreamTrackGenerator"in self?"mstg":ur()?"transfer-capture":"bitmap-shuttle"}}var F=null;function ur(){return F!==null||(F=!/Firefox/.test(navigator.userAgent)),F}function We(a,t,e){let r=[a];return e==="passthrough"&&r.push(...t.getAudioTracks()),new MediaStream(r)}var E=v("worker_controller"),A=class{worker;listeners=new Map;persistentEvents=new Set;constructor(t){this.worker=t,this.worker.addEventListener("message",this.handleMessage.bind(this)),E("constructed; message listener attached");}handleMessage(t){let{request_id:e,res:r}=t.data,n=this.listeners.get(e);E("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),E("addPersistentListener:",t);}removePersistentListener(t){this.persistentEvents.delete(t),this.listeners.delete(t);}sendMessage(t,e,r=[]){let n=crypto.randomUUID();return E("sendMessage:",t,"request_id=",n,"transferables=",r.length),new Promise(i=>{this.listeners.set(n,s=>i(s));let o={cmd:t,data:e,request_id:n};this.worker.postMessage(o,r);})}terminate(){this.worker.terminate(),this.listeners.clear(),this.persistentEvents.clear();}};var Ie=v("input-postmessage/main");function Be(a){let t=document.createElement("video");t.srcObject=a,t.muted=true,t.autoplay=true,t.playsInline=true,t.play().catch(l=>{Ie.warn("video.play() rejected:",l);});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,i=r.port2,o=false,s=(l,c)=>{if(!o){try{let f=new VideoFrame(t,{timestamp:c.mediaTime*1e6});n.postMessage({frame:f},[f]);}catch(f){Ie.warn("VideoFrame() failed; skipping frame:",f);}e(s);}};return e(s),{port:i,transferList:[i],cleanup:()=>{o=true,n.close(),t.srcObject=null,t.pause();}}}function Se(a){let t=a.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 i=new r({track:e}).readable;return {readable:i,transferList:[i],cleanup:()=>{i.cancel().catch(()=>{});}}}function Ge(a,t){switch(a){case "mstp":{let e=Se(t);return {initFields:{inputReadable:e.readable},transferList:e.transferList,cleanup:e.cleanup}}case "rvfc-postmessage":{let e=Be(t);return {initFields:{inputPort:e.port},transferList:e.transferList,cleanup:e.cleanup}}}}var pr=v("bitmap-shuttle/main"),lr=30;function Fe(a,t=lr){let e=document.createElement("canvas");e.width=a.w,e.height=a.h;let r=e.getContext("bitmaprenderer");if(!r)throw new Error("setupBitmapShuttleOutput: bitmaprenderer context not available");let i=e.captureStream(t).getVideoTracks();if(i.length===0)throw new Error("setupBitmapShuttleOutput: captureStream produced no video tracks");let o=i[0],s=new MessageChannel,u=s.port1,l=s.port2,c=false,f=null,h=()=>{},x=3,we=0;return u.onmessage=W=>{if(c){if(we++,we<x){W.data.bmp.close();return}h();}try{r.transferFromImageBitmap(W.data.bmp);}catch(b){pr.warn("transferFromImageBitmap failed:",b);}},u.start(),{videoTrack:o,port:l,transferList:[l],startPassthrough:W=>{if(c)return;c=true;let b=document.createElement("video");b.srcObject=W,b.muted=true,b.playsInline=true,b.play().catch(()=>{}),f=b;let I="requestVideoFrameCallback"in b?C=>{b.requestVideoFrameCallback(C);}:C=>{requestAnimationFrame(C);},B=()=>{if(c){if(b.videoWidth===0){I(B);return}createImageBitmap(b,{resizeWidth:e.width,resizeHeight:e.height,resizeQuality:"medium"}).then(C=>{if(!c){C.close();return}try{r.transferFromImageBitmap(C);}catch{}I(B);}).catch(()=>{I(B);});}};I(B),h=()=>{c=false,f&&(f.srcObject=null,f.pause(),f=null);};},cleanup:()=>{h(),u.onmessage=null,u.close(),o.stop();}}}function Ee(){let a=self.MediaStreamTrackGenerator;if(!a)throw new Error("setupMstgOutput: MediaStreamTrackGenerator not supported on this browser");let t=new a({kind:"video"}),e=t.writable;return {videoTrack:t,writable:e,transferList:[e],cleanup:()=>{e.abort().catch(()=>{}),t.stop();}}}function Ae(a,t=30){let e=document.createElement("canvas");e.width=a.w,e.height=a.h;let n=e.captureStream(t).getVideoTracks();if(n.length===0)throw new Error("setupTransferCaptureOutput: captureStream produced no video tracks");let i=n[0],o=e.transferControlToOffscreen();return {videoTrack:i,canvas:o,transferList:[o],cleanup:()=>{i.stop();}}}function Oe(a,t){switch(a){case "mstg":{let e=Ee();return {videoTrack:e.videoTrack,initFields:{outputWritable:e.writable},transferList:e.transferList,cleanup:e.cleanup}}case "transfer-capture":{let e=Ae(t);return {videoTrack:e.videoTrack,initFields:{outputCanvas:e.canvas},transferList:e.transferList,cleanup:e.cleanup}}case "bitmap-shuttle":{let e=Fe(t);return {videoTrack:e.videoTrack,initFields:{outputPort:e.port},transferList:e.transferList,startPassthrough:e.startPassthrough,cleanup:e.cleanup}}}}var ge=`var Fo=Object.defineProperty;var Eo=(u,t,r)=>t in u?Fo(u,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):u[t]=r;var a=(u,t,r)=>Eo(u,typeof t!="symbol"?t+"":t,r);var xt=!1;function Ct(u){xt=u}function S(u){let t=\`[longpipe/\${u}]\`,r=((...e)=>{xt&&console.log(t,...e)});return r.warn=(...e)=>{xt&&console.warn(t,...e)},r}var yt=[{model:"xs",dtype:"f16",resolution:{w:384,h:216},skipFrames:2},{model:"small",dtype:"f16",resolution:{w:384,h:216},skipFrames:1},{model:"medium",dtype:"f16",resolution:{w:512,h:288},skipFrames:1},{model:"large",dtype:"f32",resolution:{w:640,h:360},skipFrames:0},{model:"xl",dtype:"f32",resolution:{w:1280,h:720},skipFrames:0}],Do={fast:0,balanced:2,quality:4};function q(u){return u==="auto"?null:yt[Do[u]]}var K=class{constructor(t,r,e,i){a(this,"op");this.op=t.ops.BilinearUpsample(r,{outH:e,outW:i})}get output(){return this.op.output}run(){this.op.run()}};var Y=class{constructor(t,r,e,i){a(this,"op");this.op=t.ops.BicubicUpsample(r,{outH:e,outW:i})}get output(){return this.op.output}run(){this.op.run()}};var Q=class{constructor(t,r,e,i,o="main"){a(this,"presenter");this.presenter=t.presenters.CompositeSolid(r,e,i,o)}run(){this.presenter.run()}};var J=class{constructor(t,r,e,i,o="main"){a(this,"presenter");this.presenter=t.presenters.CompositeImage(r,e,i,o)}run(){this.presenter.run()}};var Z=class{constructor(t,r,e){a(this,"downs",[]);a(this,"ups",[]);let i=Oo(e),o=r;for(let n=0;n<i;n++){let s=t.ops.BilinearUpsample(o,{outH:Math.max(1,Math.floor(o.h/2)),outW:Math.max(1,Math.floor(o.w/2))});this.downs.push(s),o=s.output}for(let n=i-1;n>=1;n--){let s=this.downs[n-1].output,p=t.ops.BilinearUpsample(o,{outH:s.h,outW:s.w});this.ups.push(p),o=p.output}}get output(){return this.ups.length>0?this.ups[this.ups.length-1].output:this.downs[0].output}run(){for(let t of this.downs)t.run();for(let t of this.ups)t.run()}};function Oo(u){let t=Math.max(1,3*u);return Math.max(2,Math.min(6,Math.round(Math.log2(t))))}var Io=.05,ee=class{constructor(t,r,e,i,o="main"){a(this,"blur");a(this,"presenter");i<=Io?(this.blur=null,this.presenter=t.presenters.CompositeImage(r,e,r,o)):(this.blur=new Z(t,r,i),this.presenter=t.presenters.CompositeImageBilinear(r,e,this.blur.output,o))}run(){this.blur?.run(),this.presenter.run()}};var te=class{constructor(t){a(this,"backend",t);a(this,"displayInput");a(this,"image");a(this,"network",null);a(this,"networkInput",null);a(this,"upscaler",null);a(this,"upscalerMode","bilinear");a(this,"bgConfig",{mode:"solid",color:[0,0,0]});a(this,"compositors",new Map);let r=t.canvas;this.displayInput=t.ops.Input(r.height,r.width),this.image=this.displayInput.output}attachNetwork(t,r,e){this.network=t,this.networkInput=r,this.upscalerMode=e.upscaler,this.bgConfig=e.background,this.upscaler=this.makeUpscaler(),this.compositors.clear()}hasNetwork(){return this.network!==null}setSource(t){this.networkInput?.setSource(t),this.displayInput.setSource(t)}setUpscaler(t){t!==this.upscalerMode&&(this.upscalerMode=t,this.network&&(this.upscaler=this.makeUpscaler(),this.compositors.clear()))}setBackground(t){this.bgConfig=t}run(){this.runModel(),this.runDisplay()}runDisplay(){this.refreshDisplayInput(),this.compositeMain(!1)}runPassthrough(){this.refreshDisplayInput(),this.compositeMain(!0)}compositeMain(t){this.compositeTo("main",t?{mode:"passthrough"}:this.bgConfig)}refreshDisplayInput(){this.displayInput.run()}compositeTo(t,r){let e=this.compositors.get(t);if(e&&Ao(e.spec,r)){e.handle.run();return}let i=this.buildCompositor(t,r);this.compositors.set(t,{spec:r,handle:i}),i.run()}applyAlpha(t){if(!this.network||!this.upscaler)throw new Error("RenderOp.applyAlpha called before attachNetwork");this.backend.copyTensor(t,this.network.output),this.upscaler.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:t,network:r,image:e}=this;return this.upscalerMode==="bicubic"?new Y(t,r.output,e.h,e.w):new K(t,r.output,e.h,e.w)}buildCompositor(t,r){let{backend:e,image:i}=this;if(r.mode==="passthrough")return e.presenters.CompositePassthrough(i,t);if(!this.upscaler)throw new Error("RenderOp.compositeTo (effect spec) called before attachNetwork");let o=this.upscaler.output;switch(r.mode){case"solid":return new Q(e,i,o,r.color,t);case"image":return new J(e,i,o,r.image,t);case"blur":return new ee(e,i,o,r.sigma,t)}}};function Ao(u,t){if(u.mode!==t.mode)return!1;switch(t.mode){case"passthrough":return!0;case"solid":{let r=u.color;return r[0]===t.color[0]&&r[1]===t.color[1]&&r[2]===t.color[2]}case"blur":return u.sigma===t.sigma;case"image":return u.image===t.image}}var Mo=u=>typeof u=="object"&&u!==null&&typeof u.offset=="number"&&typeof u.length=="number";function Wt(u){if(u.byteLength<4)throw new Error("weights buffer too small");let t=new DataView(u,0,4).getUint32(0,!0),r=4+t;if(u.byteLength<r)throw new Error("weights buffer truncated (header)");let e=new Uint8Array(u,4,t),i=JSON.parse(new TextDecoder().decode(e)),o=i.__dtype__??"f32",n=o==="f16"?2:4;if(r%n!==0)throw new Error(\`payload not \${n}-byte aligned (header=\${t})\`);let s=(u.byteLength-r)/n,p=l=>{if(Mo(l)){let{offset:c,length:d}=l;if(c+d>s)throw new Error(\`array ref out of range: offset=\${c} length=\${d}\`);let _=r+c*n;return o==="f16"?new Uint16Array(u,_,d):new Float32Array(u,_,d)}if(Array.isArray(l))return l.map(p);if(typeof l=="object"&&l!==null){let c={};for(let d of Object.keys(l))d!=="__dtype__"&&(c[d]=p(l[d]));return c}return l};return p(i)}function Pt(u,t,r,e){let i=e.variant,o=i==="E"||i==="D",n=i==="D",s=t.h,p=t.w,l=[],c=null,d=null,_=0,b=0,g;if(o)if(n){if(!r.down2)throw new Error("variant D requires w.down2");_=Math.round(s/1.25),b=Math.round(p/1.25);let v=u.ops.Conv2d(t,r.down1,{outChannels:e.cHigh,kernel:3,stride:1,padding:1,activation:"relu"});l.push(v),d=v.output;let x=u.ops.BilinearUpsample(d,{outH:_,outW:b});l.push(x),c=x.output;let k=u.ops.DownAdapter(c,r.down2,r.adapter,{stride:2});l.push(k),g=k.output}else{if(!r.down2)throw new Error("variant E requires w.down2");let v=u.ops.Conv2d(t,r.down1,{outChannels:e.cHigh,kernel:3,stride:2,padding:1,activation:"relu"});l.push(v),c=v.output,_=c.h,b=c.w;let x=u.ops.DownAdapter(c,r.down2,r.adapter,{stride:2});l.push(x),g=x.output}else{let v=i==="A"?2:3,x=u.ops.DownAdapter(t,r.down1,r.adapter,{stride:v});l.push(x),g=x.output}return{steps:l,adapted:g,d1:c,dFull:d,midH:_,midW:b}}function Gt(u,t,r,e,i,o,n,s,p){let l=p.variant,c=l==="E"||l==="D",d=l==="D",_=[],b=u.ops.ConvExpand(r,s.expandFeat);_.push(b);let g=b.output,v;if(c){if(!s.up1Combine)throw new Error("two-stage variant requires w.up1Combine");let k=u.ops.BilinearUpsample(g,{outH:o,outW:n});_.push(k);let B=u.ops.CatConv6to2(k.output,e,s.up1Combine);_.push(B);let U=u.ops.BilinearUpsample(B.output,{outH:t.h,outW:t.w});_.push(U),v=U.output}else{let k=u.ops.BilinearUpsample(g,{outH:t.h,outW:t.w});_.push(k),v=k.output}let x=d?u.ops.UpFinalSkip(v,i,t,s.upCombine):u.ops.UpFinal(v,t,s.upCombine);return _.push(x),{steps:_,alpha:x.output}}var re=class{constructor(t,r,e,i,o,n){a(this,"inputs");a(this,"output");a(this,"encoderTaps");a(this,"halfTap");a(this,"steps");this.inputs=[r];let s=Pt(t,r,i,o),p=new n(t,s.adapted,e),l=t.ops.BilinearUpsample(p.featLowRes,{outH:s.adapted.h,outW:s.adapted.w}),c=Gt(t,r,l.output,s.d1,s.dFull,s.midH,s.midW,i,o);this.steps=[...s.steps,p,l,...c.steps],this.output=c.alpha,this.encoderTaps=p.encoderTaps,this.halfTap=p.halfTap}run(){for(let t of this.steps)t.run()}};var Ro=[5,5,3,3],Ho=[2,2,1,1];function oe(u,t,r,e){if(t.h===r.h&&t.w===r.w)return t;let i=u.ops.Crop(t,{outH:r.h,outW:r.w});return e.push(i),i.output}var ie=class{constructor(t,r,e,i,o,n=16,s={}){a(this,"inputs");a(this,"output");a(this,"steps");this.inputs=[r,e,...i,...s.halfTap?[s.halfTap]:[]];let p=[],l=t.ops.ChannelConcat(r,e);p.push(l);let c=t.ops.Conv2d(l.output,o.stem,{outChannels:n,kernel:7,stride:2,padding:3,activation:"relu6"});p.push(c);let d=[],_=c.output;if(s.fuseStem&&s.halfTap){let x=oe(t,s.halfTap,c.output,p),k=t.ops.ChannelConcat(c.output,x);p.push(k),d.push(k.output),_=k.output}for(let x=0;x<i.length;x++){let k=t.ops.Conv2d(_,o.stages[x],{outChannels:n,kernel:Ro[x],stride:2,padding:Ho[x],activation:"relu6"});p.push(k);let B=oe(t,i[x],k.output,p),U=t.ops.ChannelConcat(k.output,B);p.push(U),d.push(U.output),_=U.output}let b=t.ops.Conv2d(d[d.length-1],o.predictBot,{outChannels:4,kernel:3,stride:1,padding:1,activation:"none"});p.push(b);let g=b.output,v=d[d.length-1];for(let x=0;x<d.length-1;x++){let k=d.length-2-x,B=t.ops.BilinearUpsample(v,{outH:v.h*2,outW:v.w*2}),U=t.ops.Conv2d(B.output,o.deconv[x],{outChannels:n,kernel:3,stride:1,padding:1,activation:"relu6"}),X=t.ops.BilinearUpsample(g,{outH:g.h*2,outW:g.w*2});p.push(B,U,X);let vt=oe(t,U.output,d[k],p),z=oe(t,X.output,d[k],p),j=t.ops.ChannelConcat(d[k],vt),D=t.ops.ChannelConcat(j.output,z);p.push(j,D);let V=t.ops.Conv2d(D.output,o.predict[x],{outChannels:4,kernel:3,stride:1,padding:1,activation:"none"});p.push(V),g=V.output,v=D.output}this.output=g,this.steps=p}run(){for(let t of this.steps)t.run()}};var L=class{constructor(t,r,e,i){a(this,"inputs");a(this,"output");a(this,"dwOp");a(this,"pwOp");this.inputs=[r],this.dwOp=t.ops.DepthwiseConv2d(r,e.dw,{kernel:i.kernel,stride:i.stride,padding:i.padding,activation:"relu6"}),this.pwOp=t.ops.Conv2d(this.dwOp.output,e.pw,{outChannels:i.outChannels,kernel:1,stride:1,padding:0,activation:"none"}),this.output=this.pwOp.output}run(){this.dwOp.run(),this.pwOp.run()}};var w=class{constructor(t,r,e,i){a(this,"inputs");a(this,"output");a(this,"expandOp");a(this,"dwOp");a(this,"projOp");this.inputs=[r];let o=i.midChannels!==i.inChannels,n=i.stride===1&&i.inChannels===i.outChannels;this.expandOp=o?t.ops.Conv2d(r,e.expand,{outChannels:i.midChannels,kernel:1,stride:1,padding:0,activation:"relu6"}):null;let s=this.expandOp?this.expandOp.output:r;this.dwOp=t.ops.DepthwiseConv2d(s,e.dw,{kernel:i.kernel,stride:i.stride,padding:i.padding,activation:"relu6"}),this.projOp=n?t.ops.ProjResidual(this.dwOp.output,r,e.proj,{outChannels:i.outChannels}):t.ops.Conv2d(this.dwOp.output,e.proj,{outChannels:i.outChannels,kernel:1,stride:1,padding:0,activation:"none"}),this.output=this.projOp.output}run(){this.expandOp?.run(),this.dwOp.run(),this.projOp.run()}};var G=class{constructor(t,r,e,i,o){a(this,"inputs");a(this,"output");a(this,"upOp");a(this,"concatConvOp");a(this,"conv2Op");this.inputs=[r,e],this.upOp=t.ops.BilinearUpsample(r,{outH:e.h,outW:e.w}),this.concatConvOp=t.ops.ConcatConv2d(this.upOp.output,e,i.conv1,{outChannels:o.outChannels}),this.conv2Op=t.ops.Conv2d(this.concatConvOp.output,i.conv2,{outChannels:o.outChannels,kernel:3,stride:1,padding:1,activation:"relu6"}),this.output=this.conv2Op.output}run(){this.upOp.run(),this.concatConvOp.run(),this.conv2Op.run()}};var ae=class{constructor(t,r,e){a(this,"output");a(this,"featLowRes");a(this,"encoderTaps");a(this,"halfTap");a(this,"stem");a(this,"s0");a(this,"s1b0");a(this,"s1b1");a(this,"s2b0");a(this,"s2b1");a(this,"s3b0");a(this,"s3b1");a(this,"s3b2");a(this,"s4b0");a(this,"s4b1");a(this,"s4b2");a(this,"bottleneck");a(this,"dec0");a(this,"dec1");a(this,"finalUp");a(this,"outConv");a(this,"alpha");this.stem=t.ops.Conv2d(r,e.encoder.stem,{outChannels:32,kernel:3,stride:2,padding:"same",activation:"relu6"}),this.s0=new L(t,this.stem.output,e.encoder.s0,{outChannels:16,kernel:3,stride:1,padding:1}),this.s1b0=new w(t,this.s0.output,e.encoder.s1[0],{inChannels:16,midChannels:96,outChannels:24,kernel:3,stride:2,padding:"same"}),this.s1b1=new w(t,this.s1b0.output,e.encoder.s1[1],{inChannels:24,midChannels:144,outChannels:24,kernel:3,stride:1,padding:1}),this.s2b0=new w(t,this.s1b1.output,e.encoder.s2[0],{inChannels:24,midChannels:144,outChannels:40,kernel:5,stride:2,padding:"same"}),this.s2b1=new w(t,this.s2b0.output,e.encoder.s2[1],{inChannels:40,midChannels:240,outChannels:40,kernel:5,stride:1,padding:2}),this.s3b0=new w(t,this.s2b1.output,e.encoder.s3[0],{inChannels:40,midChannels:240,outChannels:80,kernel:3,stride:2,padding:"same"}),this.s3b1=new w(t,this.s3b0.output,e.encoder.s3[1],{inChannels:80,midChannels:480,outChannels:80,kernel:3,stride:1,padding:1}),this.s3b2=new w(t,this.s3b1.output,e.encoder.s3[2],{inChannels:80,midChannels:480,outChannels:80,kernel:3,stride:1,padding:1}),this.s4b0=new w(t,this.s3b2.output,e.encoder.s4[0],{inChannels:80,midChannels:480,outChannels:112,kernel:5,stride:1,padding:2}),this.s4b1=new w(t,this.s4b0.output,e.encoder.s4[1],{inChannels:112,midChannels:672,outChannels:112,kernel:5,stride:1,padding:2}),this.s4b2=new w(t,this.s4b1.output,e.encoder.s4[2],{inChannels:112,midChannels:672,outChannels:112,kernel:5,stride:1,padding:2}),this.bottleneck=t.ops.Conv2d(this.s4b2.output,e.bottleneck,{outChannels:128,kernel:1,stride:1,padding:0,activation:"relu6"}),this.dec0=new G(t,this.bottleneck.output,this.s2b1.output,e.decoder.blocks[0],{outChannels:64}),this.dec1=new G(t,this.dec0.output,this.s1b1.output,e.decoder.blocks[1],{outChannels:32}),this.finalUp=t.ops.UpsampleConv1x1(this.dec1.output,e.decoder.finalUpsample,{outH:this.dec1.output.h*2,outW:this.dec1.output.w*2,outChannels:32,activation:"relu6"}),this.featLowRes=this.finalUp.output,this.encoderTaps=[this.s1b1.output,this.s2b1.output,this.s4b2.output],this.halfTap=this.s0.output,this.outConv=t.ops.Conv2d(this.finalUp.output,e.decoder.outputConv,{outChannels:4,kernel:1,stride:1,padding:0,activation:"none"}),this.alpha=t.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 ne=class{constructor(t,r,e){a(this,"output");a(this,"featLowRes");a(this,"encoderTaps");a(this,"stem");a(this,"s0");a(this,"s1b0");a(this,"s1b1");a(this,"s2b0");a(this,"s2b1");a(this,"s3b0");a(this,"s3b1");a(this,"s3b2");a(this,"s4b0");a(this,"s4b1");a(this,"s4b2");a(this,"s5b0");a(this,"s5b1");a(this,"s5b2");a(this,"s5b3");a(this,"s6b0");a(this,"bottleneck");a(this,"dec0");a(this,"dec1");a(this,"dec2");a(this,"finalUp");a(this,"outConv");a(this,"alpha");this.stem=t.ops.Conv2d(r,e.encoder.stem,{outChannels:32,kernel:3,stride:2,padding:"same",activation:"relu6"}),this.s0=new L(t,this.stem.output,e.encoder.s0,{outChannels:16,kernel:3,stride:1,padding:1}),this.s1b0=new w(t,this.s0.output,e.encoder.s1[0],{inChannels:16,midChannels:96,outChannels:24,kernel:3,stride:2,padding:"same"}),this.s1b1=new w(t,this.s1b0.output,e.encoder.s1[1],{inChannels:24,midChannels:144,outChannels:24,kernel:3,stride:1,padding:1}),this.s2b0=new w(t,this.s1b1.output,e.encoder.s2[0],{inChannels:24,midChannels:144,outChannels:40,kernel:5,stride:2,padding:"same"}),this.s2b1=new w(t,this.s2b0.output,e.encoder.s2[1],{inChannels:40,midChannels:240,outChannels:40,kernel:5,stride:1,padding:2}),this.s3b0=new w(t,this.s2b1.output,e.encoder.s3[0],{inChannels:40,midChannels:240,outChannels:80,kernel:3,stride:2,padding:"same"}),this.s3b1=new w(t,this.s3b0.output,e.encoder.s3[1],{inChannels:80,midChannels:480,outChannels:80,kernel:3,stride:1,padding:1}),this.s3b2=new w(t,this.s3b1.output,e.encoder.s3[2],{inChannels:80,midChannels:480,outChannels:80,kernel:3,stride:1,padding:1}),this.s4b0=new w(t,this.s3b2.output,e.encoder.s4[0],{inChannels:80,midChannels:480,outChannels:112,kernel:5,stride:1,padding:2}),this.s4b1=new w(t,this.s4b0.output,e.encoder.s4[1],{inChannels:112,midChannels:672,outChannels:112,kernel:5,stride:1,padding:2}),this.s4b2=new w(t,this.s4b1.output,e.encoder.s4[2],{inChannels:112,midChannels:672,outChannels:112,kernel:5,stride:1,padding:2}),this.s5b0=new w(t,this.s4b2.output,e.encoder.s5[0],{inChannels:112,midChannels:672,outChannels:192,kernel:5,stride:2,padding:"same"}),this.s5b1=new w(t,this.s5b0.output,e.encoder.s5[1],{inChannels:192,midChannels:1152,outChannels:192,kernel:5,stride:1,padding:2}),this.s5b2=new w(t,this.s5b1.output,e.encoder.s5[2],{inChannels:192,midChannels:1152,outChannels:192,kernel:5,stride:1,padding:2}),this.s5b3=new w(t,this.s5b2.output,e.encoder.s5[3],{inChannels:192,midChannels:1152,outChannels:192,kernel:5,stride:1,padding:2}),this.s6b0=new w(t,this.s5b3.output,e.encoder.s6[0],{inChannels:192,midChannels:1152,outChannels:320,kernel:3,stride:1,padding:1}),this.bottleneck=t.ops.Conv2d(this.s6b0.output,e.bottleneck,{outChannels:128,kernel:1,stride:1,padding:0,activation:"relu6"}),this.dec0=new G(t,this.bottleneck.output,this.s4b2.output,e.decoder.blocks[0],{outChannels:64}),this.dec1=new G(t,this.dec0.output,this.s2b1.output,e.decoder.blocks[1],{outChannels:32}),this.dec2=new G(t,this.dec1.output,this.s1b1.output,e.decoder.blocks[2],{outChannels:16}),this.finalUp=t.ops.UpsampleConv1x1(this.dec2.output,e.decoder.finalUpsample,{outH:this.dec2.output.h*2,outW:this.dec2.output.w*2,outChannels:16,activation:"relu6"}),this.featLowRes=this.finalUp.output,this.encoderTaps=[this.s1b1.output,this.s2b1.output,this.s4b2.output,this.s6b0.output],this.outConv=t.ops.Conv2d(this.finalUp.output,e.decoder.outputConv,{outChannels:4,kernel:1,stride:1,padding:0,activation:"none"}),this.alpha=t.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 wt=[[{in:24,mid:144,out:32,k:3,s:2},{in:32,mid:192,out:32,k:3,s:1},{in:32,mid:192,out:32,k:3,s:1},{in:32,mid:192,out:32,k:3,s:1}],[{in:32,mid:192,out:56,k:5,s:2},{in:56,mid:336,out:56,k:5,s:1},{in:56,mid:336,out:56,k:5,s:1},{in:56,mid:336,out:56,k:5,s:1}],[{in:56,mid:336,out:112,k:3,s:2},{in:112,mid:672,out:112,k:3,s:1},{in:112,mid:672,out:112,k:3,s:1},{in:112,mid:672,out:112,k:3,s:1},{in:112,mid:672,out:112,k:3,s:1},{in:112,mid:672,out:112,k:3,s:1}],[{in:112,mid:672,out:160,k:5,s:1},{in:160,mid:960,out:160,k:5,s:1},{in:160,mid:960,out:160,k:5,s:1},{in:160,mid:960,out:160,k:5,s:1},{in:160,mid:960,out:160,k:5,s:1},{in:160,mid:960,out:160,k:5,s:1}],[{in:160,mid:960,out:272,k:5,s:2},{in:272,mid:1632,out:272,k:5,s:1},{in:272,mid:1632,out:272,k:5,s:1},{in:272,mid:1632,out:272,k:5,s:1},{in:272,mid:1632,out:272,k:5,s:1},{in:272,mid:1632,out:272,k:5,s:1},{in:272,mid:1632,out:272,k:5,s:1},{in:272,mid:1632,out:272,k:5,s:1}],[{in:272,mid:1632,out:448,k:3,s:1}]],se=class{constructor(t,r,e){a(this,"output");a(this,"featLowRes");a(this,"encoderTaps");a(this,"stem");a(this,"s0");a(this,"stages");a(this,"bottleneck");a(this,"dec0");a(this,"dec1");a(this,"dec2");a(this,"finalUp");a(this,"outConv");a(this,"alpha");this.stem=t.ops.Conv2d(r,e.encoder.stem,{outChannels:32,kernel:3,stride:2,padding:"same",activation:"relu6"}),this.s0=new L(t,this.stem.output,e.encoder.s0,{outChannels:24,kernel:3,stride:1,padding:1});let i=[e.encoder.s1,e.encoder.s2,e.encoder.s3,e.encoder.s4,e.encoder.s5,e.encoder.s6];this.stages=[];let o=this.s0.output;for(let d=0;d<wt.length;d++){let _=[];for(let b=0;b<wt[d].length;b++){let g=wt[d][b],v=new w(t,o,i[d][b],{inChannels:g.in,midChannels:g.mid,outChannels:g.out,kernel:g.k,stride:g.s,padding:g.s===2?"same":(g.k-1)/2});_.push(v),o=v.output}this.stages.push(_)}let n=d=>this.stages[d][this.stages[d].length-1].output,s=n(0),p=n(1),l=n(3),c=n(5);this.bottleneck=t.ops.Conv2d(c,e.bottleneck,{outChannels:256,kernel:1,stride:1,padding:0,activation:"relu6"}),this.dec0=new G(t,this.bottleneck.output,l,e.decoder.blocks[0],{outChannels:128}),this.dec1=new G(t,this.dec0.output,p,e.decoder.blocks[1],{outChannels:64}),this.dec2=new G(t,this.dec1.output,s,e.decoder.blocks[2],{outChannels:32}),this.finalUp=t.ops.UpsampleConv1x1(this.dec2.output,e.decoder.finalUpsample,{outH:this.dec2.output.h*2,outW:this.dec2.output.w*2,outChannels:32,activation:"relu6"}),this.featLowRes=this.finalUp.output,this.encoderTaps=[s,p,l,c],this.outConv=t.ops.Conv2d(this.finalUp.output,e.decoder.outputConv,{outChannels:4,kernel:1,stride:1,padding:0,activation:"none"}),this.alpha=t.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();for(let t of this.stages)for(let r of t)r.run();this.bottleneck.run(),this.dec0.run(),this.dec1.run(),this.dec2.run(),this.finalUp.run(),this.outConv.run(),this.alpha.run()}};var Bt=ae,Ut=ne,zo=se,O={xs:{base:Bt,wrapper:{variant:"B",cHigh:4,cLow:4,cUp:2},canvasRes:{w:384,h:216},baseRes:{w:128,h:72},flowFuseStem:!0},small:{base:Bt,wrapper:{variant:"A",cHigh:4,cLow:4,cUp:2},canvasRes:{w:384,h:216},baseRes:{w:192,h:108}},medium:{base:Ut,wrapper:{variant:"A",cHigh:4,cLow:4,cUp:2},canvasRes:{w:512,h:288},baseRes:{w:256,h:144}},large:{base:Ut,wrapper:{variant:"D",cHigh:4,cLow:4,cUp:2},canvasRes:{w:640,h:360},baseRes:{w:256,h:144}},xl:{base:zo,wrapper:{variant:"E",cHigh:4,cLow:4,cUp:2},canvasRes:{w:1280,h:720},baseRes:{w:320,h:180}}};var Vo=16,No={tLo:.15,tHi:2.5,leak:.15,release:.9,tDiv:1,divScale:2},$o=15,Xo=5,St=1e3,ue=class{constructor(t){a(this,"canvas");a(this,"backend");a(this,"backendKind");a(this,"topology");a(this,"preset",null);a(this,"enabled");a(this,"currentBackground");a(this,"modelTimingCounter",0);a(this,"renderOp");a(this,"flow",null);a(this,"bgImageInputs",new Map);a(this,"bgVideoInputs",new Map);a(this,"bgVideoPorts",new Map);a(this,"previewCanvas",null);a(this,"previewCtx",null);a(this,"previewBg",null);a(this,"previewEffectSpec",null);a(this,"previewIntervalMs",1e3/$o);a(this,"lastPreviewAt",0);a(this,"skipCounter",0);a(this,"framesRenderedAt",[]);a(this,"modelRunSamples",[]);a(this,"displayRunSamples",[]);a(this,"skippedCount",0);this.backend=t.backend,this.backendKind=t.backendKind,this.canvas=t.canvas,this.enabled=t.enabled,this.currentBackground=t.background,this.topology=t.topology,this.renderOp=new te(this.backend)}process(t){this.renderOp.setSource(t);let r=performance.now(),e=this.renderOp.hasNetwork(),i=this.enabled&&e&&this.currentBackground.kind!=="none",o=this.isPreviewTick(r),n=o&&e&&this.previewBg!==null&&this.previewBg.kind!=="none",s=!1;i&&this.flow?s=this.stepFlow():i&&(this.shouldRunModel()?(this.runModelOnce(),s=!0):this.skippedCount++),!s&&n&&(this.runModelOnce(),s=!0);let p=performance.now();o&&this.previewCanvas?(this.backendKind==="webgl"?this.compositePreviewWebGL(i,n):(this.compositeMain(i),this.renderOp.compositeTo("preview",this.previewSpec(n))),this.lastPreviewAt=r):this.compositeMain(i),this.displayRunSamples.push({ts:performance.now(),ms:performance.now()-p}),this.trimSamples(this.displayRunSamples),this.framesRenderedAt.push(performance.now()),this.trim(this.framesRenderedAt)}compositeMain(t){t?this.renderOp.runDisplay():this.renderOp.runPassthrough()}compositePreviewWebGL(t,r){this.renderOp.refreshDisplayInput(),this.renderOp.compositeTo("preview",this.previewSpec(r));let e=this.canvas.transferToImageBitmap();this.previewCtx.transferFromImageBitmap(e),this.renderOp.compositeMain(!t)}previewSpec(t){return t&&this.previewEffectSpec?this.previewEffectSpec:{mode:"passthrough"}}runModelOnce(){let t=performance.now();this.renderOp.runModel(),this.backendKind==="webgpu"&&this.modelTimingCounter%Xo===0&&this.backend.sync().then(()=>{this.modelRunSamples.push({ts:performance.now(),ms:performance.now()-t}),this.trimSamples(this.modelRunSamples)}).catch(()=>{}),this.modelTimingCounter++}stepFlow(){let t=this.flow,r=!1;return t.networkInput.run(),t.curBaseDown.run(),t.everyFrame?(t.net.run(),t.up.run(),this.runModelOnce(),r=!0,this.backend.copyTensor(t.curBaseDown.output,t.frameAHeld),this.backend.copyTensor(t.tier.output,t.predBuf)):this.shouldRunModel()?(this.runModelOnce(),r=!0,this.backend.copyTensor(t.curBaseDown.output,t.frameAHeld),this.backend.copyTensor(t.tier.output,t.alphaHeld),this.backend.copyTensor(t.tier.output,t.predBuf)):(this.skippedCount++,t.net.run(),t.up.run(),t.predWarp.run(),this.backend.copyTensor(t.predWarp.output,t.predBuf)),t.warm?(t.refWarp.run(),t.stab.run(),this.backend.copyTensor(t.stab.output,t.stabPrev),this.renderOp.applyAlpha(t.stab.output),r):(this.backend.copyTensor(t.tier.output,t.stabPrev),t.warm=r,r)}isPreviewTick(t){return!this.previewCanvas||this.previewBg===null||!this.enabled?!1:t-this.lastPreviewAt>=this.previewIntervalMs}shouldRunModel(){return this.skipCounter===0?(this.skipCounter=this.preset?.skipFrames??0,!0):(this.skipCounter--,!1)}setBackground(t){this.currentBackground=t,this.renderOp.setBackground(this.translateBackgroundFor("main",t))}setEnabled(t){this.enabled=t}attachPreview(t){if(t.width=this.canvas.width,t.height=this.canvas.height,this.previewCanvas=t,this.backendKind==="webgpu")this.backend.attachCanvas("preview",t);else{let r=t.getContext("bitmaprenderer");if(!r)throw new Error("renderer: failed to get bitmaprenderer context for preview canvas");this.previewCtx=r}}setPreview(t,r){this.previewBg=t,this.previewEffectSpec=t.kind==="none"?null:this.translateBackgroundFor("preview",t),r?.fps&&r.fps>0&&(this.previewIntervalMs=1e3/r.fps),this.lastPreviewAt=0}clearPreview(){this.previewBg=null,this.previewEffectSpec=null;let t=this.bgVideoPorts.get("preview");t&&(t.close(),this.bgVideoPorts.delete("preview"))}setPreset(t,r){let e=O[t.model];if(!e)throw new Error(\`renderer: no TIER_CONFIG entry for model '\${t.model}'\`);let i=Wt(r),o=this.backend.ops.Input(e.canvasRes.h,e.canvasRes.w),n=new re(this.backend,o.output,i.base,i.wrapper,e.wrapper,e.base);if(this.renderOp.attachNetwork(n,o,{upscaler:"bilinear",background:this.translateBackgroundFor("main",this.currentBackground)}),this.flow=null,i.flow){let s=e.baseRes,p=e.canvasRes,l=t.skipFrames===0,c=(D,V)=>this.backend.tensor(D,V,4,new Float32Array(D*V*4)),d=this.backend.ops.BilinearUpsample(o.output,{outH:s.h,outW:s.w}),_=c(s.h,s.w),b=new ie(this.backend,_,d.output,n.encoderTaps,i.flow,Vo,e.flowFuseStem?{fuseStem:!0,halfTap:n.halfTap}:{}),g=this.backend.ops.BilinearUpsample(b.output,{outH:p.h,outW:p.w}),v=p.w/s.w,x=c(p.h,p.w),k=c(p.h,p.w),B=this.backend.ops.Warp(k,g.output,{flowScale:v}),U=Math.max(1,Math.round(p.w/b.output.w)),X=Math.max(1,Math.round(p.h/b.output.h)),vt=this.backend.ops.Stabilize(g.output,x,B.output,k,{...No,stepX:U,stepY:X}),z=l?null:c(p.h,p.w),j=z?this.backend.ops.Warp(z,g.output,{flowScale:v}):null;this.flow={tier:n,everyFrame:l,warm:!1,networkInput:o,curBaseDown:d,frameAHeld:_,net:b,up:g,predBuf:x,stabPrev:k,refWarp:B,stab:vt,alphaHeld:z,predWarp:j}}this.preset=t,this.skipCounter=0}destroy(){for(let t of this.bgVideoPorts.values())t.close();this.bgVideoPorts.clear(),this.backend.destroy()}getStats(){let t=performance.now();return this.trimRecent(this.framesRenderedAt,t),this.trimSamplesAt(this.modelRunSamples,t),this.trimSamplesAt(this.displayRunSamples,t),{fps:this.framesRenderedAt.length,modelFps:this.modelRunSamples.length,modelMs:Lt(this.modelRunSamples.map(r=>r.ms)),displayMs:Lt(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}}translateBackgroundFor(t,r){let e=this.bgVideoPorts.get(t);switch(r.kind!=="video"&&e&&(e.close(),this.bgVideoPorts.delete(t)),r.kind){case"none":return{mode:"solid",color:[0,0,0]};case"color":return{mode:"solid",color:r.rgb};case"blur":return{mode:"blur",sigma:r.sigma};case"image":{let i=this.bgInputFor(this.bgImageInputs,t);return i.setSource(r.bitmap),i.run(),{mode:"image",image:i.output}}case"video":{let i=this.bgInputFor(this.bgVideoInputs,t);return e&&e.close(),this.bgVideoPorts.set(t,r.port),r.port.onmessage=o=>{let n=o.data.frame;try{i.setSource(n),i.run()}finally{n.close()}},r.port.start?.(),{mode:"image",image:i.output}}}}bgInputFor(t,r){let e=t.get(r);return e||(e=this.backend.ops.Input(this.canvas.height,this.canvas.width),t.set(r,e)),e}trim(t){t.length>240&&t.splice(0,t.length-240)}trimSamples(t){t.length>240&&t.splice(0,t.length-240)}trimRecent(t,r){let e=r-St,i=0;for(;i<t.length&&t[i]<e;)i++;i>0&&t.splice(0,i)}trimSamplesAt(t,r){let e=r-St,i=0;for(;i<t.length&&t[i].ts<e;)i++;i>0&&t.splice(0,i)}};function Lt(u){if(u.length===0)return 0;let t=u.slice().sort((e,i)=>e-i),r=t.length>>1;return t.length%2?t[r]:(t[r-1]+t[r])/2}var I=new Float32Array(1),N=new Uint32Array(I.buffer);function jo(u){I[0]=u;let t=N[0],r=t>>>16&32768,e=t&2147483647,i=(e>>>23)-127+15;if((t&2139095040)===2139095040)return(t&8388607)!==0?r|32256:r|31744;if(i>=31)return r|31744;if(i<=0){if(i<-10)return r;let l=e&8388607|8388608,c=14-i,d=l>>>c,_=l>>>c-1&1,b=(l&(1<<c-1)-1)!==0?1:0;return _&&(b||d&1)&&(d+=1),r|d}let o=e>>>13&1023,n=e>>>12&1,s=(e&4095)!==0?1:0,p=i<<10|o;return n&&(s||o&1)&&(p+=1,(p>>>10&31)===31)?r|31744:r|p}function kt(u){let t=(u&32768)<<16,r=(u&31744)>>>10,e=u&1023;if(r===0){if(e===0)return N[0]=t,I[0];let i=e,o=1;for(;(i&1024)===0;)i<<=1,o-=1;return i&=1023,N[0]=t|o+127-15<<23|i<<13,I[0]}return r===31?(N[0]=t|2139095040|e<<13,I[0]):(N[0]=t|r+127-15<<23|e<<13,I[0])}function pe(u){let t=new Uint16Array(u.length);for(let r=0;r<u.length;r++)t[r]=jo(u[r]);return t}function A(u){let t=new Float32Array(u.length);for(let r=0;r<u.length;r++)t[r]=kt(u[r]);return t}var f=class{constructor(t){a(this,"backend",t);a(this,"shader","");a(this,"pipeline");a(this,"bindGroup");a(this,"uniformDefs",[]);a(this,"uniformBuffers",{})}createUniform(t,r){this.uniformDefs.push({name:t,type:r})}setUniform(t,r){let e=this.backend.device.createBuffer({size:r.byteLength,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST,mappedAtCreation:!0});r instanceof Uint32Array?new Uint32Array(e.getMappedRange()).set(r):new Float32Array(e.getMappedRange()).set(r),e.unmap(),this.uniformBuffers[t]=e}defaultBindGroup(){let t=[],r=0;for(let e of this.inputs)t.push({binding:r++,resource:{buffer:e.buffer}});for(let e of this.weights)t.push({binding:r++,resource:{buffer:e.buffer}});for(let e of this.uniformDefs)t.push({binding:r++,resource:{buffer:this.uniformBuffers[e.name]}});return t.push({binding:r,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(),r=t.beginComputePass();r.setPipeline(this.pipeline),r.setBindGroup(0,this.bindGroup),r.dispatchWorkgroups(...this.dispatch),r.end(),this.backend.device.queue.submit([t.finish()])}};var Ft=\`// Conv2d, output-channel-blocked (K=2) \\u2014 drop-in replacement for conv2d.wgsl.
|
|
2
2
|
//
|
|
3
|
-
// Identical math, layout, and output to conv2d.wgsl, but each thread computes
|
|
4
|
-
// output channel-groups (
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
// unchanged. Dispatch ceil(out_groups / 4) in z (see conv2d.ts).
|
|
3
|
+
// Identical math, layout, and output to conv2d.wgsl, but each thread computes 2
|
|
4
|
+
// output channel-groups (8 channels) for one pixel, loading each input vec4 ONCE
|
|
5
|
+
// and reusing it across both groups' mat4x4 weight blocks in registers. Half the
|
|
6
|
+
// register pressure of the K=4 variant (2 accumulators vs 4). Output is bit-
|
|
7
|
+
// identical to conv2d.wgsl (\\u22641 ULP from FMA contraction). Dispatch
|
|
8
|
+
// ceil(out_groups / 2) in z (see conv2d.ts).
|
|
10
9
|
//
|
|
11
10
|
// Tensor layout: NHWC, channels in vec4 groups (same as conv2d.wgsl).
|
|
12
11
|
// Weight layout: [K*K][out_groups][in_groups] array of mat4x4 (same as conv2d.wgsl).
|
|
@@ -23,7 +22,7 @@ struct Params {
|
|
|
23
22
|
stride : u32,
|
|
24
23
|
pad_top : u32,
|
|
25
24
|
pad_left : u32,
|
|
26
|
-
activation : u32, // 0 = none, 1 = relu6, 2 = relu
|
|
25
|
+
activation : u32, // 0 = none, 1 = relu6, 2 = relu, 3 = leaky
|
|
27
26
|
}
|
|
28
27
|
|
|
29
28
|
@group(0) @binding(0) var<storage, read> input_buf : array<vec4<f32>>;
|
|
@@ -32,18 +31,19 @@ struct Params {
|
|
|
32
31
|
@group(0) @binding(3) var<uniform> params : Params;
|
|
33
32
|
@group(0) @binding(4) var<storage, read_write> output_buf : array<vec4<f32>>;
|
|
34
33
|
|
|
35
|
-
const KB =
|
|
34
|
+
const KB = 2u;
|
|
36
35
|
|
|
37
36
|
fn act(v: vec4<f32>, a: u32) -> vec4<f32> {
|
|
38
37
|
if (a == 1u) { return clamp(v, vec4<f32>(0.0), vec4<f32>(6.0)); }
|
|
39
38
|
if (a == 2u) { return max(v, vec4<f32>(0.0)); }
|
|
39
|
+
if (a == 3u) { return max(v, 0.1 * v); } // leaky relu (slope 0.1)
|
|
40
40
|
return v;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
@compute @workgroup_size(8, 8, 1)
|
|
44
44
|
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
45
|
-
let x = gid.x;
|
|
46
|
-
let y = gid.y;
|
|
45
|
+
let x = gid.x; // output column
|
|
46
|
+
let y = gid.y; // output row
|
|
47
47
|
let o0 = gid.z * KB; // first output channel group
|
|
48
48
|
|
|
49
49
|
if (x >= params.out_w || y >= params.out_h || o0 >= params.out_groups) {
|
|
@@ -52,19 +52,13 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
52
52
|
|
|
53
53
|
let I = params.in_groups;
|
|
54
54
|
let O = params.out_groups;
|
|
55
|
-
// Tail handling when out_groups is
|
|
56
|
-
//
|
|
55
|
+
// Tail handling when out_groups is odd: clamp the spare lane to o0 (valid
|
|
56
|
+
// index, no OOB) and just don't write it.
|
|
57
57
|
let has1 = (o0 + 1u) < O;
|
|
58
|
-
let has2 = (o0 + 2u) < O;
|
|
59
|
-
let has3 = (o0 + 3u) < O;
|
|
60
58
|
let o1 = select(o0, o0 + 1u, has1);
|
|
61
|
-
let o2 = select(o0, o0 + 2u, has2);
|
|
62
|
-
let o3 = select(o0, o0 + 3u, has3);
|
|
63
59
|
|
|
64
60
|
var acc0 = bias_buf[o0];
|
|
65
61
|
var acc1 = bias_buf[o1];
|
|
66
|
-
var acc2 = bias_buf[o2];
|
|
67
|
-
var acc3 = bias_buf[o3];
|
|
68
62
|
|
|
69
63
|
for (var ky = 0u; ky < params.kernel_h; ky++) {
|
|
70
64
|
for (var kx = 0u; kx < params.kernel_w; kx++) {
|
|
@@ -80,14 +74,10 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
80
74
|
let inB = u32(in_y_s) * params.in_w * I + u32(in_x_s) * I;
|
|
81
75
|
let wb0 = z * O * I + o0 * I;
|
|
82
76
|
let wb1 = z * O * I + o1 * I;
|
|
83
|
-
let wb2 = z * O * I + o2 * I;
|
|
84
|
-
let wb3 = z * O * I + o3 * I;
|
|
85
77
|
for (var i = 0u; i < I; i++) {
|
|
86
|
-
let iv = input_buf[inB + i]; // loaded ONCE, reused across
|
|
78
|
+
let iv = input_buf[inB + i]; // loaded ONCE, reused across 2 groups
|
|
87
79
|
acc0 += weight_buf[wb0 + i] * iv;
|
|
88
80
|
acc1 += weight_buf[wb1 + i] * iv;
|
|
89
|
-
acc2 += weight_buf[wb2 + i] * iv;
|
|
90
|
-
acc3 += weight_buf[wb3 + i] * iv;
|
|
91
81
|
}
|
|
92
82
|
}
|
|
93
83
|
}
|
|
@@ -95,15 +85,14 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
95
85
|
let baseO = y * params.out_w * O + x * O;
|
|
96
86
|
output_buf[baseO + o0] = act(acc0, params.activation);
|
|
97
87
|
if (has1) { output_buf[baseO + o1] = act(acc1, params.activation); }
|
|
98
|
-
if (has2) { output_buf[baseO + o2] = act(acc2, params.activation); }
|
|
99
|
-
if (has3) { output_buf[baseO + o3] = act(acc3, params.activation); }
|
|
100
88
|
}
|
|
101
|
-
\`;var
|
|
89
|
+
\`;var Et=\`enable f16;
|
|
102
90
|
|
|
103
|
-
// Conv2d, output-channel-blocked (K=
|
|
104
|
-
// conv2d_f16.wgsl. Each thread computes
|
|
105
|
-
// loading each input vec4
|
|
106
|
-
//
|
|
91
|
+
// Conv2d, output-channel-blocked (K=2) \\u2014 full f16. Drop-in replacement for
|
|
92
|
+
// conv2d_f16.wgsl. Each thread computes 2 output channel-groups for one pixel,
|
|
93
|
+
// loading each input vec4 ONCE and reusing it across both weight blocks. Half the
|
|
94
|
+
// register pressure of the K=4 variant (2 accumulators vs 4). Output is bit-
|
|
95
|
+
// identical to conv2d_f16.wgsl. Dispatch ceil(out_groups / 2) in z.
|
|
107
96
|
|
|
108
97
|
struct Params {
|
|
109
98
|
in_h : u32,
|
|
@@ -126,11 +115,12 @@ struct Params {
|
|
|
126
115
|
@group(0) @binding(3) var<uniform> params : Params;
|
|
127
116
|
@group(0) @binding(4) var<storage, read_write> output_buf : array<vec4<f16>>;
|
|
128
117
|
|
|
129
|
-
const KB =
|
|
118
|
+
const KB = 2u;
|
|
130
119
|
|
|
131
120
|
fn act(v: vec4<f16>, a: u32) -> vec4<f16> {
|
|
132
121
|
if (a == 1u) { return clamp(v, vec4<f16>(0.0h), vec4<f16>(6.0h)); }
|
|
133
122
|
if (a == 2u) { return max(v, vec4<f16>(0.0h)); }
|
|
123
|
+
if (a == 3u) { return max(v, 0.1h * v); } // leaky relu (slope 0.1)
|
|
134
124
|
return v;
|
|
135
125
|
}
|
|
136
126
|
|
|
@@ -147,16 +137,10 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
147
137
|
let I = params.in_groups;
|
|
148
138
|
let O = params.out_groups;
|
|
149
139
|
let has1 = (o0 + 1u) < O;
|
|
150
|
-
let has2 = (o0 + 2u) < O;
|
|
151
|
-
let has3 = (o0 + 3u) < O;
|
|
152
140
|
let o1 = select(o0, o0 + 1u, has1);
|
|
153
|
-
let o2 = select(o0, o0 + 2u, has2);
|
|
154
|
-
let o3 = select(o0, o0 + 3u, has3);
|
|
155
141
|
|
|
156
142
|
var acc0 = bias_buf[o0];
|
|
157
143
|
var acc1 = bias_buf[o1];
|
|
158
|
-
var acc2 = bias_buf[o2];
|
|
159
|
-
var acc3 = bias_buf[o3];
|
|
160
144
|
|
|
161
145
|
for (var ky = 0u; ky < params.kernel_h; ky++) {
|
|
162
146
|
for (var kx = 0u; kx < params.kernel_w; kx++) {
|
|
@@ -172,14 +156,10 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
172
156
|
let inB = u32(in_y_s) * params.in_w * I + u32(in_x_s) * I;
|
|
173
157
|
let wb0 = z * O * I + o0 * I;
|
|
174
158
|
let wb1 = z * O * I + o1 * I;
|
|
175
|
-
let wb2 = z * O * I + o2 * I;
|
|
176
|
-
let wb3 = z * O * I + o3 * I;
|
|
177
159
|
for (var i = 0u; i < I; i++) {
|
|
178
|
-
let iv = input_buf[inB + i];
|
|
160
|
+
let iv = input_buf[inB + i]; // loaded ONCE, reused across 2 groups
|
|
179
161
|
acc0 += weight_buf[wb0 + i] * iv;
|
|
180
162
|
acc1 += weight_buf[wb1 + i] * iv;
|
|
181
|
-
acc2 += weight_buf[wb2 + i] * iv;
|
|
182
|
-
acc3 += weight_buf[wb3 + i] * iv;
|
|
183
163
|
}
|
|
184
164
|
}
|
|
185
165
|
}
|
|
@@ -187,10 +167,156 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
187
167
|
let baseO = y * params.out_w * O + x * O;
|
|
188
168
|
output_buf[baseO + o0] = act(acc0, params.activation);
|
|
189
169
|
if (has1) { output_buf[baseO + o1] = act(acc1, params.activation); }
|
|
190
|
-
if (has2) { output_buf[baseO + o2] = act(acc2, params.activation); }
|
|
191
|
-
if (has3) { output_buf[baseO + o3] = act(acc3, params.activation); }
|
|
192
170
|
}
|
|
193
|
-
\`;function
|
|
171
|
+
\`;function T(u,t,r,e){return typeof e=="number"?Math.floor((u+2*e-t)/r)+1:e==="same"?Math.ceil(u/r):Math.floor((u-t)/r)+1}function M(u,t,r,e){return(u-1)*r-2*e+t}function Yo(u,t,r,e){return Math.floor(Math.max((t-1)*e+r-u,0)/2)}function C(u,t,r,e,i){return typeof u=="number"?u:u==="same"?Yo(t,r,e,i):0}function m(u){return u instanceof Float32Array||u instanceof Uint16Array?u:new Float32Array(u)}function y(u){let t=Math.max(4,Math.ceil(u.length/4)*4),r=new Float32Array(t),e=u instanceof Uint16Array;for(let i=0;i<u.length;i++)r[i]=e?kt(u[i]):u[i];return r}var le=class extends f{constructor(r,e,i,o){super(r);a(this,"inputs");a(this,"weights");a(this,"output");a(this,"dispatch");a(this,"shader");this.shader=r.dtype==="f16"?Et:Ft;let n=T(e.h,o.kernel,o.stride,o.padding),s=T(e.w,o.kernel,o.stride,o.padding),p=e.c/4,l=o.outChannels/4,c=C(o.padding,e.h,n,o.kernel,o.stride),d=C(o.padding,e.w,s,o.kernel,o.stride);this.output=r.tensor(n,s,o.outChannels),this.inputs=[e],this.weights=[r.upload(m(i.weights)),r.upload(m(i.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,n,s,p,l,o.kernel,o.kernel,o.stride,c,d,o.activation==="relu6"?1:o.activation==="relu"?2:o.activation==="leaky"?3:0])),this.defaultSetup(),this.dispatch=[Math.ceil(s/8),Math.ceil(n/8),Math.ceil(l/2)]}};var Dt=\`// ConvTranspose2d \\u2014 gather form, f32 variant. See conv_transpose2d_f16.wgsl for
|
|
172
|
+
// the math; this is the f32 storage build (mat4x4<f32>).
|
|
173
|
+
|
|
174
|
+
struct Params {
|
|
175
|
+
in_h : u32,
|
|
176
|
+
in_w : u32,
|
|
177
|
+
out_h : u32,
|
|
178
|
+
out_w : u32,
|
|
179
|
+
in_groups : u32,
|
|
180
|
+
out_groups : u32,
|
|
181
|
+
kernel_h : u32,
|
|
182
|
+
kernel_w : u32,
|
|
183
|
+
stride : u32,
|
|
184
|
+
pad_top : u32,
|
|
185
|
+
pad_left : u32,
|
|
186
|
+
activation : u32,
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
@group(0) @binding(0) var<storage, read> input_buf : array<vec4<f32>>;
|
|
190
|
+
@group(0) @binding(1) var<storage, read> weight_buf : array<mat4x4<f32>>;
|
|
191
|
+
@group(0) @binding(2) var<storage, read> bias_buf : array<vec4<f32>>;
|
|
192
|
+
@group(0) @binding(3) var<uniform> params : Params;
|
|
193
|
+
@group(0) @binding(4) var<storage, read_write> output_buf : array<vec4<f32>>;
|
|
194
|
+
|
|
195
|
+
fn act(v: vec4<f32>, a: u32) -> vec4<f32> {
|
|
196
|
+
if (a == 1u) { return clamp(v, vec4<f32>(0.0), vec4<f32>(6.0)); }
|
|
197
|
+
if (a == 2u) { return max(v, vec4<f32>(0.0)); }
|
|
198
|
+
if (a == 3u) { return max(v, 0.1 * v); }
|
|
199
|
+
return v;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
@compute @workgroup_size(8, 8, 1)
|
|
203
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
204
|
+
let ox = gid.x;
|
|
205
|
+
let oy = gid.y;
|
|
206
|
+
let o = gid.z;
|
|
207
|
+
|
|
208
|
+
if (ox >= params.out_w || oy >= params.out_h || o >= params.out_groups) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
let I = params.in_groups;
|
|
213
|
+
let O = params.out_groups;
|
|
214
|
+
let s = i32(params.stride);
|
|
215
|
+
|
|
216
|
+
var result = bias_buf[o];
|
|
217
|
+
|
|
218
|
+
for (var ky = 0u; ky < params.kernel_h; ky++) {
|
|
219
|
+
for (var kx = 0u; kx < params.kernel_w; kx++) {
|
|
220
|
+
let iy_num = i32(oy) + i32(params.pad_top) - i32(ky);
|
|
221
|
+
let ix_num = i32(ox) + i32(params.pad_left) - i32(kx);
|
|
222
|
+
if (iy_num < 0 || ix_num < 0 || (iy_num % s) != 0 || (ix_num % s) != 0) {
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
let iy = iy_num / s;
|
|
226
|
+
let ix = ix_num / s;
|
|
227
|
+
if (iy >= i32(params.in_h) || ix >= i32(params.in_w)) {
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
let z = ky * params.kernel_w + kx;
|
|
232
|
+
for (var i = 0u; i < I; i++) {
|
|
233
|
+
let in_idx = u32(iy) * params.in_w * I + u32(ix) * I + i;
|
|
234
|
+
let w_idx = z * O * I + o * I + i;
|
|
235
|
+
result += weight_buf[w_idx] * input_buf[in_idx];
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
output_buf[oy * params.out_w * O + ox * O + o] = act(result, params.activation);
|
|
241
|
+
}
|
|
242
|
+
\`;var Ot=\`enable f16;
|
|
243
|
+
|
|
244
|
+
// ConvTranspose2d \\u2014 gather form, full f16 variant.
|
|
245
|
+
// Each output (oy,ox) sums every input pixel + kernel tap that maps onto it:
|
|
246
|
+
// iy = (oy + pad - ky) / stride (must divide evenly and be in bounds)
|
|
247
|
+
// No explicit kernel flip \\u2014 the (oy + pad - ky) indexing carries it.
|
|
248
|
+
// Weight layout is IDENTICAL to conv2d (mat4x4[z][o][i], M[in_sub][out_sub] =
|
|
249
|
+
// W(in, out, ky, kx)), so the op uploads the flat buffer unchanged.
|
|
250
|
+
|
|
251
|
+
struct Params {
|
|
252
|
+
in_h : u32,
|
|
253
|
+
in_w : u32,
|
|
254
|
+
out_h : u32,
|
|
255
|
+
out_w : u32,
|
|
256
|
+
in_groups : u32,
|
|
257
|
+
out_groups : u32,
|
|
258
|
+
kernel_h : u32,
|
|
259
|
+
kernel_w : u32,
|
|
260
|
+
stride : u32,
|
|
261
|
+
pad_top : u32,
|
|
262
|
+
pad_left : u32,
|
|
263
|
+
activation : u32,
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
@group(0) @binding(0) var<storage, read> input_buf : array<vec4<f16>>;
|
|
267
|
+
@group(0) @binding(1) var<storage, read> weight_buf : array<mat4x4<f16>>;
|
|
268
|
+
@group(0) @binding(2) var<storage, read> bias_buf : array<vec4<f16>>;
|
|
269
|
+
@group(0) @binding(3) var<uniform> params : Params;
|
|
270
|
+
@group(0) @binding(4) var<storage, read_write> output_buf : array<vec4<f16>>;
|
|
271
|
+
|
|
272
|
+
fn act(v: vec4<f16>, a: u32) -> vec4<f16> {
|
|
273
|
+
if (a == 1u) { return clamp(v, vec4<f16>(0.0h), vec4<f16>(6.0h)); }
|
|
274
|
+
if (a == 2u) { return max(v, vec4<f16>(0.0h)); }
|
|
275
|
+
if (a == 3u) { return max(v, 0.1h * v); }
|
|
276
|
+
return v;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
@compute @workgroup_size(8, 8, 1)
|
|
280
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
281
|
+
let ox = gid.x;
|
|
282
|
+
let oy = gid.y;
|
|
283
|
+
let o = gid.z;
|
|
284
|
+
|
|
285
|
+
if (ox >= params.out_w || oy >= params.out_h || o >= params.out_groups) {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
let I = params.in_groups;
|
|
290
|
+
let O = params.out_groups;
|
|
291
|
+
let s = i32(params.stride);
|
|
292
|
+
|
|
293
|
+
var result = bias_buf[o];
|
|
294
|
+
|
|
295
|
+
for (var ky = 0u; ky < params.kernel_h; ky++) {
|
|
296
|
+
for (var kx = 0u; kx < params.kernel_w; kx++) {
|
|
297
|
+
let iy_num = i32(oy) + i32(params.pad_top) - i32(ky);
|
|
298
|
+
let ix_num = i32(ox) + i32(params.pad_left) - i32(kx);
|
|
299
|
+
if (iy_num < 0 || ix_num < 0 || (iy_num % s) != 0 || (ix_num % s) != 0) {
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
let iy = iy_num / s;
|
|
303
|
+
let ix = ix_num / s;
|
|
304
|
+
if (iy >= i32(params.in_h) || ix >= i32(params.in_w)) {
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
let z = ky * params.kernel_w + kx;
|
|
309
|
+
for (var i = 0u; i < I; i++) {
|
|
310
|
+
let in_idx = u32(iy) * params.in_w * I + u32(ix) * I + i;
|
|
311
|
+
let w_idx = z * O * I + o * I + i;
|
|
312
|
+
result += weight_buf[w_idx] * input_buf[in_idx];
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
output_buf[oy * params.out_w * O + ox * O + o] = act(result, params.activation);
|
|
318
|
+
}
|
|
319
|
+
\`;var ce=class extends f{constructor(r,e,i,o){super(r);a(this,"inputs");a(this,"weights");a(this,"output");a(this,"dispatch");a(this,"shader");this.shader=r.dtype==="f16"?Ot:Dt;let n=M(e.h,o.kernel,o.stride,o.padding),s=M(e.w,o.kernel,o.stride,o.padding),p=e.c/4,l=o.outChannels/4;this.output=r.tensor(n,s,o.outChannels),this.inputs=[e],this.weights=[r.upload(m(i.weights)),r.upload(m(i.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,n,s,p,l,o.kernel,o.kernel,o.stride,o.padding,o.padding,o.activation==="relu6"?1:o.activation==="relu"?2:o.activation==="leaky"?3:0])),this.defaultSetup(),this.dispatch=[Math.ceil(s/8),Math.ceil(n/8),l]}};var It=\`// Depthwise Conv2d \\u2014 groups = in_channels (each channel convolved independently).
|
|
194
320
|
//
|
|
195
321
|
// Weight layout: [K*K][channel_groups] array of vec4
|
|
196
322
|
// weight index = (ky*kernel_w + kx) * channel_groups + c
|
|
@@ -265,7 +391,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
265
391
|
let out_idx = y * params.out_w * C + x * C + c;
|
|
266
392
|
output_buf[out_idx] = result;
|
|
267
393
|
}
|
|
268
|
-
\`;var
|
|
394
|
+
\`;var At=\`enable f16;
|
|
269
395
|
|
|
270
396
|
// Depthwise conv2d \\u2014 full f16 variant. All buffers f16.
|
|
271
397
|
|
|
@@ -330,7 +456,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
330
456
|
|
|
331
457
|
output_buf[y * params.out_w * C + x * C + c] = result;
|
|
332
458
|
}
|
|
333
|
-
\`;var
|
|
459
|
+
\`;var de=class extends f{constructor(r,e,i,o){super(r);a(this,"inputs");a(this,"weights");a(this,"output");a(this,"dispatch");a(this,"shader");this.shader=r.dtype==="f16"?At:It;let n=T(e.h,o.kernel,o.stride,o.padding),s=T(e.w,o.kernel,o.stride,o.padding),p=e.c/4,l=C(o.padding,e.h,n,o.kernel,o.stride),c=C(o.padding,e.w,s,o.kernel,o.stride);this.output=r.tensor(n,s,e.c),this.inputs=[e],this.weights=[r.upload(m(i.weights)),r.upload(m(i.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,n,s,p,o.kernel,o.kernel,o.stride,l,c,o.activation==="relu6"?1:0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(s/8),Math.ceil(n/8),p]}};var Mt=\`// Element-wise add of two tensors \\u2014 used for residual connections in MBConv blocks.
|
|
334
460
|
// Operates on the flat float buffer directly; layout is irrelevant for a pure element-wise op.
|
|
335
461
|
|
|
336
462
|
struct Params {
|
|
@@ -351,7 +477,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
351
477
|
if (idx >= params.size) { return; }
|
|
352
478
|
output[idx] = input_a[idx] + input_b[idx];
|
|
353
479
|
}
|
|
354
|
-
\`;var
|
|
480
|
+
\`;var Rt=\`enable f16;
|
|
355
481
|
|
|
356
482
|
// Element-wise add \\u2014 full f16 variant.
|
|
357
483
|
// array<f16> is binary-compatible with array<vec4<f16>> written by the f16 conv shaders.
|
|
@@ -374,7 +500,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
374
500
|
if (idx >= params.size) { return; }
|
|
375
501
|
output[idx] = input_a[idx] + input_b[idx];
|
|
376
502
|
}
|
|
377
|
-
\`;var
|
|
503
|
+
\`;var me=class extends f{constructor(r,e,i){super(r);a(this,"inputs");a(this,"weights",[]);a(this,"output");a(this,"dispatch");a(this,"shader");this.shader=r.dtype==="f16"?Rt:Mt;let o=e.h*e.w*e.c;this.output=r.tensor(e.h,e.w,e.c),this.inputs=[e,i],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([o,0,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(o/256),1,1]}};var Ht=\`// Element-wise sigmoid: output = 1 / (1 + exp(-x)).
|
|
378
504
|
// Operates on packed vec4 buffers (NHWC layout). exp() and arithmetic are element-wise on vec4.
|
|
379
505
|
|
|
380
506
|
struct Params {
|
|
@@ -394,7 +520,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
394
520
|
if (idx >= params.n_groups) { return; }
|
|
395
521
|
output_buf[idx] = 1.0 / (1.0 + exp(-input_buf[idx]));
|
|
396
522
|
}
|
|
397
|
-
\`;var
|
|
523
|
+
\`;var zt=\`enable f16;
|
|
398
524
|
|
|
399
525
|
// Sigmoid \\u2014 full f16 variant.
|
|
400
526
|
|
|
@@ -416,7 +542,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
416
542
|
let x = vec4<f32>(input_buf[idx]);
|
|
417
543
|
output_buf[idx] = vec4<f16>(1.0 / (1.0 + exp(-x)));
|
|
418
544
|
}
|
|
419
|
-
\`;var
|
|
545
|
+
\`;var fe=class extends f{constructor(r,e){super(r);a(this,"inputs");a(this,"weights",[]);a(this,"output");a(this,"dispatch");a(this,"shader");this.shader=r.dtype==="f16"?zt:Ht;let i=e.h*e.w*(e.c/4);this.output=r.tensor(e.h,e.w,e.c),this.inputs=[e],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([i,0,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(i/256),1,1]}};var Vt=\`// Element-wise tanh \\u2014 used by ConvGRU candidate activation.
|
|
420
546
|
// Operates on packed vec4 buffers (NHWC layout). tanh() is element-wise on vec4.
|
|
421
547
|
|
|
422
548
|
struct Params {
|
|
@@ -436,7 +562,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
436
562
|
if (idx >= params.n_groups) { return; }
|
|
437
563
|
output_buf[idx] = tanh(input_buf[idx]);
|
|
438
564
|
}
|
|
439
|
-
\`;var
|
|
565
|
+
\`;var Nt=\`enable f16;
|
|
440
566
|
|
|
441
567
|
// Tanh \\u2014 full f16 variant.
|
|
442
568
|
|
|
@@ -458,7 +584,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
458
584
|
let x = vec4<f32>(input_buf[idx]);
|
|
459
585
|
output_buf[idx] = vec4<f16>(tanh(x));
|
|
460
586
|
}
|
|
461
|
-
\`;var
|
|
587
|
+
\`;var he=class extends f{constructor(r,e){super(r);a(this,"inputs");a(this,"weights",[]);a(this,"output");a(this,"dispatch");a(this,"shader");this.shader=r.dtype==="f16"?Nt:Vt;let i=e.h*e.w*(e.c/4);this.output=r.tensor(e.h,e.w,e.c),this.inputs=[e],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([i,0,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(i/256),1,1]}};var $t=\`// Element-wise multiply \\u2014 used in ConvGRU for r \\u2299 h_prev.
|
|
462
588
|
// Same flat-float layout as add.wgsl.
|
|
463
589
|
|
|
464
590
|
struct Params {
|
|
@@ -479,7 +605,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
479
605
|
if (idx >= params.size) { return; }
|
|
480
606
|
output[idx] = input_a[idx] * input_b[idx];
|
|
481
607
|
}
|
|
482
|
-
\`;var
|
|
608
|
+
\`;var Xt=\`enable f16;
|
|
483
609
|
|
|
484
610
|
// Element-wise multiply \\u2014 full f16 variant.
|
|
485
611
|
// array<f16> is binary-compatible with array<vec4<f16>> written by the f16 conv shaders.
|
|
@@ -502,7 +628,208 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
502
628
|
if (idx >= params.size) { return; }
|
|
503
629
|
output[idx] = input_a[idx] * input_b[idx];
|
|
504
630
|
}
|
|
505
|
-
\`;var
|
|
631
|
+
\`;var _e=class extends f{constructor(r,e,i){super(r);a(this,"inputs");a(this,"weights",[]);a(this,"output");a(this,"dispatch");a(this,"shader");this.shader=r.dtype==="f16"?Xt:$t;let o=e.h*e.w*e.c;this.output=r.tensor(e.h,e.w,e.c),this.inputs=[e,i],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([o,0,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(o/256),1,1]}};var jt=\`// Bilinear gather-warp (f32). See warp_f16.wgsl for the math.
|
|
632
|
+
|
|
633
|
+
struct Params {
|
|
634
|
+
h : u32,
|
|
635
|
+
w : u32,
|
|
636
|
+
flow_scale : f32,
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
@group(0) @binding(0) var<storage, read> source_buf : array<vec4<f32>>;
|
|
640
|
+
@group(0) @binding(1) var<storage, read> flow_buf : array<vec4<f32>>;
|
|
641
|
+
@group(0) @binding(2) var<uniform> params : Params;
|
|
642
|
+
@group(0) @binding(3) var<storage, read_write> output_buf : array<vec4<f32>>;
|
|
643
|
+
|
|
644
|
+
fn samp(x: i32, y: i32, W: i32, H: i32) -> vec4<f32> {
|
|
645
|
+
let cx = clamp(x, 0, W - 1);
|
|
646
|
+
let cy = clamp(y, 0, H - 1);
|
|
647
|
+
return source_buf[u32(cy) * u32(W) + u32(cx)];
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
@compute @workgroup_size(8, 8, 1)
|
|
651
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
652
|
+
let x = gid.x;
|
|
653
|
+
let y = gid.y;
|
|
654
|
+
if (x >= params.w || y >= params.h) { return; }
|
|
655
|
+
|
|
656
|
+
let W = i32(params.w);
|
|
657
|
+
let H = i32(params.h);
|
|
658
|
+
let idx = y * params.w + x;
|
|
659
|
+
|
|
660
|
+
let f = flow_buf[idx].xy;
|
|
661
|
+
let sx = clamp(f32(x) + params.flow_scale * f.x, 0.0, f32(W - 1));
|
|
662
|
+
let sy = clamp(f32(y) + params.flow_scale * f.y, 0.0, f32(H - 1));
|
|
663
|
+
|
|
664
|
+
let x0 = i32(floor(sx));
|
|
665
|
+
let y0 = i32(floor(sy));
|
|
666
|
+
let tx = sx - f32(x0);
|
|
667
|
+
let ty = sy - f32(y0);
|
|
668
|
+
|
|
669
|
+
let top = mix(samp(x0, y0, W, H), samp(x0 + 1, y0, W, H), tx);
|
|
670
|
+
let bot = mix(samp(x0, y0 + 1, W, H), samp(x0 + 1, y0 + 1, W, H), tx);
|
|
671
|
+
output_buf[idx] = mix(top, bot, ty);
|
|
672
|
+
}
|
|
673
|
+
\`;var qt=\`enable f16;
|
|
674
|
+
|
|
675
|
+
// Bilinear gather-warp (f16 storage, f32 coordinate math). For each output pixel
|
|
676
|
+
// p, sample the source at p + flow_scale\\xB7flow[p].xy and bilinearly interpolate,
|
|
677
|
+
// clamping the sample to the edge (border-replicate). Source + flow are 4-ch
|
|
678
|
+
// (1 group), same resolution; flow vector is in .xy.
|
|
679
|
+
|
|
680
|
+
struct Params {
|
|
681
|
+
h : u32,
|
|
682
|
+
w : u32,
|
|
683
|
+
flow_scale : f32,
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
@group(0) @binding(0) var<storage, read> source_buf : array<vec4<f16>>;
|
|
687
|
+
@group(0) @binding(1) var<storage, read> flow_buf : array<vec4<f16>>;
|
|
688
|
+
@group(0) @binding(2) var<uniform> params : Params;
|
|
689
|
+
@group(0) @binding(3) var<storage, read_write> output_buf : array<vec4<f16>>;
|
|
690
|
+
|
|
691
|
+
fn samp(x: i32, y: i32, W: i32, H: i32) -> vec4<f32> {
|
|
692
|
+
let cx = clamp(x, 0, W - 1);
|
|
693
|
+
let cy = clamp(y, 0, H - 1);
|
|
694
|
+
return vec4<f32>(source_buf[u32(cy) * u32(W) + u32(cx)]);
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
@compute @workgroup_size(8, 8, 1)
|
|
698
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
699
|
+
let x = gid.x;
|
|
700
|
+
let y = gid.y;
|
|
701
|
+
if (x >= params.w || y >= params.h) { return; }
|
|
702
|
+
|
|
703
|
+
let W = i32(params.w);
|
|
704
|
+
let H = i32(params.h);
|
|
705
|
+
let idx = y * params.w + x;
|
|
706
|
+
|
|
707
|
+
let f = vec2<f32>(flow_buf[idx].xy);
|
|
708
|
+
let sx = clamp(f32(x) + params.flow_scale * f.x, 0.0, f32(W - 1));
|
|
709
|
+
let sy = clamp(f32(y) + params.flow_scale * f.y, 0.0, f32(H - 1));
|
|
710
|
+
|
|
711
|
+
let x0 = i32(floor(sx));
|
|
712
|
+
let y0 = i32(floor(sy));
|
|
713
|
+
let tx = sx - f32(x0);
|
|
714
|
+
let ty = sy - f32(y0);
|
|
715
|
+
|
|
716
|
+
let top = mix(samp(x0, y0, W, H), samp(x0 + 1, y0, W, H), tx);
|
|
717
|
+
let bot = mix(samp(x0, y0 + 1, W, H), samp(x0 + 1, y0 + 1, W, H), tx);
|
|
718
|
+
output_buf[idx] = vec4<f16>(mix(top, bot, ty));
|
|
719
|
+
}
|
|
720
|
+
\`;var ge=class extends f{constructor(r,e,i,o){super(r);a(this,"inputs");a(this,"weights",[]);a(this,"output");a(this,"dispatch");a(this,"shader");this.shader=r.dtype==="f16"?qt:jt,this.output=r.tensor(e.h,e.w,e.c),this.inputs=[e,i],this.createUniform("params","Params");let n=new Uint32Array(3);n[0]=e.h,n[1]=e.w,new Float32Array(n.buffer)[2]=o.flowScale,this.setUniform("params",n),this.defaultSetup(),this.dispatch=[Math.ceil(e.w/8),Math.ceil(e.h/8),1]}};var Kt=\`// Flow-gated temporal stabilizer (f32). See stabilize_f16.wgsl for the math.
|
|
721
|
+
|
|
722
|
+
struct Params {
|
|
723
|
+
h : u32,
|
|
724
|
+
w : u32,
|
|
725
|
+
t_lo : f32,
|
|
726
|
+
t_hi : f32,
|
|
727
|
+
leak : f32,
|
|
728
|
+
release : f32,
|
|
729
|
+
t_div : f32,
|
|
730
|
+
div_scale: f32,
|
|
731
|
+
step_x : u32,
|
|
732
|
+
step_y : u32,
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
@group(0) @binding(0) var<storage, read> flow_buf : array<vec4<f32>>;
|
|
736
|
+
@group(0) @binding(1) var<storage, read> pred_buf : array<vec4<f32>>;
|
|
737
|
+
@group(0) @binding(2) var<storage, read> ref_buf : array<vec4<f32>>;
|
|
738
|
+
@group(0) @binding(3) var<storage, read> env_prev_buf : array<vec4<f32>>;
|
|
739
|
+
@group(0) @binding(4) var<uniform> params : Params;
|
|
740
|
+
@group(0) @binding(5) var<storage, read_write> output_buf : array<vec4<f32>>;
|
|
741
|
+
|
|
742
|
+
@compute @workgroup_size(8, 8, 1)
|
|
743
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
744
|
+
let x = gid.x;
|
|
745
|
+
let y = gid.y;
|
|
746
|
+
if (x >= params.w || y >= params.h) { return; }
|
|
747
|
+
let idx = y * params.w + x;
|
|
748
|
+
|
|
749
|
+
let mag = length(flow_buf[idx].xy);
|
|
750
|
+
let env_prev = env_prev_buf[idx].y;
|
|
751
|
+
let env = max(mag, params.release * env_prev);
|
|
752
|
+
|
|
753
|
+
let xr = min(x + params.step_x, params.w - 1u);
|
|
754
|
+
let xl = select(x - params.step_x, 0u, x < params.step_x);
|
|
755
|
+
let yd = min(y + params.step_y, params.h - 1u);
|
|
756
|
+
let yu = select(y - params.step_y, 0u, y < params.step_y);
|
|
757
|
+
let dfx = flow_buf[y * params.w + xr].x - flow_buf[y * params.w + xl].x;
|
|
758
|
+
let dfy = flow_buf[yd * params.w + x].y - flow_buf[yu * params.w + x].y;
|
|
759
|
+
let divg = abs(dfx + dfy);
|
|
760
|
+
|
|
761
|
+
let g_mag = clamp((env - params.t_lo) / max(params.t_hi - params.t_lo, 1e-3), 0.0, 1.0);
|
|
762
|
+
let g_div = clamp((divg - params.t_div) / max(params.div_scale, 1e-3), 0.0, 1.0);
|
|
763
|
+
let g = max(max(g_mag, g_div), params.leak);
|
|
764
|
+
|
|
765
|
+
let pred = pred_buf[idx].x;
|
|
766
|
+
let refv = ref_buf[idx].x;
|
|
767
|
+
let stab = g * pred + (1.0 - g) * refv;
|
|
768
|
+
|
|
769
|
+
output_buf[idx] = vec4<f32>(stab, env, 0.0, 0.0);
|
|
770
|
+
}
|
|
771
|
+
\`;var Yt=\`enable f16;
|
|
772
|
+
|
|
773
|
+
// Flow-gated temporal stabilizer (f16 storage, f32 gate math). Per pixel:
|
|
774
|
+
// env = max(|flow.xy|, release\\xB7envPrev.y) peak-hold (fast attack, slow release)
|
|
775
|
+
// div = |\\u2202fx/\\u2202x + \\u2202fy/\\u2202y| flow divergence (occlusion seam)
|
|
776
|
+
// g = max(clamp((env-tLo)/(tHi-tLo),0,1), clamp((div-tDiv)/divScale,0,1), leak)
|
|
777
|
+
// out = vec4((g\\xB7pred + (1-g)\\xB7ref).x, env, 0, 0)
|
|
778
|
+
// The divergence term opens the gate at occlusion/disocclusion boundaries (where
|
|
779
|
+
// the flow tears but the revealed-background magnitude is ~0). Finite-difference
|
|
780
|
+
// step spans ~1 base/4 pixel. alpha is in .x of pred/ref; env threads via .y.
|
|
781
|
+
|
|
782
|
+
struct Params {
|
|
783
|
+
h : u32,
|
|
784
|
+
w : u32,
|
|
785
|
+
t_lo : f32,
|
|
786
|
+
t_hi : f32,
|
|
787
|
+
leak : f32,
|
|
788
|
+
release : f32,
|
|
789
|
+
t_div : f32,
|
|
790
|
+
div_scale: f32,
|
|
791
|
+
step_x : u32,
|
|
792
|
+
step_y : u32,
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
@group(0) @binding(0) var<storage, read> flow_buf : array<vec4<f16>>;
|
|
796
|
+
@group(0) @binding(1) var<storage, read> pred_buf : array<vec4<f16>>;
|
|
797
|
+
@group(0) @binding(2) var<storage, read> ref_buf : array<vec4<f16>>;
|
|
798
|
+
@group(0) @binding(3) var<storage, read> env_prev_buf : array<vec4<f16>>;
|
|
799
|
+
@group(0) @binding(4) var<uniform> params : Params;
|
|
800
|
+
@group(0) @binding(5) var<storage, read_write> output_buf : array<vec4<f16>>;
|
|
801
|
+
|
|
802
|
+
@compute @workgroup_size(8, 8, 1)
|
|
803
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
804
|
+
let x = gid.x;
|
|
805
|
+
let y = gid.y;
|
|
806
|
+
if (x >= params.w || y >= params.h) { return; }
|
|
807
|
+
let idx = y * params.w + x;
|
|
808
|
+
|
|
809
|
+
let mag = length(vec2<f32>(flow_buf[idx].xy));
|
|
810
|
+
let env_prev = f32(env_prev_buf[idx].y);
|
|
811
|
+
let env = max(mag, params.release * env_prev);
|
|
812
|
+
|
|
813
|
+
// Flow divergence over a \\xB1step finite-difference (clamped to the edges).
|
|
814
|
+
let xr = min(x + params.step_x, params.w - 1u);
|
|
815
|
+
let xl = select(x - params.step_x, 0u, x < params.step_x);
|
|
816
|
+
let yd = min(y + params.step_y, params.h - 1u);
|
|
817
|
+
let yu = select(y - params.step_y, 0u, y < params.step_y);
|
|
818
|
+
let dfx = f32(flow_buf[y * params.w + xr].x) - f32(flow_buf[y * params.w + xl].x);
|
|
819
|
+
let dfy = f32(flow_buf[yd * params.w + x].y) - f32(flow_buf[yu * params.w + x].y);
|
|
820
|
+
let divg = abs(dfx + dfy);
|
|
821
|
+
|
|
822
|
+
let g_mag = clamp((env - params.t_lo) / max(params.t_hi - params.t_lo, 1e-3), 0.0, 1.0);
|
|
823
|
+
let g_div = clamp((divg - params.t_div) / max(params.div_scale, 1e-3), 0.0, 1.0);
|
|
824
|
+
let g = max(max(g_mag, g_div), params.leak);
|
|
825
|
+
|
|
826
|
+
let pred = f32(pred_buf[idx].x);
|
|
827
|
+
let refv = f32(ref_buf[idx].x);
|
|
828
|
+
let stab = g * pred + (1.0 - g) * refv;
|
|
829
|
+
|
|
830
|
+
output_buf[idx] = vec4<f16>(f16(stab), f16(env), 0.0h, 0.0h);
|
|
831
|
+
}
|
|
832
|
+
\`;var be=class extends f{constructor(r,e,i,o,n,s){super(r);a(this,"inputs");a(this,"weights",[]);a(this,"output");a(this,"dispatch");a(this,"shader");this.shader=r.dtype==="f16"?Yt:Kt,this.output=r.tensor(e.h,e.w,4),this.inputs=[e,i,o,n],this.createUniform("params","Params");let p=new Uint32Array(10);p[0]=e.h,p[1]=e.w;let l=new Float32Array(p.buffer);l[2]=s.tLo,l[3]=s.tHi,l[4]=s.leak,l[5]=s.release,l[6]=s.tDiv,l[7]=s.divScale,p[8]=s.stepX,p[9]=s.stepY,this.setUniform("params",p),this.defaultSetup(),this.dispatch=[Math.ceil(e.w/8),Math.ceil(e.h/8),1]}};var Qt=\`// Bilinear upsample (arbitrary ratio), align_corners=False (matches PyTorch default).
|
|
506
833
|
// Input/output in NHWC vec4 format: index = y*W*(C/4) + x*(C/4) + c_group.
|
|
507
834
|
// Each thread computes one output pixel for one channel group (vec4 = 4 channels).
|
|
508
835
|
|
|
@@ -560,7 +887,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
560
887
|
|
|
561
888
|
output_buf[oy * params.out_w * C + ox * C + c] = result;
|
|
562
889
|
}
|
|
563
|
-
\`;var
|
|
890
|
+
\`;var Jt=\`enable f16;
|
|
564
891
|
|
|
565
892
|
// Bilinear upsample 2\\xD7 \\u2014 full f16 variant.
|
|
566
893
|
// Interpolation weights (wx, wy) and intermediate blends computed in f32 for
|
|
@@ -616,7 +943,53 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
616
943
|
|
|
617
944
|
output_buf[oy * params.out_w * C + ox * C + c] = vec4<f16>(result);
|
|
618
945
|
}
|
|
619
|
-
\`;var
|
|
946
|
+
\`;var ve=class extends f{constructor(r,e,i){super(r);a(this,"inputs");a(this,"weights",[]);a(this,"output");a(this,"dispatch");a(this,"shader");this.shader=r.dtype==="f16"?Jt:Qt;let o=e.c/4;this.output=r.tensor(i.outH,i.outW,e.c),this.inputs=[e],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,i.outH,i.outW,o,0,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(i.outW/8),Math.ceil(i.outH/8),o]}};var Zt=\`// Top-left crop (f32). See crop_f16.wgsl.
|
|
947
|
+
|
|
948
|
+
struct Params {
|
|
949
|
+
in_w : u32,
|
|
950
|
+
out_h : u32,
|
|
951
|
+
out_w : u32,
|
|
952
|
+
groups : u32,
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
@group(0) @binding(0) var<storage, read> input_buf : array<vec4<f32>>;
|
|
956
|
+
@group(0) @binding(1) var<uniform> params : Params;
|
|
957
|
+
@group(0) @binding(2) var<storage, read_write> output_buf : array<vec4<f32>>;
|
|
958
|
+
|
|
959
|
+
@compute @workgroup_size(8, 8, 1)
|
|
960
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
961
|
+
let x = gid.x;
|
|
962
|
+
let y = gid.y;
|
|
963
|
+
let g = gid.z;
|
|
964
|
+
if (x >= params.out_w || y >= params.out_h || g >= params.groups) { return; }
|
|
965
|
+
let G = params.groups;
|
|
966
|
+
output_buf[y * params.out_w * G + x * G + g] = input_buf[y * params.in_w * G + x * G + g];
|
|
967
|
+
}
|
|
968
|
+
\`;var er=\`enable f16;
|
|
969
|
+
|
|
970
|
+
// Top-left crop: output[y,x,g] = input[y,x,g] for y<outH, x<outW (training crop_like).
|
|
971
|
+
|
|
972
|
+
struct Params {
|
|
973
|
+
in_w : u32,
|
|
974
|
+
out_h : u32,
|
|
975
|
+
out_w : u32,
|
|
976
|
+
groups : u32,
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
@group(0) @binding(0) var<storage, read> input_buf : array<vec4<f16>>;
|
|
980
|
+
@group(0) @binding(1) var<uniform> params : Params;
|
|
981
|
+
@group(0) @binding(2) var<storage, read_write> output_buf : array<vec4<f16>>;
|
|
982
|
+
|
|
983
|
+
@compute @workgroup_size(8, 8, 1)
|
|
984
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
985
|
+
let x = gid.x;
|
|
986
|
+
let y = gid.y;
|
|
987
|
+
let g = gid.z;
|
|
988
|
+
if (x >= params.out_w || y >= params.out_h || g >= params.groups) { return; }
|
|
989
|
+
let G = params.groups;
|
|
990
|
+
output_buf[y * params.out_w * G + x * G + g] = input_buf[y * params.in_w * G + x * G + g];
|
|
991
|
+
}
|
|
992
|
+
\`;var xe=class extends f{constructor(r,e,i){super(r);a(this,"inputs");a(this,"weights",[]);a(this,"output");a(this,"dispatch");a(this,"shader");this.shader=r.dtype==="f16"?er:Zt;let o=e.c/4;this.output=r.tensor(i.outH,i.outW,e.c),this.inputs=[e],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.w,i.outH,i.outW,o])),this.defaultSetup(),this.dispatch=[Math.ceil(i.outW/8),Math.ceil(i.outH/8),o]}};var tr=\`// Bicubic upsample (arbitrary scale) \\u2014 Keys cubic, a=-0.75 (PyTorch default
|
|
620
993
|
// for mode='bicubic', align_corners=False). Direct 2D, 4\\xD74 = 16 taps per
|
|
621
994
|
// output pixel. NHWC vec4 layout: index = y*W*(C/4) + x*(C/4) + c_group.
|
|
622
995
|
|
|
@@ -683,7 +1056,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
683
1056
|
|
|
684
1057
|
output_buf[oy * params.out_w * C + ox * C + c] = acc;
|
|
685
1058
|
}
|
|
686
|
-
\`;var
|
|
1059
|
+
\`;var rr=\`enable f16;
|
|
687
1060
|
|
|
688
1061
|
// Bicubic upsample \\u2014 full f16 storage variant. Bicubic weights and the per-
|
|
689
1062
|
// pixel accumulator are computed in f32 (cheap to keep precision around the
|
|
@@ -752,7 +1125,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
752
1125
|
|
|
753
1126
|
output_buf[oy * params.out_w * C + ox * C + c] = vec4<f16>(acc);
|
|
754
1127
|
}
|
|
755
|
-
\`;var
|
|
1128
|
+
\`;var ye=class extends f{constructor(r,e,i){super(r);a(this,"inputs");a(this,"weights",[]);a(this,"output");a(this,"dispatch");a(this,"shader");this.shader=r.dtype==="f16"?rr:tr;let o=e.c/4;this.output=r.tensor(i.outH,i.outW,e.c),this.inputs=[e],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,i.outH,i.outW,o,0,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(i.outW/8),Math.ceil(i.outH/8),o]}};var or=\`// Channel concatenation: output = cat(A, B, dim=channel).
|
|
756
1129
|
// Both A and B must share the same H\\xD7W and be in NHWC vec4 format.
|
|
757
1130
|
// Output layout: for each (y, x), the first a_groups vec4s come from A,
|
|
758
1131
|
// followed by b_groups vec4s from B.
|
|
@@ -797,7 +1170,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
797
1170
|
output_buf[out_idx] = input_b[y * W * Bg + x * Bg + c_b];
|
|
798
1171
|
}
|
|
799
1172
|
}
|
|
800
|
-
\`;var
|
|
1173
|
+
\`;var ir=\`enable f16;
|
|
801
1174
|
|
|
802
1175
|
// Channel concatenation \\u2014 full f16 variant.
|
|
803
1176
|
|
|
@@ -838,7 +1211,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
838
1211
|
output_buf[out_idx] = input_b[y * W * Bg + x * Bg + c_b];
|
|
839
1212
|
}
|
|
840
1213
|
}
|
|
841
|
-
\`;var
|
|
1214
|
+
\`;var we=class extends f{constructor(r,e,i){super(r);a(this,"inputs");a(this,"weights",[]);a(this,"output");a(this,"dispatch");a(this,"shader");this.shader=r.dtype==="f16"?ir:or;let o=e.c/4,n=i.c/4,s=o+n;this.output=r.tensor(e.h,e.w,e.c+i.c),this.inputs=[e,i],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,o,n,s,0,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(e.w/8),Math.ceil(e.h/8),s]}};var ar=\`// Conv2d + skip add fused.
|
|
842
1215
|
// Identical to conv2d.wgsl except skip is an activation input (binding 1),
|
|
843
1216
|
// added element-wise to the conv result at write time.
|
|
844
1217
|
// Eliminates the separate add dispatch and its intermediate buffer round-trip.
|
|
@@ -912,7 +1285,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
912
1285
|
let out_idx = y * params.out_w * O + x * O + o;
|
|
913
1286
|
output_buf[out_idx] = result + skip_buf[out_idx];
|
|
914
1287
|
}
|
|
915
|
-
\`;var
|
|
1288
|
+
\`;var nr=\`enable f16;
|
|
916
1289
|
|
|
917
1290
|
// Conv2d + skip add fused \\u2014 full f16 variant.
|
|
918
1291
|
|
|
@@ -986,7 +1359,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
986
1359
|
let out_idx = y * params.out_w * O + x * O + o;
|
|
987
1360
|
output_buf[out_idx] = result + skip_buf[out_idx];
|
|
988
1361
|
}
|
|
989
|
-
\`;var
|
|
1362
|
+
\`;var ke=class extends f{constructor(r,e,i,o,n){super(r);a(this,"inputs");a(this,"weights");a(this,"output");a(this,"dispatch");a(this,"shader");this.shader=r.dtype==="f16"?nr:ar;let s=T(e.h,n.kernel,n.stride,n.padding),p=T(e.w,n.kernel,n.stride,n.padding),l=e.c/4,c=n.outChannels/4,d=C(n.padding,e.h,s,n.kernel,n.stride),_=C(n.padding,e.w,p,n.kernel,n.stride);this.output=r.tensor(s,p,n.outChannels),this.inputs=[e,i],this.weights=[r.upload(m(o.weights)),r.upload(m(o.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,s,p,l,c,n.kernel,n.kernel,n.stride,d,_,n.activation==="relu6"?1:0])),this.defaultSetup(),this.dispatch=[Math.ceil(p/8),Math.ceil(s/8),c]}};var sr=\`// proj_residual: bespoke 1\\xD71 conv (no activation) + residual add, fused.
|
|
990
1363
|
// Specializes conv2d_add to kernel=1 / stride=1 / pad=0 / no activation: drops
|
|
991
1364
|
// the kernel loop, the padding checks, and the activation branch. Used by the
|
|
992
1365
|
// MBConv project+residual tail. Both inputs share the same spatial resolution.
|
|
@@ -1031,7 +1404,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1031
1404
|
|
|
1032
1405
|
output_buf[pix * O + o] = result;
|
|
1033
1406
|
}
|
|
1034
|
-
\`;var
|
|
1407
|
+
\`;var ur=\`enable f16;
|
|
1035
1408
|
|
|
1036
1409
|
// proj_residual \\u2014 full f16 variant. See proj_residual.wgsl for layout details.
|
|
1037
1410
|
// Bespoke 1\\xD71 conv (no activation) + residual add, fused.
|
|
@@ -1073,7 +1446,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1073
1446
|
|
|
1074
1447
|
output_buf[pix * O + o] = result;
|
|
1075
1448
|
}
|
|
1076
|
-
\`;var
|
|
1449
|
+
\`;var Te=class extends f{constructor(r,e,i,o,n){super(r);a(this,"inputs");a(this,"weights");a(this,"output");a(this,"dispatch");a(this,"shader");this.shader=r.dtype==="f16"?ur:sr;let s=e.c/4,p=n.outChannels/4;this.output=r.tensor(e.h,e.w,n.outChannels),this.inputs=[e,i],this.weights=[r.upload(m(o.weights)),r.upload(m(o.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,s,p])),this.defaultSetup(),this.dispatch=[Math.ceil(e.w/8),Math.ceil(e.h/8),p]}};var pr=\`// concat_conv2d: fuses [concat(a, b) \\u2192 conv 3\\xD73 (pad 1) \\u2192 relu6] into one
|
|
1077
1450
|
// dispatch. Both inputs are already at the output resolution (the upstream
|
|
1078
1451
|
// upsample stays a separate dispatch writing a clean intermediate, so the conv
|
|
1079
1452
|
// reads are plain-indexed). Identical math to conv2d; the only difference is
|
|
@@ -1133,7 +1506,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1133
1506
|
result = clamp(result, vec4<f32>(0.0), vec4<f32>(6.0));
|
|
1134
1507
|
output_buf[(y * p.w + x) * O + o] = result;
|
|
1135
1508
|
}
|
|
1136
|
-
\`;var
|
|
1509
|
+
\`;var lr=\`enable f16;
|
|
1137
1510
|
|
|
1138
1511
|
// concat_conv2d \\u2014 full f16 variant. See concat_conv2d.wgsl for layout details.
|
|
1139
1512
|
// Fuses [concat(a, b) \\u2192 conv 3\\xD73 (pad 1) \\u2192 relu6] into one dispatch.
|
|
@@ -1188,7 +1561,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1188
1561
|
result = clamp(result, vec4<f16>(0.0h), vec4<f16>(6.0h));
|
|
1189
1562
|
output_buf[(y * p.w + x) * O + o] = result;
|
|
1190
1563
|
}
|
|
1191
|
-
\`;var
|
|
1564
|
+
\`;var Ce=class extends f{constructor(r,e,i,o,n){super(r);a(this,"inputs");a(this,"weights");a(this,"output");a(this,"dispatch");a(this,"shader");this.shader=r.dtype==="f16"?lr:pr;let s=e.c/4,p=i.c/4,l=n.outChannels/4;this.output=r.tensor(e.h,e.w,n.outChannels),this.inputs=[e,i],this.weights=[r.upload(m(o.weights)),r.upload(m(o.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,s,p,l,0,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(e.w/8),Math.ceil(e.h/8),l]}};var cr=\`// gates_fused: ConvGRU z + r gates, fused into one dispatch.
|
|
1192
1565
|
// Production config (c_up=2, split_ratio=0.5 \\u2192 passthrough=1, recurrent=1):
|
|
1193
1566
|
// u_in : c_up=2 packed in a vec4 (.x = passthrough a, .y = recurrent b)
|
|
1194
1567
|
// h_prev : hidden carrier \\u2014 recurrent state in .z (see cand_update_fused: the
|
|
@@ -1233,7 +1606,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1233
1606
|
let r = 1.0 / (1.0 + exp(-r_pre));
|
|
1234
1607
|
output_buf[y * params.w + x] = vec4<f32>(z, r, 0.0, 0.0);
|
|
1235
1608
|
}
|
|
1236
|
-
\`;var
|
|
1609
|
+
\`;var dr=\`enable f16;
|
|
1237
1610
|
|
|
1238
1611
|
// gates_fused \\u2014 full f16 variant. See gates_fused.wgsl for layout details.
|
|
1239
1612
|
// ConvGRU z + r gates (production config c_up=2, recurrent=1).
|
|
@@ -1275,7 +1648,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1275
1648
|
let r = 1.0h / (1.0h + exp(-r_pre));
|
|
1276
1649
|
output_buf[y * params.w + x] = vec4<f16>(z, r, 0.0h, 0.0h);
|
|
1277
1650
|
}
|
|
1278
|
-
\`;var
|
|
1651
|
+
\`;var We=class extends f{constructor(r,e,i,o){super(r);a(this,"inputs");a(this,"weights");a(this,"output");a(this,"dispatch");a(this,"shader");this.shader=r.dtype==="f16"?dr:cr,this.output=r.tensor(e.h,e.w,4),this.inputs=[e,i],this.weights=[r.upload(m(o.weights)),r.upload(y(o.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(e.w/8),Math.ceil(e.h/8),1]}};var mr=\`// cand_update_fused: ConvGRU candidate path + state update + output, fused.
|
|
1279
1652
|
// Production config (c_up=2, recurrent=1):
|
|
1280
1653
|
// u_in : c_up=2 (.x = a passthrough, .y = b recurrent)
|
|
1281
1654
|
// h_prev : hidden carrier \\u2014 recurrent state in .z (the previous frame's
|
|
@@ -1328,7 +1701,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1328
1701
|
let b_out = u_cur.y + gamma_buf[0].x * h_new;
|
|
1329
1702
|
output_buf[cur] = vec4<f32>(u_cur.x, b_out, h_new, 0.0);
|
|
1330
1703
|
}
|
|
1331
|
-
\`;var
|
|
1704
|
+
\`;var fr=\`enable f16;
|
|
1332
1705
|
|
|
1333
1706
|
// cand_update_fused \\u2014 full f16 variant. See cand_update_fused.wgsl for details.
|
|
1334
1707
|
// ConvGRU candidate + state update + output (production config c_up=2, recurrent=1).
|
|
@@ -1374,7 +1747,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1374
1747
|
let b_out = u_cur.y + gamma_buf[0].x * h_new;
|
|
1375
1748
|
output_buf[cur] = vec4<f16>(u_cur.x, b_out, h_new, 0.0h);
|
|
1376
1749
|
}
|
|
1377
|
-
\`;var
|
|
1750
|
+
\`;var Pe=class extends f{constructor(r,e,i,o,n,s){super(r);a(this,"inputs");a(this,"weights");a(this,"output");a(this,"dispatch");a(this,"shader");this.shader=r.dtype==="f16"?fr:mr,this.output=r.tensor(e.h,e.w,4),this.inputs=[e,i,o],this.weights=[r.upload(m(n.weights)),r.upload(y(n.bias)),r.upload(y(s))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(e.w/8),Math.ceil(e.h/8),1]}};var hr=\`// conv_expand: bespoke N\\u21922 conv 3\\xD73 (pad 1) + relu (wrapper expand_feat).
|
|
1378
1751
|
// Expands feat_lr (in_c, mult of 4) to the c_up=2 carrier \\u2014 output .xy = the 2
|
|
1379
1752
|
// native channels, .zw = 0. mat4x2 per (kpos, in_group) with a vec2 accumulator.
|
|
1380
1753
|
// Weight: 9 * in_groups mat4x2 (8 floats each, col-major). Bias .xy.
|
|
@@ -1411,7 +1784,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1411
1784
|
result = max(result, vec2<f32>(0.0)); // expand_feat is F.relu
|
|
1412
1785
|
output_buf[y * params.w + x] = vec4<f32>(result, 0.0, 0.0);
|
|
1413
1786
|
}
|
|
1414
|
-
\`;var
|
|
1787
|
+
\`;var _r=\`enable f16;
|
|
1415
1788
|
|
|
1416
1789
|
// conv_expand \\u2014 full f16 variant. See conv_expand.wgsl for layout details.
|
|
1417
1790
|
// Bespoke N\\u21922 conv 3\\xD73 (pad 1) + relu (wrapper expand_feat).
|
|
@@ -1448,7 +1821,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1448
1821
|
result = max(result, vec2<f16>(0.0h));
|
|
1449
1822
|
output_buf[y * params.w + x] = vec4<f16>(result, 0.0h, 0.0h);
|
|
1450
1823
|
}
|
|
1451
|
-
\`;var
|
|
1824
|
+
\`;var Ge=class extends f{constructor(r,e,i){super(r);a(this,"inputs");a(this,"weights");a(this,"output");a(this,"dispatch");a(this,"shader");this.shader=r.dtype==="f16"?_r:hr;let o=e.c/4;this.output=r.tensor(e.h,e.w,4),this.inputs=[e],this.weights=[r.upload(m(i.weights)),r.upload(y(i.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,o,0])),this.defaultSetup(),this.dispatch=[Math.ceil(e.w/8),Math.ceil(e.h/8),1]}};var gr=\`// cat_conv_6to2: fused concat(u, d) + 6\\u21922 conv 3\\xD73 (pad 1) + relu (E up1_combine).
|
|
1452
1825
|
// u = c_up=2 carrier (.xy); d = c_high=4 (full vec4). Both same resolution.
|
|
1453
1826
|
// Channel order concat([u, d]) = (u.x, u.y, d.x, d.y, d.z, d.w), split into
|
|
1454
1827
|
// v3a = (u.x, u.y, d.x) v3b = d.yzw
|
|
@@ -1488,7 +1861,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1488
1861
|
result = max(result, vec2<f32>(0.0)); // up1_combine is F.relu
|
|
1489
1862
|
output_buf[y * params.w + x] = vec4<f32>(result, 0.0, 0.0);
|
|
1490
1863
|
}
|
|
1491
|
-
\`;var
|
|
1864
|
+
\`;var br=\`enable f16;
|
|
1492
1865
|
|
|
1493
1866
|
// cat_conv_6to2 \\u2014 full f16 variant. See cat_conv_6to2.wgsl for layout details.
|
|
1494
1867
|
// Fused concat(u, d) + 6\\u21922 conv 3\\xD73 (pad 1) + relu (E up1_combine).
|
|
@@ -1527,7 +1900,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1527
1900
|
result = max(result, vec2<f16>(0.0h));
|
|
1528
1901
|
output_buf[y * params.w + x] = vec4<f16>(result, 0.0h, 0.0h);
|
|
1529
1902
|
}
|
|
1530
|
-
\`;var
|
|
1903
|
+
\`;var Be=class extends f{constructor(r,e,i,o){super(r);a(this,"inputs");a(this,"weights");a(this,"output");a(this,"dispatch");a(this,"shader");this.shader=r.dtype==="f16"?br:gr,this.output=r.tensor(e.h,e.w,4),this.inputs=[e,i],this.weights=[r.upload(m(o.weights)),r.upload(y(o.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(e.w/8),Math.ceil(e.h/8),1]}};var vr=\`// down_adapter: fused stride-N 3\\xD73 conv (4\\u21924) + relu + 1\\xD71 adapter (4\\u21923, no
|
|
1531
1904
|
// act) into one dispatch. E variant: down2 (c_high=4 \\u2192 c_low=4, stride 2) +
|
|
1532
1905
|
// adapter. A/B variant: down1 (RGB .xyz \\u2192 4, stride 2/3) + adapter (the down
|
|
1533
1906
|
// weight's 4th input column is zeroed at export for RGB input). Symmetric pad.
|
|
@@ -1575,7 +1948,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1575
1948
|
let adapt_out = adapt_w[0] * down_out + adapt_b[0];
|
|
1576
1949
|
output_buf[y * p.out_w + x] = vec4<f32>(adapt_out.xyz, 0.0);
|
|
1577
1950
|
}
|
|
1578
|
-
\`;var
|
|
1951
|
+
\`;var xr=\`enable f16;
|
|
1579
1952
|
|
|
1580
1953
|
// down_adapter \\u2014 full f16 variant. See down_adapter.wgsl for layout details.
|
|
1581
1954
|
// Fused stride-N 3\\xD73 conv (4\\u21924) + relu + 1\\xD71 adapter (4\\u21923, no act).
|
|
@@ -1620,7 +1993,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1620
1993
|
let adapt_out = adapt_w[0] * down_out + adapt_b[0];
|
|
1621
1994
|
output_buf[y * p.out_w + x] = vec4<f16>(adapt_out.xyz, 0.0h);
|
|
1622
1995
|
}
|
|
1623
|
-
\`;var
|
|
1996
|
+
\`;var Ue=class extends f{constructor(r,e,i,o,n){super(r);a(this,"inputs");a(this,"weights");a(this,"output");a(this,"dispatch");a(this,"shader");this.shader=r.dtype==="f16"?xr:vr;let s=T(e.h,3,n.stride,1),p=T(e.w,3,n.stride,1),l=C(1,e.h,s,3,n.stride),c=C(1,e.w,p,3,n.stride);this.output=r.tensor(s,p,4),this.inputs=[e],this.weights=[r.upload(m(i.weights)),r.upload(y(i.bias)),r.upload(m(o.weights)),r.upload(y(o.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,s,p,n.stride,l,c,0])),this.defaultSetup(),this.dispatch=[Math.ceil(p/8),Math.ceil(s/8),1]}};var yr=\`// up_final: fused concat(u, rgb) \\u2192 conv 3\\xD73 5\\u21921 \\u2192 sigmoid (A/B alpha head).
|
|
1624
1997
|
// u = c_up=2 carrier (.xy); rgb = x_hr (.xyz). 5 inputs \\u2192 1 alpha (output .x).
|
|
1625
1998
|
// Weight: 18 vec4 \\u2014 [0..8] = (w0, w1, 0, 0) for u per kpos; [9..17] =
|
|
1626
1999
|
// (w2, w3, w4, 0) for rgb per kpos. Bias .x.
|
|
@@ -1654,7 +2027,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1654
2027
|
|
|
1655
2028
|
output_buf[y * params.w + x] = vec4<f32>(1.0 / (1.0 + exp(-acc)), 0.0, 0.0, 0.0);
|
|
1656
2029
|
}
|
|
1657
|
-
\`;var
|
|
2030
|
+
\`;var wr=\`enable f16;
|
|
1658
2031
|
|
|
1659
2032
|
// up_final \\u2014 full f16 variant. See up_final.wgsl for layout details.
|
|
1660
2033
|
// Fused concat(u, rgb) \\u2192 conv 3\\xD73 5\\u21921 \\u2192 sigmoid (A/B alpha head).
|
|
@@ -1688,7 +2061,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1688
2061
|
|
|
1689
2062
|
output_buf[y * params.w + x] = vec4<f16>(1.0h / (1.0h + exp(-acc)), 0.0h, 0.0h, 0.0h);
|
|
1690
2063
|
}
|
|
1691
|
-
\`;var
|
|
2064
|
+
\`;var Se=class extends f{constructor(r,e,i,o){super(r);a(this,"inputs");a(this,"weights");a(this,"output");a(this,"dispatch");a(this,"shader");this.shader=r.dtype==="f16"?wr:yr,this.output=r.tensor(e.h,e.w,4),this.inputs=[e,i],this.weights=[r.upload(m(o.weights)),r.upload(y(o.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(e.w/8),Math.ceil(e.h/8),1]}};var kr=\`// up_final_skip: C/D alpha head. Fused concat(u, d_full, rgb) \\u2192 conv 3\\xD73 9\\u21921
|
|
1692
2065
|
// \\u2192 sigmoid. u = c_up=2 (.xy); d_full = c_high=4 full-res skip (full vec4);
|
|
1693
2066
|
// rgb = x_hr (.xyz). Channel order concat = 2 + 4 + 3 = 9. Output .x = alpha.
|
|
1694
2067
|
// Weight: 27 vec4 (3 per kpos): [kpos*3+0]=(w0,w1,0,0) u; [kpos*3+1]=(w2..w5)
|
|
@@ -1725,7 +2098,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1725
2098
|
|
|
1726
2099
|
output_buf[y * params.w + x] = vec4<f32>(1.0 / (1.0 + exp(-acc)), 0.0, 0.0, 0.0);
|
|
1727
2100
|
}
|
|
1728
|
-
\`;var
|
|
2101
|
+
\`;var Tr=\`enable f16;
|
|
1729
2102
|
|
|
1730
2103
|
// up_final_skip \\u2014 full f16 variant. See up_final_skip.wgsl for layout details.
|
|
1731
2104
|
// C/D alpha head: fused concat(u, d_full, rgb) \\u2192 conv 3\\xD73 9\\u21921 \\u2192 sigmoid.
|
|
@@ -1761,7 +2134,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1761
2134
|
|
|
1762
2135
|
output_buf[y * params.w + x] = vec4<f16>(1.0h / (1.0h + exp(-acc)), 0.0h, 0.0h, 0.0h);
|
|
1763
2136
|
}
|
|
1764
|
-
\`;var
|
|
2137
|
+
\`;var Le=class extends f{constructor(r,e,i,o,n){super(r);a(this,"inputs");a(this,"weights");a(this,"output");a(this,"dispatch");a(this,"shader");this.shader=r.dtype==="f16"?Tr:kr,this.output=r.tensor(e.h,e.w,4),this.inputs=[e,i,o],this.weights=[r.upload(m(n.weights)),r.upload(y(n.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(e.w/8),Math.ceil(e.h/8),1]}};var Cr=\`// Bilinear upsample + channel concat fused.
|
|
1765
2138
|
// input_a is the decoder tensor at small spatial resolution (in_h \\xD7 in_w).
|
|
1766
2139
|
// input_b is the encoder skip feature already at output resolution (out_h \\xD7 out_w).
|
|
1767
2140
|
// For output channels 0..a_groups-1: bilinearly interpolate from input_a.
|
|
@@ -1822,7 +2195,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1822
2195
|
output_buf[out_idx] = input_b[oy * params.out_w * params.b_groups + ox * params.b_groups + c_b];
|
|
1823
2196
|
}
|
|
1824
2197
|
}
|
|
1825
|
-
\`;var
|
|
2198
|
+
\`;var Wr=\`enable f16;
|
|
1826
2199
|
|
|
1827
2200
|
// Bilinear upsample + channel concat fused \\u2014 full f16 variant.
|
|
1828
2201
|
// Bilinear weights (wx, wy) and intermediate blends computed in f32; result cast to f16.
|
|
@@ -1882,7 +2255,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1882
2255
|
output_buf[out_idx] = input_b[oy * params.out_w * params.b_groups + ox * params.b_groups + c_b];
|
|
1883
2256
|
}
|
|
1884
2257
|
}
|
|
1885
|
-
\`;var
|
|
2258
|
+
\`;var Fe=class extends f{constructor(r,e,i,o){super(r);a(this,"inputs");a(this,"weights",[]);a(this,"output");a(this,"dispatch");a(this,"shader");this.shader=r.dtype==="f16"?Wr:Cr;let n=e.c/4,s=i.c/4,p=n+s;this.output=r.tensor(o.outH,o.outW,e.c+i.c),this.inputs=[e,i],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,o.outH,o.outW,n,s,p,0])),this.defaultSetup(),this.dispatch=[Math.ceil(o.outW/8),Math.ceil(o.outH/8),p]}};var Pr=\`// Bilinear upsample + 1\\xD71 pointwise conv fused.
|
|
1886
2259
|
// For each output pixel, bilinearly samples the small input for each in_group,
|
|
1887
2260
|
// immediately applies the 1\\xD71 conv weights, and writes the activated result.
|
|
1888
2261
|
// Eliminates the intermediate full-resolution upsample buffer.
|
|
@@ -1949,7 +2322,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1949
2322
|
|
|
1950
2323
|
output_buf[oy * params.out_w * params.out_groups + ox * params.out_groups + og] = result;
|
|
1951
2324
|
}
|
|
1952
|
-
\`;var
|
|
2325
|
+
\`;var Gr=\`enable f16;
|
|
1953
2326
|
|
|
1954
2327
|
// Bilinear upsample + 1\\xD71 pointwise conv fused \\u2014 full f16 variant.
|
|
1955
2328
|
// Bilinear weights and intermediate blends computed in f32; conv accumulation in f16.
|
|
@@ -2016,7 +2389,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
2016
2389
|
|
|
2017
2390
|
output_buf[oy * params.out_w * params.out_groups + ox * params.out_groups + og] = result;
|
|
2018
2391
|
}
|
|
2019
|
-
\`;var
|
|
2392
|
+
\`;var Ee=class extends f{constructor(r,e,i,o){super(r);a(this,"inputs");a(this,"weights");a(this,"output");a(this,"dispatch");a(this,"shader");this.shader=r.dtype==="f16"?Gr:Pr;let n=e.c/4,s=o.outChannels/4;this.output=r.tensor(o.outH,o.outW,o.outChannels),this.inputs=[e],this.weights=[r.upload(m(i.weights)),r.upload(m(i.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,o.outH,o.outW,n,s,o.activation==="relu6"?1:0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(o.outW/8),Math.ceil(o.outH/8),s]}};var Br=\`// Bilinear upsample + sigmoid fused.
|
|
2020
2393
|
// Identical to bilinear_upsample.wgsl except sigmoid is applied at write time.
|
|
2021
2394
|
// Eliminates the intermediate full-resolution buffer and the separate sigmoid dispatch.
|
|
2022
2395
|
|
|
@@ -2070,7 +2443,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
2070
2443
|
|
|
2071
2444
|
output_buf[oy * params.out_w * C + ox * C + c] = 1.0 / (1.0 + exp(-result));
|
|
2072
2445
|
}
|
|
2073
|
-
\`;var
|
|
2446
|
+
\`;var Ur=\`enable f16;
|
|
2074
2447
|
|
|
2075
2448
|
// Bilinear upsample + sigmoid fused \\u2014 full f16 variant.
|
|
2076
2449
|
// Interpolation computed in f32 for accuracy; sigmoid and result cast to f16.
|
|
@@ -2125,7 +2498,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
2125
2498
|
|
|
2126
2499
|
output_buf[oy * params.out_w * C + ox * C + c] = vec4<f16>(1.0 / (1.0 + exp(-result)));
|
|
2127
2500
|
}
|
|
2128
|
-
\`;var
|
|
2501
|
+
\`;var De=class extends f{constructor(r,e,i){super(r);a(this,"inputs");a(this,"weights",[]);a(this,"output");a(this,"dispatch");a(this,"shader");this.shader=r.dtype==="f16"?Ur:Br;let o=e.c/4;this.output=r.tensor(i.outH,i.outW,e.c),this.inputs=[e],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,i.outH,i.outW,o,0,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(i.outW/8),Math.ceil(i.outH/8),o]}};var Sr=\`// Composite an RGBA image over a solid background, gated by a 1-ch alpha.
|
|
2129
2502
|
// Fragment writes the canvas's swapchain texture (premultiplied output).
|
|
2130
2503
|
//
|
|
2131
2504
|
// Caller invariants (matched in CompositeSolidWebGPU):
|
|
@@ -2170,7 +2543,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
2170
2543
|
let rgb = fg * a + params.bgColor.rgb * (1.0 - a);
|
|
2171
2544
|
return vec4<f32>(rgb, 1.0);
|
|
2172
2545
|
}
|
|
2173
|
-
\`;var
|
|
2546
|
+
\`;var Lr=\`enable f16;
|
|
2174
2547
|
|
|
2175
2548
|
// Composite an RGBA image over a solid background, gated by a 1-ch alpha.
|
|
2176
2549
|
// f16 variant: image and alpha are stored as f16; values promote to f32 on
|
|
@@ -2219,7 +2592,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
2219
2592
|
let rgb = fg * a + params.bgColor.rgb * (1.0 - a);
|
|
2220
2593
|
return vec4<f32>(rgb, 1.0);
|
|
2221
2594
|
}
|
|
2222
|
-
\`;var
|
|
2595
|
+
\`;var Oe=class{constructor(t,r,e,i){a(this,"backend",t);a(this,"pipeline");a(this,"bindGroup");a(this,"uniformBuffer");a(this,"outputView",null);if(r.h!==e.h||r.w!==e.w)throw new Error(\`CompositeSolid: image (\${r.h}\\xD7\${r.w}) and alpha (\${e.h}\\xD7\${e.w}) must match. Run the upscaler first.\`);let o=t.device;this.uniformBuffer=o.createBuffer({size:32,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});let n=new ArrayBuffer(32);new Uint32Array(n,0,1)[0]=r.w,new Float32Array(n,16,4).set([i[0],i[1],i[2],0]),o.queue.writeBuffer(this.uniformBuffer,0,n);let s=t.dtype==="f16"?Lr:Sr,p=o.createShaderModule({code:s});this.pipeline=o.createRenderPipeline({layout:"auto",vertex:{module:p,entryPoint:"vs"},fragment:{module:p,entryPoint:"fs",targets:[{format:t.canvasFormat}]},primitive:{topology:"triangle-list"}}),this.bindGroup=o.createBindGroup({layout:this.pipeline.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:r.buffer}},{binding:1,resource:{buffer:e.buffer}},{binding:2,resource:{buffer:this.uniformBuffer}}]})}setOutput(t){this.outputView=t.createView()}run(){if(!this.outputView)throw new Error("CompositeSolidWebGPU.run() called before setOutput()");let t=this.backend.device.createCommandEncoder(),r=t.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([t.finish()]),this.outputView=null}};var Fr=\`// Like composite_solid but bg is an NHWC vec4 storage buffer (e.g. virtual
|
|
2223
2596
|
// background image, or a blurred copy of the input).
|
|
2224
2597
|
|
|
2225
2598
|
struct VertexOut {
|
|
@@ -2261,7 +2634,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
2261
2634
|
let rgb = fg * a + bgc * (1.0 - a);
|
|
2262
2635
|
return vec4<f32>(rgb, 1.0);
|
|
2263
2636
|
}
|
|
2264
|
-
\`;var
|
|
2637
|
+
\`;var Er=\`enable f16;
|
|
2265
2638
|
|
|
2266
2639
|
// Like composite_solid_f16 but bg is an NHWC vec4<f16> storage buffer (e.g. a
|
|
2267
2640
|
// virtual background image, or a blurred copy of the input).
|
|
@@ -2305,7 +2678,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
2305
2678
|
let rgb = fg * a + bgc * (1.0 - a);
|
|
2306
2679
|
return vec4<f32>(rgb, 1.0);
|
|
2307
2680
|
}
|
|
2308
|
-
\`;var
|
|
2681
|
+
\`;var Ie=class{constructor(t,r,e,i){a(this,"backend",t);a(this,"pipeline");a(this,"bindGroup");a(this,"uniformBuffer");a(this,"outputView",null);if(r.h!==e.h||r.w!==e.w||r.h!==i.h||r.w!==i.w)throw new Error(\`CompositeImage: image (\${r.h}\\xD7\${r.w}), alpha (\${e.h}\\xD7\${e.w}), and bg (\${i.h}\\xD7\${i.w}) must all match. Run upscaler / resizer first.\`);let o=t.device;this.uniformBuffer=o.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});let n=new ArrayBuffer(16);new Uint32Array(n,0,1)[0]=r.w,o.queue.writeBuffer(this.uniformBuffer,0,n);let s=t.dtype==="f16"?Er:Fr,p=o.createShaderModule({code:s});this.pipeline=o.createRenderPipeline({layout:"auto",vertex:{module:p,entryPoint:"vs"},fragment:{module:p,entryPoint:"fs",targets:[{format:t.canvasFormat}]},primitive:{topology:"triangle-list"}}),this.bindGroup=o.createBindGroup({layout:this.pipeline.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:r.buffer}},{binding:1,resource:{buffer:e.buffer}},{binding:2,resource:{buffer:this.uniformBuffer}},{binding:3,resource:{buffer:i.buffer}}]})}setOutput(t){this.outputView=t.createView()}run(){if(!this.outputView)throw new Error("CompositeImageWebGPU.run() called before setOutput()");let t=this.backend.device.createCommandEncoder(),r=t.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([t.finish()]),this.outputView=null}};var Dr=\`// Like composite_image but bg is sampled bilinearly \\u2014 bg may be smaller than
|
|
2309
2682
|
// (image, alpha). Used by CompositorBlur to skip the final full-res upsample
|
|
2310
2683
|
// in the blur pyramid and let this shader's own per-pixel scan do the
|
|
2311
2684
|
// expansion (the work is already happening here for the composite anyway).
|
|
@@ -2370,7 +2743,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
2370
2743
|
let rgb = fg * a + bgc * (1.0 - a);
|
|
2371
2744
|
return vec4<f32>(rgb, 1.0);
|
|
2372
2745
|
}
|
|
2373
|
-
\`;var
|
|
2746
|
+
\`;var Or=\`enable f16;
|
|
2374
2747
|
|
|
2375
2748
|
// f16 storage variant of composite_image_bilinear. bg is at a smaller
|
|
2376
2749
|
// resolution and is bilinearly sampled to match (image, alpha) at full res.
|
|
@@ -2431,7 +2804,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
2431
2804
|
let rgb = fg * a + bgc * (1.0 - a);
|
|
2432
2805
|
return vec4<f32>(rgb, 1.0);
|
|
2433
2806
|
}
|
|
2434
|
-
\`;var
|
|
2807
|
+
\`;var Ae=class{constructor(t,r,e,i){a(this,"backend",t);a(this,"pipeline");a(this,"bindGroup");a(this,"uniformBuffer");a(this,"outputView",null);if(r.h!==e.h||r.w!==e.w)throw new Error(\`CompositeImageBilinear: image (\${r.h}\\xD7\${r.w}) and alpha (\${e.h}\\xD7\${e.w}) must match.\`);let o=t.device;this.uniformBuffer=o.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});let n=new ArrayBuffer(16),s=new Uint32Array(n);s[0]=r.w,s[1]=r.h,s[2]=i.w,s[3]=i.h,o.queue.writeBuffer(this.uniformBuffer,0,n);let p=t.dtype==="f16"?Or:Dr,l=o.createShaderModule({code:p});this.pipeline=o.createRenderPipeline({layout:"auto",vertex:{module:l,entryPoint:"vs"},fragment:{module:l,entryPoint:"fs",targets:[{format:t.canvasFormat}]},primitive:{topology:"triangle-list"}}),this.bindGroup=o.createBindGroup({layout:this.pipeline.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:r.buffer}},{binding:1,resource:{buffer:e.buffer}},{binding:2,resource:{buffer:this.uniformBuffer}},{binding:3,resource:{buffer:i.buffer}}]})}setOutput(t){this.outputView=t.createView()}run(){if(!this.outputView)throw new Error("CompositeImageBilinearWebGPU.run() called before setOutput()");let t=this.backend.device.createCommandEncoder(),r=t.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([t.finish()]),this.outputView=null}};var Ir=\`// Passthrough "compositor" \\u2014 writes the image directly to the canvas
|
|
2435
2808
|
// swapchain texture with no alpha math and no background. Used by RenderOp
|
|
2436
2809
|
// when the renderer is in disabled state, so the output canvas reflects
|
|
2437
2810
|
// the unmodified input frame instead of a stale matted result.
|
|
@@ -2469,7 +2842,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
2469
2842
|
let i = y * params.width + x;
|
|
2470
2843
|
return vec4<f32>(image[i].rgb, 1.0);
|
|
2471
2844
|
}
|
|
2472
|
-
\`;var
|
|
2845
|
+
\`;var Ar=\`enable f16;
|
|
2473
2846
|
|
|
2474
2847
|
// Passthrough "compositor" \\u2014 f16 variant. Image is stored as f16; values
|
|
2475
2848
|
// promote to f32 on read and the fragment writes f32 to the canvas
|
|
@@ -2505,7 +2878,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
2505
2878
|
let i = y * params.width + x;
|
|
2506
2879
|
return vec4<f32>(vec3<f32>(image[i].rgb), 1.0);
|
|
2507
2880
|
}
|
|
2508
|
-
\`;var
|
|
2881
|
+
\`;var Me=class{constructor(t,r){a(this,"backend",t);a(this,"pipeline");a(this,"bindGroup");a(this,"uniformBuffer");a(this,"outputView",null);let e=t.device;this.uniformBuffer=e.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});let i=new ArrayBuffer(16);new Uint32Array(i,0,1)[0]=r.w,e.queue.writeBuffer(this.uniformBuffer,0,i);let o=t.dtype==="f16"?Ar:Ir,n=e.createShaderModule({code:o});this.pipeline=e.createRenderPipeline({layout:"auto",vertex:{module:n,entryPoint:"vs"},fragment:{module:n,entryPoint:"fs",targets:[{format:t.canvasFormat}]},primitive:{topology:"triangle-list"}}),this.bindGroup=e.createBindGroup({layout:this.pipeline.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:r.buffer}},{binding:1,resource:{buffer:this.uniformBuffer}}]})}setOutput(t){this.outputView=t.createView()}run(){if(!this.outputView)throw new Error("CompositePassthroughWebGPU.run() called before setOutput()");let t=this.backend.device.createCommandEncoder(),r=t.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([t.finish()]),this.outputView=null}};var Mr=\`// Input op \\u2014 sample a regular 2D source texture (RGBA8 unorm) into the NHWC
|
|
2509
2882
|
// vec4<f32> output buffer at the target resolution. Used for ImageBitmap
|
|
2510
2883
|
// sources, which are uploaded into a persistent staging texture via
|
|
2511
2884
|
// copyExternalImageToTexture before each dispatch.
|
|
@@ -2535,7 +2908,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
2535
2908
|
let rgba = textureSampleLevel(src_tex, src_sampler, uv, 0.0);
|
|
2536
2909
|
output_buf[y * params.out_w + x] = rgba;
|
|
2537
2910
|
}
|
|
2538
|
-
\`;var
|
|
2911
|
+
\`;var Rr=\`enable f16;
|
|
2539
2912
|
|
|
2540
2913
|
// Input op \\u2014 f16 storage variant. Source is sampled as vec4<f32>; only the
|
|
2541
2914
|
// store is demoted to vec4<f16>.
|
|
@@ -2565,7 +2938,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
2565
2938
|
let rgba = textureSampleLevel(src_tex, src_sampler, uv, 0.0);
|
|
2566
2939
|
output_buf[y * params.out_w + x] = vec4<f16>(rgba);
|
|
2567
2940
|
}
|
|
2568
|
-
\`;var
|
|
2941
|
+
\`;var Hr=\`// Input op \\u2014 sample a GPUExternalTexture (zero-copy VideoFrame import) into
|
|
2569
2942
|
// the NHWC vec4<f32> output buffer at the target resolution. Used when the
|
|
2570
2943
|
// caller passes a VideoFrame to setSource(); requires importExternalTexture
|
|
2571
2944
|
// to be called in the same task as the dispatch (the texture is invalidated
|
|
@@ -2596,7 +2969,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
2596
2969
|
let rgba = textureSampleBaseClampToEdge(src_tex, src_sampler, uv);
|
|
2597
2970
|
output_buf[y * params.out_w + x] = rgba;
|
|
2598
2971
|
}
|
|
2599
|
-
\`;var
|
|
2972
|
+
\`;var zr=\`enable f16;
|
|
2600
2973
|
|
|
2601
2974
|
// Input op \\u2014 texture_external + f16 storage. Sample in f32, store as f16.
|
|
2602
2975
|
|
|
@@ -2625,12 +2998,12 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
2625
2998
|
let rgba = textureSampleBaseClampToEdge(src_tex, src_sampler, uv);
|
|
2626
2999
|
output_buf[y * params.out_w + x] = vec4<f16>(rgba);
|
|
2627
3000
|
}
|
|
2628
|
-
\`;var
|
|
3001
|
+
\`;var aa=u=>typeof VideoFrame<"u"&&u instanceof VideoFrame,Re=class{constructor(t,r,e){a(this,"output");a(this,"device");a(this,"dtype");a(this,"sampler");a(this,"uniformBuffer");a(this,"dispatch");a(this,"pipeline2d",null);a(this,"pipelineExternal",null);a(this,"stagingTex",null);a(this,"stagingW",0);a(this,"stagingH",0);a(this,"source",null);this.device=t.device,this.dtype=t.dtype,this.output=t.tensor(r,e,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 i=new ArrayBuffer(16);new Uint32Array(i,0,2).set([e,r]),this.device.queue.writeBuffer(this.uniformBuffer,0,i),this.dispatch=[Math.ceil(e/8),Math.ceil(r/8),1],this.pipeline2d=this.buildPipeline(this.dtype==="f16"?Rr:Mr)}setSource(t){this.source=t}run(){if(!this.source)throw new Error("InputWebGPU.run() called before setSource()");aa(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:!1},{texture:this.stagingTex},[t.width,t.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(t){this.pipelineExternal||(this.pipelineExternal=this.buildPipeline(this.dtype==="f16"?zr:Hr));let r=this.device.importExternalTexture({source:t}),e=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,e)}ensureStagingTexture(t,r){this.stagingTex&&this.stagingW===t&&this.stagingH===r||(this.stagingTex?.destroy(),this.stagingTex=this.device.createTexture({size:[t,r,1],format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT}),this.stagingW=t,this.stagingH=r)}buildPipeline(t){let r=this.device.createShaderModule({code:t});return this.device.createComputePipeline({layout:"auto",compute:{module:r,entryPoint:"main"}})}dispatchOnce(t,r){let e=this.device.createCommandEncoder(),i=e.beginComputePass();i.setPipeline(t),i.setBindGroup(0,r),i.dispatchWorkgroups(...this.dispatch),i.end(),this.device.queue.submit([e.finish()])}};var na=navigator.gpu?GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST:0,R=class u{constructor(t,r,e){a(this,"device",t);a(this,"canvas",r);a(this,"dtype",e);a(this,"ops");a(this,"presenters");a(this,"canvasContext");a(this,"canvasFormat");a(this,"bytesPerElement");a(this,"contexts",new Map);this.bytesPerElement=e==="f16"?2:4;let i=r.getContext("webgpu");if(!i)throw new Error("Failed to get WebGPU context from canvas");this.canvasFormat=navigator.gpu.getPreferredCanvasFormat(),this.configureContext(i),this.canvasContext=i,this.contexts.set("main",i),this.ops={Conv2d:(o,n,s)=>new le(this,o,n,s),ConvTranspose2d:(o,n,s)=>new ce(this,o,n,s),DepthwiseConv2d:(o,n,s)=>new de(this,o,n,s),Add:(o,n)=>new me(this,o,n),Sigmoid:o=>new fe(this,o),Tanh:o=>new he(this,o),ElementwiseMul:(o,n)=>new _e(this,o,n),Warp:(o,n,s)=>new ge(this,o,n,s),Stabilize:(o,n,s,p,l)=>new be(this,o,n,s,p,l),BilinearUpsample:(o,n)=>new ve(this,o,n),Crop:(o,n)=>new xe(this,o,n),BicubicUpsample:(o,n)=>new ye(this,o,n),ChannelConcat:(o,n)=>new we(this,o,n),Conv2dAdd:(o,n,s,p)=>new ke(this,o,n,s,p),ProjResidual:(o,n,s,p)=>new Te(this,o,n,s,p),ConcatConv2d:(o,n,s,p)=>new Ce(this,o,n,s,p),GatesFused:(o,n,s)=>new We(this,o,n,s),CandUpdateFused:(o,n,s,p,l)=>new Pe(this,o,n,s,p,l),ConvExpand:(o,n)=>new Ge(this,o,n),CatConv6to2:(o,n,s)=>new Be(this,o,n,s),DownAdapter:(o,n,s,p)=>new Ue(this,o,n,s,p),UpFinal:(o,n,s)=>new Se(this,o,n,s),UpFinalSkip:(o,n,s,p)=>new Le(this,o,n,s,p),UpsampleConcat:(o,n,s)=>new Fe(this,o,n,s),UpsampleConv1x1:(o,n,s)=>new Ee(this,o,n,s),UpsampleSigmoid:(o,n)=>new De(this,o,n),Input:(o,n)=>new Re(this,o,n)},this.presenters={CompositeSolid:(o,n,s,p="main")=>{let l=new Oe(this,o,n,s);return{run:()=>{l.setOutput(this.getCurrentDisplayTexture(p)),l.run()}}},CompositeImage:(o,n,s,p="main")=>{let l=new Ie(this,o,n,s);return{run:()=>{l.setOutput(this.getCurrentDisplayTexture(p)),l.run()}}},CompositeImageBilinear:(o,n,s,p="main")=>{let l=new Ae(this,o,n,s);return{run:()=>{l.setOutput(this.getCurrentDisplayTexture(p)),l.run()}}},CompositePassthrough:(o,n="main")=>{let s=new Me(this,o);return{run:()=>{s.setOutput(this.getCurrentDisplayTexture(n)),s.run()}}}}}configureContext(t){t.configure({device:this.device,format:this.canvasFormat,alphaMode:"premultiplied"})}attachCanvas(t,r){if(t==="main")throw new Error("attachCanvas: 'main' is reserved for the create() canvas");let e=r.getContext("webgpu");if(!e)throw new Error(\`attachCanvas: failed to get WebGPU context for target '\${t}'\`);this.configureContext(e),this.contexts.set(t,e)}static async isAvailable(){return navigator.gpu?await navigator.gpu.requestAdapter()!==null:!1}static async hasF16Support(){if(!navigator.gpu)return!1;let t=await navigator.gpu.requestAdapter();return t?t.features.has("shader-f16"):!1}static async create(t){let r=t.dtype??"f32",e=t.device;if(e){if(r==="f16"&&!e.features.has("shader-f16"))throw new Error("WebGPU dtype='f16' requested but supplied device lacks \`shader-f16\`")}else{let i=await navigator.gpu.requestAdapter();if(!i)throw new Error("WebGPU adapter not available");if(r==="f16"&&!i.features.has("shader-f16"))throw new Error("WebGPU dtype='f16' requested but adapter lacks \`shader-f16\` feature");e=await i.requestDevice({requiredFeatures:r==="f16"?["shader-f16"]:[]})}return new u(e,t.canvas,r)}getCurrentDisplayTexture(t="main"){let r=this.contexts.get(t);if(!r)throw new Error(\`getCurrentDisplayTexture: no canvas attached for target '\${t}'\`);return r.getCurrentTexture()}tensor(t,r,e,i){let n=t*r*e*this.bytesPerElement,s=this.device.createBuffer({size:n,usage:na,mappedAtCreation:i!==void 0});if(i!==void 0){let p=s.getMappedRange();this.writeView(p,i),s.unmap()}return{h:t,w:r,c:e,buffer:s}}upload(t){let e=t.length*this.bytesPerElement,i=this.device.createBuffer({size:e,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,mappedAtCreation:!0});return this.writeView(i.getMappedRange(),t),i.unmap(),{buffer:i}}writeView(t,r){let e=this.dtype==="f16",i=r instanceof Uint16Array;if(e===i){e?new Uint16Array(t).set(r):new Float32Array(t).set(r);return}e?new Uint16Array(t).set(pe(r)):new Float32Array(t).set(A(r))}async readback(t){let r=this.device.createBuffer({size:t.buffer.size,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ}),e=this.device.createCommandEncoder();e.copyBufferToBuffer(t.buffer,0,r,0,t.buffer.size),this.device.queue.submit([e.finish()]),await r.mapAsync(GPUMapMode.READ);let i=r.getMappedRange(),o=this.dtype==="f16"?A(new Uint16Array(i.slice(0))):new Float32Array(i.slice(0));return r.unmap(),r.destroy(),o}copyTensor(t,r){if(t.buffer.size!==r.buffer.size)throw new Error(\`copyTensor: size mismatch (src \${t.buffer.size} vs dst \${r.buffer.size})\`);let e=this.device.createCommandEncoder();e.copyBufferToBuffer(t.buffer,0,r.buffer,0,t.buffer.size),this.device.queue.submit([e.finish()])}async sync(){await this.device.queue.onSubmittedWorkDone()}destroy(){this.device.destroy()}};var sa=\`#version 300 es
|
|
2629
3002
|
const vec2 VERTS[6] = vec2[6](
|
|
2630
3003
|
vec2(-1.0,-1.0), vec2(1.0,-1.0), vec2(-1.0,1.0),
|
|
2631
3004
|
vec2(-1.0,1.0), vec2(1.0,-1.0), vec2(1.0,1.0)
|
|
2632
3005
|
);
|
|
2633
|
-
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }\`,h=class{constructor(t){
|
|
3006
|
+
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }\`,h=class{constructor(t){a(this,"backend",t);a(this,"shader","");a(this,"program");a(this,"samplers",[]);a(this,"uniformInts",{});a(this,"uniformFloats",{})}makeTexture(t,r,e){let i=this.backend.gl,o=this.backend.textureFormat,n=this.backend.toTextureView(t),s=i.createTexture();return i.bindTexture(i.TEXTURE_2D,s),i.texImage2D(i.TEXTURE_2D,0,o.internalFormat,r,e,0,o.format,o.type,n),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_MIN_FILTER,i.NEAREST),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_MAG_FILTER,i.NEAREST),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_WRAP_S,i.CLAMP_TO_EDGE),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_WRAP_T,i.CLAMP_TO_EDGE),s}defaultSetup(){let t=this.backend.gl,r=t.createShader(t.VERTEX_SHADER);t.shaderSource(r,sa),t.compileShader(r);let e=t.createShader(t.FRAGMENT_SHADER);if(t.shaderSource(e,this.shader),t.compileShader(e),!t.getShaderParameter(e,t.COMPILE_STATUS))throw new Error(\`GLSL compile error: \${t.getShaderInfoLog(e)}\`);if(this.program=t.createProgram(),t.attachShader(this.program,r),t.attachShader(this.program,e),t.linkProgram(this.program),!t.getProgramParameter(this.program,t.LINK_STATUS))throw new Error(\`GLSL link error: \${t.getProgramInfoLog(this.program)}\`)}run(){let t=this.backend.gl;t.useProgram(this.program),this.samplers.forEach(({name:r,texture:e},i)=>{t.activeTexture(t.TEXTURE0+i),t.bindTexture(t.TEXTURE_2D,e),t.uniform1i(t.getUniformLocation(this.program,r),i)});for(let[r,e]of Object.entries(this.uniformInts))t.uniform1i(t.getUniformLocation(this.program,r),e);for(let[r,e]of Object.entries(this.uniformFloats))t.uniform1f(t.getUniformLocation(this.program,r),e);t.bindFramebuffer(t.FRAMEBUFFER,this.backend.fbo),t.framebufferTexture2D(t.FRAMEBUFFER,t.COLOR_ATTACHMENT0,t.TEXTURE_2D,this.output.texture,0),t.viewport(0,0,this.dispatch[0],this.dispatch[1]),t.bindVertexArray(null),t.drawArrays(t.TRIANGLES,0,6)}};var Vr=\`#version 300 es
|
|
2634
3007
|
// Conv2d \\u2014 handles all variants: 1\\xD71 (pointwise), 3\\xD73, 5\\xD75, strided, BN-fused.
|
|
2635
3008
|
//
|
|
2636
3009
|
// Tensor layout: NHWC vec4 \\u2014 texture dimensions (W * C/4, H).
|
|
@@ -2663,7 +3036,7 @@ uniform int u_kernel_w;
|
|
|
2663
3036
|
uniform int u_stride;
|
|
2664
3037
|
uniform int u_pad_top;
|
|
2665
3038
|
uniform int u_pad_left;
|
|
2666
|
-
uniform int u_activation; // 0 = none, 1 = relu6, 2 = relu
|
|
3039
|
+
uniform int u_activation; // 0 = none, 1 = relu6, 2 = relu, 3 = leaky(0.1)
|
|
2667
3040
|
|
|
2668
3041
|
out vec4 fragColor;
|
|
2669
3042
|
|
|
@@ -2703,10 +3076,80 @@ void main() {
|
|
|
2703
3076
|
|
|
2704
3077
|
if (u_activation == 1) result = clamp(result, 0.0, 6.0);
|
|
2705
3078
|
else if (u_activation == 2) result = max(result, vec4(0.0));
|
|
3079
|
+
else if (u_activation == 3) result = max(result, 0.1 * result);
|
|
2706
3080
|
|
|
2707
3081
|
fragColor = result;
|
|
2708
3082
|
}
|
|
2709
|
-
\`;var
|
|
3083
|
+
\`;var He=class extends h{constructor(r,e,i,o){super(r);a(this,"inputs");a(this,"weights");a(this,"output");a(this,"dispatch");a(this,"shader",Vr);let n=T(e.h,o.kernel,o.stride,o.padding),s=T(e.w,o.kernel,o.stride,o.padding),p=e.c/4,l=o.outChannels/4,c=C(o.padding,e.h,n,o.kernel,o.stride),d=C(o.padding,e.w,s,o.kernel,o.stride),_=m(i.weights),b=m(i.bias),g=this.makeTexture(_,p*4,o.kernel*o.kernel*l),v=this.makeTexture(b,l,1),x=s*l,k=this.makeTexture(null,x,n);this.output={h:n,w:s,c:o.outChannels,texture:k,texW:x,texH:n},this.inputs=[e],this.weights=[],this.samplers=[{name:"u_input",texture:e.texture},{name:"u_weights",texture:g},{name:"u_bias",texture:v}],this.uniformInts={u_in_w:e.w,u_in_h:e.h,u_in_c_groups:p,u_out_c_groups:l,u_kernel_h:o.kernel,u_kernel_w:o.kernel,u_stride:o.stride,u_pad_top:c,u_pad_left:d,u_activation:o.activation==="relu6"?1:o.activation==="relu"?2:o.activation==="leaky"?3:0},this.defaultSetup(),this.dispatch=[x,n]}};var Nr=\`#version 300 es
|
|
3084
|
+
// ConvTranspose2d \\u2014 gather form. Identical texture layouts + mat4 weight
|
|
3085
|
+
// semantics as conv2d.glsl; only the spatial mapping differs:
|
|
3086
|
+
// in_y = (y_out + pad - ky) / stride (must divide evenly + be in bounds)
|
|
3087
|
+
// No explicit kernel flip \\u2014 the (y_out + pad - ky) indexing carries it.
|
|
3088
|
+
|
|
3089
|
+
precision highp float;
|
|
3090
|
+
precision highp int;
|
|
3091
|
+
|
|
3092
|
+
uniform sampler2D u_input; // (in_W * in_C_groups, in_H)
|
|
3093
|
+
uniform sampler2D u_weights; // (in_C_groups * 4, K\\xB2 * out_C_groups)
|
|
3094
|
+
uniform sampler2D u_bias; // (out_C_groups, 1)
|
|
3095
|
+
|
|
3096
|
+
uniform int u_in_w;
|
|
3097
|
+
uniform int u_in_h;
|
|
3098
|
+
uniform int u_in_c_groups;
|
|
3099
|
+
uniform int u_out_c_groups;
|
|
3100
|
+
uniform int u_kernel_h;
|
|
3101
|
+
uniform int u_kernel_w;
|
|
3102
|
+
uniform int u_stride;
|
|
3103
|
+
uniform int u_pad_top;
|
|
3104
|
+
uniform int u_pad_left;
|
|
3105
|
+
uniform int u_activation; // 0 = none, 1 = relu6, 2 = relu, 3 = leaky(0.1)
|
|
3106
|
+
|
|
3107
|
+
out vec4 fragColor;
|
|
3108
|
+
|
|
3109
|
+
void main() {
|
|
3110
|
+
int fx = int(gl_FragCoord.x);
|
|
3111
|
+
int fy = int(gl_FragCoord.y);
|
|
3112
|
+
int x_out = fx / u_out_c_groups;
|
|
3113
|
+
int y_out = fy;
|
|
3114
|
+
int o_group = fx - x_out * u_out_c_groups;
|
|
3115
|
+
|
|
3116
|
+
vec4 result = texelFetch(u_bias, ivec2(o_group, 0), 0);
|
|
3117
|
+
|
|
3118
|
+
for (int ky = 0; ky < u_kernel_h; ky++) {
|
|
3119
|
+
for (int kx = 0; kx < u_kernel_w; kx++) {
|
|
3120
|
+
int iy_num = y_out + u_pad_top - ky;
|
|
3121
|
+
int ix_num = x_out + u_pad_left - kx;
|
|
3122
|
+
if (iy_num < 0 || ix_num < 0) continue;
|
|
3123
|
+
if ((iy_num % u_stride) != 0 || (ix_num % u_stride) != 0) continue;
|
|
3124
|
+
int in_y = iy_num / u_stride;
|
|
3125
|
+
int in_x = ix_num / u_stride;
|
|
3126
|
+
if (in_y >= u_in_h || in_x >= u_in_w) continue;
|
|
3127
|
+
|
|
3128
|
+
int z = ky * u_kernel_w + kx;
|
|
3129
|
+
int w_row = z * u_out_c_groups + o_group;
|
|
3130
|
+
|
|
3131
|
+
for (int i = 0; i < u_in_c_groups; i++) {
|
|
3132
|
+
vec4 in_val = texelFetch(u_input, ivec2(in_x * u_in_c_groups + i, in_y), 0);
|
|
3133
|
+
|
|
3134
|
+
int base = i * 4;
|
|
3135
|
+
mat4 w = mat4(
|
|
3136
|
+
texelFetch(u_weights, ivec2(base, w_row), 0),
|
|
3137
|
+
texelFetch(u_weights, ivec2(base + 1, w_row), 0),
|
|
3138
|
+
texelFetch(u_weights, ivec2(base + 2, w_row), 0),
|
|
3139
|
+
texelFetch(u_weights, ivec2(base + 3, w_row), 0)
|
|
3140
|
+
);
|
|
3141
|
+
result += w * in_val;
|
|
3142
|
+
}
|
|
3143
|
+
}
|
|
3144
|
+
}
|
|
3145
|
+
|
|
3146
|
+
if (u_activation == 1) result = clamp(result, 0.0, 6.0);
|
|
3147
|
+
else if (u_activation == 2) result = max(result, vec4(0.0));
|
|
3148
|
+
else if (u_activation == 3) result = max(result, 0.1 * result);
|
|
3149
|
+
|
|
3150
|
+
fragColor = result;
|
|
3151
|
+
}
|
|
3152
|
+
\`;var ze=class extends h{constructor(r,e,i,o){super(r);a(this,"inputs");a(this,"weights");a(this,"output");a(this,"dispatch");a(this,"shader",Nr);let n=M(e.h,o.kernel,o.stride,o.padding),s=M(e.w,o.kernel,o.stride,o.padding),p=e.c/4,l=o.outChannels/4,c=m(i.weights),d=m(i.bias),_=this.makeTexture(c,p*4,o.kernel*o.kernel*l),b=this.makeTexture(d,l,1),g=s*l,v=this.makeTexture(null,g,n);this.output={h:n,w:s,c:o.outChannels,texture:v,texW:g,texH:n},this.inputs=[e],this.weights=[],this.samplers=[{name:"u_input",texture:e.texture},{name:"u_weights",texture:_},{name:"u_bias",texture:b}],this.uniformInts={u_in_w:e.w,u_in_h:e.h,u_in_c_groups:p,u_out_c_groups:l,u_kernel_h:o.kernel,u_kernel_w:o.kernel,u_stride:o.stride,u_pad_top:o.padding,u_pad_left:o.padding,u_activation:o.activation==="relu6"?1:o.activation==="relu"?2:o.activation==="leaky"?3:0},this.defaultSetup(),this.dispatch=[g,n]}};var $r=\`#version 300 es
|
|
2710
3153
|
// Depthwise Conv2d \\u2014 groups = in_channels (each channel convolved independently).
|
|
2711
3154
|
//
|
|
2712
3155
|
// Weight layout: (C_groups, K\\xB2) RGBA32F texture \\u2014 contrast with conv2d which uses mat4.
|
|
@@ -2763,7 +3206,7 @@ void main() {
|
|
|
2763
3206
|
|
|
2764
3207
|
fragColor = result;
|
|
2765
3208
|
}
|
|
2766
|
-
\`;var
|
|
3209
|
+
\`;var Ve=class extends h{constructor(r,e,i,o){super(r);a(this,"inputs");a(this,"weights");a(this,"output");a(this,"dispatch");a(this,"shader",$r);let n=T(e.h,o.kernel,o.stride,o.padding),s=T(e.w,o.kernel,o.stride,o.padding),p=e.c/4,l=C(o.padding,e.h,n,o.kernel,o.stride),c=C(o.padding,e.w,s,o.kernel,o.stride),d=m(i.weights),_=m(i.bias),b=this.makeTexture(d,p,o.kernel*o.kernel),g=this.makeTexture(_,p,1),v=s*p,x=this.makeTexture(null,v,n);this.output={h:n,w:s,c:e.c,texture:x,texW:v,texH:n},this.inputs=[e],this.weights=[],this.samplers=[{name:"u_input",texture:e.texture},{name:"u_weights",texture:b},{name:"u_bias",texture:g}],this.uniformInts={u_in_w:e.w,u_in_h:e.h,u_c_groups:p,u_kernel_h:o.kernel,u_kernel_w:o.kernel,u_stride:o.stride,u_pad_top:l,u_pad_left:c,u_apply_relu6:o.activation==="relu6"?1:0},this.defaultSetup(),this.dispatch=[v,n]}};var Xr=\`#version 300 es
|
|
2767
3210
|
// Element-wise add \\u2014 both inputs and output share the same texture dimensions.
|
|
2768
3211
|
// Works for any 2D layout; used here with a flat (nVec4, 1) texture.
|
|
2769
3212
|
|
|
@@ -2778,7 +3221,7 @@ void main() {
|
|
|
2778
3221
|
ivec2 fc = ivec2(gl_FragCoord.xy);
|
|
2779
3222
|
fragColor = texelFetch(u_input_a, fc, 0) + texelFetch(u_input_b, fc, 0);
|
|
2780
3223
|
}
|
|
2781
|
-
\`;var
|
|
3224
|
+
\`;var Ne=class extends h{constructor(r,e,i){super(r);a(this,"inputs");a(this,"weights",[]);a(this,"output");a(this,"dispatch");a(this,"shader",Xr);let o=e,n=this.makeTexture(null,o.texW,o.texH);this.output={h:e.h,w:e.w,c:e.c,texture:n,texW:o.texW,texH:o.texH},this.inputs=[e,i],this.samplers=[{name:"u_input_a",texture:e.texture},{name:"u_input_b",texture:i.texture}],this.defaultSetup(),this.dispatch=[o.texW,o.texH]}};var jr=\`#version 300 es
|
|
2782
3225
|
// Element-wise sigmoid \\u2014 works on any texture layout (flat or spatial).
|
|
2783
3226
|
|
|
2784
3227
|
precision highp float;
|
|
@@ -2791,7 +3234,7 @@ void main() {
|
|
|
2791
3234
|
vec4 x = texelFetch(u_input, ivec2(gl_FragCoord.xy), 0);
|
|
2792
3235
|
fragColor = 1.0 / (1.0 + exp(-x));
|
|
2793
3236
|
}
|
|
2794
|
-
\`;var
|
|
3237
|
+
\`;var $e=class extends h{constructor(r,e){super(r);a(this,"inputs");a(this,"weights",[]);a(this,"output");a(this,"dispatch");a(this,"shader",jr);let i=e,o=this.makeTexture(null,i.texW,i.texH);this.output={h:e.h,w:e.w,c:e.c,texture:o,texW:i.texW,texH:i.texH},this.inputs=[e],this.samplers=[{name:"u_input",texture:i.texture}],this.defaultSetup(),this.dispatch=[i.texW,i.texH]}};var qr=\`#version 300 es
|
|
2795
3238
|
// Element-wise tanh \\u2014 used by ConvGRU candidate activation.
|
|
2796
3239
|
// Layout-agnostic (flat or spatial); GLSL tanh is element-wise on vec4.
|
|
2797
3240
|
|
|
@@ -2804,7 +3247,7 @@ out vec4 fragColor;
|
|
|
2804
3247
|
void main() {
|
|
2805
3248
|
fragColor = tanh(texelFetch(u_input, ivec2(gl_FragCoord.xy), 0));
|
|
2806
3249
|
}
|
|
2807
|
-
\`;var
|
|
3250
|
+
\`;var Xe=class extends h{constructor(r,e){super(r);a(this,"inputs");a(this,"weights",[]);a(this,"output");a(this,"dispatch");a(this,"shader",qr);let i=e,o=this.makeTexture(null,i.texW,i.texH);this.output={h:e.h,w:e.w,c:e.c,texture:o,texW:i.texW,texH:i.texH},this.inputs=[e],this.samplers=[{name:"u_input",texture:i.texture}],this.defaultSetup(),this.dispatch=[i.texW,i.texH]}};var Kr=\`#version 300 es
|
|
2808
3251
|
// Element-wise multiply \\u2014 used in ConvGRU for r \\u2299 h_prev.
|
|
2809
3252
|
// Same shape constraint as add.glsl.
|
|
2810
3253
|
|
|
@@ -2813,13 +3256,104 @@ precision highp float;
|
|
|
2813
3256
|
uniform sampler2D u_input_a;
|
|
2814
3257
|
uniform sampler2D u_input_b;
|
|
2815
3258
|
|
|
2816
|
-
out vec4 fragColor;
|
|
3259
|
+
out vec4 fragColor;
|
|
3260
|
+
|
|
3261
|
+
void main() {
|
|
3262
|
+
ivec2 fc = ivec2(gl_FragCoord.xy);
|
|
3263
|
+
fragColor = texelFetch(u_input_a, fc, 0) * texelFetch(u_input_b, fc, 0);
|
|
3264
|
+
}
|
|
3265
|
+
\`;var je=class extends h{constructor(r,e,i){super(r);a(this,"inputs");a(this,"weights",[]);a(this,"output");a(this,"dispatch");a(this,"shader",Kr);let o=e,n=this.makeTexture(null,o.texW,o.texH);this.output={h:e.h,w:e.w,c:e.c,texture:n,texW:o.texW,texH:o.texH},this.inputs=[e,i],this.samplers=[{name:"u_input_a",texture:e.texture},{name:"u_input_b",texture:i.texture}],this.defaultSetup(),this.dispatch=[o.texW,o.texH]}};var Yr=\`#version 300 es
|
|
3266
|
+
// Bilinear gather-warp. out[p] = sample(source, p + flow_scale\\xB7flow[p].xy),
|
|
3267
|
+
// edge-clamped. Source + flow are 4-ch (1 group), same resolution; flow in .xy.
|
|
3268
|
+
|
|
3269
|
+
precision highp float;
|
|
3270
|
+
precision highp int;
|
|
3271
|
+
|
|
3272
|
+
uniform sampler2D u_source; // (W, H)
|
|
3273
|
+
uniform sampler2D u_flow; // (W, H), flow in .xy
|
|
3274
|
+
uniform int u_w;
|
|
3275
|
+
uniform int u_h;
|
|
3276
|
+
uniform float u_flow_scale;
|
|
3277
|
+
|
|
3278
|
+
out vec4 fragColor;
|
|
3279
|
+
|
|
3280
|
+
vec4 samp(int x, int y) {
|
|
3281
|
+
int cx = clamp(x, 0, u_w - 1);
|
|
3282
|
+
int cy = clamp(y, 0, u_h - 1);
|
|
3283
|
+
return texelFetch(u_source, ivec2(cx, cy), 0);
|
|
3284
|
+
}
|
|
3285
|
+
|
|
3286
|
+
void main() {
|
|
3287
|
+
int x = int(gl_FragCoord.x);
|
|
3288
|
+
int y = int(gl_FragCoord.y);
|
|
3289
|
+
|
|
3290
|
+
vec2 f = texelFetch(u_flow, ivec2(x, y), 0).xy;
|
|
3291
|
+
float sx = clamp(float(x) + u_flow_scale * f.x, 0.0, float(u_w - 1));
|
|
3292
|
+
float sy = clamp(float(y) + u_flow_scale * f.y, 0.0, float(u_h - 1));
|
|
3293
|
+
|
|
3294
|
+
int x0 = int(floor(sx));
|
|
3295
|
+
int y0 = int(floor(sy));
|
|
3296
|
+
float tx = sx - float(x0);
|
|
3297
|
+
float ty = sy - float(y0);
|
|
3298
|
+
|
|
3299
|
+
vec4 top = mix(samp(x0, y0), samp(x0 + 1, y0), tx);
|
|
3300
|
+
vec4 bot = mix(samp(x0, y0 + 1), samp(x0 + 1, y0 + 1), tx);
|
|
3301
|
+
fragColor = mix(top, bot, ty);
|
|
3302
|
+
}
|
|
3303
|
+
\`;var qe=class extends h{constructor(r,e,i,o){super(r);a(this,"inputs");a(this,"weights",[]);a(this,"output");a(this,"dispatch");a(this,"shader",Yr);let n=e.w,s=e.h,p=this.makeTexture(null,n,s);this.output={h:s,w:n,c:e.c,texture:p,texW:n,texH:s},this.inputs=[e,i],this.samplers=[{name:"u_source",texture:e.texture},{name:"u_flow",texture:i.texture}],this.uniformInts={u_w:n,u_h:s},this.uniformFloats={u_flow_scale:o.flowScale},this.defaultSetup(),this.dispatch=[n,s]}};var Qr=\`#version 300 es
|
|
3304
|
+
// Flow-gated temporal stabilizer. Per pixel:
|
|
3305
|
+
// env = max(|flow.xy|, release\\xB7envPrev.y) peak-hold
|
|
3306
|
+
// g = max(clamp((env - tLo)/(tHi - tLo), 0, 1), leak)
|
|
3307
|
+
// out = vec4((g\\xB7pred + (1-g)\\xB7ref).x, env, 0, 0)
|
|
3308
|
+
|
|
3309
|
+
precision highp float;
|
|
3310
|
+
precision highp int;
|
|
3311
|
+
|
|
3312
|
+
uniform sampler2D u_flow;
|
|
3313
|
+
uniform sampler2D u_pred;
|
|
3314
|
+
uniform sampler2D u_ref;
|
|
3315
|
+
uniform sampler2D u_env_prev;
|
|
3316
|
+
uniform int u_w;
|
|
3317
|
+
uniform int u_h;
|
|
3318
|
+
uniform float u_t_lo;
|
|
3319
|
+
uniform float u_t_hi;
|
|
3320
|
+
uniform float u_leak;
|
|
3321
|
+
uniform float u_release;
|
|
3322
|
+
uniform float u_t_div;
|
|
3323
|
+
uniform float u_div_scale;
|
|
3324
|
+
uniform int u_step_x;
|
|
3325
|
+
uniform int u_step_y;
|
|
3326
|
+
|
|
3327
|
+
out vec4 fragColor;
|
|
3328
|
+
|
|
3329
|
+
void main() {
|
|
3330
|
+
int x = int(gl_FragCoord.x);
|
|
3331
|
+
int y = int(gl_FragCoord.y);
|
|
3332
|
+
|
|
3333
|
+
float mag = length(texelFetch(u_flow, ivec2(x, y), 0).xy);
|
|
3334
|
+
float envPrev = texelFetch(u_env_prev, ivec2(x, y), 0).y;
|
|
3335
|
+
float env = max(mag, u_release * envPrev);
|
|
3336
|
+
|
|
3337
|
+
// Flow divergence over a \\xB1step finite-difference (clamped to the edges).
|
|
3338
|
+
int xr = min(x + u_step_x, u_w - 1);
|
|
3339
|
+
int xl = max(x - u_step_x, 0);
|
|
3340
|
+
int yd = min(y + u_step_y, u_h - 1);
|
|
3341
|
+
int yu = max(y - u_step_y, 0);
|
|
3342
|
+
float dfx = texelFetch(u_flow, ivec2(xr, y), 0).x - texelFetch(u_flow, ivec2(xl, y), 0).x;
|
|
3343
|
+
float dfy = texelFetch(u_flow, ivec2(x, yd), 0).y - texelFetch(u_flow, ivec2(x, yu), 0).y;
|
|
3344
|
+
float divg = abs(dfx + dfy);
|
|
3345
|
+
|
|
3346
|
+
float gMag = clamp((env - u_t_lo) / max(u_t_hi - u_t_lo, 1e-3), 0.0, 1.0);
|
|
3347
|
+
float gDiv = clamp((divg - u_t_div) / max(u_div_scale, 1e-3), 0.0, 1.0);
|
|
3348
|
+
float g = max(max(gMag, gDiv), u_leak);
|
|
2817
3349
|
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
3350
|
+
float pred = texelFetch(u_pred, ivec2(x, y), 0).x;
|
|
3351
|
+
float refv = texelFetch(u_ref, ivec2(x, y), 0).x;
|
|
3352
|
+
float stab = g * pred + (1.0 - g) * refv;
|
|
3353
|
+
|
|
3354
|
+
fragColor = vec4(stab, env, 0.0, 0.0);
|
|
2821
3355
|
}
|
|
2822
|
-
\`;var
|
|
3356
|
+
\`;var Ke=class extends h{constructor(r,e,i,o,n,s){super(r);a(this,"inputs");a(this,"weights",[]);a(this,"output");a(this,"dispatch");a(this,"shader",Qr);let p=e.w,l=e.h,c=this.makeTexture(null,p,l);this.output={h:l,w:p,c:4,texture:c,texW:p,texH:l},this.inputs=[e,i,o,n],this.samplers=[{name:"u_flow",texture:e.texture},{name:"u_pred",texture:i.texture},{name:"u_ref",texture:o.texture},{name:"u_env_prev",texture:n.texture}],this.uniformInts={u_w:p,u_h:l,u_step_x:s.stepX,u_step_y:s.stepY},this.uniformFloats={u_t_lo:s.tLo,u_t_hi:s.tHi,u_leak:s.leak,u_release:s.release,u_t_div:s.tDiv,u_div_scale:s.divScale},this.defaultSetup(),this.dispatch=[p,l]}};var Jr=\`#version 300 es
|
|
2823
3357
|
// Bilinear upsample (arbitrary scale) \\u2014 align_corners=False.
|
|
2824
3358
|
//
|
|
2825
3359
|
// Hardware texture filtering can't be used: adjacent texels in x belong to
|
|
@@ -2870,7 +3404,21 @@ void main() {
|
|
|
2870
3404
|
|
|
2871
3405
|
fragColor = mix(mix(v00, v10, fx), mix(v01, v11, fx), fy);
|
|
2872
3406
|
}
|
|
2873
|
-
\`;var
|
|
3407
|
+
\`;var Ye=class extends h{constructor(r,e,i){super(r);a(this,"inputs");a(this,"weights",[]);a(this,"output");a(this,"dispatch");a(this,"shader",Jr);let o=e.c/4,n=i.outW*o,s=this.makeTexture(null,n,i.outH);this.output={h:i.outH,w:i.outW,c:e.c,texture:s,texW:n,texH:i.outH},this.inputs=[e],this.samplers=[{name:"u_input",texture:e.texture}],this.uniformInts={u_in_w:e.w,u_in_h:e.h,u_out_w:i.outW,u_out_h:i.outH,u_c_groups:o},this.defaultSetup(),this.dispatch=[n,i.outH]}};var Zr=\`#version 300 es
|
|
3408
|
+
// Top-left crop: the output viewport is smaller than the input texture, so reading
|
|
3409
|
+
// the same fragment coord yields the top-left subregion (channel groups packed in
|
|
3410
|
+
// the x axis line up because group count is unchanged).
|
|
3411
|
+
|
|
3412
|
+
precision highp float;
|
|
3413
|
+
precision highp int;
|
|
3414
|
+
|
|
3415
|
+
uniform sampler2D u_input;
|
|
3416
|
+
out vec4 fragColor;
|
|
3417
|
+
|
|
3418
|
+
void main() {
|
|
3419
|
+
fragColor = texelFetch(u_input, ivec2(int(gl_FragCoord.x), int(gl_FragCoord.y)), 0);
|
|
3420
|
+
}
|
|
3421
|
+
\`;var Qe=class extends h{constructor(r,e,i){super(r);a(this,"inputs");a(this,"weights",[]);a(this,"output");a(this,"dispatch");a(this,"shader",Zr);let o=e.c/4,n=i.outW*o,s=this.makeTexture(null,n,i.outH);this.output={h:i.outH,w:i.outW,c:e.c,texture:s,texW:n,texH:i.outH},this.inputs=[e],this.samplers=[{name:"u_input",texture:e.texture}],this.defaultSetup(),this.dispatch=[n,i.outH]}};var eo=\`#version 300 es
|
|
2874
3422
|
// Bicubic upsample (arbitrary scale) \\u2014 Keys cubic, a=-0.75 (PyTorch default
|
|
2875
3423
|
// for mode='bicubic', align_corners=False).
|
|
2876
3424
|
//
|
|
@@ -2930,7 +3478,7 @@ void main() {
|
|
|
2930
3478
|
}
|
|
2931
3479
|
fragColor = acc;
|
|
2932
3480
|
}
|
|
2933
|
-
\`;var
|
|
3481
|
+
\`;var Je=class extends h{constructor(r,e,i){super(r);a(this,"inputs");a(this,"weights",[]);a(this,"output");a(this,"dispatch");a(this,"shader",eo);let o=e.c/4,n=i.outW*o,s=this.makeTexture(null,n,i.outH);this.output={h:i.outH,w:i.outW,c:e.c,texture:s,texW:n,texH:i.outH},this.inputs=[e],this.samplers=[{name:"u_input",texture:e.texture}],this.uniformInts={u_in_w:e.w,u_in_h:e.h,u_out_w:i.outW,u_out_h:i.outH,u_c_groups:o},this.defaultSetup(),this.dispatch=[n,i.outH]}};var to=\`#version 300 es
|
|
2934
3482
|
// Channel concat \\u2014 concatenates two NHWC textures along the channel dimension.
|
|
2935
3483
|
// Both inputs must share the same spatial dimensions (W, H). Channel counts are
|
|
2936
3484
|
// multiples of 4 so each "group" is one vec4 texel.
|
|
@@ -2963,7 +3511,7 @@ void main() {
|
|
|
2963
3511
|
fragColor = texelFetch(u_input_b, ivec2(x_spatial * u_b_c_groups + c_b, y), 0);
|
|
2964
3512
|
}
|
|
2965
3513
|
}
|
|
2966
|
-
\`;var
|
|
3514
|
+
\`;var Ze=class extends h{constructor(r,e,i){super(r);a(this,"inputs");a(this,"weights",[]);a(this,"output");a(this,"dispatch");a(this,"shader",to);let o=e.c/4,n=i.c/4,s=o+n,p=e.c+i.c,l=e.w*s,c=this.makeTexture(null,l,e.h);this.output={h:e.h,w:e.w,c:p,texture:c,texW:l,texH:e.h},this.inputs=[e,i],this.samplers=[{name:"u_input_a",texture:e.texture},{name:"u_input_b",texture:i.texture}],this.uniformInts={u_a_c_groups:o,u_b_c_groups:n},this.defaultSetup(),this.dispatch=[l,e.h]}};var ro=\`#version 300 es
|
|
2967
3515
|
// Bilinear upsample + sigmoid fused \\u2014 sigmoid applied at write time, no intermediate buffer.
|
|
2968
3516
|
// See bilinear_upsample.glsl for the manual 4-tap blend rationale.
|
|
2969
3517
|
//
|
|
@@ -3013,7 +3561,7 @@ void main() {
|
|
|
3013
3561
|
vec4 result = mix(mix(v00, v10, fx), mix(v01, v11, fx), fy);
|
|
3014
3562
|
fragColor = 1.0 / (1.0 + exp(-result));
|
|
3015
3563
|
}
|
|
3016
|
-
\`;var
|
|
3564
|
+
\`;var et=class extends h{constructor(r,e,i){super(r);a(this,"inputs");a(this,"weights",[]);a(this,"output");a(this,"dispatch");a(this,"shader",ro);let o=e.c/4,n=i.outW*o,s=this.makeTexture(null,n,i.outH);this.output={h:i.outH,w:i.outW,c:e.c,texture:s,texW:n,texH:i.outH},this.inputs=[e],this.samplers=[{name:"u_input",texture:e.texture}],this.uniformInts={u_in_w:e.w,u_in_h:e.h,u_out_w:i.outW,u_out_h:i.outH,u_c_groups:o},this.defaultSetup(),this.dispatch=[n,i.outH]}};var oo=\`#version 300 es
|
|
3017
3565
|
// Bilinear upsample (input_a) + channel concat (with input_b) fused.
|
|
3018
3566
|
// input_a is the decoder tensor at small spatial res (in_h \\xD7 in_w), bilinearly resized to (out_h \\xD7 out_w).
|
|
3019
3567
|
// input_b is the encoder skip feature already at output resolution.
|
|
@@ -3071,7 +3619,7 @@ void main() {
|
|
|
3071
3619
|
fragColor = texelFetch(u_input_b, ivec2(x_out * u_b_c_groups + c_b, y_out), 0);
|
|
3072
3620
|
}
|
|
3073
3621
|
}
|
|
3074
|
-
\`;var
|
|
3622
|
+
\`;var tt=class extends h{constructor(r,e,i,o){super(r);a(this,"inputs");a(this,"weights",[]);a(this,"output");a(this,"dispatch");a(this,"shader",oo);let n=e.c/4,s=i.c/4,p=n+s,l=e.c+i.c,c=o.outW*p,d=this.makeTexture(null,c,o.outH);this.output={h:o.outH,w:o.outW,c:l,texture:d,texW:c,texH:o.outH},this.inputs=[e,i],this.samplers=[{name:"u_input_a",texture:e.texture},{name:"u_input_b",texture:i.texture}],this.uniformInts={u_in_w:e.w,u_in_h:e.h,u_out_w:o.outW,u_out_h:o.outH,u_a_c_groups:n,u_b_c_groups:s},this.defaultSetup(),this.dispatch=[c,o.outH]}};var io=\`#version 300 es
|
|
3075
3623
|
// Bilinear upsample + 1\\xD71 pointwise conv fused.
|
|
3076
3624
|
// For each output pixel + out group, bilinearly samples each in_group from input,
|
|
3077
3625
|
// applies the 1\\xD71 conv weight, and writes the activated result.
|
|
@@ -3148,7 +3696,7 @@ void main() {
|
|
|
3148
3696
|
|
|
3149
3697
|
fragColor = result;
|
|
3150
3698
|
}
|
|
3151
|
-
\`;var
|
|
3699
|
+
\`;var rt=class extends h{constructor(r,e,i,o){super(r);a(this,"inputs");a(this,"weights");a(this,"output");a(this,"dispatch");a(this,"shader",io);let n=e.c/4,s=o.outChannels/4,p=m(i.weights),l=m(i.bias),c=this.makeTexture(p,n*4,s),d=this.makeTexture(l,s,1),_=o.outW*s,b=this.makeTexture(null,_,o.outH);this.output={h:o.outH,w:o.outW,c:o.outChannels,texture:b,texW:_,texH:o.outH},this.inputs=[e],this.weights=[],this.samplers=[{name:"u_input",texture:e.texture},{name:"u_weights",texture:c},{name:"u_bias",texture:d}],this.uniformInts={u_in_w:e.w,u_in_h:e.h,u_out_w:o.outW,u_out_h:o.outH,u_in_c_groups:n,u_out_c_groups:s,u_activation:o.activation==="relu6"?1:0},this.defaultSetup(),this.dispatch=[_,o.outH]}};var ao=\`#version 300 es
|
|
3152
3700
|
// Conv2d + skip add fused \\u2014 identical to conv2d.glsl with a skip texture added at write time.
|
|
3153
3701
|
// See conv2d.glsl for tensor/weight layout details.
|
|
3154
3702
|
|
|
@@ -3212,7 +3760,7 @@ void main() {
|
|
|
3212
3760
|
|
|
3213
3761
|
fragColor = result + texelFetch(u_skip, ivec2(fx, fy), 0);
|
|
3214
3762
|
}
|
|
3215
|
-
\`;var
|
|
3763
|
+
\`;var ot=class extends h{constructor(r,e,i,o,n){super(r);a(this,"inputs");a(this,"weights");a(this,"output");a(this,"dispatch");a(this,"shader",ao);let s=T(e.h,n.kernel,n.stride,n.padding),p=T(e.w,n.kernel,n.stride,n.padding),l=e.c/4,c=n.outChannels/4,d=C(n.padding,e.h,s,n.kernel,n.stride),_=C(n.padding,e.w,p,n.kernel,n.stride),b=m(o.weights),g=m(o.bias),v=this.makeTexture(b,l*4,n.kernel*n.kernel*c),x=this.makeTexture(g,c,1),k=p*c,B=this.makeTexture(null,k,s);this.output={h:s,w:p,c:n.outChannels,texture:B,texW:k,texH:s},this.inputs=[e,i],this.weights=[],this.samplers=[{name:"u_input",texture:e.texture},{name:"u_skip",texture:i.texture},{name:"u_weights",texture:v},{name:"u_bias",texture:x}],this.uniformInts={u_in_w:e.w,u_in_h:e.h,u_in_c_groups:l,u_out_c_groups:c,u_kernel_h:n.kernel,u_kernel_w:n.kernel,u_stride:n.stride,u_pad_top:d,u_pad_left:_,u_activation:n.activation==="relu6"?1:0},this.defaultSetup(),this.dispatch=[k,s]}};var no=\`#version 300 es
|
|
3216
3764
|
// proj_residual: bespoke 1\\xD71 conv (no activation) + residual add, fused.
|
|
3217
3765
|
// Specializes conv2d_add to kernel=1 / stride=1 / pad=0 / no activation. Both
|
|
3218
3766
|
// inputs share the same spatial resolution. See conv2d.glsl for the weight
|
|
@@ -3254,7 +3802,7 @@ void main() {
|
|
|
3254
3802
|
|
|
3255
3803
|
fragColor = result + texelFetch(u_skip, ivec2(fx, fy), 0);
|
|
3256
3804
|
}
|
|
3257
|
-
\`;var
|
|
3805
|
+
\`;var it=class extends h{constructor(r,e,i,o,n){super(r);a(this,"inputs");a(this,"weights");a(this,"output");a(this,"dispatch");a(this,"shader",no);let s=e.c/4,p=n.outChannels/4,l=m(o.weights),c=m(o.bias),d=this.makeTexture(l,s*4,p),_=this.makeTexture(c,p,1),b=e.w*p,g=this.makeTexture(null,b,e.h);this.output={h:e.h,w:e.w,c:n.outChannels,texture:g,texW:b,texH:e.h},this.inputs=[e,i],this.weights=[],this.samplers=[{name:"u_input",texture:e.texture},{name:"u_skip",texture:i.texture},{name:"u_weights",texture:d},{name:"u_bias",texture:_}],this.uniformInts={u_in_c_groups:s,u_out_c_groups:p},this.defaultSetup(),this.dispatch=[b,e.h]}};var so=\`#version 300 es
|
|
3258
3806
|
// concat_conv2d: fuses [concat(a, b) \\u2192 conv 3\\xD73 (pad 1) \\u2192 relu6] into one pass.
|
|
3259
3807
|
// Both inputs already at output resolution. Weight cols [0, a_groups) read a,
|
|
3260
3808
|
// [a_groups, I) read b. Weight texture layout matches conv2d.glsl
|
|
@@ -3315,7 +3863,7 @@ void main() {
|
|
|
3315
3863
|
|
|
3316
3864
|
fragColor = clamp(result, 0.0, 6.0);
|
|
3317
3865
|
}
|
|
3318
|
-
\`;var
|
|
3866
|
+
\`;var at=class extends h{constructor(r,e,i,o,n){super(r);a(this,"inputs");a(this,"weights");a(this,"output");a(this,"dispatch");a(this,"shader",so);let s=e.c/4,p=i.c/4,l=s+p,c=n.outChannels/4,d=m(o.weights),_=m(o.bias),b=this.makeTexture(d,l*4,9*c),g=this.makeTexture(_,c,1),v=e.w*c,x=this.makeTexture(null,v,e.h);this.output={h:e.h,w:e.w,c:n.outChannels,texture:x,texW:v,texH:e.h},this.inputs=[e,i],this.weights=[],this.samplers=[{name:"u_a",texture:e.texture},{name:"u_b",texture:i.texture},{name:"u_weights",texture:b},{name:"u_bias",texture:g}],this.uniformInts={u_w:e.w,u_h:e.h,u_a_groups:s,u_b_groups:p,u_out_c_groups:c},this.defaultSetup(),this.dispatch=[v,e.h]}};var uo=\`#version 300 es
|
|
3319
3867
|
// gates_fused: ConvGRU z + r gates, fused. Production config (c_up=2,
|
|
3320
3868
|
// recurrent=1). u_in (.x=a, .y=b), h_prev (.x). weights 9 vec4 =
|
|
3321
3869
|
// (z_w_b, z_w_h, r_w_b, r_w_h) in a (9,1) texture. bias .xy. output (z, r, 0, 0).
|
|
@@ -3358,7 +3906,7 @@ void main() {
|
|
|
3358
3906
|
float r = 1.0 / (1.0 + exp(-r_pre));
|
|
3359
3907
|
fragColor = vec4(z, r, 0.0, 0.0);
|
|
3360
3908
|
}
|
|
3361
|
-
\`;var
|
|
3909
|
+
\`;var nt=class extends h{constructor(r,e,i,o){super(r);a(this,"inputs");a(this,"weights");a(this,"output");a(this,"dispatch");a(this,"shader",uo);let n=this.makeTexture(m(o.weights),9,1),s=this.makeTexture(y(o.bias),1,1),p=e.w,l=this.makeTexture(null,p,e.h);this.output={h:e.h,w:e.w,c:4,texture:l,texW:p,texH:e.h},this.inputs=[e,i],this.weights=[],this.samplers=[{name:"u_u_in",texture:e.texture},{name:"u_h_prev",texture:i.texture},{name:"u_weights",texture:n},{name:"u_bias",texture:s}],this.uniformInts={u_w:e.w,u_h:e.h},this.defaultSetup(),this.dispatch=[p,e.h]}};var po=\`#version 300 es
|
|
3362
3910
|
// cand_update_fused: ConvGRU candidate + state update + output, fused.
|
|
3363
3911
|
// Production config (c_up=2, recurrent=1). u_in (.x=a, .y=b), h_prev (.x),
|
|
3364
3912
|
// gates_out (.x=z, .y=r). weights 9 vec4 (.xy = b_w, rh_w) in a (9,1) texture.
|
|
@@ -3406,7 +3954,7 @@ void main() {
|
|
|
3406
3954
|
float b_out = u_cur.y + gamma * h_new;
|
|
3407
3955
|
fragColor = vec4(u_cur.x, b_out, h_new, 0.0);
|
|
3408
3956
|
}
|
|
3409
|
-
\`;var
|
|
3957
|
+
\`;var st=class extends h{constructor(r,e,i,o,n,s){super(r);a(this,"inputs");a(this,"weights");a(this,"output");a(this,"dispatch");a(this,"shader",po);let p=this.makeTexture(m(n.weights),9,1),l=this.makeTexture(y(n.bias),1,1),c=this.makeTexture(y(s),1,1),d=e.w,_=this.makeTexture(null,d,e.h);this.output={h:e.h,w:e.w,c:4,texture:_,texW:d,texH:e.h},this.inputs=[e,i,o],this.weights=[],this.samplers=[{name:"u_u_in",texture:e.texture},{name:"u_h_prev",texture:i.texture},{name:"u_gates_out",texture:o.texture},{name:"u_weights",texture:p},{name:"u_bias",texture:l},{name:"u_gamma",texture:c}],this.uniformInts={u_w:e.w,u_h:e.h},this.defaultSetup(),this.dispatch=[d,e.h]}};var lo=\`#version 300 es
|
|
3410
3958
|
// conv_expand: bespoke N\\u21922 conv 3\\xD73 (pad 1) + relu (wrapper expand_feat).
|
|
3411
3959
|
// Input N ch (in_groups vec4); output 2ch in .xy (.zw = 0). Weights: 9 *
|
|
3412
3960
|
// in_groups mat4x2 (8 floats each, col-major c0r0,c0r1,...,c3r0,c3r1) in a
|
|
@@ -3449,7 +3997,7 @@ void main() {
|
|
|
3449
3997
|
|
|
3450
3998
|
fragColor = vec4(max(result, vec2(0.0)), 0.0, 0.0); // expand_feat is F.relu
|
|
3451
3999
|
}
|
|
3452
|
-
\`;var
|
|
4000
|
+
\`;var ut=class extends h{constructor(r,e,i){super(r);a(this,"inputs");a(this,"weights");a(this,"output");a(this,"dispatch");a(this,"shader",lo);let o=e.c/4,n=this.makeTexture(m(i.weights),18*o,1),s=this.makeTexture(y(i.bias),1,1),p=e.w,l=this.makeTexture(null,p,e.h);this.output={h:e.h,w:e.w,c:4,texture:l,texW:p,texH:e.h},this.inputs=[e],this.weights=[],this.samplers=[{name:"u_input",texture:e.texture},{name:"u_weights",texture:n},{name:"u_bias",texture:s}],this.uniformInts={u_w:e.w,u_h:e.h,u_in_groups:o},this.defaultSetup(),this.dispatch=[p,e.h]}};var co=\`#version 300 es
|
|
3453
4001
|
// cat_conv_6to2: fused concat(u[2], d[4]) \\u2192 6\\u21922 conv 3\\xD73 (pad 1) + relu
|
|
3454
4002
|
// (E up1_combine). Channel order v3a=(u.x,u.y,d.x), v3b=d.yzw. weights = 9*2
|
|
3455
4003
|
// mat3x2 (6 floats each, col-major) in a 1-row (27-texel) texture.
|
|
@@ -3496,7 +4044,7 @@ void main() {
|
|
|
3496
4044
|
|
|
3497
4045
|
fragColor = vec4(max(result, vec2(0.0)), 0.0, 0.0); // up1_combine is F.relu
|
|
3498
4046
|
}
|
|
3499
|
-
\`;var
|
|
4047
|
+
\`;var pt=class extends h{constructor(r,e,i,o){super(r);a(this,"inputs");a(this,"weights");a(this,"output");a(this,"dispatch");a(this,"shader",co);let n=this.makeTexture(m(o.weights),27,1),s=this.makeTexture(y(o.bias),1,1),p=e.w,l=this.makeTexture(null,p,e.h);this.output={h:e.h,w:e.w,c:4,texture:l,texW:p,texH:e.h},this.inputs=[e,i],this.weights=[],this.samplers=[{name:"u_u_in",texture:e.texture},{name:"u_d_in",texture:i.texture},{name:"u_weights",texture:n},{name:"u_bias",texture:s}],this.uniformInts={u_w:e.w,u_h:e.h},this.defaultSetup(),this.dispatch=[p,e.h]}};var mo=\`#version 300 es
|
|
3500
4048
|
// down_adapter: stride-N 3\\xD73 conv (mat4x4, 4\\u21924) + relu, then 1\\xD71 adapter
|
|
3501
4049
|
// (4\\u21923, last row 0). down_w = 9 mat4x4 (1-row, 36 texels); adapt_w = 1 mat4x4
|
|
3502
4050
|
// (4 texels). Output 3ch in .xyz (.w=0). Symmetric pad. Weight packing matches
|
|
@@ -3548,7 +4096,7 @@ void main() {
|
|
|
3548
4096
|
a.z = awf(2) * d.x + awf(6) * d.y + awf(10) * d.z + awf(14) * d.w + ab.z;
|
|
3549
4097
|
fragColor = vec4(a.xyz, 0.0);
|
|
3550
4098
|
}
|
|
3551
|
-
\`;var
|
|
4099
|
+
\`;var lt=class extends h{constructor(r,e,i,o,n){super(r);a(this,"inputs");a(this,"weights");a(this,"output");a(this,"dispatch");a(this,"shader",mo);let s=T(e.h,3,n.stride,1),p=T(e.w,3,n.stride,1),l=C(1,e.h,s,3,n.stride),c=this.makeTexture(m(i.weights),36,1),d=this.makeTexture(y(i.bias),1,1),_=this.makeTexture(m(o.weights),4,1),b=this.makeTexture(y(o.bias),1,1),g=p,v=this.makeTexture(null,g,s);this.output={h:s,w:p,c:4,texture:v,texW:g,texH:s},this.inputs=[e],this.weights=[],this.samplers=[{name:"u_input",texture:e.texture},{name:"u_down_w",texture:c},{name:"u_down_b",texture:d},{name:"u_adapt_w",texture:_},{name:"u_adapt_b",texture:b}],this.uniformInts={u_in_w:e.w,u_in_h:e.h,u_stride:n.stride,u_pad:l},this.defaultSetup(),this.dispatch=[g,s]}};var fo=\`#version 300 es
|
|
3552
4100
|
// up_final: cat(u[2], rgb[3]) \\u2192 conv 3\\xD73 5\\u21921 \\u2192 sigmoid (A/B alpha head).
|
|
3553
4101
|
// weights 18 vec4 (1-row): [kpos]=(w0,w1,0,0) for u, [9+kpos]=(w2,w3,w4,0) rgb.
|
|
3554
4102
|
|
|
@@ -3586,7 +4134,7 @@ void main() {
|
|
|
3586
4134
|
|
|
3587
4135
|
fragColor = vec4(1.0 / (1.0 + exp(-acc)), 0.0, 0.0, 0.0);
|
|
3588
4136
|
}
|
|
3589
|
-
\`;var
|
|
4137
|
+
\`;var ct=class extends h{constructor(r,e,i,o){super(r);a(this,"inputs");a(this,"weights");a(this,"output");a(this,"dispatch");a(this,"shader",fo);let n=this.makeTexture(m(o.weights),18,1),s=this.makeTexture(y(o.bias),1,1),p=e.w,l=this.makeTexture(null,p,e.h);this.output={h:e.h,w:e.w,c:4,texture:l,texW:p,texH:e.h},this.inputs=[e,i],this.weights=[],this.samplers=[{name:"u_u_gru",texture:e.texture},{name:"u_rgb",texture:i.texture},{name:"u_weights",texture:n},{name:"u_bias",texture:s}],this.uniformInts={u_w:e.w,u_h:e.h},this.defaultSetup(),this.dispatch=[p,e.h]}};var ho=\`#version 300 es
|
|
3590
4138
|
// up_final_skip (C/D alpha head): cat(u[2], d_full[4], rgb[3]) \\u2192 conv 9\\u21921 \\u2192
|
|
3591
4139
|
// sigmoid. Weights = 27 vec4 (3 per kpos): [kpos*3+0]=(w0,w1,0,0) u;
|
|
3592
4140
|
// [kpos*3+1]=(w2..w5) d_full; [kpos*3+2]=(w6,w7,w8,0) rgb.
|
|
@@ -3629,7 +4177,7 @@ void main() {
|
|
|
3629
4177
|
|
|
3630
4178
|
fragColor = vec4(1.0 / (1.0 + exp(-acc)), 0.0, 0.0, 0.0);
|
|
3631
4179
|
}
|
|
3632
|
-
\`;var
|
|
4180
|
+
\`;var dt=class extends h{constructor(r,e,i,o,n){super(r);a(this,"inputs");a(this,"weights");a(this,"output");a(this,"dispatch");a(this,"shader",ho);let s=this.makeTexture(m(n.weights),27,1),p=this.makeTexture(y(n.bias),1,1),l=e.w,c=this.makeTexture(null,l,e.h);this.output={h:e.h,w:e.w,c:4,texture:c,texW:l,texH:e.h},this.inputs=[e,i,o],this.weights=[],this.samplers=[{name:"u_u_gru",texture:e.texture},{name:"u_d_full",texture:i.texture},{name:"u_rgb",texture:o.texture},{name:"u_weights",texture:s},{name:"u_bias",texture:p}],this.uniformInts={u_w:e.w,u_h:e.h},this.defaultSetup(),this.dispatch=[l,e.h]}};var _o=\`#version 300 es
|
|
3633
4181
|
// Composite an RGBA image over a solid background color, gated by a
|
|
3634
4182
|
// 1-channel alpha mask. Output: premultiplied RGBA.
|
|
3635
4183
|
//
|
|
@@ -3660,12 +4208,12 @@ void main() {
|
|
|
3660
4208
|
vec3 rgb = fg * a + u_bgColor * (1.0 - a);
|
|
3661
4209
|
fragColor = vec4(rgb, 1.0);
|
|
3662
4210
|
}
|
|
3663
|
-
\`;var
|
|
4211
|
+
\`;var Da=\`#version 300 es
|
|
3664
4212
|
const vec2 VERTS[6] = vec2[6](
|
|
3665
4213
|
vec2(-1.0,-1.0), vec2(1.0,-1.0), vec2(-1.0,1.0),
|
|
3666
4214
|
vec2(-1.0,1.0), vec2(1.0,-1.0), vec2(1.0,1.0)
|
|
3667
4215
|
);
|
|
3668
|
-
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }\`,
|
|
4216
|
+
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }\`,mt=class{constructor(t,r,e,i){a(this,"backend",t);a(this,"program");a(this,"imageTex");a(this,"alphaTex");a(this,"bgColor");if(r.h!==e.h||r.w!==e.w)throw new Error(\`CompositeSolid: image (\${r.h}\\xD7\${r.w}) and alpha (\${e.h}\\xD7\${e.w}) must match. Run the upscaler first.\`);let o=r,n=e;this.imageTex=o.texture,this.alphaTex=n.texture,this.bgColor=i;let s=t.gl,p=s.createShader(s.VERTEX_SHADER);s.shaderSource(p,Da),s.compileShader(p);let l=s.createShader(s.FRAGMENT_SHADER);if(s.shaderSource(l,_o),s.compileShader(l),!s.getShaderParameter(l,s.COMPILE_STATUS))throw new Error(\`composite_solid GLSL compile error: \${s.getShaderInfoLog(l)}\`);if(this.program=s.createProgram(),s.attachShader(this.program,p),s.attachShader(this.program,l),s.linkProgram(this.program),!s.getProgramParameter(this.program,s.LINK_STATUS))throw new Error(\`composite_solid GLSL link error: \${s.getProgramInfoLog(this.program)}\`)}run(){let t=this.backend.gl;t.useProgram(this.program),t.activeTexture(t.TEXTURE0),t.bindTexture(t.TEXTURE_2D,this.imageTex),t.uniform1i(t.getUniformLocation(this.program,"u_image"),0),t.activeTexture(t.TEXTURE1),t.bindTexture(t.TEXTURE_2D,this.alphaTex),t.uniform1i(t.getUniformLocation(this.program,"u_alpha"),1),t.uniform3f(t.getUniformLocation(this.program,"u_bgColor"),this.bgColor[0],this.bgColor[1],this.bgColor[2]),this.backend.bindDisplayFramebuffer(),t.bindVertexArray(null),t.drawArrays(t.TRIANGLES,0,6)}};var go=\`#version 300 es
|
|
3669
4217
|
// Same as composite_solid but bg is a texture (NHWC vec4 tensor) instead of
|
|
3670
4218
|
// a uniform color. Caller invariants: image, alpha, bg all share h \\xD7 w, and
|
|
3671
4219
|
// canvas dimensions match.
|
|
@@ -3691,12 +4239,12 @@ void main() {
|
|
|
3691
4239
|
vec3 rgb = fg * a + bg * (1.0 - a);
|
|
3692
4240
|
fragColor = vec4(rgb, 1.0);
|
|
3693
4241
|
}
|
|
3694
|
-
\`;var
|
|
4242
|
+
\`;var Ia=\`#version 300 es
|
|
3695
4243
|
const vec2 VERTS[6] = vec2[6](
|
|
3696
4244
|
vec2(-1.0,-1.0), vec2(1.0,-1.0), vec2(-1.0,1.0),
|
|
3697
4245
|
vec2(-1.0,1.0), vec2(1.0,-1.0), vec2(1.0,1.0)
|
|
3698
4246
|
);
|
|
3699
|
-
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }\`,
|
|
4247
|
+
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }\`,ft=class{constructor(t,r,e,i){a(this,"backend",t);a(this,"program");a(this,"imageTex");a(this,"alphaTex");a(this,"bgTex");if(r.h!==e.h||r.w!==e.w||r.h!==i.h||r.w!==i.w)throw new Error(\`CompositeImage: image (\${r.h}\\xD7\${r.w}), alpha (\${e.h}\\xD7\${e.w}), and bg (\${i.h}\\xD7\${i.w}) must all match. Run upscaler / resizer first.\`);this.imageTex=r.texture,this.alphaTex=e.texture,this.bgTex=i.texture;let o=t.gl,n=o.createShader(o.VERTEX_SHADER);o.shaderSource(n,Ia),o.compileShader(n);let s=o.createShader(o.FRAGMENT_SHADER);if(o.shaderSource(s,go),o.compileShader(s),!o.getShaderParameter(s,o.COMPILE_STATUS))throw new Error(\`composite_image GLSL compile error: \${o.getShaderInfoLog(s)}\`);if(this.program=o.createProgram(),o.attachShader(this.program,n),o.attachShader(this.program,s),o.linkProgram(this.program),!o.getProgramParameter(this.program,o.LINK_STATUS))throw new Error(\`composite_image GLSL link error: \${o.getProgramInfoLog(this.program)}\`)}run(){let t=this.backend.gl;t.useProgram(this.program),t.activeTexture(t.TEXTURE0),t.bindTexture(t.TEXTURE_2D,this.imageTex),t.uniform1i(t.getUniformLocation(this.program,"u_image"),0),t.activeTexture(t.TEXTURE1),t.bindTexture(t.TEXTURE_2D,this.alphaTex),t.uniform1i(t.getUniformLocation(this.program,"u_alpha"),1),t.activeTexture(t.TEXTURE2),t.bindTexture(t.TEXTURE_2D,this.bgTex),t.uniform1i(t.getUniformLocation(this.program,"u_bg"),2),this.backend.bindDisplayFramebuffer(),t.bindVertexArray(null),t.drawArrays(t.TRIANGLES,0,6)}};var bo=\`#version 300 es
|
|
3700
4248
|
// Like composite_image but bg is bilinearly sampled \\u2014 bg is at a smaller
|
|
3701
4249
|
// resolution than (image, alpha) at canvas h \\xD7 w. Used by CompositorBlur to
|
|
3702
4250
|
// skip the final full-res upsample in the blur pyramid.
|
|
@@ -3745,12 +4293,12 @@ void main() {
|
|
|
3745
4293
|
vec3 rgb = fg * a + bg * (1.0 - a);
|
|
3746
4294
|
fragColor = vec4(rgb, 1.0);
|
|
3747
4295
|
}
|
|
3748
|
-
\`;var
|
|
4296
|
+
\`;var Ma=\`#version 300 es
|
|
3749
4297
|
const vec2 VERTS[6] = vec2[6](
|
|
3750
4298
|
vec2(-1.0,-1.0), vec2(1.0,-1.0), vec2(-1.0,1.0),
|
|
3751
4299
|
vec2(-1.0,1.0), vec2(1.0,-1.0), vec2(1.0,1.0)
|
|
3752
4300
|
);
|
|
3753
|
-
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }\`,
|
|
4301
|
+
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }\`,ht=class{constructor(t,r,e,i){a(this,"backend",t);a(this,"program");a(this,"imageTex");a(this,"alphaTex");a(this,"bgTex");a(this,"outW");a(this,"outH");a(this,"bgW");a(this,"bgH");if(r.h!==e.h||r.w!==e.w)throw new Error(\`CompositeImageBilinear: image (\${r.h}\\xD7\${r.w}) and alpha (\${e.h}\\xD7\${e.w}) must match.\`);this.imageTex=r.texture,this.alphaTex=e.texture,this.bgTex=i.texture,this.outW=r.w,this.outH=r.h,this.bgW=i.w,this.bgH=i.h;let o=t.gl,n=o.createShader(o.VERTEX_SHADER);o.shaderSource(n,Ma),o.compileShader(n);let s=o.createShader(o.FRAGMENT_SHADER);if(o.shaderSource(s,bo),o.compileShader(s),!o.getShaderParameter(s,o.COMPILE_STATUS))throw new Error(\`composite_image_bilinear GLSL compile error: \${o.getShaderInfoLog(s)}\`);if(this.program=o.createProgram(),o.attachShader(this.program,n),o.attachShader(this.program,s),o.linkProgram(this.program),!o.getProgramParameter(this.program,o.LINK_STATUS))throw new Error(\`composite_image_bilinear GLSL link error: \${o.getProgramInfoLog(this.program)}\`)}run(){let t=this.backend.gl;t.useProgram(this.program),t.activeTexture(t.TEXTURE0),t.bindTexture(t.TEXTURE_2D,this.imageTex),t.uniform1i(t.getUniformLocation(this.program,"u_image"),0),t.activeTexture(t.TEXTURE1),t.bindTexture(t.TEXTURE_2D,this.alphaTex),t.uniform1i(t.getUniformLocation(this.program,"u_alpha"),1),t.activeTexture(t.TEXTURE2),t.bindTexture(t.TEXTURE_2D,this.bgTex),t.uniform1i(t.getUniformLocation(this.program,"u_bg"),2),t.uniform1i(t.getUniformLocation(this.program,"u_out_w"),this.outW),t.uniform1i(t.getUniformLocation(this.program,"u_out_h"),this.outH),t.uniform1i(t.getUniformLocation(this.program,"u_bg_w"),this.bgW),t.uniform1i(t.getUniformLocation(this.program,"u_bg_h"),this.bgH),this.backend.bindDisplayFramebuffer(),t.bindVertexArray(null),t.drawArrays(t.TRIANGLES,0,6)}};var vo=\`#version 300 es
|
|
3754
4302
|
// Passthrough "compositor": writes the image directly to the canvas
|
|
3755
4303
|
// (default framebuffer). No alpha math, no background. Used by RenderOp
|
|
3756
4304
|
// when the renderer is in disabled state.
|
|
@@ -3773,12 +4321,12 @@ void main() {
|
|
|
3773
4321
|
vec3 rgb = texelFetch(u_image, px, 0).rgb;
|
|
3774
4322
|
fragColor = vec4(rgb, 1.0);
|
|
3775
4323
|
}
|
|
3776
|
-
\`;var
|
|
4324
|
+
\`;var Ha=\`#version 300 es
|
|
3777
4325
|
const vec2 VERTS[6] = vec2[6](
|
|
3778
4326
|
vec2(-1.0,-1.0), vec2(1.0,-1.0), vec2(-1.0,1.0),
|
|
3779
4327
|
vec2(-1.0,1.0), vec2(1.0,-1.0), vec2(1.0,1.0)
|
|
3780
4328
|
);
|
|
3781
|
-
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }\`,
|
|
4329
|
+
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }\`,_t=class{constructor(t,r){a(this,"backend",t);a(this,"program");a(this,"imageTex");this.imageTex=r.texture;let e=t.gl,i=e.createShader(e.VERTEX_SHADER);e.shaderSource(i,Ha),e.compileShader(i);let o=e.createShader(e.FRAGMENT_SHADER);if(e.shaderSource(o,vo),e.compileShader(o),!e.getShaderParameter(o,e.COMPILE_STATUS))throw new Error(\`composite_passthrough GLSL compile error: \${e.getShaderInfoLog(o)}\`);if(this.program=e.createProgram(),e.attachShader(this.program,i),e.attachShader(this.program,o),e.linkProgram(this.program),!e.getProgramParameter(this.program,e.LINK_STATUS))throw new Error(\`composite_passthrough GLSL link error: \${e.getProgramInfoLog(this.program)}\`)}run(){let t=this.backend.gl;t.useProgram(this.program),t.activeTexture(t.TEXTURE0),t.bindTexture(t.TEXTURE_2D,this.imageTex),t.uniform1i(t.getUniformLocation(this.program,"u_image"),0),this.backend.bindDisplayFramebuffer(),t.bindVertexArray(null),t.drawArrays(t.TRIANGLES,0,6)}};var xo=\`#version 300 es
|
|
3782
4330
|
precision highp float;
|
|
3783
4331
|
|
|
3784
4332
|
// Input op \\u2014 bilinear-sample a source texture (RGBA8 unorm uploaded from an
|
|
@@ -3796,21 +4344,20 @@ void main() {
|
|
|
3796
4344
|
vec2 uv = (gl_FragCoord.xy + vec2(0.5)) / vec2(float(u_out_w), float(u_out_h));
|
|
3797
4345
|
fragColor = texture(u_src, uv);
|
|
3798
4346
|
}
|
|
3799
|
-
\`;var
|
|
4347
|
+
\`;var Va=\`#version 300 es
|
|
3800
4348
|
const vec2 VERTS[6] = vec2[6](
|
|
3801
4349
|
vec2(-1.0,-1.0), vec2(1.0,-1.0), vec2(-1.0,1.0),
|
|
3802
4350
|
vec2(-1.0,1.0), vec2(1.0,-1.0), vec2(1.0,1.0)
|
|
3803
4351
|
);
|
|
3804
|
-
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }\`,rt=class{constructor(t,r,e){i(this,"backend",t);i(this,"output");i(this,"gl");i(this,"program");i(this,"srcTex");i(this,"uOutW");i(this,"uOutH");i(this,"uSrc");i(this,"source",null);let o=t.gl;this.gl=o,this.output=t.tensor(r,e,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 a=o.createShader(o.VERTEX_SHADER);o.shaderSource(a,ta),o.compileShader(a);let n=o.createShader(o.FRAGMENT_SHADER);if(o.shaderSource(n,Xr),o.compileShader(n),!o.getShaderParameter(n,o.COMPILE_STATUS))throw new Error(\`Input GLSL compile error: \${o.getShaderInfoLog(n)}\`);if(this.program=o.createProgram(),o.attachShader(this.program,a),o.attachShader(this.program,n),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(t){this.source=t}run(){if(!this.source)throw new Error("InputWebGL.run() called before setSource()");let t=this.gl;t.bindTexture(t.TEXTURE_2D,this.srcTex),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,t.RGBA,t.UNSIGNED_BYTE,this.source),t.useProgram(this.program),t.activeTexture(t.TEXTURE0),t.bindTexture(t.TEXTURE_2D,this.srcTex),t.uniform1i(this.uSrc,0),t.uniform1i(this.uOutW,this.output.w),t.uniform1i(this.uOutH,this.output.h),t.bindFramebuffer(t.FRAMEBUFFER,this.backend.fbo),t.framebufferTexture2D(t.FRAMEBUFFER,t.COLOR_ATTACHMENT0,t.TEXTURE_2D,this.output.texture,0),t.viewport(0,0,this.output.texW,this.output.texH),t.bindVertexArray(null),t.drawArrays(t.TRIANGLES,0,6)}};var L=class s{constructor(t,r,e){i(this,"gl",t);i(this,"canvas",r);i(this,"dtype",e);i(this,"ops");i(this,"presenters");i(this,"fbo");i(this,"textureFormat");this.fbo=t.createFramebuffer(),this.textureFormat=e==="f16"?{internalFormat:t.RGBA16F,format:t.RGBA,type:t.HALF_FLOAT,bytesPerElement:2}:{internalFormat:t.RGBA32F,format:t.RGBA,type:t.FLOAT,bytesPerElement:4},this.ops={Conv2d:(o,a,n)=>new Ue(this,o,a,n),DepthwiseConv2d:(o,a,n)=>new Se(this,o,a,n),Add:(o,a)=>new Le(this,o,a),Sigmoid:o=>new Fe(this,o),Tanh:o=>new Ee(this,o),ElementwiseMul:(o,a)=>new Oe(this,o,a),BilinearUpsample:(o,a)=>new Ie(this,o,a),BicubicUpsample:(o,a)=>new De(this,o,a),ChannelConcat:(o,a)=>new Ae(this,o,a),Conv2dAdd:(o,a,n,u)=>new ze(this,o,a,n,u),ProjResidual:(o,a,n,u)=>new Ve(this,o,a,n,u),ConcatConv2d:(o,a,n,u)=>new Ne(this,o,a,n,u),GatesFused:(o,a,n)=>new $e(this,o,a,n),CandUpdateFused:(o,a,n,u,p)=>new Xe(this,o,a,n,u,p),ConvExpand:(o,a)=>new je(this,o,a),CatConv6to2:(o,a,n)=>new qe(this,o,a,n),DownAdapter:(o,a,n,u)=>new Ke(this,o,a,n,u),UpFinal:(o,a,n)=>new Ye(this,o,a,n),UpFinalSkip:(o,a,n,u)=>new Qe(this,o,a,n,u),UpsampleConcat:(o,a,n)=>new Me(this,o,a,n),UpsampleConv1x1:(o,a,n)=>new He(this,o,a,n),UpsampleSigmoid:(o,a)=>new Re(this,o,a),Input:(o,a)=>new rt(this,o,a)},this.presenters={CompositeSolid:(o,a,n)=>new Je(this,o,a,n),CompositeImage:(o,a,n)=>new Ze(this,o,a,n),CompositeImageBilinear:(o,a,n)=>new et(this,o,a,n),CompositePassthrough:o=>new tt(this,o)}}static isAvailable(){let t=null;try{return t=new OffscreenCanvas(1,1).getContext("webgl2"),!(!t||!t.getExtension("EXT_color_buffer_float"))}catch{return!1}finally{t?.getExtension("WEBGL_lose_context")?.loseContext()}}static create(t){let r=t.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,t.canvas,t.dtype??"f32")}attachCanvas(t){throw new Error(\`WebGLBackend.attachCanvas('\${t}'): WebGL cannot render to a second canvas; use the renderer's snapshot-and-present path for preview output\`)}bindDisplayFramebuffer(){this.gl.bindFramebuffer(this.gl.FRAMEBUFFER,null),this.gl.viewport(0,0,this.canvas.width,this.canvas.height)}toTextureView(t){if(t===null)return null;let r=this.dtype==="f16",e=t instanceof Uint16Array;return r===e?t:r?re(t):I(t)}tensor(t,r,e,o){let a=r*(e/4),n=t,u=this.gl,p=u.createTexture(),l=this.textureFormat,c=this.toTextureView(o??null);return u.bindTexture(u.TEXTURE_2D,p),u.texImage2D(u.TEXTURE_2D,0,l.internalFormat,a,n,0,l.format,l.type,c),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:t,w:r,c:e,texture:p,texW:a,texH:n}}upload(t){return{data:t}}async readback(t){let r=this.gl,e=this.textureFormat;if(r.bindFramebuffer(r.FRAMEBUFFER,this.fbo),r.framebufferTexture2D(r.FRAMEBUFFER,r.COLOR_ATTACHMENT0,r.TEXTURE_2D,t.texture,0),this.dtype==="f16"){let a=new Uint16Array(t.texW*t.texH*4);return r.readPixels(0,0,t.texW,t.texH,e.format,r.HALF_FLOAT,a),r.bindFramebuffer(r.FRAMEBUFFER,null),I(a)}let o=new Float32Array(t.texW*t.texH*4);return r.readPixels(0,0,t.texW,t.texH,e.format,r.FLOAT,o),r.bindFramebuffer(r.FRAMEBUFFER,null),o}copyTensor(t,r){if(t.texW!==r.texW||t.texH!==r.texH)throw new Error(\`copyTensor: size mismatch (src \${t.texW}\\xD7\${t.texH} vs dst \${r.texW}\\xD7\${r.texH})\`);let e=this.gl;e.bindFramebuffer(e.FRAMEBUFFER,this.fbo),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,t.texture,0),e.bindTexture(e.TEXTURE_2D,r.texture),e.copyTexSubImage2D(e.TEXTURE_2D,0,0,0,0,0,t.texW,t.texH),e.bindFramebuffer(e.FRAMEBUFFER,null)}async sync(){let t=this.gl,r=t.fenceSync(t.SYNC_GPU_COMMANDS_COMPLETE,0);if(!r){t.finish();return}for(t.flush();;){let e=t.clientWaitSync(r,0,0);if(e===t.ALREADY_SIGNALED||e===t.CONDITION_SATISFIED){t.deleteSync(r);return}if(e===t.WAIT_FAILED)throw t.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 st=U("setup_backend");async function jr(s,t,r={}){let e=s.backend==="webgpu"||s.backend==="auto",o=!!s.outputCanvas,a=()=>s.outputCanvas??new OffscreenCanvas(t.w,t.h),n=null;if(e&&await D.isAvailable()){let p=s.dtype==="f16"&&!await D.hasF16Support()?"f32":s.dtype,l=a();try{let c=await D.create({canvas:l,dtype:p});return c.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:c,resolvedBackend:"webgpu",resolvedDtype:p,canvas:l}}catch(c){st.warn("WebGPU isAvailable but create() threw; trying WebGL fallback:",c),n=c,o&&st.warn("transfer-capture topology: WebGL fallback may also fail on the same canvas")}}if(L.isAvailable()){let p=a();try{let l=L.create({canvas:p,dtype:s.dtype});return p.addEventListener("webglcontextlost",c=>{r.onContextLost?.({message:"WebGL context lost",source:"backend-lost",recoverable:!1,cause:c})}),{backend:l,resolvedBackend:"webgl",resolvedDtype:s.dtype,canvas:p}}catch(l){st.warn("WebGL create() threw:",l),n=l}}let u=n?\` (last error: \${n.message??n})\`:"";throw new Error(\`setup_backend: no usable GPU backend\${u}\`)}var qr=.5,ra=3,Kr=10,oa=30,F=U("autotune");async function Yr(s,t=oa){let r=s instanceof L?qr*.5:qr,e=1e3/t*r;F(\`start; budget per source frame: \${e.toFixed(1)}ms (source \${t}fps \\xD7 \${r} safety)\`),F("backend dtype:",s.dtype);let o=null;for(let a of at){if(!E[a.model]){F("skip",a.model,"(no TIER_CONFIG entry)");continue}try{let n=E[a.model].baseRes;F(\`bench \${a.model} base @ \${n.w}\\xD7\${n.h} skipFrames=\${a.skipFrames} \\u2026\`);let u=await na(s,a),p=u<=e;if(F(\` \${a.model}: \${u.toFixed(1)}ms / source frame \${p?"\\u2713 within budget":"\\u2717 over budget"}\`),(p||o===null)&&(o=a),!p)break}catch(n){F(" bench failed for",a.model,":",n);break}}if(!o)throw new Error("autotune: no implementable preset available");return F("picked",o.model),o}function ia(s){let t=Object.create(s);return t.ops={...s.ops,Conv2d:(r,e,o)=>{let a={weights:new Float32Array(o.kernel*o.kernel*r.c*o.outChannels),bias:new Float32Array(o.outChannels)};return s.ops.Conv2d(r,a,o)},DepthwiseConv2d:(r,e,o)=>{let a={weights:new Float32Array(o.kernel*o.kernel*r.c),bias:new Float32Array(r.c)};return s.ops.DepthwiseConv2d(r,a,o)},Conv2dAdd:(r,e,o,a)=>{let n={weights:new Float32Array(a.kernel*a.kernel*r.c*a.outChannels),bias:new Float32Array(a.outChannels)};return s.ops.Conv2dAdd(r,e,n,a)},UpsampleConv1x1:(r,e,o)=>{let a={weights:new Float32Array(r.c*o.outChannels),bias:new Float32Array(o.outChannels)};return s.ops.UpsampleConv1x1(r,a,o)},ProjResidual:(r,e,o,a)=>{let n={weights:new Float32Array(r.c*a.outChannels),bias:new Float32Array(a.outChannels)};return s.ops.ProjResidual(r,e,n,a)},ConcatConv2d:(r,e,o,a)=>{let n={weights:new Float32Array(9*(r.c+e.c)*a.outChannels),bias:new Float32Array(a.outChannels)};return s.ops.ConcatConv2d(r,e,n,a)}},t}function aa(){let s=new Proxy({},{get:()=>s});return s}async function na(s,t){let r=E[t.model];if(!r)throw new Error(\`microbench: no TIER_CONFIG entry for '\${t.model}'\`);let e=r.base,o=ia(s),a=o.tensor(r.baseRes.h,r.baseRes.w,4),n=new e(o,a,aa());for(let c=0;c<ra;c++)n.run(),await s.sync();let u=t.skipFrames+1,p=performance.now();for(let c=0;c<Kr;c++)c%u===0&&n.run();return await s.sync(),(performance.now()-p)/Kr}async function Qr(s,t,r){let e;if(s==="auto")e=await Yr(r);else if(typeof s=="string"){let o=V(s);if(!o)throw new Error(\`resolve_preset: unknown preset name '\${s}'\`);e=o}else e=s;return e.dtype!==t?{...e,dtype:t}:e}function Jr(s){let t=null,r=null;return s.onmessage=e=>{let{frame:o}=e.data;if(r){let a=r;r=null,a(o)}else t&&t.close(),t=o},s.start?.(),new ReadableStream({pull(e){if(t){e.enqueue(t),t=null;return}return new Promise(o=>{r=a=>{e.enqueue(a),o()}})},cancel(){t&&(t.close(),t=null),s.close()}},{highWaterMark:0})}function Zr(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 Jr(s.inputPort)}}function eo(s){return new TransformStream({transform(t,r){s.process(t);let e=new VideoFrame(s.canvas,{timestamp:t.timestamp});t.close(),r.enqueue(e)}})}function to(s){return new WritableStream({write(t){s.process(t),t.close()}})}function ro(s,t){return new WritableStream({write(r){s.process(r),r.close();let e=s.canvas.transferToImageBitmap();t.postMessage({bmp:e},[e])},close(){t.close()}})}var sa=U("create_output");function oo(s,t,r){switch(s.topology.output){case"mstg":{if(!s.outputWritable)throw new Error("create_output: topology.output='mstg' but InitData.outputWritable missing");let e=eo(t);return e.readable.pipeTo(s.outputWritable,{signal:r}).catch(o=>{r.aborted||sa.warn("mstg downstream pipe failed:",o)}),e.writable}case"transfer-capture":return to(t);case"bitmap-shuttle":{if(!s.outputPort)throw new Error("create_output: topology.output='bitmap-shuttle' but InitData.outputPort missing");return ro(t,s.outputPort)}}}function io(s){if(!s.onFirstFrame)return s.input.pipeTo(s.output,{signal:s.signal});let t=!1,r=s.onFirstFrame,e=new TransformStream({transform(o,a){a.enqueue(o),t||(t=!0,queueMicrotask(r))}});return s.input.pipeThrough(e,{signal:s.signal}).pipeTo(s.output,{signal:s.signal})}var C=U("worker");C("script loaded");var W=null,A=null,ot=null;self.onmessage=async function(s){let{cmd:t,data:r,request_id:e}=s.data;C("cmd received:",t,"request_id:",e);try{let o=await ua(t,r);C("cmd ok:",t),va(e,o)}catch(o){C("cmd FAILED:",t,o),H("error",{message:\`\${t} failed: \${o.message??String(o)}\`,source:"worker",recoverable:!1,cause:o})}};async function ua(s,t){switch(s){case"init":return pa(t);case"startRender":return la(t.weights);case"setBackground":return ca(t);case"setEnabled":return da(t.enabled);case"setPreset":return ga(t);case"getStats":return W?.getStats()??null;case"destroy":return _a();case"attachPreview":return ma(t);case"setPreview":return fa(t);case"clearPreview":return ha();default:throw new Error(\`unknown cmd: \${s}\`)}}async function pa(s){if(lt(!!s.debug),C("handleInit: start; topology=",s.topology,"preset=",s.preset,"backend=",s.backend,"dtype=",s.dtype),W)throw new Error("handleInit: already initialized");C("handleInit: setupBackend\\u2026");let t=await jr(s,s.canvasSize,{onContextLost:a=>{C("GPU context lost:",a.message),H("error",a)}});C("handleInit: backend ready:",t.resolvedBackend,t.resolvedDtype,"canvas:",t.canvas.width,"x",t.canvas.height),C("handleInit: constructing Renderer (boot mode)\\u2026"),W=new te({backend:t.backend,backendKind:t.resolvedBackend,canvas:t.canvas,background:s.background,enabled:s.enabled,topology:s.topology}),A=new AbortController,C("handleInit: createInputStream\\u2026");let r=Zr(s);C("handleInit: createOutputSink\\u2026");let e=oo(s,W,A.signal);C("handleInit: starting pipe (passthrough)\\u2026"),io({input:r,output:e,signal:A.signal}).then(()=>{C("pipe completed (input ended)")}).catch(a=>{if(A?.signal.aborted){C("pipe aborted (expected on destroy)");return}C("pipe FAILED:",a),H("error",{message:\`pipe failed: \${a.message}\`,source:"worker",recoverable:!1,cause:a})}),C("handleInit: resolvePreset\\u2026");let o=await Qr(s.preset,t.resolvedDtype,t.backend);return C("handleInit: preset resolved:",o),ot=o,C("handleInit: done; returning InitResponse, awaiting startRender"),{resolvedPreset:o,resolvedBackend:t.resolvedBackend,resolvedDtype:t.resolvedDtype}}async function la(s){if(C("handleStartRender: start; weights bytes:",s.byteLength),!W||!ot)throw new Error("handleStartRender: handleInit not completed");C("handleStartRender: attaching network via setPreset\\u2026"),W.setPreset(ot,s),C("handleStartRender: ready (effect mode active)"),H("ready",void 0)}async function ca(s){W?.setBackground(s)}async function da(s){W?.setEnabled(s)}async function ma(s){if(!W)throw new Error("handleAttachPreview: not initialized");W.attachPreview(s.canvas)}async function fa(s){if(!W)throw new Error("handleSetPreview: not initialized");W.setPreview(s.background,s.fps!==void 0?{fps:s.fps}:void 0)}async function ha(){W?.clearPreview()}async function ga(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 t=typeof s.preset=="string"?V(s.preset)??ba(s.preset):s.preset;return W.setPreset(t,s.weights),{resolvedPreset:t}}async function _a(){A?.abort(),A=null,W?.destroy(),W=null,ot=null}function ba(s){throw new Error(\`handleSetPreset: unknown preset '\${s}'\`)}function va(s,t){let r={request_id:s,res:t};self.postMessage(r)}function H(s,t){let r={request_id:s,res:t};self.postMessage(r)}function Mh(s){H("stats",s)}export{Mh as emitStats};
|
|
3805
|
-
`;var y=
|
|
4352
|
+
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }\`,gt=class{constructor(t,r,e){a(this,"backend",t);a(this,"output");a(this,"gl");a(this,"program");a(this,"srcTex");a(this,"uOutW");a(this,"uOutH");a(this,"uSrc");a(this,"source",null);let i=t.gl;this.gl=i,this.output=t.tensor(r,e,4),this.srcTex=i.createTexture(),i.bindTexture(i.TEXTURE_2D,this.srcTex),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_MIN_FILTER,i.LINEAR),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_MAG_FILTER,i.LINEAR),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_WRAP_S,i.CLAMP_TO_EDGE),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_WRAP_T,i.CLAMP_TO_EDGE);let o=i.createShader(i.VERTEX_SHADER);i.shaderSource(o,Va),i.compileShader(o);let n=i.createShader(i.FRAGMENT_SHADER);if(i.shaderSource(n,xo),i.compileShader(n),!i.getShaderParameter(n,i.COMPILE_STATUS))throw new Error(\`Input GLSL compile error: \${i.getShaderInfoLog(n)}\`);if(this.program=i.createProgram(),i.attachShader(this.program,o),i.attachShader(this.program,n),i.linkProgram(this.program),!i.getProgramParameter(this.program,i.LINK_STATUS))throw new Error(\`Input GLSL link error: \${i.getProgramInfoLog(this.program)}\`);this.uSrc=i.getUniformLocation(this.program,"u_src"),this.uOutW=i.getUniformLocation(this.program,"u_out_w"),this.uOutH=i.getUniformLocation(this.program,"u_out_h")}setSource(t){this.source=t}run(){if(!this.source)throw new Error("InputWebGL.run() called before setSource()");let t=this.gl;t.bindTexture(t.TEXTURE_2D,this.srcTex),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,t.RGBA,t.UNSIGNED_BYTE,this.source),t.useProgram(this.program),t.activeTexture(t.TEXTURE0),t.bindTexture(t.TEXTURE_2D,this.srcTex),t.uniform1i(this.uSrc,0),t.uniform1i(this.uOutW,this.output.w),t.uniform1i(this.uOutH,this.output.h),t.bindFramebuffer(t.FRAMEBUFFER,this.backend.fbo),t.framebufferTexture2D(t.FRAMEBUFFER,t.COLOR_ATTACHMENT0,t.TEXTURE_2D,this.output.texture,0),t.viewport(0,0,this.output.texW,this.output.texH),t.bindVertexArray(null),t.drawArrays(t.TRIANGLES,0,6)}};var F=class u{constructor(t,r,e){a(this,"gl",t);a(this,"canvas",r);a(this,"dtype",e);a(this,"ops");a(this,"presenters");a(this,"fbo");a(this,"textureFormat");this.fbo=t.createFramebuffer(),this.textureFormat=e==="f16"?{internalFormat:t.RGBA16F,format:t.RGBA,type:t.HALF_FLOAT,bytesPerElement:2}:{internalFormat:t.RGBA32F,format:t.RGBA,type:t.FLOAT,bytesPerElement:4},this.ops={Conv2d:(i,o,n)=>new He(this,i,o,n),ConvTranspose2d:(i,o,n)=>new ze(this,i,o,n),DepthwiseConv2d:(i,o,n)=>new Ve(this,i,o,n),Add:(i,o)=>new Ne(this,i,o),Sigmoid:i=>new $e(this,i),Tanh:i=>new Xe(this,i),ElementwiseMul:(i,o)=>new je(this,i,o),Warp:(i,o,n)=>new qe(this,i,o,n),Stabilize:(i,o,n,s,p)=>new Ke(this,i,o,n,s,p),BilinearUpsample:(i,o)=>new Ye(this,i,o),Crop:(i,o)=>new Qe(this,i,o),BicubicUpsample:(i,o)=>new Je(this,i,o),ChannelConcat:(i,o)=>new Ze(this,i,o),Conv2dAdd:(i,o,n,s)=>new ot(this,i,o,n,s),ProjResidual:(i,o,n,s)=>new it(this,i,o,n,s),ConcatConv2d:(i,o,n,s)=>new at(this,i,o,n,s),GatesFused:(i,o,n)=>new nt(this,i,o,n),CandUpdateFused:(i,o,n,s,p)=>new st(this,i,o,n,s,p),ConvExpand:(i,o)=>new ut(this,i,o),CatConv6to2:(i,o,n)=>new pt(this,i,o,n),DownAdapter:(i,o,n,s)=>new lt(this,i,o,n,s),UpFinal:(i,o,n)=>new ct(this,i,o,n),UpFinalSkip:(i,o,n,s)=>new dt(this,i,o,n,s),UpsampleConcat:(i,o,n)=>new tt(this,i,o,n),UpsampleConv1x1:(i,o,n)=>new rt(this,i,o,n),UpsampleSigmoid:(i,o)=>new et(this,i,o),Input:(i,o)=>new gt(this,i,o)},this.presenters={CompositeSolid:(i,o,n)=>new mt(this,i,o,n),CompositeImage:(i,o,n)=>new ft(this,i,o,n),CompositeImageBilinear:(i,o,n)=>new ht(this,i,o,n),CompositePassthrough:i=>new _t(this,i)}}static isAvailable(){let t=null;try{return t=new OffscreenCanvas(1,1).getContext("webgl2"),!(!t||!t.getExtension("EXT_color_buffer_float"))}catch{return!1}finally{t?.getExtension("WEBGL_lose_context")?.loseContext()}}static create(t){let r=t.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 u(r,t.canvas,t.dtype??"f32")}attachCanvas(t){throw new Error(\`WebGLBackend.attachCanvas('\${t}'): WebGL cannot render to a second canvas; use the renderer's snapshot-and-present path for preview output\`)}bindDisplayFramebuffer(){this.gl.bindFramebuffer(this.gl.FRAMEBUFFER,null),this.gl.viewport(0,0,this.canvas.width,this.canvas.height)}toTextureView(t){if(t===null)return null;let r=this.dtype==="f16",e=t instanceof Uint16Array;return r===e?t:r?pe(t):A(t)}tensor(t,r,e,i){let o=r*(e/4),n=t,s=this.gl,p=s.createTexture(),l=this.textureFormat,c=this.toTextureView(i??null);return s.bindTexture(s.TEXTURE_2D,p),s.texImage2D(s.TEXTURE_2D,0,l.internalFormat,o,n,0,l.format,l.type,c),s.texParameteri(s.TEXTURE_2D,s.TEXTURE_MIN_FILTER,s.NEAREST),s.texParameteri(s.TEXTURE_2D,s.TEXTURE_MAG_FILTER,s.NEAREST),s.texParameteri(s.TEXTURE_2D,s.TEXTURE_WRAP_S,s.CLAMP_TO_EDGE),s.texParameteri(s.TEXTURE_2D,s.TEXTURE_WRAP_T,s.CLAMP_TO_EDGE),{h:t,w:r,c:e,texture:p,texW:o,texH:n}}upload(t){return{data:t}}async readback(t){let r=this.gl,e=this.textureFormat;if(r.bindFramebuffer(r.FRAMEBUFFER,this.fbo),r.framebufferTexture2D(r.FRAMEBUFFER,r.COLOR_ATTACHMENT0,r.TEXTURE_2D,t.texture,0),this.dtype==="f16"){let o=new Uint16Array(t.texW*t.texH*4);return r.readPixels(0,0,t.texW,t.texH,e.format,r.HALF_FLOAT,o),r.bindFramebuffer(r.FRAMEBUFFER,null),A(o)}let i=new Float32Array(t.texW*t.texH*4);return r.readPixels(0,0,t.texW,t.texH,e.format,r.FLOAT,i),r.bindFramebuffer(r.FRAMEBUFFER,null),i}copyTensor(t,r){if(t.texW!==r.texW||t.texH!==r.texH)throw new Error(\`copyTensor: size mismatch (src \${t.texW}\\xD7\${t.texH} vs dst \${r.texW}\\xD7\${r.texH})\`);let e=this.gl;e.bindFramebuffer(e.FRAMEBUFFER,this.fbo),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,t.texture,0),e.bindTexture(e.TEXTURE_2D,r.texture),e.copyTexSubImage2D(e.TEXTURE_2D,0,0,0,0,0,t.texW,t.texH),e.bindFramebuffer(e.FRAMEBUFFER,null)}async sync(){let t=this.gl,r=t.fenceSync(t.SYNC_GPU_COMMANDS_COMPLETE,0);if(!r){t.finish();return}for(t.flush();;){let e=t.clientWaitSync(r,0,0);if(e===t.ALREADY_SIGNALED||e===t.CONDITION_SATISFIED){t.deleteSync(r);return}if(e===t.WAIT_FAILED)throw t.deleteSync(r),new Error("WebGLBackend.sync: clientWaitSync returned WAIT_FAILED");await new Promise(i=>setTimeout(i,1))}}destroy(){this.gl.deleteFramebuffer(this.fbo),this.gl.getExtension("WEBGL_lose_context")?.loseContext()}};var Tt=S("setup_backend");async function yo(u,t,r={}){let e=u.backend==="webgpu"||u.backend==="auto",i=!!u.outputCanvas,o=()=>u.outputCanvas??new OffscreenCanvas(t.w,t.h),n=null;if(e&&await R.isAvailable()){let p=u.dtype==="f16"&&!await R.hasF16Support()?"f32":u.dtype,l=o();try{let c=await R.create({canvas:l,dtype:p});return c.device.lost.then(d=>{d.reason!=="destroyed"&&r.onContextLost?.({message:\`WebGPU device lost: \${d.reason}\${d.message?" \\u2014 "+d.message:""}\`,source:"backend-lost",recoverable:!1,cause:d})}).catch(()=>{}),{backend:c,resolvedBackend:"webgpu",resolvedDtype:p,canvas:l}}catch(c){Tt.warn("WebGPU isAvailable but create() threw; trying WebGL fallback:",c),n=c,i&&Tt.warn("transfer-capture topology: WebGL fallback may also fail on the same canvas")}}if(F.isAvailable()){let p=o();try{let l=F.create({canvas:p,dtype:u.dtype});return p.addEventListener("webglcontextlost",c=>{r.onContextLost?.({message:"WebGL context lost",source:"backend-lost",recoverable:!1,cause:c})}),{backend:l,resolvedBackend:"webgl",resolvedDtype:u.dtype,canvas:p}}catch(l){Tt.warn("WebGL create() threw:",l),n=l}}let s=n?\` (last error: \${n.message??n})\`:"";throw new Error(\`setup_backend: no usable GPU backend\${s}\`)}var wo=.5,Na=3,ko=10,$a=30,E=S("autotune");async function To(u,t=$a){let r=u instanceof F?wo*.5:wo,e=1e3/t*r;E(\`start; budget per source frame: \${e.toFixed(1)}ms (source \${t}fps \\xD7 \${r} safety)\`),E("backend dtype:",u.dtype);let i=null;for(let o of yt){if(!O[o.model]){E("skip",o.model,"(no TIER_CONFIG entry)");continue}try{let n=O[o.model].baseRes;E(\`bench \${o.model} base @ \${n.w}\\xD7\${n.h} skipFrames=\${o.skipFrames} \\u2026\`);let s=await qa(u,o),p=s<=e;if(E(\` \${o.model}: \${s.toFixed(1)}ms / source frame \${p?"\\u2713 within budget":"\\u2717 over budget"}\`),(p||i===null)&&(i=o),!p)break}catch(n){E(" bench failed for",o.model,":",n);break}}if(!i)throw new Error("autotune: no implementable preset available");return E("picked",i.model),i}function Xa(u){let t=Object.create(u);return t.ops={...u.ops,Conv2d:(r,e,i)=>{let o={weights:new Float32Array(i.kernel*i.kernel*r.c*i.outChannels),bias:new Float32Array(i.outChannels)};return u.ops.Conv2d(r,o,i)},DepthwiseConv2d:(r,e,i)=>{let o={weights:new Float32Array(i.kernel*i.kernel*r.c),bias:new Float32Array(r.c)};return u.ops.DepthwiseConv2d(r,o,i)},Conv2dAdd:(r,e,i,o)=>{let n={weights:new Float32Array(o.kernel*o.kernel*r.c*o.outChannels),bias:new Float32Array(o.outChannels)};return u.ops.Conv2dAdd(r,e,n,o)},UpsampleConv1x1:(r,e,i)=>{let o={weights:new Float32Array(r.c*i.outChannels),bias:new Float32Array(i.outChannels)};return u.ops.UpsampleConv1x1(r,o,i)},ProjResidual:(r,e,i,o)=>{let n={weights:new Float32Array(r.c*o.outChannels),bias:new Float32Array(o.outChannels)};return u.ops.ProjResidual(r,e,n,o)},ConcatConv2d:(r,e,i,o)=>{let n={weights:new Float32Array(9*(r.c+e.c)*o.outChannels),bias:new Float32Array(o.outChannels)};return u.ops.ConcatConv2d(r,e,n,o)}},t}function ja(){let u=new Proxy({},{get:()=>u});return u}async function qa(u,t){let r=O[t.model];if(!r)throw new Error(\`microbench: no TIER_CONFIG entry for '\${t.model}'\`);let e=r.base,i=Xa(u),o=i.tensor(r.baseRes.h,r.baseRes.w,4),n=new e(i,o,ja());for(let c=0;c<Na;c++)n.run(),await u.sync();let s=t.skipFrames+1,p=performance.now();for(let c=0;c<ko;c++)c%s===0&&n.run();return await u.sync(),(performance.now()-p)/ko}async function Co(u,t,r){let e;if(u==="auto")e=await To(r);else if(typeof u=="string"){let i=q(u);if(!i)throw new Error(\`resolve_preset: unknown preset name '\${u}'\`);e=i}else e=u;return e.dtype!==t?{...e,dtype:t}:e}function Wo(u){let t=null,r=null;return u.onmessage=e=>{let{frame:i}=e.data;if(r){let o=r;r=null,o(i)}else t&&t.close(),t=i},u.start?.(),new ReadableStream({pull(e){if(t){e.enqueue(t),t=null;return}return new Promise(i=>{r=o=>{e.enqueue(o),i()}})},cancel(){t&&(t.close(),t=null),u.close()}},{highWaterMark:0})}function Po(u){switch(u.topology.input){case"mstp":if(!u.inputReadable)throw new Error("create_input: topology.input='mstp' but InitData.inputReadable missing");return u.inputReadable;case"rvfc-postmessage":if(!u.inputPort)throw new Error("create_input: topology.input='rvfc-postmessage' but InitData.inputPort missing");return Wo(u.inputPort)}}function Go(u){return new TransformStream({transform(t,r){u.process(t);let e=new VideoFrame(u.canvas,{timestamp:t.timestamp});t.close(),r.enqueue(e)}})}function Bo(u){return new WritableStream({write(t){u.process(t),t.close()}})}function Uo(u,t){return new WritableStream({write(r){u.process(r),r.close();let e=u.canvas.transferToImageBitmap();t.postMessage({bmp:e},[e])},close(){t.close()}})}var Ka=S("create_output");function So(u,t,r){switch(u.topology.output){case"mstg":{if(!u.outputWritable)throw new Error("create_output: topology.output='mstg' but InitData.outputWritable missing");let e=Go(t);return e.readable.pipeTo(u.outputWritable,{signal:r}).catch(i=>{r.aborted||Ka.warn("mstg downstream pipe failed:",i)}),e.writable}case"transfer-capture":return Bo(t);case"bitmap-shuttle":{if(!u.outputPort)throw new Error("create_output: topology.output='bitmap-shuttle' but InitData.outputPort missing");return Uo(t,u.outputPort)}}}function Lo(u){if(!u.onFirstFrame)return u.input.pipeTo(u.output,{signal:u.signal});let t=!1,r=u.onFirstFrame,e=new TransformStream({transform(i,o){o.enqueue(i),t||(t=!0,queueMicrotask(r))}});return u.input.pipeThrough(e,{signal:u.signal}).pipeTo(u.output,{signal:u.signal})}var W=S("worker");W("script loaded");var P=null,H=null,bt=null;self.onmessage=async function(u){let{cmd:t,data:r,request_id:e}=u.data;W("cmd received:",t,"request_id:",e);try{let i=await Ya(t,r);W("cmd ok:",t),un(e,i)}catch(i){W("cmd FAILED:",t,i),$("error",{message:\`\${t} failed: \${i.message??String(i)}\`,source:"worker",recoverable:!1,cause:i})}};async function Ya(u,t){switch(u){case"init":return Qa(t);case"startRender":return Ja(t.weights);case"setBackground":return Za(t);case"setEnabled":return en(t.enabled);case"setPreset":return an(t);case"getStats":return P?.getStats()??null;case"destroy":return nn();case"attachPreview":return tn(t);case"setPreview":return rn(t);case"clearPreview":return on();default:throw new Error(\`unknown cmd: \${u}\`)}}async function Qa(u){if(Ct(!!u.debug),W("handleInit: start; topology=",u.topology,"preset=",u.preset,"backend=",u.backend,"dtype=",u.dtype),P)throw new Error("handleInit: already initialized");W("handleInit: setupBackend\\u2026");let t=await yo(u,u.canvasSize,{onContextLost:o=>{W("GPU context lost:",o.message),$("error",o)}});W("handleInit: backend ready:",t.resolvedBackend,t.resolvedDtype,"canvas:",t.canvas.width,"x",t.canvas.height),W("handleInit: constructing Renderer (boot mode)\\u2026"),P=new ue({backend:t.backend,backendKind:t.resolvedBackend,canvas:t.canvas,background:u.background,enabled:u.enabled,topology:u.topology}),H=new AbortController,W("handleInit: createInputStream\\u2026");let r=Po(u);W("handleInit: createOutputSink\\u2026");let e=So(u,P,H.signal);W("handleInit: starting pipe (passthrough)\\u2026"),Lo({input:r,output:e,signal:H.signal}).then(()=>{W("pipe completed (input ended)")}).catch(o=>{if(H?.signal.aborted){W("pipe aborted (expected on destroy)");return}W("pipe FAILED:",o),$("error",{message:\`pipe failed: \${o.message}\`,source:"worker",recoverable:!1,cause:o})}),W("handleInit: resolvePreset\\u2026");let i=await Co(u.preset,t.resolvedDtype,t.backend);return W("handleInit: preset resolved:",i),bt=i,W("handleInit: done; returning InitResponse, awaiting startRender"),{resolvedPreset:i,resolvedBackend:t.resolvedBackend,resolvedDtype:t.resolvedDtype}}async function Ja(u){if(W("handleStartRender: start; weights bytes:",u.byteLength),!P||!bt)throw new Error("handleStartRender: handleInit not completed");W("handleStartRender: attaching network via setPreset\\u2026"),P.setPreset(bt,u),W("handleStartRender: ready (effect mode active)"),$("ready",void 0)}async function Za(u){P?.setBackground(u)}async function en(u){P?.setEnabled(u)}async function tn(u){if(!P)throw new Error("handleAttachPreview: not initialized");P.attachPreview(u.canvas)}async function rn(u){if(!P)throw new Error("handleSetPreview: not initialized");P.setPreview(u.background,u.fps!==void 0?{fps:u.fps}:void 0)}async function on(){P?.clearPreview()}async function an(u){if(!P)throw new Error("handleSetPreset: not initialized");if(!u.weights)throw new Error("handleSetPreset: weights required for runtime preset swap");if(u.preset==="auto")throw new Error("handleSetPreset: 'auto' not supported on runtime swap (use at init for autotune)");let t=typeof u.preset=="string"?q(u.preset)??sn(u.preset):u.preset;return P.setPreset(t,u.weights),{resolvedPreset:t}}async function nn(){H?.abort(),H=null,P?.destroy(),P=null,bt=null}function sn(u){throw new Error(\`handleSetPreset: unknown preset '\${u}'\`)}function un(u,t){let r={request_id:u,res:t};self.postMessage(r)}function $(u,t){let r={request_id:u,res:t};self.postMessage(r)}function Vg(u){$("stats",u)}export{Vg as emitStats};
|
|
4353
|
+
`;var y=v("pipeline");function cr(){{let a=new Blob([ge],{type:"application/javascript"}),t=URL.createObjectURL(a),e=new Worker(t,{type:"module"});return URL.revokeObjectURL(t),e}}var dr="https://cdn.longpipe.dev/models/v/0.0.3/",fr={background:"blur",preset:"auto",weightsBaseUrl:dr,audio:"passthrough",enabled:true,adaptive:true,debug:false},Me={w:1280,h:720};function hr(a,t){if(t)return t;let r=a.getVideoTracks()[0]?.getSettings()??{};return {w:r.width||Me.w,h:r.height||Me.h}}function ze(a,t,e){let r=e==="f16"?".f16.bin":".bin";return `${a.replace(/\/$/,"")}/model_${t}${r}`}async function De(a,t,e){if(e==="f16"){let i=await fetch(ze(a,t,"f16"));if(i.ok)return i.arrayBuffer()}let r=ze(a,t,"f32"),n=await fetch(r);if(!n.ok)throw new Error(`weights fetch failed: ${n.status} ${r}`);return n.arrayBuffer()}var _e=class{stream;ready;controller;worker;inputCleanup;outputCleanup;adaptive=null;bgCleanup=null;previewBgCleanup=null;constructor(t,e){let r={...fr,...e};ye(r.debug);let n=Ue(),i=Ge(n.input,t),o=hr(t,r.outputResolution),s=Oe(n.output,o);this.inputCleanup=i.cleanup,this.outputCleanup=s.cleanup,this.stream=We(s.videoTrack,t,r.audio),s.startPassthrough?.(t),this.worker=cr(),this.controller=new A(this.worker),this.ready=new Promise((c,f)=>{this.controller.addPersistentListener("ready",()=>{y("ready handler invoked; resolving .ready"),r.onReady?.(),c();}),this.controller.addPersistentListener("error",h=>{console.error(`[longpipe/pipeline] error (${h.source}):`,h.message),h.recoverable||f(new Error(h.message)),r.onError?.(h);});});let u={topology:n,preset:r.preset,enabled:r.enabled,backend:"auto",dtype:"f16",canvasSize:o,debug:r.debug,...i.initFields,...s.initFields},l=[...i.transferList,...s.transferList];this.bootstrap(u,r.background,l,r.weightsBaseUrl,r.adaptive,r.onError);}async bootstrap(t,e,r,n,i,o){try{y("normalizing background\u2026");let s=await G(e);this.bgCleanup=s.cleanup??null;let u={...t,background:s.background},l=[...r,...s.transferList??[]];y("sending init\u2026");let c=await this.controller.sendMessage("init",u,l);y("init resolved:",c),y("fetching weights:",c.resolvedPreset.model,c.resolvedDtype);let f=await De(n,c.resolvedPreset.model,c.resolvedDtype);y("weights bytes:",f.byteLength),y("sending startRender\u2026"),await this.controller.sendMessage("startRender",{weights:f},[f]),y("startRender resolved; awaiting first frame"),u.preset==="auto"&&i&&(this.adaptive=new S({backendKind:c.resolvedBackend,initialModel:c.resolvedPreset.model,fetchWeights:h=>De(n,h,c.resolvedDtype),getStats:()=>this.getStats(),swapPreset:async(h,x)=>{await this.controller.sendMessage("setPreset",{preset:h,weights:x},[x]);},onError:o}),this.adaptive.start());}catch(s){console.error("[longpipe/pipeline] bootstrap failed:",s),this.controller.handleMessage.call(this.controller,{data:{request_id:"error",res:{message:s.message??String(s),source:"worker",recoverable:false,cause:s}}});}}then(t,e){return this.ready.then(()=>t?t(this):this,e)}async setBackground(t){let e=await G(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});}attachPreview(t){let e=t.transferControlToOffscreen();this.controller.sendMessage("attachPreview",{canvas:e},[e]);}async setPreview(t){let e=await G(t.background),r=this.previewBgCleanup;this.previewBgCleanup=e.cleanup??null,await this.controller.sendMessage("setPreview",{background:e.background,fps:t.fps},e.transferList),r?.();}clearPreview(){this.controller.sendMessage("clearPreview",{}),this.previewBgCleanup?.(),this.previewBgCleanup=null;}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.previewBgCleanup?.(),this.previewBgCleanup=null,this.controller.sendMessage("destroy",{}),this.controller.terminate(),this.inputCleanup(),this.outputCleanup();}};var T=new Float32Array(1),U=new Uint32Array(T.buffer);function gr(a){T[0]=a;let t=U[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 l=r&8388607|8388608,c=14-n,f=l>>>c,h=l>>>c-1&1,x=(l&(1<<c-1)-1)!==0?1:0;return h&&(x||f&1)&&(f+=1),e|f}let i=r>>>13&1023,o=r>>>12&1,s=(r&4095)!==0?1:0,u=n<<10|i;return o&&(s||i&1)&&(u+=1,(u>>>10&31)===31)?e|31744:e|u}function me(a){let t=(a&32768)<<16,e=(a&31744)>>>10,r=a&1023;if(e===0){if(r===0)return U[0]=t,T[0];let n=r,i=1;for(;(n&1024)===0;)n<<=1,i-=1;return n&=1023,U[0]=t|i+127-15<<23|n<<13,T[0]}return e===31?(U[0]=t|2139095040|r<<13,T[0]):(U[0]=t|e+127-15<<23|r<<13,T[0])}function He(a){let t=new Uint16Array(a.length);for(let e=0;e<a.length;e++)t[e]=gr(a[e]);return t}function be(a){let t=new Float32Array(a.length);for(let e=0;e<a.length;e++)t[e]=me(a[e]);return t}var p=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 Re=`// Conv2d, output-channel-blocked (K=2) \u2014 drop-in replacement for conv2d.wgsl.
|
|
3806
4354
|
//
|
|
3807
|
-
// Identical math, layout, and output to conv2d.wgsl, but each thread computes
|
|
3808
|
-
// output channel-groups (
|
|
3809
|
-
//
|
|
3810
|
-
//
|
|
3811
|
-
//
|
|
3812
|
-
//
|
|
3813
|
-
// unchanged. Dispatch ceil(out_groups / 4) in z (see conv2d.ts).
|
|
4355
|
+
// Identical math, layout, and output to conv2d.wgsl, but each thread computes 2
|
|
4356
|
+
// output channel-groups (8 channels) for one pixel, loading each input vec4 ONCE
|
|
4357
|
+
// and reusing it across both groups' mat4x4 weight blocks in registers. Half the
|
|
4358
|
+
// register pressure of the K=4 variant (2 accumulators vs 4). Output is bit-
|
|
4359
|
+
// identical to conv2d.wgsl (\u22641 ULP from FMA contraction). Dispatch
|
|
4360
|
+
// ceil(out_groups / 2) in z (see conv2d.ts).
|
|
3814
4361
|
//
|
|
3815
4362
|
// Tensor layout: NHWC, channels in vec4 groups (same as conv2d.wgsl).
|
|
3816
4363
|
// Weight layout: [K*K][out_groups][in_groups] array of mat4x4 (same as conv2d.wgsl).
|
|
@@ -3827,7 +4374,7 @@ struct Params {
|
|
|
3827
4374
|
stride : u32,
|
|
3828
4375
|
pad_top : u32,
|
|
3829
4376
|
pad_left : u32,
|
|
3830
|
-
activation : u32, // 0 = none, 1 = relu6, 2 = relu
|
|
4377
|
+
activation : u32, // 0 = none, 1 = relu6, 2 = relu, 3 = leaky
|
|
3831
4378
|
}
|
|
3832
4379
|
|
|
3833
4380
|
@group(0) @binding(0) var<storage, read> input_buf : array<vec4<f32>>;
|
|
@@ -3836,18 +4383,19 @@ struct Params {
|
|
|
3836
4383
|
@group(0) @binding(3) var<uniform> params : Params;
|
|
3837
4384
|
@group(0) @binding(4) var<storage, read_write> output_buf : array<vec4<f32>>;
|
|
3838
4385
|
|
|
3839
|
-
const KB =
|
|
4386
|
+
const KB = 2u;
|
|
3840
4387
|
|
|
3841
4388
|
fn act(v: vec4<f32>, a: u32) -> vec4<f32> {
|
|
3842
4389
|
if (a == 1u) { return clamp(v, vec4<f32>(0.0), vec4<f32>(6.0)); }
|
|
3843
4390
|
if (a == 2u) { return max(v, vec4<f32>(0.0)); }
|
|
4391
|
+
if (a == 3u) { return max(v, 0.1 * v); } // leaky relu (slope 0.1)
|
|
3844
4392
|
return v;
|
|
3845
4393
|
}
|
|
3846
4394
|
|
|
3847
4395
|
@compute @workgroup_size(8, 8, 1)
|
|
3848
4396
|
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
3849
|
-
let x = gid.x;
|
|
3850
|
-
let y = gid.y;
|
|
4397
|
+
let x = gid.x; // output column
|
|
4398
|
+
let y = gid.y; // output row
|
|
3851
4399
|
let o0 = gid.z * KB; // first output channel group
|
|
3852
4400
|
|
|
3853
4401
|
if (x >= params.out_w || y >= params.out_h || o0 >= params.out_groups) {
|
|
@@ -3856,19 +4404,13 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
3856
4404
|
|
|
3857
4405
|
let I = params.in_groups;
|
|
3858
4406
|
let O = params.out_groups;
|
|
3859
|
-
// Tail handling when out_groups is
|
|
3860
|
-
//
|
|
4407
|
+
// Tail handling when out_groups is odd: clamp the spare lane to o0 (valid
|
|
4408
|
+
// index, no OOB) and just don't write it.
|
|
3861
4409
|
let has1 = (o0 + 1u) < O;
|
|
3862
|
-
let has2 = (o0 + 2u) < O;
|
|
3863
|
-
let has3 = (o0 + 3u) < O;
|
|
3864
4410
|
let o1 = select(o0, o0 + 1u, has1);
|
|
3865
|
-
let o2 = select(o0, o0 + 2u, has2);
|
|
3866
|
-
let o3 = select(o0, o0 + 3u, has3);
|
|
3867
4411
|
|
|
3868
4412
|
var acc0 = bias_buf[o0];
|
|
3869
4413
|
var acc1 = bias_buf[o1];
|
|
3870
|
-
var acc2 = bias_buf[o2];
|
|
3871
|
-
var acc3 = bias_buf[o3];
|
|
3872
4414
|
|
|
3873
4415
|
for (var ky = 0u; ky < params.kernel_h; ky++) {
|
|
3874
4416
|
for (var kx = 0u; kx < params.kernel_w; kx++) {
|
|
@@ -3884,14 +4426,10 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
3884
4426
|
let inB = u32(in_y_s) * params.in_w * I + u32(in_x_s) * I;
|
|
3885
4427
|
let wb0 = z * O * I + o0 * I;
|
|
3886
4428
|
let wb1 = z * O * I + o1 * I;
|
|
3887
|
-
let wb2 = z * O * I + o2 * I;
|
|
3888
|
-
let wb3 = z * O * I + o3 * I;
|
|
3889
4429
|
for (var i = 0u; i < I; i++) {
|
|
3890
|
-
let iv = input_buf[inB + i]; // loaded ONCE, reused across
|
|
4430
|
+
let iv = input_buf[inB + i]; // loaded ONCE, reused across 2 groups
|
|
3891
4431
|
acc0 += weight_buf[wb0 + i] * iv;
|
|
3892
4432
|
acc1 += weight_buf[wb1 + i] * iv;
|
|
3893
|
-
acc2 += weight_buf[wb2 + i] * iv;
|
|
3894
|
-
acc3 += weight_buf[wb3 + i] * iv;
|
|
3895
4433
|
}
|
|
3896
4434
|
}
|
|
3897
4435
|
}
|
|
@@ -3899,15 +4437,14 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
3899
4437
|
let baseO = y * params.out_w * O + x * O;
|
|
3900
4438
|
output_buf[baseO + o0] = act(acc0, params.activation);
|
|
3901
4439
|
if (has1) { output_buf[baseO + o1] = act(acc1, params.activation); }
|
|
3902
|
-
if (has2) { output_buf[baseO + o2] = act(acc2, params.activation); }
|
|
3903
|
-
if (has3) { output_buf[baseO + o3] = act(acc3, params.activation); }
|
|
3904
4440
|
}
|
|
3905
|
-
`;var
|
|
4441
|
+
`;var Le=`enable f16;
|
|
3906
4442
|
|
|
3907
|
-
// Conv2d, output-channel-blocked (K=
|
|
3908
|
-
// conv2d_f16.wgsl. Each thread computes
|
|
3909
|
-
// loading each input vec4
|
|
3910
|
-
//
|
|
4443
|
+
// Conv2d, output-channel-blocked (K=2) \u2014 full f16. Drop-in replacement for
|
|
4444
|
+
// conv2d_f16.wgsl. Each thread computes 2 output channel-groups for one pixel,
|
|
4445
|
+
// loading each input vec4 ONCE and reusing it across both weight blocks. Half the
|
|
4446
|
+
// register pressure of the K=4 variant (2 accumulators vs 4). Output is bit-
|
|
4447
|
+
// identical to conv2d_f16.wgsl. Dispatch ceil(out_groups / 2) in z.
|
|
3911
4448
|
|
|
3912
4449
|
struct Params {
|
|
3913
4450
|
in_h : u32,
|
|
@@ -3930,11 +4467,12 @@ struct Params {
|
|
|
3930
4467
|
@group(0) @binding(3) var<uniform> params : Params;
|
|
3931
4468
|
@group(0) @binding(4) var<storage, read_write> output_buf : array<vec4<f16>>;
|
|
3932
4469
|
|
|
3933
|
-
const KB =
|
|
4470
|
+
const KB = 2u;
|
|
3934
4471
|
|
|
3935
4472
|
fn act(v: vec4<f16>, a: u32) -> vec4<f16> {
|
|
3936
4473
|
if (a == 1u) { return clamp(v, vec4<f16>(0.0h), vec4<f16>(6.0h)); }
|
|
3937
4474
|
if (a == 2u) { return max(v, vec4<f16>(0.0h)); }
|
|
4475
|
+
if (a == 3u) { return max(v, 0.1h * v); } // leaky relu (slope 0.1)
|
|
3938
4476
|
return v;
|
|
3939
4477
|
}
|
|
3940
4478
|
|
|
@@ -3951,16 +4489,10 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
3951
4489
|
let I = params.in_groups;
|
|
3952
4490
|
let O = params.out_groups;
|
|
3953
4491
|
let has1 = (o0 + 1u) < O;
|
|
3954
|
-
let has2 = (o0 + 2u) < O;
|
|
3955
|
-
let has3 = (o0 + 3u) < O;
|
|
3956
4492
|
let o1 = select(o0, o0 + 1u, has1);
|
|
3957
|
-
let o2 = select(o0, o0 + 2u, has2);
|
|
3958
|
-
let o3 = select(o0, o0 + 3u, has3);
|
|
3959
4493
|
|
|
3960
4494
|
var acc0 = bias_buf[o0];
|
|
3961
4495
|
var acc1 = bias_buf[o1];
|
|
3962
|
-
var acc2 = bias_buf[o2];
|
|
3963
|
-
var acc3 = bias_buf[o3];
|
|
3964
4496
|
|
|
3965
4497
|
for (var ky = 0u; ky < params.kernel_h; ky++) {
|
|
3966
4498
|
for (var kx = 0u; kx < params.kernel_w; kx++) {
|
|
@@ -3976,14 +4508,10 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
3976
4508
|
let inB = u32(in_y_s) * params.in_w * I + u32(in_x_s) * I;
|
|
3977
4509
|
let wb0 = z * O * I + o0 * I;
|
|
3978
4510
|
let wb1 = z * O * I + o1 * I;
|
|
3979
|
-
let wb2 = z * O * I + o2 * I;
|
|
3980
|
-
let wb3 = z * O * I + o3 * I;
|
|
3981
4511
|
for (var i = 0u; i < I; i++) {
|
|
3982
|
-
let iv = input_buf[inB + i];
|
|
4512
|
+
let iv = input_buf[inB + i]; // loaded ONCE, reused across 2 groups
|
|
3983
4513
|
acc0 += weight_buf[wb0 + i] * iv;
|
|
3984
4514
|
acc1 += weight_buf[wb1 + i] * iv;
|
|
3985
|
-
acc2 += weight_buf[wb2 + i] * iv;
|
|
3986
|
-
acc3 += weight_buf[wb3 + i] * iv;
|
|
3987
4515
|
}
|
|
3988
4516
|
}
|
|
3989
4517
|
}
|
|
@@ -3991,10 +4519,156 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
3991
4519
|
let baseO = y * params.out_w * O + x * O;
|
|
3992
4520
|
output_buf[baseO + o0] = act(acc0, params.activation);
|
|
3993
4521
|
if (has1) { output_buf[baseO + o1] = act(acc1, params.activation); }
|
|
3994
|
-
if (has2) { output_buf[baseO + o2] = act(acc2, params.activation); }
|
|
3995
|
-
if (has3) { output_buf[baseO + o3] = act(acc3, params.activation); }
|
|
3996
4522
|
}
|
|
3997
|
-
`;function _(a,t,e,r){return typeof r=="number"?Math.floor((a+2*r-t)/e)+1:r==="same"?Math.ceil(a/e):Math.floor((a-t)/e)+1}function
|
|
4523
|
+
`;function _(a,t,e,r){return typeof r=="number"?Math.floor((a+2*r-t)/e)+1:r==="same"?Math.ceil(a/e):Math.floor((a-t)/e)+1}function ve(a,t,e,r){return (a-1)*e-2*r+t}function br(a,t,e,r){return Math.floor(Math.max((t-1)*r+e-a,0)/2)}function m(a,t,e,r,n){return typeof a=="number"?a:a==="same"?br(t,e,r,n):0}function d(a){return a instanceof Float32Array||a instanceof Uint16Array?a:new Float32Array(a)}function g(a){let t=Math.max(4,Math.ceil(a.length/4)*4),e=new Float32Array(t),r=a instanceof Uint16Array;for(let n=0;n<a.length;n++)e[n]=r?me(a[n]):a[n];return e}var O=class extends p{inputs;weights;output;dispatch;shader;constructor(t,e,r,n){super(t),this.shader=t.dtype==="f16"?Le:Re;let i=_(e.h,n.kernel,n.stride,n.padding),o=_(e.w,n.kernel,n.stride,n.padding),s=e.c/4,u=n.outChannels/4,l=m(n.padding,e.h,i,n.kernel,n.stride),c=m(n.padding,e.w,o,n.kernel,n.stride);this.output=t.tensor(i,o,n.outChannels),this.inputs=[e],this.weights=[t.upload(d(r.weights)),t.upload(d(r.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,i,o,s,u,n.kernel,n.kernel,n.stride,l,c,n.activation==="relu6"?1:n.activation==="relu"?2:n.activation==="leaky"?3:0])),this.defaultSetup(),this.dispatch=[Math.ceil(o/8),Math.ceil(i/8),Math.ceil(u/2)];}};var Ve=`// ConvTranspose2d \u2014 gather form, f32 variant. See conv_transpose2d_f16.wgsl for
|
|
4524
|
+
// the math; this is the f32 storage build (mat4x4<f32>).
|
|
4525
|
+
|
|
4526
|
+
struct Params {
|
|
4527
|
+
in_h : u32,
|
|
4528
|
+
in_w : u32,
|
|
4529
|
+
out_h : u32,
|
|
4530
|
+
out_w : u32,
|
|
4531
|
+
in_groups : u32,
|
|
4532
|
+
out_groups : u32,
|
|
4533
|
+
kernel_h : u32,
|
|
4534
|
+
kernel_w : u32,
|
|
4535
|
+
stride : u32,
|
|
4536
|
+
pad_top : u32,
|
|
4537
|
+
pad_left : u32,
|
|
4538
|
+
activation : u32,
|
|
4539
|
+
}
|
|
4540
|
+
|
|
4541
|
+
@group(0) @binding(0) var<storage, read> input_buf : array<vec4<f32>>;
|
|
4542
|
+
@group(0) @binding(1) var<storage, read> weight_buf : array<mat4x4<f32>>;
|
|
4543
|
+
@group(0) @binding(2) var<storage, read> bias_buf : array<vec4<f32>>;
|
|
4544
|
+
@group(0) @binding(3) var<uniform> params : Params;
|
|
4545
|
+
@group(0) @binding(4) var<storage, read_write> output_buf : array<vec4<f32>>;
|
|
4546
|
+
|
|
4547
|
+
fn act(v: vec4<f32>, a: u32) -> vec4<f32> {
|
|
4548
|
+
if (a == 1u) { return clamp(v, vec4<f32>(0.0), vec4<f32>(6.0)); }
|
|
4549
|
+
if (a == 2u) { return max(v, vec4<f32>(0.0)); }
|
|
4550
|
+
if (a == 3u) { return max(v, 0.1 * v); }
|
|
4551
|
+
return v;
|
|
4552
|
+
}
|
|
4553
|
+
|
|
4554
|
+
@compute @workgroup_size(8, 8, 1)
|
|
4555
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
4556
|
+
let ox = gid.x;
|
|
4557
|
+
let oy = gid.y;
|
|
4558
|
+
let o = gid.z;
|
|
4559
|
+
|
|
4560
|
+
if (ox >= params.out_w || oy >= params.out_h || o >= params.out_groups) {
|
|
4561
|
+
return;
|
|
4562
|
+
}
|
|
4563
|
+
|
|
4564
|
+
let I = params.in_groups;
|
|
4565
|
+
let O = params.out_groups;
|
|
4566
|
+
let s = i32(params.stride);
|
|
4567
|
+
|
|
4568
|
+
var result = bias_buf[o];
|
|
4569
|
+
|
|
4570
|
+
for (var ky = 0u; ky < params.kernel_h; ky++) {
|
|
4571
|
+
for (var kx = 0u; kx < params.kernel_w; kx++) {
|
|
4572
|
+
let iy_num = i32(oy) + i32(params.pad_top) - i32(ky);
|
|
4573
|
+
let ix_num = i32(ox) + i32(params.pad_left) - i32(kx);
|
|
4574
|
+
if (iy_num < 0 || ix_num < 0 || (iy_num % s) != 0 || (ix_num % s) != 0) {
|
|
4575
|
+
continue;
|
|
4576
|
+
}
|
|
4577
|
+
let iy = iy_num / s;
|
|
4578
|
+
let ix = ix_num / s;
|
|
4579
|
+
if (iy >= i32(params.in_h) || ix >= i32(params.in_w)) {
|
|
4580
|
+
continue;
|
|
4581
|
+
}
|
|
4582
|
+
|
|
4583
|
+
let z = ky * params.kernel_w + kx;
|
|
4584
|
+
for (var i = 0u; i < I; i++) {
|
|
4585
|
+
let in_idx = u32(iy) * params.in_w * I + u32(ix) * I + i;
|
|
4586
|
+
let w_idx = z * O * I + o * I + i;
|
|
4587
|
+
result += weight_buf[w_idx] * input_buf[in_idx];
|
|
4588
|
+
}
|
|
4589
|
+
}
|
|
4590
|
+
}
|
|
4591
|
+
|
|
4592
|
+
output_buf[oy * params.out_w * O + ox * O + o] = act(result, params.activation);
|
|
4593
|
+
}
|
|
4594
|
+
`;var Ne=`enable f16;
|
|
4595
|
+
|
|
4596
|
+
// ConvTranspose2d \u2014 gather form, full f16 variant.
|
|
4597
|
+
// Each output (oy,ox) sums every input pixel + kernel tap that maps onto it:
|
|
4598
|
+
// iy = (oy + pad - ky) / stride (must divide evenly and be in bounds)
|
|
4599
|
+
// No explicit kernel flip \u2014 the (oy + pad - ky) indexing carries it.
|
|
4600
|
+
// Weight layout is IDENTICAL to conv2d (mat4x4[z][o][i], M[in_sub][out_sub] =
|
|
4601
|
+
// W(in, out, ky, kx)), so the op uploads the flat buffer unchanged.
|
|
4602
|
+
|
|
4603
|
+
struct Params {
|
|
4604
|
+
in_h : u32,
|
|
4605
|
+
in_w : u32,
|
|
4606
|
+
out_h : u32,
|
|
4607
|
+
out_w : u32,
|
|
4608
|
+
in_groups : u32,
|
|
4609
|
+
out_groups : u32,
|
|
4610
|
+
kernel_h : u32,
|
|
4611
|
+
kernel_w : u32,
|
|
4612
|
+
stride : u32,
|
|
4613
|
+
pad_top : u32,
|
|
4614
|
+
pad_left : u32,
|
|
4615
|
+
activation : u32,
|
|
4616
|
+
}
|
|
4617
|
+
|
|
4618
|
+
@group(0) @binding(0) var<storage, read> input_buf : array<vec4<f16>>;
|
|
4619
|
+
@group(0) @binding(1) var<storage, read> weight_buf : array<mat4x4<f16>>;
|
|
4620
|
+
@group(0) @binding(2) var<storage, read> bias_buf : array<vec4<f16>>;
|
|
4621
|
+
@group(0) @binding(3) var<uniform> params : Params;
|
|
4622
|
+
@group(0) @binding(4) var<storage, read_write> output_buf : array<vec4<f16>>;
|
|
4623
|
+
|
|
4624
|
+
fn act(v: vec4<f16>, a: u32) -> vec4<f16> {
|
|
4625
|
+
if (a == 1u) { return clamp(v, vec4<f16>(0.0h), vec4<f16>(6.0h)); }
|
|
4626
|
+
if (a == 2u) { return max(v, vec4<f16>(0.0h)); }
|
|
4627
|
+
if (a == 3u) { return max(v, 0.1h * v); }
|
|
4628
|
+
return v;
|
|
4629
|
+
}
|
|
4630
|
+
|
|
4631
|
+
@compute @workgroup_size(8, 8, 1)
|
|
4632
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
4633
|
+
let ox = gid.x;
|
|
4634
|
+
let oy = gid.y;
|
|
4635
|
+
let o = gid.z;
|
|
4636
|
+
|
|
4637
|
+
if (ox >= params.out_w || oy >= params.out_h || o >= params.out_groups) {
|
|
4638
|
+
return;
|
|
4639
|
+
}
|
|
4640
|
+
|
|
4641
|
+
let I = params.in_groups;
|
|
4642
|
+
let O = params.out_groups;
|
|
4643
|
+
let s = i32(params.stride);
|
|
4644
|
+
|
|
4645
|
+
var result = bias_buf[o];
|
|
4646
|
+
|
|
4647
|
+
for (var ky = 0u; ky < params.kernel_h; ky++) {
|
|
4648
|
+
for (var kx = 0u; kx < params.kernel_w; kx++) {
|
|
4649
|
+
let iy_num = i32(oy) + i32(params.pad_top) - i32(ky);
|
|
4650
|
+
let ix_num = i32(ox) + i32(params.pad_left) - i32(kx);
|
|
4651
|
+
if (iy_num < 0 || ix_num < 0 || (iy_num % s) != 0 || (ix_num % s) != 0) {
|
|
4652
|
+
continue;
|
|
4653
|
+
}
|
|
4654
|
+
let iy = iy_num / s;
|
|
4655
|
+
let ix = ix_num / s;
|
|
4656
|
+
if (iy >= i32(params.in_h) || ix >= i32(params.in_w)) {
|
|
4657
|
+
continue;
|
|
4658
|
+
}
|
|
4659
|
+
|
|
4660
|
+
let z = ky * params.kernel_w + kx;
|
|
4661
|
+
for (var i = 0u; i < I; i++) {
|
|
4662
|
+
let in_idx = u32(iy) * params.in_w * I + u32(ix) * I + i;
|
|
4663
|
+
let w_idx = z * O * I + o * I + i;
|
|
4664
|
+
result += weight_buf[w_idx] * input_buf[in_idx];
|
|
4665
|
+
}
|
|
4666
|
+
}
|
|
4667
|
+
}
|
|
4668
|
+
|
|
4669
|
+
output_buf[oy * params.out_w * O + ox * O + o] = act(result, params.activation);
|
|
4670
|
+
}
|
|
4671
|
+
`;var M=class extends p{inputs;weights;output;dispatch;shader;constructor(t,e,r,n){super(t),this.shader=t.dtype==="f16"?Ne:Ve;let i=ve(e.h,n.kernel,n.stride,n.padding),o=ve(e.w,n.kernel,n.stride,n.padding),s=e.c/4,u=n.outChannels/4;this.output=t.tensor(i,o,n.outChannels),this.inputs=[e],this.weights=[t.upload(d(r.weights)),t.upload(d(r.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,i,o,s,u,n.kernel,n.kernel,n.stride,n.padding,n.padding,n.activation==="relu6"?1:n.activation==="relu"?2:n.activation==="leaky"?3:0])),this.defaultSetup(),this.dispatch=[Math.ceil(o/8),Math.ceil(i/8),u];}};var $e=`// Depthwise Conv2d \u2014 groups = in_channels (each channel convolved independently).
|
|
3998
4672
|
//
|
|
3999
4673
|
// Weight layout: [K*K][channel_groups] array of vec4
|
|
4000
4674
|
// weight index = (ky*kernel_w + kx) * channel_groups + c
|
|
@@ -4069,7 +4743,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4069
4743
|
let out_idx = y * params.out_w * C + x * C + c;
|
|
4070
4744
|
output_buf[out_idx] = result;
|
|
4071
4745
|
}
|
|
4072
|
-
`;var
|
|
4746
|
+
`;var je=`enable f16;
|
|
4073
4747
|
|
|
4074
4748
|
// Depthwise conv2d \u2014 full f16 variant. All buffers f16.
|
|
4075
4749
|
|
|
@@ -4134,7 +4808,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4134
4808
|
|
|
4135
4809
|
output_buf[y * params.out_w * C + x * C + c] = result;
|
|
4136
4810
|
}
|
|
4137
|
-
`;var z=class extends p{inputs;weights;output;dispatch;shader;constructor(t,e,r,n){super(t),this.shader=t.dtype==="f16"?
|
|
4811
|
+
`;var z=class extends p{inputs;weights;output;dispatch;shader;constructor(t,e,r,n){super(t),this.shader=t.dtype==="f16"?je:$e;let i=_(e.h,n.kernel,n.stride,n.padding),o=_(e.w,n.kernel,n.stride,n.padding),s=e.c/4,u=m(n.padding,e.h,i,n.kernel,n.stride),l=m(n.padding,e.w,o,n.kernel,n.stride);this.output=t.tensor(i,o,e.c),this.inputs=[e],this.weights=[t.upload(d(r.weights)),t.upload(d(r.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,i,o,s,n.kernel,n.kernel,n.stride,u,l,n.activation==="relu6"?1:0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(o/8),Math.ceil(i/8),s];}};var qe=`// Element-wise add of two tensors \u2014 used for residual connections in MBConv blocks.
|
|
4138
4812
|
// Operates on the flat float buffer directly; layout is irrelevant for a pure element-wise op.
|
|
4139
4813
|
|
|
4140
4814
|
struct Params {
|
|
@@ -4155,7 +4829,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4155
4829
|
if (idx >= params.size) { return; }
|
|
4156
4830
|
output[idx] = input_a[idx] + input_b[idx];
|
|
4157
4831
|
}
|
|
4158
|
-
`;var
|
|
4832
|
+
`;var Xe=`enable f16;
|
|
4159
4833
|
|
|
4160
4834
|
// Element-wise add \u2014 full f16 variant.
|
|
4161
4835
|
// array<f16> is binary-compatible with array<vec4<f16>> written by the f16 conv shaders.
|
|
@@ -4178,7 +4852,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4178
4852
|
if (idx >= params.size) { return; }
|
|
4179
4853
|
output[idx] = input_a[idx] + input_b[idx];
|
|
4180
4854
|
}
|
|
4181
|
-
`;var D=class extends p{inputs;weights=[];output;dispatch;shader;constructor(t,e,r){super(t),this.shader=t.dtype==="f16"?
|
|
4855
|
+
`;var D=class extends p{inputs;weights=[];output;dispatch;shader;constructor(t,e,r){super(t),this.shader=t.dtype==="f16"?Xe:qe;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 Ke=`// Element-wise sigmoid: output = 1 / (1 + exp(-x)).
|
|
4182
4856
|
// Operates on packed vec4 buffers (NHWC layout). exp() and arithmetic are element-wise on vec4.
|
|
4183
4857
|
|
|
4184
4858
|
struct Params {
|
|
@@ -4198,7 +4872,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4198
4872
|
if (idx >= params.n_groups) { return; }
|
|
4199
4873
|
output_buf[idx] = 1.0 / (1.0 + exp(-input_buf[idx]));
|
|
4200
4874
|
}
|
|
4201
|
-
`;var
|
|
4875
|
+
`;var Ye=`enable f16;
|
|
4202
4876
|
|
|
4203
4877
|
// Sigmoid \u2014 full f16 variant.
|
|
4204
4878
|
|
|
@@ -4220,7 +4894,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4220
4894
|
let x = vec4<f32>(input_buf[idx]);
|
|
4221
4895
|
output_buf[idx] = vec4<f16>(1.0 / (1.0 + exp(-x)));
|
|
4222
4896
|
}
|
|
4223
|
-
`;var
|
|
4897
|
+
`;var H=class extends p{inputs;weights=[];output;dispatch;shader;constructor(t,e){super(t),this.shader=t.dtype==="f16"?Ye:Ke;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 Je=`// Element-wise tanh \u2014 used by ConvGRU candidate activation.
|
|
4224
4898
|
// Operates on packed vec4 buffers (NHWC layout). tanh() is element-wise on vec4.
|
|
4225
4899
|
|
|
4226
4900
|
struct Params {
|
|
@@ -4240,7 +4914,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4240
4914
|
if (idx >= params.n_groups) { return; }
|
|
4241
4915
|
output_buf[idx] = tanh(input_buf[idx]);
|
|
4242
4916
|
}
|
|
4243
|
-
`;var
|
|
4917
|
+
`;var Qe=`enable f16;
|
|
4244
4918
|
|
|
4245
4919
|
// Tanh \u2014 full f16 variant.
|
|
4246
4920
|
|
|
@@ -4262,7 +4936,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4262
4936
|
let x = vec4<f32>(input_buf[idx]);
|
|
4263
4937
|
output_buf[idx] = vec4<f16>(tanh(x));
|
|
4264
4938
|
}
|
|
4265
|
-
`;var
|
|
4939
|
+
`;var R=class extends p{inputs;weights=[];output;dispatch;shader;constructor(t,e){super(t),this.shader=t.dtype==="f16"?Qe:Je;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 Ze=`// Element-wise multiply \u2014 used in ConvGRU for r \u2299 h_prev.
|
|
4266
4940
|
// Same flat-float layout as add.wgsl.
|
|
4267
4941
|
|
|
4268
4942
|
struct Params {
|
|
@@ -4283,7 +4957,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4283
4957
|
if (idx >= params.size) { return; }
|
|
4284
4958
|
output[idx] = input_a[idx] * input_b[idx];
|
|
4285
4959
|
}
|
|
4286
|
-
`;var
|
|
4960
|
+
`;var et=`enable f16;
|
|
4287
4961
|
|
|
4288
4962
|
// Element-wise multiply \u2014 full f16 variant.
|
|
4289
4963
|
// array<f16> is binary-compatible with array<vec4<f16>> written by the f16 conv shaders.
|
|
@@ -4306,7 +4980,208 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4306
4980
|
if (idx >= params.size) { return; }
|
|
4307
4981
|
output[idx] = input_a[idx] * input_b[idx];
|
|
4308
4982
|
}
|
|
4309
|
-
`;var L=class extends p{inputs;weights=[];output;dispatch;shader;constructor(t,e,r){super(t),this.shader=t.dtype==="f16"?
|
|
4983
|
+
`;var L=class extends p{inputs;weights=[];output;dispatch;shader;constructor(t,e,r){super(t),this.shader=t.dtype==="f16"?et:Ze;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 tt=`// Bilinear gather-warp (f32). See warp_f16.wgsl for the math.
|
|
4984
|
+
|
|
4985
|
+
struct Params {
|
|
4986
|
+
h : u32,
|
|
4987
|
+
w : u32,
|
|
4988
|
+
flow_scale : f32,
|
|
4989
|
+
}
|
|
4990
|
+
|
|
4991
|
+
@group(0) @binding(0) var<storage, read> source_buf : array<vec4<f32>>;
|
|
4992
|
+
@group(0) @binding(1) var<storage, read> flow_buf : array<vec4<f32>>;
|
|
4993
|
+
@group(0) @binding(2) var<uniform> params : Params;
|
|
4994
|
+
@group(0) @binding(3) var<storage, read_write> output_buf : array<vec4<f32>>;
|
|
4995
|
+
|
|
4996
|
+
fn samp(x: i32, y: i32, W: i32, H: i32) -> vec4<f32> {
|
|
4997
|
+
let cx = clamp(x, 0, W - 1);
|
|
4998
|
+
let cy = clamp(y, 0, H - 1);
|
|
4999
|
+
return source_buf[u32(cy) * u32(W) + u32(cx)];
|
|
5000
|
+
}
|
|
5001
|
+
|
|
5002
|
+
@compute @workgroup_size(8, 8, 1)
|
|
5003
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
5004
|
+
let x = gid.x;
|
|
5005
|
+
let y = gid.y;
|
|
5006
|
+
if (x >= params.w || y >= params.h) { return; }
|
|
5007
|
+
|
|
5008
|
+
let W = i32(params.w);
|
|
5009
|
+
let H = i32(params.h);
|
|
5010
|
+
let idx = y * params.w + x;
|
|
5011
|
+
|
|
5012
|
+
let f = flow_buf[idx].xy;
|
|
5013
|
+
let sx = clamp(f32(x) + params.flow_scale * f.x, 0.0, f32(W - 1));
|
|
5014
|
+
let sy = clamp(f32(y) + params.flow_scale * f.y, 0.0, f32(H - 1));
|
|
5015
|
+
|
|
5016
|
+
let x0 = i32(floor(sx));
|
|
5017
|
+
let y0 = i32(floor(sy));
|
|
5018
|
+
let tx = sx - f32(x0);
|
|
5019
|
+
let ty = sy - f32(y0);
|
|
5020
|
+
|
|
5021
|
+
let top = mix(samp(x0, y0, W, H), samp(x0 + 1, y0, W, H), tx);
|
|
5022
|
+
let bot = mix(samp(x0, y0 + 1, W, H), samp(x0 + 1, y0 + 1, W, H), tx);
|
|
5023
|
+
output_buf[idx] = mix(top, bot, ty);
|
|
5024
|
+
}
|
|
5025
|
+
`;var rt=`enable f16;
|
|
5026
|
+
|
|
5027
|
+
// Bilinear gather-warp (f16 storage, f32 coordinate math). For each output pixel
|
|
5028
|
+
// p, sample the source at p + flow_scale\xB7flow[p].xy and bilinearly interpolate,
|
|
5029
|
+
// clamping the sample to the edge (border-replicate). Source + flow are 4-ch
|
|
5030
|
+
// (1 group), same resolution; flow vector is in .xy.
|
|
5031
|
+
|
|
5032
|
+
struct Params {
|
|
5033
|
+
h : u32,
|
|
5034
|
+
w : u32,
|
|
5035
|
+
flow_scale : f32,
|
|
5036
|
+
}
|
|
5037
|
+
|
|
5038
|
+
@group(0) @binding(0) var<storage, read> source_buf : array<vec4<f16>>;
|
|
5039
|
+
@group(0) @binding(1) var<storage, read> flow_buf : array<vec4<f16>>;
|
|
5040
|
+
@group(0) @binding(2) var<uniform> params : Params;
|
|
5041
|
+
@group(0) @binding(3) var<storage, read_write> output_buf : array<vec4<f16>>;
|
|
5042
|
+
|
|
5043
|
+
fn samp(x: i32, y: i32, W: i32, H: i32) -> vec4<f32> {
|
|
5044
|
+
let cx = clamp(x, 0, W - 1);
|
|
5045
|
+
let cy = clamp(y, 0, H - 1);
|
|
5046
|
+
return vec4<f32>(source_buf[u32(cy) * u32(W) + u32(cx)]);
|
|
5047
|
+
}
|
|
5048
|
+
|
|
5049
|
+
@compute @workgroup_size(8, 8, 1)
|
|
5050
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
5051
|
+
let x = gid.x;
|
|
5052
|
+
let y = gid.y;
|
|
5053
|
+
if (x >= params.w || y >= params.h) { return; }
|
|
5054
|
+
|
|
5055
|
+
let W = i32(params.w);
|
|
5056
|
+
let H = i32(params.h);
|
|
5057
|
+
let idx = y * params.w + x;
|
|
5058
|
+
|
|
5059
|
+
let f = vec2<f32>(flow_buf[idx].xy);
|
|
5060
|
+
let sx = clamp(f32(x) + params.flow_scale * f.x, 0.0, f32(W - 1));
|
|
5061
|
+
let sy = clamp(f32(y) + params.flow_scale * f.y, 0.0, f32(H - 1));
|
|
5062
|
+
|
|
5063
|
+
let x0 = i32(floor(sx));
|
|
5064
|
+
let y0 = i32(floor(sy));
|
|
5065
|
+
let tx = sx - f32(x0);
|
|
5066
|
+
let ty = sy - f32(y0);
|
|
5067
|
+
|
|
5068
|
+
let top = mix(samp(x0, y0, W, H), samp(x0 + 1, y0, W, H), tx);
|
|
5069
|
+
let bot = mix(samp(x0, y0 + 1, W, H), samp(x0 + 1, y0 + 1, W, H), tx);
|
|
5070
|
+
output_buf[idx] = vec4<f16>(mix(top, bot, ty));
|
|
5071
|
+
}
|
|
5072
|
+
`;var V=class extends p{inputs;weights=[];output;dispatch;shader;constructor(t,e,r,n){super(t),this.shader=t.dtype==="f16"?rt:tt,this.output=t.tensor(e.h,e.w,e.c),this.inputs=[e,r],this.createUniform("params","Params");let i=new Uint32Array(3);i[0]=e.h,i[1]=e.w,new Float32Array(i.buffer)[2]=n.flowScale,this.setUniform("params",i),this.defaultSetup(),this.dispatch=[Math.ceil(e.w/8),Math.ceil(e.h/8),1];}};var nt=`// Flow-gated temporal stabilizer (f32). See stabilize_f16.wgsl for the math.
|
|
5073
|
+
|
|
5074
|
+
struct Params {
|
|
5075
|
+
h : u32,
|
|
5076
|
+
w : u32,
|
|
5077
|
+
t_lo : f32,
|
|
5078
|
+
t_hi : f32,
|
|
5079
|
+
leak : f32,
|
|
5080
|
+
release : f32,
|
|
5081
|
+
t_div : f32,
|
|
5082
|
+
div_scale: f32,
|
|
5083
|
+
step_x : u32,
|
|
5084
|
+
step_y : u32,
|
|
5085
|
+
}
|
|
5086
|
+
|
|
5087
|
+
@group(0) @binding(0) var<storage, read> flow_buf : array<vec4<f32>>;
|
|
5088
|
+
@group(0) @binding(1) var<storage, read> pred_buf : array<vec4<f32>>;
|
|
5089
|
+
@group(0) @binding(2) var<storage, read> ref_buf : array<vec4<f32>>;
|
|
5090
|
+
@group(0) @binding(3) var<storage, read> env_prev_buf : array<vec4<f32>>;
|
|
5091
|
+
@group(0) @binding(4) var<uniform> params : Params;
|
|
5092
|
+
@group(0) @binding(5) var<storage, read_write> output_buf : array<vec4<f32>>;
|
|
5093
|
+
|
|
5094
|
+
@compute @workgroup_size(8, 8, 1)
|
|
5095
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
5096
|
+
let x = gid.x;
|
|
5097
|
+
let y = gid.y;
|
|
5098
|
+
if (x >= params.w || y >= params.h) { return; }
|
|
5099
|
+
let idx = y * params.w + x;
|
|
5100
|
+
|
|
5101
|
+
let mag = length(flow_buf[idx].xy);
|
|
5102
|
+
let env_prev = env_prev_buf[idx].y;
|
|
5103
|
+
let env = max(mag, params.release * env_prev);
|
|
5104
|
+
|
|
5105
|
+
let xr = min(x + params.step_x, params.w - 1u);
|
|
5106
|
+
let xl = select(x - params.step_x, 0u, x < params.step_x);
|
|
5107
|
+
let yd = min(y + params.step_y, params.h - 1u);
|
|
5108
|
+
let yu = select(y - params.step_y, 0u, y < params.step_y);
|
|
5109
|
+
let dfx = flow_buf[y * params.w + xr].x - flow_buf[y * params.w + xl].x;
|
|
5110
|
+
let dfy = flow_buf[yd * params.w + x].y - flow_buf[yu * params.w + x].y;
|
|
5111
|
+
let divg = abs(dfx + dfy);
|
|
5112
|
+
|
|
5113
|
+
let g_mag = clamp((env - params.t_lo) / max(params.t_hi - params.t_lo, 1e-3), 0.0, 1.0);
|
|
5114
|
+
let g_div = clamp((divg - params.t_div) / max(params.div_scale, 1e-3), 0.0, 1.0);
|
|
5115
|
+
let g = max(max(g_mag, g_div), params.leak);
|
|
5116
|
+
|
|
5117
|
+
let pred = pred_buf[idx].x;
|
|
5118
|
+
let refv = ref_buf[idx].x;
|
|
5119
|
+
let stab = g * pred + (1.0 - g) * refv;
|
|
5120
|
+
|
|
5121
|
+
output_buf[idx] = vec4<f32>(stab, env, 0.0, 0.0);
|
|
5122
|
+
}
|
|
5123
|
+
`;var at=`enable f16;
|
|
5124
|
+
|
|
5125
|
+
// Flow-gated temporal stabilizer (f16 storage, f32 gate math). Per pixel:
|
|
5126
|
+
// env = max(|flow.xy|, release\xB7envPrev.y) peak-hold (fast attack, slow release)
|
|
5127
|
+
// div = |\u2202fx/\u2202x + \u2202fy/\u2202y| flow divergence (occlusion seam)
|
|
5128
|
+
// g = max(clamp((env-tLo)/(tHi-tLo),0,1), clamp((div-tDiv)/divScale,0,1), leak)
|
|
5129
|
+
// out = vec4((g\xB7pred + (1-g)\xB7ref).x, env, 0, 0)
|
|
5130
|
+
// The divergence term opens the gate at occlusion/disocclusion boundaries (where
|
|
5131
|
+
// the flow tears but the revealed-background magnitude is ~0). Finite-difference
|
|
5132
|
+
// step spans ~1 base/4 pixel. alpha is in .x of pred/ref; env threads via .y.
|
|
5133
|
+
|
|
5134
|
+
struct Params {
|
|
5135
|
+
h : u32,
|
|
5136
|
+
w : u32,
|
|
5137
|
+
t_lo : f32,
|
|
5138
|
+
t_hi : f32,
|
|
5139
|
+
leak : f32,
|
|
5140
|
+
release : f32,
|
|
5141
|
+
t_div : f32,
|
|
5142
|
+
div_scale: f32,
|
|
5143
|
+
step_x : u32,
|
|
5144
|
+
step_y : u32,
|
|
5145
|
+
}
|
|
5146
|
+
|
|
5147
|
+
@group(0) @binding(0) var<storage, read> flow_buf : array<vec4<f16>>;
|
|
5148
|
+
@group(0) @binding(1) var<storage, read> pred_buf : array<vec4<f16>>;
|
|
5149
|
+
@group(0) @binding(2) var<storage, read> ref_buf : array<vec4<f16>>;
|
|
5150
|
+
@group(0) @binding(3) var<storage, read> env_prev_buf : array<vec4<f16>>;
|
|
5151
|
+
@group(0) @binding(4) var<uniform> params : Params;
|
|
5152
|
+
@group(0) @binding(5) var<storage, read_write> output_buf : array<vec4<f16>>;
|
|
5153
|
+
|
|
5154
|
+
@compute @workgroup_size(8, 8, 1)
|
|
5155
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
5156
|
+
let x = gid.x;
|
|
5157
|
+
let y = gid.y;
|
|
5158
|
+
if (x >= params.w || y >= params.h) { return; }
|
|
5159
|
+
let idx = y * params.w + x;
|
|
5160
|
+
|
|
5161
|
+
let mag = length(vec2<f32>(flow_buf[idx].xy));
|
|
5162
|
+
let env_prev = f32(env_prev_buf[idx].y);
|
|
5163
|
+
let env = max(mag, params.release * env_prev);
|
|
5164
|
+
|
|
5165
|
+
// Flow divergence over a \xB1step finite-difference (clamped to the edges).
|
|
5166
|
+
let xr = min(x + params.step_x, params.w - 1u);
|
|
5167
|
+
let xl = select(x - params.step_x, 0u, x < params.step_x);
|
|
5168
|
+
let yd = min(y + params.step_y, params.h - 1u);
|
|
5169
|
+
let yu = select(y - params.step_y, 0u, y < params.step_y);
|
|
5170
|
+
let dfx = f32(flow_buf[y * params.w + xr].x) - f32(flow_buf[y * params.w + xl].x);
|
|
5171
|
+
let dfy = f32(flow_buf[yd * params.w + x].y) - f32(flow_buf[yu * params.w + x].y);
|
|
5172
|
+
let divg = abs(dfx + dfy);
|
|
5173
|
+
|
|
5174
|
+
let g_mag = clamp((env - params.t_lo) / max(params.t_hi - params.t_lo, 1e-3), 0.0, 1.0);
|
|
5175
|
+
let g_div = clamp((divg - params.t_div) / max(params.div_scale, 1e-3), 0.0, 1.0);
|
|
5176
|
+
let g = max(max(g_mag, g_div), params.leak);
|
|
5177
|
+
|
|
5178
|
+
let pred = f32(pred_buf[idx].x);
|
|
5179
|
+
let refv = f32(ref_buf[idx].x);
|
|
5180
|
+
let stab = g * pred + (1.0 - g) * refv;
|
|
5181
|
+
|
|
5182
|
+
output_buf[idx] = vec4<f16>(f16(stab), f16(env), 0.0h, 0.0h);
|
|
5183
|
+
}
|
|
5184
|
+
`;var N=class extends p{inputs;weights=[];output;dispatch;shader;constructor(t,e,r,n,i,o){super(t),this.shader=t.dtype==="f16"?at:nt,this.output=t.tensor(e.h,e.w,4),this.inputs=[e,r,n,i],this.createUniform("params","Params");let s=new Uint32Array(10);s[0]=e.h,s[1]=e.w;let u=new Float32Array(s.buffer);u[2]=o.tLo,u[3]=o.tHi,u[4]=o.leak,u[5]=o.release,u[6]=o.tDiv,u[7]=o.divScale,s[8]=o.stepX,s[9]=o.stepY,this.setUniform("params",s),this.defaultSetup(),this.dispatch=[Math.ceil(e.w/8),Math.ceil(e.h/8),1];}};var it=`// Bilinear upsample (arbitrary ratio), align_corners=False (matches PyTorch default).
|
|
4310
5185
|
// Input/output in NHWC vec4 format: index = y*W*(C/4) + x*(C/4) + c_group.
|
|
4311
5186
|
// Each thread computes one output pixel for one channel group (vec4 = 4 channels).
|
|
4312
5187
|
|
|
@@ -4364,7 +5239,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4364
5239
|
|
|
4365
5240
|
output_buf[oy * params.out_w * C + ox * C + c] = result;
|
|
4366
5241
|
}
|
|
4367
|
-
`;var
|
|
5242
|
+
`;var ot=`enable f16;
|
|
4368
5243
|
|
|
4369
5244
|
// Bilinear upsample 2\xD7 \u2014 full f16 variant.
|
|
4370
5245
|
// Interpolation weights (wx, wy) and intermediate blends computed in f32 for
|
|
@@ -4420,7 +5295,53 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4420
5295
|
|
|
4421
5296
|
output_buf[oy * params.out_w * C + ox * C + c] = vec4<f16>(result);
|
|
4422
5297
|
}
|
|
4423
|
-
`;var
|
|
5298
|
+
`;var $=class extends p{inputs;weights=[];output;dispatch;shader;constructor(t,e,r){super(t),this.shader=t.dtype==="f16"?ot:it;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 st=`// Top-left crop (f32). See crop_f16.wgsl.
|
|
5299
|
+
|
|
5300
|
+
struct Params {
|
|
5301
|
+
in_w : u32,
|
|
5302
|
+
out_h : u32,
|
|
5303
|
+
out_w : u32,
|
|
5304
|
+
groups : u32,
|
|
5305
|
+
}
|
|
5306
|
+
|
|
5307
|
+
@group(0) @binding(0) var<storage, read> input_buf : array<vec4<f32>>;
|
|
5308
|
+
@group(0) @binding(1) var<uniform> params : Params;
|
|
5309
|
+
@group(0) @binding(2) var<storage, read_write> output_buf : array<vec4<f32>>;
|
|
5310
|
+
|
|
5311
|
+
@compute @workgroup_size(8, 8, 1)
|
|
5312
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
5313
|
+
let x = gid.x;
|
|
5314
|
+
let y = gid.y;
|
|
5315
|
+
let g = gid.z;
|
|
5316
|
+
if (x >= params.out_w || y >= params.out_h || g >= params.groups) { return; }
|
|
5317
|
+
let G = params.groups;
|
|
5318
|
+
output_buf[y * params.out_w * G + x * G + g] = input_buf[y * params.in_w * G + x * G + g];
|
|
5319
|
+
}
|
|
5320
|
+
`;var ut=`enable f16;
|
|
5321
|
+
|
|
5322
|
+
// Top-left crop: output[y,x,g] = input[y,x,g] for y<outH, x<outW (training crop_like).
|
|
5323
|
+
|
|
5324
|
+
struct Params {
|
|
5325
|
+
in_w : u32,
|
|
5326
|
+
out_h : u32,
|
|
5327
|
+
out_w : u32,
|
|
5328
|
+
groups : u32,
|
|
5329
|
+
}
|
|
5330
|
+
|
|
5331
|
+
@group(0) @binding(0) var<storage, read> input_buf : array<vec4<f16>>;
|
|
5332
|
+
@group(0) @binding(1) var<uniform> params : Params;
|
|
5333
|
+
@group(0) @binding(2) var<storage, read_write> output_buf : array<vec4<f16>>;
|
|
5334
|
+
|
|
5335
|
+
@compute @workgroup_size(8, 8, 1)
|
|
5336
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
5337
|
+
let x = gid.x;
|
|
5338
|
+
let y = gid.y;
|
|
5339
|
+
let g = gid.z;
|
|
5340
|
+
if (x >= params.out_w || y >= params.out_h || g >= params.groups) { return; }
|
|
5341
|
+
let G = params.groups;
|
|
5342
|
+
output_buf[y * params.out_w * G + x * G + g] = input_buf[y * params.in_w * G + x * G + g];
|
|
5343
|
+
}
|
|
5344
|
+
`;var j=class extends p{inputs;weights=[];output;dispatch;shader;constructor(t,e,r){super(t),this.shader=t.dtype==="f16"?ut:st;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.w,r.outH,r.outW,n])),this.defaultSetup(),this.dispatch=[Math.ceil(r.outW/8),Math.ceil(r.outH/8),n];}};var pt=`// Bicubic upsample (arbitrary scale) \u2014 Keys cubic, a=-0.75 (PyTorch default
|
|
4424
5345
|
// for mode='bicubic', align_corners=False). Direct 2D, 4\xD74 = 16 taps per
|
|
4425
5346
|
// output pixel. NHWC vec4 layout: index = y*W*(C/4) + x*(C/4) + c_group.
|
|
4426
5347
|
|
|
@@ -4487,7 +5408,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4487
5408
|
|
|
4488
5409
|
output_buf[oy * params.out_w * C + ox * C + c] = acc;
|
|
4489
5410
|
}
|
|
4490
|
-
`;var
|
|
5411
|
+
`;var lt=`enable f16;
|
|
4491
5412
|
|
|
4492
5413
|
// Bicubic upsample \u2014 full f16 storage variant. Bicubic weights and the per-
|
|
4493
5414
|
// pixel accumulator are computed in f32 (cheap to keep precision around the
|
|
@@ -4556,7 +5477,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4556
5477
|
|
|
4557
5478
|
output_buf[oy * params.out_w * C + ox * C + c] = vec4<f16>(acc);
|
|
4558
5479
|
}
|
|
4559
|
-
`;var
|
|
5480
|
+
`;var q=class extends p{inputs;weights=[];output;dispatch;shader;constructor(t,e,r){super(t),this.shader=t.dtype==="f16"?lt:pt;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 ct=`// Channel concatenation: output = cat(A, B, dim=channel).
|
|
4560
5481
|
// Both A and B must share the same H\xD7W and be in NHWC vec4 format.
|
|
4561
5482
|
// Output layout: for each (y, x), the first a_groups vec4s come from A,
|
|
4562
5483
|
// followed by b_groups vec4s from B.
|
|
@@ -4601,7 +5522,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4601
5522
|
output_buf[out_idx] = input_b[y * W * Bg + x * Bg + c_b];
|
|
4602
5523
|
}
|
|
4603
5524
|
}
|
|
4604
|
-
`;var
|
|
5525
|
+
`;var dt=`enable f16;
|
|
4605
5526
|
|
|
4606
5527
|
// Channel concatenation \u2014 full f16 variant.
|
|
4607
5528
|
|
|
@@ -4642,7 +5563,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4642
5563
|
output_buf[out_idx] = input_b[y * W * Bg + x * Bg + c_b];
|
|
4643
5564
|
}
|
|
4644
5565
|
}
|
|
4645
|
-
`;var
|
|
5566
|
+
`;var X=class extends p{inputs;weights=[];output;dispatch;shader;constructor(t,e,r){super(t),this.shader=t.dtype==="f16"?dt:ct;let n=e.c/4,i=r.c/4,o=n+i;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,i,o,0,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(e.w/8),Math.ceil(e.h/8),o];}};var ft=`// Conv2d + skip add fused.
|
|
4646
5567
|
// Identical to conv2d.wgsl except skip is an activation input (binding 1),
|
|
4647
5568
|
// added element-wise to the conv result at write time.
|
|
4648
5569
|
// Eliminates the separate add dispatch and its intermediate buffer round-trip.
|
|
@@ -4716,7 +5637,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4716
5637
|
let out_idx = y * params.out_w * O + x * O + o;
|
|
4717
5638
|
output_buf[out_idx] = result + skip_buf[out_idx];
|
|
4718
5639
|
}
|
|
4719
|
-
`;var
|
|
5640
|
+
`;var ht=`enable f16;
|
|
4720
5641
|
|
|
4721
5642
|
// Conv2d + skip add fused \u2014 full f16 variant.
|
|
4722
5643
|
|
|
@@ -4790,7 +5711,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4790
5711
|
let out_idx = y * params.out_w * O + x * O + o;
|
|
4791
5712
|
output_buf[out_idx] = result + skip_buf[out_idx];
|
|
4792
5713
|
}
|
|
4793
|
-
`;var
|
|
5714
|
+
`;var K=class extends p{inputs;weights;output;dispatch;shader;constructor(t,e,r,n,i){super(t),this.shader=t.dtype==="f16"?ht:ft;let o=_(e.h,i.kernel,i.stride,i.padding),s=_(e.w,i.kernel,i.stride,i.padding),u=e.c/4,l=i.outChannels/4,c=m(i.padding,e.h,o,i.kernel,i.stride),f=m(i.padding,e.w,s,i.kernel,i.stride);this.output=t.tensor(o,s,i.outChannels),this.inputs=[e,r],this.weights=[t.upload(d(n.weights)),t.upload(d(n.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,o,s,u,l,i.kernel,i.kernel,i.stride,c,f,i.activation==="relu6"?1:0])),this.defaultSetup(),this.dispatch=[Math.ceil(s/8),Math.ceil(o/8),l];}};var gt=`// proj_residual: bespoke 1\xD71 conv (no activation) + residual add, fused.
|
|
4794
5715
|
// Specializes conv2d_add to kernel=1 / stride=1 / pad=0 / no activation: drops
|
|
4795
5716
|
// the kernel loop, the padding checks, and the activation branch. Used by the
|
|
4796
5717
|
// MBConv project+residual tail. Both inputs share the same spatial resolution.
|
|
@@ -4835,7 +5756,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4835
5756
|
|
|
4836
5757
|
output_buf[pix * O + o] = result;
|
|
4837
5758
|
}
|
|
4838
|
-
`;var
|
|
5759
|
+
`;var _t=`enable f16;
|
|
4839
5760
|
|
|
4840
5761
|
// proj_residual \u2014 full f16 variant. See proj_residual.wgsl for layout details.
|
|
4841
5762
|
// Bespoke 1\xD71 conv (no activation) + residual add, fused.
|
|
@@ -4877,7 +5798,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4877
5798
|
|
|
4878
5799
|
output_buf[pix * O + o] = result;
|
|
4879
5800
|
}
|
|
4880
|
-
`;var
|
|
5801
|
+
`;var Y=class extends p{inputs;weights;output;dispatch;shader;constructor(t,e,r,n,i){super(t),this.shader=t.dtype==="f16"?_t:gt;let o=e.c/4,s=i.outChannels/4;this.output=t.tensor(e.h,e.w,i.outChannels),this.inputs=[e,r],this.weights=[t.upload(d(n.weights)),t.upload(d(n.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,o,s])),this.defaultSetup(),this.dispatch=[Math.ceil(e.w/8),Math.ceil(e.h/8),s];}};var mt=`// concat_conv2d: fuses [concat(a, b) \u2192 conv 3\xD73 (pad 1) \u2192 relu6] into one
|
|
4881
5802
|
// dispatch. Both inputs are already at the output resolution (the upstream
|
|
4882
5803
|
// upsample stays a separate dispatch writing a clean intermediate, so the conv
|
|
4883
5804
|
// reads are plain-indexed). Identical math to conv2d; the only difference is
|
|
@@ -4937,7 +5858,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4937
5858
|
result = clamp(result, vec4<f32>(0.0), vec4<f32>(6.0));
|
|
4938
5859
|
output_buf[(y * p.w + x) * O + o] = result;
|
|
4939
5860
|
}
|
|
4940
|
-
`;var
|
|
5861
|
+
`;var bt=`enable f16;
|
|
4941
5862
|
|
|
4942
5863
|
// concat_conv2d \u2014 full f16 variant. See concat_conv2d.wgsl for layout details.
|
|
4943
5864
|
// Fuses [concat(a, b) \u2192 conv 3\xD73 (pad 1) \u2192 relu6] into one dispatch.
|
|
@@ -4992,7 +5913,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4992
5913
|
result = clamp(result, vec4<f16>(0.0h), vec4<f16>(6.0h));
|
|
4993
5914
|
output_buf[(y * p.w + x) * O + o] = result;
|
|
4994
5915
|
}
|
|
4995
|
-
`;var
|
|
5916
|
+
`;var J=class extends p{inputs;weights;output;dispatch;shader;constructor(t,e,r,n,i){super(t),this.shader=t.dtype==="f16"?bt:mt;let o=e.c/4,s=r.c/4,u=i.outChannels/4;this.output=t.tensor(e.h,e.w,i.outChannels),this.inputs=[e,r],this.weights=[t.upload(d(n.weights)),t.upload(d(n.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,o,s,u,0,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(e.w/8),Math.ceil(e.h/8),u];}};var vt=`// gates_fused: ConvGRU z + r gates, fused into one dispatch.
|
|
4996
5917
|
// Production config (c_up=2, split_ratio=0.5 \u2192 passthrough=1, recurrent=1):
|
|
4997
5918
|
// u_in : c_up=2 packed in a vec4 (.x = passthrough a, .y = recurrent b)
|
|
4998
5919
|
// h_prev : hidden carrier \u2014 recurrent state in .z (see cand_update_fused: the
|
|
@@ -5037,7 +5958,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5037
5958
|
let r = 1.0 / (1.0 + exp(-r_pre));
|
|
5038
5959
|
output_buf[y * params.w + x] = vec4<f32>(z, r, 0.0, 0.0);
|
|
5039
5960
|
}
|
|
5040
|
-
`;var
|
|
5961
|
+
`;var xt=`enable f16;
|
|
5041
5962
|
|
|
5042
5963
|
// gates_fused \u2014 full f16 variant. See gates_fused.wgsl for layout details.
|
|
5043
5964
|
// ConvGRU z + r gates (production config c_up=2, recurrent=1).
|
|
@@ -5079,7 +6000,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5079
6000
|
let r = 1.0h / (1.0h + exp(-r_pre));
|
|
5080
6001
|
output_buf[y * params.w + x] = vec4<f16>(z, r, 0.0h, 0.0h);
|
|
5081
6002
|
}
|
|
5082
|
-
`;var
|
|
6003
|
+
`;var Q=class extends p{inputs;weights;output;dispatch;shader;constructor(t,e,r,n){super(t),this.shader=t.dtype==="f16"?xt:vt,this.output=t.tensor(e.h,e.w,4),this.inputs=[e,r],this.weights=[t.upload(d(n.weights)),t.upload(g(n.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(e.w/8),Math.ceil(e.h/8),1];}};var wt=`// cand_update_fused: ConvGRU candidate path + state update + output, fused.
|
|
5083
6004
|
// Production config (c_up=2, recurrent=1):
|
|
5084
6005
|
// u_in : c_up=2 (.x = a passthrough, .y = b recurrent)
|
|
5085
6006
|
// h_prev : hidden carrier \u2014 recurrent state in .z (the previous frame's
|
|
@@ -5132,7 +6053,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5132
6053
|
let b_out = u_cur.y + gamma_buf[0].x * h_new;
|
|
5133
6054
|
output_buf[cur] = vec4<f32>(u_cur.x, b_out, h_new, 0.0);
|
|
5134
6055
|
}
|
|
5135
|
-
`;var
|
|
6056
|
+
`;var yt=`enable f16;
|
|
5136
6057
|
|
|
5137
6058
|
// cand_update_fused \u2014 full f16 variant. See cand_update_fused.wgsl for details.
|
|
5138
6059
|
// ConvGRU candidate + state update + output (production config c_up=2, recurrent=1).
|
|
@@ -5178,7 +6099,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5178
6099
|
let b_out = u_cur.y + gamma_buf[0].x * h_new;
|
|
5179
6100
|
output_buf[cur] = vec4<f16>(u_cur.x, b_out, h_new, 0.0h);
|
|
5180
6101
|
}
|
|
5181
|
-
`;var
|
|
6102
|
+
`;var Z=class extends p{inputs;weights;output;dispatch;shader;constructor(t,e,r,n,i,o){super(t),this.shader=t.dtype==="f16"?yt:wt,this.output=t.tensor(e.h,e.w,4),this.inputs=[e,r,n],this.weights=[t.upload(d(i.weights)),t.upload(g(i.bias)),t.upload(g(o))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(e.w/8),Math.ceil(e.h/8),1];}};var kt=`// conv_expand: bespoke N\u21922 conv 3\xD73 (pad 1) + relu (wrapper expand_feat).
|
|
5182
6103
|
// Expands feat_lr (in_c, mult of 4) to the c_up=2 carrier \u2014 output .xy = the 2
|
|
5183
6104
|
// native channels, .zw = 0. mat4x2 per (kpos, in_group) with a vec2 accumulator.
|
|
5184
6105
|
// Weight: 9 * in_groups mat4x2 (8 floats each, col-major). Bias .xy.
|
|
@@ -5215,7 +6136,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5215
6136
|
result = max(result, vec2<f32>(0.0)); // expand_feat is F.relu
|
|
5216
6137
|
output_buf[y * params.w + x] = vec4<f32>(result, 0.0, 0.0);
|
|
5217
6138
|
}
|
|
5218
|
-
`;var
|
|
6139
|
+
`;var Ct=`enable f16;
|
|
5219
6140
|
|
|
5220
6141
|
// conv_expand \u2014 full f16 variant. See conv_expand.wgsl for layout details.
|
|
5221
6142
|
// Bespoke N\u21922 conv 3\xD73 (pad 1) + relu (wrapper expand_feat).
|
|
@@ -5252,7 +6173,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5252
6173
|
result = max(result, vec2<f16>(0.0h));
|
|
5253
6174
|
output_buf[y * params.w + x] = vec4<f16>(result, 0.0h, 0.0h);
|
|
5254
6175
|
}
|
|
5255
|
-
`;var
|
|
6176
|
+
`;var ee=class extends p{inputs;weights;output;dispatch;shader;constructor(t,e,r){super(t),this.shader=t.dtype==="f16"?Ct:kt;let n=e.c/4;this.output=t.tensor(e.h,e.w,4),this.inputs=[e],this.weights=[t.upload(d(r.weights)),t.upload(g(r.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,n,0])),this.defaultSetup(),this.dispatch=[Math.ceil(e.w/8),Math.ceil(e.h/8),1];}};var Pt=`// cat_conv_6to2: fused concat(u, d) + 6\u21922 conv 3\xD73 (pad 1) + relu (E up1_combine).
|
|
5256
6177
|
// u = c_up=2 carrier (.xy); d = c_high=4 (full vec4). Both same resolution.
|
|
5257
6178
|
// Channel order concat([u, d]) = (u.x, u.y, d.x, d.y, d.z, d.w), split into
|
|
5258
6179
|
// v3a = (u.x, u.y, d.x) v3b = d.yzw
|
|
@@ -5292,7 +6213,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5292
6213
|
result = max(result, vec2<f32>(0.0)); // up1_combine is F.relu
|
|
5293
6214
|
output_buf[y * params.w + x] = vec4<f32>(result, 0.0, 0.0);
|
|
5294
6215
|
}
|
|
5295
|
-
`;var
|
|
6216
|
+
`;var Tt=`enable f16;
|
|
5296
6217
|
|
|
5297
6218
|
// cat_conv_6to2 \u2014 full f16 variant. See cat_conv_6to2.wgsl for layout details.
|
|
5298
6219
|
// Fused concat(u, d) + 6\u21922 conv 3\xD73 (pad 1) + relu (E up1_combine).
|
|
@@ -5331,7 +6252,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5331
6252
|
result = max(result, vec2<f16>(0.0h));
|
|
5332
6253
|
output_buf[y * params.w + x] = vec4<f16>(result, 0.0h, 0.0h);
|
|
5333
6254
|
}
|
|
5334
|
-
`;var
|
|
6255
|
+
`;var te=class extends p{inputs;weights;output;dispatch;shader;constructor(t,e,r,n){super(t),this.shader=t.dtype==="f16"?Tt:Pt,this.output=t.tensor(e.h,e.w,4),this.inputs=[e,r],this.weights=[t.upload(d(n.weights)),t.upload(g(n.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(e.w/8),Math.ceil(e.h/8),1];}};var Ut=`// down_adapter: fused stride-N 3\xD73 conv (4\u21924) + relu + 1\xD71 adapter (4\u21923, no
|
|
5335
6256
|
// act) into one dispatch. E variant: down2 (c_high=4 \u2192 c_low=4, stride 2) +
|
|
5336
6257
|
// adapter. A/B variant: down1 (RGB .xyz \u2192 4, stride 2/3) + adapter (the down
|
|
5337
6258
|
// weight's 4th input column is zeroed at export for RGB input). Symmetric pad.
|
|
@@ -5379,7 +6300,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5379
6300
|
let adapt_out = adapt_w[0] * down_out + adapt_b[0];
|
|
5380
6301
|
output_buf[y * p.out_w + x] = vec4<f32>(adapt_out.xyz, 0.0);
|
|
5381
6302
|
}
|
|
5382
|
-
`;var
|
|
6303
|
+
`;var Wt=`enable f16;
|
|
5383
6304
|
|
|
5384
6305
|
// down_adapter \u2014 full f16 variant. See down_adapter.wgsl for layout details.
|
|
5385
6306
|
// Fused stride-N 3\xD73 conv (4\u21924) + relu + 1\xD71 adapter (4\u21923, no act).
|
|
@@ -5424,7 +6345,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5424
6345
|
let adapt_out = adapt_w[0] * down_out + adapt_b[0];
|
|
5425
6346
|
output_buf[y * p.out_w + x] = vec4<f16>(adapt_out.xyz, 0.0h);
|
|
5426
6347
|
}
|
|
5427
|
-
`;var
|
|
6348
|
+
`;var re=class extends p{inputs;weights;output;dispatch;shader;constructor(t,e,r,n,i){super(t),this.shader=t.dtype==="f16"?Wt:Ut;let o=_(e.h,3,i.stride,1),s=_(e.w,3,i.stride,1),u=m(1,e.h,o,3,i.stride),l=m(1,e.w,s,3,i.stride);this.output=t.tensor(o,s,4),this.inputs=[e],this.weights=[t.upload(d(r.weights)),t.upload(g(r.bias)),t.upload(d(n.weights)),t.upload(g(n.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,o,s,i.stride,u,l,0])),this.defaultSetup(),this.dispatch=[Math.ceil(s/8),Math.ceil(o/8),1];}};var It=`// up_final: fused concat(u, rgb) \u2192 conv 3\xD73 5\u21921 \u2192 sigmoid (A/B alpha head).
|
|
5428
6349
|
// u = c_up=2 carrier (.xy); rgb = x_hr (.xyz). 5 inputs \u2192 1 alpha (output .x).
|
|
5429
6350
|
// Weight: 18 vec4 \u2014 [0..8] = (w0, w1, 0, 0) for u per kpos; [9..17] =
|
|
5430
6351
|
// (w2, w3, w4, 0) for rgb per kpos. Bias .x.
|
|
@@ -5458,7 +6379,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5458
6379
|
|
|
5459
6380
|
output_buf[y * params.w + x] = vec4<f32>(1.0 / (1.0 + exp(-acc)), 0.0, 0.0, 0.0);
|
|
5460
6381
|
}
|
|
5461
|
-
`;var
|
|
6382
|
+
`;var Bt=`enable f16;
|
|
5462
6383
|
|
|
5463
6384
|
// up_final \u2014 full f16 variant. See up_final.wgsl for layout details.
|
|
5464
6385
|
// Fused concat(u, rgb) \u2192 conv 3\xD73 5\u21921 \u2192 sigmoid (A/B alpha head).
|
|
@@ -5492,7 +6413,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5492
6413
|
|
|
5493
6414
|
output_buf[y * params.w + x] = vec4<f16>(1.0h / (1.0h + exp(-acc)), 0.0h, 0.0h, 0.0h);
|
|
5494
6415
|
}
|
|
5495
|
-
`;var
|
|
6416
|
+
`;var ne=class extends p{inputs;weights;output;dispatch;shader;constructor(t,e,r,n){super(t),this.shader=t.dtype==="f16"?Bt:It,this.output=t.tensor(e.h,e.w,4),this.inputs=[e,r],this.weights=[t.upload(d(n.weights)),t.upload(g(n.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(e.w/8),Math.ceil(e.h/8),1];}};var St=`// up_final_skip: C/D alpha head. Fused concat(u, d_full, rgb) \u2192 conv 3\xD73 9\u21921
|
|
5496
6417
|
// \u2192 sigmoid. u = c_up=2 (.xy); d_full = c_high=4 full-res skip (full vec4);
|
|
5497
6418
|
// rgb = x_hr (.xyz). Channel order concat = 2 + 4 + 3 = 9. Output .x = alpha.
|
|
5498
6419
|
// Weight: 27 vec4 (3 per kpos): [kpos*3+0]=(w0,w1,0,0) u; [kpos*3+1]=(w2..w5)
|
|
@@ -5529,7 +6450,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5529
6450
|
|
|
5530
6451
|
output_buf[y * params.w + x] = vec4<f32>(1.0 / (1.0 + exp(-acc)), 0.0, 0.0, 0.0);
|
|
5531
6452
|
}
|
|
5532
|
-
`;var
|
|
6453
|
+
`;var Gt=`enable f16;
|
|
5533
6454
|
|
|
5534
6455
|
// up_final_skip \u2014 full f16 variant. See up_final_skip.wgsl for layout details.
|
|
5535
6456
|
// C/D alpha head: fused concat(u, d_full, rgb) \u2192 conv 3\xD73 9\u21921 \u2192 sigmoid.
|
|
@@ -5565,7 +6486,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5565
6486
|
|
|
5566
6487
|
output_buf[y * params.w + x] = vec4<f16>(1.0h / (1.0h + exp(-acc)), 0.0h, 0.0h, 0.0h);
|
|
5567
6488
|
}
|
|
5568
|
-
`;var
|
|
6489
|
+
`;var ae=class extends p{inputs;weights;output;dispatch;shader;constructor(t,e,r,n,i){super(t),this.shader=t.dtype==="f16"?Gt:St,this.output=t.tensor(e.h,e.w,4),this.inputs=[e,r,n],this.weights=[t.upload(d(i.weights)),t.upload(g(i.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(e.w/8),Math.ceil(e.h/8),1];}};var Ft=`// Bilinear upsample + channel concat fused.
|
|
5569
6490
|
// input_a is the decoder tensor at small spatial resolution (in_h \xD7 in_w).
|
|
5570
6491
|
// input_b is the encoder skip feature already at output resolution (out_h \xD7 out_w).
|
|
5571
6492
|
// For output channels 0..a_groups-1: bilinearly interpolate from input_a.
|
|
@@ -5626,7 +6547,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5626
6547
|
output_buf[out_idx] = input_b[oy * params.out_w * params.b_groups + ox * params.b_groups + c_b];
|
|
5627
6548
|
}
|
|
5628
6549
|
}
|
|
5629
|
-
`;var
|
|
6550
|
+
`;var Et=`enable f16;
|
|
5630
6551
|
|
|
5631
6552
|
// Bilinear upsample + channel concat fused \u2014 full f16 variant.
|
|
5632
6553
|
// Bilinear weights (wx, wy) and intermediate blends computed in f32; result cast to f16.
|
|
@@ -5686,7 +6607,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5686
6607
|
output_buf[out_idx] = input_b[oy * params.out_w * params.b_groups + ox * params.b_groups + c_b];
|
|
5687
6608
|
}
|
|
5688
6609
|
}
|
|
5689
|
-
`;var
|
|
6610
|
+
`;var ie=class extends p{inputs;weights=[];output;dispatch;shader;constructor(t,e,r,n){super(t),this.shader=t.dtype==="f16"?Et:Ft;let i=e.c/4,o=r.c/4,s=i+o;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,i,o,s,0])),this.defaultSetup(),this.dispatch=[Math.ceil(n.outW/8),Math.ceil(n.outH/8),s];}};var At=`// Bilinear upsample + 1\xD71 pointwise conv fused.
|
|
5690
6611
|
// For each output pixel, bilinearly samples the small input for each in_group,
|
|
5691
6612
|
// immediately applies the 1\xD71 conv weights, and writes the activated result.
|
|
5692
6613
|
// Eliminates the intermediate full-resolution upsample buffer.
|
|
@@ -5753,7 +6674,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5753
6674
|
|
|
5754
6675
|
output_buf[oy * params.out_w * params.out_groups + ox * params.out_groups + og] = result;
|
|
5755
6676
|
}
|
|
5756
|
-
`;var
|
|
6677
|
+
`;var Ot=`enable f16;
|
|
5757
6678
|
|
|
5758
6679
|
// Bilinear upsample + 1\xD71 pointwise conv fused \u2014 full f16 variant.
|
|
5759
6680
|
// Bilinear weights and intermediate blends computed in f32; conv accumulation in f16.
|
|
@@ -5820,7 +6741,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5820
6741
|
|
|
5821
6742
|
output_buf[oy * params.out_w * params.out_groups + ox * params.out_groups + og] = result;
|
|
5822
6743
|
}
|
|
5823
|
-
`;var
|
|
6744
|
+
`;var oe=class extends p{inputs;weights;output;dispatch;shader;constructor(t,e,r,n){super(t),this.shader=t.dtype==="f16"?Ot:At;let i=e.c/4,o=n.outChannels/4;this.output=t.tensor(n.outH,n.outW,n.outChannels),this.inputs=[e],this.weights=[t.upload(d(r.weights)),t.upload(d(r.bias))],this.createUniform("params","Params"),this.setUniform("params",new Uint32Array([e.h,e.w,n.outH,n.outW,i,o,n.activation==="relu6"?1:0,0])),this.defaultSetup(),this.dispatch=[Math.ceil(n.outW/8),Math.ceil(n.outH/8),o];}};var Mt=`// Bilinear upsample + sigmoid fused.
|
|
5824
6745
|
// Identical to bilinear_upsample.wgsl except sigmoid is applied at write time.
|
|
5825
6746
|
// Eliminates the intermediate full-resolution buffer and the separate sigmoid dispatch.
|
|
5826
6747
|
|
|
@@ -5874,7 +6795,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5874
6795
|
|
|
5875
6796
|
output_buf[oy * params.out_w * C + ox * C + c] = 1.0 / (1.0 + exp(-result));
|
|
5876
6797
|
}
|
|
5877
|
-
`;var
|
|
6798
|
+
`;var zt=`enable f16;
|
|
5878
6799
|
|
|
5879
6800
|
// Bilinear upsample + sigmoid fused \u2014 full f16 variant.
|
|
5880
6801
|
// Interpolation computed in f32 for accuracy; sigmoid and result cast to f16.
|
|
@@ -5929,7 +6850,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5929
6850
|
|
|
5930
6851
|
output_buf[oy * params.out_w * C + ox * C + c] = vec4<f16>(1.0 / (1.0 + exp(-result)));
|
|
5931
6852
|
}
|
|
5932
|
-
`;var
|
|
6853
|
+
`;var se=class extends p{inputs;weights=[];output;dispatch;shader;constructor(t,e,r){super(t),this.shader=t.dtype==="f16"?zt:Mt;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 Dt=`// Composite an RGBA image over a solid background, gated by a 1-ch alpha.
|
|
5933
6854
|
// Fragment writes the canvas's swapchain texture (premultiplied output).
|
|
5934
6855
|
//
|
|
5935
6856
|
// Caller invariants (matched in CompositeSolidWebGPU):
|
|
@@ -5974,7 +6895,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
5974
6895
|
let rgb = fg * a + params.bgColor.rgb * (1.0 - a);
|
|
5975
6896
|
return vec4<f32>(rgb, 1.0);
|
|
5976
6897
|
}
|
|
5977
|
-
`;var
|
|
6898
|
+
`;var Ht=`enable f16;
|
|
5978
6899
|
|
|
5979
6900
|
// Composite an RGBA image over a solid background, gated by a 1-ch alpha.
|
|
5980
6901
|
// f16 variant: image and alpha are stored as f16; values promote to f32 on
|
|
@@ -6023,7 +6944,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
6023
6944
|
let rgb = fg * a + params.bgColor.rgb * (1.0 - a);
|
|
6024
6945
|
return vec4<f32>(rgb, 1.0);
|
|
6025
6946
|
}
|
|
6026
|
-
`;var
|
|
6947
|
+
`;var ue=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 i=t.device;this.uniformBuffer=i.createBuffer({size:32,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});let o=new ArrayBuffer(32);new Uint32Array(o,0,1)[0]=e.w,new Float32Array(o,16,4).set([n[0],n[1],n[2],0]),i.queue.writeBuffer(this.uniformBuffer,0,o);let s=t.dtype==="f16"?Ht:Dt,u=i.createShaderModule({code:s});this.pipeline=i.createRenderPipeline({layout:"auto",vertex:{module:u,entryPoint:"vs"},fragment:{module:u,entryPoint:"fs",targets:[{format:t.canvasFormat}]},primitive:{topology:"triangle-list"}}),this.bindGroup=i.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 Rt=`// Like composite_solid but bg is an NHWC vec4 storage buffer (e.g. virtual
|
|
6027
6948
|
// background image, or a blurred copy of the input).
|
|
6028
6949
|
|
|
6029
6950
|
struct VertexOut {
|
|
@@ -6065,7 +6986,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
6065
6986
|
let rgb = fg * a + bgc * (1.0 - a);
|
|
6066
6987
|
return vec4<f32>(rgb, 1.0);
|
|
6067
6988
|
}
|
|
6068
|
-
`;var
|
|
6989
|
+
`;var Lt=`enable f16;
|
|
6069
6990
|
|
|
6070
6991
|
// Like composite_solid_f16 but bg is an NHWC vec4<f16> storage buffer (e.g. a
|
|
6071
6992
|
// virtual background image, or a blurred copy of the input).
|
|
@@ -6109,7 +7030,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
6109
7030
|
let rgb = fg * a + bgc * (1.0 - a);
|
|
6110
7031
|
return vec4<f32>(rgb, 1.0);
|
|
6111
7032
|
}
|
|
6112
|
-
`;var
|
|
7033
|
+
`;var pe=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 i=t.device;this.uniformBuffer=i.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});let o=new ArrayBuffer(16);new Uint32Array(o,0,1)[0]=e.w,i.queue.writeBuffer(this.uniformBuffer,0,o);let s=t.dtype==="f16"?Lt:Rt,u=i.createShaderModule({code:s});this.pipeline=i.createRenderPipeline({layout:"auto",vertex:{module:u,entryPoint:"vs"},fragment:{module:u,entryPoint:"fs",targets:[{format:t.canvasFormat}]},primitive:{topology:"triangle-list"}}),this.bindGroup=i.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 Vt=`// Like composite_image but bg is sampled bilinearly \u2014 bg may be smaller than
|
|
6113
7034
|
// (image, alpha). Used by CompositorBlur to skip the final full-res upsample
|
|
6114
7035
|
// in the blur pyramid and let this shader's own per-pixel scan do the
|
|
6115
7036
|
// expansion (the work is already happening here for the composite anyway).
|
|
@@ -6174,7 +7095,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
6174
7095
|
let rgb = fg * a + bgc * (1.0 - a);
|
|
6175
7096
|
return vec4<f32>(rgb, 1.0);
|
|
6176
7097
|
}
|
|
6177
|
-
`;var
|
|
7098
|
+
`;var Nt=`enable f16;
|
|
6178
7099
|
|
|
6179
7100
|
// f16 storage variant of composite_image_bilinear. bg is at a smaller
|
|
6180
7101
|
// resolution and is bilinearly sampled to match (image, alpha) at full res.
|
|
@@ -6235,7 +7156,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
6235
7156
|
let rgb = fg * a + bgc * (1.0 - a);
|
|
6236
7157
|
return vec4<f32>(rgb, 1.0);
|
|
6237
7158
|
}
|
|
6238
|
-
`;var
|
|
7159
|
+
`;var le=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 i=t.device;this.uniformBuffer=i.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});let o=new ArrayBuffer(16),s=new Uint32Array(o);s[0]=e.w,s[1]=e.h,s[2]=n.w,s[3]=n.h,i.queue.writeBuffer(this.uniformBuffer,0,o);let u=t.dtype==="f16"?Nt:Vt,l=i.createShaderModule({code:u});this.pipeline=i.createRenderPipeline({layout:"auto",vertex:{module:l,entryPoint:"vs"},fragment:{module:l,entryPoint:"fs",targets:[{format:t.canvasFormat}]},primitive:{topology:"triangle-list"}}),this.bindGroup=i.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 $t=`// Passthrough "compositor" \u2014 writes the image directly to the canvas
|
|
6239
7160
|
// swapchain texture with no alpha math and no background. Used by RenderOp
|
|
6240
7161
|
// when the renderer is in disabled state, so the output canvas reflects
|
|
6241
7162
|
// the unmodified input frame instead of a stale matted result.
|
|
@@ -6273,7 +7194,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
6273
7194
|
let i = y * params.width + x;
|
|
6274
7195
|
return vec4<f32>(image[i].rgb, 1.0);
|
|
6275
7196
|
}
|
|
6276
|
-
`;var
|
|
7197
|
+
`;var jt=`enable f16;
|
|
6277
7198
|
|
|
6278
7199
|
// Passthrough "compositor" \u2014 f16 variant. Image is stored as f16; values
|
|
6279
7200
|
// promote to f32 on read and the fragment writes f32 to the canvas
|
|
@@ -6309,7 +7230,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
6309
7230
|
let i = y * params.width + x;
|
|
6310
7231
|
return vec4<f32>(vec3<f32>(image[i].rgb), 1.0);
|
|
6311
7232
|
}
|
|
6312
|
-
`;var
|
|
7233
|
+
`;var ce=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 i=t.dtype==="f16"?jt:$t,o=r.createShaderModule({code:i});this.pipeline=r.createRenderPipeline({layout:"auto",vertex:{module:o,entryPoint:"vs"},fragment:{module:o,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 qt=`// Input op \u2014 sample a regular 2D source texture (RGBA8 unorm) into the NHWC
|
|
6313
7234
|
// vec4<f32> output buffer at the target resolution. Used for ImageBitmap
|
|
6314
7235
|
// sources, which are uploaded into a persistent staging texture via
|
|
6315
7236
|
// copyExternalImageToTexture before each dispatch.
|
|
@@ -6339,7 +7260,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
6339
7260
|
let rgba = textureSampleLevel(src_tex, src_sampler, uv, 0.0);
|
|
6340
7261
|
output_buf[y * params.out_w + x] = rgba;
|
|
6341
7262
|
}
|
|
6342
|
-
`;var
|
|
7263
|
+
`;var Xt=`enable f16;
|
|
6343
7264
|
|
|
6344
7265
|
// Input op \u2014 f16 storage variant. Source is sampled as vec4<f32>; only the
|
|
6345
7266
|
// store is demoted to vec4<f16>.
|
|
@@ -6369,7 +7290,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
6369
7290
|
let rgba = textureSampleLevel(src_tex, src_sampler, uv, 0.0);
|
|
6370
7291
|
output_buf[y * params.out_w + x] = vec4<f16>(rgba);
|
|
6371
7292
|
}
|
|
6372
|
-
`;var
|
|
7293
|
+
`;var Kt=`// Input op \u2014 sample a GPUExternalTexture (zero-copy VideoFrame import) into
|
|
6373
7294
|
// the NHWC vec4<f32> output buffer at the target resolution. Used when the
|
|
6374
7295
|
// caller passes a VideoFrame to setSource(); requires importExternalTexture
|
|
6375
7296
|
// to be called in the same task as the dispatch (the texture is invalidated
|
|
@@ -6400,7 +7321,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
6400
7321
|
let rgba = textureSampleBaseClampToEdge(src_tex, src_sampler, uv);
|
|
6401
7322
|
output_buf[y * params.out_w + x] = rgba;
|
|
6402
7323
|
}
|
|
6403
|
-
`;var
|
|
7324
|
+
`;var Yt=`enable f16;
|
|
6404
7325
|
|
|
6405
7326
|
// Input op \u2014 texture_external + f16 storage. Sample in f32, store as f16.
|
|
6406
7327
|
|
|
@@ -6429,4 +7350,4 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
6429
7350
|
let rgba = textureSampleBaseClampToEdge(src_tex, src_sampler, uv);
|
|
6430
7351
|
output_buf[y * params.out_w + x] = vec4<f16>(rgba);
|
|
6431
7352
|
}
|
|
6432
|
-
`;var
|
|
7353
|
+
`;var Wn=a=>typeof VideoFrame<"u"&&a instanceof VideoFrame,de=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"?Xt:qt);}setSource(t){this.source=t;}run(){if(!this.source)throw new Error("InputWebGPU.run() called before setSource()");Wn(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"?Yt:Kt));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 In=navigator.gpu?GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST:0,xe=class a{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.canvasFormat=navigator.gpu.getPreferredCanvasFormat(),this.configureContext(n),this.canvasContext=n,this.contexts.set("main",n),this.ops={Conv2d:(i,o,s)=>new O(this,i,o,s),ConvTranspose2d:(i,o,s)=>new M(this,i,o,s),DepthwiseConv2d:(i,o,s)=>new z(this,i,o,s),Add:(i,o)=>new D(this,i,o),Sigmoid:i=>new H(this,i),Tanh:i=>new R(this,i),ElementwiseMul:(i,o)=>new L(this,i,o),Warp:(i,o,s)=>new V(this,i,o,s),Stabilize:(i,o,s,u,l)=>new N(this,i,o,s,u,l),BilinearUpsample:(i,o)=>new $(this,i,o),Crop:(i,o)=>new j(this,i,o),BicubicUpsample:(i,o)=>new q(this,i,o),ChannelConcat:(i,o)=>new X(this,i,o),Conv2dAdd:(i,o,s,u)=>new K(this,i,o,s,u),ProjResidual:(i,o,s,u)=>new Y(this,i,o,s,u),ConcatConv2d:(i,o,s,u)=>new J(this,i,o,s,u),GatesFused:(i,o,s)=>new Q(this,i,o,s),CandUpdateFused:(i,o,s,u,l)=>new Z(this,i,o,s,u,l),ConvExpand:(i,o)=>new ee(this,i,o),CatConv6to2:(i,o,s)=>new te(this,i,o,s),DownAdapter:(i,o,s,u)=>new re(this,i,o,s,u),UpFinal:(i,o,s)=>new ne(this,i,o,s),UpFinalSkip:(i,o,s,u)=>new ae(this,i,o,s,u),UpsampleConcat:(i,o,s)=>new ie(this,i,o,s),UpsampleConv1x1:(i,o,s)=>new oe(this,i,o,s),UpsampleSigmoid:(i,o)=>new se(this,i,o),Input:(i,o)=>new de(this,i,o)},this.presenters={CompositeSolid:(i,o,s,u="main")=>{let l=new ue(this,i,o,s);return {run:()=>{l.setOutput(this.getCurrentDisplayTexture(u)),l.run();}}},CompositeImage:(i,o,s,u="main")=>{let l=new pe(this,i,o,s);return {run:()=>{l.setOutput(this.getCurrentDisplayTexture(u)),l.run();}}},CompositeImageBilinear:(i,o,s,u="main")=>{let l=new le(this,i,o,s);return {run:()=>{l.setOutput(this.getCurrentDisplayTexture(u)),l.run();}}},CompositePassthrough:(i,o="main")=>{let s=new ce(this,i);return {run:()=>{s.setOutput(this.getCurrentDisplayTexture(o)),s.run();}}}};}device;canvas;dtype;ops;presenters;canvasContext;canvasFormat;bytesPerElement;contexts=new Map;configureContext(t){t.configure({device:this.device,format:this.canvasFormat,alphaMode:"premultiplied"});}attachCanvas(t,e){if(t==="main")throw new Error("attachCanvas: 'main' is reserved for the create() canvas");let r=e.getContext("webgpu");if(!r)throw new Error(`attachCanvas: failed to get WebGPU context for target '${t}'`);this.configureContext(r),this.contexts.set(t,r);}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 a(r,t.canvas,e)}getCurrentDisplayTexture(t="main"){let e=this.contexts.get(t);if(!e)throw new Error(`getCurrentDisplayTexture: no canvas attached for target '${t}'`);return e.getCurrentTexture()}tensor(t,e,r,n){let o=t*e*r*this.bytesPerElement,s=this.device.createBuffer({size:o,usage:In,mappedAtCreation:n!==void 0});if(n!==void 0){let u=s.getMappedRange();this.writeView(u,n),s.unmap();}return {h:t,w:e,c:r,buffer:s}}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(He(e)):new Float32Array(t).set(be(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(),i=this.dtype==="f16"?be(new Uint16Array(n.slice(0))):new Float32Array(n.slice(0));return e.unmap(),e.destroy(),i}copyTensor(t,e){if(t.buffer.size!==e.buffer.size)throw new Error(`copyTensor: size mismatch (src ${t.buffer.size} vs dst ${e.buffer.size})`);let r=this.device.createCommandEncoder();r.copyBufferToBuffer(t.buffer,0,e.buffer,0,t.buffer.size),this.device.queue.submit([r.finish()]);}async sync(){await this.device.queue.onSubmittedWorkDone();}destroy(){this.device.destroy();}};export{_e as EffectsPipeline,xe as WebGPUBackend};
|