123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- import { GPUTextureViewDimension, GPUIndexFormat, GPUFilterMode, GPUPrimitiveTopology, GPULoadOp, GPUStoreOp } from './WebGPUConstants.js';
- class WebGPUTexturePassUtils {
- constructor( device ) {
- this.device = device;
- const mipmapVertexSource = `
- struct VarysStruct {
- @builtin( position ) Position: vec4<f32>,
- @location( 0 ) vTex : vec2<f32>
- };
- @vertex
- fn main( @builtin( vertex_index ) vertexIndex : u32 ) -> VarysStruct {
- var Varys : VarysStruct;
- var pos = array< vec2<f32>, 4 >(
- vec2<f32>( -1.0, 1.0 ),
- vec2<f32>( 1.0, 1.0 ),
- vec2<f32>( -1.0, -1.0 ),
- vec2<f32>( 1.0, -1.0 )
- );
- var tex = array< vec2<f32>, 4 >(
- vec2<f32>( 0.0, 0.0 ),
- vec2<f32>( 1.0, 0.0 ),
- vec2<f32>( 0.0, 1.0 ),
- vec2<f32>( 1.0, 1.0 )
- );
- Varys.vTex = tex[ vertexIndex ];
- Varys.Position = vec4<f32>( pos[ vertexIndex ], 0.0, 1.0 );
- return Varys;
- }
- `;
- const mipmapFragmentSource = `
- @group( 0 ) @binding( 0 )
- var imgSampler : sampler;
- @group( 0 ) @binding( 1 )
- var img : texture_2d<f32>;
- @fragment
- fn main( @location( 0 ) vTex : vec2<f32> ) -> @location( 0 ) vec4<f32> {
- return textureSample( img, imgSampler, vTex );
- }
- `;
- const flipYFragmentSource = `
- @group( 0 ) @binding( 0 )
- var imgSampler : sampler;
- @group( 0 ) @binding( 1 )
- var img : texture_2d<f32>;
- @fragment
- fn main( @location( 0 ) vTex : vec2<f32> ) -> @location( 0 ) vec4<f32> {
- return textureSample( img, imgSampler, vec2( vTex.x, 1.0 - vTex.y ) );
- }
- `;
- this.mipmapSampler = device.createSampler( { minFilter: GPUFilterMode.Linear } );
- this.flipYSampler = device.createSampler( { minFilter: GPUFilterMode.Nearest } ); //@TODO?: Consider using textureLoad()
- // We'll need a new pipeline for every texture format used.
- this.transferPipelines = {};
- this.flipYPipelines = {};
- this.mipmapVertexShaderModule = device.createShaderModule( {
- label: 'mipmapVertex',
- code: mipmapVertexSource
- } );
- this.mipmapFragmentShaderModule = device.createShaderModule( {
- label: 'mipmapFragment',
- code: mipmapFragmentSource
- } );
- this.flipYFragmentShaderModule = device.createShaderModule( {
- label: 'flipYFragment',
- code: flipYFragmentSource
- } );
- }
- getTransferPipeline( format ) {
- let pipeline = this.transferPipelines[ format ];
- if ( pipeline === undefined ) {
- pipeline = this.device.createRenderPipeline( {
- vertex: {
- module: this.mipmapVertexShaderModule,
- entryPoint: 'main'
- },
- fragment: {
- module: this.mipmapFragmentShaderModule,
- entryPoint: 'main',
- targets: [ { format } ]
- },
- primitive: {
- topology: GPUPrimitiveTopology.TriangleStrip,
- stripIndexFormat: GPUIndexFormat.Uint32
- },
- layout: 'auto'
- } );
- this.transferPipelines[ format ] = pipeline;
- }
- return pipeline;
- }
- getFlipYPipeline( format ) {
- let pipeline = this.flipYPipelines[ format ];
- if ( pipeline === undefined ) {
- pipeline = this.device.createRenderPipeline( {
- 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;
- }
- flipY( textureGPU, textureGPUDescriptor, baseArrayLayer = 0 ) {
- 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 },
- 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 commandEncoder = this.device.createCommandEncoder( {} );
- const pass = ( pipeline, sourceView, destinationView ) => {
- const bindGroupLayout = pipeline.getBindGroupLayout( 0 ); // @TODO: Consider making this static.
- const bindGroup = this.device.createBindGroup( {
- layout: bindGroupLayout,
- entries: [ {
- binding: 0,
- resource: this.flipYSampler
- }, {
- binding: 1,
- resource: sourceView
- } ]
- } );
- const passEncoder = commandEncoder.beginRenderPass( {
- colorAttachments: [ {
- view: destinationView,
- 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.end();
- };
- pass( transferPipeline, srcView, dstView );
- pass( flipYPipeline, dstView, srcView );
- this.device.queue.submit( [ commandEncoder.finish() ] );
- tempTexture.destroy();
- }
- generateMipmaps( textureGPU, textureGPUDescriptor, baseArrayLayer = 0 ) {
- const pipeline = this.getTransferPipeline( textureGPUDescriptor.format );
- const commandEncoder = this.device.createCommandEncoder( {} );
- const bindGroupLayout = pipeline.getBindGroupLayout( 0 ); // @TODO: Consider making this static.
- let srcView = textureGPU.createView( {
- baseMipLevel: 0,
- mipLevelCount: 1,
- dimension: GPUTextureViewDimension.TwoD,
- baseArrayLayer
- } );
- 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 passEncoder = commandEncoder.beginRenderPass( {
- colorAttachments: [ {
- view: dstView,
- 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.end();
- srcView = dstView;
- }
- this.device.queue.submit( [ commandEncoder.finish() ] );
- }
- }
- export default WebGPUTexturePassUtils;
|