@luma.gl/webgpu 9.0.0-beta.6 → 9.0.0-beta.7

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.
Files changed (63) hide show
  1. package/dist/adapter/helpers/get-bind-group.d.ts +3 -3
  2. package/dist/adapter/helpers/get-bind-group.d.ts.map +1 -1
  3. package/dist/adapter/resources/webgpu-buffer.d.ts.map +1 -1
  4. package/dist/adapter/resources/webgpu-buffer.js +3 -1
  5. package/dist/adapter/resources/webgpu-compute-pass.d.ts +14 -8
  6. package/dist/adapter/resources/webgpu-compute-pass.d.ts.map +1 -1
  7. package/dist/adapter/resources/webgpu-compute-pass.js +18 -13
  8. package/dist/adapter/resources/webgpu-compute-pipeline.d.ts +13 -3
  9. package/dist/adapter/resources/webgpu-compute-pipeline.d.ts.map +1 -1
  10. package/dist/adapter/resources/webgpu-compute-pipeline.js +25 -7
  11. package/dist/adapter/resources/webgpu-external-texture.d.ts.map +1 -1
  12. package/dist/adapter/resources/webgpu-external-texture.js +2 -0
  13. package/dist/adapter/resources/webgpu-query-set.d.ts.map +1 -1
  14. package/dist/adapter/resources/webgpu-query-set.js +3 -1
  15. package/dist/adapter/resources/webgpu-render-pipeline.d.ts +49 -1
  16. package/dist/adapter/resources/webgpu-render-pipeline.d.ts.map +1 -1
  17. package/dist/adapter/resources/webgpu-render-pipeline.js +69 -51
  18. package/dist/adapter/resources/webgpu-sampler.d.ts.map +1 -1
  19. package/dist/adapter/resources/webgpu-sampler.js +3 -0
  20. package/dist/adapter/resources/webgpu-shader.d.ts +1 -4
  21. package/dist/adapter/resources/webgpu-shader.d.ts.map +1 -1
  22. package/dist/adapter/resources/webgpu-shader.js +7 -18
  23. package/dist/adapter/resources/webgpu-texture-view.d.ts.map +1 -1
  24. package/dist/adapter/resources/webgpu-texture-view.js +3 -0
  25. package/dist/adapter/resources/webgpu-texture.d.ts +3 -4
  26. package/dist/adapter/resources/webgpu-texture.d.ts.map +1 -1
  27. package/dist/adapter/resources/webgpu-texture.js +8 -8
  28. package/dist/adapter/webgpu-canvas-context.d.ts.map +1 -1
  29. package/dist/adapter/webgpu-canvas-context.js +2 -1
  30. package/dist/adapter/webgpu-device.d.ts +2 -7
  31. package/dist/adapter/webgpu-device.d.ts.map +1 -1
  32. package/dist/adapter/webgpu-device.js +9 -19
  33. package/dist/dist.dev.js +132 -175
  34. package/dist/index.cjs +122 -131
  35. package/dist/index.cjs.map +4 -4
  36. package/dist.min.js +1 -1
  37. package/package.json +2 -2
  38. package/src/adapter/helpers/get-bind-group.ts +4 -4
  39. package/src/adapter/resources/webgpu-buffer.ts +3 -1
  40. package/src/adapter/resources/webgpu-compute-pass.ts +19 -14
  41. package/src/adapter/resources/webgpu-compute-pipeline.ts +36 -9
  42. package/src/adapter/resources/webgpu-external-texture.ts +2 -0
  43. package/src/adapter/resources/webgpu-query-set.ts +3 -1
  44. package/src/adapter/resources/webgpu-render-pipeline.ts +63 -92
  45. package/src/adapter/resources/webgpu-sampler.ts +3 -0
  46. package/src/adapter/resources/webgpu-shader.ts +8 -23
  47. package/src/adapter/resources/webgpu-texture-view.ts +3 -0
  48. package/src/adapter/resources/webgpu-texture.ts +11 -10
  49. package/src/adapter/webgpu-canvas-context.ts +2 -1
  50. package/src/adapter/webgpu-device.ts +11 -20
  51. package/dist/adapter/helpers/generate-mipmaps.d.ts +0 -10
  52. package/dist/adapter/helpers/generate-mipmaps.d.ts.map +0 -1
  53. package/dist/adapter/helpers/generate-mipmaps.js +0 -103
  54. package/dist/adapter/resources/webgpu-query.d.ts +0 -1
  55. package/dist/adapter/resources/webgpu-query.d.ts.map +0 -1
  56. package/dist/adapter/resources/webgpu-query.js +0 -43
  57. package/dist/adapter/webgpu-types.d.ts +0 -1
  58. package/dist/adapter/webgpu-types.d.ts.map +0 -1
  59. package/dist/adapter/webgpu-types.js +0 -0
  60. package/dist/glsl/glsllang.d.ts +0 -3
  61. package/dist/glsl/glsllang.d.ts.map +0 -1
  62. package/dist/glsl/glsllang.js +0 -12
  63. package/src/adapter/helpers/generate-mipmaps.ts +0 -118
package/dist.min.js CHANGED
@@ -4,6 +4,6 @@
4
4
  else if (typeof define === 'function' && define.amd) define([], factory);
5
5
  else if (typeof exports === 'object') exports['luma'] = factory();
