longpipe 0.0.10 → 0.0.12
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 +45 -9
- package/dist/index.cjs +1205 -253
- package/dist/index.d.cts +53 -4
- package/dist/index.d.ts +53 -4
- package/dist/index.js +1205 -253
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,12 +1,42 @@
|
|
|
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 y=[{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 _e=false;function Te(a){_e=a;}function x(a){let t=`[longpipe/${a}]`,e=((...r)=>{_e&&console.log(t,...r);});return e.warn=(...r)=>{_e&&console.warn(t,...r);},e}var T=x("adaptive"),sr=2e3,ur=1e4,pr=30,lr=20,cr=5e3,dr=.3,fr=15e3,G=class{constructor(t){this.opts=t;this.currentPresetIdx=y.findIndex(e=>e.model===t.initialModel),this.lastSwapAt=performance.now();}opts;timer=null;currentPresetIdx;lastSwapAt=0;overshootStart=0;headroomStart=0;start(){T(`started; backend=${this.opts.backendKind} initial=${this.opts.initialModel} idx=${this.currentPresetIdx}`),this.timer=setInterval(()=>{this.tick().catch(t=>T("tick failed:",t));},sr);}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<ur)return;let e=await this.opts.getStats();if(e.fps<lr?(this.overshootStart===0&&(this.overshootStart=t),t-this.overshootStart>=cr&&this.tryDowngrade(e.fps)):this.overshootStart=0,this.opts.backendKind==="webgpu"&&e.modelMs>0){let r=1e3/pr*dr;e.modelMs<r?(this.headroomStart===0&&(this.headroomStart=t),t-this.headroomStart>=fr&&this.tryUpgrade(e.modelMs,r)):this.headroomStart=0;}}tryDowngrade(t){if(this.currentPresetIdx<=0)return;let e=this.currentPresetIdx-1;T(`downgrade ${y[this.currentPresetIdx].model} \u2192 ${y[e].model} (fps=${t})`),this.swap(e);}tryUpgrade(t,e){if(this.currentPresetIdx>=y.length-1)return;let r=this.currentPresetIdx+1;T(`upgrade ${y[this.currentPresetIdx].model} \u2192 ${y[r].model} (modelMs=${t.toFixed(1)} < ${e.toFixed(1)})`),this.swap(r);}async swap(t){let e=y[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,T(`swap to ${e.model} done`);}catch(r){T("swap failed:",r),this.opts.onError?.({message:`adaptive preset swap failed: ${r.message??String(r)}`,source:"adaptive",recoverable:true,cause:r});}}};async function Ue(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 m=new VideoFrame(r,{timestamp:h.mediaTime*1e6});i.postMessage({frame:m},[m]);}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 hr=4,be=8,We=16;async function F(a){if(typeof a=="string")return a==="none"?{background:{kind:"none"}}:a==="blur"?{background:{kind:"blur",sigma:be}}:{background:{kind:"image",bitmap:await Be(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 Ie(a);let t=a;if(t.color!==void 0)return {background:{kind:"color",rgb:gr(t.color)}};if(t.blur!==void 0)return {background:{kind:"blur",sigma:mr(t.blur)}};if(t.image!==void 0)return {background:{kind:"image",bitmap:await _r(t.image)}};if(t.video!==void 0)return await Ie(t.video);throw new Error(`background: unrecognized input shape \u2014 ${P(a)}`)}async function Ie(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 ${P(a)}`);let e=await Ue(t);return {background:{kind:"video",port:e.port},transferList:e.transferList,cleanup:e.cleanup}}function gr(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 ${P(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 ${P(a)}`);return [a[0],a[1],a[2]]}function mr(a){if(a===true)return be;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 We*e}if(t==="low")return hr;if(t==="medium")return be;if(t==="high")return We;throw new Error(`background.blur.strength must be 'low' | 'medium' | 'high' | number, got ${P(t)}`)}throw new Error(`background.blur: must be true, { strength }, or { sigma } \u2014 got ${P(a)}`)}async function _r(a){if(a instanceof ImageBitmap)return a;if(typeof HTMLImageElement<"u"&&a instanceof HTMLImageElement)return createImageBitmap(a);if(typeof a=="string")return Be(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 ${P(a)}`)}async function Be(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 P(a){return a===null?"null":typeof a!="object"?typeof a+"("+String(a)+")":`${a.constructor?.name??"Object"} ${JSON.stringify(a).slice(0,80)}`}function Se(){return {input:"MediaStreamTrackProcessor"in self?"mstp":"rvfc-postmessage",output:"MediaStreamTrackGenerator"in self?"mstg":br()?"transfer-capture":"bitmap-shuttle"}}var A=null;function br(){return A!==null||(A=!/Firefox/.test(navigator.userAgent)),A}function Ee(a){return a==="denoise"?{mode:"denoise",denoise:{}}:typeof a=="object"?{mode:"denoise",denoise:a.denoise}:{mode:a}}function Ge(a,t,e,r){let n=[a];return e.mode==="passthrough"?n.push(...t.getAudioTracks()):e.mode==="denoise"&&r&&n.push(r),new MediaStream(n)}var U={rnnoise:{wasm:"rnnoise.wasm",weights:null,scaleIn:32768,scaleOut:30517578125e-15,needsSimd:false,exports:{malloc:"malloc",create:"rn_create",process:"rn_process"}},dfn:{wasm:"dfn.wasm",weights:"dfn_weights.pack",scaleIn:1,scaleOut:1,needsSimd:true,exports:{malloc:"df_lite_malloc",create:"df_lite_create",process:"df_lite_process",setBeta:"df_lite_set_beta",setGruLeak:"df_lite_set_gru_leak"}},dfnint8:{wasm:"dfn.wasm",weights:"dfn_weights_int8.pack",scaleIn:1,scaleOut:1,needsSimd:true,exports:{malloc:"df_lite_malloc",create:"df_lite_create_i8",process:"df_lite_process",setBeta:"df_lite_set_beta",setGruLeak:"df_lite_set_gru_leak"}}},vr={high:"dfn",mid:"dfnint8",low:"rnnoise"},xr=["high","mid","low"];function wr(a){return xr.includes(a)}function Fe(a){return wr(a)?vr[a]:a}function Ae(a,t){return `${a.replace(/\/$/,"")}/${t}`}async function Me(a){let t=await fetch(a);if(!t.ok)throw new Error(`audio asset fetch failed: ${t.status} ${a}`);return t.arrayBuffer()}async function Oe(a,t){let e=U[a],[r,n]=await Promise.all([Me(Ae(t,e.wasm)),e.weights?Me(Ae(t,e.weights)):Promise.resolve(null)]);return {wasmBytes:r,weights:n}}function M(){try{return WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,5,1,96,0,1,123,3,2,1,0,10,22,1,20,0,253,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11]))}catch{return false}}var yr=1.3,kr=64,Pr=3,Cr=`
|
|
2
|
+
self.onmessage = async (e) => {
|
|
3
|
+
const { wasmUrl, iters, rounds, budget } = e.data
|
|
4
|
+
try {
|
|
5
|
+
const res = await fetch(wasmUrl)
|
|
6
|
+
if (!res.ok) throw new Error(res.status + ' ' + wasmUrl)
|
|
7
|
+
const module = await WebAssembly.compile(await res.arrayBuffer())
|
|
8
|
+
const imports = {}
|
|
9
|
+
for (const im of WebAssembly.Module.imports(module)) {
|
|
10
|
+
;(imports[im.module] = imports[im.module] || {})
|
|
11
|
+
if (im.kind === 'function') imports[im.module][im.name] = () => 0
|
|
12
|
+
}
|
|
13
|
+
const ex = new WebAssembly.Instance(module, imports).exports
|
|
14
|
+
const best = (fn) => {
|
|
15
|
+
fn(iters) // warm up
|
|
16
|
+
let b = Infinity
|
|
17
|
+
for (let r = 0; r < rounds; r++) {
|
|
18
|
+
const t = performance.now()
|
|
19
|
+
fn(iters)
|
|
20
|
+
b = Math.min(b, (performance.now() - t) / iters)
|
|
21
|
+
}
|
|
22
|
+
return b
|
|
23
|
+
}
|
|
24
|
+
const dfnMs = best(ex.calibrate_f32)
|
|
25
|
+
const int8Ms = ex.calibrate_i8 ? best(ex.calibrate_i8) : Infinity
|
|
26
|
+
const model = dfnMs <= budget ? 'dfn' : int8Ms <= budget ? 'dfnint8' : 'rnnoise'
|
|
27
|
+
self.postMessage({ model, dfnMs, int8Ms })
|
|
28
|
+
} catch (err) {
|
|
29
|
+
self.postMessage({ error: (err && err.message) || String(err) })
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
`;async function De(a,t){if(!M())return "rnnoise";let e=`${a.replace(/\/$/,"")}/${U.dfn.wasm}`,r=null,n=null;try{r=URL.createObjectURL(new Blob([Cr],{type:"application/javascript"})),n=new Worker(r);let i=await new Promise((o,s)=>{n.onmessage=u=>o(u.data),n.onerror=u=>s(new Error(u.message||"probe worker error")),n.postMessage({wasmUrl:e,iters:kr,rounds:Pr,budget:yr});});if(i.error)throw new Error(i.error);return i.model??"rnnoise"}catch(i){return t?.(`audio tier probe failed (${i.message??String(i)}); using rnnoise`),"rnnoise"}finally{n?.terminate(),r&&URL.revokeObjectURL(r);}}var ve='var b=Object.defineProperty;var y=(u,a,i)=>a in u?b(u,a,{enumerable:!0,configurable:!0,writable:!0,value:i}):u[a]=i;var r=(u,a,i)=>y(u,typeof a!="symbol"?a+"":a,i);var f={rnnoise:{wasm:"rnnoise.wasm",weights:null,scaleIn:32768,scaleOut:30517578125e-15,needsSimd:!1,exports:{malloc:"malloc",create:"rn_create",process:"rn_process"}},dfn:{wasm:"dfn.wasm",weights:"dfn_weights.pack",scaleIn:1,scaleOut:1,needsSimd:!0,exports:{malloc:"df_lite_malloc",create:"df_lite_create",process:"df_lite_process",setBeta:"df_lite_set_beta",setGruLeak:"df_lite_set_gru_leak"}},dfnint8:{wasm:"dfn.wasm",weights:"dfn_weights_int8.pack",scaleIn:1,scaleOut:1,needsSimd:!0,exports:{malloc:"df_lite_malloc",create:"df_lite_create_i8",process:"df_lite_process",setBeta:"df_lite_set_beta",setGruLeak:"df_lite_set_gru_leak"}}};var c=4096,m=class extends AudioWorkletProcessor{constructor(i){super();r(this,"cfg");r(this,"mem");r(this,"run");r(this,"state",0);r(this,"inPtr",0);r(this,"outPtr",0);r(this,"setBeta",null);r(this,"setGruLeak",null);r(this,"resample",!1);r(this,"rsPush",null);r(this,"inRs",0);r(this,"outRs",0);r(this,"rsDevInPtr",0);r(this,"rsOutPtr",0);r(this,"enabled");r(this,"model");r(this,"inAcc",new Float32Array(480));r(this,"inFill",0);r(this,"outRing",new Float32Array(4096));r(this,"outRead",0);r(this,"outWrite",0);r(this,"outCount",0);r(this,"primed",!1);r(this,"now");r(this,"times",new Float32Array(256));r(this,"tIdx",0);r(this,"hops",0);r(this,"_f32",null);let o=i.processorOptions;this.model=o.model,this.enabled=o.enabled,this.cfg=f[o.model];try{let t=this.instantiate(o.wasmBytes),e=n=>n?t[n]:void 0;this.mem=t.memory;let s=t[this.cfg.exports.malloc];if(this.run=t[this.cfg.exports.process],this.inPtr=s(480*4),this.outPtr=s(480*4),o.weights?this.state=t[this.cfg.exports.create](this.upload(s,o.weights),o.weights.byteLength):this.state=t[this.cfg.exports.create](),this.setBeta=e(this.cfg.exports.setBeta)??null,this.setGruLeak=e(this.cfg.exports.setGruLeak)??null,this.setBeta&&(o.postFilterBeta??0)>0&&this.setBeta(this.state,o.postFilterBeta),this.setGruLeak&&(o.gruLeak??1)<1&&this.setGruLeak(this.state,o.gruLeak),sampleRate!==48e3){let n=t.df_resampler_create;this.rsPush=t.df_resampler_push??null,n&&this.rsPush?(this.resample=!0,this.inRs=n(sampleRate,48e3),this.outRs=n(48e3,sampleRate),this.rsDevInPtr=s(256*4),this.rsOutPtr=s(c*4)):this.post({type:"error",message:`${o.model} can\'t resample ${sampleRate}\\u219248000 Hz; needs a 48 kHz AudioContext`})}}catch(t){let e=t;this.post({type:"error",message:`denoise init failed: ${e.message??String(t)}${e.stack?`\n`+e.stack:""}`})}this.now=typeof performance<"u"&&performance.now?()=>performance.now():null,this.port.onmessage=t=>{let e=t.data;e.type==="enabled"?this.enabled=e.value:e.type==="config"&&(this.setBeta&&e.postFilterBeta!=null&&this.setBeta(this.state,e.postFilterBeta),this.setGruLeak&&e.gruLeak!=null&&this.setGruLeak(this.state,e.gruLeak))},this.post({type:"ready"})}instantiate(i){var e;let o=new WebAssembly.Module(i),t={};for(let s of WebAssembly.Module.imports(o))t[e=s.module]??(t[e]={}),s.kind==="function"?t[s.module][s.name]=()=>0:s.kind==="memory"?t[s.module][s.name]=new WebAssembly.Memory({initial:256}):s.kind==="table"?t[s.module][s.name]=new WebAssembly.Table({initial:0,element:"anyfunc"}):s.kind==="global"&&(t[s.module][s.name]=new WebAssembly.Global({value:"i32",mutable:!1},0));return new WebAssembly.Instance(o,t).exports}upload(i,o){let t=new Uint8Array(o),e=i(t.length);return new Uint8Array(this.mem.buffer).set(t,e),e}heap(){return(!this._f32||this._f32.buffer!==this.mem.buffer)&&(this._f32=new Float32Array(this.mem.buffer)),this._f32}post(i){this.port.postMessage(i)}pushOut(i){this.outRing[this.outWrite]=i,this.outWrite=(this.outWrite+1)%this.outRing.length,this.outCount++}feed48k(i,o){for(let t=0;t<o;t++)this.inAcc[this.inFill++]=i[t],this.inFill===480&&(this.runHop(),this.inFill=0)}runHop(){let i=this.heap(),o=this.inPtr>>2;for(let e=0;e<480;e++)i[o+e]=this.inAcc[e]*this.cfg.scaleIn;let t=this.now?this.now():0;if(this.run(this.state,this.inPtr,this.outPtr),this.now&&(this.times[this.tIdx=this.tIdx+1&255]=this.now()-t),this.resample&&this.rsPush){let e=this.rsPush(this.outRs,this.outPtr,480,this.rsOutPtr,c);i=this.heap();let s=this.rsOutPtr>>2;for(let n=0;n<e;n++)this.pushOut(i[s+n])}else{let e=this.outPtr>>2;for(let s=0;s<480;s++)this.pushOut(i[e+s]*this.cfg.scaleOut)}++this.hops>=50&&(this.reportStats(),this.hops=0)}reportStats(){let i=Array.from(this.times).filter(e=>e>0).sort((e,s)=>e-s),o=e=>i.length?i[Math.min(i.length-1,Math.floor(e*i.length))]:null,t={model:this.model,p50Ms:this.now?o(.5):null,p95Ms:this.now?o(.95):null,latencyMs:this.outCount/sampleRate*1e3,active:this.enabled&&this.state!==0,sampleRate};this.post({type:"stats",stats:t})}process(i,o){let t=i[0]?.[0],e=o[0]?.[0];if(!e)return!0;let s=e.length;if(!t||!this.enabled||this.state===0)return t&&!this.enabled?e.set(t):e.fill(0),!0;if(this.resample&&this.rsPush){let n=this.heap(),g=this.rsDevInPtr>>2;for(let h=0;h<s;h++)n[g+h]=t[h];let d=this.rsPush(this.inRs,this.rsDevInPtr,s,this.rsOutPtr,c);n=this.heap(),this.feed48k(n.subarray(this.rsOutPtr>>2,(this.rsOutPtr>>2)+d),d)}else this.feed48k(t,s);if(!this.primed)if(this.outCount>=480)this.primed=!0;else return e.fill(0),!0;if(this.outCount>=s)for(let n=0;n<s;n++)e[n]=this.outRing[this.outRead],this.outRead=(this.outRead+1)%this.outRing.length,this.outCount--;else e.fill(0);return!0}};registerProcessor("denoise",m);\n';var Ur=.03,Wr=.995,O=class{constructor(t,e){this.opts=e;this.ctx=new AudioContext({sampleRate:48e3}),this.source=this.ctx.createMediaStreamSource(new MediaStream([t])),this.dest=this.ctx.createMediaStreamDestination(),this.outputTrack=this.dest.stream.getAudioTracks()[0],this.source.connect(this.dest),this.ready=this.init().catch(r=>{this.opts.onError?.(`audio denoise init failed: ${r.message??String(r)}`);});}opts;outputTrack;ready;ctx;source;dest;node=null;model=null;latestStats=null;destroyed=false;resolveExplicit(){let t=Fe(this.opts.model);return U[t].needsSimd&&!M()?(this.opts.onError?.(`${t} needs wasm SIMD; falling back to rnnoise`),"rnnoise"):t}async init(){let t=this.opts.model==="auto"?await De(this.opts.weightsBaseUrl,this.opts.onError):this.resolveExplicit();this.model=t;let e=await Oe(t,this.opts.weightsBaseUrl);if(await this.ctx.audioWorklet.addModule(Ir()),this.destroyed)return;let r={model:t,wasmBytes:e.wasmBytes,weights:e.weights,enabled:this.opts.enabled??true,postFilterBeta:this.opts.postFilterBeta??Ur,gruLeak:this.opts.gruLeak??Wr},n=new AudioWorkletNode(this.ctx,"denoise",{numberOfInputs:1,numberOfOutputs:1,outputChannelCount:[1],processorOptions:r});n.port.onmessage=i=>{let o=i.data;o.type==="stats"?this.latestStats=o.stats:o.type==="error"?this.opts.onError?.(o.message):o.type==="ready"&&this.opts.onReady?.();},this.node=n,this.source.disconnect(this.dest),this.source.connect(n).connect(this.dest);}setEnabled(t){this.node?.port.postMessage({type:"enabled",value:t});}setConfig(t){this.node?.port.postMessage({type:"config",...t});}getStats(){return this.latestStats}destroy(){this.destroyed=true;try{this.node?.disconnect();}catch{}try{this.source.disconnect();}catch{}this.ctx.close();}};function Ir(){return URL.createObjectURL(new Blob([ve],{type:"application/javascript"}))}var D=x("worker_controller"),z=class{worker;listeners=new Map;persistentEvents=new Set;constructor(t){this.worker=t,this.worker.addEventListener("message",this.handleMessage.bind(this)),D("constructed; message listener attached");}handleMessage(t){let{request_id:e,res:r}=t.data,n=this.listeners.get(e);D("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),D("addPersistentListener:",t);}removePersistentListener(t){this.persistentEvents.delete(t),this.listeners.delete(t);}sendMessage(t,e,r=[]){let n=crypto.randomUUID();return D("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 ze=x("input-postmessage/main");function Re(a){let t=document.createElement("video");t.srcObject=a,t.muted=true,t.autoplay=true,t.playsInline=true,t.play().catch(l=>{ze.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){ze.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 He(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 Le(a,t){switch(a){case "mstp":{let e=He(t);return {initFields:{inputReadable:e.readable},transferList:e.transferList,cleanup:e.cleanup}}case "rvfc-postmessage":{let e=Re(t);return {initFields:{inputPort:e.port},transferList:e.transferList,cleanup:e.cleanup}}}}var Br=x("bitmap-shuttle/main"),Sr=30;function Ve(a,t=Sr){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=()=>{},m=3,w=0;return u.onmessage=B=>{if(c){if(w++,w<m){B.data.bmp.close();return}h();}try{r.transferFromImageBitmap(B.data.bmp);}catch(v){Br.warn("transferFromImageBitmap failed:",v);}},u.start(),{videoTrack:o,port:l,transferList:[l],startPassthrough:B=>{if(c)return;c=true;let v=document.createElement("video");v.srcObject=B,v.muted=true,v.playsInline=true,v.play().catch(()=>{}),f=v;let S="requestVideoFrameCallback"in v?C=>{v.requestVideoFrameCallback(C);}:C=>{requestAnimationFrame(C);},E=()=>{if(c){if(v.videoWidth===0){S(E);return}createImageBitmap(v,{resizeWidth:e.width,resizeHeight:e.height,resizeQuality:"medium"}).then(C=>{if(!c){C.close();return}try{r.transferFromImageBitmap(C);}catch{}S(E);}).catch(()=>{S(E);});}};S(E),h=()=>{c=false,f&&(f.srcObject=null,f.pause(),f=null);};},cleanup:()=>{h(),u.onmessage=null,u.close(),o.stop();}}}function Ne(){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 $e(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 je(a,t){switch(a){case "mstg":{let e=Ne();return {videoTrack:e.videoTrack,initFields:{outputWritable:e.writable},transferList:e.transferList,cleanup:e.cleanup}}case "transfer-capture":{let e=$e(t);return {videoTrack:e.videoTrack,initFields:{outputCanvas:e.canvas},transferList:e.transferList,cleanup:e.cleanup}}case "bitmap-shuttle":{let e=Ve(t);return {videoTrack:e.videoTrack,initFields:{outputPort:e.port},transferList:e.transferList,startPassthrough:e.startPassthrough,cleanup:e.cleanup}}}}var xe=`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
33
|
//
|
|
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).
|
|
34
|
+
// Identical math, layout, and output to conv2d.wgsl, but each thread computes 2
|
|
35
|
+
// output channel-groups (8 channels) for one pixel, loading each input vec4 ONCE
|
|
36
|
+
// and reusing it across both groups' mat4x4 weight blocks in registers. Half the
|
|
37
|
+
// register pressure of the K=4 variant (2 accumulators vs 4). Output is bit-
|
|
38
|
+
// identical to conv2d.wgsl (\\u22641 ULP from FMA contraction). Dispatch
|
|
39
|
+
// ceil(out_groups / 2) in z (see conv2d.ts).
|
|
10
40
|
//
|
|
11
41
|
// Tensor layout: NHWC, channels in vec4 groups (same as conv2d.wgsl).
|
|
12
42
|
// Weight layout: [K*K][out_groups][in_groups] array of mat4x4 (same as conv2d.wgsl).
|
|
@@ -23,7 +53,7 @@ struct Params {
|
|
|
23
53
|
stride : u32,
|
|
24
54
|
pad_top : u32,
|
|
25
55
|
pad_left : u32,
|
|
26
|
-
activation : u32, // 0 = none, 1 = relu6, 2 = relu
|
|
56
|
+
activation : u32, // 0 = none, 1 = relu6, 2 = relu, 3 = leaky
|
|
27
57
|
}
|
|
28
58
|
|
|
29
59
|
@group(0) @binding(0) var<storage, read> input_buf : array<vec4<f32>>;
|
|
@@ -32,18 +62,19 @@ struct Params {
|
|
|
32
62
|
@group(0) @binding(3) var<uniform> params : Params;
|
|
33
63
|
@group(0) @binding(4) var<storage, read_write> output_buf : array<vec4<f32>>;
|
|
34
64
|
|
|
35
|
-
const KB =
|
|
65
|
+
const KB = 2u;
|
|
36
66
|
|
|
37
67
|
fn act(v: vec4<f32>, a: u32) -> vec4<f32> {
|
|
38
68
|
if (a == 1u) { return clamp(v, vec4<f32>(0.0), vec4<f32>(6.0)); }
|
|
39
69
|
if (a == 2u) { return max(v, vec4<f32>(0.0)); }
|
|
70
|
+
if (a == 3u) { return max(v, 0.1 * v); } // leaky relu (slope 0.1)
|
|
40
71
|
return v;
|
|
41
72
|
}
|
|
42
73
|
|
|
43
74
|
@compute @workgroup_size(8, 8, 1)
|
|
44
75
|
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
45
|
-
let x = gid.x;
|
|
46
|
-
let y = gid.y;
|
|
76
|
+
let x = gid.x; // output column
|
|
77
|
+
let y = gid.y; // output row
|
|
47
78
|
let o0 = gid.z * KB; // first output channel group
|
|
48
79
|
|
|
49
80
|
if (x >= params.out_w || y >= params.out_h || o0 >= params.out_groups) {
|
|
@@ -52,19 +83,13 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
52
83
|
|
|
53
84
|
let I = params.in_groups;
|
|
54
85
|
let O = params.out_groups;
|
|
55
|
-
// Tail handling when out_groups is
|
|
56
|
-
//
|
|
86
|
+
// Tail handling when out_groups is odd: clamp the spare lane to o0 (valid
|
|
87
|
+
// index, no OOB) and just don't write it.
|
|
57
88
|
let has1 = (o0 + 1u) < O;
|
|
58
|
-
let has2 = (o0 + 2u) < O;
|
|
59
|
-
let has3 = (o0 + 3u) < O;
|
|
60
89
|
let o1 = select(o0, o0 + 1u, has1);
|
|
61
|
-
let o2 = select(o0, o0 + 2u, has2);
|
|
62
|
-
let o3 = select(o0, o0 + 3u, has3);
|
|
63
90
|
|
|
64
91
|
var acc0 = bias_buf[o0];
|
|
65
92
|
var acc1 = bias_buf[o1];
|
|
66
|
-
var acc2 = bias_buf[o2];
|
|
67
|
-
var acc3 = bias_buf[o3];
|
|
68
93
|
|
|
69
94
|
for (var ky = 0u; ky < params.kernel_h; ky++) {
|
|
70
95
|
for (var kx = 0u; kx < params.kernel_w; kx++) {
|
|
@@ -80,14 +105,10 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
80
105
|
let inB = u32(in_y_s) * params.in_w * I + u32(in_x_s) * I;
|
|
81
106
|
let wb0 = z * O * I + o0 * I;
|
|
82
107
|
let wb1 = z * O * I + o1 * I;
|
|
83
|
-
let wb2 = z * O * I + o2 * I;
|
|
84
|
-
let wb3 = z * O * I + o3 * I;
|
|
85
108
|
for (var i = 0u; i < I; i++) {
|
|
86
|
-
let iv = input_buf[inB + i]; // loaded ONCE, reused across
|
|
109
|
+
let iv = input_buf[inB + i]; // loaded ONCE, reused across 2 groups
|
|
87
110
|
acc0 += weight_buf[wb0 + i] * iv;
|
|
88
111
|
acc1 += weight_buf[wb1 + i] * iv;
|
|
89
|
-
acc2 += weight_buf[wb2 + i] * iv;
|
|
90
|
-
acc3 += weight_buf[wb3 + i] * iv;
|
|
91
112
|
}
|
|
92
113
|
}
|
|
93
114
|
}
|
|
@@ -95,15 +116,14 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
95
116
|
let baseO = y * params.out_w * O + x * O;
|
|
96
117
|
output_buf[baseO + o0] = act(acc0, params.activation);
|
|
97
118
|
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
119
|
}
|
|
101
|
-
\`;var
|
|
120
|
+
\`;var Et=\`enable f16;
|
|
102
121
|
|
|
103
|
-
// Conv2d, output-channel-blocked (K=
|
|
104
|
-
// conv2d_f16.wgsl. Each thread computes
|
|
105
|
-
// loading each input vec4
|
|
106
|
-
//
|
|
122
|
+
// Conv2d, output-channel-blocked (K=2) \\u2014 full f16. Drop-in replacement for
|
|
123
|
+
// conv2d_f16.wgsl. Each thread computes 2 output channel-groups for one pixel,
|
|
124
|
+
// loading each input vec4 ONCE and reusing it across both weight blocks. Half the
|
|
125
|
+
// register pressure of the K=4 variant (2 accumulators vs 4). Output is bit-
|
|
126
|
+
// identical to conv2d_f16.wgsl. Dispatch ceil(out_groups / 2) in z.
|
|
107
127
|
|
|
108
128
|
struct Params {
|
|
109
129
|
in_h : u32,
|
|
@@ -126,11 +146,12 @@ struct Params {
|
|
|
126
146
|
@group(0) @binding(3) var<uniform> params : Params;
|
|
127
147
|
@group(0) @binding(4) var<storage, read_write> output_buf : array<vec4<f16>>;
|
|
128
148
|
|
|
129
|
-
const KB =
|
|
149
|
+
const KB = 2u;
|
|
130
150
|
|
|
131
151
|
fn act(v: vec4<f16>, a: u32) -> vec4<f16> {
|
|
132
152
|
if (a == 1u) { return clamp(v, vec4<f16>(0.0h), vec4<f16>(6.0h)); }
|
|
133
153
|
if (a == 2u) { return max(v, vec4<f16>(0.0h)); }
|
|
154
|
+
if (a == 3u) { return max(v, 0.1h * v); } // leaky relu (slope 0.1)
|
|
134
155
|
return v;
|
|
135
156
|
}
|
|
136
157
|
|
|
@@ -147,16 +168,10 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
147
168
|
let I = params.in_groups;
|
|
148
169
|
let O = params.out_groups;
|
|
149
170
|
let has1 = (o0 + 1u) < O;
|
|
150
|
-
let has2 = (o0 + 2u) < O;
|
|
151
|
-
let has3 = (o0 + 3u) < O;
|
|
152
171
|
let o1 = select(o0, o0 + 1u, has1);
|
|
153
|
-
let o2 = select(o0, o0 + 2u, has2);
|
|
154
|
-
let o3 = select(o0, o0 + 3u, has3);
|
|
155
172
|
|
|
156
173
|
var acc0 = bias_buf[o0];
|
|
157
174
|
var acc1 = bias_buf[o1];
|
|
158
|
-
var acc2 = bias_buf[o2];
|
|
159
|
-
var acc3 = bias_buf[o3];
|
|
160
175
|
|
|
161
176
|
for (var ky = 0u; ky < params.kernel_h; ky++) {
|
|
162
177
|
for (var kx = 0u; kx < params.kernel_w; kx++) {
|
|
@@ -172,14 +187,10 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
172
187
|
let inB = u32(in_y_s) * params.in_w * I + u32(in_x_s) * I;
|
|
173
188
|
let wb0 = z * O * I + o0 * I;
|
|
174
189
|
let wb1 = z * O * I + o1 * I;
|
|
175
|
-
let wb2 = z * O * I + o2 * I;
|
|
176
|
-
let wb3 = z * O * I + o3 * I;
|
|
177
190
|
for (var i = 0u; i < I; i++) {
|
|
178
|
-
let iv = input_buf[inB + i];
|
|
191
|
+
let iv = input_buf[inB + i]; // loaded ONCE, reused across 2 groups
|
|
179
192
|
acc0 += weight_buf[wb0 + i] * iv;
|
|
180
193
|
acc1 += weight_buf[wb1 + i] * iv;
|
|
181
|
-
acc2 += weight_buf[wb2 + i] * iv;
|
|
182
|
-
acc3 += weight_buf[wb3 + i] * iv;
|
|
183
194
|
}
|
|
184
195
|
}
|
|
185
196
|
}
|
|
@@ -187,10 +198,156 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
187
198
|
let baseO = y * params.out_w * O + x * O;
|
|
188
199
|
output_buf[baseO + o0] = act(acc0, params.activation);
|
|
189
200
|
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
201
|
}
|
|
193
|
-
\`;function
|
|
202
|
+
\`;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
|
|
203
|
+
// the math; this is the f32 storage build (mat4x4<f32>).
|
|
204
|
+
|
|
205
|
+
struct Params {
|
|
206
|
+
in_h : u32,
|
|
207
|
+
in_w : u32,
|
|
208
|
+
out_h : u32,
|
|
209
|
+
out_w : u32,
|
|
210
|
+
in_groups : u32,
|
|
211
|
+
out_groups : u32,
|
|
212
|
+
kernel_h : u32,
|
|
213
|
+
kernel_w : u32,
|
|
214
|
+
stride : u32,
|
|
215
|
+
pad_top : u32,
|
|
216
|
+
pad_left : u32,
|
|
217
|
+
activation : u32,
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
@group(0) @binding(0) var<storage, read> input_buf : array<vec4<f32>>;
|
|
221
|
+
@group(0) @binding(1) var<storage, read> weight_buf : array<mat4x4<f32>>;
|
|
222
|
+
@group(0) @binding(2) var<storage, read> bias_buf : array<vec4<f32>>;
|
|
223
|
+
@group(0) @binding(3) var<uniform> params : Params;
|
|
224
|
+
@group(0) @binding(4) var<storage, read_write> output_buf : array<vec4<f32>>;
|
|
225
|
+
|
|
226
|
+
fn act(v: vec4<f32>, a: u32) -> vec4<f32> {
|
|
227
|
+
if (a == 1u) { return clamp(v, vec4<f32>(0.0), vec4<f32>(6.0)); }
|
|
228
|
+
if (a == 2u) { return max(v, vec4<f32>(0.0)); }
|
|
229
|
+
if (a == 3u) { return max(v, 0.1 * v); }
|
|
230
|
+
return v;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
@compute @workgroup_size(8, 8, 1)
|
|
234
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
235
|
+
let ox = gid.x;
|
|
236
|
+
let oy = gid.y;
|
|
237
|
+
let o = gid.z;
|
|
238
|
+
|
|
239
|
+
if (ox >= params.out_w || oy >= params.out_h || o >= params.out_groups) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
let I = params.in_groups;
|
|
244
|
+
let O = params.out_groups;
|
|
245
|
+
let s = i32(params.stride);
|
|
246
|
+
|
|
247
|
+
var result = bias_buf[o];
|
|
248
|
+
|
|
249
|
+
for (var ky = 0u; ky < params.kernel_h; ky++) {
|
|
250
|
+
for (var kx = 0u; kx < params.kernel_w; kx++) {
|
|
251
|
+
let iy_num = i32(oy) + i32(params.pad_top) - i32(ky);
|
|
252
|
+
let ix_num = i32(ox) + i32(params.pad_left) - i32(kx);
|
|
253
|
+
if (iy_num < 0 || ix_num < 0 || (iy_num % s) != 0 || (ix_num % s) != 0) {
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
let iy = iy_num / s;
|
|
257
|
+
let ix = ix_num / s;
|
|
258
|
+
if (iy >= i32(params.in_h) || ix >= i32(params.in_w)) {
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
let z = ky * params.kernel_w + kx;
|
|
263
|
+
for (var i = 0u; i < I; i++) {
|
|
264
|
+
let in_idx = u32(iy) * params.in_w * I + u32(ix) * I + i;
|
|
265
|
+
let w_idx = z * O * I + o * I + i;
|
|
266
|
+
result += weight_buf[w_idx] * input_buf[in_idx];
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
output_buf[oy * params.out_w * O + ox * O + o] = act(result, params.activation);
|
|
272
|
+
}
|
|
273
|
+
\`;var Ot=\`enable f16;
|
|
274
|
+
|
|
275
|
+
// ConvTranspose2d \\u2014 gather form, full f16 variant.
|
|
276
|
+
// Each output (oy,ox) sums every input pixel + kernel tap that maps onto it:
|
|
277
|
+
// iy = (oy + pad - ky) / stride (must divide evenly and be in bounds)
|
|
278
|
+
// No explicit kernel flip \\u2014 the (oy + pad - ky) indexing carries it.
|
|
279
|
+
// Weight layout is IDENTICAL to conv2d (mat4x4[z][o][i], M[in_sub][out_sub] =
|
|
280
|
+
// W(in, out, ky, kx)), so the op uploads the flat buffer unchanged.
|
|
281
|
+
|
|
282
|
+
struct Params {
|
|
283
|
+
in_h : u32,
|
|
284
|
+
in_w : u32,
|
|
285
|
+
out_h : u32,
|
|
286
|
+
out_w : u32,
|
|
287
|
+
in_groups : u32,
|
|
288
|
+
out_groups : u32,
|
|
289
|
+
kernel_h : u32,
|
|
290
|
+
kernel_w : u32,
|
|
291
|
+
stride : u32,
|
|
292
|
+
pad_top : u32,
|
|
293
|
+
pad_left : u32,
|
|
294
|
+
activation : u32,
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
@group(0) @binding(0) var<storage, read> input_buf : array<vec4<f16>>;
|
|
298
|
+
@group(0) @binding(1) var<storage, read> weight_buf : array<mat4x4<f16>>;
|
|
299
|
+
@group(0) @binding(2) var<storage, read> bias_buf : array<vec4<f16>>;
|
|
300
|
+
@group(0) @binding(3) var<uniform> params : Params;
|
|
301
|
+
@group(0) @binding(4) var<storage, read_write> output_buf : array<vec4<f16>>;
|
|
302
|
+
|
|
303
|
+
fn act(v: vec4<f16>, a: u32) -> vec4<f16> {
|
|
304
|
+
if (a == 1u) { return clamp(v, vec4<f16>(0.0h), vec4<f16>(6.0h)); }
|
|
305
|
+
if (a == 2u) { return max(v, vec4<f16>(0.0h)); }
|
|
306
|
+
if (a == 3u) { return max(v, 0.1h * v); }
|
|
307
|
+
return v;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
@compute @workgroup_size(8, 8, 1)
|
|
311
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
312
|
+
let ox = gid.x;
|
|
313
|
+
let oy = gid.y;
|
|
314
|
+
let o = gid.z;
|
|
315
|
+
|
|
316
|
+
if (ox >= params.out_w || oy >= params.out_h || o >= params.out_groups) {
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
let I = params.in_groups;
|
|
321
|
+
let O = params.out_groups;
|
|
322
|
+
let s = i32(params.stride);
|
|
323
|
+
|
|
324
|
+
var result = bias_buf[o];
|
|
325
|
+
|
|
326
|
+
for (var ky = 0u; ky < params.kernel_h; ky++) {
|
|
327
|
+
for (var kx = 0u; kx < params.kernel_w; kx++) {
|
|
328
|
+
let iy_num = i32(oy) + i32(params.pad_top) - i32(ky);
|
|
329
|
+
let ix_num = i32(ox) + i32(params.pad_left) - i32(kx);
|
|
330
|
+
if (iy_num < 0 || ix_num < 0 || (iy_num % s) != 0 || (ix_num % s) != 0) {
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
let iy = iy_num / s;
|
|
334
|
+
let ix = ix_num / s;
|
|
335
|
+
if (iy >= i32(params.in_h) || ix >= i32(params.in_w)) {
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
let z = ky * params.kernel_w + kx;
|
|
340
|
+
for (var i = 0u; i < I; i++) {
|
|
341
|
+
let in_idx = u32(iy) * params.in_w * I + u32(ix) * I + i;
|
|
342
|
+
let w_idx = z * O * I + o * I + i;
|
|
343
|
+
result += weight_buf[w_idx] * input_buf[in_idx];
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
output_buf[oy * params.out_w * O + ox * O + o] = act(result, params.activation);
|
|
349
|
+
}
|
|
350
|
+
\`;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
351
|
//
|
|
195
352
|
// Weight layout: [K*K][channel_groups] array of vec4
|
|
196
353
|
// weight index = (ky*kernel_w + kx) * channel_groups + c
|
|
@@ -265,7 +422,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
265
422
|
let out_idx = y * params.out_w * C + x * C + c;
|
|
266
423
|
output_buf[out_idx] = result;
|
|
267
424
|
}
|
|
268
|
-
\`;var
|
|
425
|
+
\`;var At=\`enable f16;
|
|
269
426
|
|
|
270
427
|
// Depthwise conv2d \\u2014 full f16 variant. All buffers f16.
|
|
271
428
|
|
|
@@ -330,7 +487,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
330
487
|
|
|
331
488
|
output_buf[y * params.out_w * C + x * C + c] = result;
|
|
332
489
|
}
|
|
333
|
-
\`;var
|
|
490
|
+
\`;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
491
|
// Operates on the flat float buffer directly; layout is irrelevant for a pure element-wise op.
|
|
335
492
|
|
|
336
493
|
struct Params {
|
|
@@ -351,7 +508,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
351
508
|
if (idx >= params.size) { return; }
|
|
352
509
|
output[idx] = input_a[idx] + input_b[idx];
|
|
353
510
|
}
|
|
354
|
-
\`;var
|
|
511
|
+
\`;var Rt=\`enable f16;
|
|
355
512
|
|
|
356
513
|
// Element-wise add \\u2014 full f16 variant.
|
|
357
514
|
// array<f16> is binary-compatible with array<vec4<f16>> written by the f16 conv shaders.
|
|
@@ -374,7 +531,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
374
531
|
if (idx >= params.size) { return; }
|
|
375
532
|
output[idx] = input_a[idx] + input_b[idx];
|
|
376
533
|
}
|
|
377
|
-
\`;var
|
|
534
|
+
\`;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
535
|
// Operates on packed vec4 buffers (NHWC layout). exp() and arithmetic are element-wise on vec4.
|
|
379
536
|
|
|
380
537
|
struct Params {
|
|
@@ -394,7 +551,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
394
551
|
if (idx >= params.n_groups) { return; }
|
|
395
552
|
output_buf[idx] = 1.0 / (1.0 + exp(-input_buf[idx]));
|
|
396
553
|
}
|
|
397
|
-
\`;var
|
|
554
|
+
\`;var zt=\`enable f16;
|
|
398
555
|
|
|
399
556
|
// Sigmoid \\u2014 full f16 variant.
|
|
400
557
|
|
|
@@ -416,7 +573,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
416
573
|
let x = vec4<f32>(input_buf[idx]);
|
|
417
574
|
output_buf[idx] = vec4<f16>(1.0 / (1.0 + exp(-x)));
|
|
418
575
|
}
|
|
419
|
-
\`;var
|
|
576
|
+
\`;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
577
|
// Operates on packed vec4 buffers (NHWC layout). tanh() is element-wise on vec4.
|
|
421
578
|
|
|
422
579
|
struct Params {
|
|
@@ -436,7 +593,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
436
593
|
if (idx >= params.n_groups) { return; }
|
|
437
594
|
output_buf[idx] = tanh(input_buf[idx]);
|
|
438
595
|
}
|
|
439
|
-
\`;var
|
|
596
|
+
\`;var Nt=\`enable f16;
|
|
440
597
|
|
|
441
598
|
// Tanh \\u2014 full f16 variant.
|
|
442
599
|
|
|
@@ -458,7 +615,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
458
615
|
let x = vec4<f32>(input_buf[idx]);
|
|
459
616
|
output_buf[idx] = vec4<f16>(tanh(x));
|
|
460
617
|
}
|
|
461
|
-
\`;var
|
|
618
|
+
\`;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
619
|
// Same flat-float layout as add.wgsl.
|
|
463
620
|
|
|
464
621
|
struct Params {
|
|
@@ -479,7 +636,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
479
636
|
if (idx >= params.size) { return; }
|
|
480
637
|
output[idx] = input_a[idx] * input_b[idx];
|
|
481
638
|
}
|
|
482
|
-
\`;var
|
|
639
|
+
\`;var Xt=\`enable f16;
|
|
483
640
|
|
|
484
641
|
// Element-wise multiply \\u2014 full f16 variant.
|
|
485
642
|
// array<f16> is binary-compatible with array<vec4<f16>> written by the f16 conv shaders.
|
|
@@ -502,7 +659,208 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
502
659
|
if (idx >= params.size) { return; }
|
|
503
660
|
output[idx] = input_a[idx] * input_b[idx];
|
|
504
661
|
}
|
|
505
|
-
\`;var
|
|
662
|
+
\`;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.
|
|
663
|
+
|
|
664
|
+
struct Params {
|
|
665
|
+
h : u32,
|
|
666
|
+
w : u32,
|
|
667
|
+
flow_scale : f32,
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
@group(0) @binding(0) var<storage, read> source_buf : array<vec4<f32>>;
|
|
671
|
+
@group(0) @binding(1) var<storage, read> flow_buf : array<vec4<f32>>;
|
|
672
|
+
@group(0) @binding(2) var<uniform> params : Params;
|
|
673
|
+
@group(0) @binding(3) var<storage, read_write> output_buf : array<vec4<f32>>;
|
|
674
|
+
|
|
675
|
+
fn samp(x: i32, y: i32, W: i32, H: i32) -> vec4<f32> {
|
|
676
|
+
let cx = clamp(x, 0, W - 1);
|
|
677
|
+
let cy = clamp(y, 0, H - 1);
|
|
678
|
+
return source_buf[u32(cy) * u32(W) + u32(cx)];
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
@compute @workgroup_size(8, 8, 1)
|
|
682
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
683
|
+
let x = gid.x;
|
|
684
|
+
let y = gid.y;
|
|
685
|
+
if (x >= params.w || y >= params.h) { return; }
|
|
686
|
+
|
|
687
|
+
let W = i32(params.w);
|
|
688
|
+
let H = i32(params.h);
|
|
689
|
+
let idx = y * params.w + x;
|
|
690
|
+
|
|
691
|
+
let f = flow_buf[idx].xy;
|
|
692
|
+
let sx = clamp(f32(x) + params.flow_scale * f.x, 0.0, f32(W - 1));
|
|
693
|
+
let sy = clamp(f32(y) + params.flow_scale * f.y, 0.0, f32(H - 1));
|
|
694
|
+
|
|
695
|
+
let x0 = i32(floor(sx));
|
|
696
|
+
let y0 = i32(floor(sy));
|
|
697
|
+
let tx = sx - f32(x0);
|
|
698
|
+
let ty = sy - f32(y0);
|
|
699
|
+
|
|
700
|
+
let top = mix(samp(x0, y0, W, H), samp(x0 + 1, y0, W, H), tx);
|
|
701
|
+
let bot = mix(samp(x0, y0 + 1, W, H), samp(x0 + 1, y0 + 1, W, H), tx);
|
|
702
|
+
output_buf[idx] = mix(top, bot, ty);
|
|
703
|
+
}
|
|
704
|
+
\`;var qt=\`enable f16;
|
|
705
|
+
|
|
706
|
+
// Bilinear gather-warp (f16 storage, f32 coordinate math). For each output pixel
|
|
707
|
+
// p, sample the source at p + flow_scale\\xB7flow[p].xy and bilinearly interpolate,
|
|
708
|
+
// clamping the sample to the edge (border-replicate). Source + flow are 4-ch
|
|
709
|
+
// (1 group), same resolution; flow vector is in .xy.
|
|
710
|
+
|
|
711
|
+
struct Params {
|
|
712
|
+
h : u32,
|
|
713
|
+
w : u32,
|
|
714
|
+
flow_scale : f32,
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
@group(0) @binding(0) var<storage, read> source_buf : array<vec4<f16>>;
|
|
718
|
+
@group(0) @binding(1) var<storage, read> flow_buf : array<vec4<f16>>;
|
|
719
|
+
@group(0) @binding(2) var<uniform> params : Params;
|
|
720
|
+
@group(0) @binding(3) var<storage, read_write> output_buf : array<vec4<f16>>;
|
|
721
|
+
|
|
722
|
+
fn samp(x: i32, y: i32, W: i32, H: i32) -> vec4<f32> {
|
|
723
|
+
let cx = clamp(x, 0, W - 1);
|
|
724
|
+
let cy = clamp(y, 0, H - 1);
|
|
725
|
+
return vec4<f32>(source_buf[u32(cy) * u32(W) + u32(cx)]);
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
@compute @workgroup_size(8, 8, 1)
|
|
729
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
730
|
+
let x = gid.x;
|
|
731
|
+
let y = gid.y;
|
|
732
|
+
if (x >= params.w || y >= params.h) { return; }
|
|
733
|
+
|
|
734
|
+
let W = i32(params.w);
|
|
735
|
+
let H = i32(params.h);
|
|
736
|
+
let idx = y * params.w + x;
|
|
737
|
+
|
|
738
|
+
let f = vec2<f32>(flow_buf[idx].xy);
|
|
739
|
+
let sx = clamp(f32(x) + params.flow_scale * f.x, 0.0, f32(W - 1));
|
|
740
|
+
let sy = clamp(f32(y) + params.flow_scale * f.y, 0.0, f32(H - 1));
|
|
741
|
+
|
|
742
|
+
let x0 = i32(floor(sx));
|
|
743
|
+
let y0 = i32(floor(sy));
|
|
744
|
+
let tx = sx - f32(x0);
|
|
745
|
+
let ty = sy - f32(y0);
|
|
746
|
+
|
|
747
|
+
let top = mix(samp(x0, y0, W, H), samp(x0 + 1, y0, W, H), tx);
|
|
748
|
+
let bot = mix(samp(x0, y0 + 1, W, H), samp(x0 + 1, y0 + 1, W, H), tx);
|
|
749
|
+
output_buf[idx] = vec4<f16>(mix(top, bot, ty));
|
|
750
|
+
}
|
|
751
|
+
\`;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.
|
|
752
|
+
|
|
753
|
+
struct Params {
|
|
754
|
+
h : u32,
|
|
755
|
+
w : u32,
|
|
756
|
+
t_lo : f32,
|
|
757
|
+
t_hi : f32,
|
|
758
|
+
leak : f32,
|
|
759
|
+
release : f32,
|
|
760
|
+
t_div : f32,
|
|
761
|
+
div_scale: f32,
|
|
762
|
+
step_x : u32,
|
|
763
|
+
step_y : u32,
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
@group(0) @binding(0) var<storage, read> flow_buf : array<vec4<f32>>;
|
|
767
|
+
@group(0) @binding(1) var<storage, read> pred_buf : array<vec4<f32>>;
|
|
768
|
+
@group(0) @binding(2) var<storage, read> ref_buf : array<vec4<f32>>;
|
|
769
|
+
@group(0) @binding(3) var<storage, read> env_prev_buf : array<vec4<f32>>;
|
|
770
|
+
@group(0) @binding(4) var<uniform> params : Params;
|
|
771
|
+
@group(0) @binding(5) var<storage, read_write> output_buf : array<vec4<f32>>;
|
|
772
|
+
|
|
773
|
+
@compute @workgroup_size(8, 8, 1)
|
|
774
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
775
|
+
let x = gid.x;
|
|
776
|
+
let y = gid.y;
|
|
777
|
+
if (x >= params.w || y >= params.h) { return; }
|
|
778
|
+
let idx = y * params.w + x;
|
|
779
|
+
|
|
780
|
+
let mag = length(flow_buf[idx].xy);
|
|
781
|
+
let env_prev = env_prev_buf[idx].y;
|
|
782
|
+
let env = max(mag, params.release * env_prev);
|
|
783
|
+
|
|
784
|
+
let xr = min(x + params.step_x, params.w - 1u);
|
|
785
|
+
let xl = select(x - params.step_x, 0u, x < params.step_x);
|
|
786
|
+
let yd = min(y + params.step_y, params.h - 1u);
|
|
787
|
+
let yu = select(y - params.step_y, 0u, y < params.step_y);
|
|
788
|
+
let dfx = flow_buf[y * params.w + xr].x - flow_buf[y * params.w + xl].x;
|
|
789
|
+
let dfy = flow_buf[yd * params.w + x].y - flow_buf[yu * params.w + x].y;
|
|
790
|
+
let divg = abs(dfx + dfy);
|
|
791
|
+
|
|
792
|
+
let g_mag = clamp((env - params.t_lo) / max(params.t_hi - params.t_lo, 1e-3), 0.0, 1.0);
|
|
793
|
+
let g_div = clamp((divg - params.t_div) / max(params.div_scale, 1e-3), 0.0, 1.0);
|
|
794
|
+
let g = max(max(g_mag, g_div), params.leak);
|
|
795
|
+
|
|
796
|
+
let pred = pred_buf[idx].x;
|
|
797
|
+
let refv = ref_buf[idx].x;
|
|
798
|
+
let stab = g * pred + (1.0 - g) * refv;
|
|
799
|
+
|
|
800
|
+
output_buf[idx] = vec4<f32>(stab, env, 0.0, 0.0);
|
|
801
|
+
}
|
|
802
|
+
\`;var Yt=\`enable f16;
|
|
803
|
+
|
|
804
|
+
// Flow-gated temporal stabilizer (f16 storage, f32 gate math). Per pixel:
|
|
805
|
+
// env = max(|flow.xy|, release\\xB7envPrev.y) peak-hold (fast attack, slow release)
|
|
806
|
+
// div = |\\u2202fx/\\u2202x + \\u2202fy/\\u2202y| flow divergence (occlusion seam)
|
|
807
|
+
// g = max(clamp((env-tLo)/(tHi-tLo),0,1), clamp((div-tDiv)/divScale,0,1), leak)
|
|
808
|
+
// out = vec4((g\\xB7pred + (1-g)\\xB7ref).x, env, 0, 0)
|
|
809
|
+
// The divergence term opens the gate at occlusion/disocclusion boundaries (where
|
|
810
|
+
// the flow tears but the revealed-background magnitude is ~0). Finite-difference
|
|
811
|
+
// step spans ~1 base/4 pixel. alpha is in .x of pred/ref; env threads via .y.
|
|
812
|
+
|
|
813
|
+
struct Params {
|
|
814
|
+
h : u32,
|
|
815
|
+
w : u32,
|
|
816
|
+
t_lo : f32,
|
|
817
|
+
t_hi : f32,
|
|
818
|
+
leak : f32,
|
|
819
|
+
release : f32,
|
|
820
|
+
t_div : f32,
|
|
821
|
+
div_scale: f32,
|
|
822
|
+
step_x : u32,
|
|
823
|
+
step_y : u32,
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
@group(0) @binding(0) var<storage, read> flow_buf : array<vec4<f16>>;
|
|
827
|
+
@group(0) @binding(1) var<storage, read> pred_buf : array<vec4<f16>>;
|
|
828
|
+
@group(0) @binding(2) var<storage, read> ref_buf : array<vec4<f16>>;
|
|
829
|
+
@group(0) @binding(3) var<storage, read> env_prev_buf : array<vec4<f16>>;
|
|
830
|
+
@group(0) @binding(4) var<uniform> params : Params;
|
|
831
|
+
@group(0) @binding(5) var<storage, read_write> output_buf : array<vec4<f16>>;
|
|
832
|
+
|
|
833
|
+
@compute @workgroup_size(8, 8, 1)
|
|
834
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
835
|
+
let x = gid.x;
|
|
836
|
+
let y = gid.y;
|
|
837
|
+
if (x >= params.w || y >= params.h) { return; }
|
|
838
|
+
let idx = y * params.w + x;
|
|
839
|
+
|
|
840
|
+
let mag = length(vec2<f32>(flow_buf[idx].xy));
|
|
841
|
+
let env_prev = f32(env_prev_buf[idx].y);
|
|
842
|
+
let env = max(mag, params.release * env_prev);
|
|
843
|
+
|
|
844
|
+
// Flow divergence over a \\xB1step finite-difference (clamped to the edges).
|
|
845
|
+
let xr = min(x + params.step_x, params.w - 1u);
|
|
846
|
+
let xl = select(x - params.step_x, 0u, x < params.step_x);
|
|
847
|
+
let yd = min(y + params.step_y, params.h - 1u);
|
|
848
|
+
let yu = select(y - params.step_y, 0u, y < params.step_y);
|
|
849
|
+
let dfx = f32(flow_buf[y * params.w + xr].x) - f32(flow_buf[y * params.w + xl].x);
|
|
850
|
+
let dfy = f32(flow_buf[yd * params.w + x].y) - f32(flow_buf[yu * params.w + x].y);
|
|
851
|
+
let divg = abs(dfx + dfy);
|
|
852
|
+
|
|
853
|
+
let g_mag = clamp((env - params.t_lo) / max(params.t_hi - params.t_lo, 1e-3), 0.0, 1.0);
|
|
854
|
+
let g_div = clamp((divg - params.t_div) / max(params.div_scale, 1e-3), 0.0, 1.0);
|
|
855
|
+
let g = max(max(g_mag, g_div), params.leak);
|
|
856
|
+
|
|
857
|
+
let pred = f32(pred_buf[idx].x);
|
|
858
|
+
let refv = f32(ref_buf[idx].x);
|
|
859
|
+
let stab = g * pred + (1.0 - g) * refv;
|
|
860
|
+
|
|
861
|
+
output_buf[idx] = vec4<f16>(f16(stab), f16(env), 0.0h, 0.0h);
|
|
862
|
+
}
|
|
863
|
+
\`;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
864
|
// Input/output in NHWC vec4 format: index = y*W*(C/4) + x*(C/4) + c_group.
|
|
507
865
|
// Each thread computes one output pixel for one channel group (vec4 = 4 channels).
|
|
508
866
|
|
|
@@ -560,7 +918,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
560
918
|
|
|
561
919
|
output_buf[oy * params.out_w * C + ox * C + c] = result;
|
|
562
920
|
}
|
|
563
|
-
\`;var
|
|
921
|
+
\`;var Jt=\`enable f16;
|
|
564
922
|
|
|
565
923
|
// Bilinear upsample 2\\xD7 \\u2014 full f16 variant.
|
|
566
924
|
// Interpolation weights (wx, wy) and intermediate blends computed in f32 for
|
|
@@ -616,7 +974,53 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
616
974
|
|
|
617
975
|
output_buf[oy * params.out_w * C + ox * C + c] = vec4<f16>(result);
|
|
618
976
|
}
|
|
619
|
-
\`;var
|
|
977
|
+
\`;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.
|
|
978
|
+
|
|
979
|
+
struct Params {
|
|
980
|
+
in_w : u32,
|
|
981
|
+
out_h : u32,
|
|
982
|
+
out_w : u32,
|
|
983
|
+
groups : u32,
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
@group(0) @binding(0) var<storage, read> input_buf : array<vec4<f32>>;
|
|
987
|
+
@group(0) @binding(1) var<uniform> params : Params;
|
|
988
|
+
@group(0) @binding(2) var<storage, read_write> output_buf : array<vec4<f32>>;
|
|
989
|
+
|
|
990
|
+
@compute @workgroup_size(8, 8, 1)
|
|
991
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
992
|
+
let x = gid.x;
|
|
993
|
+
let y = gid.y;
|
|
994
|
+
let g = gid.z;
|
|
995
|
+
if (x >= params.out_w || y >= params.out_h || g >= params.groups) { return; }
|
|
996
|
+
let G = params.groups;
|
|
997
|
+
output_buf[y * params.out_w * G + x * G + g] = input_buf[y * params.in_w * G + x * G + g];
|
|
998
|
+
}
|
|
999
|
+
\`;var er=\`enable f16;
|
|
1000
|
+
|
|
1001
|
+
// Top-left crop: output[y,x,g] = input[y,x,g] for y<outH, x<outW (training crop_like).
|
|
1002
|
+
|
|
1003
|
+
struct Params {
|
|
1004
|
+
in_w : u32,
|
|
1005
|
+
out_h : u32,
|
|
1006
|
+
out_w : u32,
|
|
1007
|
+
groups : u32,
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
@group(0) @binding(0) var<storage, read> input_buf : array<vec4<f16>>;
|
|
1011
|
+
@group(0) @binding(1) var<uniform> params : Params;
|
|
1012
|
+
@group(0) @binding(2) var<storage, read_write> output_buf : array<vec4<f16>>;
|
|
1013
|
+
|
|
1014
|
+
@compute @workgroup_size(8, 8, 1)
|
|
1015
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
1016
|
+
let x = gid.x;
|
|
1017
|
+
let y = gid.y;
|
|
1018
|
+
let g = gid.z;
|
|
1019
|
+
if (x >= params.out_w || y >= params.out_h || g >= params.groups) { return; }
|
|
1020
|
+
let G = params.groups;
|
|
1021
|
+
output_buf[y * params.out_w * G + x * G + g] = input_buf[y * params.in_w * G + x * G + g];
|
|
1022
|
+
}
|
|
1023
|
+
\`;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
1024
|
// for mode='bicubic', align_corners=False). Direct 2D, 4\\xD74 = 16 taps per
|
|
621
1025
|
// output pixel. NHWC vec4 layout: index = y*W*(C/4) + x*(C/4) + c_group.
|
|
622
1026
|
|
|
@@ -683,7 +1087,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
683
1087
|
|
|
684
1088
|
output_buf[oy * params.out_w * C + ox * C + c] = acc;
|
|
685
1089
|
}
|
|
686
|
-
\`;var
|
|
1090
|
+
\`;var rr=\`enable f16;
|
|
687
1091
|
|
|
688
1092
|
// Bicubic upsample \\u2014 full f16 storage variant. Bicubic weights and the per-
|
|
689
1093
|
// pixel accumulator are computed in f32 (cheap to keep precision around the
|
|
@@ -752,7 +1156,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
752
1156
|
|
|
753
1157
|
output_buf[oy * params.out_w * C + ox * C + c] = vec4<f16>(acc);
|
|
754
1158
|
}
|
|
755
|
-
\`;var
|
|
1159
|
+
\`;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
1160
|
// Both A and B must share the same H\\xD7W and be in NHWC vec4 format.
|
|
757
1161
|
// Output layout: for each (y, x), the first a_groups vec4s come from A,
|
|
758
1162
|
// followed by b_groups vec4s from B.
|
|
@@ -797,7 +1201,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
797
1201
|
output_buf[out_idx] = input_b[y * W * Bg + x * Bg + c_b];
|
|
798
1202
|
}
|
|
799
1203
|
}
|
|
800
|
-
\`;var
|
|
1204
|
+
\`;var ir=\`enable f16;
|
|
801
1205
|
|
|
802
1206
|
// Channel concatenation \\u2014 full f16 variant.
|
|
803
1207
|
|
|
@@ -838,7 +1242,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
838
1242
|
output_buf[out_idx] = input_b[y * W * Bg + x * Bg + c_b];
|
|
839
1243
|
}
|
|
840
1244
|
}
|
|
841
|
-
\`;var
|
|
1245
|
+
\`;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
1246
|
// Identical to conv2d.wgsl except skip is an activation input (binding 1),
|
|
843
1247
|
// added element-wise to the conv result at write time.
|
|
844
1248
|
// Eliminates the separate add dispatch and its intermediate buffer round-trip.
|
|
@@ -912,7 +1316,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
912
1316
|
let out_idx = y * params.out_w * O + x * O + o;
|
|
913
1317
|
output_buf[out_idx] = result + skip_buf[out_idx];
|
|
914
1318
|
}
|
|
915
|
-
\`;var
|
|
1319
|
+
\`;var nr=\`enable f16;
|
|
916
1320
|
|
|
917
1321
|
// Conv2d + skip add fused \\u2014 full f16 variant.
|
|
918
1322
|
|
|
@@ -986,7 +1390,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
986
1390
|
let out_idx = y * params.out_w * O + x * O + o;
|
|
987
1391
|
output_buf[out_idx] = result + skip_buf[out_idx];
|
|
988
1392
|
}
|
|
989
|
-
\`;var
|
|
1393
|
+
\`;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
1394
|
// Specializes conv2d_add to kernel=1 / stride=1 / pad=0 / no activation: drops
|
|
991
1395
|
// the kernel loop, the padding checks, and the activation branch. Used by the
|
|
992
1396
|
// MBConv project+residual tail. Both inputs share the same spatial resolution.
|
|
@@ -1031,7 +1435,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1031
1435
|
|
|
1032
1436
|
output_buf[pix * O + o] = result;
|
|
1033
1437
|
}
|
|
1034
|
-
\`;var
|
|
1438
|
+
\`;var ur=\`enable f16;
|
|
1035
1439
|
|
|
1036
1440
|
// proj_residual \\u2014 full f16 variant. See proj_residual.wgsl for layout details.
|
|
1037
1441
|
// Bespoke 1\\xD71 conv (no activation) + residual add, fused.
|
|
@@ -1073,7 +1477,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1073
1477
|
|
|
1074
1478
|
output_buf[pix * O + o] = result;
|
|
1075
1479
|
}
|
|
1076
|
-
\`;var
|
|
1480
|
+
\`;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
1481
|
// dispatch. Both inputs are already at the output resolution (the upstream
|
|
1078
1482
|
// upsample stays a separate dispatch writing a clean intermediate, so the conv
|
|
1079
1483
|
// reads are plain-indexed). Identical math to conv2d; the only difference is
|
|
@@ -1133,7 +1537,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1133
1537
|
result = clamp(result, vec4<f32>(0.0), vec4<f32>(6.0));
|
|
1134
1538
|
output_buf[(y * p.w + x) * O + o] = result;
|
|
1135
1539
|
}
|
|
1136
|
-
\`;var
|
|
1540
|
+
\`;var lr=\`enable f16;
|
|
1137
1541
|
|
|
1138
1542
|
// concat_conv2d \\u2014 full f16 variant. See concat_conv2d.wgsl for layout details.
|
|
1139
1543
|
// Fuses [concat(a, b) \\u2192 conv 3\\xD73 (pad 1) \\u2192 relu6] into one dispatch.
|
|
@@ -1188,7 +1592,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1188
1592
|
result = clamp(result, vec4<f16>(0.0h), vec4<f16>(6.0h));
|
|
1189
1593
|
output_buf[(y * p.w + x) * O + o] = result;
|
|
1190
1594
|
}
|
|
1191
|
-
\`;var
|
|
1595
|
+
\`;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
1596
|
// Production config (c_up=2, split_ratio=0.5 \\u2192 passthrough=1, recurrent=1):
|
|
1193
1597
|
// u_in : c_up=2 packed in a vec4 (.x = passthrough a, .y = recurrent b)
|
|
1194
1598
|
// h_prev : hidden carrier \\u2014 recurrent state in .z (see cand_update_fused: the
|
|
@@ -1233,7 +1637,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1233
1637
|
let r = 1.0 / (1.0 + exp(-r_pre));
|
|
1234
1638
|
output_buf[y * params.w + x] = vec4<f32>(z, r, 0.0, 0.0);
|
|
1235
1639
|
}
|
|
1236
|
-
\`;var
|
|
1640
|
+
\`;var dr=\`enable f16;
|
|
1237
1641
|
|
|
1238
1642
|
// gates_fused \\u2014 full f16 variant. See gates_fused.wgsl for layout details.
|
|
1239
1643
|
// ConvGRU z + r gates (production config c_up=2, recurrent=1).
|
|
@@ -1275,7 +1679,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1275
1679
|
let r = 1.0h / (1.0h + exp(-r_pre));
|
|
1276
1680
|
output_buf[y * params.w + x] = vec4<f16>(z, r, 0.0h, 0.0h);
|
|
1277
1681
|
}
|
|
1278
|
-
\`;var
|
|
1682
|
+
\`;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
1683
|
// Production config (c_up=2, recurrent=1):
|
|
1280
1684
|
// u_in : c_up=2 (.x = a passthrough, .y = b recurrent)
|
|
1281
1685
|
// h_prev : hidden carrier \\u2014 recurrent state in .z (the previous frame's
|
|
@@ -1328,7 +1732,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1328
1732
|
let b_out = u_cur.y + gamma_buf[0].x * h_new;
|
|
1329
1733
|
output_buf[cur] = vec4<f32>(u_cur.x, b_out, h_new, 0.0);
|
|
1330
1734
|
}
|
|
1331
|
-
\`;var
|
|
1735
|
+
\`;var fr=\`enable f16;
|
|
1332
1736
|
|
|
1333
1737
|
// cand_update_fused \\u2014 full f16 variant. See cand_update_fused.wgsl for details.
|
|
1334
1738
|
// ConvGRU candidate + state update + output (production config c_up=2, recurrent=1).
|
|
@@ -1374,7 +1778,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1374
1778
|
let b_out = u_cur.y + gamma_buf[0].x * h_new;
|
|
1375
1779
|
output_buf[cur] = vec4<f16>(u_cur.x, b_out, h_new, 0.0h);
|
|
1376
1780
|
}
|
|
1377
|
-
\`;var
|
|
1781
|
+
\`;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
1782
|
// Expands feat_lr (in_c, mult of 4) to the c_up=2 carrier \\u2014 output .xy = the 2
|
|
1379
1783
|
// native channels, .zw = 0. mat4x2 per (kpos, in_group) with a vec2 accumulator.
|
|
1380
1784
|
// Weight: 9 * in_groups mat4x2 (8 floats each, col-major). Bias .xy.
|
|
@@ -1411,7 +1815,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1411
1815
|
result = max(result, vec2<f32>(0.0)); // expand_feat is F.relu
|
|
1412
1816
|
output_buf[y * params.w + x] = vec4<f32>(result, 0.0, 0.0);
|
|
1413
1817
|
}
|
|
1414
|
-
\`;var
|
|
1818
|
+
\`;var _r=\`enable f16;
|
|
1415
1819
|
|
|
1416
1820
|
// conv_expand \\u2014 full f16 variant. See conv_expand.wgsl for layout details.
|
|
1417
1821
|
// Bespoke N\\u21922 conv 3\\xD73 (pad 1) + relu (wrapper expand_feat).
|
|
@@ -1448,7 +1852,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1448
1852
|
result = max(result, vec2<f16>(0.0h));
|
|
1449
1853
|
output_buf[y * params.w + x] = vec4<f16>(result, 0.0h, 0.0h);
|
|
1450
1854
|
}
|
|
1451
|
-
\`;var
|
|
1855
|
+
\`;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
1856
|
// u = c_up=2 carrier (.xy); d = c_high=4 (full vec4). Both same resolution.
|
|
1453
1857
|
// Channel order concat([u, d]) = (u.x, u.y, d.x, d.y, d.z, d.w), split into
|
|
1454
1858
|
// v3a = (u.x, u.y, d.x) v3b = d.yzw
|
|
@@ -1488,7 +1892,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1488
1892
|
result = max(result, vec2<f32>(0.0)); // up1_combine is F.relu
|
|
1489
1893
|
output_buf[y * params.w + x] = vec4<f32>(result, 0.0, 0.0);
|
|
1490
1894
|
}
|
|
1491
|
-
\`;var
|
|
1895
|
+
\`;var br=\`enable f16;
|
|
1492
1896
|
|
|
1493
1897
|
// cat_conv_6to2 \\u2014 full f16 variant. See cat_conv_6to2.wgsl for layout details.
|
|
1494
1898
|
// Fused concat(u, d) + 6\\u21922 conv 3\\xD73 (pad 1) + relu (E up1_combine).
|
|
@@ -1527,7 +1931,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1527
1931
|
result = max(result, vec2<f16>(0.0h));
|
|
1528
1932
|
output_buf[y * params.w + x] = vec4<f16>(result, 0.0h, 0.0h);
|
|
1529
1933
|
}
|
|
1530
|
-
\`;var
|
|
1934
|
+
\`;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
1935
|
// act) into one dispatch. E variant: down2 (c_high=4 \\u2192 c_low=4, stride 2) +
|
|
1532
1936
|
// adapter. A/B variant: down1 (RGB .xyz \\u2192 4, stride 2/3) + adapter (the down
|
|
1533
1937
|
// weight's 4th input column is zeroed at export for RGB input). Symmetric pad.
|
|
@@ -1575,7 +1979,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1575
1979
|
let adapt_out = adapt_w[0] * down_out + adapt_b[0];
|
|
1576
1980
|
output_buf[y * p.out_w + x] = vec4<f32>(adapt_out.xyz, 0.0);
|
|
1577
1981
|
}
|
|
1578
|
-
\`;var
|
|
1982
|
+
\`;var xr=\`enable f16;
|
|
1579
1983
|
|
|
1580
1984
|
// down_adapter \\u2014 full f16 variant. See down_adapter.wgsl for layout details.
|
|
1581
1985
|
// Fused stride-N 3\\xD73 conv (4\\u21924) + relu + 1\\xD71 adapter (4\\u21923, no act).
|
|
@@ -1620,7 +2024,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1620
2024
|
let adapt_out = adapt_w[0] * down_out + adapt_b[0];
|
|
1621
2025
|
output_buf[y * p.out_w + x] = vec4<f16>(adapt_out.xyz, 0.0h);
|
|
1622
2026
|
}
|
|
1623
|
-
\`;var
|
|
2027
|
+
\`;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
2028
|
// u = c_up=2 carrier (.xy); rgb = x_hr (.xyz). 5 inputs \\u2192 1 alpha (output .x).
|
|
1625
2029
|
// Weight: 18 vec4 \\u2014 [0..8] = (w0, w1, 0, 0) for u per kpos; [9..17] =
|
|
1626
2030
|
// (w2, w3, w4, 0) for rgb per kpos. Bias .x.
|
|
@@ -1654,7 +2058,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1654
2058
|
|
|
1655
2059
|
output_buf[y * params.w + x] = vec4<f32>(1.0 / (1.0 + exp(-acc)), 0.0, 0.0, 0.0);
|
|
1656
2060
|
}
|
|
1657
|
-
\`;var
|
|
2061
|
+
\`;var wr=\`enable f16;
|
|
1658
2062
|
|
|
1659
2063
|
// up_final \\u2014 full f16 variant. See up_final.wgsl for layout details.
|
|
1660
2064
|
// Fused concat(u, rgb) \\u2192 conv 3\\xD73 5\\u21921 \\u2192 sigmoid (A/B alpha head).
|
|
@@ -1688,7 +2092,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1688
2092
|
|
|
1689
2093
|
output_buf[y * params.w + x] = vec4<f16>(1.0h / (1.0h + exp(-acc)), 0.0h, 0.0h, 0.0h);
|
|
1690
2094
|
}
|
|
1691
|
-
\`;var
|
|
2095
|
+
\`;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
2096
|
// \\u2192 sigmoid. u = c_up=2 (.xy); d_full = c_high=4 full-res skip (full vec4);
|
|
1693
2097
|
// rgb = x_hr (.xyz). Channel order concat = 2 + 4 + 3 = 9. Output .x = alpha.
|
|
1694
2098
|
// Weight: 27 vec4 (3 per kpos): [kpos*3+0]=(w0,w1,0,0) u; [kpos*3+1]=(w2..w5)
|
|
@@ -1725,7 +2129,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1725
2129
|
|
|
1726
2130
|
output_buf[y * params.w + x] = vec4<f32>(1.0 / (1.0 + exp(-acc)), 0.0, 0.0, 0.0);
|
|
1727
2131
|
}
|
|
1728
|
-
\`;var
|
|
2132
|
+
\`;var Tr=\`enable f16;
|
|
1729
2133
|
|
|
1730
2134
|
// up_final_skip \\u2014 full f16 variant. See up_final_skip.wgsl for layout details.
|
|
1731
2135
|
// C/D alpha head: fused concat(u, d_full, rgb) \\u2192 conv 3\\xD73 9\\u21921 \\u2192 sigmoid.
|
|
@@ -1761,7 +2165,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1761
2165
|
|
|
1762
2166
|
output_buf[y * params.w + x] = vec4<f16>(1.0h / (1.0h + exp(-acc)), 0.0h, 0.0h, 0.0h);
|
|
1763
2167
|
}
|
|
1764
|
-
\`;var
|
|
2168
|
+
\`;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
2169
|
// input_a is the decoder tensor at small spatial resolution (in_h \\xD7 in_w).
|
|
1766
2170
|
// input_b is the encoder skip feature already at output resolution (out_h \\xD7 out_w).
|
|
1767
2171
|
// For output channels 0..a_groups-1: bilinearly interpolate from input_a.
|
|
@@ -1822,7 +2226,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1822
2226
|
output_buf[out_idx] = input_b[oy * params.out_w * params.b_groups + ox * params.b_groups + c_b];
|
|
1823
2227
|
}
|
|
1824
2228
|
}
|
|
1825
|
-
\`;var
|
|
2229
|
+
\`;var Wr=\`enable f16;
|
|
1826
2230
|
|
|
1827
2231
|
// Bilinear upsample + channel concat fused \\u2014 full f16 variant.
|
|
1828
2232
|
// Bilinear weights (wx, wy) and intermediate blends computed in f32; result cast to f16.
|
|
@@ -1882,7 +2286,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1882
2286
|
output_buf[out_idx] = input_b[oy * params.out_w * params.b_groups + ox * params.b_groups + c_b];
|
|
1883
2287
|
}
|
|
1884
2288
|
}
|
|
1885
|
-
\`;var
|
|
2289
|
+
\`;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
2290
|
// For each output pixel, bilinearly samples the small input for each in_group,
|
|
1887
2291
|
// immediately applies the 1\\xD71 conv weights, and writes the activated result.
|
|
1888
2292
|
// Eliminates the intermediate full-resolution upsample buffer.
|
|
@@ -1949,7 +2353,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
1949
2353
|
|
|
1950
2354
|
output_buf[oy * params.out_w * params.out_groups + ox * params.out_groups + og] = result;
|
|
1951
2355
|
}
|
|
1952
|
-
\`;var
|
|
2356
|
+
\`;var Gr=\`enable f16;
|
|
1953
2357
|
|
|
1954
2358
|
// Bilinear upsample + 1\\xD71 pointwise conv fused \\u2014 full f16 variant.
|
|
1955
2359
|
// Bilinear weights and intermediate blends computed in f32; conv accumulation in f16.
|
|
@@ -2016,7 +2420,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
2016
2420
|
|
|
2017
2421
|
output_buf[oy * params.out_w * params.out_groups + ox * params.out_groups + og] = result;
|
|
2018
2422
|
}
|
|
2019
|
-
\`;var
|
|
2423
|
+
\`;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
2424
|
// Identical to bilinear_upsample.wgsl except sigmoid is applied at write time.
|
|
2021
2425
|
// Eliminates the intermediate full-resolution buffer and the separate sigmoid dispatch.
|
|
2022
2426
|
|
|
@@ -2070,7 +2474,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
2070
2474
|
|
|
2071
2475
|
output_buf[oy * params.out_w * C + ox * C + c] = 1.0 / (1.0 + exp(-result));
|
|
2072
2476
|
}
|
|
2073
|
-
\`;var
|
|
2477
|
+
\`;var Ur=\`enable f16;
|
|
2074
2478
|
|
|
2075
2479
|
// Bilinear upsample + sigmoid fused \\u2014 full f16 variant.
|
|
2076
2480
|
// Interpolation computed in f32 for accuracy; sigmoid and result cast to f16.
|
|
@@ -2125,7 +2529,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
2125
2529
|
|
|
2126
2530
|
output_buf[oy * params.out_w * C + ox * C + c] = vec4<f16>(1.0 / (1.0 + exp(-result)));
|
|
2127
2531
|
}
|
|
2128
|
-
\`;var
|
|
2532
|
+
\`;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
2533
|
// Fragment writes the canvas's swapchain texture (premultiplied output).
|
|
2130
2534
|
//
|
|
2131
2535
|
// Caller invariants (matched in CompositeSolidWebGPU):
|
|
@@ -2170,7 +2574,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
2170
2574
|
let rgb = fg * a + params.bgColor.rgb * (1.0 - a);
|
|
2171
2575
|
return vec4<f32>(rgb, 1.0);
|
|
2172
2576
|
}
|
|
2173
|
-
\`;var
|
|
2577
|
+
\`;var Lr=\`enable f16;
|
|
2174
2578
|
|
|
2175
2579
|
// Composite an RGBA image over a solid background, gated by a 1-ch alpha.
|
|
2176
2580
|
// f16 variant: image and alpha are stored as f16; values promote to f32 on
|
|
@@ -2219,7 +2623,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
2219
2623
|
let rgb = fg * a + params.bgColor.rgb * (1.0 - a);
|
|
2220
2624
|
return vec4<f32>(rgb, 1.0);
|
|
2221
2625
|
}
|
|
2222
|
-
\`;var
|
|
2626
|
+
\`;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
2627
|
// background image, or a blurred copy of the input).
|
|
2224
2628
|
|
|
2225
2629
|
struct VertexOut {
|
|
@@ -2261,7 +2665,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
2261
2665
|
let rgb = fg * a + bgc * (1.0 - a);
|
|
2262
2666
|
return vec4<f32>(rgb, 1.0);
|
|
2263
2667
|
}
|
|
2264
|
-
\`;var
|
|
2668
|
+
\`;var Er=\`enable f16;
|
|
2265
2669
|
|
|
2266
2670
|
// Like composite_solid_f16 but bg is an NHWC vec4<f16> storage buffer (e.g. a
|
|
2267
2671
|
// virtual background image, or a blurred copy of the input).
|
|
@@ -2305,7 +2709,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
2305
2709
|
let rgb = fg * a + bgc * (1.0 - a);
|
|
2306
2710
|
return vec4<f32>(rgb, 1.0);
|
|
2307
2711
|
}
|
|
2308
|
-
\`;var
|
|
2712
|
+
\`;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
2713
|
// (image, alpha). Used by CompositorBlur to skip the final full-res upsample
|
|
2310
2714
|
// in the blur pyramid and let this shader's own per-pixel scan do the
|
|
2311
2715
|
// expansion (the work is already happening here for the composite anyway).
|
|
@@ -2370,7 +2774,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
2370
2774
|
let rgb = fg * a + bgc * (1.0 - a);
|
|
2371
2775
|
return vec4<f32>(rgb, 1.0);
|
|
2372
2776
|
}
|
|
2373
|
-
\`;var
|
|
2777
|
+
\`;var Or=\`enable f16;
|
|
2374
2778
|
|
|
2375
2779
|
// f16 storage variant of composite_image_bilinear. bg is at a smaller
|
|
2376
2780
|
// resolution and is bilinearly sampled to match (image, alpha) at full res.
|
|
@@ -2431,7 +2835,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
2431
2835
|
let rgb = fg * a + bgc * (1.0 - a);
|
|
2432
2836
|
return vec4<f32>(rgb, 1.0);
|
|
2433
2837
|
}
|
|
2434
|
-
\`;var
|
|
2838
|
+
\`;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
2839
|
// swapchain texture with no alpha math and no background. Used by RenderOp
|
|
2436
2840
|
// when the renderer is in disabled state, so the output canvas reflects
|
|
2437
2841
|
// the unmodified input frame instead of a stale matted result.
|
|
@@ -2469,7 +2873,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
2469
2873
|
let i = y * params.width + x;
|
|
2470
2874
|
return vec4<f32>(image[i].rgb, 1.0);
|
|
2471
2875
|
}
|
|
2472
|
-
\`;var
|
|
2876
|
+
\`;var Ar=\`enable f16;
|
|
2473
2877
|
|
|
2474
2878
|
// Passthrough "compositor" \\u2014 f16 variant. Image is stored as f16; values
|
|
2475
2879
|
// promote to f32 on read and the fragment writes f32 to the canvas
|
|
@@ -2505,7 +2909,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
2505
2909
|
let i = y * params.width + x;
|
|
2506
2910
|
return vec4<f32>(vec3<f32>(image[i].rgb), 1.0);
|
|
2507
2911
|
}
|
|
2508
|
-
\`;var
|
|
2912
|
+
\`;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
2913
|
// vec4<f32> output buffer at the target resolution. Used for ImageBitmap
|
|
2510
2914
|
// sources, which are uploaded into a persistent staging texture via
|
|
2511
2915
|
// copyExternalImageToTexture before each dispatch.
|
|
@@ -2535,7 +2939,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
2535
2939
|
let rgba = textureSampleLevel(src_tex, src_sampler, uv, 0.0);
|
|
2536
2940
|
output_buf[y * params.out_w + x] = rgba;
|
|
2537
2941
|
}
|
|
2538
|
-
\`;var
|
|
2942
|
+
\`;var Rr=\`enable f16;
|
|
2539
2943
|
|
|
2540
2944
|
// Input op \\u2014 f16 storage variant. Source is sampled as vec4<f32>; only the
|
|
2541
2945
|
// store is demoted to vec4<f16>.
|
|
@@ -2565,7 +2969,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
2565
2969
|
let rgba = textureSampleLevel(src_tex, src_sampler, uv, 0.0);
|
|
2566
2970
|
output_buf[y * params.out_w + x] = vec4<f16>(rgba);
|
|
2567
2971
|
}
|
|
2568
|
-
\`;var
|
|
2972
|
+
\`;var Hr=\`// Input op \\u2014 sample a GPUExternalTexture (zero-copy VideoFrame import) into
|
|
2569
2973
|
// the NHWC vec4<f32> output buffer at the target resolution. Used when the
|
|
2570
2974
|
// caller passes a VideoFrame to setSource(); requires importExternalTexture
|
|
2571
2975
|
// to be called in the same task as the dispatch (the texture is invalidated
|
|
@@ -2596,7 +3000,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
2596
3000
|
let rgba = textureSampleBaseClampToEdge(src_tex, src_sampler, uv);
|
|
2597
3001
|
output_buf[y * params.out_w + x] = rgba;
|
|
2598
3002
|
}
|
|
2599
|
-
\`;var
|
|
3003
|
+
\`;var zr=\`enable f16;
|
|
2600
3004
|
|
|
2601
3005
|
// Input op \\u2014 texture_external + f16 storage. Sample in f32, store as f16.
|
|
2602
3006
|
|
|
@@ -2625,12 +3029,12 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
2625
3029
|
let rgba = textureSampleBaseClampToEdge(src_tex, src_sampler, uv);
|
|
2626
3030
|
output_buf[y * params.out_w + x] = vec4<f16>(rgba);
|
|
2627
3031
|
}
|
|
2628
|
-
\`;var
|
|
3032
|
+
\`;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
3033
|
const vec2 VERTS[6] = vec2[6](
|
|
2630
3034
|
vec2(-1.0,-1.0), vec2(1.0,-1.0), vec2(-1.0,1.0),
|
|
2631
3035
|
vec2(-1.0,1.0), vec2(1.0,-1.0), vec2(1.0,1.0)
|
|
2632
3036
|
);
|
|
2633
|
-
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }\`,h=class{constructor(t){
|
|
3037
|
+
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
3038
|
// Conv2d \\u2014 handles all variants: 1\\xD71 (pointwise), 3\\xD73, 5\\xD75, strided, BN-fused.
|
|
2635
3039
|
//
|
|
2636
3040
|
// Tensor layout: NHWC vec4 \\u2014 texture dimensions (W * C/4, H).
|
|
@@ -2663,7 +3067,7 @@ uniform int u_kernel_w;
|
|
|
2663
3067
|
uniform int u_stride;
|
|
2664
3068
|
uniform int u_pad_top;
|
|
2665
3069
|
uniform int u_pad_left;
|
|
2666
|
-
uniform int u_activation; // 0 = none, 1 = relu6, 2 = relu
|
|
3070
|
+
uniform int u_activation; // 0 = none, 1 = relu6, 2 = relu, 3 = leaky(0.1)
|
|
2667
3071
|
|
|
2668
3072
|
out vec4 fragColor;
|
|
2669
3073
|
|
|
@@ -2703,10 +3107,80 @@ void main() {
|
|
|
2703
3107
|
|
|
2704
3108
|
if (u_activation == 1) result = clamp(result, 0.0, 6.0);
|
|
2705
3109
|
else if (u_activation == 2) result = max(result, vec4(0.0));
|
|
3110
|
+
else if (u_activation == 3) result = max(result, 0.1 * result);
|
|
2706
3111
|
|
|
2707
3112
|
fragColor = result;
|
|
2708
3113
|
}
|
|
2709
|
-
\`;var
|
|
3114
|
+
\`;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
|
|
3115
|
+
// ConvTranspose2d \\u2014 gather form. Identical texture layouts + mat4 weight
|
|
3116
|
+
// semantics as conv2d.glsl; only the spatial mapping differs:
|
|
3117
|
+
// in_y = (y_out + pad - ky) / stride (must divide evenly + be in bounds)
|
|
3118
|
+
// No explicit kernel flip \\u2014 the (y_out + pad - ky) indexing carries it.
|
|
3119
|
+
|
|
3120
|
+
precision highp float;
|
|
3121
|
+
precision highp int;
|
|
3122
|
+
|
|
3123
|
+
uniform sampler2D u_input; // (in_W * in_C_groups, in_H)
|
|
3124
|
+
uniform sampler2D u_weights; // (in_C_groups * 4, K\\xB2 * out_C_groups)
|
|
3125
|
+
uniform sampler2D u_bias; // (out_C_groups, 1)
|
|
3126
|
+
|
|
3127
|
+
uniform int u_in_w;
|
|
3128
|
+
uniform int u_in_h;
|
|
3129
|
+
uniform int u_in_c_groups;
|
|
3130
|
+
uniform int u_out_c_groups;
|
|
3131
|
+
uniform int u_kernel_h;
|
|
3132
|
+
uniform int u_kernel_w;
|
|
3133
|
+
uniform int u_stride;
|
|
3134
|
+
uniform int u_pad_top;
|
|
3135
|
+
uniform int u_pad_left;
|
|
3136
|
+
uniform int u_activation; // 0 = none, 1 = relu6, 2 = relu, 3 = leaky(0.1)
|
|
3137
|
+
|
|
3138
|
+
out vec4 fragColor;
|
|
3139
|
+
|
|
3140
|
+
void main() {
|
|
3141
|
+
int fx = int(gl_FragCoord.x);
|
|
3142
|
+
int fy = int(gl_FragCoord.y);
|
|
3143
|
+
int x_out = fx / u_out_c_groups;
|
|
3144
|
+
int y_out = fy;
|
|
3145
|
+
int o_group = fx - x_out * u_out_c_groups;
|
|
3146
|
+
|
|
3147
|
+
vec4 result = texelFetch(u_bias, ivec2(o_group, 0), 0);
|
|
3148
|
+
|
|
3149
|
+
for (int ky = 0; ky < u_kernel_h; ky++) {
|
|
3150
|
+
for (int kx = 0; kx < u_kernel_w; kx++) {
|
|
3151
|
+
int iy_num = y_out + u_pad_top - ky;
|
|
3152
|
+
int ix_num = x_out + u_pad_left - kx;
|
|
3153
|
+
if (iy_num < 0 || ix_num < 0) continue;
|
|
3154
|
+
if ((iy_num % u_stride) != 0 || (ix_num % u_stride) != 0) continue;
|
|
3155
|
+
int in_y = iy_num / u_stride;
|
|
3156
|
+
int in_x = ix_num / u_stride;
|
|
3157
|
+
if (in_y >= u_in_h || in_x >= u_in_w) continue;
|
|
3158
|
+
|
|
3159
|
+
int z = ky * u_kernel_w + kx;
|
|
3160
|
+
int w_row = z * u_out_c_groups + o_group;
|
|
3161
|
+
|
|
3162
|
+
for (int i = 0; i < u_in_c_groups; i++) {
|
|
3163
|
+
vec4 in_val = texelFetch(u_input, ivec2(in_x * u_in_c_groups + i, in_y), 0);
|
|
3164
|
+
|
|
3165
|
+
int base = i * 4;
|
|
3166
|
+
mat4 w = mat4(
|
|
3167
|
+
texelFetch(u_weights, ivec2(base, w_row), 0),
|
|
3168
|
+
texelFetch(u_weights, ivec2(base + 1, w_row), 0),
|
|
3169
|
+
texelFetch(u_weights, ivec2(base + 2, w_row), 0),
|
|
3170
|
+
texelFetch(u_weights, ivec2(base + 3, w_row), 0)
|
|
3171
|
+
);
|
|
3172
|
+
result += w * in_val;
|
|
3173
|
+
}
|
|
3174
|
+
}
|
|
3175
|
+
}
|
|
3176
|
+
|
|
3177
|
+
if (u_activation == 1) result = clamp(result, 0.0, 6.0);
|
|
3178
|
+
else if (u_activation == 2) result = max(result, vec4(0.0));
|
|
3179
|
+
else if (u_activation == 3) result = max(result, 0.1 * result);
|
|
3180
|
+
|
|
3181
|
+
fragColor = result;
|
|
3182
|
+
}
|
|
3183
|
+
\`;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
3184
|
// Depthwise Conv2d \\u2014 groups = in_channels (each channel convolved independently).
|
|
2711
3185
|
//
|
|
2712
3186
|
// Weight layout: (C_groups, K\\xB2) RGBA32F texture \\u2014 contrast with conv2d which uses mat4.
|
|
@@ -2763,7 +3237,7 @@ void main() {
|
|
|
2763
3237
|
|
|
2764
3238
|
fragColor = result;
|
|
2765
3239
|
}
|
|
2766
|
-
\`;var
|
|
3240
|
+
\`;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
3241
|
// Element-wise add \\u2014 both inputs and output share the same texture dimensions.
|
|
2768
3242
|
// Works for any 2D layout; used here with a flat (nVec4, 1) texture.
|
|
2769
3243
|
|
|
@@ -2778,7 +3252,7 @@ void main() {
|
|
|
2778
3252
|
ivec2 fc = ivec2(gl_FragCoord.xy);
|
|
2779
3253
|
fragColor = texelFetch(u_input_a, fc, 0) + texelFetch(u_input_b, fc, 0);
|
|
2780
3254
|
}
|
|
2781
|
-
\`;var
|
|
3255
|
+
\`;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
3256
|
// Element-wise sigmoid \\u2014 works on any texture layout (flat or spatial).
|
|
2783
3257
|
|
|
2784
3258
|
precision highp float;
|
|
@@ -2787,39 +3261,130 @@ uniform sampler2D u_input;
|
|
|
2787
3261
|
|
|
2788
3262
|
out vec4 fragColor;
|
|
2789
3263
|
|
|
2790
|
-
void main() {
|
|
2791
|
-
vec4 x = texelFetch(u_input, ivec2(gl_FragCoord.xy), 0);
|
|
2792
|
-
fragColor = 1.0 / (1.0 + exp(-x));
|
|
3264
|
+
void main() {
|
|
3265
|
+
vec4 x = texelFetch(u_input, ivec2(gl_FragCoord.xy), 0);
|
|
3266
|
+
fragColor = 1.0 / (1.0 + exp(-x));
|
|
3267
|
+
}
|
|
3268
|
+
\`;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
|
|
3269
|
+
// Element-wise tanh \\u2014 used by ConvGRU candidate activation.
|
|
3270
|
+
// Layout-agnostic (flat or spatial); GLSL tanh is element-wise on vec4.
|
|
3271
|
+
|
|
3272
|
+
precision highp float;
|
|
3273
|
+
|
|
3274
|
+
uniform sampler2D u_input;
|
|
3275
|
+
|
|
3276
|
+
out vec4 fragColor;
|
|
3277
|
+
|
|
3278
|
+
void main() {
|
|
3279
|
+
fragColor = tanh(texelFetch(u_input, ivec2(gl_FragCoord.xy), 0));
|
|
3280
|
+
}
|
|
3281
|
+
\`;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
|
|
3282
|
+
// Element-wise multiply \\u2014 used in ConvGRU for r \\u2299 h_prev.
|
|
3283
|
+
// Same shape constraint as add.glsl.
|
|
3284
|
+
|
|
3285
|
+
precision highp float;
|
|
3286
|
+
|
|
3287
|
+
uniform sampler2D u_input_a;
|
|
3288
|
+
uniform sampler2D u_input_b;
|
|
3289
|
+
|
|
3290
|
+
out vec4 fragColor;
|
|
3291
|
+
|
|
3292
|
+
void main() {
|
|
3293
|
+
ivec2 fc = ivec2(gl_FragCoord.xy);
|
|
3294
|
+
fragColor = texelFetch(u_input_a, fc, 0) * texelFetch(u_input_b, fc, 0);
|
|
3295
|
+
}
|
|
3296
|
+
\`;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
|
|
3297
|
+
// Bilinear gather-warp. out[p] = sample(source, p + flow_scale\\xB7flow[p].xy),
|
|
3298
|
+
// edge-clamped. Source + flow are 4-ch (1 group), same resolution; flow in .xy.
|
|
3299
|
+
|
|
3300
|
+
precision highp float;
|
|
3301
|
+
precision highp int;
|
|
3302
|
+
|
|
3303
|
+
uniform sampler2D u_source; // (W, H)
|
|
3304
|
+
uniform sampler2D u_flow; // (W, H), flow in .xy
|
|
3305
|
+
uniform int u_w;
|
|
3306
|
+
uniform int u_h;
|
|
3307
|
+
uniform float u_flow_scale;
|
|
3308
|
+
|
|
3309
|
+
out vec4 fragColor;
|
|
3310
|
+
|
|
3311
|
+
vec4 samp(int x, int y) {
|
|
3312
|
+
int cx = clamp(x, 0, u_w - 1);
|
|
3313
|
+
int cy = clamp(y, 0, u_h - 1);
|
|
3314
|
+
return texelFetch(u_source, ivec2(cx, cy), 0);
|
|
3315
|
+
}
|
|
3316
|
+
|
|
3317
|
+
void main() {
|
|
3318
|
+
int x = int(gl_FragCoord.x);
|
|
3319
|
+
int y = int(gl_FragCoord.y);
|
|
3320
|
+
|
|
3321
|
+
vec2 f = texelFetch(u_flow, ivec2(x, y), 0).xy;
|
|
3322
|
+
float sx = clamp(float(x) + u_flow_scale * f.x, 0.0, float(u_w - 1));
|
|
3323
|
+
float sy = clamp(float(y) + u_flow_scale * f.y, 0.0, float(u_h - 1));
|
|
3324
|
+
|
|
3325
|
+
int x0 = int(floor(sx));
|
|
3326
|
+
int y0 = int(floor(sy));
|
|
3327
|
+
float tx = sx - float(x0);
|
|
3328
|
+
float ty = sy - float(y0);
|
|
3329
|
+
|
|
3330
|
+
vec4 top = mix(samp(x0, y0), samp(x0 + 1, y0), tx);
|
|
3331
|
+
vec4 bot = mix(samp(x0, y0 + 1), samp(x0 + 1, y0 + 1), tx);
|
|
3332
|
+
fragColor = mix(top, bot, ty);
|
|
2793
3333
|
}
|
|
2794
|
-
\`;var
|
|
2795
|
-
//
|
|
2796
|
-
//
|
|
3334
|
+
\`;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
|
|
3335
|
+
// Flow-gated temporal stabilizer. Per pixel:
|
|
3336
|
+
// env = max(|flow.xy|, release\\xB7envPrev.y) peak-hold
|
|
3337
|
+
// g = max(clamp((env - tLo)/(tHi - tLo), 0, 1), leak)
|
|
3338
|
+
// out = vec4((g\\xB7pred + (1-g)\\xB7ref).x, env, 0, 0)
|
|
2797
3339
|
|
|
2798
3340
|
precision highp float;
|
|
3341
|
+
precision highp int;
|
|
2799
3342
|
|
|
2800
|
-
uniform sampler2D
|
|
3343
|
+
uniform sampler2D u_flow;
|
|
3344
|
+
uniform sampler2D u_pred;
|
|
3345
|
+
uniform sampler2D u_ref;
|
|
3346
|
+
uniform sampler2D u_env_prev;
|
|
3347
|
+
uniform int u_w;
|
|
3348
|
+
uniform int u_h;
|
|
3349
|
+
uniform float u_t_lo;
|
|
3350
|
+
uniform float u_t_hi;
|
|
3351
|
+
uniform float u_leak;
|
|
3352
|
+
uniform float u_release;
|
|
3353
|
+
uniform float u_t_div;
|
|
3354
|
+
uniform float u_div_scale;
|
|
3355
|
+
uniform int u_step_x;
|
|
3356
|
+
uniform int u_step_y;
|
|
2801
3357
|
|
|
2802
3358
|
out vec4 fragColor;
|
|
2803
3359
|
|
|
2804
3360
|
void main() {
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
\`;var Ee=class extends h{constructor(r,e){super(r);i(this,"inputs");i(this,"weights",[]);i(this,"output");i(this,"dispatch");i(this,"shader",Tr);let o=e,a=this.makeTexture(null,o.texW,o.texH);this.output={h:e.h,w:e.w,c:e.c,texture:a,texW:o.texW,texH:o.texH},this.inputs=[e],this.samplers=[{name:"u_input",texture:o.texture}],this.defaultSetup(),this.dispatch=[o.texW,o.texH]}};var Cr=\`#version 300 es
|
|
2808
|
-
// Element-wise multiply \\u2014 used in ConvGRU for r \\u2299 h_prev.
|
|
2809
|
-
// Same shape constraint as add.glsl.
|
|
3361
|
+
int x = int(gl_FragCoord.x);
|
|
3362
|
+
int y = int(gl_FragCoord.y);
|
|
2810
3363
|
|
|
2811
|
-
|
|
3364
|
+
float mag = length(texelFetch(u_flow, ivec2(x, y), 0).xy);
|
|
3365
|
+
float envPrev = texelFetch(u_env_prev, ivec2(x, y), 0).y;
|
|
3366
|
+
float env = max(mag, u_release * envPrev);
|
|
2812
3367
|
|
|
2813
|
-
|
|
2814
|
-
|
|
3368
|
+
// Flow divergence over a \\xB1step finite-difference (clamped to the edges).
|
|
3369
|
+
int xr = min(x + u_step_x, u_w - 1);
|
|
3370
|
+
int xl = max(x - u_step_x, 0);
|
|
3371
|
+
int yd = min(y + u_step_y, u_h - 1);
|
|
3372
|
+
int yu = max(y - u_step_y, 0);
|
|
3373
|
+
float dfx = texelFetch(u_flow, ivec2(xr, y), 0).x - texelFetch(u_flow, ivec2(xl, y), 0).x;
|
|
3374
|
+
float dfy = texelFetch(u_flow, ivec2(x, yd), 0).y - texelFetch(u_flow, ivec2(x, yu), 0).y;
|
|
3375
|
+
float divg = abs(dfx + dfy);
|
|
2815
3376
|
|
|
2816
|
-
|
|
3377
|
+
float gMag = clamp((env - u_t_lo) / max(u_t_hi - u_t_lo, 1e-3), 0.0, 1.0);
|
|
3378
|
+
float gDiv = clamp((divg - u_t_div) / max(u_div_scale, 1e-3), 0.0, 1.0);
|
|
3379
|
+
float g = max(max(gMag, gDiv), u_leak);
|
|
2817
3380
|
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
3381
|
+
float pred = texelFetch(u_pred, ivec2(x, y), 0).x;
|
|
3382
|
+
float refv = texelFetch(u_ref, ivec2(x, y), 0).x;
|
|
3383
|
+
float stab = g * pred + (1.0 - g) * refv;
|
|
3384
|
+
|
|
3385
|
+
fragColor = vec4(stab, env, 0.0, 0.0);
|
|
2821
3386
|
}
|
|
2822
|
-
\`;var
|
|
3387
|
+
\`;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
3388
|
// Bilinear upsample (arbitrary scale) \\u2014 align_corners=False.
|
|
2824
3389
|
//
|
|
2825
3390
|
// Hardware texture filtering can't be used: adjacent texels in x belong to
|
|
@@ -2870,7 +3435,21 @@ void main() {
|
|
|
2870
3435
|
|
|
2871
3436
|
fragColor = mix(mix(v00, v10, fx), mix(v01, v11, fx), fy);
|
|
2872
3437
|
}
|
|
2873
|
-
\`;var
|
|
3438
|
+
\`;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
|
|
3439
|
+
// Top-left crop: the output viewport is smaller than the input texture, so reading
|
|
3440
|
+
// the same fragment coord yields the top-left subregion (channel groups packed in
|
|
3441
|
+
// the x axis line up because group count is unchanged).
|
|
3442
|
+
|
|
3443
|
+
precision highp float;
|
|
3444
|
+
precision highp int;
|
|
3445
|
+
|
|
3446
|
+
uniform sampler2D u_input;
|
|
3447
|
+
out vec4 fragColor;
|
|
3448
|
+
|
|
3449
|
+
void main() {
|
|
3450
|
+
fragColor = texelFetch(u_input, ivec2(int(gl_FragCoord.x), int(gl_FragCoord.y)), 0);
|
|
3451
|
+
}
|
|
3452
|
+
\`;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
3453
|
// Bicubic upsample (arbitrary scale) \\u2014 Keys cubic, a=-0.75 (PyTorch default
|
|
2875
3454
|
// for mode='bicubic', align_corners=False).
|
|
2876
3455
|
//
|
|
@@ -2930,7 +3509,7 @@ void main() {
|
|
|
2930
3509
|
}
|
|
2931
3510
|
fragColor = acc;
|
|
2932
3511
|
}
|
|
2933
|
-
\`;var
|
|
3512
|
+
\`;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
3513
|
// Channel concat \\u2014 concatenates two NHWC textures along the channel dimension.
|
|
2935
3514
|
// Both inputs must share the same spatial dimensions (W, H). Channel counts are
|
|
2936
3515
|
// multiples of 4 so each "group" is one vec4 texel.
|
|
@@ -2963,7 +3542,7 @@ void main() {
|
|
|
2963
3542
|
fragColor = texelFetch(u_input_b, ivec2(x_spatial * u_b_c_groups + c_b, y), 0);
|
|
2964
3543
|
}
|
|
2965
3544
|
}
|
|
2966
|
-
\`;var
|
|
3545
|
+
\`;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
3546
|
// Bilinear upsample + sigmoid fused \\u2014 sigmoid applied at write time, no intermediate buffer.
|
|
2968
3547
|
// See bilinear_upsample.glsl for the manual 4-tap blend rationale.
|
|
2969
3548
|
//
|
|
@@ -3013,7 +3592,7 @@ void main() {
|
|
|
3013
3592
|
vec4 result = mix(mix(v00, v10, fx), mix(v01, v11, fx), fy);
|
|
3014
3593
|
fragColor = 1.0 / (1.0 + exp(-result));
|
|
3015
3594
|
}
|
|
3016
|
-
\`;var
|
|
3595
|
+
\`;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
3596
|
// Bilinear upsample (input_a) + channel concat (with input_b) fused.
|
|
3018
3597
|
// input_a is the decoder tensor at small spatial res (in_h \\xD7 in_w), bilinearly resized to (out_h \\xD7 out_w).
|
|
3019
3598
|
// input_b is the encoder skip feature already at output resolution.
|
|
@@ -3071,7 +3650,7 @@ void main() {
|
|
|
3071
3650
|
fragColor = texelFetch(u_input_b, ivec2(x_out * u_b_c_groups + c_b, y_out), 0);
|
|
3072
3651
|
}
|
|
3073
3652
|
}
|
|
3074
|
-
\`;var
|
|
3653
|
+
\`;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
3654
|
// Bilinear upsample + 1\\xD71 pointwise conv fused.
|
|
3076
3655
|
// For each output pixel + out group, bilinearly samples each in_group from input,
|
|
3077
3656
|
// applies the 1\\xD71 conv weight, and writes the activated result.
|
|
@@ -3148,7 +3727,7 @@ void main() {
|
|
|
3148
3727
|
|
|
3149
3728
|
fragColor = result;
|
|
3150
3729
|
}
|
|
3151
|
-
\`;var
|
|
3730
|
+
\`;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
3731
|
// Conv2d + skip add fused \\u2014 identical to conv2d.glsl with a skip texture added at write time.
|
|
3153
3732
|
// See conv2d.glsl for tensor/weight layout details.
|
|
3154
3733
|
|
|
@@ -3212,7 +3791,7 @@ void main() {
|
|
|
3212
3791
|
|
|
3213
3792
|
fragColor = result + texelFetch(u_skip, ivec2(fx, fy), 0);
|
|
3214
3793
|
}
|
|
3215
|
-
\`;var
|
|
3794
|
+
\`;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
3795
|
// proj_residual: bespoke 1\\xD71 conv (no activation) + residual add, fused.
|
|
3217
3796
|
// Specializes conv2d_add to kernel=1 / stride=1 / pad=0 / no activation. Both
|
|
3218
3797
|
// inputs share the same spatial resolution. See conv2d.glsl for the weight
|
|
@@ -3254,7 +3833,7 @@ void main() {
|
|
|
3254
3833
|
|
|
3255
3834
|
fragColor = result + texelFetch(u_skip, ivec2(fx, fy), 0);
|
|
3256
3835
|
}
|
|
3257
|
-
\`;var
|
|
3836
|
+
\`;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
3837
|
// concat_conv2d: fuses [concat(a, b) \\u2192 conv 3\\xD73 (pad 1) \\u2192 relu6] into one pass.
|
|
3259
3838
|
// Both inputs already at output resolution. Weight cols [0, a_groups) read a,
|
|
3260
3839
|
// [a_groups, I) read b. Weight texture layout matches conv2d.glsl
|
|
@@ -3315,7 +3894,7 @@ void main() {
|
|
|
3315
3894
|
|
|
3316
3895
|
fragColor = clamp(result, 0.0, 6.0);
|
|
3317
3896
|
}
|
|
3318
|
-
\`;var
|
|
3897
|
+
\`;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
3898
|
// gates_fused: ConvGRU z + r gates, fused. Production config (c_up=2,
|
|
3320
3899
|
// recurrent=1). u_in (.x=a, .y=b), h_prev (.x). weights 9 vec4 =
|
|
3321
3900
|
// (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 +3937,7 @@ void main() {
|
|
|
3358
3937
|
float r = 1.0 / (1.0 + exp(-r_pre));
|
|
3359
3938
|
fragColor = vec4(z, r, 0.0, 0.0);
|
|
3360
3939
|
}
|
|
3361
|
-
\`;var
|
|
3940
|
+
\`;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
3941
|
// cand_update_fused: ConvGRU candidate + state update + output, fused.
|
|
3363
3942
|
// Production config (c_up=2, recurrent=1). u_in (.x=a, .y=b), h_prev (.x),
|
|
3364
3943
|
// gates_out (.x=z, .y=r). weights 9 vec4 (.xy = b_w, rh_w) in a (9,1) texture.
|
|
@@ -3406,7 +3985,7 @@ void main() {
|
|
|
3406
3985
|
float b_out = u_cur.y + gamma * h_new;
|
|
3407
3986
|
fragColor = vec4(u_cur.x, b_out, h_new, 0.0);
|
|
3408
3987
|
}
|
|
3409
|
-
\`;var
|
|
3988
|
+
\`;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
3989
|
// conv_expand: bespoke N\\u21922 conv 3\\xD73 (pad 1) + relu (wrapper expand_feat).
|
|
3411
3990
|
// Input N ch (in_groups vec4); output 2ch in .xy (.zw = 0). Weights: 9 *
|
|
3412
3991
|
// in_groups mat4x2 (8 floats each, col-major c0r0,c0r1,...,c3r0,c3r1) in a
|
|
@@ -3449,7 +4028,7 @@ void main() {
|
|
|
3449
4028
|
|
|
3450
4029
|
fragColor = vec4(max(result, vec2(0.0)), 0.0, 0.0); // expand_feat is F.relu
|
|
3451
4030
|
}
|
|
3452
|
-
\`;var
|
|
4031
|
+
\`;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
4032
|
// cat_conv_6to2: fused concat(u[2], d[4]) \\u2192 6\\u21922 conv 3\\xD73 (pad 1) + relu
|
|
3454
4033
|
// (E up1_combine). Channel order v3a=(u.x,u.y,d.x), v3b=d.yzw. weights = 9*2
|
|
3455
4034
|
// mat3x2 (6 floats each, col-major) in a 1-row (27-texel) texture.
|
|
@@ -3496,7 +4075,7 @@ void main() {
|
|
|
3496
4075
|
|
|
3497
4076
|
fragColor = vec4(max(result, vec2(0.0)), 0.0, 0.0); // up1_combine is F.relu
|
|
3498
4077
|
}
|
|
3499
|
-
\`;var
|
|
4078
|
+
\`;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
4079
|
// down_adapter: stride-N 3\\xD73 conv (mat4x4, 4\\u21924) + relu, then 1\\xD71 adapter
|
|
3501
4080
|
// (4\\u21923, last row 0). down_w = 9 mat4x4 (1-row, 36 texels); adapt_w = 1 mat4x4
|
|
3502
4081
|
// (4 texels). Output 3ch in .xyz (.w=0). Symmetric pad. Weight packing matches
|
|
@@ -3548,7 +4127,7 @@ void main() {
|
|
|
3548
4127
|
a.z = awf(2) * d.x + awf(6) * d.y + awf(10) * d.z + awf(14) * d.w + ab.z;
|
|
3549
4128
|
fragColor = vec4(a.xyz, 0.0);
|
|
3550
4129
|
}
|
|
3551
|
-
\`;var
|
|
4130
|
+
\`;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
4131
|
// up_final: cat(u[2], rgb[3]) \\u2192 conv 3\\xD73 5\\u21921 \\u2192 sigmoid (A/B alpha head).
|
|
3553
4132
|
// weights 18 vec4 (1-row): [kpos]=(w0,w1,0,0) for u, [9+kpos]=(w2,w3,w4,0) rgb.
|
|
3554
4133
|
|
|
@@ -3586,7 +4165,7 @@ void main() {
|
|
|
3586
4165
|
|
|
3587
4166
|
fragColor = vec4(1.0 / (1.0 + exp(-acc)), 0.0, 0.0, 0.0);
|
|
3588
4167
|
}
|
|
3589
|
-
\`;var
|
|
4168
|
+
\`;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
4169
|
// up_final_skip (C/D alpha head): cat(u[2], d_full[4], rgb[3]) \\u2192 conv 9\\u21921 \\u2192
|
|
3591
4170
|
// sigmoid. Weights = 27 vec4 (3 per kpos): [kpos*3+0]=(w0,w1,0,0) u;
|
|
3592
4171
|
// [kpos*3+1]=(w2..w5) d_full; [kpos*3+2]=(w6,w7,w8,0) rgb.
|
|
@@ -3629,7 +4208,7 @@ void main() {
|
|
|
3629
4208
|
|
|
3630
4209
|
fragColor = vec4(1.0 / (1.0 + exp(-acc)), 0.0, 0.0, 0.0);
|
|
3631
4210
|
}
|
|
3632
|
-
\`;var
|
|
4211
|
+
\`;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
4212
|
// Composite an RGBA image over a solid background color, gated by a
|
|
3634
4213
|
// 1-channel alpha mask. Output: premultiplied RGBA.
|
|
3635
4214
|
//
|
|
@@ -3660,12 +4239,12 @@ void main() {
|
|
|
3660
4239
|
vec3 rgb = fg * a + u_bgColor * (1.0 - a);
|
|
3661
4240
|
fragColor = vec4(rgb, 1.0);
|
|
3662
4241
|
}
|
|
3663
|
-
\`;var
|
|
4242
|
+
\`;var Da=\`#version 300 es
|
|
3664
4243
|
const vec2 VERTS[6] = vec2[6](
|
|
3665
4244
|
vec2(-1.0,-1.0), vec2(1.0,-1.0), vec2(-1.0,1.0),
|
|
3666
4245
|
vec2(-1.0,1.0), vec2(1.0,-1.0), vec2(1.0,1.0)
|
|
3667
4246
|
);
|
|
3668
|
-
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); }\`,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
4248
|
// Same as composite_solid but bg is a texture (NHWC vec4 tensor) instead of
|
|
3670
4249
|
// a uniform color. Caller invariants: image, alpha, bg all share h \\xD7 w, and
|
|
3671
4250
|
// canvas dimensions match.
|
|
@@ -3691,12 +4270,12 @@ void main() {
|
|
|
3691
4270
|
vec3 rgb = fg * a + bg * (1.0 - a);
|
|
3692
4271
|
fragColor = vec4(rgb, 1.0);
|
|
3693
4272
|
}
|
|
3694
|
-
\`;var
|
|
4273
|
+
\`;var Ia=\`#version 300 es
|
|
3695
4274
|
const vec2 VERTS[6] = vec2[6](
|
|
3696
4275
|
vec2(-1.0,-1.0), vec2(1.0,-1.0), vec2(-1.0,1.0),
|
|
3697
4276
|
vec2(-1.0,1.0), vec2(1.0,-1.0), vec2(1.0,1.0)
|
|
3698
4277
|
);
|
|
3699
|
-
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }\`,
|
|
4278
|
+
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
4279
|
// Like composite_image but bg is bilinearly sampled \\u2014 bg is at a smaller
|
|
3701
4280
|
// resolution than (image, alpha) at canvas h \\xD7 w. Used by CompositorBlur to
|
|
3702
4281
|
// skip the final full-res upsample in the blur pyramid.
|
|
@@ -3745,12 +4324,12 @@ void main() {
|
|
|
3745
4324
|
vec3 rgb = fg * a + bg * (1.0 - a);
|
|
3746
4325
|
fragColor = vec4(rgb, 1.0);
|
|
3747
4326
|
}
|
|
3748
|
-
\`;var
|
|
4327
|
+
\`;var Ma=\`#version 300 es
|
|
3749
4328
|
const vec2 VERTS[6] = vec2[6](
|
|
3750
4329
|
vec2(-1.0,-1.0), vec2(1.0,-1.0), vec2(-1.0,1.0),
|
|
3751
4330
|
vec2(-1.0,1.0), vec2(1.0,-1.0), vec2(1.0,1.0)
|
|
3752
4331
|
);
|
|
3753
|
-
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }\`,
|
|
4332
|
+
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
4333
|
// Passthrough "compositor": writes the image directly to the canvas
|
|
3755
4334
|
// (default framebuffer). No alpha math, no background. Used by RenderOp
|
|
3756
4335
|
// when the renderer is in disabled state.
|
|
@@ -3773,12 +4352,12 @@ void main() {
|
|
|
3773
4352
|
vec3 rgb = texelFetch(u_image, px, 0).rgb;
|
|
3774
4353
|
fragColor = vec4(rgb, 1.0);
|
|
3775
4354
|
}
|
|
3776
|
-
\`;var
|
|
4355
|
+
\`;var Ha=\`#version 300 es
|
|
3777
4356
|
const vec2 VERTS[6] = vec2[6](
|
|
3778
4357
|
vec2(-1.0,-1.0), vec2(1.0,-1.0), vec2(-1.0,1.0),
|
|
3779
4358
|
vec2(-1.0,1.0), vec2(1.0,-1.0), vec2(1.0,1.0)
|
|
3780
4359
|
);
|
|
3781
|
-
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }\`,
|
|
4360
|
+
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
4361
|
precision highp float;
|
|
3783
4362
|
|
|
3784
4363
|
// Input op \\u2014 bilinear-sample a source texture (RGBA8 unorm uploaded from an
|
|
@@ -3796,21 +4375,20 @@ void main() {
|
|
|
3796
4375
|
vec2 uv = (gl_FragCoord.xy + vec2(0.5)) / vec2(float(u_out_w), float(u_out_h));
|
|
3797
4376
|
fragColor = texture(u_src, uv);
|
|
3798
4377
|
}
|
|
3799
|
-
\`;var
|
|
4378
|
+
\`;var Va=\`#version 300 es
|
|
3800
4379
|
const vec2 VERTS[6] = vec2[6](
|
|
3801
4380
|
vec2(-1.0,-1.0), vec2(1.0,-1.0), vec2(-1.0,1.0),
|
|
3802
4381
|
vec2(-1.0,1.0), vec2(1.0,-1.0), vec2(1.0,1.0)
|
|
3803
4382
|
);
|
|
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
|
|
4383
|
+
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};
|
|
4384
|
+
`;var k=x("pipeline");function Er(){{let a=new Blob([xe],{type:"application/javascript"}),t=URL.createObjectURL(a),e=new Worker(t,{type:"module"});return URL.revokeObjectURL(t),e}}var Gr="https://cdn.longpipe.dev/models/v/0.0.4/",Fr={background:"blur",preset:"auto",weightsBaseUrl:Gr,audio:"passthrough",enabled:true,adaptive:true,debug:false},qe={w:1280,h:720};function Ar(a,t){if(t)return t;let r=a.getVideoTracks()[0]?.getSettings()??{};return {w:r.width||qe.w,h:r.height||qe.h}}function Xe(a,t,e){let r=e==="f16"?".f16.bin":".bin";return `${a.replace(/\/$/,"")}/model_${t}${r}`}async function Ke(a,t,e){if(e==="f16"){let i=await fetch(Xe(a,t,"f16"));if(i.ok)return i.arrayBuffer()}let r=Xe(a,t,"f32"),n=await fetch(r);if(!n.ok)throw new Error(`weights fetch failed: ${n.status} ${r}`);return n.arrayBuffer()}var we=class{stream;ready;controller;worker;inputCleanup;outputCleanup;adaptive=null;denoiser=null;bgCleanup=null;previewBgCleanup=null;constructor(t,e){let r={...Fr,...e};Te(r.debug);let n=Se(),i=Le(n.input,t),o=Ar(t,r.outputResolution),s=je(n.output,o);this.inputCleanup=i.cleanup,this.outputCleanup=s.cleanup;let u=Ee(r.audio),l;if(u.mode==="denoise"){let h=t.getAudioTracks()[0];h?(this.denoiser=new O(h,{model:u.denoise?.model??"auto",weightsBaseUrl:r.weightsBaseUrl,postFilterBeta:u.denoise?.postFilterBeta,gruLeak:u.denoise?.gruLeak,enabled:u.denoise?.enabled,onError:m=>r.onError?.({message:m,source:"audio",recoverable:true})}),l=this.denoiser.outputTrack):r.onError?.({message:'audio: "denoise" requested but the input stream has no audio track',source:"audio",recoverable:true});}this.stream=Ge(s.videoTrack,t,u,l),s.startPassthrough?.(t),this.worker=Er(),this.controller=new z(this.worker),this.ready=new Promise((h,m)=>{this.controller.addPersistentListener("ready",()=>{k("ready handler invoked; resolving .ready"),r.onReady?.(),h();}),this.controller.addPersistentListener("error",w=>{console.error(`[longpipe/pipeline] error (${w.source}):`,w.message),w.recoverable||m(new Error(w.message)),r.onError?.(w);});});let c={topology:n,preset:r.preset,enabled:r.enabled,backend:"auto",dtype:"f16",canvasSize:o,debug:r.debug,...i.initFields,...s.initFields},f=[...i.transferList,...s.transferList];this.bootstrap(c,r.background,f,r.weightsBaseUrl,r.adaptive,r.onError);}async bootstrap(t,e,r,n,i,o){try{k("normalizing background\u2026");let s=await F(e);this.bgCleanup=s.cleanup??null;let u={...t,background:s.background},l=[...r,...s.transferList??[]];k("sending init\u2026");let c=await this.controller.sendMessage("init",u,l);k("init resolved:",c),k("fetching weights:",c.resolvedPreset.model,c.resolvedDtype);let f=await Ke(n,c.resolvedPreset.model,c.resolvedDtype);k("weights bytes:",f.byteLength),k("sending startRender\u2026"),await this.controller.sendMessage("startRender",{weights:f},[f]),k("startRender resolved; awaiting first frame"),u.preset==="auto"&&i&&(this.adaptive=new G({backendKind:c.resolvedBackend,initialModel:c.resolvedPreset.model,fetchWeights:h=>Ke(n,h,c.resolvedDtype),getStats:()=>this.getStats(),swapPreset:async(h,m)=>{await this.controller.sendMessage("setPreset",{preset:h,weights:m},[m]);},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 F(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 F(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",{})}setDenoise(t){if(this.denoiser){if(typeof t=="boolean"){this.denoiser.setEnabled(t);return}(t.postFilterBeta!=null||t.gruLeak!=null)&&this.denoiser.setConfig({postFilterBeta:t.postFilterBeta,gruLeak:t.gruLeak}),t.enabled!=null&&this.denoiser.setEnabled(t.enabled);}}getAudioStats(){return this.denoiser?.getStats()??null}destroy(){this.adaptive?.stop(),this.adaptive=null,this.denoiser?.destroy(),this.denoiser=null,this.bgCleanup?.(),this.bgCleanup=null,this.previewBgCleanup?.(),this.previewBgCleanup=null,this.controller.sendMessage("destroy",{}),this.controller.terminate(),this.inputCleanup(),this.outputCleanup();}};var W=new Float32Array(1),I=new Uint32Array(W.buffer);function Mr(a){W[0]=a;let t=I[0],e=t>>>16&32768,r=t&2147483647,n=(r>>>23)-127+15;if((t&2139095040)===2139095040)return (t&8388607)!==0?e|32256:e|31744;if(n>=31)return e|31744;if(n<=0){if(n<-10)return e;let l=r&8388607|8388608,c=14-n,f=l>>>c,h=l>>>c-1&1,m=(l&(1<<c-1)-1)!==0?1:0;return h&&(m||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 ye(a){let t=(a&32768)<<16,e=(a&31744)>>>10,r=a&1023;if(e===0){if(r===0)return I[0]=t,W[0];let n=r,i=1;for(;(n&1024)===0;)n<<=1,i-=1;return n&=1023,I[0]=t|i+127-15<<23|n<<13,W[0]}return e===31?(I[0]=t|2139095040|r<<13,W[0]):(I[0]=t|e+127-15<<23|r<<13,W[0])}function Ye(a){let t=new Uint16Array(a.length);for(let e=0;e<a.length;e++)t[e]=Mr(a[e]);return t}function ke(a){let t=new Float32Array(a.length);for(let e=0;e<a.length;e++)t[e]=ye(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 Je=`// Conv2d, output-channel-blocked (K=2) \u2014 drop-in replacement for conv2d.wgsl.
|
|
3806
4385
|
//
|
|
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).
|
|
4386
|
+
// Identical math, layout, and output to conv2d.wgsl, but each thread computes 2
|
|
4387
|
+
// output channel-groups (8 channels) for one pixel, loading each input vec4 ONCE
|
|
4388
|
+
// and reusing it across both groups' mat4x4 weight blocks in registers. Half the
|
|
4389
|
+
// register pressure of the K=4 variant (2 accumulators vs 4). Output is bit-
|
|
4390
|
+
// identical to conv2d.wgsl (\u22641 ULP from FMA contraction). Dispatch
|
|
4391
|
+
// ceil(out_groups / 2) in z (see conv2d.ts).
|
|
3814
4392
|
//
|
|
3815
4393
|
// Tensor layout: NHWC, channels in vec4 groups (same as conv2d.wgsl).
|
|
3816
4394
|
// Weight layout: [K*K][out_groups][in_groups] array of mat4x4 (same as conv2d.wgsl).
|
|
@@ -3827,7 +4405,7 @@ struct Params {
|
|
|
3827
4405
|
stride : u32,
|
|
3828
4406
|
pad_top : u32,
|
|
3829
4407
|
pad_left : u32,
|
|
3830
|
-
activation : u32, // 0 = none, 1 = relu6, 2 = relu
|
|
4408
|
+
activation : u32, // 0 = none, 1 = relu6, 2 = relu, 3 = leaky
|
|
3831
4409
|
}
|
|
3832
4410
|
|
|
3833
4411
|
@group(0) @binding(0) var<storage, read> input_buf : array<vec4<f32>>;
|
|
@@ -3836,18 +4414,19 @@ struct Params {
|
|
|
3836
4414
|
@group(0) @binding(3) var<uniform> params : Params;
|
|
3837
4415
|
@group(0) @binding(4) var<storage, read_write> output_buf : array<vec4<f32>>;
|
|
3838
4416
|
|
|
3839
|
-
const KB =
|
|
4417
|
+
const KB = 2u;
|
|
3840
4418
|
|
|
3841
4419
|
fn act(v: vec4<f32>, a: u32) -> vec4<f32> {
|
|
3842
4420
|
if (a == 1u) { return clamp(v, vec4<f32>(0.0), vec4<f32>(6.0)); }
|
|
3843
4421
|
if (a == 2u) { return max(v, vec4<f32>(0.0)); }
|
|
4422
|
+
if (a == 3u) { return max(v, 0.1 * v); } // leaky relu (slope 0.1)
|
|
3844
4423
|
return v;
|
|
3845
4424
|
}
|
|
3846
4425
|
|
|
3847
4426
|
@compute @workgroup_size(8, 8, 1)
|
|
3848
4427
|
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
3849
|
-
let x = gid.x;
|
|
3850
|
-
let y = gid.y;
|
|
4428
|
+
let x = gid.x; // output column
|
|
4429
|
+
let y = gid.y; // output row
|
|
3851
4430
|
let o0 = gid.z * KB; // first output channel group
|
|
3852
4431
|
|
|
3853
4432
|
if (x >= params.out_w || y >= params.out_h || o0 >= params.out_groups) {
|
|
@@ -3856,19 +4435,13 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
3856
4435
|
|
|
3857
4436
|
let I = params.in_groups;
|
|
3858
4437
|
let O = params.out_groups;
|
|
3859
|
-
// Tail handling when out_groups is
|
|
3860
|
-
//
|
|
4438
|
+
// Tail handling when out_groups is odd: clamp the spare lane to o0 (valid
|
|
4439
|
+
// index, no OOB) and just don't write it.
|
|
3861
4440
|
let has1 = (o0 + 1u) < O;
|
|
3862
|
-
let has2 = (o0 + 2u) < O;
|
|
3863
|
-
let has3 = (o0 + 3u) < O;
|
|
3864
4441
|
let o1 = select(o0, o0 + 1u, has1);
|
|
3865
|
-
let o2 = select(o0, o0 + 2u, has2);
|
|
3866
|
-
let o3 = select(o0, o0 + 3u, has3);
|
|
3867
4442
|
|
|
3868
4443
|
var acc0 = bias_buf[o0];
|
|
3869
4444
|
var acc1 = bias_buf[o1];
|
|
3870
|
-
var acc2 = bias_buf[o2];
|
|
3871
|
-
var acc3 = bias_buf[o3];
|
|
3872
4445
|
|
|
3873
4446
|
for (var ky = 0u; ky < params.kernel_h; ky++) {
|
|
3874
4447
|
for (var kx = 0u; kx < params.kernel_w; kx++) {
|
|
@@ -3884,14 +4457,10 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
3884
4457
|
let inB = u32(in_y_s) * params.in_w * I + u32(in_x_s) * I;
|
|
3885
4458
|
let wb0 = z * O * I + o0 * I;
|
|
3886
4459
|
let wb1 = z * O * I + o1 * I;
|
|
3887
|
-
let wb2 = z * O * I + o2 * I;
|
|
3888
|
-
let wb3 = z * O * I + o3 * I;
|
|
3889
4460
|
for (var i = 0u; i < I; i++) {
|
|
3890
|
-
let iv = input_buf[inB + i]; // loaded ONCE, reused across
|
|
4461
|
+
let iv = input_buf[inB + i]; // loaded ONCE, reused across 2 groups
|
|
3891
4462
|
acc0 += weight_buf[wb0 + i] * iv;
|
|
3892
4463
|
acc1 += weight_buf[wb1 + i] * iv;
|
|
3893
|
-
acc2 += weight_buf[wb2 + i] * iv;
|
|
3894
|
-
acc3 += weight_buf[wb3 + i] * iv;
|
|
3895
4464
|
}
|
|
3896
4465
|
}
|
|
3897
4466
|
}
|
|
@@ -3899,15 +4468,14 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
3899
4468
|
let baseO = y * params.out_w * O + x * O;
|
|
3900
4469
|
output_buf[baseO + o0] = act(acc0, params.activation);
|
|
3901
4470
|
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
4471
|
}
|
|
3905
|
-
`;var
|
|
4472
|
+
`;var Qe=`enable f16;
|
|
3906
4473
|
|
|
3907
|
-
// Conv2d, output-channel-blocked (K=
|
|
3908
|
-
// conv2d_f16.wgsl. Each thread computes
|
|
3909
|
-
// loading each input vec4
|
|
3910
|
-
//
|
|
4474
|
+
// Conv2d, output-channel-blocked (K=2) \u2014 full f16. Drop-in replacement for
|
|
4475
|
+
// conv2d_f16.wgsl. Each thread computes 2 output channel-groups for one pixel,
|
|
4476
|
+
// loading each input vec4 ONCE and reusing it across both weight blocks. Half the
|
|
4477
|
+
// register pressure of the K=4 variant (2 accumulators vs 4). Output is bit-
|
|
4478
|
+
// identical to conv2d_f16.wgsl. Dispatch ceil(out_groups / 2) in z.
|
|
3911
4479
|
|
|
3912
4480
|
struct Params {
|
|
3913
4481
|
in_h : u32,
|
|
@@ -3930,11 +4498,12 @@ struct Params {
|
|
|
3930
4498
|
@group(0) @binding(3) var<uniform> params : Params;
|
|
3931
4499
|
@group(0) @binding(4) var<storage, read_write> output_buf : array<vec4<f16>>;
|
|
3932
4500
|
|
|
3933
|
-
const KB =
|
|
4501
|
+
const KB = 2u;
|
|
3934
4502
|
|
|
3935
4503
|
fn act(v: vec4<f16>, a: u32) -> vec4<f16> {
|
|
3936
4504
|
if (a == 1u) { return clamp(v, vec4<f16>(0.0h), vec4<f16>(6.0h)); }
|
|
3937
4505
|
if (a == 2u) { return max(v, vec4<f16>(0.0h)); }
|
|
4506
|
+
if (a == 3u) { return max(v, 0.1h * v); } // leaky relu (slope 0.1)
|
|
3938
4507
|
return v;
|
|
3939
4508
|
}
|
|
3940
4509
|
|
|
@@ -3951,16 +4520,10 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
3951
4520
|
let I = params.in_groups;
|
|
3952
4521
|
let O = params.out_groups;
|
|
3953
4522
|
let has1 = (o0 + 1u) < O;
|
|
3954
|
-
let has2 = (o0 + 2u) < O;
|
|
3955
|
-
let has3 = (o0 + 3u) < O;
|
|
3956
4523
|
let o1 = select(o0, o0 + 1u, has1);
|
|
3957
|
-
let o2 = select(o0, o0 + 2u, has2);
|
|
3958
|
-
let o3 = select(o0, o0 + 3u, has3);
|
|
3959
4524
|
|
|
3960
4525
|
var acc0 = bias_buf[o0];
|
|
3961
4526
|
var acc1 = bias_buf[o1];
|
|
3962
|
-
var acc2 = bias_buf[o2];
|
|
3963
|
-
var acc3 = bias_buf[o3];
|
|
3964
4527
|
|
|
3965
4528
|
for (var ky = 0u; ky < params.kernel_h; ky++) {
|
|
3966
4529
|
for (var kx = 0u; kx < params.kernel_w; kx++) {
|
|
@@ -3976,14 +4539,10 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
3976
4539
|
let inB = u32(in_y_s) * params.in_w * I + u32(in_x_s) * I;
|
|
3977
4540
|
let wb0 = z * O * I + o0 * I;
|
|
3978
4541
|
let wb1 = z * O * I + o1 * I;
|
|
3979
|
-
let wb2 = z * O * I + o2 * I;
|
|
3980
|
-
let wb3 = z * O * I + o3 * I;
|
|
3981
4542
|
for (var i = 0u; i < I; i++) {
|
|
3982
|
-
let iv = input_buf[inB + i];
|
|
4543
|
+
let iv = input_buf[inB + i]; // loaded ONCE, reused across 2 groups
|
|
3983
4544
|
acc0 += weight_buf[wb0 + i] * iv;
|
|
3984
4545
|
acc1 += weight_buf[wb1 + i] * iv;
|
|
3985
|
-
acc2 += weight_buf[wb2 + i] * iv;
|
|
3986
|
-
acc3 += weight_buf[wb3 + i] * iv;
|
|
3987
4546
|
}
|
|
3988
4547
|
}
|
|
3989
4548
|
}
|
|
@@ -3991,10 +4550,156 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
3991
4550
|
let baseO = y * params.out_w * O + x * O;
|
|
3992
4551
|
output_buf[baseO + o0] = act(acc0, params.activation);
|
|
3993
4552
|
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
4553
|
}
|
|
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
|
|
4554
|
+
`;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 Pe(a,t,e,r){return (a-1)*e-2*r+t}function zr(a,t,e,r){return Math.floor(Math.max((t-1)*r+e-a,0)/2)}function b(a,t,e,r,n){return typeof a=="number"?a:a==="same"?zr(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?ye(a[n]):a[n];return e}var R=class extends p{inputs;weights;output;dispatch;shader;constructor(t,e,r,n){super(t),this.shader=t.dtype==="f16"?Qe:Je;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=b(n.padding,e.h,i,n.kernel,n.stride),c=b(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 Ze=`// ConvTranspose2d \u2014 gather form, f32 variant. See conv_transpose2d_f16.wgsl for
|
|
4555
|
+
// the math; this is the f32 storage build (mat4x4<f32>).
|
|
4556
|
+
|
|
4557
|
+
struct Params {
|
|
4558
|
+
in_h : u32,
|
|
4559
|
+
in_w : u32,
|
|
4560
|
+
out_h : u32,
|
|
4561
|
+
out_w : u32,
|
|
4562
|
+
in_groups : u32,
|
|
4563
|
+
out_groups : u32,
|
|
4564
|
+
kernel_h : u32,
|
|
4565
|
+
kernel_w : u32,
|
|
4566
|
+
stride : u32,
|
|
4567
|
+
pad_top : u32,
|
|
4568
|
+
pad_left : u32,
|
|
4569
|
+
activation : u32,
|
|
4570
|
+
}
|
|
4571
|
+
|
|
4572
|
+
@group(0) @binding(0) var<storage, read> input_buf : array<vec4<f32>>;
|
|
4573
|
+
@group(0) @binding(1) var<storage, read> weight_buf : array<mat4x4<f32>>;
|
|
4574
|
+
@group(0) @binding(2) var<storage, read> bias_buf : array<vec4<f32>>;
|
|
4575
|
+
@group(0) @binding(3) var<uniform> params : Params;
|
|
4576
|
+
@group(0) @binding(4) var<storage, read_write> output_buf : array<vec4<f32>>;
|
|
4577
|
+
|
|
4578
|
+
fn act(v: vec4<f32>, a: u32) -> vec4<f32> {
|
|
4579
|
+
if (a == 1u) { return clamp(v, vec4<f32>(0.0), vec4<f32>(6.0)); }
|
|
4580
|
+
if (a == 2u) { return max(v, vec4<f32>(0.0)); }
|
|
4581
|
+
if (a == 3u) { return max(v, 0.1 * v); }
|
|
4582
|
+
return v;
|
|
4583
|
+
}
|
|
4584
|
+
|
|
4585
|
+
@compute @workgroup_size(8, 8, 1)
|
|
4586
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
4587
|
+
let ox = gid.x;
|
|
4588
|
+
let oy = gid.y;
|
|
4589
|
+
let o = gid.z;
|
|
4590
|
+
|
|
4591
|
+
if (ox >= params.out_w || oy >= params.out_h || o >= params.out_groups) {
|
|
4592
|
+
return;
|
|
4593
|
+
}
|
|
4594
|
+
|
|
4595
|
+
let I = params.in_groups;
|
|
4596
|
+
let O = params.out_groups;
|
|
4597
|
+
let s = i32(params.stride);
|
|
4598
|
+
|
|
4599
|
+
var result = bias_buf[o];
|
|
4600
|
+
|
|
4601
|
+
for (var ky = 0u; ky < params.kernel_h; ky++) {
|
|
4602
|
+
for (var kx = 0u; kx < params.kernel_w; kx++) {
|
|
4603
|
+
let iy_num = i32(oy) + i32(params.pad_top) - i32(ky);
|
|
4604
|
+
let ix_num = i32(ox) + i32(params.pad_left) - i32(kx);
|
|
4605
|
+
if (iy_num < 0 || ix_num < 0 || (iy_num % s) != 0 || (ix_num % s) != 0) {
|
|
4606
|
+
continue;
|
|
4607
|
+
}
|
|
4608
|
+
let iy = iy_num / s;
|
|
4609
|
+
let ix = ix_num / s;
|
|
4610
|
+
if (iy >= i32(params.in_h) || ix >= i32(params.in_w)) {
|
|
4611
|
+
continue;
|
|
4612
|
+
}
|
|
4613
|
+
|
|
4614
|
+
let z = ky * params.kernel_w + kx;
|
|
4615
|
+
for (var i = 0u; i < I; i++) {
|
|
4616
|
+
let in_idx = u32(iy) * params.in_w * I + u32(ix) * I + i;
|
|
4617
|
+
let w_idx = z * O * I + o * I + i;
|
|
4618
|
+
result += weight_buf[w_idx] * input_buf[in_idx];
|
|
4619
|
+
}
|
|
4620
|
+
}
|
|
4621
|
+
}
|
|
4622
|
+
|
|
4623
|
+
output_buf[oy * params.out_w * O + ox * O + o] = act(result, params.activation);
|
|
4624
|
+
}
|
|
4625
|
+
`;var et=`enable f16;
|
|
4626
|
+
|
|
4627
|
+
// ConvTranspose2d \u2014 gather form, full f16 variant.
|
|
4628
|
+
// Each output (oy,ox) sums every input pixel + kernel tap that maps onto it:
|
|
4629
|
+
// iy = (oy + pad - ky) / stride (must divide evenly and be in bounds)
|
|
4630
|
+
// No explicit kernel flip \u2014 the (oy + pad - ky) indexing carries it.
|
|
4631
|
+
// Weight layout is IDENTICAL to conv2d (mat4x4[z][o][i], M[in_sub][out_sub] =
|
|
4632
|
+
// W(in, out, ky, kx)), so the op uploads the flat buffer unchanged.
|
|
4633
|
+
|
|
4634
|
+
struct Params {
|
|
4635
|
+
in_h : u32,
|
|
4636
|
+
in_w : u32,
|
|
4637
|
+
out_h : u32,
|
|
4638
|
+
out_w : u32,
|
|
4639
|
+
in_groups : u32,
|
|
4640
|
+
out_groups : u32,
|
|
4641
|
+
kernel_h : u32,
|
|
4642
|
+
kernel_w : u32,
|
|
4643
|
+
stride : u32,
|
|
4644
|
+
pad_top : u32,
|
|
4645
|
+
pad_left : u32,
|
|
4646
|
+
activation : u32,
|
|
4647
|
+
}
|
|
4648
|
+
|
|
4649
|
+
@group(0) @binding(0) var<storage, read> input_buf : array<vec4<f16>>;
|
|
4650
|
+
@group(0) @binding(1) var<storage, read> weight_buf : array<mat4x4<f16>>;
|
|
4651
|
+
@group(0) @binding(2) var<storage, read> bias_buf : array<vec4<f16>>;
|
|
4652
|
+
@group(0) @binding(3) var<uniform> params : Params;
|
|
4653
|
+
@group(0) @binding(4) var<storage, read_write> output_buf : array<vec4<f16>>;
|
|
4654
|
+
|
|
4655
|
+
fn act(v: vec4<f16>, a: u32) -> vec4<f16> {
|
|
4656
|
+
if (a == 1u) { return clamp(v, vec4<f16>(0.0h), vec4<f16>(6.0h)); }
|
|
4657
|
+
if (a == 2u) { return max(v, vec4<f16>(0.0h)); }
|
|
4658
|
+
if (a == 3u) { return max(v, 0.1h * v); }
|
|
4659
|
+
return v;
|
|
4660
|
+
}
|
|
4661
|
+
|
|
4662
|
+
@compute @workgroup_size(8, 8, 1)
|
|
4663
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
4664
|
+
let ox = gid.x;
|
|
4665
|
+
let oy = gid.y;
|
|
4666
|
+
let o = gid.z;
|
|
4667
|
+
|
|
4668
|
+
if (ox >= params.out_w || oy >= params.out_h || o >= params.out_groups) {
|
|
4669
|
+
return;
|
|
4670
|
+
}
|
|
4671
|
+
|
|
4672
|
+
let I = params.in_groups;
|
|
4673
|
+
let O = params.out_groups;
|
|
4674
|
+
let s = i32(params.stride);
|
|
4675
|
+
|
|
4676
|
+
var result = bias_buf[o];
|
|
4677
|
+
|
|
4678
|
+
for (var ky = 0u; ky < params.kernel_h; ky++) {
|
|
4679
|
+
for (var kx = 0u; kx < params.kernel_w; kx++) {
|
|
4680
|
+
let iy_num = i32(oy) + i32(params.pad_top) - i32(ky);
|
|
4681
|
+
let ix_num = i32(ox) + i32(params.pad_left) - i32(kx);
|
|
4682
|
+
if (iy_num < 0 || ix_num < 0 || (iy_num % s) != 0 || (ix_num % s) != 0) {
|
|
4683
|
+
continue;
|
|
4684
|
+
}
|
|
4685
|
+
let iy = iy_num / s;
|
|
4686
|
+
let ix = ix_num / s;
|
|
4687
|
+
if (iy >= i32(params.in_h) || ix >= i32(params.in_w)) {
|
|
4688
|
+
continue;
|
|
4689
|
+
}
|
|
4690
|
+
|
|
4691
|
+
let z = ky * params.kernel_w + kx;
|
|
4692
|
+
for (var i = 0u; i < I; i++) {
|
|
4693
|
+
let in_idx = u32(iy) * params.in_w * I + u32(ix) * I + i;
|
|
4694
|
+
let w_idx = z * O * I + o * I + i;
|
|
4695
|
+
result += weight_buf[w_idx] * input_buf[in_idx];
|
|
4696
|
+
}
|
|
4697
|
+
}
|
|
4698
|
+
}
|
|
4699
|
+
|
|
4700
|
+
output_buf[oy * params.out_w * O + ox * O + o] = act(result, params.activation);
|
|
4701
|
+
}
|
|
4702
|
+
`;var H=class extends p{inputs;weights;output;dispatch;shader;constructor(t,e,r,n){super(t),this.shader=t.dtype==="f16"?et:Ze;let i=Pe(e.h,n.kernel,n.stride,n.padding),o=Pe(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 tt=`// Depthwise Conv2d \u2014 groups = in_channels (each channel convolved independently).
|
|
3998
4703
|
//
|
|
3999
4704
|
// Weight layout: [K*K][channel_groups] array of vec4
|
|
4000
4705
|
// weight index = (ky*kernel_w + kx) * channel_groups + c
|
|
@@ -4069,7 +4774,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4069
4774
|
let out_idx = y * params.out_w * C + x * C + c;
|
|
4070
4775
|
output_buf[out_idx] = result;
|
|
4071
4776
|
}
|
|
4072
|
-
`;var
|
|
4777
|
+
`;var rt=`enable f16;
|
|
4073
4778
|
|
|
4074
4779
|
// Depthwise conv2d \u2014 full f16 variant. All buffers f16.
|
|
4075
4780
|
|
|
@@ -4134,7 +4839,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4134
4839
|
|
|
4135
4840
|
output_buf[y * params.out_w * C + x * C + c] = result;
|
|
4136
4841
|
}
|
|
4137
|
-
`;var
|
|
4842
|
+
`;var L=class extends p{inputs;weights;output;dispatch;shader;constructor(t,e,r,n){super(t),this.shader=t.dtype==="f16"?rt:tt;let i=_(e.h,n.kernel,n.stride,n.padding),o=_(e.w,n.kernel,n.stride,n.padding),s=e.c/4,u=b(n.padding,e.h,i,n.kernel,n.stride),l=b(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 nt=`// Element-wise add of two tensors \u2014 used for residual connections in MBConv blocks.
|
|
4138
4843
|
// Operates on the flat float buffer directly; layout is irrelevant for a pure element-wise op.
|
|
4139
4844
|
|
|
4140
4845
|
struct Params {
|
|
@@ -4155,7 +4860,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4155
4860
|
if (idx >= params.size) { return; }
|
|
4156
4861
|
output[idx] = input_a[idx] + input_b[idx];
|
|
4157
4862
|
}
|
|
4158
|
-
`;var
|
|
4863
|
+
`;var at=`enable f16;
|
|
4159
4864
|
|
|
4160
4865
|
// Element-wise add \u2014 full f16 variant.
|
|
4161
4866
|
// array<f16> is binary-compatible with array<vec4<f16>> written by the f16 conv shaders.
|
|
@@ -4178,7 +4883,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4178
4883
|
if (idx >= params.size) { return; }
|
|
4179
4884
|
output[idx] = input_a[idx] + input_b[idx];
|
|
4180
4885
|
}
|
|
4181
|
-
`;var
|
|
4886
|
+
`;var V=class extends p{inputs;weights=[];output;dispatch;shader;constructor(t,e,r){super(t),this.shader=t.dtype==="f16"?at:nt;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 it=`// Element-wise sigmoid: output = 1 / (1 + exp(-x)).
|
|
4182
4887
|
// Operates on packed vec4 buffers (NHWC layout). exp() and arithmetic are element-wise on vec4.
|
|
4183
4888
|
|
|
4184
4889
|
struct Params {
|
|
@@ -4198,7 +4903,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4198
4903
|
if (idx >= params.n_groups) { return; }
|
|
4199
4904
|
output_buf[idx] = 1.0 / (1.0 + exp(-input_buf[idx]));
|
|
4200
4905
|
}
|
|
4201
|
-
`;var
|
|
4906
|
+
`;var ot=`enable f16;
|
|
4202
4907
|
|
|
4203
4908
|
// Sigmoid \u2014 full f16 variant.
|
|
4204
4909
|
|
|
@@ -4220,7 +4925,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4220
4925
|
let x = vec4<f32>(input_buf[idx]);
|
|
4221
4926
|
output_buf[idx] = vec4<f16>(1.0 / (1.0 + exp(-x)));
|
|
4222
4927
|
}
|
|
4223
|
-
`;var
|
|
4928
|
+
`;var N=class extends p{inputs;weights=[];output;dispatch;shader;constructor(t,e){super(t),this.shader=t.dtype==="f16"?ot:it;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 st=`// Element-wise tanh \u2014 used by ConvGRU candidate activation.
|
|
4224
4929
|
// Operates on packed vec4 buffers (NHWC layout). tanh() is element-wise on vec4.
|
|
4225
4930
|
|
|
4226
4931
|
struct Params {
|
|
@@ -4240,7 +4945,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4240
4945
|
if (idx >= params.n_groups) { return; }
|
|
4241
4946
|
output_buf[idx] = tanh(input_buf[idx]);
|
|
4242
4947
|
}
|
|
4243
|
-
`;var
|
|
4948
|
+
`;var ut=`enable f16;
|
|
4244
4949
|
|
|
4245
4950
|
// Tanh \u2014 full f16 variant.
|
|
4246
4951
|
|
|
@@ -4262,7 +4967,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4262
4967
|
let x = vec4<f32>(input_buf[idx]);
|
|
4263
4968
|
output_buf[idx] = vec4<f16>(tanh(x));
|
|
4264
4969
|
}
|
|
4265
|
-
`;var
|
|
4970
|
+
`;var $=class extends p{inputs;weights=[];output;dispatch;shader;constructor(t,e){super(t),this.shader=t.dtype==="f16"?ut:st;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 pt=`// Element-wise multiply \u2014 used in ConvGRU for r \u2299 h_prev.
|
|
4266
4971
|
// Same flat-float layout as add.wgsl.
|
|
4267
4972
|
|
|
4268
4973
|
struct Params {
|
|
@@ -4283,7 +4988,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4283
4988
|
if (idx >= params.size) { return; }
|
|
4284
4989
|
output[idx] = input_a[idx] * input_b[idx];
|
|
4285
4990
|
}
|
|
4286
|
-
`;var
|
|
4991
|
+
`;var lt=`enable f16;
|
|
4287
4992
|
|
|
4288
4993
|
// Element-wise multiply \u2014 full f16 variant.
|
|
4289
4994
|
// array<f16> is binary-compatible with array<vec4<f16>> written by the f16 conv shaders.
|
|
@@ -4306,7 +5011,208 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4306
5011
|
if (idx >= params.size) { return; }
|
|
4307
5012
|
output[idx] = input_a[idx] * input_b[idx];
|
|
4308
5013
|
}
|
|
4309
|
-
`;var
|
|
5014
|
+
`;var j=class extends p{inputs;weights=[];output;dispatch;shader;constructor(t,e,r){super(t),this.shader=t.dtype==="f16"?lt:pt;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 ct=`// Bilinear gather-warp (f32). See warp_f16.wgsl for the math.
|
|
5015
|
+
|
|
5016
|
+
struct Params {
|
|
5017
|
+
h : u32,
|
|
5018
|
+
w : u32,
|
|
5019
|
+
flow_scale : f32,
|
|
5020
|
+
}
|
|
5021
|
+
|
|
5022
|
+
@group(0) @binding(0) var<storage, read> source_buf : array<vec4<f32>>;
|
|
5023
|
+
@group(0) @binding(1) var<storage, read> flow_buf : array<vec4<f32>>;
|
|
5024
|
+
@group(0) @binding(2) var<uniform> params : Params;
|
|
5025
|
+
@group(0) @binding(3) var<storage, read_write> output_buf : array<vec4<f32>>;
|
|
5026
|
+
|
|
5027
|
+
fn samp(x: i32, y: i32, W: i32, H: i32) -> vec4<f32> {
|
|
5028
|
+
let cx = clamp(x, 0, W - 1);
|
|
5029
|
+
let cy = clamp(y, 0, H - 1);
|
|
5030
|
+
return source_buf[u32(cy) * u32(W) + u32(cx)];
|
|
5031
|
+
}
|
|
5032
|
+
|
|
5033
|
+
@compute @workgroup_size(8, 8, 1)
|
|
5034
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
5035
|
+
let x = gid.x;
|
|
5036
|
+
let y = gid.y;
|
|
5037
|
+
if (x >= params.w || y >= params.h) { return; }
|
|
5038
|
+
|
|
5039
|
+
let W = i32(params.w);
|
|
5040
|
+
let H = i32(params.h);
|
|
5041
|
+
let idx = y * params.w + x;
|
|
5042
|
+
|
|
5043
|
+
let f = flow_buf[idx].xy;
|
|
5044
|
+
let sx = clamp(f32(x) + params.flow_scale * f.x, 0.0, f32(W - 1));
|
|
5045
|
+
let sy = clamp(f32(y) + params.flow_scale * f.y, 0.0, f32(H - 1));
|
|
5046
|
+
|
|
5047
|
+
let x0 = i32(floor(sx));
|
|
5048
|
+
let y0 = i32(floor(sy));
|
|
5049
|
+
let tx = sx - f32(x0);
|
|
5050
|
+
let ty = sy - f32(y0);
|
|
5051
|
+
|
|
5052
|
+
let top = mix(samp(x0, y0, W, H), samp(x0 + 1, y0, W, H), tx);
|
|
5053
|
+
let bot = mix(samp(x0, y0 + 1, W, H), samp(x0 + 1, y0 + 1, W, H), tx);
|
|
5054
|
+
output_buf[idx] = mix(top, bot, ty);
|
|
5055
|
+
}
|
|
5056
|
+
`;var dt=`enable f16;
|
|
5057
|
+
|
|
5058
|
+
// Bilinear gather-warp (f16 storage, f32 coordinate math). For each output pixel
|
|
5059
|
+
// p, sample the source at p + flow_scale\xB7flow[p].xy and bilinearly interpolate,
|
|
5060
|
+
// clamping the sample to the edge (border-replicate). Source + flow are 4-ch
|
|
5061
|
+
// (1 group), same resolution; flow vector is in .xy.
|
|
5062
|
+
|
|
5063
|
+
struct Params {
|
|
5064
|
+
h : u32,
|
|
5065
|
+
w : u32,
|
|
5066
|
+
flow_scale : f32,
|
|
5067
|
+
}
|
|
5068
|
+
|
|
5069
|
+
@group(0) @binding(0) var<storage, read> source_buf : array<vec4<f16>>;
|
|
5070
|
+
@group(0) @binding(1) var<storage, read> flow_buf : array<vec4<f16>>;
|
|
5071
|
+
@group(0) @binding(2) var<uniform> params : Params;
|
|
5072
|
+
@group(0) @binding(3) var<storage, read_write> output_buf : array<vec4<f16>>;
|
|
5073
|
+
|
|
5074
|
+
fn samp(x: i32, y: i32, W: i32, H: i32) -> vec4<f32> {
|
|
5075
|
+
let cx = clamp(x, 0, W - 1);
|
|
5076
|
+
let cy = clamp(y, 0, H - 1);
|
|
5077
|
+
return vec4<f32>(source_buf[u32(cy) * u32(W) + u32(cx)]);
|
|
5078
|
+
}
|
|
5079
|
+
|
|
5080
|
+
@compute @workgroup_size(8, 8, 1)
|
|
5081
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
5082
|
+
let x = gid.x;
|
|
5083
|
+
let y = gid.y;
|
|
5084
|
+
if (x >= params.w || y >= params.h) { return; }
|
|
5085
|
+
|
|
5086
|
+
let W = i32(params.w);
|
|
5087
|
+
let H = i32(params.h);
|
|
5088
|
+
let idx = y * params.w + x;
|
|
5089
|
+
|
|
5090
|
+
let f = vec2<f32>(flow_buf[idx].xy);
|
|
5091
|
+
let sx = clamp(f32(x) + params.flow_scale * f.x, 0.0, f32(W - 1));
|
|
5092
|
+
let sy = clamp(f32(y) + params.flow_scale * f.y, 0.0, f32(H - 1));
|
|
5093
|
+
|
|
5094
|
+
let x0 = i32(floor(sx));
|
|
5095
|
+
let y0 = i32(floor(sy));
|
|
5096
|
+
let tx = sx - f32(x0);
|
|
5097
|
+
let ty = sy - f32(y0);
|
|
5098
|
+
|
|
5099
|
+
let top = mix(samp(x0, y0, W, H), samp(x0 + 1, y0, W, H), tx);
|
|
5100
|
+
let bot = mix(samp(x0, y0 + 1, W, H), samp(x0 + 1, y0 + 1, W, H), tx);
|
|
5101
|
+
output_buf[idx] = vec4<f16>(mix(top, bot, ty));
|
|
5102
|
+
}
|
|
5103
|
+
`;var q=class extends p{inputs;weights=[];output;dispatch;shader;constructor(t,e,r,n){super(t),this.shader=t.dtype==="f16"?dt:ct,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 ft=`// Flow-gated temporal stabilizer (f32). See stabilize_f16.wgsl for the math.
|
|
5104
|
+
|
|
5105
|
+
struct Params {
|
|
5106
|
+
h : u32,
|
|
5107
|
+
w : u32,
|
|
5108
|
+
t_lo : f32,
|
|
5109
|
+
t_hi : f32,
|
|
5110
|
+
leak : f32,
|
|
5111
|
+
release : f32,
|
|
5112
|
+
t_div : f32,
|
|
5113
|
+
div_scale: f32,
|
|
5114
|
+
step_x : u32,
|
|
5115
|
+
step_y : u32,
|
|
5116
|
+
}
|
|
5117
|
+
|
|
5118
|
+
@group(0) @binding(0) var<storage, read> flow_buf : array<vec4<f32>>;
|
|
5119
|
+
@group(0) @binding(1) var<storage, read> pred_buf : array<vec4<f32>>;
|
|
5120
|
+
@group(0) @binding(2) var<storage, read> ref_buf : array<vec4<f32>>;
|
|
5121
|
+
@group(0) @binding(3) var<storage, read> env_prev_buf : array<vec4<f32>>;
|
|
5122
|
+
@group(0) @binding(4) var<uniform> params : Params;
|
|
5123
|
+
@group(0) @binding(5) var<storage, read_write> output_buf : array<vec4<f32>>;
|
|
5124
|
+
|
|
5125
|
+
@compute @workgroup_size(8, 8, 1)
|
|
5126
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
5127
|
+
let x = gid.x;
|
|
5128
|
+
let y = gid.y;
|
|
5129
|
+
if (x >= params.w || y >= params.h) { return; }
|
|
5130
|
+
let idx = y * params.w + x;
|
|
5131
|
+
|
|
5132
|
+
let mag = length(flow_buf[idx].xy);
|
|
5133
|
+
let env_prev = env_prev_buf[idx].y;
|
|
5134
|
+
let env = max(mag, params.release * env_prev);
|
|
5135
|
+
|
|
5136
|
+
let xr = min(x + params.step_x, params.w - 1u);
|
|
5137
|
+
let xl = select(x - params.step_x, 0u, x < params.step_x);
|
|
5138
|
+
let yd = min(y + params.step_y, params.h - 1u);
|
|
5139
|
+
let yu = select(y - params.step_y, 0u, y < params.step_y);
|
|
5140
|
+
let dfx = flow_buf[y * params.w + xr].x - flow_buf[y * params.w + xl].x;
|
|
5141
|
+
let dfy = flow_buf[yd * params.w + x].y - flow_buf[yu * params.w + x].y;
|
|
5142
|
+
let divg = abs(dfx + dfy);
|
|
5143
|
+
|
|
5144
|
+
let g_mag = clamp((env - params.t_lo) / max(params.t_hi - params.t_lo, 1e-3), 0.0, 1.0);
|
|
5145
|
+
let g_div = clamp((divg - params.t_div) / max(params.div_scale, 1e-3), 0.0, 1.0);
|
|
5146
|
+
let g = max(max(g_mag, g_div), params.leak);
|
|
5147
|
+
|
|
5148
|
+
let pred = pred_buf[idx].x;
|
|
5149
|
+
let refv = ref_buf[idx].x;
|
|
5150
|
+
let stab = g * pred + (1.0 - g) * refv;
|
|
5151
|
+
|
|
5152
|
+
output_buf[idx] = vec4<f32>(stab, env, 0.0, 0.0);
|
|
5153
|
+
}
|
|
5154
|
+
`;var ht=`enable f16;
|
|
5155
|
+
|
|
5156
|
+
// Flow-gated temporal stabilizer (f16 storage, f32 gate math). Per pixel:
|
|
5157
|
+
// env = max(|flow.xy|, release\xB7envPrev.y) peak-hold (fast attack, slow release)
|
|
5158
|
+
// div = |\u2202fx/\u2202x + \u2202fy/\u2202y| flow divergence (occlusion seam)
|
|
5159
|
+
// g = max(clamp((env-tLo)/(tHi-tLo),0,1), clamp((div-tDiv)/divScale,0,1), leak)
|
|
5160
|
+
// out = vec4((g\xB7pred + (1-g)\xB7ref).x, env, 0, 0)
|
|
5161
|
+
// The divergence term opens the gate at occlusion/disocclusion boundaries (where
|
|
5162
|
+
// the flow tears but the revealed-background magnitude is ~0). Finite-difference
|
|
5163
|
+
// step spans ~1 base/4 pixel. alpha is in .x of pred/ref; env threads via .y.
|
|
5164
|
+
|
|
5165
|
+
struct Params {
|
|
5166
|
+
h : u32,
|
|
5167
|
+
w : u32,
|
|
5168
|
+
t_lo : f32,
|
|
5169
|
+
t_hi : f32,
|
|
5170
|
+
leak : f32,
|
|
5171
|
+
release : f32,
|
|
5172
|
+
t_div : f32,
|
|
5173
|
+
div_scale: f32,
|
|
5174
|
+
step_x : u32,
|
|
5175
|
+
step_y : u32,
|
|
5176
|
+
}
|
|
5177
|
+
|
|
5178
|
+
@group(0) @binding(0) var<storage, read> flow_buf : array<vec4<f16>>;
|
|
5179
|
+
@group(0) @binding(1) var<storage, read> pred_buf : array<vec4<f16>>;
|
|
5180
|
+
@group(0) @binding(2) var<storage, read> ref_buf : array<vec4<f16>>;
|
|
5181
|
+
@group(0) @binding(3) var<storage, read> env_prev_buf : array<vec4<f16>>;
|
|
5182
|
+
@group(0) @binding(4) var<uniform> params : Params;
|
|
5183
|
+
@group(0) @binding(5) var<storage, read_write> output_buf : array<vec4<f16>>;
|
|
5184
|
+
|
|
5185
|
+
@compute @workgroup_size(8, 8, 1)
|
|
5186
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
5187
|
+
let x = gid.x;
|
|
5188
|
+
let y = gid.y;
|
|
5189
|
+
if (x >= params.w || y >= params.h) { return; }
|
|
5190
|
+
let idx = y * params.w + x;
|
|
5191
|
+
|
|
5192
|
+
let mag = length(vec2<f32>(flow_buf[idx].xy));
|
|
5193
|
+
let env_prev = f32(env_prev_buf[idx].y);
|
|
5194
|
+
let env = max(mag, params.release * env_prev);
|
|
5195
|
+
|
|
5196
|
+
// Flow divergence over a \xB1step finite-difference (clamped to the edges).
|
|
5197
|
+
let xr = min(x + params.step_x, params.w - 1u);
|
|
5198
|
+
let xl = select(x - params.step_x, 0u, x < params.step_x);
|
|
5199
|
+
let yd = min(y + params.step_y, params.h - 1u);
|
|
5200
|
+
let yu = select(y - params.step_y, 0u, y < params.step_y);
|
|
5201
|
+
let dfx = f32(flow_buf[y * params.w + xr].x) - f32(flow_buf[y * params.w + xl].x);
|
|
5202
|
+
let dfy = f32(flow_buf[yd * params.w + x].y) - f32(flow_buf[yu * params.w + x].y);
|
|
5203
|
+
let divg = abs(dfx + dfy);
|
|
5204
|
+
|
|
5205
|
+
let g_mag = clamp((env - params.t_lo) / max(params.t_hi - params.t_lo, 1e-3), 0.0, 1.0);
|
|
5206
|
+
let g_div = clamp((divg - params.t_div) / max(params.div_scale, 1e-3), 0.0, 1.0);
|
|
5207
|
+
let g = max(max(g_mag, g_div), params.leak);
|
|
5208
|
+
|
|
5209
|
+
let pred = f32(pred_buf[idx].x);
|
|
5210
|
+
let refv = f32(ref_buf[idx].x);
|
|
5211
|
+
let stab = g * pred + (1.0 - g) * refv;
|
|
5212
|
+
|
|
5213
|
+
output_buf[idx] = vec4<f16>(f16(stab), f16(env), 0.0h, 0.0h);
|
|
5214
|
+
}
|
|
5215
|
+
`;var X=class extends p{inputs;weights=[];output;dispatch;shader;constructor(t,e,r,n,i,o){super(t),this.shader=t.dtype==="f16"?ht:ft,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 gt=`// Bilinear upsample (arbitrary ratio), align_corners=False (matches PyTorch default).
|
|
4310
5216
|
// Input/output in NHWC vec4 format: index = y*W*(C/4) + x*(C/4) + c_group.
|
|
4311
5217
|
// Each thread computes one output pixel for one channel group (vec4 = 4 channels).
|
|
4312
5218
|
|
|
@@ -4364,7 +5270,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4364
5270
|
|
|
4365
5271
|
output_buf[oy * params.out_w * C + ox * C + c] = result;
|
|
4366
5272
|
}
|
|
4367
|
-
`;var
|
|
5273
|
+
`;var mt=`enable f16;
|
|
4368
5274
|
|
|
4369
5275
|
// Bilinear upsample 2\xD7 \u2014 full f16 variant.
|
|
4370
5276
|
// Interpolation weights (wx, wy) and intermediate blends computed in f32 for
|
|
@@ -4420,7 +5326,53 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4420
5326
|
|
|
4421
5327
|
output_buf[oy * params.out_w * C + ox * C + c] = vec4<f16>(result);
|
|
4422
5328
|
}
|
|
4423
|
-
`;var
|
|
5329
|
+
`;var K=class extends p{inputs;weights=[];output;dispatch;shader;constructor(t,e,r){super(t),this.shader=t.dtype==="f16"?mt:gt;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 _t=`// Top-left crop (f32). See crop_f16.wgsl.
|
|
5330
|
+
|
|
5331
|
+
struct Params {
|
|
5332
|
+
in_w : u32,
|
|
5333
|
+
out_h : u32,
|
|
5334
|
+
out_w : u32,
|
|
5335
|
+
groups : u32,
|
|
5336
|
+
}
|
|
5337
|
+
|
|
5338
|
+
@group(0) @binding(0) var<storage, read> input_buf : array<vec4<f32>>;
|
|
5339
|
+
@group(0) @binding(1) var<uniform> params : Params;
|
|
5340
|
+
@group(0) @binding(2) var<storage, read_write> output_buf : array<vec4<f32>>;
|
|
5341
|
+
|
|
5342
|
+
@compute @workgroup_size(8, 8, 1)
|
|
5343
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
5344
|
+
let x = gid.x;
|
|
5345
|
+
let y = gid.y;
|
|
5346
|
+
let g = gid.z;
|
|
5347
|
+
if (x >= params.out_w || y >= params.out_h || g >= params.groups) { return; }
|
|
5348
|
+
let G = params.groups;
|
|
5349
|
+
output_buf[y * params.out_w * G + x * G + g] = input_buf[y * params.in_w * G + x * G + g];
|
|
5350
|
+
}
|
|
5351
|
+
`;var bt=`enable f16;
|
|
5352
|
+
|
|
5353
|
+
// Top-left crop: output[y,x,g] = input[y,x,g] for y<outH, x<outW (training crop_like).
|
|
5354
|
+
|
|
5355
|
+
struct Params {
|
|
5356
|
+
in_w : u32,
|
|
5357
|
+
out_h : u32,
|
|
5358
|
+
out_w : u32,
|
|
5359
|
+
groups : u32,
|
|
5360
|
+
}
|
|
5361
|
+
|
|
5362
|
+
@group(0) @binding(0) var<storage, read> input_buf : array<vec4<f16>>;
|
|
5363
|
+
@group(0) @binding(1) var<uniform> params : Params;
|
|
5364
|
+
@group(0) @binding(2) var<storage, read_write> output_buf : array<vec4<f16>>;
|
|
5365
|
+
|
|
5366
|
+
@compute @workgroup_size(8, 8, 1)
|
|
5367
|
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
5368
|
+
let x = gid.x;
|
|
5369
|
+
let y = gid.y;
|
|
5370
|
+
let g = gid.z;
|
|
5371
|
+
if (x >= params.out_w || y >= params.out_h || g >= params.groups) { return; }
|
|
5372
|
+
let G = params.groups;
|
|
5373
|
+
output_buf[y * params.out_w * G + x * G + g] = input_buf[y * params.in_w * G + x * G + g];
|
|
5374
|
+
}
|
|
5375
|
+
`;var Y=class extends p{inputs;weights=[];output;dispatch;shader;constructor(t,e,r){super(t),this.shader=t.dtype==="f16"?bt:_t;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 vt=`// Bicubic upsample (arbitrary scale) \u2014 Keys cubic, a=-0.75 (PyTorch default
|
|
4424
5376
|
// for mode='bicubic', align_corners=False). Direct 2D, 4\xD74 = 16 taps per
|
|
4425
5377
|
// output pixel. NHWC vec4 layout: index = y*W*(C/4) + x*(C/4) + c_group.
|
|
4426
5378
|
|
|
@@ -4487,7 +5439,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4487
5439
|
|
|
4488
5440
|
output_buf[oy * params.out_w * C + ox * C + c] = acc;
|
|
4489
5441
|
}
|
|
4490
|
-
`;var
|
|
5442
|
+
`;var xt=`enable f16;
|
|
4491
5443
|
|
|
4492
5444
|
// Bicubic upsample \u2014 full f16 storage variant. Bicubic weights and the per-
|
|
4493
5445
|
// pixel accumulator are computed in f32 (cheap to keep precision around the
|
|
@@ -4556,7 +5508,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4556
5508
|
|
|
4557
5509
|
output_buf[oy * params.out_w * C + ox * C + c] = vec4<f16>(acc);
|
|
4558
5510
|
}
|
|
4559
|
-
`;var
|
|
5511
|
+
`;var J=class extends p{inputs;weights=[];output;dispatch;shader;constructor(t,e,r){super(t),this.shader=t.dtype==="f16"?xt:vt;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 wt=`// Channel concatenation: output = cat(A, B, dim=channel).
|
|
4560
5512
|
// Both A and B must share the same H\xD7W and be in NHWC vec4 format.
|
|
4561
5513
|
// Output layout: for each (y, x), the first a_groups vec4s come from A,
|
|
4562
5514
|
// followed by b_groups vec4s from B.
|
|
@@ -4601,7 +5553,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4601
5553
|
output_buf[out_idx] = input_b[y * W * Bg + x * Bg + c_b];
|
|
4602
5554
|
}
|
|
4603
5555
|
}
|
|
4604
|
-
`;var
|
|
5556
|
+
`;var yt=`enable f16;
|
|
4605
5557
|
|
|
4606
5558
|
// Channel concatenation \u2014 full f16 variant.
|
|
4607
5559
|
|
|
@@ -4642,7 +5594,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4642
5594
|
output_buf[out_idx] = input_b[y * W * Bg + x * Bg + c_b];
|
|
4643
5595
|
}
|
|
4644
5596
|
}
|
|
4645
|
-
`;var
|
|
5597
|
+
`;var Q=class extends p{inputs;weights=[];output;dispatch;shader;constructor(t,e,r){super(t),this.shader=t.dtype==="f16"?yt:wt;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 kt=`// Conv2d + skip add fused.
|
|
4646
5598
|
// Identical to conv2d.wgsl except skip is an activation input (binding 1),
|
|
4647
5599
|
// added element-wise to the conv result at write time.
|
|
4648
5600
|
// Eliminates the separate add dispatch and its intermediate buffer round-trip.
|
|
@@ -4716,7 +5668,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4716
5668
|
let out_idx = y * params.out_w * O + x * O + o;
|
|
4717
5669
|
output_buf[out_idx] = result + skip_buf[out_idx];
|
|
4718
5670
|
}
|
|
4719
|
-
`;var
|
|
5671
|
+
`;var Pt=`enable f16;
|
|
4720
5672
|
|
|
4721
5673
|
// Conv2d + skip add fused \u2014 full f16 variant.
|
|
4722
5674
|
|
|
@@ -4790,7 +5742,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4790
5742
|
let out_idx = y * params.out_w * O + x * O + o;
|
|
4791
5743
|
output_buf[out_idx] = result + skip_buf[out_idx];
|
|
4792
5744
|
}
|
|
4793
|
-
`;var
|
|
5745
|
+
`;var Z=class extends p{inputs;weights;output;dispatch;shader;constructor(t,e,r,n,i){super(t),this.shader=t.dtype==="f16"?Pt:kt;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=b(i.padding,e.h,o,i.kernel,i.stride),f=b(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 Ct=`// proj_residual: bespoke 1\xD71 conv (no activation) + residual add, fused.
|
|
4794
5746
|
// Specializes conv2d_add to kernel=1 / stride=1 / pad=0 / no activation: drops
|
|
4795
5747
|
// the kernel loop, the padding checks, and the activation branch. Used by the
|
|
4796
5748
|
// MBConv project+residual tail. Both inputs share the same spatial resolution.
|
|
@@ -4835,7 +5787,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4835
5787
|
|
|
4836
5788
|
output_buf[pix * O + o] = result;
|
|
4837
5789
|
}
|
|
4838
|
-
`;var
|
|
5790
|
+
`;var Tt=`enable f16;
|
|
4839
5791
|
|
|
4840
5792
|
// proj_residual \u2014 full f16 variant. See proj_residual.wgsl for layout details.
|
|
4841
5793
|
// Bespoke 1\xD71 conv (no activation) + residual add, fused.
|
|
@@ -4877,7 +5829,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4877
5829
|
|
|
4878
5830
|
output_buf[pix * O + o] = result;
|
|
4879
5831
|
}
|
|
4880
|
-
`;var
|
|
5832
|
+
`;var ee=class extends p{inputs;weights;output;dispatch;shader;constructor(t,e,r,n,i){super(t),this.shader=t.dtype==="f16"?Tt:Ct;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 Ut=`// concat_conv2d: fuses [concat(a, b) \u2192 conv 3\xD73 (pad 1) \u2192 relu6] into one
|
|
4881
5833
|
// dispatch. Both inputs are already at the output resolution (the upstream
|
|
4882
5834
|
// upsample stays a separate dispatch writing a clean intermediate, so the conv
|
|
4883
5835
|
// reads are plain-indexed). Identical math to conv2d; the only difference is
|
|
@@ -4937,7 +5889,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4937
5889
|
result = clamp(result, vec4<f32>(0.0), vec4<f32>(6.0));
|
|
4938
5890
|
output_buf[(y * p.w + x) * O + o] = result;
|
|
4939
5891
|
}
|
|
4940
|
-
`;var
|
|
5892
|
+
`;var Wt=`enable f16;
|
|
4941
5893
|
|
|
4942
5894
|
// concat_conv2d \u2014 full f16 variant. See concat_conv2d.wgsl for layout details.
|
|
4943
5895
|
// Fuses [concat(a, b) \u2192 conv 3\xD73 (pad 1) \u2192 relu6] into one dispatch.
|
|
@@ -4992,7 +5944,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
4992
5944
|
result = clamp(result, vec4<f16>(0.0h), vec4<f16>(6.0h));
|
|
4993
5945
|
output_buf[(y * p.w + x) * O + o] = result;
|
|
4994
5946
|
}
|
|
4995
|
-
`;var
|
|
5947
|
+
`;var te=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.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 It=`// gates_fused: ConvGRU z + r gates, fused into one dispatch.
|
|
4996
5948
|
// Production config (c_up=2, split_ratio=0.5 \u2192 passthrough=1, recurrent=1):
|
|
4997
5949
|
// u_in : c_up=2 packed in a vec4 (.x = passthrough a, .y = recurrent b)
|
|
4998
5950
|
// h_prev : hidden carrier \u2014 recurrent state in .z (see cand_update_fused: the
|
|
@@ -5037,7 +5989,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5037
5989
|
let r = 1.0 / (1.0 + exp(-r_pre));
|
|
5038
5990
|
output_buf[y * params.w + x] = vec4<f32>(z, r, 0.0, 0.0);
|
|
5039
5991
|
}
|
|
5040
|
-
`;var
|
|
5992
|
+
`;var Bt=`enable f16;
|
|
5041
5993
|
|
|
5042
5994
|
// gates_fused \u2014 full f16 variant. See gates_fused.wgsl for layout details.
|
|
5043
5995
|
// ConvGRU z + r gates (production config c_up=2, recurrent=1).
|
|
@@ -5079,7 +6031,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5079
6031
|
let r = 1.0h / (1.0h + exp(-r_pre));
|
|
5080
6032
|
output_buf[y * params.w + x] = vec4<f16>(z, r, 0.0h, 0.0h);
|
|
5081
6033
|
}
|
|
5082
|
-
`;var
|
|
6034
|
+
`;var re=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=`// cand_update_fused: ConvGRU candidate path + state update + output, fused.
|
|
5083
6035
|
// Production config (c_up=2, recurrent=1):
|
|
5084
6036
|
// u_in : c_up=2 (.x = a passthrough, .y = b recurrent)
|
|
5085
6037
|
// h_prev : hidden carrier \u2014 recurrent state in .z (the previous frame's
|
|
@@ -5132,7 +6084,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5132
6084
|
let b_out = u_cur.y + gamma_buf[0].x * h_new;
|
|
5133
6085
|
output_buf[cur] = vec4<f32>(u_cur.x, b_out, h_new, 0.0);
|
|
5134
6086
|
}
|
|
5135
|
-
`;var
|
|
6087
|
+
`;var Et=`enable f16;
|
|
5136
6088
|
|
|
5137
6089
|
// cand_update_fused \u2014 full f16 variant. See cand_update_fused.wgsl for details.
|
|
5138
6090
|
// ConvGRU candidate + state update + output (production config c_up=2, recurrent=1).
|
|
@@ -5178,7 +6130,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5178
6130
|
let b_out = u_cur.y + gamma_buf[0].x * h_new;
|
|
5179
6131
|
output_buf[cur] = vec4<f16>(u_cur.x, b_out, h_new, 0.0h);
|
|
5180
6132
|
}
|
|
5181
|
-
`;var
|
|
6133
|
+
`;var ne=class extends p{inputs;weights;output;dispatch;shader;constructor(t,e,r,n,i,o){super(t),this.shader=t.dtype==="f16"?Et: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)),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 Gt=`// conv_expand: bespoke N\u21922 conv 3\xD73 (pad 1) + relu (wrapper expand_feat).
|
|
5182
6134
|
// Expands feat_lr (in_c, mult of 4) to the c_up=2 carrier \u2014 output .xy = the 2
|
|
5183
6135
|
// native channels, .zw = 0. mat4x2 per (kpos, in_group) with a vec2 accumulator.
|
|
5184
6136
|
// Weight: 9 * in_groups mat4x2 (8 floats each, col-major). Bias .xy.
|
|
@@ -5215,7 +6167,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5215
6167
|
result = max(result, vec2<f32>(0.0)); // expand_feat is F.relu
|
|
5216
6168
|
output_buf[y * params.w + x] = vec4<f32>(result, 0.0, 0.0);
|
|
5217
6169
|
}
|
|
5218
|
-
`;var
|
|
6170
|
+
`;var Ft=`enable f16;
|
|
5219
6171
|
|
|
5220
6172
|
// conv_expand \u2014 full f16 variant. See conv_expand.wgsl for layout details.
|
|
5221
6173
|
// Bespoke N\u21922 conv 3\xD73 (pad 1) + relu (wrapper expand_feat).
|
|
@@ -5252,7 +6204,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5252
6204
|
result = max(result, vec2<f16>(0.0h));
|
|
5253
6205
|
output_buf[y * params.w + x] = vec4<f16>(result, 0.0h, 0.0h);
|
|
5254
6206
|
}
|
|
5255
|
-
`;var
|
|
6207
|
+
`;var ae=class extends p{inputs;weights;output;dispatch;shader;constructor(t,e,r){super(t),this.shader=t.dtype==="f16"?Ft:Gt;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 At=`// cat_conv_6to2: fused concat(u, d) + 6\u21922 conv 3\xD73 (pad 1) + relu (E up1_combine).
|
|
5256
6208
|
// u = c_up=2 carrier (.xy); d = c_high=4 (full vec4). Both same resolution.
|
|
5257
6209
|
// Channel order concat([u, d]) = (u.x, u.y, d.x, d.y, d.z, d.w), split into
|
|
5258
6210
|
// v3a = (u.x, u.y, d.x) v3b = d.yzw
|
|
@@ -5292,7 +6244,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5292
6244
|
result = max(result, vec2<f32>(0.0)); // up1_combine is F.relu
|
|
5293
6245
|
output_buf[y * params.w + x] = vec4<f32>(result, 0.0, 0.0);
|
|
5294
6246
|
}
|
|
5295
|
-
`;var
|
|
6247
|
+
`;var Mt=`enable f16;
|
|
5296
6248
|
|
|
5297
6249
|
// cat_conv_6to2 \u2014 full f16 variant. See cat_conv_6to2.wgsl for layout details.
|
|
5298
6250
|
// Fused concat(u, d) + 6\u21922 conv 3\xD73 (pad 1) + relu (E up1_combine).
|
|
@@ -5331,7 +6283,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5331
6283
|
result = max(result, vec2<f16>(0.0h));
|
|
5332
6284
|
output_buf[y * params.w + x] = vec4<f16>(result, 0.0h, 0.0h);
|
|
5333
6285
|
}
|
|
5334
|
-
`;var
|
|
6286
|
+
`;var ie=class extends p{inputs;weights;output;dispatch;shader;constructor(t,e,r,n){super(t),this.shader=t.dtype==="f16"?Mt:At,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 Ot=`// down_adapter: fused stride-N 3\xD73 conv (4\u21924) + relu + 1\xD71 adapter (4\u21923, no
|
|
5335
6287
|
// act) into one dispatch. E variant: down2 (c_high=4 \u2192 c_low=4, stride 2) +
|
|
5336
6288
|
// adapter. A/B variant: down1 (RGB .xyz \u2192 4, stride 2/3) + adapter (the down
|
|
5337
6289
|
// weight's 4th input column is zeroed at export for RGB input). Symmetric pad.
|
|
@@ -5379,7 +6331,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5379
6331
|
let adapt_out = adapt_w[0] * down_out + adapt_b[0];
|
|
5380
6332
|
output_buf[y * p.out_w + x] = vec4<f32>(adapt_out.xyz, 0.0);
|
|
5381
6333
|
}
|
|
5382
|
-
`;var
|
|
6334
|
+
`;var Dt=`enable f16;
|
|
5383
6335
|
|
|
5384
6336
|
// down_adapter \u2014 full f16 variant. See down_adapter.wgsl for layout details.
|
|
5385
6337
|
// Fused stride-N 3\xD73 conv (4\u21924) + relu + 1\xD71 adapter (4\u21923, no act).
|
|
@@ -5424,7 +6376,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5424
6376
|
let adapt_out = adapt_w[0] * down_out + adapt_b[0];
|
|
5425
6377
|
output_buf[y * p.out_w + x] = vec4<f16>(adapt_out.xyz, 0.0h);
|
|
5426
6378
|
}
|
|
5427
|
-
`;var
|
|
6379
|
+
`;var oe=class extends p{inputs;weights;output;dispatch;shader;constructor(t,e,r,n,i){super(t),this.shader=t.dtype==="f16"?Dt:Ot;let o=_(e.h,3,i.stride,1),s=_(e.w,3,i.stride,1),u=b(1,e.h,o,3,i.stride),l=b(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 zt=`// up_final: fused concat(u, rgb) \u2192 conv 3\xD73 5\u21921 \u2192 sigmoid (A/B alpha head).
|
|
5428
6380
|
// u = c_up=2 carrier (.xy); rgb = x_hr (.xyz). 5 inputs \u2192 1 alpha (output .x).
|
|
5429
6381
|
// Weight: 18 vec4 \u2014 [0..8] = (w0, w1, 0, 0) for u per kpos; [9..17] =
|
|
5430
6382
|
// (w2, w3, w4, 0) for rgb per kpos. Bias .x.
|
|
@@ -5458,7 +6410,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5458
6410
|
|
|
5459
6411
|
output_buf[y * params.w + x] = vec4<f32>(1.0 / (1.0 + exp(-acc)), 0.0, 0.0, 0.0);
|
|
5460
6412
|
}
|
|
5461
|
-
`;var
|
|
6413
|
+
`;var Rt=`enable f16;
|
|
5462
6414
|
|
|
5463
6415
|
// up_final \u2014 full f16 variant. See up_final.wgsl for layout details.
|
|
5464
6416
|
// Fused concat(u, rgb) \u2192 conv 3\xD73 5\u21921 \u2192 sigmoid (A/B alpha head).
|
|
@@ -5492,7 +6444,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5492
6444
|
|
|
5493
6445
|
output_buf[y * params.w + x] = vec4<f16>(1.0h / (1.0h + exp(-acc)), 0.0h, 0.0h, 0.0h);
|
|
5494
6446
|
}
|
|
5495
|
-
`;var
|
|
6447
|
+
`;var se=class extends p{inputs;weights;output;dispatch;shader;constructor(t,e,r,n){super(t),this.shader=t.dtype==="f16"?Rt:zt,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 Ht=`// up_final_skip: C/D alpha head. Fused concat(u, d_full, rgb) \u2192 conv 3\xD73 9\u21921
|
|
5496
6448
|
// \u2192 sigmoid. u = c_up=2 (.xy); d_full = c_high=4 full-res skip (full vec4);
|
|
5497
6449
|
// rgb = x_hr (.xyz). Channel order concat = 2 + 4 + 3 = 9. Output .x = alpha.
|
|
5498
6450
|
// Weight: 27 vec4 (3 per kpos): [kpos*3+0]=(w0,w1,0,0) u; [kpos*3+1]=(w2..w5)
|
|
@@ -5529,7 +6481,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5529
6481
|
|
|
5530
6482
|
output_buf[y * params.w + x] = vec4<f32>(1.0 / (1.0 + exp(-acc)), 0.0, 0.0, 0.0);
|
|
5531
6483
|
}
|
|
5532
|
-
`;var
|
|
6484
|
+
`;var Lt=`enable f16;
|
|
5533
6485
|
|
|
5534
6486
|
// up_final_skip \u2014 full f16 variant. See up_final_skip.wgsl for layout details.
|
|
5535
6487
|
// C/D alpha head: fused concat(u, d_full, rgb) \u2192 conv 3\xD73 9\u21921 \u2192 sigmoid.
|
|
@@ -5565,7 +6517,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5565
6517
|
|
|
5566
6518
|
output_buf[y * params.w + x] = vec4<f16>(1.0h / (1.0h + exp(-acc)), 0.0h, 0.0h, 0.0h);
|
|
5567
6519
|
}
|
|
5568
|
-
`;var
|
|
6520
|
+
`;var ue=class extends p{inputs;weights;output;dispatch;shader;constructor(t,e,r,n,i){super(t),this.shader=t.dtype==="f16"?Lt:Ht,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 Vt=`// Bilinear upsample + channel concat fused.
|
|
5569
6521
|
// input_a is the decoder tensor at small spatial resolution (in_h \xD7 in_w).
|
|
5570
6522
|
// input_b is the encoder skip feature already at output resolution (out_h \xD7 out_w).
|
|
5571
6523
|
// For output channels 0..a_groups-1: bilinearly interpolate from input_a.
|
|
@@ -5626,7 +6578,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5626
6578
|
output_buf[out_idx] = input_b[oy * params.out_w * params.b_groups + ox * params.b_groups + c_b];
|
|
5627
6579
|
}
|
|
5628
6580
|
}
|
|
5629
|
-
`;var
|
|
6581
|
+
`;var Nt=`enable f16;
|
|
5630
6582
|
|
|
5631
6583
|
// Bilinear upsample + channel concat fused \u2014 full f16 variant.
|
|
5632
6584
|
// Bilinear weights (wx, wy) and intermediate blends computed in f32; result cast to f16.
|
|
@@ -5686,7 +6638,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5686
6638
|
output_buf[out_idx] = input_b[oy * params.out_w * params.b_groups + ox * params.b_groups + c_b];
|
|
5687
6639
|
}
|
|
5688
6640
|
}
|
|
5689
|
-
`;var
|
|
6641
|
+
`;var pe=class extends p{inputs;weights=[];output;dispatch;shader;constructor(t,e,r,n){super(t),this.shader=t.dtype==="f16"?Nt:Vt;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 $t=`// Bilinear upsample + 1\xD71 pointwise conv fused.
|
|
5690
6642
|
// For each output pixel, bilinearly samples the small input for each in_group,
|
|
5691
6643
|
// immediately applies the 1\xD71 conv weights, and writes the activated result.
|
|
5692
6644
|
// Eliminates the intermediate full-resolution upsample buffer.
|
|
@@ -5753,7 +6705,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5753
6705
|
|
|
5754
6706
|
output_buf[oy * params.out_w * params.out_groups + ox * params.out_groups + og] = result;
|
|
5755
6707
|
}
|
|
5756
|
-
`;var
|
|
6708
|
+
`;var jt=`enable f16;
|
|
5757
6709
|
|
|
5758
6710
|
// Bilinear upsample + 1\xD71 pointwise conv fused \u2014 full f16 variant.
|
|
5759
6711
|
// Bilinear weights and intermediate blends computed in f32; conv accumulation in f16.
|
|
@@ -5820,7 +6772,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5820
6772
|
|
|
5821
6773
|
output_buf[oy * params.out_w * params.out_groups + ox * params.out_groups + og] = result;
|
|
5822
6774
|
}
|
|
5823
|
-
`;var
|
|
6775
|
+
`;var le=class extends p{inputs;weights;output;dispatch;shader;constructor(t,e,r,n){super(t),this.shader=t.dtype==="f16"?jt:$t;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 qt=`// Bilinear upsample + sigmoid fused.
|
|
5824
6776
|
// Identical to bilinear_upsample.wgsl except sigmoid is applied at write time.
|
|
5825
6777
|
// Eliminates the intermediate full-resolution buffer and the separate sigmoid dispatch.
|
|
5826
6778
|
|
|
@@ -5874,7 +6826,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5874
6826
|
|
|
5875
6827
|
output_buf[oy * params.out_w * C + ox * C + c] = 1.0 / (1.0 + exp(-result));
|
|
5876
6828
|
}
|
|
5877
|
-
`;var
|
|
6829
|
+
`;var Xt=`enable f16;
|
|
5878
6830
|
|
|
5879
6831
|
// Bilinear upsample + sigmoid fused \u2014 full f16 variant.
|
|
5880
6832
|
// Interpolation computed in f32 for accuracy; sigmoid and result cast to f16.
|
|
@@ -5929,7 +6881,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
5929
6881
|
|
|
5930
6882
|
output_buf[oy * params.out_w * C + ox * C + c] = vec4<f16>(1.0 / (1.0 + exp(-result)));
|
|
5931
6883
|
}
|
|
5932
|
-
`;var
|
|
6884
|
+
`;var ce=class extends p{inputs;weights=[];output;dispatch;shader;constructor(t,e,r){super(t),this.shader=t.dtype==="f16"?Xt:qt;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 Kt=`// Composite an RGBA image over a solid background, gated by a 1-ch alpha.
|
|
5933
6885
|
// Fragment writes the canvas's swapchain texture (premultiplied output).
|
|
5934
6886
|
//
|
|
5935
6887
|
// Caller invariants (matched in CompositeSolidWebGPU):
|
|
@@ -5974,7 +6926,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
5974
6926
|
let rgb = fg * a + params.bgColor.rgb * (1.0 - a);
|
|
5975
6927
|
return vec4<f32>(rgb, 1.0);
|
|
5976
6928
|
}
|
|
5977
|
-
`;var
|
|
6929
|
+
`;var Yt=`enable f16;
|
|
5978
6930
|
|
|
5979
6931
|
// Composite an RGBA image over a solid background, gated by a 1-ch alpha.
|
|
5980
6932
|
// f16 variant: image and alpha are stored as f16; values promote to f32 on
|
|
@@ -6023,7 +6975,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
6023
6975
|
let rgb = fg * a + params.bgColor.rgb * (1.0 - a);
|
|
6024
6976
|
return vec4<f32>(rgb, 1.0);
|
|
6025
6977
|
}
|
|
6026
|
-
`;var
|
|
6978
|
+
`;var de=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"?Yt:Kt,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 Jt=`// Like composite_solid but bg is an NHWC vec4 storage buffer (e.g. virtual
|
|
6027
6979
|
// background image, or a blurred copy of the input).
|
|
6028
6980
|
|
|
6029
6981
|
struct VertexOut {
|
|
@@ -6065,7 +7017,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
6065
7017
|
let rgb = fg * a + bgc * (1.0 - a);
|
|
6066
7018
|
return vec4<f32>(rgb, 1.0);
|
|
6067
7019
|
}
|
|
6068
|
-
`;var
|
|
7020
|
+
`;var Qt=`enable f16;
|
|
6069
7021
|
|
|
6070
7022
|
// Like composite_solid_f16 but bg is an NHWC vec4<f16> storage buffer (e.g. a
|
|
6071
7023
|
// virtual background image, or a blurred copy of the input).
|
|
@@ -6109,7 +7061,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
6109
7061
|
let rgb = fg * a + bgc * (1.0 - a);
|
|
6110
7062
|
return vec4<f32>(rgb, 1.0);
|
|
6111
7063
|
}
|
|
6112
|
-
`;var
|
|
7064
|
+
`;var fe=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"?Qt:Jt,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 Zt=`// Like composite_image but bg is sampled bilinearly \u2014 bg may be smaller than
|
|
6113
7065
|
// (image, alpha). Used by CompositorBlur to skip the final full-res upsample
|
|
6114
7066
|
// in the blur pyramid and let this shader's own per-pixel scan do the
|
|
6115
7067
|
// expansion (the work is already happening here for the composite anyway).
|
|
@@ -6174,7 +7126,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
6174
7126
|
let rgb = fg * a + bgc * (1.0 - a);
|
|
6175
7127
|
return vec4<f32>(rgb, 1.0);
|
|
6176
7128
|
}
|
|
6177
|
-
`;var
|
|
7129
|
+
`;var er=`enable f16;
|
|
6178
7130
|
|
|
6179
7131
|
// f16 storage variant of composite_image_bilinear. bg is at a smaller
|
|
6180
7132
|
// resolution and is bilinearly sampled to match (image, alpha) at full res.
|
|
@@ -6235,7 +7187,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
6235
7187
|
let rgb = fg * a + bgc * (1.0 - a);
|
|
6236
7188
|
return vec4<f32>(rgb, 1.0);
|
|
6237
7189
|
}
|
|
6238
|
-
`;var
|
|
7190
|
+
`;var he=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"?er:Zt,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 tr=`// Passthrough "compositor" \u2014 writes the image directly to the canvas
|
|
6239
7191
|
// swapchain texture with no alpha math and no background. Used by RenderOp
|
|
6240
7192
|
// when the renderer is in disabled state, so the output canvas reflects
|
|
6241
7193
|
// the unmodified input frame instead of a stale matted result.
|
|
@@ -6273,7 +7225,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
6273
7225
|
let i = y * params.width + x;
|
|
6274
7226
|
return vec4<f32>(image[i].rgb, 1.0);
|
|
6275
7227
|
}
|
|
6276
|
-
`;var
|
|
7228
|
+
`;var rr=`enable f16;
|
|
6277
7229
|
|
|
6278
7230
|
// Passthrough "compositor" \u2014 f16 variant. Image is stored as f16; values
|
|
6279
7231
|
// promote to f32 on read and the fragment writes f32 to the canvas
|
|
@@ -6309,7 +7261,7 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
|
|
|
6309
7261
|
let i = y * params.width + x;
|
|
6310
7262
|
return vec4<f32>(vec3<f32>(image[i].rgb), 1.0);
|
|
6311
7263
|
}
|
|
6312
|
-
`;var
|
|
7264
|
+
`;var ge=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"?rr:tr,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 nr=`// Input op \u2014 sample a regular 2D source texture (RGBA8 unorm) into the NHWC
|
|
6313
7265
|
// vec4<f32> output buffer at the target resolution. Used for ImageBitmap
|
|
6314
7266
|
// sources, which are uploaded into a persistent staging texture via
|
|
6315
7267
|
// copyExternalImageToTexture before each dispatch.
|
|
@@ -6339,7 +7291,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
6339
7291
|
let rgba = textureSampleLevel(src_tex, src_sampler, uv, 0.0);
|
|
6340
7292
|
output_buf[y * params.out_w + x] = rgba;
|
|
6341
7293
|
}
|
|
6342
|
-
`;var
|
|
7294
|
+
`;var ar=`enable f16;
|
|
6343
7295
|
|
|
6344
7296
|
// Input op \u2014 f16 storage variant. Source is sampled as vec4<f32>; only the
|
|
6345
7297
|
// store is demoted to vec4<f16>.
|
|
@@ -6369,7 +7321,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
6369
7321
|
let rgba = textureSampleLevel(src_tex, src_sampler, uv, 0.0);
|
|
6370
7322
|
output_buf[y * params.out_w + x] = vec4<f16>(rgba);
|
|
6371
7323
|
}
|
|
6372
|
-
`;var
|
|
7324
|
+
`;var ir=`// Input op \u2014 sample a GPUExternalTexture (zero-copy VideoFrame import) into
|
|
6373
7325
|
// the NHWC vec4<f32> output buffer at the target resolution. Used when the
|
|
6374
7326
|
// caller passes a VideoFrame to setSource(); requires importExternalTexture
|
|
6375
7327
|
// to be called in the same task as the dispatch (the texture is invalidated
|
|
@@ -6400,7 +7352,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
6400
7352
|
let rgba = textureSampleBaseClampToEdge(src_tex, src_sampler, uv);
|
|
6401
7353
|
output_buf[y * params.out_w + x] = rgba;
|
|
6402
7354
|
}
|
|
6403
|
-
`;var
|
|
7355
|
+
`;var or=`enable f16;
|
|
6404
7356
|
|
|
6405
7357
|
// Input op \u2014 texture_external + f16 storage. Sample in f32, store as f16.
|
|
6406
7358
|
|
|
@@ -6429,4 +7381,4 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
6429
7381
|
let rgba = textureSampleBaseClampToEdge(src_tex, src_sampler, uv);
|
|
6430
7382
|
output_buf[y * params.out_w + x] = vec4<f16>(rgba);
|
|
6431
7383
|
}
|
|
6432
|
-
`;var
|
|
7384
|
+
`;var Kn=a=>typeof VideoFrame<"u"&&a instanceof VideoFrame,me=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"?ar:nr);}setSource(t){this.source=t;}run(){if(!this.source)throw new Error("InputWebGPU.run() called before setSource()");Kn(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"?or:ir));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 Yn=navigator.gpu?GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST:0,Ce=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 R(this,i,o,s),ConvTranspose2d:(i,o,s)=>new H(this,i,o,s),DepthwiseConv2d:(i,o,s)=>new L(this,i,o,s),Add:(i,o)=>new V(this,i,o),Sigmoid:i=>new N(this,i),Tanh:i=>new $(this,i),ElementwiseMul:(i,o)=>new j(this,i,o),Warp:(i,o,s)=>new q(this,i,o,s),Stabilize:(i,o,s,u,l)=>new X(this,i,o,s,u,l),BilinearUpsample:(i,o)=>new K(this,i,o),Crop:(i,o)=>new Y(this,i,o),BicubicUpsample:(i,o)=>new J(this,i,o),ChannelConcat:(i,o)=>new Q(this,i,o),Conv2dAdd:(i,o,s,u)=>new Z(this,i,o,s,u),ProjResidual:(i,o,s,u)=>new ee(this,i,o,s,u),ConcatConv2d:(i,o,s,u)=>new te(this,i,o,s,u),GatesFused:(i,o,s)=>new re(this,i,o,s),CandUpdateFused:(i,o,s,u,l)=>new ne(this,i,o,s,u,l),ConvExpand:(i,o)=>new ae(this,i,o),CatConv6to2:(i,o,s)=>new ie(this,i,o,s),DownAdapter:(i,o,s,u)=>new oe(this,i,o,s,u),UpFinal:(i,o,s)=>new se(this,i,o,s),UpFinalSkip:(i,o,s,u)=>new ue(this,i,o,s,u),UpsampleConcat:(i,o,s)=>new pe(this,i,o,s),UpsampleConv1x1:(i,o,s)=>new le(this,i,o,s),UpsampleSigmoid:(i,o)=>new ce(this,i,o),Input:(i,o)=>new me(this,i,o)},this.presenters={CompositeSolid:(i,o,s,u="main")=>{let l=new de(this,i,o,s);return {run:()=>{l.setOutput(this.getCurrentDisplayTexture(u)),l.run();}}},CompositeImage:(i,o,s,u="main")=>{let l=new fe(this,i,o,s);return {run:()=>{l.setOutput(this.getCurrentDisplayTexture(u)),l.run();}}},CompositeImageBilinear:(i,o,s,u="main")=>{let l=new he(this,i,o,s);return {run:()=>{l.setOutput(this.getCurrentDisplayTexture(u)),l.run();}}},CompositePassthrough:(i,o="main")=>{let s=new ge(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:Yn,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(Ye(e)):new Float32Array(t).set(ke(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"?ke(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{we as EffectsPipeline,Ce as WebGPUBackend};
|