@@ -40,6 +40,8 @@ function rendererWebGPU(p5, fn) {
4040 // Used to group draws into one big render pass
4141 this . activeRenderPass = null ;
4242 this . activeRenderPassEncoder = null ;
43+ this . activeShaderOptions = null ;
44+ this . activeShader = null ;
4345
4446 this . samplers = new Map ( ) ;
4547
@@ -70,9 +72,6 @@ function rendererWebGPU(p5, fn) {
7072 // Registry to track geometries with buffer pools
7173 this . _geometriesWithPools = [ ] ;
7274
73- // Reusable Map for uniform buffer bindings to avoid GC
74- this . _uniformBuffersForBinding = new Map ( ) ;
75-
7675 // Flag to track if any draws have happened that need queue submission
7776 this . _hasPendingDraws = false ;
7877 this . _pendingCommandEncoders = [ ] ;
@@ -278,6 +277,8 @@ function rendererWebGPU(p5, fn) {
278277 this . _pendingCommandEncoders . push ( commandEncoder . finish ( ) ) ;
279278 this . activeRenderPassEncoder = null ;
280279 this . activeRenderPass = null ;
280+ this . activeShader = null ;
281+ this . activeShaderOptions = null ;
281282 }
282283
283284 clear ( ...args ) {
@@ -520,6 +521,14 @@ function rendererWebGPU(p5, fn) {
520521 }
521522 }
522523
524+ _shaderOptionsDifferent ( newOptions ) {
525+ if ( ! this . activeShaderOptions ) return true ;
526+ for ( const key in this . activeShaderOptions ) {
527+ if ( this . activeShaderOptions [ key ] !== newOptions [ key ] ) return true ;
528+ }
529+ return false ;
530+ }
531+
523532 _initShader ( shader ) {
524533 const device = this . device ;
525534
@@ -1296,13 +1305,14 @@ function rendererWebGPU(p5, fn) {
12961305 // });
12971306 buf . offset = 0 ;
12981307 buf . lastOffset = 0 ;
1299- this . resettingUniformBuffers . push (
1308+ // this.resettingUniformBuffers.push(
13001309 buf . buffer . mapAsync ( GPUMapMode . WRITE ) . then ( ( ) => {
13011310 buf . data = new Float32Array ( buf . buffer . getMappedRange ( ) ) ;
13021311 buf . dataView = new DataView ( buf . data . buffer ) ;
1312+ this . uniformBufferPool . push ( buf ) ;
13031313 return buf ;
13041314 } )
1305- )
1315+ // )
13061316 }
13071317 this . activeUniformBuffers = [ ] ;
13081318 this . currentUniformBuffer = undefined ;
@@ -1380,7 +1390,7 @@ function rendererWebGPU(p5, fn) {
13801390 this . _markGeometryBuffersForReturn ( geometry ) ;
13811391 }
13821392
1383- this . uniformBufferPool . push ( ...( await Promise . all ( this . resettingUniformBuffers ) ) ) ;
1393+ // this.uniformBufferPool.push(...(await Promise.all(this.resettingUniformBuffers)));
13841394 this . resettingUniformBuffers = [ ] ;
13851395
13861396 // Return all vertex buffers to their pools
@@ -1425,7 +1435,12 @@ function rendererWebGPU(p5, fn) {
14251435 this . _beginActiveRenderPass ( ) ;
14261436 const passEncoder = this . activeRenderPass ;
14271437 const currentShader = this . _curShader ;
1428- passEncoder . setPipeline ( currentShader . getPipeline ( this . _shaderOptions ( { mode } ) ) ) ;
1438+ const shaderOptions = this . _shaderOptions ( { mode } ) ;
1439+ if ( this . activeShader !== currentShader || this . _shaderOptionsDifferent ( shaderOptions ) ) {
1440+ passEncoder . setPipeline ( currentShader . getPipeline ( shaderOptions ) ) ;
1441+ }
1442+ this . activeShader = currentShader ;
1443+ this . activeShaderOptions = shaderOptions ;
14291444
14301445 // Set stencil reference value for clipping
14311446 const drawTarget = this . drawTarget ( ) ;
@@ -1445,8 +1460,8 @@ function rendererWebGPU(p5, fn) {
14451460 passEncoder . setVertexBuffer ( location , gpuBuffer , 0 ) ;
14461461 }
14471462
1448- // Clear and reuse the map to avoid GC
1449- this . _uniformBuffersForBinding . clear ( ) ;
1463+ const uniformBuffersForBinding = { } ;
1464+ const uniformBufferOffsets = { } ;
14501465
14511466 for ( const bufferGroup of currentShader . _uniformBufferGroups ) {
14521467 if ( bufferGroup . dynamic ) {
@@ -1462,7 +1477,8 @@ function rendererWebGPU(p5, fn) {
14621477 uniformBufferInfo . offset += Math . ceil ( bufferGroup . size / this . uniformBufferAlignment ) * this . uniformBufferAlignment ;
14631478
14641479 // Make a shallow copy so that we keep track of the last offset for this uniform
1465- this . _uniformBuffersForBinding . set ( bufferGroup . cacheKey , { ...uniformBufferInfo } ) ;
1480+ uniformBuffersForBinding [ bufferGroup . cacheKey ] = uniformBufferInfo ;
1481+ uniformBufferOffsets [ bufferGroup . cacheKey ] = uniformBufferInfo . lastOffset ;
14661482 } else {
14671483 // Bind uniforms to a binding-specific buffer, which may be cached for performance
14681484 let bufferInfo ;
@@ -1492,56 +1508,60 @@ function rendererWebGPU(p5, fn) {
14921508 bufferGroup . currentBuffer = bufferInfo ;
14931509 }
14941510
1495- this . _uniformBuffersForBinding . set ( bufferGroup . cacheKey , bufferInfo ) ;
1511+ uniformBuffersForBinding [ bufferGroup . cacheKey ] = bufferInfo ;
1512+ }
1513+ }
1514+ for ( const sampler of currentShader . samplers ) {
1515+ const key = sampler . group + ',' + sampler . binding ;
1516+ if ( currentShader . buffersDirty [ key ] ) {
1517+ currentShader . _cachedBindGroup [ sampler . group ] = undefined ;
1518+ currentShader . buffersDirty [ key ] = false ;
14961519 }
14971520 }
14981521
14991522 // Bind sampler/texture uniforms and uniform buffers
15001523 for ( const [ group , entries ] of currentShader . _groupEntries ) {
1501- const bgEntries = entries . map ( entry => {
1524+ const dynamicEntryOffsets = [ ] ;
1525+ const bgEntries = [ ] ;
1526+ let bindGroup = currentShader . _cachedBindGroup [ group ] ;
1527+ for ( const entry of entries ) {
15021528 // Check if this is a uniform buffer binding
15031529 const uniformBufferInfo = entry . bufferGroup &&
1504- this . _uniformBuffersForBinding . get ( entry . bufferGroup . cacheKey ) ;
1530+ uniformBuffersForBinding [ entry . bufferGroup . cacheKey ] ;
15051531 if ( uniformBufferInfo && entry . bufferGroup ) {
1506- return {
1532+ if ( entry . bufferGroup . dynamic ) {
1533+ dynamicEntryOffsets . push ( uniformBufferOffsets [ entry . bufferGroup . cacheKey ] ) ;
1534+ }
1535+ if ( ! bindGroup ) {
1536+ bgEntries . push ( {
1537+ binding : entry . binding ,
1538+ resource : entry . bufferGroup . dynamic
1539+ ? {
1540+ buffer : uniformBufferInfo . uniformBuffer ,
1541+ offset : 0 ,
1542+ size : Math . ceil ( entry . bufferGroup . size / this . uniformBufferAlignment ) * this . uniformBufferAlignment ,
1543+ }
1544+ : { buffer : uniformBufferInfo . buffer } ,
1545+ } ) ;
1546+ }
1547+ } else if ( ! bindGroup ) {
1548+ bgEntries . push ( {
15071549 binding : entry . binding ,
1508- resource : entry . bufferGroup . dynamic
1509- ? {
1510- buffer : uniformBufferInfo . uniformBuffer ,
1511- offset : 0 ,
1512- size : Math . ceil ( entry . bufferGroup . size / this . uniformBufferAlignment ) * this . uniformBufferAlignment ,
1513- }
1514- : { buffer : uniformBufferInfo . buffer } ,
1515- } ;
1550+ resource : entry . uniform . type === 'sampler'
1551+ ? ( entry . uniform . textureSource . texture || this . _getEmptyTexture ( ) ) . getSampler ( )
1552+ : ( entry . uniform . texture || this . _getEmptyTexture ( ) ) . textureHandle . view ,
1553+ } ) ;
15161554 }
1517-
1518- const key = entry . uniform . group + ',' + entry . uniform . binding ;
1519- if ( currentShader . buffersDirty [ key ] ) {
1520- currentShader . _cachedBindGroup [ group ] = undefined ;
1521- currentShader . buffersDirty [ key ] = false ;
1522- }
1523-
1524- return {
1525- binding : entry . binding ,
1526- resource : entry . uniform . type === 'sampler'
1527- ? ( entry . uniform . textureSource . texture || this . _getEmptyTexture ( ) ) . getSampler ( )
1528- : ( entry . uniform . texture || this . _getEmptyTexture ( ) ) . textureHandle . view ,
1529- } ;
1530- } ) ;
1555+ }
15311556
15321557 const layout = currentShader . _bindGroupLayouts [ group ] ;
1533- let bindGroup = currentShader . _cachedBindGroup [ group ] ;
15341558 if ( ! bindGroup ) {
15351559 bindGroup = this . device . createBindGroup ( {
15361560 layout,
15371561 entries : bgEntries ,
15381562 } ) ;
15391563 }
15401564 currentShader . _cachedBindGroup [ group ] = bindGroup ;
1541- const dynamicEntryOffsets = entries
1542- . map ( e => e . bufferGroup && this . _uniformBuffersForBinding . get ( e . bufferGroup . cacheKey ) )
1543- . filter ( b => b ?. dynamic )
1544- . map ( b => b . lastOffset ) ;
15451565 passEncoder . setBindGroup (
15461566 group ,
15471567 bindGroup ,
@@ -1588,29 +1608,45 @@ function rendererWebGPU(p5, fn) {
15881608 for ( const uniform of groupUniforms ) {
15891609 const fullUniform = shader . uniforms [ uniform . name ] ;
15901610 if ( ! fullUniform || fullUniform . isSampler ) continue ;
1611+ const uniformData = fullUniform . _mappedData ;
15911612
15921613 if ( fullUniform . baseType === 'u32' ) {
15931614 if ( fullUniform . size === 4 ) {
1594- dataView . setUint32 ( offset + fullUniform . offset , fullUniform . _cachedData , true ) ;
1615+ dataView . setUint32 ( offset + fullUniform . offset , uniformData , true ) ;
15951616 } else {
1596- const uniformData = fullUniform . _cachedData ;
1617+ const uniformData = uniformData ;
15971618 for ( let i = 0 ; i < uniformData . length ; i ++ ) {
15981619 dataView . setUint32 ( offset + fullUniform . offset + i * 4 , uniformData [ i ] , true ) ;
15991620 }
16001621 }
16011622 } else if ( fullUniform . baseType === 'i32' ) {
16021623 if ( fullUniform . size === 4 ) {
1603- dataView . setInt32 ( offset + fullUniform . offset , fullUniform . _cachedData , true ) ;
1624+ dataView . setInt32 ( offset + fullUniform . offset , uniformData , true ) ;
16041625 } else {
1605- const uniformData = fullUniform . _cachedData ;
1626+ const uniformData = uniformData ;
16061627 for ( let i = 0 ; i < uniformData . length ; i ++ ) {
16071628 dataView . setInt32 ( offset + fullUniform . offset + i * 4 , uniformData [ i ] , true ) ;
16081629 }
16091630 }
1631+ } else if ( fullUniform . packInPlace ) {
1632+ // In-place packing for mat3: write directly to buffer with padding
1633+ const baseOffset = ( offset + fullUniform . offset ) / 4 ;
1634+ // Column 0
1635+ data [ baseOffset + 0 ] = uniformData [ 0 ] ;
1636+ data [ baseOffset + 1 ] = uniformData [ 1 ] ;
1637+ data [ baseOffset + 2 ] = uniformData [ 2 ] ;
1638+ // Column 1
1639+ data [ baseOffset + 4 ] = uniformData [ 3 ] ;
1640+ data [ baseOffset + 5 ] = uniformData [ 4 ] ;
1641+ data [ baseOffset + 6 ] = uniformData [ 5 ] ;
1642+ // Column 2
1643+ data [ baseOffset + 8 ] = uniformData [ 6 ] ;
1644+ data [ baseOffset + 9 ] = uniformData [ 7 ] ;
1645+ data [ baseOffset + 10 ] = uniformData [ 8 ] ;
16101646 } else if ( fullUniform . size === 4 ) {
1611- data . set ( [ fullUniform . _cachedData ] , ( offset + fullUniform . offset ) / 4 ) ;
1612- } else if ( fullUniform . _cachedData !== undefined ) {
1613- data . set ( fullUniform . _cachedData , ( offset + fullUniform . offset ) / 4 ) ;
1647+ data . set ( [ uniformData ] , ( offset + fullUniform . offset ) / 4 ) ;
1648+ } else if ( uniformData !== undefined ) {
1649+ data . set ( uniformData , ( offset + fullUniform . offset ) / 4 ) ;
16141650 }
16151651 }
16161652 }
@@ -1664,17 +1700,16 @@ function rendererWebGPU(p5, fn) {
16641700 const align = dim === 2 ? 8 : 16 ;
16651701 // Each column must be aligned
16661702 const size = Math . ceil ( dim * 4 / align ) * align * dim ;
1703+ // For mat3, use in-place packing to avoid array allocation
16671704 const pack = dim === 3
16681705 ? ( data ) => [
16691706 ...data . slice ( 0 , 3 ) ,
1670- 0 ,
16711707 ...data . slice ( 3 , 6 ) ,
1672- 0 ,
16731708 ...data . slice ( 6 , 9 ) ,
1674- 0
16751709 ]
16761710 : undefined ;
1677- return { align, size, pack, items : dim * dim , baseType : 'f32' } ;
1711+ const packInPlace = dim === 3 ;
1712+ return { align, size, pack, packInPlace, items : dim * dim , baseType : 'f32' } ;
16781713 }
16791714 if ( / ^ a r r a y < .+ > $ / . test ( type ) ) {
16801715 const [ , subtype , rawLength ] = type . match ( / ^ a r r a y < ( .+ ) , \s * ( \d + ) > / ) ;
@@ -1711,7 +1746,7 @@ function rendererWebGPU(p5, fn) {
17111746
17121747 while ( ( match = elementRegex . exec ( structBody ) ) !== null ) {
17131748 const [ _ , location , name , type ] = match ;
1714- const { size, align, pack, baseType } = baseAlignAndSize ( type ) ;
1749+ const { size, align, pack, packInPlace , baseType } = baseAlignAndSize ( type ) ;
17151750 offset = Math . ceil ( offset / align ) * align ;
17161751 const offsetEnd = offset + size ;
17171752 elements [ name ] = {
@@ -1723,6 +1758,7 @@ function rendererWebGPU(p5, fn) {
17231758 offset,
17241759 offsetEnd,
17251760 pack,
1761+ packInPlace,
17261762 baseType
17271763 } ;
17281764 index ++ ;
@@ -1873,6 +1909,8 @@ function rendererWebGPU(p5, fn) {
18731909 if ( uniform . isSampler ) {
18741910 uniform . texture =
18751911 data instanceof Texture ? data : this . getTexture ( data ) ;
1912+ } else {
1913+ uniform . _mappedData = this . _mapUniformData ( uniform , uniform . _cachedData ) ;
18761914 }
18771915 shader . buffersDirty = shader . buffersDirty || { } ;
18781916 shader . buffersDirty [ uniform . group + ',' + uniform . binding ] = true ;
0 commit comments