// Field mip levels preserve the legacy trilinear AO sample at level 2.2. const GPU_FIELD_MIP = ` @group(0) @binding(0) var source: texture_2d; @group(0) @binding(1) var linear: sampler; @vertex fn vs(@builtin(vertex_index) i: u32) -> @builtin(position) vec4f { let pos=array(vec2f(-1,-1),vec2f(3,-1),vec2f(-1,3)); return vec4f(pos[i],0,1); } @fragment fn fs(@builtin(position) p: vec4f) -> @location(0) vec4f { let size=max(vec2u(1),textureDimensions(source)/2u); return textureSampleLevel(source,linear,p.xy/vec2f(size),0); }`; async function gpuSmoothInit() { const d=GPU.device; const pipeline=(code,vertex,format)=>d.createRenderPipelineAsync({layout:'auto',vertex:{module:d.createShaderModule({code:vertex}),entryPoint:'vs'},fragment:{module:d.createShaderModule({code}),entryPoint:'fs',targets:[{format}]},primitive:{topology:'triangle-list'}}); GPU.smooth=await pipeline(GPU_SMOOTH,GPU_DRAW,GPU.format); GPU.fieldMip=await pipeline(GPU_FIELD_MIP,GPU_FIELD_MIP,'rgba8unorm'); GPU.smoothUniform=d.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}); } function gpuSmoothTextures() { const w=R.bw,h=R.bh; GPU.smoothOver=Array.from({length:3},()=>gpuTexture(w,h)); GPU.smoothMask=gpuTexture(w,h,'r8uint'); GPU.backTex=gpuTexture(w,h,'rgba8unorm',true); GPU.treeTex=gpuTexture(w,h,'rgba8unorm',true); GPU.fieldTex=GPU.device.createTexture({size:[w,h],format:'rgba8unorm',mipLevelCount:Math.min(4,1+Math.floor(Math.log2(Math.max(w,h)))),usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.STORAGE_BINDING|GPUTextureUsage.RENDER_ATTACHMENT}); GPU.viewTextures.push(...GPU.smoothOver,GPU.smoothMask,GPU.backTex,GPU.treeTex,GPU.fieldTex); } function gpuSmoothBindings(group,view,buffer) { const colourResources=[buffer(GPU.uniform),buffer(GPU.lut),buffer(GPU.land),...GPU.worldTextures.slice(0,9).map(view),view(GPU.override),view(GPU.overrideGlow),view(GPU.colourTex),null,view(GPU.backTex),view(GPU.treeTex),GPU.fieldTex.createView({baseMipLevel:0,mipLevelCount:1}),...GPU.smoothOver.map(view),view(GPU.smoothMask)]; GPU.bindColourSmooth=GPU.device.createBindGroup({layout:GPU.colourSmooth.getBindGroupLayout(0),entries:colourResources.map((resource,binding)=>({binding,resource})).filter(e=>e.resource)}); GPU.bindSmooth=group(GPU.smooth,[buffer(GPU.uniform),view(GPU.colourTex),view(GPU.backTex),view(GPU.treeTex),view(GPU.fieldTex),view(GPU.lightTex),view(GPU.glowTex),GPU.sampler,buffer(GPU.smoothUniform)]); GPU.fieldMips=[]; for(let i=1;i