diff --git a/examples/webgpu_compute_birds.html b/examples/webgpu_compute_birds.html index a5f64a6b1d434a..075f910ac8957c 100644 --- a/examples/webgpu_compute_birds.html +++ b/examples/webgpu_compute_birds.html @@ -158,7 +158,7 @@ // - renderer = new THREE.WebGPURenderer( { antialias: true, forceWebGL: false } ); + renderer = new THREE.WebGPURenderer( { antialias: true, forceWebGL: false, requiredLimits: { maxStorageBuffersInVertexStage: 3 } } ); renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( window.innerWidth, window.innerHeight ); renderer.setAnimationLoop( render ); diff --git a/examples/webgpu_compute_cloth.html b/examples/webgpu_compute_cloth.html index 908a631e472951..47d4f51a58eba0 100644 --- a/examples/webgpu_compute_cloth.html +++ b/examples/webgpu_compute_cloth.html @@ -90,7 +90,7 @@ async function init() { - renderer = new THREE.WebGPURenderer( { antialias: true } ); + renderer = new THREE.WebGPURenderer( { antialias: true, requiredLimits: { maxStorageBuffersInVertexStage: 1 } } ); renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( window.innerWidth, window.innerHeight ); renderer.toneMapping = THREE.NeutralToneMapping; diff --git a/examples/webgpu_compute_particles_fluid.html b/examples/webgpu_compute_particles_fluid.html index 7d26c79d5347d5..ee02b41800c7be 100644 --- a/examples/webgpu_compute_particles_fluid.html +++ b/examples/webgpu_compute_particles_fluid.html @@ -77,7 +77,7 @@ async function init() { - renderer = new THREE.WebGPURenderer( { antialias: true } ); + renderer = new THREE.WebGPURenderer( { antialias: true, requiredLimits: { maxStorageBuffersInVertexStage: 1 } } ); renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( window.innerWidth, window.innerHeight ); renderer.toneMapping = THREE.ACESFilmicToneMapping; diff --git a/examples/webgpu_compute_points.html b/examples/webgpu_compute_points.html index ed0de9049165e1..ab87413135bd17 100644 --- a/examples/webgpu_compute_points.html +++ b/examples/webgpu_compute_points.html @@ -124,7 +124,7 @@ mesh.count = particlesCount; scene.add( mesh ); - renderer = new THREE.WebGPURenderer( { antialias: true } ); + renderer = new THREE.WebGPURenderer( { antialias: true, requiredLimits: { maxStorageBuffersInVertexStage: 1 } } ); renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( window.innerWidth, window.innerHeight ); renderer.setAnimationLoop( animate ); diff --git a/examples/webgpu_compute_water.html b/examples/webgpu_compute_water.html index 60848b49fe4e76..49a863564aefb4 100644 --- a/examples/webgpu_compute_water.html +++ b/examples/webgpu_compute_water.html @@ -457,7 +457,7 @@ const duckMesh = new THREE.InstancedMesh( duckModel.geometry, duckModel.material, NUM_DUCKS ); scene.add( duckMesh ); - renderer = new THREE.WebGPURenderer( { antialias: true } ); + renderer = new THREE.WebGPURenderer( { antialias: true, requiredLimits: { maxStorageBuffersInVertexStage: 2 } } ); renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( window.innerWidth, window.innerHeight ); renderer.toneMapping = THREE.ACESFilmicToneMapping; diff --git a/examples/webgpu_mrt.html b/examples/webgpu_mrt.html index 3dfdc7cd40a61c..9df0536b7a0c29 100644 --- a/examples/webgpu_mrt.html +++ b/examples/webgpu_mrt.html @@ -82,7 +82,7 @@ // renderer - renderer = new THREE.WebGPURenderer( { antialias: true } ); + renderer = new THREE.WebGPURenderer( { antialias: true, requiredLimits: { maxColorAttachments: 5 } } ); renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( window.innerWidth, window.innerHeight ); renderer.setAnimationLoop( render ); diff --git a/package.json b/package.json index a5e769d34152eb..3335e9658eed5f 100644 --- a/package.json +++ b/package.json @@ -54,12 +54,11 @@ "lint-addons": "eslint examples/jsm", "lint-examples": "eslint examples", "lint-editor": "eslint editor", - "lint-playground": "eslint playground", "lint-manual": "eslint manual", "lint-test": "eslint test", "lint-utils": "eslint utils", "lint": "npm run lint-core", - "lint-fix": "npm run lint-core -- --fix && npm run lint-addons -- --fix && npm run lint-examples -- --fix && npm run lint-docs -- --fix && npm run lint-editor -- --fix && npm run lint-playground -- --fix && npm run lint-manual -- --fix && npm run lint-test -- --fix && npm run lint-utils -- --fix", + "lint-fix": "npm run lint-core -- --fix && npm run lint-addons -- --fix && npm run lint-examples -- --fix && npm run lint-editor -- --fix && npm run lint-manual -- --fix && npm run lint-test -- --fix && npm run lint-utils -- --fix", "test-unit": "qunit test/unit/three.source.unit.js", "test-unit-addons": "qunit test/unit/three.addons.unit.js", "test-e2e": "node test/e2e/puppeteer.js", diff --git a/src/nodes/core/NodeBuilder.js b/src/nodes/core/NodeBuilder.js index ee2c64bbb7b276..48425d7863316b 100644 --- a/src/nodes/core/NodeBuilder.js +++ b/src/nodes/core/NodeBuilder.js @@ -584,7 +584,7 @@ class NodeBuilder { bindingsArray.push( binding ); - sharedGroup = sharedGroup && binding.groupNode.shared !== true; + sharedGroup = sharedGroup && binding.groupNode.shared; } @@ -598,7 +598,7 @@ class NodeBuilder { if ( bindGroup === undefined ) { - bindGroup = new BindGroup( groupName, bindingsArray, this.bindingsIndexes[ groupName ].group, bindingsArray ); + bindGroup = new BindGroup( groupName, bindingsArray, this.bindingsIndexes[ groupName ].group ); bindGroupsCache.set( bindingsArray, bindGroup ); @@ -606,7 +606,7 @@ class NodeBuilder { } else { - bindGroup = new BindGroup( groupName, bindingsArray, this.bindingsIndexes[ groupName ].group, bindingsArray ); + bindGroup = new BindGroup( groupName, bindingsArray, this.bindingsIndexes[ groupName ].group ); } diff --git a/src/renderers/common/BindGroup.js b/src/renderers/common/BindGroup.js index ea44aaf4962fae..43afc93a7855a7 100644 --- a/src/renderers/common/BindGroup.js +++ b/src/renderers/common/BindGroup.js @@ -15,9 +15,8 @@ class BindGroup { * @param {string} name - The bind group's name. * @param {Array} bindings - An array of bindings. * @param {number} index - The group index. - * @param {Array} bindingsReference - An array of reference bindings. */ - constructor( name = '', bindings = [], index = 0, bindingsReference = [] ) { + constructor( name = '', bindings = [], index = 0 ) { /** * The bind group's name. @@ -40,13 +39,6 @@ class BindGroup { */ this.index = index; - /** - * An array of reference bindings. - * - * @type {Array} - */ - this.bindingsReference = bindingsReference; - /** * The group's ID. * diff --git a/src/renderers/common/nodes/NodeBuilderState.js b/src/renderers/common/nodes/NodeBuilderState.js index 5e9b47832e43e7..4b0dfd3b800412 100644 --- a/src/renderers/common/nodes/NodeBuilderState.js +++ b/src/renderers/common/nodes/NodeBuilderState.js @@ -126,7 +126,7 @@ class NodeBuilderState { if ( shared !== true ) { - const bindingsGroup = new BindGroup( instanceGroup.name, [], instanceGroup.index, instanceGroup.bindingsReference ); + const bindingsGroup = new BindGroup( instanceGroup.name, [], instanceGroup.index ); bindings.push( bindingsGroup ); for ( const instanceBinding of instanceGroup.bindings ) { diff --git a/src/renderers/webgpu/utils/WebGPUTexturePassUtils.js b/src/renderers/webgpu/utils/WebGPUTexturePassUtils.js index 0390649f2fa075..ebcf069b803a52 100644 --- a/src/renderers/webgpu/utils/WebGPUTexturePassUtils.js +++ b/src/renderers/webgpu/utils/WebGPUTexturePassUtils.js @@ -1,5 +1,5 @@ import DataMap from '../../common/DataMap.js'; -import { GPUTextureViewDimension, GPUIndexFormat, GPUFilterMode, GPUPrimitiveTopology, GPULoadOp, GPUStoreOp } from './WebGPUConstants.js'; +import { GPUFilterMode, GPULoadOp, GPUStoreOp } from './WebGPUConstants.js'; /** * A WebGPU backend utility module used by {@link WebGPUTextureUtils}. @@ -24,65 +24,88 @@ class WebGPUTexturePassUtils extends DataMap { */ this.device = device; - const mipmapVertexSource = ` + const mipmapSource = ` struct VarysStruct { - @builtin( position ) Position: vec4, - @location( 0 ) vTex : vec2 + @builtin( position ) Position: vec4f, + @location( 0 ) vTex : vec2f, + @location( 1 ) @interpolate(flat, either) vBaseArrayLayer: u32, }; +@group( 0 ) @binding ( 2 ) +var flipY: u32; + @vertex -fn main( @builtin( vertex_index ) vertexIndex : u32 ) -> VarysStruct { +fn mainVS( + @builtin( vertex_index ) vertexIndex : u32, + @builtin( instance_index ) instanceIndex : u32 ) -> VarysStruct { var Varys : VarysStruct; - var pos = array< vec2, 4 >( - vec2( -1.0, 1.0 ), - vec2( 1.0, 1.0 ), - vec2( -1.0, -1.0 ), - vec2( 1.0, -1.0 ) - ); - - var tex = array< vec2, 4 >( - vec2( 0.0, 0.0 ), - vec2( 1.0, 0.0 ), - vec2( 0.0, 1.0 ), - vec2( 1.0, 1.0 ) + var pos = array( + vec2f( -1, -1 ), + vec2f( -1, 3 ), + vec2f( 3, -1 ), ); - Varys.vTex = tex[ vertexIndex ]; - Varys.Position = vec4( pos[ vertexIndex ], 0.0, 1.0 ); + let p = pos[ vertexIndex ]; + let mult = select( vec2f( 0.5, -0.5 ), vec2f( 0.5, 0.5 ), flipY != 0 ); + Varys.vTex = p * vec2f( 0.5, -0.5 ) + vec2f( 0.5 ); + Varys.Position = vec4f( p, 0, 1 ); + Varys.vBaseArrayLayer = instanceIndex; return Varys; } -`; - const mipmapFragmentSource = ` @group( 0 ) @binding( 0 ) var imgSampler : sampler; @group( 0 ) @binding( 1 ) -var img : texture_2d; +var img2d : texture_2d; @fragment -fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { +fn main_2d( Varys: VarysStruct ) -> @location( 0 ) vec4 { - return textureSample( img, imgSampler, vTex ); + return textureSample( img2d, imgSampler, Varys.vTex ); } -`; - const flipYFragmentSource = ` -@group( 0 ) @binding( 0 ) -var imgSampler : sampler; +@group( 0 ) @binding( 1 ) +var img2dArray : texture_2d_array; + +@fragment +fn main_2d_array( Varys: VarysStruct ) -> @location( 0 ) vec4 { + + return textureSample( img2dArray, imgSampler, Varys.vTex, Varys.vBaseArrayLayer ); + +} + +const faceMat = array( + mat3x3f( 0, 0, -2, 0, -2, 0, 1, 1, 1 ), // pos-x + mat3x3f( 0, 0, 2, 0, -2, 0, -1, 1, -1 ), // neg-x + mat3x3f( 2, 0, 0, 0, 0, 2, -1, 1, -1 ), // pos-y + mat3x3f( 2, 0, 0, 0, 0, -2, -1, -1, 1 ), // neg-y + mat3x3f( 2, 0, 0, 0, -2, 0, -1, 1, 1 ), // pos-z + mat3x3f( -2, 0, 0, 0, -2, 0, 1, 1, -1 ), // neg-z +); @group( 0 ) @binding( 1 ) -var img : texture_2d; +var imgCube : texture_cube; @fragment -fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { +fn main_cube( Varys: VarysStruct ) -> @location( 0 ) vec4 { - return textureSample( img, imgSampler, vec2( vTex.x, 1.0 - vTex.y ) ); + return textureSample( imgCube, imgSampler, faceMat[ Varys.vBaseArrayLayer ] * vec3f( fract( Varys.vTex ), 1 ) ); + +} + +@group( 0 ) @binding( 1 ) +var imgCubeArray : texture_cube_array; + +@fragment +fn main_cube_array( Varys: VarysStruct ) -> @location( 0 ) vec4 { + + return textureSample( imgCubeArray, imgSampler, faceMat[ Varys.vBaseArrayLayer % 6 ] * vec3f( fract( Varys.vTex ), 1 ), Varys.vBaseArrayLayer ); } `; @@ -102,49 +125,40 @@ fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { this.flipYSampler = device.createSampler( { minFilter: GPUFilterMode.Nearest } ); //@TODO?: Consider using textureLoad() /** - * A cache for GPU render pipelines used for copy/transfer passes. - * Every texture format requires a unique pipeline. - * - * @type {Object} - */ - this.transferPipelines = {}; - - /** - * A cache for GPU render pipelines used for flipY passes. - * Every texture format requires a unique pipeline. - * - * @type {Object} + * flip uniform buffer + * @type {GPUBuffer} */ - this.flipYPipelines = {}; + this.flipUniformBuffer = device.createBuffer( { + size: 4, + usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST + } ); + device.queue.writeBuffer( this.flipUniformBuffer, 0, new Uint32Array( [ 1 ] ) ); /** - * The mipmap vertex shader module. - * - * @type {GPUShaderModule} + * no flip uniform buffer + * @type {GPUBuffer} */ - this.mipmapVertexShaderModule = device.createShaderModule( { - label: 'mipmapVertex', - code: mipmapVertexSource + this.noFlipUniformBuffer = device.createBuffer( { + size: 4, + usage: GPUBufferUsage.UNIFORM } ); /** - * The mipmap fragment shader module. + * A cache for GPU render pipelines used for copy/transfer passes. + * Every texture format and textureBindingViewDimension combo requires a unique pipeline. * - * @type {GPUShaderModule} + * @type {Object} */ - this.mipmapFragmentShaderModule = device.createShaderModule( { - label: 'mipmapFragment', - code: mipmapFragmentSource - } ); + this.transferPipelines = {}; /** - * The flipY fragment shader module. + * The mipmap shader module. * * @type {GPUShaderModule} */ - this.flipYFragmentShaderModule = device.createShaderModule( { - label: 'flipYFragment', - code: flipYFragmentSource + this.mipmapShaderModule = device.createShaderModule( { + label: 'mipmap', + code: mipmapSource } ); } @@ -154,29 +168,27 @@ fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { * requires a unique render pipeline for each texture format. * * @param {string} format - The GPU texture format + * @param {string?} textureBindingViewDimension - The GPU texture binding view dimension * @return {GPURenderPipeline} The GPU render pipeline. */ - getTransferPipeline( format ) { + getTransferPipeline( format, textureBindingViewDimension ) { - let pipeline = this.transferPipelines[ format ]; + textureBindingViewDimension = textureBindingViewDimension || '2d-array'; + const key = `${ format }-${ textureBindingViewDimension }`; + let pipeline = this.transferPipelines[ key ]; if ( pipeline === undefined ) { pipeline = this.device.createRenderPipeline( { - label: `mipmap-${ format }`, + label: `mipmap-${ format }-${ textureBindingViewDimension }`, vertex: { - module: this.mipmapVertexShaderModule, - entryPoint: 'main' + module: this.mipmapShaderModule, }, fragment: { - module: this.mipmapFragmentShaderModule, - entryPoint: 'main', + module: this.mipmapShaderModule, + entryPoint: `main_${ textureBindingViewDimension.replace( '-', '_' ) }`, targets: [ { format } ] }, - primitive: { - topology: GPUPrimitiveTopology.TriangleStrip, - stripIndexFormat: GPUIndexFormat.Uint32 - }, layout: 'auto' } ); @@ -188,45 +200,6 @@ fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { } - /** - * Returns a render pipeline for the flipY render pass. The pass - * requires a unique render pipeline for each texture format. - * - * @param {string} format - The GPU texture format - * @return {GPURenderPipeline} The GPU render pipeline. - */ - getFlipYPipeline( format ) { - - let pipeline = this.flipYPipelines[ format ]; - - if ( pipeline === undefined ) { - - pipeline = this.device.createRenderPipeline( { - label: `flipY-${ format }`, - vertex: { - module: this.mipmapVertexShaderModule, - entryPoint: 'main' - }, - fragment: { - module: this.flipYFragmentShaderModule, - entryPoint: 'main', - targets: [ { format } ] - }, - primitive: { - topology: GPUPrimitiveTopology.TriangleStrip, - stripIndexFormat: GPUIndexFormat.Uint32 - }, - layout: 'auto' - } ); - - this.flipYPipelines[ format ] = pipeline; - - } - - return pipeline; - - } - /** * Flip the contents of the given GPU texture along its vertical axis. * @@ -239,32 +212,18 @@ fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { const format = textureGPUDescriptor.format; const { width, height } = textureGPUDescriptor.size; - const transferPipeline = this.getTransferPipeline( format ); - const flipYPipeline = this.getFlipYPipeline( format ); - const tempTexture = this.device.createTexture( { - size: { width, height, depthOrArrayLayers: 1 }, + size: { width, height }, format, usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING } ); - const srcView = textureGPU.createView( { - baseMipLevel: 0, - mipLevelCount: 1, - dimension: GPUTextureViewDimension.TwoD, - baseArrayLayer - } ); - - const dstView = tempTexture.createView( { - baseMipLevel: 0, - mipLevelCount: 1, - dimension: GPUTextureViewDimension.TwoD, - baseArrayLayer: 0 - } ); + const copyTransferPipeline = this.getTransferPipeline( format, textureGPU.textureBindingViewDimension ); + const flipTransferPipeline = this.getTransferPipeline( format, tempTexture.textureBindingViewDimension ); const commandEncoder = this.device.createCommandEncoder( {} ); - const pass = ( pipeline, sourceView, destinationView ) => { + const pass = ( pipeline, sourceTexture, sourceArrayLayer, destinationTexture, destinationArrayLayer, flipY ) => { const bindGroupLayout = pipeline.getBindGroupLayout( 0 ); // @TODO: Consider making this static. @@ -275,28 +234,40 @@ fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { resource: this.flipYSampler }, { binding: 1, - resource: sourceView + resource: sourceTexture.createView( { + dimension: sourceTexture.textureBindingViewDimension || '2d-array', + baseMipLevel: 0, + mipLevelCount: 1, + } ), + }, { + binding: 2, + resource: { buffer: flipY ? this.flipUniformBuffer : this.noFlipUniformBuffer } } ] } ); const passEncoder = commandEncoder.beginRenderPass( { colorAttachments: [ { - view: destinationView, + view: destinationTexture.createView( { + dimension: '2d', + baseMipLevel: 0, + mipLevelCount: 1, + baseArrayLayer: destinationArrayLayer, + arrayLayerCount: 1, + } ), loadOp: GPULoadOp.Clear, storeOp: GPUStoreOp.Store, - clearValue: [ 0, 0, 0, 0 ] } ] } ); passEncoder.setPipeline( pipeline ); passEncoder.setBindGroup( 0, bindGroup ); - passEncoder.draw( 4, 1, 0, 0 ); + passEncoder.draw( 3, 1, 0, sourceArrayLayer ); passEncoder.end(); }; - pass( transferPipeline, srcView, dstView ); - pass( flipYPipeline, dstView, srcView ); + pass( copyTransferPipeline, textureGPU, baseArrayLayer, tempTexture, 0, false ); + pass( flipTransferPipeline, tempTexture, 0, textureGPU, baseArrayLayer, true ); this.device.queue.submit( [ commandEncoder.finish() ] ); @@ -308,21 +279,13 @@ fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { * Generates mipmaps for the given GPU texture. * * @param {GPUTexture} textureGPU - The GPU texture object. - * @param {Object} textureGPUDescriptor - The texture descriptor. - * @param {number} [baseArrayLayer=0] - The index of the first array layer accessible to the texture view. * @param {?GPUCommandEncoder} [encoder=null] - An optional command encoder used to generate mipmaps. */ - generateMipmaps( textureGPU, textureGPUDescriptor, baseArrayLayer = 0, encoder = null ) { + generateMipmaps( textureGPU, encoder = null ) { const textureData = this.get( textureGPU ); - if ( textureData.layers === undefined ) { - - textureData.layers = []; - - } - - const passes = textureData.layers[ baseArrayLayer ] || this._mipmapCreateBundles( textureGPU, textureGPUDescriptor, baseArrayLayer ); + const passes = textureData.layers || this._mipmapCreateBundles( textureGPU ); const commandEncoder = encoder || this.device.createCommandEncoder( { label: 'mipmapEncoder' } ); @@ -330,7 +293,7 @@ fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { if ( encoder === null ) this.device.queue.submit( [ commandEncoder.finish() ] ); - textureData.layers[ baseArrayLayer ] = passes; + textureData.layers = passes; } @@ -339,68 +302,67 @@ fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { * are managed as render bundles to improve performance. * * @param {GPUTexture} textureGPU - The GPU texture object. - * @param {Object} textureGPUDescriptor - The texture descriptor. - * @param {number} baseArrayLayer - The index of the first array layer accessible to the texture view. * @return {Array} An array of render bundles. */ - _mipmapCreateBundles( textureGPU, textureGPUDescriptor, baseArrayLayer ) { + _mipmapCreateBundles( textureGPU ) { - const pipeline = this.getTransferPipeline( textureGPUDescriptor.format ); + const textureBindingViewDimension = textureGPU.textureBindingViewDimension || '2d-array'; + const pipeline = this.getTransferPipeline( textureGPU.format, textureBindingViewDimension ); const bindGroupLayout = pipeline.getBindGroupLayout( 0 ); // @TODO: Consider making this static. - let srcView = textureGPU.createView( { - baseMipLevel: 0, - mipLevelCount: 1, - dimension: GPUTextureViewDimension.TwoD, - baseArrayLayer - } ); - const passes = []; - for ( let i = 1; i < textureGPUDescriptor.mipLevelCount; i ++ ) { - - const bindGroup = this.device.createBindGroup( { - layout: bindGroupLayout, - entries: [ { - binding: 0, - resource: this.mipmapSampler - }, { - binding: 1, - resource: srcView - } ] - } ); - - const dstView = textureGPU.createView( { - baseMipLevel: i, - mipLevelCount: 1, - dimension: GPUTextureViewDimension.TwoD, - baseArrayLayer - } ); - - const passDescriptor = { - colorAttachments: [ { - view: dstView, - loadOp: GPULoadOp.Clear, - storeOp: GPUStoreOp.Store, - clearValue: [ 0, 0, 0, 0 ] - } ] - }; - - const passEncoder = this.device.createRenderBundleEncoder( { - colorFormats: [ textureGPUDescriptor.format ] - } ); - - passEncoder.setPipeline( pipeline ); - passEncoder.setBindGroup( 0, bindGroup ); - passEncoder.draw( 4, 1, 0, 0 ); - - passes.push( { - renderBundles: [ passEncoder.finish() ], - passDescriptor - } ); - - srcView = dstView; + for ( let baseMipLevel = 1; baseMipLevel < textureGPU.mipLevelCount; baseMipLevel ++ ) { + + for ( let baseArrayLayer = 0; baseArrayLayer < textureGPU.depthOrArrayLayers; baseArrayLayer ++ ) { + + const bindGroup = this.device.createBindGroup( { + layout: bindGroupLayout, + entries: [ { + binding: 0, + resource: this.mipmapSampler + }, { + binding: 1, + resource: textureGPU.createView( { + dimension: textureBindingViewDimension, + baseMipLevel: baseMipLevel - 1, + mipLevelCount: 1, + } ), + }, { + binding: 2, + resource: { buffer: this.noFlipUniformBuffer } + } ] + } ); + + const passDescriptor = { + colorAttachments: [ { + view: textureGPU.createView( { + dimension: '2d', + baseMipLevel, + mipLevelCount: 1, + baseArrayLayer, + arrayLayerCount: 1, + } ), + loadOp: GPULoadOp.Clear, + storeOp: GPUStoreOp.Store, + } ] + }; + + const passEncoder = this.device.createRenderBundleEncoder( { + colorFormats: [ textureGPU.format ] + } ); + + passEncoder.setPipeline( pipeline ); + passEncoder.setBindGroup( 0, bindGroup ); + passEncoder.draw( 3, 1, 0, baseArrayLayer ); + + passes.push( { + renderBundles: [ passEncoder.finish() ], + passDescriptor + } ); + + } } diff --git a/src/renderers/webgpu/utils/WebGPUTextureUtils.js b/src/renderers/webgpu/utils/WebGPUTextureUtils.js index 1402d045d7fb5c..e79680aa56acfe 100644 --- a/src/renderers/webgpu/utils/WebGPUTextureUtils.js +++ b/src/renderers/webgpu/utils/WebGPUTextureUtils.js @@ -371,25 +371,7 @@ class WebGPUTextureUtils { const textureData = this.backend.get( texture ); - if ( texture.isCubeTexture ) { - - for ( let i = 0; i < 6; i ++ ) { - - this._generateMipmaps( textureData.texture, textureData.textureDescriptorGPU, i, encoder ); - - } - - } else { - - const depth = texture.image.depth || 1; - - for ( let i = 0; i < depth; i ++ ) { - - this._generateMipmaps( textureData.texture, textureData.textureDescriptorGPU, i, encoder ); - - } - - } + this._generateMipmaps( textureData.texture, encoder ); }