6
6
  else root['luma'] = factory();})(globalThis, function () {
7
- var __exports__=(()=>{var he=Object.create;var w=Object.defineProperty;var me=Object.getOwnPropertyDescriptor;var fe=Object.getOwnPropertyNames;var Pe=Object.getPrototypeOf,be=Object.prototype.hasOwnProperty;var ge=(i,e,t)=>e in i?w(i,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):i[e]=t;var ye=(i,e)=>()=>(e||i((e={exports:{}}).exports,e),e.exports),ve=(i,e)=>{for(var t in e)w(i,t,{get:e[t],enumerable:!0})},Y=(i,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of fe(e))!be.call(i,n)&&n!==t&&w(i,n,{get:()=>e[n],enumerable:!(r=me(e,n))||r.enumerable});return i};var p=(i,e,t)=>(t=i!=null?he(Pe(i)):{},Y(e||!i||!i.__esModule?w(t,"default",{value:i,enumerable:!0}):t,i)),xe=i=>Y(w({},"__esModule",{value:!0}),i);var X=(i,e,t)=>(ge(i,typeof e!="symbol"?e+"":e,t),t);var s=ye((Ae,J)=>{J.exports=globalThis.luma});var Te={};ve(Te,{WebGPUBuffer:()=>b,WebGPUDevice:()=>B,WebGPUSampler:()=>c,WebGPUShader:()=>G,WebGPUTexture:()=>x});var l=p(s(),1);var D=p(s(),1);function Ge(i){return i.byteLength||i.data?.byteLength||0}var b=class extends D.Buffer{device;handle;byteLength;constructor(e,t){super(e,t),this.device=e,this.byteLength=Ge(t);let r=Boolean(t.data),n=Math.ceil(this.byteLength/4)*4;this.handle=this.props.handle||this.device.handle.createBuffer({size:n,usage:this.props.usage||GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_DST,mappedAtCreation:this.props.mappedAtCreation||r,label:this.props.id}),t.data&&this._writeMapped(t.data),r&&!t.mappedAtCreation&&this.handle.unmap()}destroy(){this.handle.destroy()}write(e,t=0){this.device.handle.queue.writeBuffer(this.handle,t,e.buffer,e.byteOffset,e.byteLength)}async readAsync(e=0,t=this.byteLength){let r=new b(this.device,{usage:D.Buffer.MAP_READ|D.Buffer.COPY_DST,byteLength:t}),n=this.device.handle.createCommandEncoder();n.copyBufferToBuffer(this.handle,e,r.handle,0,t),this.device.handle.queue.submit([n.finish()]),await r.handle.mapAsync(GPUMapMode.READ,e,t);let o=r.handle.getMappedRange().slice(0);return r.handle.unmap(),r.destroy(),new Uint8Array(o)}_writeMapped(e){let t=this.handle.getMappedRange();new e.constructor(t).set(e)}mapAsync(e,t=0,r){return this.handle.mapAsync(e,t,r)}getMappedRange(e=0,t){return this.handle.getMappedRange(e,t)}unmap(){this.handle.unmap()}};var ee=p(s(),1);function v(i){if(i.includes("webgl"))throw new Error("webgl-only format");return i}var Z=p(s(),1),c=class extends Z.Sampler{device;handle;constructor(e,t){super(e,t),this.device=e;let r={...this.props};r.type!=="comparison-sampler"&&delete r.compare,this.handle=this.handle||this.device.handle.createSampler(r),this.handle.label=this.props.id}destroy(){}};var K=p(s(),1),T=class extends K.TextureView{device;handle;texture;constructor(e,t){super(e,t),this.device=e,this.texture=t.texture,this.handle=this.handle||this.texture.handle.createView({format:t.format||this.texture.format,dimension:t.dimension||this.texture.dimension,aspect:t.aspect,baseMipLevel:t.baseMipLevel,mipLevelCount:t.mipLevelCount,baseArrayLayer:t.baseArrayLayer,arrayLayerCount:t.arrayLayerCount}),this.handle.label=this.props.id}destroy(){}};var Ue={"1d":"1d","2d":"2d","2d-array":"2d",cube:"2d","cube-array":"2d","3d":"3d"},x=class extends ee.Texture{device;handle;height=1;width=1;sampler;view;constructor(e,t){if(super(e,t),this.device=e,t.data instanceof Promise){t.data.then(r=>{this.props={...t,data:r},this.initialize(this.props)});return}this.initialize(t)}initialize(e){this.handle=this.props.handle||this.createHandle(),this.handle.label||=this.id,this.props.data&&this.setData({data:this.props.data}),this.width=this.handle.width,this.height=this.handle.height,this.sampler=e.sampler instanceof c?e.sampler:new c(this.device,e.sampler),this.view=new T(this.device,{...this.props,texture:this})}createHandle(){let e=this.props.width||this.props.data?.width||1,t=this.props.height||this.props.data?.height||1;return this.device.handle.createTexture({label:this.id,size:{width:e,height:t,depthOrArrayLayers:this.props.depth},dimension:Ue[this.props.dimension],format:v(this.props.format),usage:this.props.usage,mipLevelCount:this.props.mipLevels,sampleCount:this.props.samples})}destroy(){this.handle.destroy()}setSampler(e){return this.sampler=e instanceof c?e:new c(this.device,e),this}setData(e){return this.setImage({source:e.data})}setImage(e){let{source:t,width:r=e.source.width,height:n=e.source.height,depth:o=1,sourceX:a=0,sourceY:u=0,mipLevel:d=0,x:g=0,y=0,z:Q=0,aspect:q="all",colorSpace:$="srgb",premultipliedAlpha:ce=!1}=e;return this.device.handle.queue.copyExternalImageToTexture({source:t,origin:[a,u]},{texture:this.handle,origin:[g,y,Q],mipLevel:d,aspect:q,colorSpace:$,premultipliedAlpha:ce},[r,n,o]),{width:r,height:n}}createView(){return this.handle.createView({label:this.id})}};var te=p(s(),1);var R=class extends te.ExternalTexture{device;handle;sampler;constructor(e,t){super(e,t),this.device=e,this.handle=this.props.handle||this.device.handle.importExternalTexture({source:t.source,colorSpace:t.colorSpace}),this.sampler=null}destroy(){}setSampler(e){return this.sampler=e instanceof c?e:new c(this.device,e),this}};var A=p(s(),1),G=class extends A.Shader{device;handle;constructor(e,t){super(e,t),this.device=e,this.device.handle.pushErrorScope("validation"),this.handle=this.props.handle||this.createHandle(),this.handle.label=this.props.id,this._checkCompilationError(this.device.handle.popErrorScope())}async _checkCompilationError(e){let t=await e;if(t){this.debugShader();let r=await this.getCompilationInfo();throw A.log.error(`Shader compilation error: ${t.message}`,r)(),new Error(`Shader compilation error: ${t.message}`)}}destroy(){}async getCompilationInfo(){return(await this.handle.getCompilationInfo()).messages}createHandle(){let{source:e,stage:t}=this.props,r=this.props.language;switch(r==="auto"&&(r=e.includes("->")?"wgsl":"glsl"),r){case"wgsl":return this.device.handle.createShaderModule({code:e});case"glsl":return this.device.handle.createShaderModule({code:e,transform:n=>this.device.glslang.compileGLSL(n,t)});default:throw new Error(r)}}};var f=p(s(),1);function h(i){return i.depthStencil=i.depthStencil||{format:"depth24plus",stencilFront:{},stencilBack:{},depthWriteEnabled:!1,depthCompare:"less-equal"},i.depthStencil}var we={cullMode:(i,e,t)=>{t.primitive=t.primitive||{},t.primitive.cullMode=e},frontFace:(i,e,t)=>{t.primitive=t.primitive||{},t.primitive.frontFace=e},depthWriteEnabled:(i,e,t)=>{let r=h(t);r.depthWriteEnabled=e},depthCompare:(i,e,t)=>{let r=h(t);r.depthCompare=e},depthFormat:(i,e,t)=>{let r=h(t);r.format=e},depthBias:(i,e,t)=>{let r=h(t);r.depthBias=e},depthBiasSlopeScale:(i,e,t)=>{let r=h(t);r.depthBiasSlopeScale=e},depthBiasClamp:(i,e,t)=>{let r=h(t);r.depthBiasClamp=e},stencilReadMask:(i,e,t)=>{let r=h(t);r.stencilReadMask=e},stencilWriteMask:(i,e,t)=>{let r=h(t);r.stencilWriteMask=e},stencilCompare:(i,e,t)=>{let r=h(t);r.stencilFront.compare=e,r.stencilBack.compare=e},stencilPassOperation:(i,e,t)=>{let r=h(t);r.stencilFront.passOp=e,r.stencilBack.passOp=e},stencilFailOperation:(i,e,t)=>{let r=h(t);r.stencilFront.failOp=e,r.stencilBack.failOp=e},stencilDepthFailOperation:(i,e,t)=>{let r=h(t);r.stencilFront.depthFailOp=e,r.stencilBack.depthFailOp=e},sampleCount:(i,e,t)=>{t.multisample=t.multisample||{},t.multisample.count=e},sampleMask:(i,e,t)=>{t.multisample=t.multisample||{},t.multisample.mask=e},sampleAlphaToCoverageEnabled:(i,e,t)=>{t.multisample=t.multisample||{},t.multisample.alphaToCoverageEnabled=e},colorMask:(i,e,t)=>{let r=re(t);r[0].writeMask=e},blendColorOperation:(i,e,t)=>{re(t)}},Se={primitive:{cullMode:"back",topology:"triangle-list"},vertex:{module:void 0,entryPoint:"main"},fragment:{module:void 0,entryPoint:"main",targets:[]},layout:"auto"};function ie(i,e={}){Object.assign(i,{...Se,...i}),We(i,e)}function We(i,e){for(let[t,r]of Object.entries(e)){let n=we[t];if(!n)throw new Error(`Illegal parameter ${t}`);n(t,r,i)}}function re(i){if(i.fragment.targets=i.fragment?.targets||[],!Array.isArray(i.fragment?.targets))throw new Error("colorstate");return i.fragment?.targets?.length===0&&i.fragment.targets?.push({}),i.fragment?.targets}var m=p(s(),1);function ne(i,e,t,r){let n=Be(r,t);return i.createBindGroup({layout:e,entries:n})}function Ce(i,e){let t=i.bindings.find(r=>r.name===e||`${r.name}uniforms`===e.toLocaleLowerCase());return t||m.log.warn(`Binding ${e} not set: Not found in shader layout.`)(),t}function Be(i,e){let t=[];for(let[r,n]of Object.entries(i)){let o=Ce(e,r);o&&t.push(De(n,o.location))}return t}function De(i,e){if(i instanceof m.Buffer)return{binding:e,resource:{buffer:(0,m.cast)(i).handle}};if(i instanceof m.Sampler)return{binding:e,resource:(0,m.cast)(i).handle};if(i instanceof m.Texture)return{binding:e,resource:(0,m.cast)(i).handle.createView({label:"bind-group-auto-created"})};throw new Error("invalid binding")}var U=p(s(),1);function z(i){if(i.endsWith("-webgl"))throw new Error(`WebGPU does not support vertex format ${i}`);return i}function ae(i,e){let t=[],r=new Set;for(let n of e){let o=[],a="vertex",u=0;if(n.attributes)for(let d of n.attributes){let g=d.attribute,y=oe(i,g,r);a=y.stepMode||(y.name.startsWith("instance")?"instance":"vertex"),o.push({format:z(d.format||n.format),offset:d.byteOffset,shaderLocation:y.location}),u+=(0,U.decodeVertexFormat)(n.format).byteLength}else{let d=oe(i,n.name,r);if(!d)continue;u=(0,U.decodeVertexFormat)(n.format).byteLength,a=d.stepMode||(d.name.startsWith("instance")?"instance":"vertex"),o.push({format:z(n.format),offset:0,shaderLocation:d.location})}t.push({arrayStride:n.byteStride||u,stepMode:a,attributes:o})}for(let n of i.attributes)r.has(n.name)||t.push({arrayStride:(0,U.decodeVertexFormat)("float32x3").byteLength,stepMode:n.stepMode||(n.name.startsWith("instance")?"instance":"vertex"),attributes:[{format:z("float32x3"),offset:0,shaderLocation:n.location}]});return t}function oe(i,e,t){let r=i.attributes.find(n=>n.name===e);if(!r)return U.log.warn(`Unknown attribute ${e}`)(),null;if(t.has(e))throw new Error(`Duplicate attribute ${e}`);return t.add(e),r}var E=class extends f.RenderPipeline{device;handle;vs;fs=null;_bindGroupLayout=null;_bindGroup=null;constructor(e,t){if(super(e,t),this.device=e,this.handle=this.props.handle,!this.handle){let r=this._getRenderPipelineDescriptor();f.log.groupCollapsed(1,`new WebGPURenderPipeline(${this.id})`)(),f.log.probe(1,JSON.stringify(r,null,2))(),f.log.groupEnd(1)(),this.handle=this.device.handle.createRenderPipeline(r)}this.handle.label=this.props.id,this.vs=(0,f.cast)(t.vs),this.fs=(0,f.cast)(t.fs)}destroy(){}setBindings(e){Object.assign(this.props.bindings,e)}draw(e){let t=(0,f.cast)(e.renderPass)||this.device.getDefaultRenderPass();t.handle.setPipeline(this.handle);let r=this._getBindGroup();r&&t.handle.setBindGroup(0,r),e.vertexArray.bindBeforeRender(e.renderPass),e.indexCount?t.handle.drawIndexed(e.indexCount,e.instanceCount,e.firstIndex,e.baseVertex,e.firstInstance):t.handle.draw(e.vertexCount||0,e.instanceCount||1,e.firstInstance),e.vertexArray.unbindAfterRender(e.renderPass)}_getBindGroup(){return this._bindGroupLayout=this._bindGroupLayout||this.handle.getBindGroupLayout(0),this._bindGroup=this._bindGroup||ne(this.device.handle,this._bindGroupLayout,this.props.shaderLayout,this.props.bindings),this._bindGroup}_getRenderPipelineDescriptor(){let e={module:(0,f.cast)(this.props.vs).handle,entryPoint:this.props.vsEntryPoint||"main",buffers:ae(this.props.shaderLayout,this.props.bufferLayout)},t;switch(this.props.fs&&(t={module:(0,f.cast)(this.props.fs).handle,entryPoint:this.props.fsEntryPoint||"main",targets:[{format:v(this.device?.canvasContext?.format)}]}),this.props.topology){case"triangle-fan-webgl":case"line-loop-webgl":throw new Error(`WebGPU does not support primitive topology ${this.props.topology}`);default:}let r={vertex:e,fragment:t,primitive:{topology:this.props.topology},layout:"auto"};return ie(r,this.props.parameters),r}};var se=p(s(),1),L=class extends se.ComputePipeline{device;handle;constructor(e,t){super(e,t),this.device=e;let r=this.props.cs;this.handle=this.props.handle||this.device.handle.createComputePipeline({label:this.props.id,compute:{module:r.handle,entryPoint:this.props.csEntryPoint},layout:"auto"})}_getBindGroupLayout(){return this.handle.getBindGroupLayout(0)}};var P=p(s(),1),F=class extends P.RenderPass{device;handle;pipeline=null;constructor(e,t={}){super(e,t),this.device=e;let r=t.framebuffer||e.canvasContext.getCurrentFramebuffer(),n=this.getRenderPassDescriptor(r),o=t.timestampQuerySet;if(o&&(n.occlusionQuerySet=o.handle),e.features.has("timestamp-query")){let a=t.timestampQuerySet;n.timestampWrites=a?{querySet:a.handle,beginningOfPassWriteIndex:t.beginTimestampIndex,endOfPassWriteIndex:t.endTimestampIndex}:void 0}this.handle=this.props.handle||e.commandEncoder.beginRenderPass(n),this.handle.label=this.props.id,P.log.groupCollapsed(3,`new WebGPURenderPass(${this.id})`)(),P.log.probe(3,JSON.stringify(n,null,2))(),P.log.groupEnd(3)()}destroy(){}end(){this.handle.end()}setPipeline(e){this.pipeline=(0,P.cast)(e),this.handle.setPipeline(this.pipeline.handle)}setBindings(e){this.pipeline?.setBindings(e);let t=this.pipeline?._getBindGroup();t&&this.handle.setBindGroup(0,t)}setIndexBuffer(e,t,r=0,n){this.handle.setIndexBuffer((0,P.cast)(e).handle,t,r,n)}setVertexBuffer(e,t,r=0){this.handle.setVertexBuffer(e,(0,P.cast)(t).handle,r)}draw(e){e.indexCount?this.handle.drawIndexed(e.indexCount,e.instanceCount,e.firstIndex,e.baseVertex,e.firstInstance):this.handle.draw(e.vertexCount||0,e.instanceCount||1,e.firstIndex,e.firstInstance)}drawIndirect(){}setParameters(e){let{blendConstant:t,stencilReference:r,scissorRect:n,viewport:o}=e;t&&this.handle.setBlendConstant(t),r&&this.handle.setStencilReference(r),n&&this.handle.setScissorRect(n[0],n[1],n[2],n[3]),o&&this.handle.setViewport(o[0],o[1],o[2],o[3],o[4],o[5])}pushDebugGroup(e){this.handle.pushDebugGroup(e)}popDebugGroup(){this.handle.popDebugGroup()}insertDebugMarker(e){this.handle.insertDebugMarker(e)}beginOcclusionQuery(e){this.handle.beginOcclusionQuery(e)}endOcclusionQuery(){this.handle.endOcclusionQuery()}getRenderPassDescriptor(e){let t={colorAttachments:[]};if(t.colorAttachments=e.colorAttachments.map(r=>({loadOp:this.props.clearColor!==!1?"clear":"load",colorClearValue:this.props.clearColor||[0,0,0,0],storeOp:this.props.discard?"discard":"store",view:r.handle})),e.depthStencilAttachment){t.depthStencilAttachment={view:e.depthStencilAttachment.handle};let{depthStencilAttachment:r}=t;this.props.depthReadOnly&&(r.depthReadOnly=!0),r.depthClearValue=this.props.clearDepth||0,!0&&(r.depthLoadOp=this.props.clearDepth!==!1?"clear":"load",r.depthStoreOp="store"),!1&&(r.stencilLoadOp=this.props.clearStencil!==!1?"clear":"load",r.stencilStoreOp="store")}return t}};var de=p(s(),1),I=class extends de.ComputePass{device;handle;_bindGroupLayout=null;constructor(e,t){super(e,t),this.device=e;let r;if(e.features.has("timestamp-query")){let n=t.timestampQuerySet;n&&(r={querySet:n.handle,beginningOfPassWriteIndex:t.beginTimestampIndex,endOfPassWriteIndex:t.endTimestampIndex})}this.handle=this.props.handle||e.commandEncoder?.beginComputePass({label:this.props.id,timestampWrites:r})}destroy(){}end(){this.handle.end()}setPipeline(e){let t=e;this.handle.setPipeline(t.handle),this._bindGroupLayout=t._getBindGroupLayout()}setBindings(e){throw new Error("fix me")}dispatch(e,t,r){this.handle.dispatchWorkgroups(e,t,r)}dispatchIndirect(e,t=0){let r=e;this.handle.dispatchWorkgroupsIndirect(r.handle,t)}pushDebugGroup(e){this.handle.pushDebugGroup(e)}popDebugGroup(){this.handle.popDebugGroup()}insertDebugMarker(e){this.handle.insertDebugMarker(e)}};var W=p(s(),1);function S(i){if(typeof window<"u"&&typeof window.process=="object"&&window.process.type==="renderer"||typeof process<"u"&&typeof process.versions=="object"&&Boolean(process.versions.electron))return!0;let e=typeof navigator=="object"&&typeof navigator.userAgent=="string"&&navigator.userAgent,t=i||e;return!!(t&&t.indexOf("Electron")>=0)}function N(){return!(typeof process=="object"&&String(process)==="[object process]"&&!process.browser)||S()}var xt=globalThis.self||globalThis.window||globalThis.global,Gt=globalThis.window||globalThis.self||globalThis.global,Ut=globalThis.document||{},wt=globalThis.process||{},St=globalThis.console,pe=globalThis.navigator||{};var j=globalThis;function V(i){if(!i&&!N())return"Node";if(S(i))return"Electron";let e=i||pe.userAgent||"";if(e.indexOf("Edge")>-1)return"Edge";let t=e.indexOf("MSIE ")!==-1,r=e.indexOf("Trident/")!==-1;return t||r?"IE":j.chrome?"Chrome":j.safari?"Safari":j.mozInnerScreenX?"Firefox":"Unknown"}var k=class extends W.VertexArray{get[Symbol.toStringTag](){return"WebGPUVertexArray"}device;handle;constructor(e,t){super(e,t),this.device=e}destroy(){}setIndexBuffer(e){this.indexBuffer=e}setBuffer(e,t){this.attributes[e]=t}bindBeforeRender(e,t,r){let n=e,o=this.indexBuffer;o?.handle&&(W.log.warn("setting index buffer",o?.handle,o?.indexType)(),n.handle.setIndexBuffer(o?.handle,o?.indexType));for(let a=0;a<this.maxVertexAttributes;a++){let u=this.attributes[a];u?.handle&&(W.log.warn(`setting vertex buffer ${a}`,u?.handle)(),n.handle.setVertexBuffer(a,u?.handle))}}unbindAfterRender(e){}static isConstantAttributeZeroSupported(e){return V()==="Chrome"}};var _=p(s(),1);var ue=p(s(),1),M=class extends ue.Framebuffer{device;constructor(e,t){super(e,t),this.device=e,this.autoCreateAttachmentTextures()}};var C=class extends _.CanvasContext{device;gpuCanvasContext;format=navigator.gpu.getPreferredCanvasFormat();depthStencilFormat="depth24plus";depthStencilAttachment=null;constructor(e,t,r){super(r),this.device=e,this.width=-1,this.height=-1,this._setAutoCreatedCanvasId(`${this.device.id}-canvas`),this.gpuCanvasContext=this.canvas.getContext("webgpu"),this.format="bgra8unorm"}destroy(){this.gpuCanvasContext.unconfigure()}getCurrentFramebuffer(){this.update();let e=this.getCurrentTexture();return this.width=e.width,this.height=e.height,this._createDepthStencilAttachment(),new M(this.device,{colorAttachments:[e],depthStencilAttachment:this.depthStencilAttachment})}update(){let[e,t]=this.getPixelSize();(e!==this.width||t!==this.height)&&(this.width=e,this.height=t,this.depthStencilAttachment&&(this.depthStencilAttachment.destroy(),this.depthStencilAttachment=null),this.gpuCanvasContext.configure({device:this.device.handle,format:v(this.format),colorSpace:this.props.colorSpace,alphaMode:this.props.alphaMode}),_.log.log(1,`Resized to ${this.width}x${this.height}px`)())}resize(e){this.update()}getCurrentTexture(){return this.device._createTexture({id:`${this.id}#color-texture`,handle:this.gpuCanvasContext.getCurrentTexture()})}_createDepthStencilAttachment(){return this.depthStencilAttachment||(this.depthStencilAttachment=this.device.createTexture({id:`${this.id}#depth-stencil-texture`,format:this.depthStencilFormat,width:this.width,height:this.height,usage:GPUTextureUsage.RENDER_ATTACHMENT})),this.depthStencilAttachment}};var le=p(s(),1),O=class extends le.QuerySet{device;handle;constructor(e,t){super(e,t),this.device=e,this.handle=this.props.handle||this.device.handle.createQuerySet({type:this.props.type,count:this.props.count}),this.handle.label=this.props.id}destroy(){this.handle.destroy()}};var H=class extends l.Device{handle;adapter;adapterInfo;features;info;limits;lost;canvasContext=null;_isLost=!1;commandEncoder=null;renderPass=null;static isSupported(){return Boolean(typeof navigator<"u"&&navigator.gpu)}static async create(e){if(!navigator.gpu)throw new Error("WebGPU not available. Open in Chrome Canary and turn on chrome://flags/#enable-unsafe-webgpu");l.log.groupCollapsed(1,"WebGPUDevice created")();let t=await navigator.gpu.requestAdapter({powerPreference:"high-performance"});if(!t)throw new Error("Failed to request WebGPU adapter");let r=await t.requestAdapterInfo();l.log.probe(2,"Adapter available",r)();let n=[],o={};if(e.requestMaximalLimits){n.push(...Array.from(t.features));for(let d in t.limits)o[d]=t.limits[d];delete o.minSubgroupSize,delete o.maxSubgroupSize}let a=await t.requestDevice({requiredFeatures:n,requiredLimits:o});l.log.probe(1,"GPUDevice available")(),typeof e.canvas=="string"&&(await l.CanvasContext.pageLoaded,l.log.probe(1,"DOM is loaded")());let u=new H(a,t,r,e);return l.log.probe(1,"Device created. For more info, set chrome://flags/#enable-webgpu-developer-features")(),l.log.table(1,u.info)(),l.log.groupEnd(1)(),u}constructor(e,t,r,n){super({...n,id:n.id||(0,l.uid)("webgpu-device")}),this.handle=e,this.adapter=t,this.adapterInfo=r,this.info=this._getInfo(),this.features=this._getFeatures(),this.limits=this.handle.limits,this.lost=new Promise(async o=>{let a=await this.handle.lost;this._isLost=!0,o({reason:"destroyed",message:a.message})}),this.canvasContext=new C(this,this.adapter,{canvas:n.canvas,height:n.height,width:n.width,container:n.container})}destroy(){this.handle.destroy()}isTextureFormatSupported(e){return!e.includes("webgl")}isTextureFormatFilterable(e){return this.isTextureFormatSupported(e)}isTextureFormatRenderable(e){return this.isTextureFormatSupported(e)}get isLost(){return this._isLost}createBuffer(e){let t=this._getBufferProps(e);return new b(this,t)}_createTexture(e){return new x(this,e)}createExternalTexture(e){return new R(this,e)}createShader(e){return new G(this,e)}createSampler(e){return new c(this,e)}createRenderPipeline(e){return new E(this,e)}createFramebuffer(e){throw new Error("Not implemented")}createComputePipeline(e){return new L(this,e)}createVertexArray(e){return new k(this,e)}beginRenderPass(e){return this.commandEncoder=this.commandEncoder||this.handle.createCommandEncoder(),new F(this,e)}beginComputePass(e){return this.commandEncoder=this.commandEncoder||this.handle.createCommandEncoder(),new I(this,e)}createTransformFeedback(e){throw new Error("Transform feedback not supported in WebGPU")}createQuerySet(e){return new O(this,e)}createCanvasContext(e){return new C(this,this.adapter,e)}getDefaultRenderPass(){throw new Error("a")}submit(){let e=this.commandEncoder?.finish();e&&this.handle.queue.submit([e]),this.commandEncoder=null}_getInfo(){let[e,t]=(this.adapterInfo.driver||"").split(" Version "),r=this.adapterInfo.vendor||this.adapter.__brand||"unknown",n=e||"",o=t||"",a=r==="apple"?"apple":"unknown",u=this.adapterInfo.architecture||"unknown",d=this.adapterInfo.backend||"unknown",g=(this.adapterInfo.type||"").split(" ")[0].toLowerCase()||"unknown";return{type:"webgpu",vendor:r,renderer:n,version:o,gpu:a,gpuType:g,gpuBackend:d,gpuArchitecture:u,shadingLanguage:"wgsl",shadingLanguageVersion:100}}_getFeatures(){let e=new Set(this.handle.features);e.has("depth-clamping")&&(e.delete("depth-clamping"),e.add("depth-clip-control")),e.has("texture-compression-bc")&&e.add("texture-compression-bc5-webgl");let t=["timer-query-webgl","compilation-status-async-webgl","float32-renderable-webgl","float16-renderable-webgl","norm16-renderable-webgl","texture-filterable-anisotropic-webgl","shader-noperspective-interpolation-webgl"];for(let r of t)e.add(r);return new l.DeviceFeatures(Array.from(e))}copyExternalImageToTexture(e){let{source:t,sourceX:r=0,sourceY:n=0,texture:o,mipLevel:a=0,aspect:u="all",colorSpace:d="display-p3",premultipliedAlpha:g=!1,width:y=o.width,height:Q=o.height,depth:q=1}=e,$=o;this.handle?.queue.copyExternalImageToTexture({source:t,origin:[r,n]},{texture:$.handle,origin:[0,0,0],mipLevel:a,aspect:u,colorSpace:d,premultipliedAlpha:g},[y,Q,q])}},B=H;X(B,"type","webgpu");return xe(Te);})();
7
+ var __exports__=(()=>{var ce=Object.create;var S=Object.defineProperty;var me=Object.getOwnPropertyDescriptor;var fe=Object.getOwnPropertyNames;var Pe=Object.getPrototypeOf,be=Object.prototype.hasOwnProperty;var ge=(i,e,t)=>e in i?S(i,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):i[e]=t;var ye=(i,e)=>()=>(e||i((e={exports:{}}).exports,e),e.exports),ve=(i,e)=>{for(var t in e)S(i,t,{get:e[t],enumerable:!0})},X=(i,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of fe(e))!be.call(i,n)&&n!==t&&S(i,n,{get:()=>e[n],enumerable:!(r=me(e,n))||r.enumerable});return i};var p=(i,e,t)=>(t=i!=null?ce(Pe(i)):{},X(e||!i||!i.__esModule?S(t,"default",{value:i,enumerable:!0}):t,i)),xe=i=>X(S({},"__esModule",{value:!0}),i);var J=(i,e,t)=>(ge(i,typeof e!="symbol"?e+"":e,t),t);var a=ye((Ae,Z)=>{Z.exports=globalThis.luma});var Te={};ve(Te,{WebGPUBuffer:()=>b,WebGPUDevice:()=>T,WebGPUSampler:()=>h,WebGPUShader:()=>G,WebGPUTexture:()=>x});var l=p(a(),1);var R=p(a(),1);function Ge(i){return i.byteLength||i.data?.byteLength||0}var b=class extends R.Buffer{device;handle;byteLength;constructor(e,t){super(e,t),this.device=e,this.byteLength=Ge(t);let r=Boolean(t.data),n=Math.ceil(this.byteLength/4)*4;this.handle=this.props.handle||this.device.handle.createBuffer({size:n,usage:this.props.usage||GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_DST,mappedAtCreation:this.props.mappedAtCreation||r,label:this.props.id}),t.data&&this._writeMapped(t.data),r&&!t.mappedAtCreation&&this.handle.unmap()}destroy(){this.handle?.destroy(),this.handle=null}write(e,t=0){this.device.handle.queue.writeBuffer(this.handle,t,e.buffer,e.byteOffset,e.byteLength)}async readAsync(e=0,t=this.byteLength){let r=new b(this.device,{usage:R.Buffer.MAP_READ|R.Buffer.COPY_DST,byteLength:t}),n=this.device.handle.createCommandEncoder();n.copyBufferToBuffer(this.handle,e,r.handle,0,t),this.device.handle.queue.submit([n.finish()]),await r.handle.mapAsync(GPUMapMode.READ,e,t);let o=r.handle.getMappedRange().slice(0);return r.handle.unmap(),r.destroy(),new Uint8Array(o)}_writeMapped(e){let t=this.handle.getMappedRange();new e.constructor(t).set(e)}mapAsync(e,t=0,r){return this.handle.mapAsync(e,t,r)}getMappedRange(e=0,t){return this.handle.getMappedRange(e,t)}unmap(){this.handle.unmap()}};var te=p(a(),1);function v(i){if(i.includes("webgl"))throw new Error("webgl-only format");return i}var K=p(a(),1),h=class extends K.Sampler{device;handle;constructor(e,t){super(e,t),this.device=e;let r={...this.props};r.type!=="comparison-sampler"&&delete r.compare,this.handle=this.handle||this.device.handle.createSampler(r),this.handle.label=this.props.id}destroy(){this.handle=null}};var ee=p(a(),1),W=class extends ee.TextureView{device;handle;texture;constructor(e,t){super(e,t),this.device=e,this.texture=t.texture,this.handle=this.handle||this.texture.handle.createView({format:t.format||this.texture.format,dimension:t.dimension||this.texture.dimension,aspect:t.aspect,baseMipLevel:t.baseMipLevel,mipLevelCount:t.mipLevelCount,baseArrayLayer:t.baseArrayLayer,arrayLayerCount:t.arrayLayerCount}),this.handle.label=this.props.id}destroy(){this.handle=null}};var Ue={"1d":"1d","2d":"2d","2d-array":"2d",cube:"2d","cube-array":"2d","3d":"3d"},x=class extends te.Texture{device;handle;height=1;width=1;sampler;view;constructor(e,t){if(super(e,t),this.device=e,t.data instanceof Promise){t.data.then(r=>{this.props={...t,data:r},this.initialize(this.props)});return}this.initialize(t)}destroy(){this.handle?.destroy(),this.handle=null}createView(e){return new W(this.device,{...e,texture:this})}initialize(e){this.handle=this.props.handle||this.createHandle(),this.handle.label||=this.id,this.props.data&&this.setData({data:this.props.data}),this.width=this.handle.width,this.height=this.handle.height,this.sampler=e.sampler instanceof h?e.sampler:new h(this.device,e.sampler),this.view=new W(this.device,{...this.props,texture:this})}createHandle(){let e=this.props.width||this.props.data?.width||1,t=this.props.height||this.props.data?.height||1;return this.device.handle.createTexture({label:this.id,size:{width:e,height:t,depthOrArrayLayers:this.props.depth},dimension:Ue[this.props.dimension],format:v(this.props.format),usage:this.props.usage,mipLevelCount:this.props.mipLevels,sampleCount:this.props.samples})}setSampler(e){return this.sampler=e instanceof h?e:new h(this.device,e),this}setData(e){return this.setImage({source:e.data})}setImage(e){let{source:t,width:r=e.source.width,height:n=e.source.height,depth:o=1,sourceX:s=0,sourceY:u=0,mipLevel:d=0,x:g=0,y=0,z:q=0,aspect:$="all",colorSpace:z="srgb",premultipliedAlpha:he=!1}=e;return this.device.handle.queue.copyExternalImageToTexture({source:t,origin:[s,u]},{texture:this.handle,origin:[g,y,q],mipLevel:d,aspect:$,colorSpace:z,premultipliedAlpha:he},[r,n,o]),{width:r,height:n}}};var re=p(a(),1);var A=class extends re.ExternalTexture{device;handle;sampler;constructor(e,t){super(e,t),this.device=e,this.handle=this.props.handle||this.device.handle.importExternalTexture({source:t.source,colorSpace:t.colorSpace}),this.sampler=null}destroy(){this.handle=null}setSampler(e){return this.sampler=e instanceof h?e:new h(this.device,e),this}};var E=p(a(),1),G=class extends E.Shader{device;handle;constructor(e,t){super(e,t),this.device=e,this.device.handle.pushErrorScope("validation"),this.handle=this.props.handle||this.createHandle(),this.handle.label=this.props.id,this._checkCompilationError(this.device.handle.popErrorScope())}async _checkCompilationError(e){let t=await e;if(t){this.debugShader();let r=await this.getCompilationInfo();throw E.log.error(`Shader compilation error: ${t.message}`,r)(),new Error(`Shader compilation error: ${t.message}`)}}destroy(){this.handle=null}async getCompilationInfo(){return(await this.handle.getCompilationInfo()).messages}createHandle(){let{source:e}=this.props,t=e.includes("#version");if(this.props.language==="glsl"||t)throw new Error("GLSL shaders are not supported in WebGPU");return this.device.handle.createShaderModule({code:e})}};var f=p(a(),1);function c(i){return i.depthStencil=i.depthStencil||{format:"depth24plus",stencilFront:{},stencilBack:{},depthWriteEnabled:!1,depthCompare:"less-equal"},i.depthStencil}var we={cullMode:(i,e,t)=>{t.primitive=t.primitive||{},t.primitive.cullMode=e},frontFace:(i,e,t)=>{t.primitive=t.primitive||{},t.primitive.frontFace=e},depthWriteEnabled:(i,e,t)=>{let r=c(t);r.depthWriteEnabled=e},depthCompare:(i,e,t)=>{let r=c(t);r.depthCompare=e},depthFormat:(i,e,t)=>{let r=c(t);r.format=e},depthBias:(i,e,t)=>{let r=c(t);r.depthBias=e},depthBiasSlopeScale:(i,e,t)=>{let r=c(t);r.depthBiasSlopeScale=e},depthBiasClamp:(i,e,t)=>{let r=c(t);r.depthBiasClamp=e},stencilReadMask:(i,e,t)=>{let r=c(t);r.stencilReadMask=e},stencilWriteMask:(i,e,t)=>{let r=c(t);r.stencilWriteMask=e},stencilCompare:(i,e,t)=>{let r=c(t);r.stencilFront.compare=e,r.stencilBack.compare=e},stencilPassOperation:(i,e,t)=>{let r=c(t);r.stencilFront.passOp=e,r.stencilBack.passOp=e},stencilFailOperation:(i,e,t)=>{let r=c(t);r.stencilFront.failOp=e,r.stencilBack.failOp=e},stencilDepthFailOperation:(i,e,t)=>{let r=c(t);r.stencilFront.depthFailOp=e,r.stencilBack.depthFailOp=e},sampleCount:(i,e,t)=>{t.multisample=t.multisample||{},t.multisample.count=e},sampleMask:(i,e,t)=>{t.multisample=t.multisample||{},t.multisample.mask=e},sampleAlphaToCoverageEnabled:(i,e,t)=>{t.multisample=t.multisample||{},t.multisample.alphaToCoverageEnabled=e},colorMask:(i,e,t)=>{let r=ie(t);r[0].writeMask=e},blendColorOperation:(i,e,t)=>{ie(t)}},Se={primitive:{cullMode:"back",topology:"triangle-list"},vertex:{module:void 0,entryPoint:"main"},fragment:{module:void 0,entryPoint:"main",targets:[]},layout:"auto"};function ne(i,e={}){Object.assign(i,{...Se,...i}),We(i,e)}function We(i,e){for(let[t,r]of Object.entries(e)){let n=we[t];if(!n)throw new Error(`Illegal parameter ${t}`);n(t,r,i)}}function ie(i){if(i.fragment.targets=i.fragment?.targets||[],!Array.isArray(i.fragment?.targets))throw new Error("colorstate");return i.fragment?.targets?.length===0&&i.fragment.targets?.push({}),i.fragment?.targets}var m=p(a(),1);function L(i,e,t,r){let n=Ce(r,t);return i.createBindGroup({layout:e,entries:n})}function Be(i,e){let t=i.bindings.find(r=>r.name===e||`${r.name}uniforms`===e.toLocaleLowerCase());return t||m.log.warn(`Binding ${e} not set: Not found in shader layout.`)(),t}function Ce(i,e){let t=[];for(let[r,n]of Object.entries(i)){let o=Be(e,r);o&&t.push(De(n,o.location))}return t}function De(i,e){if(i instanceof m.Buffer)return{binding:e,resource:{buffer:(0,m.cast)(i).handle}};if(i instanceof m.Sampler)return{binding:e,resource:(0,m.cast)(i).handle};if(i instanceof m.Texture)return{binding:e,resource:(0,m.cast)(i).handle.createView({label:"bind-group-auto-created"})};throw new Error("invalid binding")}var U=p(a(),1);function N(i){if(i.endsWith("-webgl"))throw new Error(`WebGPU does not support vertex format ${i}`);return i}function se(i,e){let t=[],r=new Set;for(let n of e){let o=[],s="vertex",u=0;if(n.attributes)for(let d of n.attributes){let g=d.attribute,y=oe(i,g,r);s=y.stepMode||(y.name.startsWith("instance")?"instance":"vertex"),o.push({format:N(d.format||n.format),offset:d.byteOffset,shaderLocation:y.location}),u+=(0,U.decodeVertexFormat)(n.format).byteLength}else{let d=oe(i,n.name,r);if(!d)continue;u=(0,U.decodeVertexFormat)(n.format).byteLength,s=d.stepMode||(d.name.startsWith("instance")?"instance":"vertex"),o.push({format:N(n.format),offset:0,shaderLocation:d.location})}t.push({arrayStride:n.byteStride||u,stepMode:s,attributes:o})}for(let n of i.attributes)r.has(n.name)||t.push({arrayStride:(0,U.decodeVertexFormat)("float32x3").byteLength,stepMode:n.stepMode||(n.name.startsWith("instance")?"instance":"vertex"),attributes:[{format:N("float32x3"),offset:0,shaderLocation:n.location}]});return t}function oe(i,e,t){let r=i.attributes.find(n=>n.name===e);if(!r)return U.log.warn(`Unknown attribute ${e}`)(),null;if(t.has(e))throw new Error(`Duplicate attribute ${e}`);return t.add(e),r}var F=class extends f.RenderPipeline{device;handle;vs;fs=null;_bindings;_bindGroupLayout=null;_bindGroup=null;constructor(e,t){if(super(e,t),this.device=e,this.handle=this.props.handle,!this.handle){let r=this._getRenderPipelineDescriptor();f.log.groupCollapsed(1,`new WebGPURenderPipeline(${this.id})`)(),f.log.probe(1,JSON.stringify(r,null,2))(),f.log.groupEnd(1)(),this.handle=this.device.handle.createRenderPipeline(r)}this.handle.label=this.props.id,this.vs=(0,f.cast)(t.vs),this.fs=(0,f.cast)(t.fs),this._bindings={...this.props.bindings}}destroy(){this.handle=null}setBindings(e){Object.assign(this._bindings,e)}draw(e){let t=e.renderPass;t.handle.setPipeline(this.handle);let r=this._getBindGroup();return r&&t.handle.setBindGroup(0,r),e.vertexArray.bindBeforeRender(e.renderPass),e.indexCount?t.handle.drawIndexed(e.indexCount,e.instanceCount,e.firstIndex,e.baseVertex,e.firstInstance):t.handle.draw(e.vertexCount||0,e.instanceCount||1,e.firstInstance),e.vertexArray.unbindAfterRender(e.renderPass),!0}_getBindGroup(){return this.props.shaderLayout.bindings.length===0?null:(this._bindGroupLayout=this._bindGroupLayout||this.handle.getBindGroupLayout(0),this._bindGroup=this._bindGroup||L(this.device.handle,this._bindGroupLayout,this.props.shaderLayout,this._bindings),this._bindGroup)}_getRenderPipelineDescriptor(){let e={module:(0,f.cast)(this.props.vs).handle,entryPoint:this.props.vertexEntryPoint||"main",buffers:se(this.props.shaderLayout,this.props.bufferLayout)},t={module:(0,f.cast)(this.props.fs).handle,entryPoint:this.props.fragmentEntryPoint||"main",targets:[{format:v(this.device?.canvasContext?.format)}]};switch(this.props.topology){case"triangle-fan-webgl":case"line-loop-webgl":throw new Error(`WebGPU does not support primitive topology ${this.props.topology}`);default:}let r={vertex:e,fragment:t,primitive:{topology:this.props.topology},layout:"auto"};return ne(r,this.props.parameters),r}};var ae=p(a(),1),w=class extends ae.Framebuffer{device;constructor(e,t){super(e,t),this.device=e,this.autoCreateAttachmentTextures()}};var de=p(a(),1);var I=class extends de.ComputePipeline{device;handle;_bindGroupLayout=null;_bindGroup=null;_bindings={};constructor(e,t){super(e,t),this.device=e;let r=this.props.shader;this.handle=this.props.handle||this.device.handle.createComputePipeline({label:this.props.id,compute:{module:r.handle,entryPoint:this.props.entryPoint,constants:this.props.constants},layout:"auto"})}setBindings(e){Object.assign(this._bindings,e)}_getBindGroup(){return this._bindGroupLayout=this._bindGroupLayout||this.handle.getBindGroupLayout(0),this._bindGroup=this._bindGroup||L(this.device.handle,this._bindGroupLayout,this.props.shaderLayout,this._bindings),this._bindGroup}};var P=p(a(),1),_=class extends P.RenderPass{device;handle;pipeline=null;constructor(e,t={}){super(e,t),this.device=e;let r=t.framebuffer||e.canvasContext.getCurrentFramebuffer(),n=this.getRenderPassDescriptor(r),o=t.timestampQuerySet;if(o&&(n.occlusionQuerySet=o.handle),e.features.has("timestamp-query")){let s=t.timestampQuerySet;n.timestampWrites=s?{querySet:s.handle,beginningOfPassWriteIndex:t.beginTimestampIndex,endOfPassWriteIndex:t.endTimestampIndex}:void 0}this.handle=this.props.handle||e.commandEncoder.beginRenderPass(n),this.handle.label=this.props.id,P.log.groupCollapsed(3,`new WebGPURenderPass(${this.id})`)(),P.log.probe(3,JSON.stringify(n,null,2))(),P.log.groupEnd(3)()}destroy(){}end(){this.handle.end()}setPipeline(e){this.pipeline=(0,P.cast)(e),this.handle.setPipeline(this.pipeline.handle)}setBindings(e){this.pipeline?.setBindings(e);let t=this.pipeline?._getBindGroup();t&&this.handle.setBindGroup(0,t)}setIndexBuffer(e,t,r=0,n){this.handle.setIndexBuffer((0,P.cast)(e).handle,t,r,n)}setVertexBuffer(e,t,r=0){this.handle.setVertexBuffer(e,(0,P.cast)(t).handle,r)}draw(e){e.indexCount?this.handle.drawIndexed(e.indexCount,e.instanceCount,e.firstIndex,e.baseVertex,e.firstInstance):this.handle.draw(e.vertexCount||0,e.instanceCount||1,e.firstIndex,e.firstInstance)}drawIndirect(){}setParameters(e){let{blendConstant:t,stencilReference:r,scissorRect:n,viewport:o}=e;t&&this.handle.setBlendConstant(t),r&&this.handle.setStencilReference(r),n&&this.handle.setScissorRect(n[0],n[1],n[2],n[3]),o&&this.handle.setViewport(o[0],o[1],o[2],o[3],o[4],o[5])}pushDebugGroup(e){this.handle.pushDebugGroup(e)}popDebugGroup(){this.handle.popDebugGroup()}insertDebugMarker(e){this.handle.insertDebugMarker(e)}beginOcclusionQuery(e){this.handle.beginOcclusionQuery(e)}endOcclusionQuery(){this.handle.endOcclusionQuery()}getRenderPassDescriptor(e){let t={colorAttachments:[]};if(t.colorAttachments=e.colorAttachments.map(r=>({loadOp:this.props.clearColor!==!1?"clear":"load",colorClearValue:this.props.clearColor||[0,0,0,0],storeOp:this.props.discard?"discard":"store",view:r.handle})),e.depthStencilAttachment){t.depthStencilAttachment={view:e.depthStencilAttachment.handle};let{depthStencilAttachment:r}=t;this.props.depthReadOnly&&(r.depthReadOnly=!0),r.depthClearValue=this.props.clearDepth||0,!0&&(r.depthLoadOp=this.props.clearDepth!==!1?"clear":"load",r.depthStoreOp="store"),!1&&(r.stencilLoadOp=this.props.clearStencil!==!1?"clear":"load",r.stencilStoreOp="store")}return t}};var pe=p(a(),1),V=class extends pe.ComputePass{device;handle;_webgpuPipeline=null;constructor(e,t){super(e,t),this.device=e;let r;if(e.features.has("timestamp-query")){let n=t.timestampQuerySet;n&&(r={querySet:n.handle,beginningOfPassWriteIndex:t.beginTimestampIndex,endOfPassWriteIndex:t.endTimestampIndex})}this.handle=this.props.handle||e.commandEncoder?.beginComputePass({label:this.props.id,timestampWrites:r})}destroy(){}end(){this.handle.end()}setPipeline(e){let t=e;this.handle.setPipeline(t.handle),this._webgpuPipeline=t,this.setBindings([])}setBindings(e){let t=this._webgpuPipeline._getBindGroup();this.handle.setBindGroup(0,t)}dispatch(e,t,r){this.handle.dispatchWorkgroups(e,t,r)}dispatchIndirect(e,t=0){let r=e;this.handle.dispatchWorkgroupsIndirect(r.handle,t)}pushDebugGroup(e){this.handle.pushDebugGroup(e)}popDebugGroup(){this.handle.popDebugGroup()}insertDebugMarker(e){this.handle.insertDebugMarker(e)}};var C=p(a(),1);function B(i){if(typeof window<"u"&&typeof window.process=="object"&&window.process.type==="renderer"||typeof process<"u"&&typeof process.versions=="object"&&Boolean(process.versions.electron))return!0;let e=typeof navigator=="object"&&typeof navigator.userAgent=="string"&&navigator.userAgent,t=i||e;return!!(t&&t.indexOf("Electron")>=0)}function j(){return!(typeof process=="object"&&String(process)==="[object process]"&&!process.browser)||B()}var St=globalThis.self||globalThis.window||globalThis.global,Wt=globalThis.window||globalThis.self||globalThis.global,Bt=globalThis.document||{},Ct=globalThis.process||{},Dt=globalThis.console,ue=globalThis.navigator||{};var H=globalThis;function k(i){if(!i&&!j())return"Node";if(B(i))return"Electron";let e=i||ue.userAgent||"";if(e.indexOf("Edge")>-1)return"Edge";let t=e.indexOf("MSIE ")!==-1,r=e.indexOf("Trident/")!==-1;return t||r?"IE":H.chrome?"Chrome":H.safari?"Safari":H.mozInnerScreenX?"Firefox":"Unknown"}var M=class extends C.VertexArray{get[Symbol.toStringTag](){return"WebGPUVertexArray"}device;handle;constructor(e,t){super(e,t),this.device=e}destroy(){}setIndexBuffer(e){this.indexBuffer=e}setBuffer(e,t){this.attributes[e]=t}bindBeforeRender(e,t,r){let n=e,o=this.indexBuffer;o?.handle&&(C.log.warn("setting index buffer",o?.handle,o?.indexType)(),n.handle.setIndexBuffer(o?.handle,o?.indexType));for(let s=0;s<this.maxVertexAttributes;s++){let u=this.attributes[s];u?.handle&&(C.log.warn(`setting vertex buffer ${s}`,u?.handle)(),n.handle.setVertexBuffer(s,u?.handle))}}unbindAfterRender(e){}static isConstantAttributeZeroSupported(e){return k()==="Chrome"}};var O=p(a(),1);var D=class extends O.CanvasContext{device;gpuCanvasContext;format=navigator.gpu.getPreferredCanvasFormat();depthStencilFormat="depth24plus";depthStencilAttachment=null;constructor(e,t,r){super(r),this.device=e,this.width=-1,this.height=-1,this._setAutoCreatedCanvasId(`${this.device.id}-canvas`),this.gpuCanvasContext=this.canvas.getContext("webgpu"),this.format="bgra8unorm"}destroy(){this.gpuCanvasContext.unconfigure()}getCurrentFramebuffer(){this.update();let e=this.getCurrentTexture();return this.width=e.width,this.height=e.height,this._createDepthStencilAttachment(),new w(this.device,{colorAttachments:[e],depthStencilAttachment:this.depthStencilAttachment})}update(){let[e,t]=this.getPixelSize();(e!==this.width||t!==this.height)&&(this.width=e,this.height=t,this.depthStencilAttachment&&(this.depthStencilAttachment.destroy(),this.depthStencilAttachment=null),this.gpuCanvasContext.configure({device:this.device.handle,format:v(this.format),colorSpace:this.props.colorSpace,alphaMode:this.props.alphaMode}),O.log.log(1,`Resized to ${this.width}x${this.height}px`)())}resize(e){this.update()}getCurrentTexture(){return this.device._createTexture({id:`${this.id}#color-texture`,handle:this.gpuCanvasContext.getCurrentTexture(),format:this.format})}_createDepthStencilAttachment(){return this.depthStencilAttachment||(this.depthStencilAttachment=this.device.createTexture({id:`${this.id}#depth-stencil-texture`,format:this.depthStencilFormat,width:this.width,height:this.height,usage:GPUTextureUsage.RENDER_ATTACHMENT})),this.depthStencilAttachment}};var le=p(a(),1),Q=class extends le.QuerySet{device;handle;constructor(e,t){super(e,t),this.device=e,this.handle=this.props.handle||this.device.handle.createQuerySet({type:this.props.type,count:this.props.count}),this.handle.label=this.props.id}destroy(){this.handle?.destroy(),this.handle=null}};var Y=class extends l.Device{type="webgpu";handle;adapter;adapterInfo;features;info;limits;lost;canvasContext=null;_isLost=!1;commandEncoder=null;renderPass=null;static isSupported(){return Boolean(typeof navigator<"u"&&navigator.gpu)}static async create(e){if(!navigator.gpu)throw new Error("WebGPU not available. Open in Chrome Canary and turn on chrome://flags/#enable-unsafe-webgpu");l.log.groupCollapsed(1,"WebGPUDevice created")();let t=await navigator.gpu.requestAdapter({powerPreference:"high-performance"});if(!t)throw new Error("Failed to request WebGPU adapter");let r=await t.requestAdapterInfo();l.log.probe(2,"Adapter available",r)();let n=[],o={};if(e.requestMaxLimits){n.push(...Array.from(t.features));for(let d in t.limits)o[d]=t.limits[d];delete o.minSubgroupSize,delete o.maxSubgroupSize}let s=await t.requestDevice({requiredFeatures:n,requiredLimits:o});l.log.probe(1,"GPUDevice available")(),typeof e.canvas=="string"&&(await l.CanvasContext.pageLoaded,l.log.probe(1,"DOM is loaded")());let u=new Y(s,t,r,e);return l.log.probe(1,"Device created. For more info, set chrome://flags/#enable-webgpu-developer-features")(),l.log.table(1,u.info)(),l.log.groupEnd(1)(),u}constructor(e,t,r,n){super({...n,id:n.id||(0,l.uid)("webgpu-device")}),this.handle=e,this.adapter=t,this.adapterInfo=r,this.info=this._getInfo(),this.features=this._getFeatures(),this.limits=this.handle.limits,this.lost=new Promise(async o=>{let s=await this.handle.lost;this._isLost=!0,o({reason:"destroyed",message:s.message})}),this.canvasContext=new D(this,this.adapter,{canvas:n.canvas,height:n.height,width:n.width,container:n.container})}destroy(){this.handle.destroy()}isTextureFormatSupported(e){return!e.includes("webgl")}isTextureFormatFilterable(e){return this.isTextureFormatSupported(e)&&!e.startsWith("depth")&&!e.startsWith("stencil")}isTextureFormatRenderable(e){return this.isTextureFormatSupported(e)}get isLost(){return this._isLost}createBuffer(e){let t=this._getBufferProps(e);return new b(this,t)}_createTexture(e){return new x(this,e)}createExternalTexture(e){return new A(this,e)}createShader(e){return new G(this,e)}createSampler(e){return new h(this,e)}createRenderPipeline(e){return new F(this,e)}createFramebuffer(e){return new w(this,e)}createComputePipeline(e){return new I(this,e)}createVertexArray(e){return new M(this,e)}beginRenderPass(e){return this.commandEncoder=this.commandEncoder||this.handle.createCommandEncoder(),new _(this,e)}beginComputePass(e){return this.commandEncoder=this.commandEncoder||this.handle.createCommandEncoder(),new V(this,e)}createTransformFeedback(e){throw new Error("Transform feedback not supported in WebGPU")}createQuerySet(e){return new Q(this,e)}createCanvasContext(e){return new D(this,this.adapter,e)}submit(){let e=this.commandEncoder?.finish();e&&this.handle.queue.submit([e]),this.commandEncoder=null}_getInfo(){let[e,t]=(this.adapterInfo.driver||"").split(" Version "),r=this.adapterInfo.vendor||this.adapter.__brand||"unknown",n=e||"",o=t||"",s=r==="apple"?"apple":"unknown",u=this.adapterInfo.architecture||"unknown",d=this.adapterInfo.backend||"unknown",g=(this.adapterInfo.type||"").split(" ")[0].toLowerCase()||"unknown";return{type:"webgpu",vendor:r,renderer:n,version:o,gpu:s,gpuType:g,gpuBackend:d,gpuArchitecture:u,shadingLanguage:"wgsl",shadingLanguageVersion:100}}_getFeatures(){let e=new Set(this.handle.features);e.has("depth-clamping")&&(e.delete("depth-clamping"),e.add("depth-clip-control")),e.has("texture-compression-bc")&&e.add("texture-compression-bc5-webgl");let t=["timer-query-webgl","compilation-status-async-webgl","float32-renderable-webgl","float16-renderable-webgl","norm16-renderable-webgl","texture-filterable-anisotropic-webgl","shader-noperspective-interpolation-webgl"];for(let r of t)e.add(r);return new l.DeviceFeatures(Array.from(e),this.props.disabledFeatures)}copyExternalImageToTexture(e){let{source:t,sourceX:r=0,sourceY:n=0,texture:o,mipLevel:s=0,aspect:u="all",colorSpace:d="display-p3",premultipliedAlpha:g=!1,width:y=o.width,height:q=o.height,depth:$=1}=e,z=o;this.handle?.queue.copyExternalImageToTexture({source:t,origin:[r,n]},{texture:z.handle,origin:[0,0,0],mipLevel:s,aspect:u,colorSpace:d,premultipliedAlpha:g},[y,q,$])}},T=Y;J(T,"type","webgpu");return xe(Te);})();
8
8
  return __exports__;
