| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 | // Copyright 2020 Brandon Jones//// Permission is hereby granted, free of charge, to any person obtaining a copy// of this software and associated documentation files (the "Software"), to deal// in the Software without restriction, including without limitation the rights// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell// copies of the Software, and to permit persons to whom the Software is// furnished to do so, subject to the following conditions:// The above copyright notice and this permission notice shall be included in// all copies or substantial portions of the Software.// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE// SOFTWARE.import { GPUIndexFormat, GPUFilterMode, GPUPrimitiveTopology } from './constants.js';// ported from https://github.com/toji/web-texture-tool/blob/master/src/webgpu-mipmap-generator.jsclass WebGPUTextureUtils {	constructor( device ) {		this.device = device;		const mipmapVertexSource = `[[ block ]]struct VarysStruct {	[[ builtin( position ) ]] Position: vec4<f32>;	[[ location( 0 ) ]] vTex : vec2<f32>;};[[ stage( 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>;[[ stage( fragment ) ]]fn main( [[ location( 0 ) ]] vTex : vec2<f32> ) -> [[ location( 0 ) ]] vec4<f32> {	return textureSample( img, imgSampler, vTex );}`;		this.sampler = device.createSampler( { minFilter: GPUFilterMode.Linear } );		// We'll need a new pipeline for every texture format used.		this.pipelines = {};		this.mipmapVertexShaderModule = device.createShaderModule( {			code: mipmapVertexSource		} );		this.mipmapFragmentShaderModule = device.createShaderModule( {			code: mipmapFragmentSource		} );	}	getMipmapPipeline( format ) {		let pipeline = this.pipelines[ 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				}			} );			this.pipelines[ format ] = pipeline;		}		return pipeline;	}	generateMipmaps( textureGPU, textureGPUDescriptor ) {		const pipeline = this.getMipmapPipeline( 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		} );		for ( let i = 1; i < textureGPUDescriptor.mipLevelCount; i ++ ) {			const dstView = textureGPU.createView( {				baseMipLevel: i,				mipLevelCount: 1			} );			const passEncoder = commandEncoder.beginRenderPass( {				colorAttachments: [ {					view: dstView,					loadValue: [ 0, 0, 0, 0 ]				} ]			} );			const bindGroup = this.device.createBindGroup( {				layout: bindGroupLayout,				entries: [ {					binding: 0,					resource: this.sampler				}, {					binding: 1,					resource: srcView				} ]			} );			passEncoder.setPipeline( pipeline );			passEncoder.setBindGroup( 0, bindGroup );			passEncoder.draw( 4, 1, 0, 0 );			passEncoder.endPass();			srcView = dstView;		}		this.device.queue.submit( [ commandEncoder.finish() ] );	}}export default WebGPUTextureUtils;
 |