修改静态资源文件夹位置
This commit is contained in:
1339
public/sdk/three/jsm/renderers/webgpu/WebGPUBackend.js
Normal file
1339
public/sdk/three/jsm/renderers/webgpu/WebGPUBackend.js
Normal file
File diff suppressed because it is too large
Load Diff
53
public/sdk/three/jsm/renderers/webgpu/WebGPURenderer.js
Normal file
53
public/sdk/three/jsm/renderers/webgpu/WebGPURenderer.js
Normal file
@ -0,0 +1,53 @@
|
||||
import WebGPU from '../../capabilities/WebGPU.js';
|
||||
|
||||
import Renderer from '../common/Renderer.js';
|
||||
import WebGLBackend from '../webgl/WebGLBackend.js';
|
||||
import WebGPUBackend from './WebGPUBackend.js';
|
||||
/*
|
||||
const debugHandler = {
|
||||
|
||||
get: function ( target, name ) {
|
||||
|
||||
// Add |update
|
||||
if ( /^(create|destroy)/.test( name ) ) console.log( 'WebGPUBackend.' + name );
|
||||
|
||||
return target[ name ];
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
*/
|
||||
class WebGPURenderer extends Renderer {
|
||||
|
||||
constructor( parameters = {} ) {
|
||||
|
||||
let BackendClass;
|
||||
|
||||
if ( parameters.forceWebGL ) {
|
||||
|
||||
BackendClass = WebGLBackend;
|
||||
|
||||
} else if ( WebGPU.isAvailable() ) {
|
||||
|
||||
BackendClass = WebGPUBackend;
|
||||
|
||||
} else {
|
||||
|
||||
BackendClass = WebGLBackend;
|
||||
|
||||
console.warn( 'THREE.WebGPURenderer: WebGPU is not available, running under WebGL2 backend.' );
|
||||
|
||||
}
|
||||
|
||||
const backend = new BackendClass( parameters );
|
||||
|
||||
//super( new Proxy( backend, debugHandler ) );
|
||||
super( backend, parameters );
|
||||
|
||||
this.isWebGPURenderer = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGPURenderer;
|
1095
public/sdk/three/jsm/renderers/webgpu/nodes/WGSLNodeBuilder.js
Normal file
1095
public/sdk/three/jsm/renderers/webgpu/nodes/WGSLNodeBuilder.js
Normal file
File diff suppressed because it is too large
Load Diff
104
public/sdk/three/jsm/renderers/webgpu/nodes/WGSLNodeFunction.js
Normal file
104
public/sdk/three/jsm/renderers/webgpu/nodes/WGSLNodeFunction.js
Normal file
@ -0,0 +1,104 @@
|
||||
import NodeFunction from '../../../nodes/core/NodeFunction.js';
|
||||
import NodeFunctionInput from '../../../nodes/core/NodeFunctionInput.js';
|
||||
|
||||
const declarationRegexp = /^[fn]*\s*([a-z_0-9]+)?\s*\(([\s\S]*?)\)\s*[\-\>]*\s*([a-z_0-9]+)?/i;
|
||||
const propertiesRegexp = /[a-z_0-9]+|<(.*?)>+/ig;
|
||||
|
||||
const wgslTypeLib = {
|
||||
f32: 'float'
|
||||
};
|
||||
|
||||
const parse = ( source ) => {
|
||||
|
||||
source = source.trim();
|
||||
|
||||
const declaration = source.match( declarationRegexp );
|
||||
|
||||
if ( declaration !== null && declaration.length === 4 ) {
|
||||
|
||||
// tokenizer
|
||||
|
||||
const inputsCode = declaration[ 2 ];
|
||||
const propsMatches = [];
|
||||
|
||||
let nameMatch = null;
|
||||
|
||||
while ( ( nameMatch = propertiesRegexp.exec( inputsCode ) ) !== null ) {
|
||||
|
||||
propsMatches.push( nameMatch );
|
||||
|
||||
}
|
||||
|
||||
// parser
|
||||
|
||||
const inputs = [];
|
||||
|
||||
let i = 0;
|
||||
|
||||
while ( i < propsMatches.length ) {
|
||||
|
||||
// default
|
||||
|
||||
const name = propsMatches[ i ++ ][ 0 ];
|
||||
let type = propsMatches[ i ++ ][ 0 ];
|
||||
|
||||
type = wgslTypeLib[ type ] || type;
|
||||
|
||||
// precision
|
||||
|
||||
if ( i < propsMatches.length && propsMatches[ i ][ 0 ].startsWith( '<' ) === true )
|
||||
i ++;
|
||||
|
||||
// add input
|
||||
|
||||
inputs.push( new NodeFunctionInput( type, name ) );
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
const blockCode = source.substring( declaration[ 0 ].length );
|
||||
|
||||
const name = declaration[ 1 ] !== undefined ? declaration[ 1 ] : '';
|
||||
const type = declaration[ 3 ] || 'void';
|
||||
|
||||
return {
|
||||
type,
|
||||
inputs,
|
||||
name,
|
||||
inputsCode,
|
||||
blockCode
|
||||
};
|
||||
|
||||
} else {
|
||||
|
||||
throw new Error( 'FunctionNode: Function is not a WGSL code.' );
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class WGSLNodeFunction extends NodeFunction {
|
||||
|
||||
constructor( source ) {
|
||||
|
||||
const { type, inputs, name, inputsCode, blockCode } = parse( source );
|
||||
|
||||
super( type, inputs, name );
|
||||
|
||||
this.inputsCode = inputsCode;
|
||||
this.blockCode = blockCode;
|
||||
|
||||
}
|
||||
|
||||
getCode( name = this.name ) {
|
||||
|
||||
const type = this.type !== 'void' ? '-> ' + this.type : '';
|
||||
|
||||
return `fn ${ name } ( ${ this.inputsCode.trim() } ) ${ type }` + this.blockCode;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WGSLNodeFunction;
|
@ -0,0 +1,14 @@
|
||||
import NodeParser from '../../../nodes/core/NodeParser.js';
|
||||
import WGSLNodeFunction from './WGSLNodeFunction.js';
|
||||
|
||||
class WGSLNodeParser extends NodeParser {
|
||||
|
||||
parseFunction( source ) {
|
||||
|
||||
return new WGSLNodeFunction( source );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WGSLNodeParser;
|
@ -0,0 +1,321 @@
|
||||
import { Float16BufferAttribute } from 'three';
|
||||
import { GPUInputStepMode } from './WebGPUConstants.js';
|
||||
|
||||
const typedArraysToVertexFormatPrefix = new Map( [
|
||||
[ Int8Array, [ 'sint8', 'snorm8' ]],
|
||||
[ Uint8Array, [ 'uint8', 'unorm8' ]],
|
||||
[ Int16Array, [ 'sint16', 'snorm16' ]],
|
||||
[ Uint16Array, [ 'uint16', 'unorm16' ]],
|
||||
[ Int32Array, [ 'sint32', 'snorm32' ]],
|
||||
[ Uint32Array, [ 'uint32', 'unorm32' ]],
|
||||
[ Float32Array, [ 'float32', ]],
|
||||
] );
|
||||
|
||||
const typedAttributeToVertexFormatPrefix = new Map( [
|
||||
[ Float16BufferAttribute, [ 'float16', ]],
|
||||
] );
|
||||
|
||||
const typeArraysToVertexFormatPrefixForItemSize1 = new Map( [
|
||||
[ Int32Array, 'sint32' ],
|
||||
[ Int16Array, 'sint32' ], // patch for INT16
|
||||
[ Uint32Array, 'uint32' ],
|
||||
[ Uint16Array, 'uint32' ], // patch for UINT16
|
||||
[ Float32Array, 'float32' ]
|
||||
] );
|
||||
|
||||
class WebGPUAttributeUtils {
|
||||
|
||||
constructor( backend ) {
|
||||
|
||||
this.backend = backend;
|
||||
|
||||
}
|
||||
|
||||
createAttribute( attribute, usage ) {
|
||||
|
||||
const bufferAttribute = this._getBufferAttribute( attribute );
|
||||
|
||||
const backend = this.backend;
|
||||
const bufferData = backend.get( bufferAttribute );
|
||||
|
||||
let buffer = bufferData.buffer;
|
||||
|
||||
if ( buffer === undefined ) {
|
||||
|
||||
const device = backend.device;
|
||||
|
||||
let array = bufferAttribute.array;
|
||||
|
||||
// patch for INT16 and UINT16
|
||||
if ( attribute.normalized === false && ( array.constructor === Int16Array || array.constructor === Uint16Array ) ) {
|
||||
|
||||
const tempArray = new Uint32Array( array.length );
|
||||
for ( let i = 0; i < array.length; i ++ ) {
|
||||
|
||||
tempArray[ i ] = array[ i ];
|
||||
|
||||
}
|
||||
|
||||
array = tempArray;
|
||||
|
||||
}
|
||||
|
||||
bufferAttribute.array = array;
|
||||
|
||||
if ( ( bufferAttribute.isStorageBufferAttribute || bufferAttribute.isStorageInstancedBufferAttribute ) && bufferAttribute.itemSize === 3 ) {
|
||||
|
||||
array = new array.constructor( bufferAttribute.count * 4 );
|
||||
|
||||
for ( let i = 0; i < bufferAttribute.count; i ++ ) {
|
||||
|
||||
array.set( bufferAttribute.array.subarray( i * 3, i * 3 + 3 ), i * 4 );
|
||||
|
||||
}
|
||||
|
||||
// Update BufferAttribute
|
||||
bufferAttribute.itemSize = 4;
|
||||
bufferAttribute.array = array;
|
||||
|
||||
}
|
||||
|
||||
const size = array.byteLength + ( ( 4 - ( array.byteLength % 4 ) ) % 4 ); // ensure 4 byte alignment, see #20441
|
||||
|
||||
buffer = device.createBuffer( {
|
||||
label: bufferAttribute.name,
|
||||
size: size,
|
||||
usage: usage,
|
||||
mappedAtCreation: true
|
||||
} );
|
||||
|
||||
new array.constructor( buffer.getMappedRange() ).set( array );
|
||||
|
||||
buffer.unmap();
|
||||
|
||||
bufferData.buffer = buffer;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
updateAttribute( attribute ) {
|
||||
|
||||
const bufferAttribute = this._getBufferAttribute( attribute );
|
||||
|
||||
const backend = this.backend;
|
||||
const device = backend.device;
|
||||
|
||||
const buffer = backend.get( bufferAttribute ).buffer;
|
||||
|
||||
const array = bufferAttribute.array;
|
||||
const updateRanges = bufferAttribute.updateRanges;
|
||||
|
||||
if ( updateRanges.length === 0 ) {
|
||||
|
||||
// Not using update ranges
|
||||
|
||||
device.queue.writeBuffer(
|
||||
buffer,
|
||||
0,
|
||||
array,
|
||||
0
|
||||
);
|
||||
|
||||
} else {
|
||||
|
||||
for ( let i = 0, l = updateRanges.length; i < l; i ++ ) {
|
||||
|
||||
const range = updateRanges[ i ];
|
||||
device.queue.writeBuffer(
|
||||
buffer,
|
||||
0,
|
||||
array,
|
||||
range.start * array.BYTES_PER_ELEMENT,
|
||||
range.count * array.BYTES_PER_ELEMENT
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
bufferAttribute.clearUpdateRanges();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
createShaderVertexBuffers( renderObject ) {
|
||||
|
||||
const attributes = renderObject.getAttributes();
|
||||
const vertexBuffers = new Map();
|
||||
|
||||
for ( let slot = 0; slot < attributes.length; slot ++ ) {
|
||||
|
||||
const geometryAttribute = attributes[ slot ];
|
||||
const bytesPerElement = geometryAttribute.array.BYTES_PER_ELEMENT;
|
||||
const bufferAttribute = this._getBufferAttribute( geometryAttribute );
|
||||
|
||||
let vertexBufferLayout = vertexBuffers.get( bufferAttribute );
|
||||
|
||||
if ( vertexBufferLayout === undefined ) {
|
||||
|
||||
let arrayStride, stepMode;
|
||||
|
||||
if ( geometryAttribute.isInterleavedBufferAttribute === true ) {
|
||||
|
||||
arrayStride = geometryAttribute.data.stride * bytesPerElement;
|
||||
stepMode = geometryAttribute.data.isInstancedInterleavedBuffer ? GPUInputStepMode.Instance : GPUInputStepMode.Vertex;
|
||||
|
||||
} else {
|
||||
|
||||
arrayStride = geometryAttribute.itemSize * bytesPerElement;
|
||||
stepMode = geometryAttribute.isInstancedBufferAttribute ? GPUInputStepMode.Instance : GPUInputStepMode.Vertex;
|
||||
|
||||
}
|
||||
|
||||
// patch for INT16 and UINT16
|
||||
if ( geometryAttribute.normalized === false && ( geometryAttribute.array.constructor === Int16Array || geometryAttribute.array.constructor === Uint16Array ) ) {
|
||||
|
||||
arrayStride = 4;
|
||||
|
||||
}
|
||||
|
||||
vertexBufferLayout = {
|
||||
arrayStride,
|
||||
attributes: [],
|
||||
stepMode
|
||||
};
|
||||
|
||||
vertexBuffers.set( bufferAttribute, vertexBufferLayout );
|
||||
|
||||
}
|
||||
|
||||
const format = this._getVertexFormat( geometryAttribute );
|
||||
const offset = ( geometryAttribute.isInterleavedBufferAttribute === true ) ? geometryAttribute.offset * bytesPerElement : 0;
|
||||
|
||||
vertexBufferLayout.attributes.push( {
|
||||
shaderLocation: slot,
|
||||
offset,
|
||||
format
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
return Array.from( vertexBuffers.values() );
|
||||
|
||||
}
|
||||
|
||||
destroyAttribute( attribute ) {
|
||||
|
||||
const backend = this.backend;
|
||||
const data = backend.get( this._getBufferAttribute( attribute ) );
|
||||
|
||||
data.buffer.destroy();
|
||||
|
||||
backend.delete( attribute );
|
||||
|
||||
}
|
||||
|
||||
async getArrayBufferAsync( attribute ) {
|
||||
|
||||
const backend = this.backend;
|
||||
const device = backend.device;
|
||||
|
||||
const data = backend.get( this._getBufferAttribute( attribute ) );
|
||||
|
||||
const bufferGPU = data.buffer;
|
||||
const size = bufferGPU.size;
|
||||
|
||||
let readBufferGPU = data.readBuffer;
|
||||
let needsUnmap = true;
|
||||
|
||||
if ( readBufferGPU === undefined ) {
|
||||
|
||||
readBufferGPU = device.createBuffer( {
|
||||
label: attribute.name,
|
||||
size,
|
||||
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
|
||||
} );
|
||||
|
||||
needsUnmap = false;
|
||||
|
||||
data.readBuffer = readBufferGPU;
|
||||
|
||||
}
|
||||
|
||||
const cmdEncoder = device.createCommandEncoder( {} );
|
||||
|
||||
cmdEncoder.copyBufferToBuffer(
|
||||
bufferGPU,
|
||||
0,
|
||||
readBufferGPU,
|
||||
0,
|
||||
size
|
||||
);
|
||||
|
||||
if ( needsUnmap ) readBufferGPU.unmap();
|
||||
|
||||
const gpuCommands = cmdEncoder.finish();
|
||||
device.queue.submit( [ gpuCommands ] );
|
||||
|
||||
await readBufferGPU.mapAsync( GPUMapMode.READ );
|
||||
|
||||
const arrayBuffer = readBufferGPU.getMappedRange();
|
||||
|
||||
return arrayBuffer;
|
||||
|
||||
}
|
||||
|
||||
_getVertexFormat( geometryAttribute ) {
|
||||
|
||||
const { itemSize, normalized } = geometryAttribute;
|
||||
const ArrayType = geometryAttribute.array.constructor;
|
||||
const AttributeType = geometryAttribute.constructor;
|
||||
|
||||
let format;
|
||||
|
||||
if ( itemSize == 1 ) {
|
||||
|
||||
format = typeArraysToVertexFormatPrefixForItemSize1.get( ArrayType );
|
||||
|
||||
} else {
|
||||
|
||||
const prefixOptions = typedAttributeToVertexFormatPrefix.get( AttributeType ) || typedArraysToVertexFormatPrefix.get( ArrayType );
|
||||
const prefix = prefixOptions[ normalized ? 1 : 0 ];
|
||||
|
||||
if ( prefix ) {
|
||||
|
||||
const bytesPerUnit = ArrayType.BYTES_PER_ELEMENT * itemSize;
|
||||
const paddedBytesPerUnit = Math.floor( ( bytesPerUnit + 3 ) / 4 ) * 4;
|
||||
const paddedItemSize = paddedBytesPerUnit / ArrayType.BYTES_PER_ELEMENT;
|
||||
|
||||
if ( paddedItemSize % 1 ) {
|
||||
|
||||
throw new Error( 'THREE.WebGPUAttributeUtils: Bad vertex format item size.' );
|
||||
|
||||
}
|
||||
|
||||
format = `${prefix}x${paddedItemSize}`;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( ! format ) {
|
||||
|
||||
console.error( 'THREE.WebGPUAttributeUtils: Vertex format not supported yet.' );
|
||||
|
||||
}
|
||||
|
||||
return format;
|
||||
|
||||
}
|
||||
|
||||
_getBufferAttribute( attribute ) {
|
||||
|
||||
if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
|
||||
|
||||
return attribute;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGPUAttributeUtils;
|
@ -0,0 +1,258 @@
|
||||
import {
|
||||
GPUTextureAspect, GPUTextureViewDimension, GPUBufferBindingType, GPUTextureSampleType
|
||||
} from './WebGPUConstants.js';
|
||||
import { FloatType, IntType, UnsignedIntType } from 'three';
|
||||
|
||||
class WebGPUBindingUtils {
|
||||
|
||||
constructor( backend ) {
|
||||
|
||||
this.backend = backend;
|
||||
|
||||
}
|
||||
|
||||
createBindingsLayout( bindings ) {
|
||||
|
||||
const backend = this.backend;
|
||||
const device = backend.device;
|
||||
|
||||
const entries = [];
|
||||
|
||||
let index = 0;
|
||||
|
||||
for ( const binding of bindings ) {
|
||||
|
||||
const bindingGPU = {
|
||||
binding: index ++,
|
||||
visibility: binding.visibility
|
||||
};
|
||||
|
||||
if ( binding.isUniformBuffer || binding.isStorageBuffer ) {
|
||||
|
||||
const buffer = {}; // GPUBufferBindingLayout
|
||||
|
||||
if ( binding.isStorageBuffer ) {
|
||||
|
||||
buffer.type = GPUBufferBindingType.Storage;
|
||||
|
||||
}
|
||||
|
||||
bindingGPU.buffer = buffer;
|
||||
|
||||
} else if ( binding.isSampler ) {
|
||||
|
||||
const sampler = {}; // GPUSamplerBindingLayout
|
||||
|
||||
if ( binding.texture.isDepthTexture ) {
|
||||
|
||||
if ( binding.texture.compareFunction !== null ) {
|
||||
|
||||
sampler.type = 'comparison';
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bindingGPU.sampler = sampler;
|
||||
|
||||
} else if ( binding.isSampledTexture && binding.texture.isVideoTexture ) {
|
||||
|
||||
bindingGPU.externalTexture = {}; // GPUExternalTextureBindingLayout
|
||||
|
||||
} else if ( binding.isSampledTexture && binding.store ) {
|
||||
|
||||
const format = this.backend.get( binding.texture ).texture.format;
|
||||
|
||||
bindingGPU.storageTexture = { format }; // GPUStorageTextureBindingLayout
|
||||
|
||||
} else if ( binding.isSampledTexture ) {
|
||||
|
||||
const texture = {}; // GPUTextureBindingLayout
|
||||
|
||||
if ( binding.texture.isDepthTexture ) {
|
||||
|
||||
texture.sampleType = GPUTextureSampleType.Depth;
|
||||
|
||||
} else if ( binding.texture.isDataTexture ) {
|
||||
|
||||
const type = binding.texture.type;
|
||||
|
||||
if ( type === IntType ) {
|
||||
|
||||
texture.sampleType = GPUTextureSampleType.SInt;
|
||||
|
||||
} else if ( type === UnsignedIntType ) {
|
||||
|
||||
texture.sampleType = GPUTextureSampleType.UInt;
|
||||
|
||||
} else if ( type === FloatType ) {
|
||||
|
||||
// @TODO: Add support for this soon: backend.hasFeature( 'float32-filterable' )
|
||||
|
||||
texture.sampleType = GPUTextureSampleType.UnfilterableFloat;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( binding.isSampledCubeTexture ) {
|
||||
|
||||
texture.viewDimension = GPUTextureViewDimension.Cube;
|
||||
|
||||
} else if ( binding.texture.isDataArrayTexture ) {
|
||||
|
||||
texture.viewDimension = GPUTextureViewDimension.TwoDArray;
|
||||
|
||||
}
|
||||
|
||||
bindingGPU.texture = texture;
|
||||
|
||||
} else {
|
||||
|
||||
console.error( `WebGPUBindingUtils: Unsupported binding "${ binding }".` );
|
||||
|
||||
}
|
||||
|
||||
entries.push( bindingGPU );
|
||||
|
||||
}
|
||||
|
||||
return device.createBindGroupLayout( { entries } );
|
||||
|
||||
}
|
||||
|
||||
createBindings( bindings ) {
|
||||
|
||||
const backend = this.backend;
|
||||
const bindingsData = backend.get( bindings );
|
||||
|
||||
// setup (static) binding layout and (dynamic) binding group
|
||||
|
||||
const bindLayoutGPU = this.createBindingsLayout( bindings );
|
||||
const bindGroupGPU = this.createBindGroup( bindings, bindLayoutGPU );
|
||||
|
||||
bindingsData.layout = bindLayoutGPU;
|
||||
bindingsData.group = bindGroupGPU;
|
||||
bindingsData.bindings = bindings;
|
||||
|
||||
}
|
||||
|
||||
updateBinding( binding ) {
|
||||
|
||||
const backend = this.backend;
|
||||
const device = backend.device;
|
||||
|
||||
const buffer = binding.buffer;
|
||||
const bufferGPU = backend.get( binding ).buffer;
|
||||
|
||||
device.queue.writeBuffer( bufferGPU, 0, buffer, 0 );
|
||||
|
||||
}
|
||||
|
||||
createBindGroup( bindings, layoutGPU ) {
|
||||
|
||||
const backend = this.backend;
|
||||
const device = backend.device;
|
||||
|
||||
let bindingPoint = 0;
|
||||
const entriesGPU = [];
|
||||
|
||||
for ( const binding of bindings ) {
|
||||
|
||||
if ( binding.isUniformBuffer ) {
|
||||
|
||||
const bindingData = backend.get( binding );
|
||||
|
||||
if ( bindingData.buffer === undefined ) {
|
||||
|
||||
const byteLength = binding.byteLength;
|
||||
|
||||
const usage = GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST;
|
||||
|
||||
const bufferGPU = device.createBuffer( {
|
||||
label: 'bindingBuffer_' + binding.name,
|
||||
size: byteLength,
|
||||
usage: usage
|
||||
} );
|
||||
|
||||
bindingData.buffer = bufferGPU;
|
||||
|
||||
}
|
||||
|
||||
entriesGPU.push( { binding: bindingPoint, resource: { buffer: bindingData.buffer } } );
|
||||
|
||||
} else if ( binding.isStorageBuffer ) {
|
||||
|
||||
const bindingData = backend.get( binding );
|
||||
|
||||
if ( bindingData.buffer === undefined ) {
|
||||
|
||||
const attribute = binding.attribute;
|
||||
//const usage = GPUBufferUsage.STORAGE | GPUBufferUsage.VERTEX | /*GPUBufferUsage.COPY_SRC |*/ GPUBufferUsage.COPY_DST;
|
||||
|
||||
//backend.attributeUtils.createAttribute( attribute, usage ); // @TODO: Move it to universal renderer
|
||||
|
||||
bindingData.buffer = backend.get( attribute ).buffer;
|
||||
|
||||
}
|
||||
|
||||
entriesGPU.push( { binding: bindingPoint, resource: { buffer: bindingData.buffer } } );
|
||||
|
||||
} else if ( binding.isSampler ) {
|
||||
|
||||
const textureGPU = backend.get( binding.texture );
|
||||
|
||||
entriesGPU.push( { binding: bindingPoint, resource: textureGPU.sampler } );
|
||||
|
||||
} else if ( binding.isSampledTexture ) {
|
||||
|
||||
const textureData = backend.get( binding.texture );
|
||||
|
||||
let dimensionViewGPU;
|
||||
|
||||
if ( binding.isSampledCubeTexture ) {
|
||||
|
||||
dimensionViewGPU = GPUTextureViewDimension.Cube;
|
||||
|
||||
} else if ( binding.texture.isDataArrayTexture ) {
|
||||
|
||||
dimensionViewGPU = GPUTextureViewDimension.TwoDArray;
|
||||
|
||||
} else {
|
||||
|
||||
dimensionViewGPU = GPUTextureViewDimension.TwoD;
|
||||
|
||||
}
|
||||
|
||||
let resourceGPU;
|
||||
|
||||
if ( textureData.externalTexture !== undefined ) {
|
||||
|
||||
resourceGPU = device.importExternalTexture( { source: textureData.externalTexture } );
|
||||
|
||||
} else {
|
||||
|
||||
const aspectGPU = GPUTextureAspect.All;
|
||||
|
||||
resourceGPU = textureData.texture.createView( { aspect: aspectGPU, dimension: dimensionViewGPU, mipLevelCount: binding.store ? 1 : textureData.mipLevelCount } );
|
||||
|
||||
}
|
||||
|
||||
entriesGPU.push( { binding: bindingPoint, resource: resourceGPU } );
|
||||
|
||||
}
|
||||
|
||||
bindingPoint ++;
|
||||
|
||||
}
|
||||
|
||||
return device.createBindGroup( {
|
||||
layout: layoutGPU,
|
||||
entries: entriesGPU
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGPUBindingUtils;
|
324
public/sdk/three/jsm/renderers/webgpu/utils/WebGPUConstants.js
Normal file
324
public/sdk/three/jsm/renderers/webgpu/utils/WebGPUConstants.js
Normal file
@ -0,0 +1,324 @@
|
||||
export const GPUPrimitiveTopology = {
|
||||
PointList: 'point-list',
|
||||
LineList: 'line-list',
|
||||
LineStrip: 'line-strip',
|
||||
TriangleList: 'triangle-list',
|
||||
TriangleStrip: 'triangle-strip',
|
||||
};
|
||||
|
||||
export const GPUCompareFunction = {
|
||||
Never: 'never',
|
||||
Less: 'less',
|
||||
Equal: 'equal',
|
||||
LessEqual: 'less-equal',
|
||||
Greater: 'greater',
|
||||
NotEqual: 'not-equal',
|
||||
GreaterEqual: 'greater-equal',
|
||||
Always: 'always'
|
||||
};
|
||||
|
||||
export const GPUStoreOp = {
|
||||
Store: 'store',
|
||||
Discard: 'discard'
|
||||
};
|
||||
|
||||
export const GPULoadOp = {
|
||||
Load: 'load',
|
||||
Clear: 'clear'
|
||||
};
|
||||
|
||||
export const GPUFrontFace = {
|
||||
CCW: 'ccw',
|
||||
CW: 'cw'
|
||||
};
|
||||
|
||||
export const GPUCullMode = {
|
||||
None: 'none',
|
||||
Front: 'front',
|
||||
Back: 'back'
|
||||
};
|
||||
|
||||
export const GPUIndexFormat = {
|
||||
Uint16: 'uint16',
|
||||
Uint32: 'uint32'
|
||||
};
|
||||
|
||||
export const GPUVertexFormat = {
|
||||
Uint8x2: 'uint8x2',
|
||||
Uint8x4: 'uint8x4',
|
||||
Sint8x2: 'sint8x2',
|
||||
Sint8x4: 'sint8x4',
|
||||
Unorm8x2: 'unorm8x2',
|
||||
Unorm8x4: 'unorm8x4',
|
||||
Snorm8x2: 'snorm8x2',
|
||||
Snorm8x4: 'snorm8x4',
|
||||
Uint16x2: 'uint16x2',
|
||||
Uint16x4: 'uint16x4',
|
||||
Sint16x2: 'sint16x2',
|
||||
Sint16x4: 'sint16x4',
|
||||
Unorm16x2: 'unorm16x2',
|
||||
Unorm16x4: 'unorm16x4',
|
||||
Snorm16x2: 'snorm16x2',
|
||||
Snorm16x4: 'snorm16x4',
|
||||
Float16x2: 'float16x2',
|
||||
Float16x4: 'float16x4',
|
||||
Float32: 'float32',
|
||||
Float32x2: 'float32x2',
|
||||
Float32x3: 'float32x3',
|
||||
Float32x4: 'float32x4',
|
||||
Uint32: 'uint32',
|
||||
Uint32x2: 'uint32x2',
|
||||
Uint32x3: 'uint32x3',
|
||||
Uint32x4: 'uint32x4',
|
||||
Sint32: 'sint32',
|
||||
Sint32x2: 'sint32x2',
|
||||
Sint32x3: 'sint32x3',
|
||||
Sint32x4: 'sint32x4'
|
||||
};
|
||||
|
||||
export const GPUTextureFormat = {
|
||||
|
||||
// 8-bit formats
|
||||
|
||||
R8Unorm: 'r8unorm',
|
||||
R8Snorm: 'r8snorm',
|
||||
R8Uint: 'r8uint',
|
||||
R8Sint: 'r8sint',
|
||||
|
||||
// 16-bit formats
|
||||
|
||||
R16Uint: 'r16uint',
|
||||
R16Sint: 'r16sint',
|
||||
R16Float: 'r16float',
|
||||
RG8Unorm: 'rg8unorm',
|
||||
RG8Snorm: 'rg8snorm',
|
||||
RG8Uint: 'rg8uint',
|
||||
RG8Sint: 'rg8sint',
|
||||
|
||||
// 32-bit formats
|
||||
|
||||
R32Uint: 'r32uint',
|
||||
R32Sint: 'r32sint',
|
||||
R32Float: 'r32float',
|
||||
RG16Uint: 'rg16uint',
|
||||
RG16Sint: 'rg16sint',
|
||||
RG16Float: 'rg16float',
|
||||
RGBA8Unorm: 'rgba8unorm',
|
||||
RGBA8UnormSRGB: 'rgba8unorm-srgb',
|
||||
RGBA8Snorm: 'rgba8snorm',
|
||||
RGBA8Uint: 'rgba8uint',
|
||||
RGBA8Sint: 'rgba8sint',
|
||||
BGRA8Unorm: 'bgra8unorm',
|
||||
BGRA8UnormSRGB: 'bgra8unorm-srgb',
|
||||
// Packed 32-bit formats
|
||||
RGB9E5UFloat: 'rgb9e5ufloat',
|
||||
RGB10A2Unorm: 'rgb10a2unorm',
|
||||
RG11B10uFloat: 'rgb10a2unorm',
|
||||
|
||||
// 64-bit formats
|
||||
|
||||
RG32Uint: 'rg32uint',
|
||||
RG32Sint: 'rg32sint',
|
||||
RG32Float: 'rg32float',
|
||||
RGBA16Uint: 'rgba16uint',
|
||||
RGBA16Sint: 'rgba16sint',
|
||||
RGBA16Float: 'rgba16float',
|
||||
|
||||
// 128-bit formats
|
||||
|
||||
RGBA32Uint: 'rgba32uint',
|
||||
RGBA32Sint: 'rgba32sint',
|
||||
RGBA32Float: 'rgba32float',
|
||||
|
||||
// Depth and stencil formats
|
||||
|
||||
Stencil8: 'stencil8',
|
||||
Depth16Unorm: 'depth16unorm',
|
||||
Depth24Plus: 'depth24plus',
|
||||
Depth24PlusStencil8: 'depth24plus-stencil8',
|
||||
Depth32Float: 'depth32float',
|
||||
|
||||
// 'depth32float-stencil8' extension
|
||||
|
||||
Depth32FloatStencil8: 'depth32float-stencil8',
|
||||
|
||||
// BC compressed formats usable if 'texture-compression-bc' is both
|
||||
// supported by the device/user agent and enabled in requestDevice.
|
||||
|
||||
BC1RGBAUnorm: 'bc1-rgba-unorm',
|
||||
BC1RGBAUnormSRGB: 'bc1-rgba-unorm-srgb',
|
||||
BC2RGBAUnorm: 'bc2-rgba-unorm',
|
||||
BC2RGBAUnormSRGB: 'bc2-rgba-unorm-srgb',
|
||||
BC3RGBAUnorm: 'bc3-rgba-unorm',
|
||||
BC3RGBAUnormSRGB: 'bc3-rgba-unorm-srgb',
|
||||
BC4RUnorm: 'bc4-r-unorm',
|
||||
BC4RSnorm: 'bc4-r-snorm',
|
||||
BC5RGUnorm: 'bc5-rg-unorm',
|
||||
BC5RGSnorm: 'bc5-rg-snorm',
|
||||
BC6HRGBUFloat: 'bc6h-rgb-ufloat',
|
||||
BC6HRGBFloat: 'bc6h-rgb-float',
|
||||
BC7RGBAUnorm: 'bc7-rgba-unorm',
|
||||
BC7RGBAUnormSRGB: 'bc7-rgba-srgb',
|
||||
|
||||
// ETC2 compressed formats usable if 'texture-compression-etc2' is both
|
||||
// supported by the device/user agent and enabled in requestDevice.
|
||||
|
||||
ETC2RGB8Unorm: 'etc2-rgb8unorm',
|
||||
ETC2RGB8UnormSRGB: 'etc2-rgb8unorm-srgb',
|
||||
ETC2RGB8A1Unorm: 'etc2-rgb8a1unorm',
|
||||
ETC2RGB8A1UnormSRGB: 'etc2-rgb8a1unorm-srgb',
|
||||
ETC2RGBA8Unorm: 'etc2-rgba8unorm',
|
||||
ETC2RGBA8UnormSRGB: 'etc2-rgba8unorm-srgb',
|
||||
EACR11Unorm: 'eac-r11unorm',
|
||||
EACR11Snorm: 'eac-r11snorm',
|
||||
EACRG11Unorm: 'eac-rg11unorm',
|
||||
EACRG11Snorm: 'eac-rg11snorm',
|
||||
|
||||
// ASTC compressed formats usable if 'texture-compression-astc' is both
|
||||
// supported by the device/user agent and enabled in requestDevice.
|
||||
|
||||
ASTC4x4Unorm: 'astc-4x4-unorm',
|
||||
ASTC4x4UnormSRGB: 'astc-4x4-unorm-srgb',
|
||||
ASTC5x4Unorm: 'astc-5x4-unorm',
|
||||
ASTC5x4UnormSRGB: 'astc-5x4-unorm-srgb',
|
||||
ASTC5x5Unorm: 'astc-5x5-unorm',
|
||||
ASTC5x5UnormSRGB: 'astc-5x5-unorm-srgb',
|
||||
ASTC6x5Unorm: 'astc-6x5-unorm',
|
||||
ASTC6x5UnormSRGB: 'astc-6x5-unorm-srgb',
|
||||
ASTC6x6Unorm: 'astc-6x6-unorm',
|
||||
ASTC6x6UnormSRGB: 'astc-6x6-unorm-srgb',
|
||||
ASTC8x5Unorm: 'astc-8x5-unorm',
|
||||
ASTC8x5UnormSRGB: 'astc-8x5-unorm-srgb',
|
||||
ASTC8x6Unorm: 'astc-8x6-unorm',
|
||||
ASTC8x6UnormSRGB: 'astc-8x6-unorm-srgb',
|
||||
ASTC8x8Unorm: 'astc-8x8-unorm',
|
||||
ASTC8x8UnormSRGB: 'astc-8x8-unorm-srgb',
|
||||
ASTC10x5Unorm: 'astc-10x5-unorm',
|
||||
ASTC10x5UnormSRGB: 'astc-10x5-unorm-srgb',
|
||||
ASTC10x6Unorm: 'astc-10x6-unorm',
|
||||
ASTC10x6UnormSRGB: 'astc-10x6-unorm-srgb',
|
||||
ASTC10x8Unorm: 'astc-10x8-unorm',
|
||||
ASTC10x8UnormSRGB: 'astc-10x8-unorm-srgb',
|
||||
ASTC10x10Unorm: 'astc-10x10-unorm',
|
||||
ASTC10x10UnormSRGB: 'astc-10x10-unorm-srgb',
|
||||
ASTC12x10Unorm: 'astc-12x10-unorm',
|
||||
ASTC12x10UnormSRGB: 'astc-12x10-unorm-srgb',
|
||||
ASTC12x12Unorm: 'astc-12x12-unorm',
|
||||
ASTC12x12UnormSRGB: 'astc-12x12-unorm-srgb',
|
||||
|
||||
};
|
||||
|
||||
export const GPUAddressMode = {
|
||||
ClampToEdge: 'clamp-to-edge',
|
||||
Repeat: 'repeat',
|
||||
MirrorRepeat: 'mirror-repeat'
|
||||
};
|
||||
|
||||
export const GPUFilterMode = {
|
||||
Linear: 'linear',
|
||||
Nearest: 'nearest'
|
||||
};
|
||||
|
||||
export const GPUBlendFactor = {
|
||||
Zero: 'zero',
|
||||
One: 'one',
|
||||
Src: 'src',
|
||||
OneMinusSrc: 'one-minus-src',
|
||||
SrcAlpha: 'src-alpha',
|
||||
OneMinusSrcAlpha: 'one-minus-src-alpha',
|
||||
Dst: 'dst',
|
||||
OneMinusDstColor: 'one-minus-dst',
|
||||
DstAlpha: 'dst-alpha',
|
||||
OneMinusDstAlpha: 'one-minus-dst-alpha',
|
||||
SrcAlphaSaturated: 'src-alpha-saturated',
|
||||
Constant: 'constant',
|
||||
OneMinusConstant: 'one-minus-constant'
|
||||
};
|
||||
|
||||
export const GPUBlendOperation = {
|
||||
Add: 'add',
|
||||
Subtract: 'subtract',
|
||||
ReverseSubtract: 'reverse-subtract',
|
||||
Min: 'min',
|
||||
Max: 'max'
|
||||
};
|
||||
|
||||
export const GPUColorWriteFlags = {
|
||||
None: 0,
|
||||
Red: 0x1,
|
||||
Green: 0x2,
|
||||
Blue: 0x4,
|
||||
Alpha: 0x8,
|
||||
All: 0xF
|
||||
};
|
||||
|
||||
export const GPUStencilOperation = {
|
||||
Keep: 'keep',
|
||||
Zero: 'zero',
|
||||
Replace: 'replace',
|
||||
Invert: 'invert',
|
||||
IncrementClamp: 'increment-clamp',
|
||||
DecrementClamp: 'decrement-clamp',
|
||||
IncrementWrap: 'increment-wrap',
|
||||
DecrementWrap: 'decrement-wrap'
|
||||
};
|
||||
|
||||
export const GPUBufferBindingType = {
|
||||
Uniform: 'uniform',
|
||||
Storage: 'storage',
|
||||
ReadOnlyStorage: 'read-only-storage'
|
||||
};
|
||||
|
||||
export const GPUSamplerBindingType = {
|
||||
Filtering: 'filtering',
|
||||
NonFiltering: 'non-filtering',
|
||||
Comparison: 'comparison'
|
||||
};
|
||||
|
||||
export const GPUTextureSampleType = {
|
||||
Float: 'float',
|
||||
UnfilterableFloat: 'unfilterable-float',
|
||||
Depth: 'depth',
|
||||
SInt: 'sint',
|
||||
UInt: 'uint'
|
||||
};
|
||||
|
||||
export const GPUTextureDimension = {
|
||||
OneD: '1d',
|
||||
TwoD: '2d',
|
||||
ThreeD: '3d'
|
||||
};
|
||||
|
||||
export const GPUTextureViewDimension = {
|
||||
OneD: '1d',
|
||||
TwoD: '2d',
|
||||
TwoDArray: '2d-array',
|
||||
Cube: 'cube',
|
||||
CubeArray: 'cube-array',
|
||||
ThreeD: '3d'
|
||||
};
|
||||
|
||||
export const GPUTextureAspect = {
|
||||
All: 'all',
|
||||
StencilOnly: 'stencil-only',
|
||||
DepthOnly: 'depth-only'
|
||||
};
|
||||
|
||||
export const GPUInputStepMode = {
|
||||
Vertex: 'vertex',
|
||||
Instance: 'instance'
|
||||
};
|
||||
|
||||
export const GPUFeatureName = {
|
||||
DepthClipControl: 'depth-clip-control',
|
||||
Depth32FloatStencil8: 'depth32float-stencil8',
|
||||
TextureCompressionBC: 'texture-compression-bc',
|
||||
TextureCompressionETC2: 'texture-compression-etc2',
|
||||
TextureCompressionASTC: 'texture-compression-astc',
|
||||
TimestampQuery: 'timestamp-query',
|
||||
IndirectFirstInstance: 'indirect-first-instance',
|
||||
ShaderF16: 'shader-f16',
|
||||
RG11B10UFloat: 'rg11b10ufloat-renderable',
|
||||
BGRA8UNormStorage: 'bgra8unorm-storage',
|
||||
Float32Filterable: 'float32-filterable'
|
||||
};
|
@ -0,0 +1,591 @@
|
||||
import { BlendColorFactor, OneMinusBlendColorFactor, } from '../../common/Constants.js';
|
||||
|
||||
import {
|
||||
GPUFrontFace, GPUCullMode, GPUColorWriteFlags, GPUCompareFunction, GPUBlendFactor, GPUBlendOperation, GPUIndexFormat, GPUStencilOperation
|
||||
} from './WebGPUConstants.js';
|
||||
|
||||
import {
|
||||
FrontSide, BackSide, DoubleSide,
|
||||
NeverDepth, AlwaysDepth, LessDepth, LessEqualDepth, EqualDepth, GreaterEqualDepth, GreaterDepth, NotEqualDepth,
|
||||
NoBlending, NormalBlending, AdditiveBlending, SubtractiveBlending, MultiplyBlending, CustomBlending,
|
||||
ZeroFactor, OneFactor, SrcColorFactor, OneMinusSrcColorFactor, SrcAlphaFactor, OneMinusSrcAlphaFactor, DstColorFactor,
|
||||
OneMinusDstColorFactor, DstAlphaFactor, OneMinusDstAlphaFactor, SrcAlphaSaturateFactor,
|
||||
AddEquation, SubtractEquation, ReverseSubtractEquation, MinEquation, MaxEquation,
|
||||
KeepStencilOp, ZeroStencilOp, ReplaceStencilOp, InvertStencilOp, IncrementStencilOp, DecrementStencilOp, IncrementWrapStencilOp, DecrementWrapStencilOp,
|
||||
NeverStencilFunc, AlwaysStencilFunc, LessStencilFunc, LessEqualStencilFunc, EqualStencilFunc, GreaterEqualStencilFunc, GreaterStencilFunc, NotEqualStencilFunc
|
||||
} from 'three';
|
||||
|
||||
class WebGPUPipelineUtils {
|
||||
|
||||
constructor( backend ) {
|
||||
|
||||
this.backend = backend;
|
||||
|
||||
}
|
||||
|
||||
createRenderPipeline( renderObject, promises ) {
|
||||
|
||||
const { object, material, geometry, pipeline } = renderObject;
|
||||
const { vertexProgram, fragmentProgram } = pipeline;
|
||||
|
||||
const backend = this.backend;
|
||||
const device = backend.device;
|
||||
const utils = backend.utils;
|
||||
|
||||
const pipelineData = backend.get( pipeline );
|
||||
const bindingsData = backend.get( renderObject.getBindings() );
|
||||
|
||||
// vertex buffers
|
||||
|
||||
const vertexBuffers = backend.attributeUtils.createShaderVertexBuffers( renderObject );
|
||||
|
||||
// blending
|
||||
|
||||
let blending;
|
||||
|
||||
if ( material.transparent === true && material.blending !== NoBlending ) {
|
||||
|
||||
blending = this._getBlending( material );
|
||||
|
||||
}
|
||||
|
||||
// stencil
|
||||
|
||||
let stencilFront = {};
|
||||
|
||||
if ( material.stencilWrite === true ) {
|
||||
|
||||
stencilFront = {
|
||||
compare: this._getStencilCompare( material ),
|
||||
failOp: this._getStencilOperation( material.stencilFail ),
|
||||
depthFailOp: this._getStencilOperation( material.stencilZFail ),
|
||||
passOp: this._getStencilOperation( material.stencilZPass )
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
const colorWriteMask = this._getColorWriteMask( material );
|
||||
|
||||
const targets = [];
|
||||
|
||||
if ( renderObject.context.textures !== null ) {
|
||||
|
||||
const textures = renderObject.context.textures;
|
||||
|
||||
for ( let i = 0; i < textures.length; i ++ ) {
|
||||
|
||||
const colorFormat = utils.getTextureFormatGPU( textures[ i ] );
|
||||
|
||||
targets.push( {
|
||||
format: colorFormat,
|
||||
blend: blending,
|
||||
writeMask: colorWriteMask
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
const colorFormat = utils.getCurrentColorFormat( renderObject.context );
|
||||
|
||||
targets.push( {
|
||||
format: colorFormat,
|
||||
blend: blending,
|
||||
writeMask: colorWriteMask
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
const vertexModule = backend.get( vertexProgram ).module;
|
||||
const fragmentModule = backend.get( fragmentProgram ).module;
|
||||
|
||||
const primitiveState = this._getPrimitiveState( object, geometry, material );
|
||||
const depthCompare = this._getDepthCompare( material );
|
||||
const depthStencilFormat = utils.getCurrentDepthStencilFormat( renderObject.context );
|
||||
let sampleCount = utils.getSampleCount( renderObject.context );
|
||||
|
||||
if ( sampleCount > 1 ) {
|
||||
|
||||
// WebGPU only supports power-of-two sample counts and 2 is not a valid value
|
||||
sampleCount = Math.pow( 2, Math.floor( Math.log2( sampleCount ) ) );
|
||||
|
||||
if ( sampleCount === 2 ) {
|
||||
|
||||
sampleCount = 4;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const pipelineDescriptor = {
|
||||
vertex: Object.assign( {}, vertexModule, { buffers: vertexBuffers } ),
|
||||
fragment: Object.assign( {}, fragmentModule, { targets } ),
|
||||
primitive: primitiveState,
|
||||
depthStencil: {
|
||||
format: depthStencilFormat,
|
||||
depthWriteEnabled: material.depthWrite,
|
||||
depthCompare: depthCompare,
|
||||
stencilFront: stencilFront,
|
||||
stencilBack: {}, // three.js does not provide an API to configure the back function (gl.stencilFuncSeparate() was never used)
|
||||
stencilReadMask: material.stencilFuncMask,
|
||||
stencilWriteMask: material.stencilWriteMask
|
||||
},
|
||||
multisample: {
|
||||
count: sampleCount,
|
||||
alphaToCoverageEnabled: material.alphaToCoverage
|
||||
},
|
||||
layout: device.createPipelineLayout( {
|
||||
bindGroupLayouts: [ bindingsData.layout ]
|
||||
} )
|
||||
};
|
||||
|
||||
if ( promises === null ) {
|
||||
|
||||
pipelineData.pipeline = device.createRenderPipeline( pipelineDescriptor );
|
||||
|
||||
} else {
|
||||
|
||||
const p = new Promise( ( resolve /*, reject*/ ) => {
|
||||
|
||||
device.createRenderPipelineAsync( pipelineDescriptor ).then( pipeline => {
|
||||
|
||||
pipelineData.pipeline = pipeline;
|
||||
resolve();
|
||||
|
||||
} );
|
||||
|
||||
} );
|
||||
|
||||
promises.push( p );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
createComputePipeline( pipeline, bindings ) {
|
||||
|
||||
const backend = this.backend;
|
||||
const device = backend.device;
|
||||
|
||||
const computeProgram = backend.get( pipeline.computeProgram ).module;
|
||||
|
||||
const pipelineGPU = backend.get( pipeline );
|
||||
const bindingsData = backend.get( bindings );
|
||||
|
||||
pipelineGPU.pipeline = device.createComputePipeline( {
|
||||
compute: computeProgram,
|
||||
layout: device.createPipelineLayout( {
|
||||
bindGroupLayouts: [ bindingsData.layout ]
|
||||
} )
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
_getBlending( material ) {
|
||||
|
||||
let color, alpha;
|
||||
|
||||
const blending = material.blending;
|
||||
|
||||
if ( blending === CustomBlending ) {
|
||||
|
||||
const blendSrcAlpha = material.blendSrcAlpha !== null ? material.blendSrcAlpha : GPUBlendFactor.One;
|
||||
const blendDstAlpha = material.blendDstAlpha !== null ? material.blendDstAlpha : GPUBlendFactor.Zero;
|
||||
const blendEquationAlpha = material.blendEquationAlpha !== null ? material.blendEquationAlpha : GPUBlendFactor.Add;
|
||||
|
||||
color = {
|
||||
srcFactor: this._getBlendFactor( material.blendSrc ),
|
||||
dstFactor: this._getBlendFactor( material.blendDst ),
|
||||
operation: this._getBlendOperation( material.blendEquation )
|
||||
};
|
||||
|
||||
alpha = {
|
||||
srcFactor: this._getBlendFactor( blendSrcAlpha ),
|
||||
dstFactor: this._getBlendFactor( blendDstAlpha ),
|
||||
operation: this._getBlendOperation( blendEquationAlpha )
|
||||
};
|
||||
|
||||
} else {
|
||||
|
||||
const premultipliedAlpha = material.premultipliedAlpha;
|
||||
|
||||
const setBlend = ( srcRGB, dstRGB, srcAlpha, dstAlpha ) => {
|
||||
|
||||
color = {
|
||||
srcFactor: srcRGB,
|
||||
dstFactor: dstRGB,
|
||||
operation: GPUBlendOperation.Add
|
||||
};
|
||||
|
||||
alpha = {
|
||||
srcFactor: srcAlpha,
|
||||
dstFactor: dstAlpha,
|
||||
operation: GPUBlendOperation.Add
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
if ( premultipliedAlpha ) {
|
||||
|
||||
switch ( blending ) {
|
||||
|
||||
case NormalBlending:
|
||||
setBlend( GPUBlendFactor.SrcAlpha, GPUBlendFactor.OneMinusSrcAlpha, GPUBlendFactor.One, GPUBlendFactor.OneMinusSrcAlpha );
|
||||
break;
|
||||
|
||||
case AdditiveBlending:
|
||||
setBlend( GPUBlendFactor.SrcAlpha, GPUBlendFactor.One, GPUBlendFactor.One, GPUBlendFactor.One );
|
||||
break;
|
||||
|
||||
case SubtractiveBlending:
|
||||
setBlend( GPUBlendFactor.Zero, GPUBlendFactor.OneMinusSrc, GPUBlendFactor.Zero, GPUBlendFactor.One );
|
||||
break;
|
||||
|
||||
case MultiplyBlending:
|
||||
setBlend( GPUBlendFactor.Zero, GPUBlendFactor.Src, GPUBlendFactor.Zero, GPUBlendFactor.SrcAlpha );
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
switch ( blending ) {
|
||||
|
||||
case NormalBlending:
|
||||
setBlend( GPUBlendFactor.SrcAlpha, GPUBlendFactor.OneMinusSrcAlpha, GPUBlendFactor.One, GPUBlendFactor.OneMinusSrcAlpha );
|
||||
break;
|
||||
|
||||
case AdditiveBlending:
|
||||
setBlend( GPUBlendFactor.SrcAlpha, GPUBlendFactor.One, GPUBlendFactor.SrcAlpha, GPUBlendFactor.One );
|
||||
break;
|
||||
|
||||
case SubtractiveBlending:
|
||||
setBlend( GPUBlendFactor.Zero, GPUBlendFactor.OneMinusSrc, GPUBlendFactor.Zero, GPUBlendFactor.One );
|
||||
break;
|
||||
|
||||
case MultiplyBlending:
|
||||
setBlend( GPUBlendFactor.Zero, GPUBlendFactor.Src, GPUBlendFactor.Zero, GPUBlendFactor.Src );
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( color !== undefined && alpha !== undefined ) {
|
||||
|
||||
return { color, alpha };
|
||||
|
||||
} else {
|
||||
|
||||
console.error( 'THREE.WebGPURenderer: Invalid blending: ', blending );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_getBlendFactor( blend ) {
|
||||
|
||||
let blendFactor;
|
||||
|
||||
switch ( blend ) {
|
||||
|
||||
case ZeroFactor:
|
||||
blendFactor = GPUBlendFactor.Zero;
|
||||
break;
|
||||
|
||||
case OneFactor:
|
||||
blendFactor = GPUBlendFactor.One;
|
||||
break;
|
||||
|
||||
case SrcColorFactor:
|
||||
blendFactor = GPUBlendFactor.Src;
|
||||
break;
|
||||
|
||||
case OneMinusSrcColorFactor:
|
||||
blendFactor = GPUBlendFactor.OneMinusSrc;
|
||||
break;
|
||||
|
||||
case SrcAlphaFactor:
|
||||
blendFactor = GPUBlendFactor.SrcAlpha;
|
||||
break;
|
||||
|
||||
case OneMinusSrcAlphaFactor:
|
||||
blendFactor = GPUBlendFactor.OneMinusSrcAlpha;
|
||||
break;
|
||||
|
||||
case DstColorFactor:
|
||||
blendFactor = GPUBlendFactor.Dst;
|
||||
break;
|
||||
|
||||
case OneMinusDstColorFactor:
|
||||
blendFactor = GPUBlendFactor.OneMinusDstColor;
|
||||
break;
|
||||
|
||||
case DstAlphaFactor:
|
||||
blendFactor = GPUBlendFactor.DstAlpha;
|
||||
break;
|
||||
|
||||
case OneMinusDstAlphaFactor:
|
||||
blendFactor = GPUBlendFactor.OneMinusDstAlpha;
|
||||
break;
|
||||
|
||||
case SrcAlphaSaturateFactor:
|
||||
blendFactor = GPUBlendFactor.SrcAlphaSaturated;
|
||||
break;
|
||||
|
||||
case BlendColorFactor:
|
||||
blendFactor = GPUBlendFactor.Constant;
|
||||
break;
|
||||
|
||||
case OneMinusBlendColorFactor:
|
||||
blendFactor = GPUBlendFactor.OneMinusConstant;
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error( 'THREE.WebGPURenderer: Blend factor not supported.', blend );
|
||||
|
||||
}
|
||||
|
||||
return blendFactor;
|
||||
|
||||
}
|
||||
|
||||
_getStencilCompare( material ) {
|
||||
|
||||
let stencilCompare;
|
||||
|
||||
const stencilFunc = material.stencilFunc;
|
||||
|
||||
switch ( stencilFunc ) {
|
||||
|
||||
case NeverStencilFunc:
|
||||
stencilCompare = GPUCompareFunction.Never;
|
||||
break;
|
||||
|
||||
case AlwaysStencilFunc:
|
||||
stencilCompare = GPUCompareFunction.Always;
|
||||
break;
|
||||
|
||||
case LessStencilFunc:
|
||||
stencilCompare = GPUCompareFunction.Less;
|
||||
break;
|
||||
|
||||
case LessEqualStencilFunc:
|
||||
stencilCompare = GPUCompareFunction.LessEqual;
|
||||
break;
|
||||
|
||||
case EqualStencilFunc:
|
||||
stencilCompare = GPUCompareFunction.Equal;
|
||||
break;
|
||||
|
||||
case GreaterEqualStencilFunc:
|
||||
stencilCompare = GPUCompareFunction.GreaterEqual;
|
||||
break;
|
||||
|
||||
case GreaterStencilFunc:
|
||||
stencilCompare = GPUCompareFunction.Greater;
|
||||
break;
|
||||
|
||||
case NotEqualStencilFunc:
|
||||
stencilCompare = GPUCompareFunction.NotEqual;
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error( 'THREE.WebGPURenderer: Invalid stencil function.', stencilFunc );
|
||||
|
||||
}
|
||||
|
||||
return stencilCompare;
|
||||
|
||||
}
|
||||
|
||||
_getStencilOperation( op ) {
|
||||
|
||||
let stencilOperation;
|
||||
|
||||
switch ( op ) {
|
||||
|
||||
case KeepStencilOp:
|
||||
stencilOperation = GPUStencilOperation.Keep;
|
||||
break;
|
||||
|
||||
case ZeroStencilOp:
|
||||
stencilOperation = GPUStencilOperation.Zero;
|
||||
break;
|
||||
|
||||
case ReplaceStencilOp:
|
||||
stencilOperation = GPUStencilOperation.Replace;
|
||||
break;
|
||||
|
||||
case InvertStencilOp:
|
||||
stencilOperation = GPUStencilOperation.Invert;
|
||||
break;
|
||||
|
||||
case IncrementStencilOp:
|
||||
stencilOperation = GPUStencilOperation.IncrementClamp;
|
||||
break;
|
||||
|
||||
case DecrementStencilOp:
|
||||
stencilOperation = GPUStencilOperation.DecrementClamp;
|
||||
break;
|
||||
|
||||
case IncrementWrapStencilOp:
|
||||
stencilOperation = GPUStencilOperation.IncrementWrap;
|
||||
break;
|
||||
|
||||
case DecrementWrapStencilOp:
|
||||
stencilOperation = GPUStencilOperation.DecrementWrap;
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error( 'THREE.WebGPURenderer: Invalid stencil operation.', stencilOperation );
|
||||
|
||||
}
|
||||
|
||||
return stencilOperation;
|
||||
|
||||
}
|
||||
|
||||
_getBlendOperation( blendEquation ) {
|
||||
|
||||
let blendOperation;
|
||||
|
||||
switch ( blendEquation ) {
|
||||
|
||||
case AddEquation:
|
||||
blendOperation = GPUBlendOperation.Add;
|
||||
break;
|
||||
|
||||
case SubtractEquation:
|
||||
blendOperation = GPUBlendOperation.Subtract;
|
||||
break;
|
||||
|
||||
case ReverseSubtractEquation:
|
||||
blendOperation = GPUBlendOperation.ReverseSubtract;
|
||||
break;
|
||||
|
||||
case MinEquation:
|
||||
blendOperation = GPUBlendOperation.Min;
|
||||
break;
|
||||
|
||||
case MaxEquation:
|
||||
blendOperation = GPUBlendOperation.Max;
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error( 'THREE.WebGPUPipelineUtils: Blend equation not supported.', blendEquation );
|
||||
|
||||
}
|
||||
|
||||
return blendOperation;
|
||||
|
||||
}
|
||||
|
||||
_getPrimitiveState( object, geometry, material ) {
|
||||
|
||||
const descriptor = {};
|
||||
const utils = this.backend.utils;
|
||||
|
||||
descriptor.topology = utils.getPrimitiveTopology( object, material );
|
||||
|
||||
if ( geometry.index !== null && object.isLine === true && object.isLineSegments !== true ) {
|
||||
|
||||
descriptor.stripIndexFormat = ( geometry.index.array instanceof Uint16Array ) ? GPUIndexFormat.Uint16 : GPUIndexFormat.Uint32;
|
||||
|
||||
}
|
||||
|
||||
switch ( material.side ) {
|
||||
|
||||
case FrontSide:
|
||||
descriptor.frontFace = GPUFrontFace.CCW;
|
||||
descriptor.cullMode = GPUCullMode.Back;
|
||||
break;
|
||||
|
||||
case BackSide:
|
||||
descriptor.frontFace = GPUFrontFace.CCW;
|
||||
descriptor.cullMode = GPUCullMode.Front;
|
||||
break;
|
||||
|
||||
case DoubleSide:
|
||||
descriptor.frontFace = GPUFrontFace.CCW;
|
||||
descriptor.cullMode = GPUCullMode.None;
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error( 'THREE.WebGPUPipelineUtils: Unknown material.side value.', material.side );
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return descriptor;
|
||||
|
||||
}
|
||||
|
||||
_getColorWriteMask( material ) {
|
||||
|
||||
return ( material.colorWrite === true ) ? GPUColorWriteFlags.All : GPUColorWriteFlags.None;
|
||||
|
||||
}
|
||||
|
||||
_getDepthCompare( material ) {
|
||||
|
||||
let depthCompare;
|
||||
|
||||
if ( material.depthTest === false ) {
|
||||
|
||||
depthCompare = GPUCompareFunction.Always;
|
||||
|
||||
} else {
|
||||
|
||||
const depthFunc = material.depthFunc;
|
||||
|
||||
switch ( depthFunc ) {
|
||||
|
||||
case NeverDepth:
|
||||
depthCompare = GPUCompareFunction.Never;
|
||||
break;
|
||||
|
||||
case AlwaysDepth:
|
||||
depthCompare = GPUCompareFunction.Always;
|
||||
break;
|
||||
|
||||
case LessDepth:
|
||||
depthCompare = GPUCompareFunction.Less;
|
||||
break;
|
||||
|
||||
case LessEqualDepth:
|
||||
depthCompare = GPUCompareFunction.LessEqual;
|
||||
break;
|
||||
|
||||
case EqualDepth:
|
||||
depthCompare = GPUCompareFunction.Equal;
|
||||
break;
|
||||
|
||||
case GreaterEqualDepth:
|
||||
depthCompare = GPUCompareFunction.GreaterEqual;
|
||||
break;
|
||||
|
||||
case GreaterDepth:
|
||||
depthCompare = GPUCompareFunction.Greater;
|
||||
break;
|
||||
|
||||
case NotEqualDepth:
|
||||
depthCompare = GPUCompareFunction.NotEqual;
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error( 'THREE.WebGPUPipelineUtils: Invalid depth function.', depthFunc );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return depthCompare;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGPUPipelineUtils;
|
@ -0,0 +1,285 @@
|
||||
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;
|
1114
public/sdk/three/jsm/renderers/webgpu/utils/WebGPUTextureUtils.js
Normal file
1114
public/sdk/three/jsm/renderers/webgpu/utils/WebGPUTextureUtils.js
Normal file
File diff suppressed because it is too large
Load Diff
93
public/sdk/three/jsm/renderers/webgpu/utils/WebGPUUtils.js
Normal file
93
public/sdk/three/jsm/renderers/webgpu/utils/WebGPUUtils.js
Normal file
@ -0,0 +1,93 @@
|
||||
import { GPUPrimitiveTopology, GPUTextureFormat } from './WebGPUConstants.js';
|
||||
|
||||
class WebGPUUtils {
|
||||
|
||||
constructor( backend ) {
|
||||
|
||||
this.backend = backend;
|
||||
|
||||
}
|
||||
|
||||
getCurrentDepthStencilFormat( renderContext ) {
|
||||
|
||||
let format;
|
||||
|
||||
if ( renderContext.depthTexture !== null ) {
|
||||
|
||||
format = this.getTextureFormatGPU( renderContext.depthTexture );
|
||||
|
||||
} else if ( renderContext.depth && renderContext.stencil ) {
|
||||
|
||||
format = GPUTextureFormat.Depth24PlusStencil8;
|
||||
|
||||
} else if ( renderContext.depth ) {
|
||||
|
||||
format = GPUTextureFormat.Depth24Plus;
|
||||
|
||||
}
|
||||
|
||||
return format;
|
||||
|
||||
}
|
||||
|
||||
getTextureFormatGPU( texture ) {
|
||||
|
||||
return this.backend.get( texture ).texture.format;
|
||||
|
||||
}
|
||||
|
||||
getCurrentColorFormat( renderContext ) {
|
||||
|
||||
let format;
|
||||
|
||||
if ( renderContext.textures !== null ) {
|
||||
|
||||
format = this.getTextureFormatGPU( renderContext.textures[ 0 ] );
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
format = GPUTextureFormat.BGRA8Unorm; // default context format
|
||||
|
||||
}
|
||||
|
||||
return format;
|
||||
|
||||
}
|
||||
|
||||
getCurrentColorSpace( renderContext ) {
|
||||
|
||||
if ( renderContext.textures !== null ) {
|
||||
|
||||
return renderContext.textures[ 0 ].colorSpace;
|
||||
|
||||
}
|
||||
|
||||
return this.backend.renderer.outputColorSpace;
|
||||
|
||||
}
|
||||
|
||||
getPrimitiveTopology( object, material ) {
|
||||
|
||||
if ( object.isPoints ) return GPUPrimitiveTopology.PointList;
|
||||
else if ( object.isLineSegments || ( object.isMesh && material.wireframe === true ) ) return GPUPrimitiveTopology.LineList;
|
||||
else if ( object.isLine ) return GPUPrimitiveTopology.LineStrip;
|
||||
else if ( object.isMesh ) return GPUPrimitiveTopology.TriangleList;
|
||||
|
||||
}
|
||||
|
||||
getSampleCount( renderContext ) {
|
||||
|
||||
if ( renderContext.textures !== null ) {
|
||||
|
||||
return renderContext.sampleCount;
|
||||
|
||||
}
|
||||
|
||||
return this.backend.parameters.sampleCount;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGPUUtils;
|
Reference in New Issue
Block a user