9
9
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luma.gl/webgpu",
3
- "version": "9.0.0-beta.6",
3
+ "version": "9.0.0-beta.7",
4
4
  "description": "WebGPU adapter for the luma.gl core API",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -43,5 +43,5 @@
43
43
  "@probe.gl/env": "^4.0.2",
44
44
  "@webgpu/types": "^0.1.34"
45
45
  },
46
- "gitHead": "cb2f0938d03a65e3588622ac99650b14a10488b6"
46
+ "gitHead": "e9606a88e0aab3dc27c87020cac89040ea1a8a02"
47
47
  }
@@ -2,7 +2,7 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
- import type {ShaderLayout, BindingDeclaration, Binding} from '@luma.gl/core';
5
+ import type {ComputeShaderLayout, BindingDeclaration, Binding} from '@luma.gl/core';
6
6
  import {Buffer, Sampler, Texture, log, cast} from '@luma.gl/core';
7
7
  import type {WebGPUBuffer} from '../resources/webgpu-buffer';
8
8
  import type {WebGPUSampler} from '../resources/webgpu-sampler';
@@ -30,7 +30,7 @@ export function makeBindGroupLayout(
30
30
  export function getBindGroup(
31
31
  device: GPUDevice,
32
32
  bindGroupLayout: GPUBindGroupLayout,
33
- shaderLayout: ShaderLayout,
33
+ shaderLayout: ComputeShaderLayout,
34
34
  bindings: Record<string, Binding>
35
35
  ): GPUBindGroup {
36
36
  const entries = getBindGroupEntries(bindings, shaderLayout);
@@ -41,7 +41,7 @@ export function getBindGroup(
41
41
  }
42
42
 
43
43
  export function getShaderLayoutBinding(
44
- shaderLayout: ShaderLayout,
44
+ shaderLayout: ComputeShaderLayout,
45
45
  bindingName: string
46
46
  ): BindingDeclaration {
47
47
  const bindingLayout = shaderLayout.bindings.find(
@@ -60,7 +60,7 @@ export function getShaderLayoutBinding(
60
60
  */
61
61
  function getBindGroupEntries(
62
62
  bindings: Record<string, Binding>,
63
- shaderLayout: ShaderLayout
63
+ shaderLayout: ComputeShaderLayout
64
64
  ): GPUBindGroupEntry[] {
65
65
  const entries: GPUBindGroupEntry[] = [];
66
66
 
@@ -45,7 +45,9 @@ export class WebGPUBuffer extends Buffer {
45
45
  }
46
46
 
47
47
  override destroy(): void {
48
- this.handle.destroy();
48
+ this.handle?.destroy();
49
+ // @ts-expect-error readonly
50
+ this.handle = null;
49
51
  }
50
52
 
51
53
  // WebGPU provides multiple ways to write a buffer...
@@ -5,14 +5,14 @@
5
5
  import {ComputePass, ComputePassProps, ComputePipeline, Buffer, Binding} from '@luma.gl/core';
6
6
  import {WebGPUDevice} from '../webgpu-device';
7
7
  import {WebGPUBuffer} from './webgpu-buffer';
8
- // import {WebGPUCommandEncoder} from './webgpu-command-encoder';
9
8
  import {WebGPUComputePipeline} from './webgpu-compute-pipeline';
10
9
  import {WebGPUQuerySet} from './webgpu-query-set';
11
10
 
12
11
  export class WebGPUComputePass extends ComputePass {
13
12
  readonly device: WebGPUDevice;
14
13
  readonly handle: GPUComputePassEncoder;
15
- _bindGroupLayout: GPUBindGroupLayout | null = null;
14
+
15
+ _webgpuPipeline: WebGPUComputePipeline | null = null;
16
16
 
17
17
  constructor(device: WebGPUDevice, props: ComputePassProps) {
18
18
  super(device, props);
@@ -49,21 +49,24 @@ export class WebGPUComputePass extends ComputePass {
49
49
  setPipeline(pipeline: ComputePipeline): void {
50
50
  const wgpuPipeline = pipeline as WebGPUComputePipeline;
51
51
  this.handle.setPipeline(wgpuPipeline.handle);
52
- this._bindGroupLayout = wgpuPipeline._getBindGroupLayout();
52
+ this._webgpuPipeline = wgpuPipeline;
53
+ this.setBindings([]);
53
54
  }
54
55
 
55
- /** Sets an array of bindings (uniform buffers, samplers, textures, ...) */
56
+ /**
57
+ * Sets an array of bindings (uniform buffers, samplers, textures, ...)
58
+ * TODO - still some API confusion - does this method go here or on the pipeline?
59
+ */
56
60
  setBindings(bindings: Binding[]): void {
57
- throw new Error('fix me');
58
- // const bindGroup = getBindGroup(this.device.handle, this._bindGroupLayout, this.props.bindings);
59
- // this.handle.setBindGroup(0, bindGroup);
61
+ const bindGroup = this._webgpuPipeline._getBindGroup();
62
+ this.handle.setBindGroup(0, bindGroup);
60
63
  }
61
64
 
62
65
  /**
63
66
  * Dispatch work to be performed with the current ComputePipeline.
64
- * @param x X dimension of the grid of workgroups to dispatch.
65
- * @param y Y dimension of the grid of workgroups to dispatch.
66
- * @param z Z dimension of the grid of workgroups to dispatch.
67
+ * @param x X dimension of the grid of work groups to dispatch.
68
+ * @param y Y dimension of the grid of work groups to dispatch.
69
+ * @param z Z dimension of the grid of work groups to dispatch.
67
70
  */
68
71
  dispatch(x: number, y?: number, z?: number): void {
69
72
  this.handle.dispatchWorkgroups(x, y, z);
@@ -71,12 +74,14 @@ export class WebGPUComputePass extends ComputePass {
71
74
 
72
75
  /**
73
76
  * Dispatch work to be performed with the current ComputePipeline.
74
- * @param indirectBuffer buffer must be a tightly packed block of three 32-bit unsigned integer values (12 bytes total), given in the same order as the arguments for dispatch()
75
- * @param indirectOffset
77
+ *
78
+ * Buffer must be a tightly packed block of three 32-bit unsigned integer values (12 bytes total), given in the same order as the arguments for dispatch()
79
+ * @param indirectBuffer
80
+ * @param indirectOffset offset in buffer to the beginning of the dispatch data.
76
81
  */
77
- dispatchIndirect(indirectBuffer: Buffer, indirectOffset: number = 0): void {
82
+ dispatchIndirect(indirectBuffer: Buffer, indirectByteOffset: number = 0): void {
78
83
  const webgpuBuffer = indirectBuffer as WebGPUBuffer;
79
- this.handle.dispatchWorkgroupsIndirect(webgpuBuffer.handle, indirectOffset);
84
+ this.handle.dispatchWorkgroupsIndirect(webgpuBuffer.handle, indirectByteOffset);
80
85
  }
81
86
 
82
87
  pushDebugGroup(groupLabel: string): void {
@@ -2,8 +2,8 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
- import {ComputePipeline, ComputePipelineProps} from '@luma.gl/core';
6
-
5
+ import {ComputePipeline, ComputePipelineProps, Binding} from '@luma.gl/core';
6
+ import {getBindGroup} from '../helpers/get-bind-group';
7
7
  import {WebGPUDevice} from '../webgpu-device';
8
8
  import {WebGPUShader} from './webgpu-shader';
9
9
 
@@ -14,27 +14,54 @@ export class WebGPUComputePipeline extends ComputePipeline {
14
14
  device: WebGPUDevice;
15
15
  handle: GPUComputePipeline;
16
16
 
17
+ /** For internal use to create BindGroups */
18
+ private _bindGroupLayout: GPUBindGroupLayout | null = null;
19
+ private _bindGroup: GPUBindGroup | null = null;
20
+ /** For internal use to create BindGroups */
21
+ private _bindings: Record<string, Binding> = {};
22
+
17
23
  constructor(device: WebGPUDevice, props: ComputePipelineProps) {
18
24
  super(device, props);
19
25
  this.device = device;
20
26
 
21
- const webgpuShader = this.props.cs as WebGPUShader;
27
+ const webgpuShader = this.props.shader as WebGPUShader;
28
+
22
29
  this.handle =
23
30
  this.props.handle ||
24
31
  this.device.handle.createComputePipeline({
25
32
  label: this.props.id,
26
33
  compute: {
27
34
  module: webgpuShader.handle,
28
- entryPoint: this.props.csEntryPoint
29
- // constants: this.props.csConstants
35
+ entryPoint: this.props.entryPoint,
36
+ constants: this.props.constants
30
37
  },
31
38
  layout: 'auto'
32
39
  });
33
40
  }
34
41
 
35
- /** For internal use in render passes */
36
- _getBindGroupLayout() {
37
- // TODO: Cache?
38
- return this.handle.getBindGroupLayout(0);
42
+ /**
43
+ * @todo Use renderpass.setBindings() ?
44
+ * @todo Do we want to expose BindGroups in the API and remove this?
45
+ */
46
+ setBindings(bindings: Record<string, Binding>): void {
47
+ Object.assign(this._bindings, bindings);
48
+ }
49
+
50
+ /** Return a bind group created by setBindings */
51
+ _getBindGroup() {
52
+ // Get hold of the bind group layout. We don't want to do this unless we know there is at least one bind group
53
+ this._bindGroupLayout = this._bindGroupLayout || this.handle.getBindGroupLayout(0);
54
+
55
+ // Set up the bindings
56
+ this._bindGroup =
57
+ this._bindGroup ||
58
+ getBindGroup(
59
+ this.device.handle,
60
+ this._bindGroupLayout,
61
+ this.props.shaderLayout,
62
+ this._bindings
63
+ );
64
+
65
+ return this._bindGroup;
39
66
  }
40
67
  }
@@ -31,6 +31,8 @@ export class WebGPUExternalTexture extends ExternalTexture {
31
31
  // External textures are destroyed automatically,
32
32
  // as a microtask, instead of manually or upon garbage collection like other resources.
33
33
  // this.handle.destroy();
34
+ // @ts-expect-error readonly
35
+ this.handle = null;
34
36
  }
35
37
 
36
38
  /** Set default sampler */
@@ -30,6 +30,8 @@ export class WebGPUQuerySet extends QuerySet {
30
30
  }
31
31
 
32
32
  override destroy(): void {
33
- this.handle.destroy();
33
+ this.handle?.destroy();
34
+ // @ts-expect-error readonly
35
+ this.handle = null;
34
36
  }
35
37
  }
@@ -25,12 +25,8 @@ export class WebGPURenderPipeline extends RenderPipeline {
25
25
  vs: WebGPUShader;
26
26
  fs: WebGPUShader | null = null;
27
27
 
28
- // private _bufferSlots: Record<string, number>;
29
- // private _buffers: Buffer[];
30
- // private _firstIndex: number;
31
- // private _lastIndex: number;
32
-
33
28
  /** For internal use to create BindGroups */
29
+ private _bindings: Record<string, Binding>;
34
30
  private _bindGroupLayout: GPUBindGroupLayout | null = null;
35
31
  private _bindGroup: GPUBindGroup | null = null;
36
32
 
@@ -50,46 +46,23 @@ export class WebGPURenderPipeline extends RenderPipeline {
50
46
  this.vs = cast<WebGPUShader>(props.vs);
51
47
  this.fs = cast<WebGPUShader>(props.fs);
52
48
 
53
- // this._bufferSlots = getBufferSlots(this.props.shaderLayout, this.props.bufferLayout);
54
- // this._buffers = new Array<Buffer>(Object.keys(this._bufferSlots).length).fill(null);
49
+ this._bindings = {...this.props.bindings};
55
50
  }
56
51
 
57
52
  override destroy(): void {
58
53
  // WebGPURenderPipeline has no destroy method.
54
+ this.handle = null;
59
55
  }
60
56
 
61
- // setIndexBuffer(indexBuffer: Buffer): void {
62
- // this._indexBuffer = cast<WebGPUBuffer>(indexBuffer);
63
- // }
64
-
65
- // setAttributes(attributes: Record<string, Buffer>): void {
66
- // for (const [name, buffer] of Object.entries(attributes)) {
67
- // const bufferIndex = this._bufferSlots[name];
68
- // if (bufferIndex >= 0) {
69
- // this._buffers[bufferIndex] = buffer;
70
- // } else {
71
- // throw new Error(
72
- // `Setting attribute '${name}' not listed in shader layout for program ${this.id}`
73
- // );
74
- // }
75
- // }
76
- // // for (let i = 0; i < this._bufferSlots.length; ++i) {
77
- // // const bufferName = this._bufferSlots[i];
78
- // // if (attributes[bufferName]) {
79
- // // this.handle
80
- // // }
81
- // // }
82
- // }
83
-
57
+ /**
58
+ * @todo Use renderpass.setBindings() ?
59
+ * @todo Do we want to expose BindGroups in the API and remove this?
60
+ */
84
61
  setBindings(bindings: Record<string, Binding>): void {
85
- // if (isObjectEmpty(bindings)) {
86
- // return;
87
- // }
88
-
89
- // Do we want to save things on CPU side?
90
- Object.assign(this.props.bindings, bindings);
62
+ Object.assign(this._bindings, bindings);
91
63
  }
92
64
 
65
+ /** @todo - should this be moved to renderpass? */
93
66
  draw(options: {
94
67
  renderPass: RenderPass;
95
68
  vertexArray: VertexArray;
@@ -100,9 +73,8 @@ export class WebGPURenderPipeline extends RenderPipeline {
100
73
  firstIndex?: number;
101
74
  firstInstance?: number;
102
75
  baseVertex?: number;
103
- }): void {
104
- const webgpuRenderPass: WebGPURenderPass =
105
- cast<WebGPURenderPass>(options.renderPass) || this.device.getDefaultRenderPass();
76
+ }): boolean {
77
+ const webgpuRenderPass = options.renderPass as WebGPURenderPass;
106
78
 
107
79
  // Set pipeline
108
80
  webgpuRenderPass.handle.setPipeline(this.handle);
@@ -136,25 +108,28 @@ export class WebGPURenderPipeline extends RenderPipeline {
136
108
 
137
109
  // Note: Rebinds constant attributes before each draw call
138
110
  options.vertexArray.unbindAfterRender(options.renderPass);
139
- }
140
111
 
141
- // _getBuffers() {
142
- // return this._buffers;
143
- // }
112
+ return true;
113
+ }
144
114
 
145
115
  /** Return a bind group created by setBindings */
146
116
  _getBindGroup() {
117
+ if (this.props.shaderLayout.bindings.length === 0) {
118
+ return null;
119
+ }
120
+
147
121
  // Get hold of the bind group layout. We don't want to do this unless we know there is at least one bind group
148
122
  this._bindGroupLayout = this._bindGroupLayout || this.handle.getBindGroupLayout(0);
149
123
 
150
124
  // Set up the bindings
125
+ // TODO what if bindings change? We need to rebuild the bind group!
151
126
  this._bindGroup =
152
127
  this._bindGroup ||
153
128
  getBindGroup(
154
129
  this.device.handle,
155
130
  this._bindGroupLayout,
156
131
  this.props.shaderLayout,
157
- this.props.bindings
132
+ this._bindings
158
133
  );
159
134
 
160
135
  return this._bindGroup;
@@ -167,24 +142,21 @@ export class WebGPURenderPipeline extends RenderPipeline {
167
142
  // Set up the vertex stage
168
143
  const vertex: GPUVertexState = {
169
144
  module: cast<WebGPUShader>(this.props.vs).handle,
170
- entryPoint: this.props.vsEntryPoint || 'main',
145
+ entryPoint: this.props.vertexEntryPoint || 'main',
171
146
  buffers: getVertexBufferLayout(this.props.shaderLayout, this.props.bufferLayout)
172
147
  };
173
148
 
174
149
  // Set up the fragment stage
175
- let fragment: GPUFragmentState | undefined;
176
- if (this.props.fs) {
177
- fragment = {
178
- module: cast<WebGPUShader>(this.props.fs).handle,
179
- entryPoint: this.props.fsEntryPoint || 'main',
180
- targets: [
181
- {
182
- // TODO exclamation mark hack!
183
- format: getWebGPUTextureFormat(this.device?.canvasContext?.format)
184
- }
185
- ]
186
- };
187
- }
150
+ const fragment: GPUFragmentState = {
151
+ module: cast<WebGPUShader>(this.props.fs).handle,
152
+ entryPoint: this.props.fragmentEntryPoint || 'main',
153
+ targets: [
154
+ {
155
+ // TODO exclamation mark hack!
156
+ format: getWebGPUTextureFormat(this.device?.canvasContext?.format)
157
+ }
158
+ ]
159
+ };
188
160
 
189
161
  // WebGPU has more restrictive topology support than WebGL
190
162
  switch (this.props.topology) {
@@ -209,47 +181,46 @@ export class WebGPURenderPipeline extends RenderPipeline {
209
181
 
210
182
  return descriptor;
211
183
  }
184
+ }
185
+ /**
186
+ _setAttributeBuffers(webgpuRenderPass: WebGPURenderPass) {
187
+ if (this._indexBuffer) {
188
+ webgpuRenderPass.handle.setIndexBuffer(this._indexBuffer.handle, this._indexBuffer.props.indexType);
189
+ }
212
190
 
213
- /**
214
- _setAttributeBuffers(webgpuRenderPass: WebGPURenderPass) {
215
- if (this._indexBuffer) {
216
- webgpuRenderPass.handle.setIndexBuffer(this._indexBuffer.handle, this._indexBuffer.props.indexType);
191
+ const buffers = this._getBuffers();
192
+ for (let i = 0; i < buffers.length; ++i) {
193
+ const buffer = cast<WebGPUBuffer>(buffers[i]);
194
+ if (!buffer) {
195
+ const attribute = this.props.shaderLayout.attributes.find(
196
+ (attribute) => attribute.location === i
197
+ );
198
+ throw new Error(
199
+ `No buffer provided for attribute '${attribute?.name || ''}' in Model '${this.props.id}'`
200
+ );
217
201
  }
202
+ webgpuRenderPass.handle.setVertexBuffer(i, buffer.handle);
203
+ }
218
204
 
219
- const buffers = this._getBuffers();
220
- for (let i = 0; i < buffers.length; ++i) {
221
- const buffer = cast<WebGPUBuffer>(buffers[i]);
222
- if (!buffer) {
223
- const attribute = this.props.shaderLayout.attributes.find(
224
- (attribute) => attribute.location === i
225
- );
226
- throw new Error(
227
- `No buffer provided for attribute '${attribute?.name || ''}' in Model '${this.props.id}'`
228
- );
229
- }
230
- webgpuRenderPass.handle.setVertexBuffer(i, buffer.handle);
205
+ // TODO - HANDLE buffer maps
206
+ /*
207
+ for (const [bufferName, attributeMapping] of Object.entries(this.props.bufferLayout)) {
208
+ const buffer = cast<WebGPUBuffer>(this.props.attributes[bufferName]);
209
+ if (!buffer) {
210
+ log.warn(`Missing buffer for buffer map ${bufferName}`)();
211
+ continue;
231
212
  }
232
213
 
233
- // TODO - HANDLE buffer maps
234
- /*
235
- for (const [bufferName, attributeMapping] of Object.entries(this.props.bufferLayout)) {
236
- const buffer = cast<WebGPUBuffer>(this.props.attributes[bufferName]);
237
- if (!buffer) {
238
- log.warn(`Missing buffer for buffer map ${bufferName}`)();
239
- continue;
240
- }
241
-
242
- if ('location' in attributeMapping) {
214
+ if ('location' in attributeMapping) {
215
+ // @ts-expect-error TODO model must not depend on webgpu
216
+ renderPass.handle.setVertexBuffer(layout.location, buffer.handle);
217
+ } else {
218
+ for (const [bufferName, mapping] of Object.entries(attributeMapping)) {
243
219
  // @ts-expect-error TODO model must not depend on webgpu
244
- renderPass.handle.setVertexBuffer(layout.location, buffer.handle);
245
- } else {
246
- for (const [bufferName, mapping] of Object.entries(attributeMapping)) {
247
- // @ts-expect-error TODO model must not depend on webgpu
248
- renderPass.handle.setVertexBuffer(field.location, buffer.handle);
249
- }
220
+ renderPass.handle.setVertexBuffer(field.location, buffer.handle);
250
221
  }
251
222
  }
252
- *
253
223
  }
254
- */
224
+ *
255
225
  }
226
+ */
@@ -27,6 +27,9 @@ export class WebGPUSampler extends Sampler {
27
27
  }
28
28
 
29
29
  override destroy(): void {
30
+ // GPUSampler does not have a destroy method
30
31
  // this.handle.destroy();
32
+ // @ts-expect-error readonly
33
+ this.handle = null;
31
34
  }
32
35
  }
@@ -6,10 +6,6 @@ import type {ShaderProps, CompilerMessage} from '@luma.gl/core';
6
6
  import {Shader, log} from '@luma.gl/core';
7
7
  import type {WebGPUDevice} from '../webgpu-device';
8
8
 
9
- export type WebGPUShaderProps = ShaderProps & {
10
- handle?: GPUShaderModule;
11
- };
12
-
13
9
  /**
14
10
  * Immutable shader
15
11
  */
@@ -17,7 +13,7 @@ export class WebGPUShader extends Shader {
17
13
  readonly device: WebGPUDevice;
18
14
  readonly handle: GPUShaderModule;
19
15
 
20
- constructor(device: WebGPUDevice, props: WebGPUShaderProps) {
16
+ constructor(device: WebGPUDevice, props: ShaderProps) {
21
17
  super(device, props);
22
18
  this.device = device;
23
19
 
@@ -46,6 +42,8 @@ export class WebGPUShader extends Shader {
46
42
  override destroy(): void {
47
43
  // Note: WebGPU does not offer a method to destroy shaders
48
44
  // this.handle.destroy();
45
+ // @ts-expect-error readonly
46
+ this.handle = null;
49
47
  }
50
48
 
51
49
  /** Returns compilation info for this shader */
@@ -57,26 +55,13 @@ export class WebGPUShader extends Shader {
57
55
  // PRIVATE METHODS
58
56
 
59
57
  protected createHandle(): GPUShaderModule {
60
- const {source, stage} = this.props;
58
+ const {source} = this.props;
61
59
 
62
- let language = this.props.language;
63
- // Compile from src
64
- if (language === 'auto') {
65
- // wgsl uses C++ "auto" style arrow notation
66
- language = source.includes('->') ? 'wgsl' : 'glsl';
60
+ const isGLSL = source.includes('#version');
61
+ if (this.props.language === 'glsl' || isGLSL) {
62
+ throw new Error('GLSL shaders are not supported in WebGPU');
67
63
  }
68
64
 
69
- switch (language) {
70
- case 'wgsl':
71
- return this.device.handle.createShaderModule({code: source});
72
- case 'glsl':
73
- return this.device.handle.createShaderModule({
74
- code: source,
75
- // @ts-expect-error
76
- transform: glsl => this.device.glslang.compileGLSL(glsl, stage)
77
- });
78
- default:
79
- throw new Error(language);
80
- }
65
+ return this.device.handle.createShaderModule({code: source});
81
66
  }
82
67
  }