Initial commit
This commit is contained in:
1085
node_modules/three/examples/jsm/renderers/webgpu/WebGPUBackend.js
generated
vendored
Normal file
1085
node_modules/three/examples/jsm/renderers/webgpu/WebGPUBackend.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
48
node_modules/three/examples/jsm/renderers/webgpu/WebGPURenderer.js
generated
vendored
Normal file
48
node_modules/three/examples/jsm/renderers/webgpu/WebGPURenderer.js
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
import Renderer from '../common/Renderer.js';
|
||||
import WebGLBackend from '../webgl/WebGLBackend.js';
|
||||
import WebGPUBackend from './WebGPUBackend.js';
|
||||
import WebGPU from '../../capabilities/WebGPU.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 ( 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 );
|
||||
|
||||
this.isWebGPURenderer = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGPURenderer;
|
||||
967
node_modules/three/examples/jsm/renderers/webgpu/nodes/WGSLNodeBuilder.js
generated
vendored
Normal file
967
node_modules/three/examples/jsm/renderers/webgpu/nodes/WGSLNodeBuilder.js
generated
vendored
Normal file
@@ -0,0 +1,967 @@
|
||||
import { NoColorSpace, FloatType } from 'three';
|
||||
|
||||
import UniformsGroup from '../../common/UniformsGroup.js';
|
||||
|
||||
import NodeSampler from '../../common/nodes/NodeSampler.js';
|
||||
import { NodeSampledTexture, NodeSampledCubeTexture } from '../../common/nodes/NodeSampledTexture.js';
|
||||
|
||||
import UniformBuffer from '../../common/UniformBuffer.js';
|
||||
import StorageBuffer from '../../common/StorageBuffer.js';
|
||||
import { getVectorLength, getStrideLength } from '../../common/BufferUtils.js';
|
||||
|
||||
import { NodeBuilder, CodeNode, NodeMaterial, FunctionNode } from '../../../nodes/Nodes.js';
|
||||
|
||||
import { getFormat } from '../utils/WebGPUTextureUtils.js';
|
||||
|
||||
import WGSLNodeParser from './WGSLNodeParser.js';
|
||||
|
||||
const gpuShaderStageLib = {
|
||||
'vertex': GPUShaderStage.VERTEX,
|
||||
'fragment': GPUShaderStage.FRAGMENT,
|
||||
'compute': GPUShaderStage.COMPUTE
|
||||
};
|
||||
|
||||
const supports = {
|
||||
instance: true
|
||||
};
|
||||
|
||||
const wgslTypeLib = {
|
||||
float: 'f32',
|
||||
int: 'i32',
|
||||
uint: 'u32',
|
||||
bool: 'bool',
|
||||
color: 'vec3<f32>',
|
||||
|
||||
vec2: 'vec2<f32>',
|
||||
ivec2: 'vec2<i32>',
|
||||
uvec2: 'vec2<u32>',
|
||||
bvec2: 'vec2<bool>',
|
||||
|
||||
vec3: 'vec3<f32>',
|
||||
ivec3: 'vec3<i32>',
|
||||
uvec3: 'vec3<u32>',
|
||||
bvec3: 'vec3<bool>',
|
||||
|
||||
vec4: 'vec4<f32>',
|
||||
ivec4: 'vec4<i32>',
|
||||
uvec4: 'vec4<u32>',
|
||||
bvec4: 'vec4<bool>',
|
||||
|
||||
mat3: 'mat3x3<f32>',
|
||||
imat3: 'mat3x3<i32>',
|
||||
umat3: 'mat3x3<u32>',
|
||||
bmat3: 'mat3x3<bool>',
|
||||
|
||||
mat4: 'mat4x4<f32>',
|
||||
imat4: 'mat4x4<i32>',
|
||||
umat4: 'mat4x4<u32>',
|
||||
bmat4: 'mat4x4<bool>'
|
||||
};
|
||||
|
||||
const wgslMethods = {
|
||||
dFdx: 'dpdx',
|
||||
dFdy: '- dpdy',
|
||||
mod: 'threejs_mod',
|
||||
lessThanEqual: 'threejs_lessThanEqual',
|
||||
inversesqrt: 'inverseSqrt'
|
||||
};
|
||||
|
||||
const wgslPolyfill = {
|
||||
lessThanEqual: new CodeNode( `
|
||||
fn threejs_lessThanEqual( a : vec3<f32>, b : vec3<f32> ) -> vec3<bool> {
|
||||
|
||||
return vec3<bool>( a.x <= b.x, a.y <= b.y, a.z <= b.z );
|
||||
|
||||
}
|
||||
` ),
|
||||
mod: new CodeNode( `
|
||||
fn threejs_mod( x : f32, y : f32 ) -> f32 {
|
||||
|
||||
return x - y * floor( x / y );
|
||||
|
||||
}
|
||||
` ),
|
||||
repeatWrapping: new CodeNode( `
|
||||
fn threejs_repeatWrapping( uv : vec2<f32>, dimension : vec2<u32> ) -> vec2<u32> {
|
||||
|
||||
let uvScaled = vec2<u32>( uv * vec2<f32>( dimension ) );
|
||||
|
||||
return ( ( uvScaled % dimension ) + dimension ) % dimension;
|
||||
|
||||
}
|
||||
` )
|
||||
};
|
||||
|
||||
class WGSLNodeBuilder extends NodeBuilder {
|
||||
|
||||
constructor( object, renderer, scene = null ) {
|
||||
|
||||
super( object, renderer, new WGSLNodeParser(), scene );
|
||||
|
||||
this.uniformsGroup = {};
|
||||
|
||||
this.builtins = {
|
||||
vertex: new Map(),
|
||||
fragment: new Map(),
|
||||
compute: new Map(),
|
||||
attribute: new Map()
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
build() {
|
||||
|
||||
const { object, material } = this;
|
||||
|
||||
if ( material !== null ) {
|
||||
|
||||
NodeMaterial.fromMaterial( material ).build( this );
|
||||
|
||||
} else {
|
||||
|
||||
this.addFlow( 'compute', object );
|
||||
|
||||
}
|
||||
|
||||
return super.build();
|
||||
|
||||
}
|
||||
|
||||
needsColorSpaceToLinear( texture ) {
|
||||
|
||||
return texture.isVideoTexture === true && texture.colorSpace !== NoColorSpace;
|
||||
|
||||
}
|
||||
|
||||
_getSampler( texture, textureProperty, uvSnippet, shaderStage = this.shaderStage ) {
|
||||
|
||||
if ( shaderStage === 'fragment' ) {
|
||||
|
||||
return `textureSample( ${textureProperty}, ${textureProperty}_sampler, ${uvSnippet} )`;
|
||||
|
||||
} else {
|
||||
|
||||
return this.getTextureLoad( texture, textureProperty, uvSnippet );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_getVideoSampler( textureProperty, uvSnippet, shaderStage = this.shaderStage ) {
|
||||
|
||||
if ( shaderStage === 'fragment' ) {
|
||||
|
||||
return `textureSampleBaseClampToEdge( ${textureProperty}, ${textureProperty}_sampler, vec2<f32>( ${uvSnippet}.x, 1.0 - ${uvSnippet}.y ) )`;
|
||||
|
||||
} else {
|
||||
|
||||
console.error( `WebGPURenderer: THREE.VideoTexture does not support ${ shaderStage } shader.` );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_getSamplerLevel( texture, textureProperty, uvSnippet, biasSnippet, shaderStage = this.shaderStage ) {
|
||||
|
||||
if ( shaderStage === 'fragment' && this.isUnfilterable( texture ) === false ) {
|
||||
|
||||
return `textureSampleLevel( ${textureProperty}, ${textureProperty}_sampler, ${uvSnippet}, ${biasSnippet} )`;
|
||||
|
||||
} else {
|
||||
|
||||
return this.getTextureLoad( texture, textureProperty, uvSnippet, biasSnippet );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
getTextureLoad( texture, textureProperty, uvSnippet, biasSnippet = '0' ) {
|
||||
|
||||
this._include( 'repeatWrapping' );
|
||||
|
||||
const dimension = `textureDimensions( ${textureProperty}, 0 )`;
|
||||
|
||||
return `textureLoad( ${textureProperty}, threejs_repeatWrapping( ${uvSnippet}, ${dimension} ), i32( ${biasSnippet} ) )`;
|
||||
|
||||
}
|
||||
|
||||
isUnfilterable( texture ) {
|
||||
|
||||
return texture.isDataTexture === true && texture.type === FloatType;
|
||||
|
||||
}
|
||||
|
||||
getTexture( texture, textureProperty, uvSnippet, shaderStage = this.shaderStage ) {
|
||||
|
||||
let snippet = null;
|
||||
|
||||
if ( texture.isVideoTexture === true ) {
|
||||
|
||||
snippet = this._getVideoSampler( textureProperty, uvSnippet, shaderStage );
|
||||
|
||||
} else if ( this.isUnfilterable( texture ) ) {
|
||||
|
||||
snippet = this.getTextureLoad( texture, textureProperty, uvSnippet );
|
||||
|
||||
} else {
|
||||
|
||||
snippet = this._getSampler( texture, textureProperty, uvSnippet, shaderStage );
|
||||
|
||||
}
|
||||
|
||||
return snippet;
|
||||
|
||||
}
|
||||
|
||||
getTextureCompare( texture, textureProperty, uvSnippet, compareSnippet, shaderStage = this.shaderStage ) {
|
||||
|
||||
if ( shaderStage === 'fragment' ) {
|
||||
|
||||
return `textureSampleCompare( ${textureProperty}, ${textureProperty}_sampler, ${uvSnippet}, ${compareSnippet} )`;
|
||||
|
||||
} else {
|
||||
|
||||
console.error( `WebGPURenderer: THREE.DepthTexture.compareFunction() does not support ${ shaderStage } shader.` );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
getTextureLevel( texture, textureProperty, uvSnippet, biasSnippet, shaderStage = this.shaderStage ) {
|
||||
|
||||
let snippet = null;
|
||||
|
||||
if ( texture.isVideoTexture === true ) {
|
||||
|
||||
snippet = this._getVideoSampler( textureProperty, uvSnippet, shaderStage );
|
||||
|
||||
} else {
|
||||
|
||||
snippet = this._getSamplerLevel( texture, textureProperty, uvSnippet, biasSnippet, shaderStage );
|
||||
|
||||
}
|
||||
|
||||
return snippet;
|
||||
|
||||
}
|
||||
|
||||
getPropertyName( node, shaderStage = this.shaderStage ) {
|
||||
|
||||
if ( node.isNodeVarying === true && node.needsInterpolation === true ) {
|
||||
|
||||
if ( shaderStage === 'vertex' ) {
|
||||
|
||||
return `NodeVaryings.${ node.name }`;
|
||||
|
||||
}
|
||||
|
||||
} else if ( node.isNodeUniform === true ) {
|
||||
|
||||
const name = node.name;
|
||||
const type = node.type;
|
||||
|
||||
if ( type === 'texture' || type === 'cubeTexture' ) {
|
||||
|
||||
return name;
|
||||
|
||||
} else if ( type === 'buffer' || type === 'storageBuffer' ) {
|
||||
|
||||
return `NodeBuffer_${node.node.id}.${name}`;
|
||||
|
||||
} else {
|
||||
|
||||
return `NodeUniforms.${name}`;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return super.getPropertyName( node );
|
||||
|
||||
}
|
||||
|
||||
getUniformFromNode( node, type, shaderStage, name = null ) {
|
||||
|
||||
const uniformNode = super.getUniformFromNode( node, type, shaderStage, name );
|
||||
const nodeData = this.getDataFromNode( node, shaderStage );
|
||||
|
||||
if ( nodeData.uniformGPU === undefined ) {
|
||||
|
||||
let uniformGPU;
|
||||
|
||||
const bindings = this.bindings[ shaderStage ];
|
||||
|
||||
if ( type === 'texture' || type === 'cubeTexture' ) {
|
||||
|
||||
let texture = null;
|
||||
|
||||
if ( type === 'texture' ) {
|
||||
|
||||
texture = new NodeSampledTexture( uniformNode.name, uniformNode.node );
|
||||
|
||||
} else if ( type === 'cubeTexture' ) {
|
||||
|
||||
texture = new NodeSampledCubeTexture( uniformNode.name, uniformNode.node );
|
||||
|
||||
}
|
||||
|
||||
texture.store = node.isStoreTextureNode === true;
|
||||
texture.setVisibility( gpuShaderStageLib[ shaderStage ] );
|
||||
|
||||
// add first textures in sequence and group for last
|
||||
const lastBinding = bindings[ bindings.length - 1 ];
|
||||
const index = lastBinding && lastBinding.isUniformsGroup ? bindings.length - 1 : bindings.length;
|
||||
|
||||
if ( shaderStage === 'fragment' && this.isUnfilterable( node.value ) === false && texture.store === false ) {
|
||||
|
||||
const sampler = new NodeSampler( `${uniformNode.name}_sampler`, uniformNode.node );
|
||||
sampler.setVisibility( gpuShaderStageLib[ shaderStage ] );
|
||||
|
||||
bindings.splice( index, 0, sampler, texture );
|
||||
|
||||
uniformGPU = [ sampler, texture ];
|
||||
|
||||
} else {
|
||||
|
||||
bindings.splice( index, 0, texture );
|
||||
|
||||
uniformGPU = [ texture ];
|
||||
|
||||
}
|
||||
|
||||
} else if ( type === 'buffer' || type === 'storageBuffer' ) {
|
||||
|
||||
const bufferClass = type === 'storageBuffer' ? StorageBuffer : UniformBuffer;
|
||||
const buffer = new bufferClass( 'NodeBuffer_' + node.id, node.value );
|
||||
buffer.setVisibility( gpuShaderStageLib[ shaderStage ] );
|
||||
|
||||
// add first textures in sequence and group for last
|
||||
const lastBinding = bindings[ bindings.length - 1 ];
|
||||
const index = lastBinding && lastBinding.isUniformsGroup ? bindings.length - 1 : bindings.length;
|
||||
|
||||
bindings.splice( index, 0, buffer );
|
||||
|
||||
uniformGPU = buffer;
|
||||
|
||||
} else {
|
||||
|
||||
let uniformsGroup = this.uniformsGroup[ shaderStage ];
|
||||
|
||||
if ( uniformsGroup === undefined ) {
|
||||
|
||||
uniformsGroup = new UniformsGroup( 'nodeUniforms' );
|
||||
uniformsGroup.setVisibility( gpuShaderStageLib[ shaderStage ] );
|
||||
|
||||
this.uniformsGroup[ shaderStage ] = uniformsGroup;
|
||||
|
||||
bindings.push( uniformsGroup );
|
||||
|
||||
}
|
||||
|
||||
if ( node.isArrayUniformNode === true ) {
|
||||
|
||||
uniformGPU = [];
|
||||
|
||||
for ( const uniformNode of node.nodes ) {
|
||||
|
||||
const uniformNodeGPU = this.getNodeUniform( uniformNode, type );
|
||||
|
||||
// fit bounds to buffer
|
||||
uniformNodeGPU.boundary = getVectorLength( uniformNodeGPU.itemSize );
|
||||
uniformNodeGPU.itemSize = getStrideLength( uniformNodeGPU.itemSize );
|
||||
|
||||
uniformsGroup.addUniform( uniformNodeGPU );
|
||||
|
||||
uniformGPU.push( uniformNodeGPU );
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
uniformGPU = this.getNodeUniform( uniformNode, type );
|
||||
|
||||
uniformsGroup.addUniform( uniformGPU );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
nodeData.uniformGPU = uniformGPU;
|
||||
|
||||
if ( shaderStage === 'vertex' ) {
|
||||
|
||||
this.bindingsOffset[ 'fragment' ] = bindings.length;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return uniformNode;
|
||||
|
||||
}
|
||||
|
||||
isReference( type ) {
|
||||
|
||||
return super.isReference( type ) || type === 'texture_2d' || type === 'texture_cube' || type === 'texture_storage_2d';
|
||||
|
||||
}
|
||||
|
||||
getBuiltin( name, property, type, shaderStage = this.shaderStage ) {
|
||||
|
||||
const map = this.builtins[ shaderStage ];
|
||||
|
||||
if ( map.has( name ) === false ) {
|
||||
|
||||
map.set( name, {
|
||||
name,
|
||||
property,
|
||||
type
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
return property;
|
||||
|
||||
}
|
||||
|
||||
getVertexIndex() {
|
||||
|
||||
if ( this.shaderStage === 'vertex' ) {
|
||||
|
||||
return this.getBuiltin( 'vertex_index', 'vertexIndex', 'u32', 'attribute' );
|
||||
|
||||
}
|
||||
|
||||
return 'vertexIndex';
|
||||
|
||||
}
|
||||
|
||||
buildFunctionNode( shaderNode ) {
|
||||
|
||||
const layout = shaderNode.layout;
|
||||
const flowData = this.flowShaderNode( shaderNode );
|
||||
|
||||
const parameters = [];
|
||||
|
||||
for ( const input of layout.inputs ) {
|
||||
|
||||
parameters.push( input.name + ' : ' + this.getType( input.type ) );
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
const code = `fn ${ layout.name }( ${ parameters.join( ', ' ) } ) -> ${ this.getType( layout.type ) } {
|
||||
${ flowData.vars }
|
||||
${ flowData.code }
|
||||
return ${ flowData.result };
|
||||
|
||||
}`;
|
||||
|
||||
//
|
||||
|
||||
return new FunctionNode( code );
|
||||
|
||||
}
|
||||
|
||||
getInstanceIndex() {
|
||||
|
||||
if ( this.shaderStage === 'vertex' ) {
|
||||
|
||||
return this.getBuiltin( 'instance_index', 'instanceIndex', 'u32', 'attribute' );
|
||||
|
||||
}
|
||||
|
||||
return 'instanceIndex';
|
||||
|
||||
}
|
||||
|
||||
getFrontFacing() {
|
||||
|
||||
return this.getBuiltin( 'front_facing', 'isFront', 'bool' );
|
||||
|
||||
}
|
||||
|
||||
getFragCoord() {
|
||||
|
||||
return this.getBuiltin( 'position', 'fragCoord', 'vec4<f32>', 'fragment' );
|
||||
|
||||
}
|
||||
|
||||
isFlipY() {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
getAttributes( shaderStage ) {
|
||||
|
||||
const snippets = [];
|
||||
|
||||
if ( shaderStage === 'compute' ) {
|
||||
|
||||
this.getBuiltin( 'global_invocation_id', 'id', 'vec3<u32>', 'attribute' );
|
||||
|
||||
}
|
||||
|
||||
if ( shaderStage === 'vertex' || shaderStage === 'compute' ) {
|
||||
|
||||
for ( const { name, property, type } of this.builtins.attribute.values() ) {
|
||||
|
||||
snippets.push( `@builtin( ${name} ) ${property} : ${type}` );
|
||||
|
||||
}
|
||||
|
||||
const attributes = this.getAttributesArray();
|
||||
|
||||
for ( let index = 0, length = attributes.length; index < length; index ++ ) {
|
||||
|
||||
const attribute = attributes[ index ];
|
||||
const name = attribute.name;
|
||||
const type = this.getType( attribute.type );
|
||||
|
||||
snippets.push( `@location( ${index} ) ${ name } : ${ type }` );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return snippets.join( ',\n\t' );
|
||||
|
||||
}
|
||||
|
||||
getStructMembers( struct ) {
|
||||
|
||||
const snippets = [];
|
||||
const members = struct.getMemberTypes();
|
||||
|
||||
for ( let i = 0; i < members.length; i ++ ) {
|
||||
|
||||
const member = members[ i ];
|
||||
snippets.push( `\t@location( ${i} ) m${i} : ${ member }<f32>` );
|
||||
|
||||
}
|
||||
|
||||
return snippets.join( ',\n' );
|
||||
|
||||
}
|
||||
|
||||
getStructs( shaderStage ) {
|
||||
|
||||
const snippets = [];
|
||||
const structs = this.structs[ shaderStage ];
|
||||
|
||||
for ( let index = 0, length = structs.length; index < length; index ++ ) {
|
||||
|
||||
const struct = structs[ index ];
|
||||
const name = struct.name;
|
||||
|
||||
let snippet = `\struct ${ name } {\n`;
|
||||
snippet += this.getStructMembers( struct );
|
||||
snippet += '\n}';
|
||||
|
||||
snippets.push( snippet );
|
||||
|
||||
}
|
||||
|
||||
return snippets.join( '\n\n' );
|
||||
|
||||
}
|
||||
|
||||
getVar( type, name ) {
|
||||
|
||||
return `var ${ name } : ${ this.getType( type ) }`;
|
||||
|
||||
}
|
||||
|
||||
getVars( shaderStage ) {
|
||||
|
||||
const snippets = [];
|
||||
const vars = this.vars[ shaderStage ];
|
||||
|
||||
if ( vars !== undefined ) {
|
||||
|
||||
for ( const variable of vars ) {
|
||||
|
||||
snippets.push( `\t${ this.getVar( variable.type, variable.name ) };` );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return `\n${ snippets.join( '\n' ) }\n`;
|
||||
|
||||
}
|
||||
|
||||
getVaryings( shaderStage ) {
|
||||
|
||||
const snippets = [];
|
||||
|
||||
if ( shaderStage === 'vertex' ) {
|
||||
|
||||
this.getBuiltin( 'position', 'Vertex', 'vec4<f32>', 'vertex' );
|
||||
|
||||
}
|
||||
|
||||
if ( shaderStage === 'vertex' || shaderStage === 'fragment' ) {
|
||||
|
||||
const varyings = this.varyings;
|
||||
const vars = this.vars[ shaderStage ];
|
||||
|
||||
for ( let index = 0; index < varyings.length; index ++ ) {
|
||||
|
||||
const varying = varyings[ index ];
|
||||
|
||||
if ( varying.needsInterpolation ) {
|
||||
|
||||
let attributesSnippet = `@location( ${index} )`;
|
||||
|
||||
if ( /^(int|uint|ivec|uvec)/.test( varying.type ) ) {
|
||||
|
||||
attributesSnippet += ' @interpolate( flat )';
|
||||
|
||||
|
||||
}
|
||||
|
||||
snippets.push( `${ attributesSnippet } ${ varying.name } : ${ this.getType( varying.type ) }` );
|
||||
|
||||
} else if ( shaderStage === 'vertex' && vars.includes( varying ) === false ) {
|
||||
|
||||
vars.push( varying );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for ( const { name, property, type } of this.builtins[ shaderStage ].values() ) {
|
||||
|
||||
snippets.push( `@builtin( ${name} ) ${property} : ${type}` );
|
||||
|
||||
}
|
||||
|
||||
const code = snippets.join( ',\n\t' );
|
||||
|
||||
return shaderStage === 'vertex' ? this._getWGSLStruct( 'NodeVaryingsStruct', '\t' + code ) : code;
|
||||
|
||||
}
|
||||
|
||||
getUniforms( shaderStage ) {
|
||||
|
||||
const uniforms = this.uniforms[ shaderStage ];
|
||||
|
||||
const bindingSnippets = [];
|
||||
const bufferSnippets = [];
|
||||
const groupSnippets = [];
|
||||
|
||||
let index = this.bindingsOffset[ shaderStage ];
|
||||
|
||||
for ( const uniform of uniforms ) {
|
||||
|
||||
if ( uniform.type === 'texture' || uniform.type === 'cubeTexture' ) {
|
||||
|
||||
const texture = uniform.node.value;
|
||||
|
||||
if ( shaderStage === 'fragment' && this.isUnfilterable( texture ) === false && uniform.node.isStoreTextureNode !== true ) {
|
||||
|
||||
if ( texture.isDepthTexture === true && texture.compareFunction !== null ) {
|
||||
|
||||
bindingSnippets.push( `@binding( ${index ++} ) @group( 0 ) var ${uniform.name}_sampler : sampler_comparison;` );
|
||||
|
||||
} else {
|
||||
|
||||
bindingSnippets.push( `@binding( ${index ++} ) @group( 0 ) var ${uniform.name}_sampler : sampler;` );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let textureType;
|
||||
|
||||
if ( texture.isCubeTexture === true ) {
|
||||
|
||||
textureType = 'texture_cube<f32>';
|
||||
|
||||
} else if ( texture.isDepthTexture === true ) {
|
||||
|
||||
textureType = 'texture_depth_2d';
|
||||
|
||||
} else if ( texture.isVideoTexture === true ) {
|
||||
|
||||
textureType = 'texture_external';
|
||||
|
||||
} else if ( uniform.node.isStoreTextureNode === true ) {
|
||||
|
||||
const format = getFormat( texture );
|
||||
|
||||
textureType = 'texture_storage_2d<' + format + ', write>';
|
||||
|
||||
} else {
|
||||
|
||||
textureType = 'texture_2d<f32>';
|
||||
|
||||
}
|
||||
|
||||
bindingSnippets.push( `@binding( ${index ++} ) @group( 0 ) var ${uniform.name} : ${textureType};` );
|
||||
|
||||
} else if ( uniform.type === 'buffer' || uniform.type === 'storageBuffer' ) {
|
||||
|
||||
const bufferNode = uniform.node;
|
||||
const bufferType = this.getType( bufferNode.bufferType );
|
||||
const bufferCount = bufferNode.bufferCount;
|
||||
|
||||
const bufferCountSnippet = bufferCount > 0 ? ', ' + bufferCount : '';
|
||||
const bufferSnippet = `\t${uniform.name} : array< ${bufferType}${bufferCountSnippet} >\n`;
|
||||
const bufferAccessMode = bufferNode.isStorageBufferNode ? 'storage,read_write' : 'uniform';
|
||||
|
||||
bufferSnippets.push( this._getWGSLStructBinding( 'NodeBuffer_' + bufferNode.id, bufferSnippet, bufferAccessMode, index ++ ) );
|
||||
|
||||
} else {
|
||||
|
||||
const vectorType = this.getType( this.getVectorType( uniform.type ) );
|
||||
|
||||
if ( Array.isArray( uniform.value ) === true ) {
|
||||
|
||||
const length = uniform.value.length;
|
||||
|
||||
groupSnippets.push( `uniform ${vectorType}[ ${length} ] ${uniform.name}` );
|
||||
|
||||
} else {
|
||||
|
||||
groupSnippets.push( `\t${uniform.name} : ${ vectorType}` );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let code = bindingSnippets.join( '\n' );
|
||||
code += bufferSnippets.join( '\n' );
|
||||
|
||||
if ( groupSnippets.length > 0 ) {
|
||||
|
||||
code += this._getWGSLStructBinding( 'NodeUniforms', groupSnippets.join( ',\n' ), 'uniform', index ++ );
|
||||
|
||||
}
|
||||
|
||||
return code;
|
||||
|
||||
}
|
||||
|
||||
buildCode() {
|
||||
|
||||
const shadersData = this.material !== null ? { fragment: {}, vertex: {} } : { compute: {} };
|
||||
|
||||
for ( const shaderStage in shadersData ) {
|
||||
|
||||
let flow = '// code\n\n';
|
||||
flow += this.flowCode[ shaderStage ];
|
||||
|
||||
const flowNodes = this.flowNodes[ shaderStage ];
|
||||
const mainNode = flowNodes[ flowNodes.length - 1 ];
|
||||
|
||||
for ( const node of flowNodes ) {
|
||||
|
||||
const flowSlotData = this.getFlowData( node/*, shaderStage*/ );
|
||||
const slotName = node.name;
|
||||
|
||||
if ( slotName ) {
|
||||
|
||||
if ( flow.length > 0 ) flow += '\n';
|
||||
|
||||
flow += `\t// flow -> ${ slotName }\n\t`;
|
||||
|
||||
}
|
||||
|
||||
flow += `${ flowSlotData.code }\n\t`;
|
||||
|
||||
if ( node === mainNode && shaderStage !== 'compute' ) {
|
||||
|
||||
flow += '// result\n\t';
|
||||
|
||||
if ( shaderStage === 'vertex' ) {
|
||||
|
||||
flow += 'NodeVaryings.Vertex = ';
|
||||
|
||||
} else if ( shaderStage === 'fragment' ) {
|
||||
|
||||
flow += 'return ';
|
||||
|
||||
}
|
||||
|
||||
flow += `${ flowSlotData.result };`;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const outputNode = mainNode.outputNode;
|
||||
const stageData = shadersData[ shaderStage ];
|
||||
|
||||
stageData.uniforms = this.getUniforms( shaderStage );
|
||||
stageData.attributes = this.getAttributes( shaderStage );
|
||||
stageData.varyings = this.getVaryings( shaderStage );
|
||||
stageData.structs = this.getStructs( shaderStage );
|
||||
stageData.vars = this.getVars( shaderStage );
|
||||
stageData.codes = this.getCodes( shaderStage );
|
||||
stageData.returnType = ( outputNode !== undefined && outputNode.isOutputStructNode === true ) ? outputNode.nodeType : '@location( 0 ) vec4<f32>';
|
||||
stageData.flow = flow;
|
||||
|
||||
}
|
||||
|
||||
if ( this.material !== null ) {
|
||||
|
||||
this.vertexShader = this._getWGSLVertexCode( shadersData.vertex );
|
||||
this.fragmentShader = this._getWGSLFragmentCode( shadersData.fragment );
|
||||
|
||||
} else {
|
||||
|
||||
this.computeShader = this._getWGSLComputeCode( shadersData.compute, ( this.object.workgroupSize || [ 64 ] ).join( ', ' ) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
getMethod( method ) {
|
||||
|
||||
if ( wgslPolyfill[ method ] !== undefined ) {
|
||||
|
||||
this._include( method );
|
||||
|
||||
}
|
||||
|
||||
return wgslMethods[ method ] || method;
|
||||
|
||||
}
|
||||
|
||||
getType( type ) {
|
||||
|
||||
return wgslTypeLib[ type ] || type;
|
||||
|
||||
}
|
||||
|
||||
isAvailable( name ) {
|
||||
|
||||
return supports[ name ] === true;
|
||||
|
||||
}
|
||||
|
||||
_include( name ) {
|
||||
|
||||
wgslPolyfill[ name ].build( this );
|
||||
|
||||
}
|
||||
|
||||
_getWGSLVertexCode( shaderData ) {
|
||||
|
||||
return `${ this.getSignature() }
|
||||
|
||||
// uniforms
|
||||
${shaderData.uniforms}
|
||||
|
||||
// varyings
|
||||
${shaderData.varyings}
|
||||
|
||||
// codes
|
||||
${shaderData.codes}
|
||||
|
||||
@vertex
|
||||
fn main( ${shaderData.attributes} ) -> NodeVaryingsStruct {
|
||||
|
||||
// system
|
||||
var NodeVaryings: NodeVaryingsStruct;
|
||||
|
||||
// vars
|
||||
${shaderData.vars}
|
||||
|
||||
// flow
|
||||
${shaderData.flow}
|
||||
|
||||
return NodeVaryings;
|
||||
|
||||
}
|
||||
`;
|
||||
|
||||
}
|
||||
|
||||
_getWGSLFragmentCode( shaderData ) {
|
||||
|
||||
return `${ this.getSignature() }
|
||||
|
||||
// uniforms
|
||||
${shaderData.uniforms}
|
||||
|
||||
// structs
|
||||
${shaderData.structs}
|
||||
|
||||
// codes
|
||||
${shaderData.codes}
|
||||
|
||||
@fragment
|
||||
fn main( ${shaderData.varyings} ) -> ${shaderData.returnType} {
|
||||
|
||||
// vars
|
||||
${shaderData.vars}
|
||||
|
||||
// flow
|
||||
${shaderData.flow}
|
||||
|
||||
}
|
||||
`;
|
||||
|
||||
}
|
||||
|
||||
_getWGSLComputeCode( shaderData, workgroupSize ) {
|
||||
|
||||
return `${ this.getSignature() }
|
||||
// system
|
||||
var<private> instanceIndex : u32;
|
||||
|
||||
// uniforms
|
||||
${shaderData.uniforms}
|
||||
|
||||
// codes
|
||||
${shaderData.codes}
|
||||
|
||||
@compute @workgroup_size( ${workgroupSize} )
|
||||
fn main( ${shaderData.attributes} ) {
|
||||
|
||||
// system
|
||||
instanceIndex = id.x;
|
||||
|
||||
// vars
|
||||
${shaderData.vars}
|
||||
|
||||
// flow
|
||||
${shaderData.flow}
|
||||
|
||||
}
|
||||
`;
|
||||
|
||||
}
|
||||
|
||||
_getWGSLStruct( name, vars ) {
|
||||
|
||||
return `
|
||||
struct ${name} {
|
||||
${vars}
|
||||
};`;
|
||||
|
||||
}
|
||||
|
||||
_getWGSLStructBinding( name, vars, access, binding = 0, group = 0 ) {
|
||||
|
||||
const structName = name + 'Struct';
|
||||
const structSnippet = this._getWGSLStruct( structName, vars );
|
||||
|
||||
return `${structSnippet}
|
||||
@binding( ${binding} ) @group( ${group} )
|
||||
var<${access}> ${name} : ${structName};`;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WGSLNodeBuilder;
|
||||
104
node_modules/three/examples/jsm/renderers/webgpu/nodes/WGSLNodeFunction.js
generated
vendored
Normal file
104
node_modules/three/examples/jsm/renderers/webgpu/nodes/WGSLNodeFunction.js
generated
vendored
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;
|
||||
14
node_modules/three/examples/jsm/renderers/webgpu/nodes/WGSLNodeParser.js
generated
vendored
Normal file
14
node_modules/three/examples/jsm/renderers/webgpu/nodes/WGSLNodeParser.js
generated
vendored
Normal file
@@ -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;
|
||||
274
node_modules/three/examples/jsm/renderers/webgpu/utils/WebGPUAttributeUtils.js
generated
vendored
Normal file
274
node_modules/three/examples/jsm/renderers/webgpu/utils/WebGPUAttributeUtils.js
generated
vendored
Normal file
@@ -0,0 +1,274 @@
|
||||
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' ],
|
||||
[ Uint32Array, 'uint32' ],
|
||||
[ 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;
|
||||
|
||||
const array = bufferAttribute.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 updateRange = bufferAttribute.updateRange;
|
||||
|
||||
if ( updateRange.count === - 1 ) {
|
||||
|
||||
// Not using update ranges
|
||||
|
||||
device.queue.writeBuffer(
|
||||
buffer,
|
||||
0,
|
||||
array,
|
||||
0
|
||||
);
|
||||
|
||||
} else {
|
||||
|
||||
device.queue.writeBuffer(
|
||||
buffer,
|
||||
0,
|
||||
array,
|
||||
updateRange.offset * array.BYTES_PER_ELEMENT,
|
||||
updateRange.count * array.BYTES_PER_ELEMENT
|
||||
);
|
||||
|
||||
updateRange.count = - 1; // reset range
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
236
node_modules/three/examples/jsm/renderers/webgpu/utils/WebGPUBindingUtils.js
generated
vendored
Normal file
236
node_modules/three/examples/jsm/renderers/webgpu/utils/WebGPUBindingUtils.js
generated
vendored
Normal file
@@ -0,0 +1,236 @@
|
||||
import {
|
||||
GPUTextureAspect, GPUTextureViewDimension, GPUBufferBindingType, GPUTextureSampleType
|
||||
} from './WebGPUConstants.js';
|
||||
import { FloatType } 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 && binding.texture.type === FloatType ) {
|
||||
|
||||
// @TODO: Add support for this soon: backend.hasFeature( 'float32-filterable' )
|
||||
|
||||
texture.sampleType = GPUTextureSampleType.UnfilterableFloat;
|
||||
|
||||
}
|
||||
|
||||
if ( binding.isSampledCubeTexture ) {
|
||||
|
||||
texture.viewDimension = GPUTextureViewDimension.Cube;
|
||||
|
||||
}
|
||||
|
||||
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',
|
||||
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 {
|
||||
|
||||
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 } );
|
||||
|
||||
}
|
||||
|
||||
entriesGPU.push( { binding: bindingPoint, resource: resourceGPU } );
|
||||
|
||||
}
|
||||
|
||||
bindingPoint ++;
|
||||
|
||||
}
|
||||
|
||||
return device.createBindGroup( {
|
||||
layout: layoutGPU,
|
||||
entries: entriesGPU
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebGPUBindingUtils;
|
||||
324
node_modules/three/examples/jsm/renderers/webgpu/utils/WebGPUConstants.js
generated
vendored
Normal file
324
node_modules/three/examples/jsm/renderers/webgpu/utils/WebGPUConstants.js
generated
vendored
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'
|
||||
};
|
||||
558
node_modules/three/examples/jsm/renderers/webgpu/utils/WebGPUPipelineUtils.js
generated
vendored
Normal file
558
node_modules/three/examples/jsm/renderers/webgpu/utils/WebGPUPipelineUtils.js
generated
vendored
Normal file
@@ -0,0 +1,558 @@
|
||||
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 ) {
|
||||
|
||||
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 );
|
||||
const sampleCount = utils.getSampleCount( renderObject.context );
|
||||
|
||||
pipelineData.pipeline = device.createRenderPipeline( {
|
||||
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 ]
|
||||
} )
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
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 ( object.isLine === true && object.isLineSegments !== true ) {
|
||||
|
||||
const count = ( geometry.index ) ? geometry.index.count : geometry.attributes.position.count;
|
||||
descriptor.stripIndexFormat = ( count > 65535 ) ? GPUIndexFormat.Uint32 : GPUIndexFormat.Uint16; // define data type for primitive restart value
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
285
node_modules/three/examples/jsm/renderers/webgpu/utils/WebGPUTexturePassUtils.js
generated
vendored
Normal file
285
node_modules/three/examples/jsm/renderers/webgpu/utils/WebGPUTexturePassUtils.js
generated
vendored
Normal file
@@ -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;
|
||||
885
node_modules/three/examples/jsm/renderers/webgpu/utils/WebGPUTextureUtils.js
generated
vendored
Normal file
885
node_modules/three/examples/jsm/renderers/webgpu/utils/WebGPUTextureUtils.js
generated
vendored
Normal file
@@ -0,0 +1,885 @@
|
||||
import {
|
||||
GPUTextureFormat, GPUAddressMode, GPUFilterMode, GPUTextureDimension, GPUFeatureName
|
||||
} from './WebGPUConstants.js';
|
||||
|
||||
import {
|
||||
CubeTexture, Texture,
|
||||
NearestFilter, NearestMipmapNearestFilter, NearestMipmapLinearFilter,
|
||||
RepeatWrapping, MirroredRepeatWrapping,
|
||||
RGB_ETC2_Format, RGBA_ETC2_EAC_Format,
|
||||
RGBAFormat, RedFormat, RGFormat, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, UnsignedByteType, FloatType, HalfFloatType, SRGBColorSpace, DepthFormat, DepthStencilFormat,
|
||||
RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_ASTC_10x5_Format,
|
||||
RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_10x10_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, UnsignedIntType, UnsignedShortType, UnsignedInt248Type,
|
||||
NeverCompare, AlwaysCompare, LessCompare, LessEqualCompare, EqualCompare, GreaterEqualCompare, GreaterCompare, NotEqualCompare
|
||||
} from 'three';
|
||||
|
||||
import { CubeReflectionMapping, CubeRefractionMapping, EquirectangularReflectionMapping, EquirectangularRefractionMapping } from 'three';
|
||||
|
||||
import WebGPUTexturePassUtils from './WebGPUTexturePassUtils.js';
|
||||
|
||||
const _compareToWebGPU = {
|
||||
[ NeverCompare ]: 'never',
|
||||
[ LessCompare ]: 'less',
|
||||
[ EqualCompare ]: 'equal',
|
||||
[ LessEqualCompare ]: 'less-equal',
|
||||
[ GreaterCompare ]: 'greater',
|
||||
[ GreaterEqualCompare ]: 'greater-equal',
|
||||
[ AlwaysCompare ]: 'always',
|
||||
[ NotEqualCompare ]: 'not-equal'
|
||||
};
|
||||
|
||||
const _flipMap = [ 0, 1, 3, 2, 4, 5 ];
|
||||
|
||||
class WebGPUTextureUtils {
|
||||
|
||||
constructor( backend ) {
|
||||
|
||||
this.backend = backend;
|
||||
|
||||
this._passUtils = null;
|
||||
|
||||
this.defaultTexture = null;
|
||||
this.defaultCubeTexture = null;
|
||||
|
||||
}
|
||||
|
||||
createSampler( texture ) {
|
||||
|
||||
const backend = this.backend;
|
||||
const device = backend.device;
|
||||
|
||||
const textureGPU = backend.get( texture );
|
||||
|
||||
const samplerDescriptorGPU = {
|
||||
addressModeU: this._convertAddressMode( texture.wrapS ),
|
||||
addressModeV: this._convertAddressMode( texture.wrapT ),
|
||||
addressModeW: this._convertAddressMode( texture.wrapR ),
|
||||
magFilter: this._convertFilterMode( texture.magFilter ),
|
||||
minFilter: this._convertFilterMode( texture.minFilter ),
|
||||
mipmapFilter: this._convertFilterMode( texture.minFilter ),
|
||||
maxAnisotropy: texture.anisotropy
|
||||
};
|
||||
|
||||
if ( texture.isDepthTexture && texture.compareFunction !== null ) {
|
||||
|
||||
samplerDescriptorGPU.compare = _compareToWebGPU[ texture.compareFunction ];
|
||||
|
||||
}
|
||||
|
||||
textureGPU.sampler = device.createSampler( samplerDescriptorGPU );
|
||||
|
||||
}
|
||||
|
||||
createDefaultTexture( texture ) {
|
||||
|
||||
let textureGPU;
|
||||
|
||||
if ( texture.isCubeTexture ) {
|
||||
|
||||
textureGPU = this._getDefaultCubeTextureGPU();
|
||||
|
||||
} else {
|
||||
|
||||
textureGPU = this._getDefaultTextureGPU();
|
||||
|
||||
}
|
||||
|
||||
this.backend.get( texture ).texture = textureGPU;
|
||||
|
||||
}
|
||||
|
||||
createTexture( texture, options = {} ) {
|
||||
|
||||
const backend = this.backend;
|
||||
const textureData = backend.get( texture );
|
||||
|
||||
if ( textureData.initialized ) {
|
||||
|
||||
throw new Error( 'WebGPUTextureUtils: Texture already initialized.' );
|
||||
|
||||
}
|
||||
|
||||
if ( options.needsMipmaps === undefined ) options.needsMipmaps = false;
|
||||
if ( options.levels === undefined ) options.levels = 1;
|
||||
if ( options.depth === undefined ) options.depth = 1;
|
||||
|
||||
const { width, height, depth, levels } = options;
|
||||
|
||||
const dimension = this._getDimension( texture );
|
||||
const format = texture.internalFormat || getFormat( texture, this.device );
|
||||
|
||||
const sampleCount = options.sampleCount !== undefined ? options.sampleCount : 1;
|
||||
const primarySampleCount = texture.isRenderTargetTexture ? 1 : sampleCount;
|
||||
|
||||
let usage = GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC;
|
||||
|
||||
if ( texture.isStorageTexture === true ) {
|
||||
|
||||
usage |= GPUTextureUsage.STORAGE_BINDING;
|
||||
|
||||
}
|
||||
|
||||
if ( texture.isCompressedTexture !== true ) {
|
||||
|
||||
usage |= GPUTextureUsage.RENDER_ATTACHMENT;
|
||||
|
||||
}
|
||||
|
||||
const textureDescriptorGPU = {
|
||||
label: texture.name,
|
||||
size: {
|
||||
width: width,
|
||||
height: height,
|
||||
depthOrArrayLayers: depth,
|
||||
},
|
||||
mipLevelCount: levels,
|
||||
sampleCount: primarySampleCount,
|
||||
dimension: dimension,
|
||||
format: format,
|
||||
usage: usage
|
||||
};
|
||||
|
||||
// texture creation
|
||||
|
||||
if ( texture.isVideoTexture ) {
|
||||
|
||||
const video = texture.source.data;
|
||||
const videoFrame = new VideoFrame( video );
|
||||
|
||||
textureDescriptorGPU.size.width = videoFrame.displayWidth;
|
||||
textureDescriptorGPU.size.height = videoFrame.displayHeight;
|
||||
|
||||
videoFrame.close();
|
||||
|
||||
textureData.externalTexture = video;
|
||||
|
||||
} else {
|
||||
|
||||
if ( format === undefined ) {
|
||||
|
||||
console.warn( 'WebGPURenderer: Texture format not supported.' );
|
||||
|
||||
return this.createDefaultTexture( texture );
|
||||
|
||||
}
|
||||
|
||||
textureData.texture = backend.device.createTexture( textureDescriptorGPU );
|
||||
|
||||
}
|
||||
|
||||
if ( texture.isRenderTargetTexture && sampleCount > 1 ) {
|
||||
|
||||
const msaaTextureDescriptorGPU = Object.assign( {}, textureDescriptorGPU );
|
||||
|
||||
msaaTextureDescriptorGPU.label = msaaTextureDescriptorGPU.label + '-msaa';
|
||||
msaaTextureDescriptorGPU.sampleCount = sampleCount;
|
||||
|
||||
textureData.msaaTexture = backend.device.createTexture( msaaTextureDescriptorGPU );
|
||||
|
||||
}
|
||||
|
||||
textureData.initialized = true;
|
||||
|
||||
textureData.textureDescriptorGPU = textureDescriptorGPU;
|
||||
|
||||
}
|
||||
|
||||
destroyTexture( texture ) {
|
||||
|
||||
const backend = this.backend;
|
||||
const textureData = backend.get( texture );
|
||||
|
||||
textureData.texture.destroy();
|
||||
|
||||
if ( textureData.msaaTexture !== undefined ) textureData.msaaTexture.destroy();
|
||||
|
||||
backend.delete( texture );
|
||||
|
||||
}
|
||||
|
||||
destroySampler( texture ) {
|
||||
|
||||
const backend = this.backend;
|
||||
const textureData = backend.get( texture );
|
||||
|
||||
delete textureData.sampler;
|
||||
|
||||
}
|
||||
|
||||
generateMipmaps( texture ) {
|
||||
|
||||
const textureData = this.backend.get( texture );
|
||||
|
||||
if ( texture.isCubeTexture ) {
|
||||
|
||||
for ( let i = 0; i < 6; i ++ ) {
|
||||
|
||||
this._generateMipmaps( textureData.texture, textureData.textureDescriptorGPU, i );
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
this._generateMipmaps( textureData.texture, textureData.textureDescriptorGPU );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
updateTexture( texture, options ) {
|
||||
|
||||
const textureData = this.backend.get( texture );
|
||||
|
||||
const { textureDescriptorGPU } = textureData;
|
||||
|
||||
if ( texture.isRenderTargetTexture || ( textureDescriptorGPU === undefined /* unsupported texture format */ ) )
|
||||
return;
|
||||
|
||||
// transfer texture data
|
||||
|
||||
if ( texture.isDataTexture || texture.isDataArrayTexture || texture.isData3DTexture ) {
|
||||
|
||||
this._copyBufferToTexture( options.image, textureData.texture, textureDescriptorGPU, 0, false );
|
||||
|
||||
} else if ( texture.isCompressedTexture ) {
|
||||
|
||||
this._copyCompressedBufferToTexture( texture.mipmaps, textureData.texture, textureDescriptorGPU );
|
||||
|
||||
} else if ( texture.isCubeTexture ) {
|
||||
|
||||
this._copyCubeMapToTexture( options.images, textureData.texture, textureDescriptorGPU, texture.flipY );
|
||||
|
||||
} else if ( texture.isVideoTexture ) {
|
||||
|
||||
const video = texture.source.data;
|
||||
|
||||
textureData.externalTexture = video;
|
||||
|
||||
} else {
|
||||
|
||||
this._copyImageToTexture( options.image, textureData.texture, textureDescriptorGPU, 0, texture.flipY );
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
textureData.version = texture.version;
|
||||
|
||||
if ( texture.onUpdate ) texture.onUpdate( texture );
|
||||
|
||||
}
|
||||
|
||||
async copyTextureToBuffer( texture, x, y, width, height ) {
|
||||
|
||||
const device = this.backend.device;
|
||||
|
||||
const textureData = this.backend.get( texture );
|
||||
const textureGPU = textureData.texture;
|
||||
const format = textureData.textureDescriptorGPU.format;
|
||||
const bytesPerTexel = this._getBytesPerTexel( format );
|
||||
|
||||
const readBuffer = device.createBuffer(
|
||||
{
|
||||
size: width * height * bytesPerTexel,
|
||||
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
|
||||
}
|
||||
);
|
||||
|
||||
const encoder = device.createCommandEncoder();
|
||||
|
||||
encoder.copyTextureToBuffer(
|
||||
{
|
||||
texture: textureGPU,
|
||||
origin: { x, y },
|
||||
},
|
||||
{
|
||||
buffer: readBuffer,
|
||||
bytesPerRow: width * bytesPerTexel
|
||||
},
|
||||
{
|
||||
width: width,
|
||||
height: height
|
||||
}
|
||||
|
||||
);
|
||||
|
||||
const typedArrayType = this._getTypedArrayType( format );
|
||||
|
||||
device.queue.submit( [ encoder.finish() ] );
|
||||
|
||||
await readBuffer.mapAsync( GPUMapMode.READ );
|
||||
|
||||
const buffer = readBuffer.getMappedRange();
|
||||
|
||||
return new typedArrayType( buffer );
|
||||
|
||||
}
|
||||
|
||||
_isEnvironmentTexture( texture ) {
|
||||
|
||||
const mapping = texture.mapping;
|
||||
|
||||
return ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ) || ( mapping === CubeReflectionMapping || mapping === CubeRefractionMapping );
|
||||
|
||||
}
|
||||
|
||||
_getDefaultTextureGPU() {
|
||||
|
||||
let defaultTexture = this.defaultTexture;
|
||||
|
||||
if ( defaultTexture === null ) {
|
||||
|
||||
const texture = new Texture();
|
||||
texture.minFilter = NearestFilter;
|
||||
texture.magFilter = NearestFilter;
|
||||
|
||||
this.createTexture( texture, { width: 1, height: 1 } );
|
||||
|
||||
this.defaultTexture = defaultTexture = texture;
|
||||
|
||||
}
|
||||
|
||||
return this.backend.get( defaultTexture ).texture;
|
||||
|
||||
}
|
||||
|
||||
_getDefaultCubeTextureGPU() {
|
||||
|
||||
let defaultCubeTexture = this.defaultTexture;
|
||||
|
||||
if ( defaultCubeTexture === null ) {
|
||||
|
||||
const texture = new CubeTexture();
|
||||
texture.minFilter = NearestFilter;
|
||||
texture.magFilter = NearestFilter;
|
||||
|
||||
this.createTexture( texture, { width: 1, height: 1, depth: 6 } );
|
||||
|
||||
this.defaultCubeTexture = defaultCubeTexture = texture;
|
||||
|
||||
}
|
||||
|
||||
return this.backend.get( defaultCubeTexture ).texture;
|
||||
|
||||
}
|
||||
|
||||
_copyCubeMapToTexture( images, textureGPU, textureDescriptorGPU, flipY ) {
|
||||
|
||||
for ( let i = 0; i < 6; i ++ ) {
|
||||
|
||||
const image = images[ i ];
|
||||
|
||||
const flipIndex = flipY === true ? _flipMap[ i ] : i;
|
||||
|
||||
if ( image.isDataTexture ) {
|
||||
|
||||
this._copyBufferToTexture( image.image, textureGPU, textureDescriptorGPU, flipIndex, flipY );
|
||||
|
||||
} else {
|
||||
|
||||
this._copyImageToTexture( image, textureGPU, textureDescriptorGPU, flipIndex, flipY );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_copyImageToTexture( image, textureGPU, textureDescriptorGPU, originDepth, flipY ) {
|
||||
|
||||
const device = this.backend.device;
|
||||
|
||||
device.queue.copyExternalImageToTexture(
|
||||
{
|
||||
source: image
|
||||
}, {
|
||||
texture: textureGPU,
|
||||
mipLevel: 0,
|
||||
origin: { x: 0, y: 0, z: originDepth }
|
||||
}, {
|
||||
width: image.width,
|
||||
height: image.height,
|
||||
depthOrArrayLayers: 1
|
||||
}
|
||||
);
|
||||
|
||||
if ( flipY === true ) {
|
||||
|
||||
this._flipY( textureGPU, textureDescriptorGPU, originDepth );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_getPassUtils() {
|
||||
|
||||
let passUtils = this._passUtils;
|
||||
|
||||
if ( passUtils === null ) {
|
||||
|
||||
this._passUtils = passUtils = new WebGPUTexturePassUtils( this.backend.device );
|
||||
|
||||
}
|
||||
|
||||
return passUtils;
|
||||
|
||||
}
|
||||
|
||||
_generateMipmaps( textureGPU, textureDescriptorGPU, baseArrayLayer = 0 ) {
|
||||
|
||||
this._getPassUtils().generateMipmaps( textureGPU, textureDescriptorGPU, baseArrayLayer );
|
||||
|
||||
}
|
||||
|
||||
_flipY( textureGPU, textureDescriptorGPU, originDepth = 0 ) {
|
||||
|
||||
this._getPassUtils().flipY( textureGPU, textureDescriptorGPU, originDepth );
|
||||
|
||||
}
|
||||
|
||||
_copyBufferToTexture( image, textureGPU, textureDescriptorGPU, originDepth, flipY ) {
|
||||
|
||||
// @TODO: Consider to use GPUCommandEncoder.copyBufferToTexture()
|
||||
// @TODO: Consider to support valid buffer layouts with other formats like RGB
|
||||
|
||||
const device = this.backend.device;
|
||||
|
||||
const data = image.data;
|
||||
|
||||
const bytesPerTexel = this._getBytesPerTexel( textureDescriptorGPU.format );
|
||||
const bytesPerRow = image.width * bytesPerTexel;
|
||||
|
||||
device.queue.writeTexture(
|
||||
{
|
||||
texture: textureGPU,
|
||||
mipLevel: 0,
|
||||
origin: { x: 0, y: 0, z: originDepth }
|
||||
},
|
||||
data,
|
||||
{
|
||||
offset: 0,
|
||||
bytesPerRow
|
||||
},
|
||||
{
|
||||
width: image.width,
|
||||
height: image.height,
|
||||
depthOrArrayLayers: ( image.depth !== undefined ) ? image.depth : 1
|
||||
} );
|
||||
|
||||
if ( flipY === true ) {
|
||||
|
||||
this._flipY( textureGPU, textureDescriptorGPU, originDepth );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_copyCompressedBufferToTexture( mipmaps, textureGPU, textureDescriptorGPU ) {
|
||||
|
||||
// @TODO: Consider to use GPUCommandEncoder.copyBufferToTexture()
|
||||
|
||||
const device = this.backend.device;
|
||||
|
||||
const blockData = this._getBlockData( textureDescriptorGPU.format );
|
||||
|
||||
for ( let i = 0; i < mipmaps.length; i ++ ) {
|
||||
|
||||
const mipmap = mipmaps[ i ];
|
||||
|
||||
const width = mipmap.width;
|
||||
const height = mipmap.height;
|
||||
|
||||
const bytesPerRow = Math.ceil( width / blockData.width ) * blockData.byteLength;
|
||||
|
||||
device.queue.writeTexture(
|
||||
{
|
||||
texture: textureGPU,
|
||||
mipLevel: i
|
||||
},
|
||||
mipmap.data,
|
||||
{
|
||||
offset: 0,
|
||||
bytesPerRow
|
||||
},
|
||||
{
|
||||
width: Math.ceil( width / blockData.width ) * blockData.width,
|
||||
height: Math.ceil( height / blockData.width ) * blockData.width,
|
||||
depthOrArrayLayers: 1
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_getBlockData( format ) {
|
||||
|
||||
// this method is only relevant for compressed texture formats
|
||||
|
||||
if ( format === GPUTextureFormat.BC1RGBAUnorm || format === GPUTextureFormat.BC1RGBAUnormSRGB ) return { byteLength: 8, width: 4, height: 4 }; // DXT1
|
||||
if ( format === GPUTextureFormat.BC2RGBAUnorm || format === GPUTextureFormat.BC2RGBAUnormSRGB ) return { byteLength: 16, width: 4, height: 4 }; // DXT3
|
||||
if ( format === GPUTextureFormat.BC3RGBAUnorm || format === GPUTextureFormat.BC3RGBAUnormSRGB ) return { byteLength: 16, width: 4, height: 4 }; // DXT5
|
||||
if ( format === GPUTextureFormat.BC4RUnorm || format === GPUTextureFormat.BC4RSNorm ) return { byteLength: 8, width: 4, height: 4 }; // RGTC1
|
||||
if ( format === GPUTextureFormat.BC5RGUnorm || format === GPUTextureFormat.BC5RGSnorm ) return { byteLength: 16, width: 4, height: 4 }; // RGTC2
|
||||
if ( format === GPUTextureFormat.BC6HRGBUFloat || format === GPUTextureFormat.BC6HRGBFloat ) return { byteLength: 16, width: 4, height: 4 }; // BPTC (float)
|
||||
if ( format === GPUTextureFormat.BC7RGBAUnorm || format === GPUTextureFormat.BC7RGBAUnormSRGB ) return { byteLength: 16, width: 4, height: 4 }; // BPTC (unorm)
|
||||
|
||||
if ( format === GPUTextureFormat.ETC2RGB8Unorm || format === GPUTextureFormat.ETC2RGB8UnormSRGB ) return { byteLength: 8, width: 4, height: 4 };
|
||||
if ( format === GPUTextureFormat.ETC2RGB8A1Unorm || format === GPUTextureFormat.ETC2RGB8A1UnormSRGB ) return { byteLength: 8, width: 4, height: 4 };
|
||||
if ( format === GPUTextureFormat.ETC2RGBA8Unorm || format === GPUTextureFormat.ETC2RGBA8UnormSRGB ) return { byteLength: 16, width: 4, height: 4 };
|
||||
if ( format === GPUTextureFormat.EACR11Unorm ) return { byteLength: 8, width: 4, height: 4 };
|
||||
if ( format === GPUTextureFormat.EACR11Snorm ) return { byteLength: 8, width: 4, height: 4 };
|
||||
if ( format === GPUTextureFormat.EACRG11Unorm ) return { byteLength: 16, width: 4, height: 4 };
|
||||
if ( format === GPUTextureFormat.EACRG11Snorm ) return { byteLength: 16, width: 4, height: 4 };
|
||||
|
||||
if ( format === GPUTextureFormat.ASTC4x4Unorm || format === GPUTextureFormat.ASTC4x4UnormSRGB ) return { byteLength: 16, width: 4, height: 4 };
|
||||
if ( format === GPUTextureFormat.ASTC5x4Unorm || format === GPUTextureFormat.ASTC5x4UnormSRGB ) return { byteLength: 16, width: 5, height: 4 };
|
||||
if ( format === GPUTextureFormat.ASTC5x5Unorm || format === GPUTextureFormat.ASTC5x5UnormSRGB ) return { byteLength: 16, width: 5, height: 5 };
|
||||
if ( format === GPUTextureFormat.ASTC6x5Unorm || format === GPUTextureFormat.ASTC6x5UnormSRGB ) return { byteLength: 16, width: 6, height: 5 };
|
||||
if ( format === GPUTextureFormat.ASTC6x6Unorm || format === GPUTextureFormat.ASTC6x6UnormSRGB ) return { byteLength: 16, width: 6, height: 6 };
|
||||
if ( format === GPUTextureFormat.ASTC8x5Unorm || format === GPUTextureFormat.ASTC8x5UnormSRGB ) return { byteLength: 16, width: 8, height: 5 };
|
||||
if ( format === GPUTextureFormat.ASTC8x6Unorm || format === GPUTextureFormat.ASTC8x6UnormSRGB ) return { byteLength: 16, width: 8, height: 6 };
|
||||
if ( format === GPUTextureFormat.ASTC8x8Unorm || format === GPUTextureFormat.ASTC8x8UnormSRGB ) return { byteLength: 16, width: 8, height: 8 };
|
||||
if ( format === GPUTextureFormat.ASTC10x5Unorm || format === GPUTextureFormat.ASTC10x5UnormSRGB ) return { byteLength: 16, width: 10, height: 5 };
|
||||
if ( format === GPUTextureFormat.ASTC10x6Unorm || format === GPUTextureFormat.ASTC10x6UnormSRGB ) return { byteLength: 16, width: 10, height: 6 };
|
||||
if ( format === GPUTextureFormat.ASTC10x8Unorm || format === GPUTextureFormat.ASTC10x8UnormSRGB ) return { byteLength: 16, width: 10, height: 8 };
|
||||
if ( format === GPUTextureFormat.ASTC10x10Unorm || format === GPUTextureFormat.ASTC10x10UnormSRGB ) return { byteLength: 16, width: 10, height: 10 };
|
||||
if ( format === GPUTextureFormat.ASTC12x10Unorm || format === GPUTextureFormat.ASTC12x10UnormSRGB ) return { byteLength: 16, width: 12, height: 10 };
|
||||
if ( format === GPUTextureFormat.ASTC12x12Unorm || format === GPUTextureFormat.ASTC12x12UnormSRGB ) return { byteLength: 16, width: 12, height: 12 };
|
||||
|
||||
}
|
||||
|
||||
_convertAddressMode( value ) {
|
||||
|
||||
let addressMode = GPUAddressMode.ClampToEdge;
|
||||
|
||||
if ( value === RepeatWrapping ) {
|
||||
|
||||
addressMode = GPUAddressMode.Repeat;
|
||||
|
||||
} else if ( value === MirroredRepeatWrapping ) {
|
||||
|
||||
addressMode = GPUAddressMode.MirrorRepeat;
|
||||
|
||||
}
|
||||
|
||||
return addressMode;
|
||||
|
||||
}
|
||||
|
||||
_convertFilterMode( value ) {
|
||||
|
||||
let filterMode = GPUFilterMode.Linear;
|
||||
|
||||
if ( value === NearestFilter || value === NearestMipmapNearestFilter || value === NearestMipmapLinearFilter ) {
|
||||
|
||||
filterMode = GPUFilterMode.Nearest;
|
||||
|
||||
}
|
||||
|
||||
return filterMode;
|
||||
|
||||
}
|
||||
|
||||
_getBytesPerTexel( format ) {
|
||||
|
||||
if ( format === GPUTextureFormat.R8Unorm ) return 1;
|
||||
if ( format === GPUTextureFormat.R16Float ) return 2;
|
||||
if ( format === GPUTextureFormat.RG8Unorm ) return 2;
|
||||
if ( format === GPUTextureFormat.RG16Float ) return 4;
|
||||
if ( format === GPUTextureFormat.R32Float ) return 4;
|
||||
if ( format === GPUTextureFormat.RGBA8Unorm || format === GPUTextureFormat.RGBA8UnormSRGB ) return 4;
|
||||
if ( format === GPUTextureFormat.RG32Float ) return 8;
|
||||
if ( format === GPUTextureFormat.RGBA16Float ) return 8;
|
||||
if ( format === GPUTextureFormat.RGBA32Float ) return 16;
|
||||
|
||||
}
|
||||
|
||||
_getTypedArrayType( format ) {
|
||||
|
||||
if ( format === GPUTextureFormat.R8Uint ) return Uint8Array;
|
||||
if ( format === GPUTextureFormat.R8Sint ) return Int8Array;
|
||||
if ( format === GPUTextureFormat.R8Unorm ) return Uint8Array;
|
||||
if ( format === GPUTextureFormat.R8Snorm ) return Int8Array;
|
||||
if ( format === GPUTextureFormat.RG8Uint ) return Uint8Array;
|
||||
if ( format === GPUTextureFormat.RG8Sint ) return Int8Array;
|
||||
if ( format === GPUTextureFormat.RG8Unorm ) return Uint8Array;
|
||||
if ( format === GPUTextureFormat.RG8Snorm ) return Int8Array;
|
||||
if ( format === GPUTextureFormat.RGBA8Uint ) return Uint8Array;
|
||||
if ( format === GPUTextureFormat.RGBA8Sint ) return Int8Array;
|
||||
if ( format === GPUTextureFormat.RGBA8Unorm ) return Uint8Array;
|
||||
if ( format === GPUTextureFormat.RGBA8Snorm ) return Int8Array;
|
||||
|
||||
|
||||
if ( format === GPUTextureFormat.R16Uint ) return Uint16Array;
|
||||
if ( format === GPUTextureFormat.R16Sint ) return Int16Array;
|
||||
if ( format === GPUTextureFormat.RG16Uint ) return Uint16Array;
|
||||
if ( format === GPUTextureFormat.RG16Sint ) return Int16Array;
|
||||
if ( format === GPUTextureFormat.RGBA16Uint ) return Uint16Array;
|
||||
if ( format === GPUTextureFormat.RGBA16Sint ) return Int16Array;
|
||||
|
||||
|
||||
if ( format === GPUTextureFormat.R32Uint ) return Uint32Array;
|
||||
if ( format === GPUTextureFormat.R32Sint ) return Int32Array;
|
||||
if ( format === GPUTextureFormat.R32Float ) return Float32Array;
|
||||
if ( format === GPUTextureFormat.RG32Uint ) return Uint32Array;
|
||||
if ( format === GPUTextureFormat.RG32Sint ) return Int32Array;
|
||||
if ( format === GPUTextureFormat.RG32Float ) return Float32Array;
|
||||
if ( format === GPUTextureFormat.RGBA32Uint ) return Uint32Array;
|
||||
if ( format === GPUTextureFormat.RGBA32Sint ) return Int32Array;
|
||||
if ( format === GPUTextureFormat.RGBA32Float ) return Float32Array;
|
||||
|
||||
}
|
||||
|
||||
_getDimension( texture ) {
|
||||
|
||||
let dimension;
|
||||
|
||||
if ( texture.isData3DTexture ) {
|
||||
|
||||
dimension = GPUTextureDimension.ThreeD;
|
||||
|
||||
} else {
|
||||
|
||||
dimension = GPUTextureDimension.TwoD;
|
||||
|
||||
}
|
||||
|
||||
return dimension;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export function getFormat( texture, device = null ) {
|
||||
|
||||
const format = texture.format;
|
||||
const type = texture.type;
|
||||
const colorSpace = texture.colorSpace;
|
||||
|
||||
let formatGPU;
|
||||
|
||||
if ( /*texture.isRenderTargetTexture === true ||*/ texture.isFramebufferTexture === true ) {
|
||||
|
||||
formatGPU = GPUTextureFormat.BGRA8Unorm;
|
||||
|
||||
} else if ( texture.isCompressedTexture === true ) {
|
||||
|
||||
switch ( format ) {
|
||||
|
||||
case RGBA_S3TC_DXT1_Format:
|
||||
formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.BC1RGBAUnormSRGB : GPUTextureFormat.BC1RGBAUnorm;
|
||||
break;
|
||||
|
||||
case RGBA_S3TC_DXT3_Format:
|
||||
formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.BC2RGBAUnormSRGB : GPUTextureFormat.BC2RGBAUnorm;
|
||||
break;
|
||||
|
||||
case RGBA_S3TC_DXT5_Format:
|
||||
formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.BC3RGBAUnormSRGB : GPUTextureFormat.BC3RGBAUnorm;
|
||||
break;
|
||||
|
||||
case RGB_ETC2_Format:
|
||||
formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ETC2RGB8UnormSRGB : GPUTextureFormat.ETC2RGB8Unorm;
|
||||
break;
|
||||
|
||||
case RGBA_ETC2_EAC_Format:
|
||||
formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ETC2RGBA8UnormSRGB : GPUTextureFormat.ETC2RGBA8Unorm;
|
||||
break;
|
||||
|
||||
case RGBA_ASTC_4x4_Format:
|
||||
formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC4x4UnormSRGB : GPUTextureFormat.ASTC4x4Unorm;
|
||||
break;
|
||||
|
||||
case RGBA_ASTC_5x4_Format:
|
||||
formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC5x4UnormSRGB : GPUTextureFormat.ASTC5x4Unorm;
|
||||
break;
|
||||
|
||||
case RGBA_ASTC_5x5_Format:
|
||||
formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC5x5UnormSRGB : GPUTextureFormat.ASTC5x5Unorm;
|
||||
break;
|
||||
|
||||
case RGBA_ASTC_6x5_Format:
|
||||
formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC6x5UnormSRGB : GPUTextureFormat.ASTC6x5Unorm;
|
||||
break;
|
||||
|
||||
case RGBA_ASTC_6x6_Format:
|
||||
formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC6x6UnormSRGB : GPUTextureFormat.ASTC6x6Unorm;
|
||||
break;
|
||||
|
||||
case RGBA_ASTC_8x5_Format:
|
||||
formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC8x5UnormSRGB : GPUTextureFormat.ASTC8x5Unorm;
|
||||
break;
|
||||
|
||||
case RGBA_ASTC_8x6_Format:
|
||||
formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC8x6UnormSRGB : GPUTextureFormat.ASTC8x6Unorm;
|
||||
break;
|
||||
|
||||
case RGBA_ASTC_8x8_Format:
|
||||
formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC8x8UnormSRGB : GPUTextureFormat.ASTC8x8Unorm;
|
||||
break;
|
||||
|
||||
case RGBA_ASTC_10x5_Format:
|
||||
formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC10x5UnormSRGB : GPUTextureFormat.ASTC10x5Unorm;
|
||||
break;
|
||||
|
||||
case RGBA_ASTC_10x6_Format:
|
||||
formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC10x6UnormSRGB : GPUTextureFormat.ASTC10x6Unorm;
|
||||
break;
|
||||
|
||||
case RGBA_ASTC_10x8_Format:
|
||||
formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC10x8UnormSRGB : GPUTextureFormat.ASTC10x8Unorm;
|
||||
break;
|
||||
|
||||
case RGBA_ASTC_10x10_Format:
|
||||
formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC10x10UnormSRGB : GPUTextureFormat.ASTC10x10Unorm;
|
||||
break;
|
||||
|
||||
case RGBA_ASTC_12x10_Format:
|
||||
formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC12x10UnormSRGB : GPUTextureFormat.ASTC12x10Unorm;
|
||||
break;
|
||||
|
||||
case RGBA_ASTC_12x12_Format:
|
||||
formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC12x12UnormSRGB : GPUTextureFormat.ASTC12x12Unorm;
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error( 'WebGPURenderer: Unsupported texture format.', format );
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
switch ( format ) {
|
||||
|
||||
case RGBAFormat:
|
||||
|
||||
switch ( type ) {
|
||||
|
||||
case UnsignedByteType:
|
||||
formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.RGBA8UnormSRGB : GPUTextureFormat.RGBA8Unorm;
|
||||
break;
|
||||
|
||||
case HalfFloatType:
|
||||
formatGPU = GPUTextureFormat.RGBA16Float;
|
||||
break;
|
||||
|
||||
case FloatType:
|
||||
formatGPU = GPUTextureFormat.RGBA32Float;
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error( 'WebGPURenderer: Unsupported texture type with RGBAFormat.', type );
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RedFormat:
|
||||
|
||||
switch ( type ) {
|
||||
|
||||
case UnsignedByteType:
|
||||
formatGPU = GPUTextureFormat.R8Unorm;
|
||||
break;
|
||||
|
||||
case HalfFloatType:
|
||||
formatGPU = GPUTextureFormat.R16Float;
|
||||
break;
|
||||
|
||||
case FloatType:
|
||||
formatGPU = GPUTextureFormat.R32Float;
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error( 'WebGPURenderer: Unsupported texture type with RedFormat.', type );
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RGFormat:
|
||||
|
||||
switch ( type ) {
|
||||
|
||||
case UnsignedByteType:
|
||||
formatGPU = GPUTextureFormat.RG8Unorm;
|
||||
break;
|
||||
|
||||
case HalfFloatType:
|
||||
formatGPU = GPUTextureFormat.RG16Float;
|
||||
break;
|
||||
|
||||
case FloatType:
|
||||
formatGPU = GPUTextureFormat.RG32Float;
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error( 'WebGPURenderer: Unsupported texture type with RGFormat.', type );
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case DepthFormat:
|
||||
|
||||
switch ( type ) {
|
||||
|
||||
case UnsignedShortType:
|
||||
formatGPU = GPUTextureFormat.Depth16Unorm;
|
||||
break;
|
||||
|
||||
case UnsignedIntType:
|
||||
formatGPU = GPUTextureFormat.Depth24Plus;
|
||||
break;
|
||||
|
||||
case FloatType:
|
||||
formatGPU = GPUTextureFormat.Depth32Float;
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error( 'WebGPURenderer: Unsupported texture type with DepthFormat.', type );
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case DepthStencilFormat:
|
||||
|
||||
switch ( type ) {
|
||||
|
||||
case UnsignedInt248Type:
|
||||
formatGPU = GPUTextureFormat.Depth24PlusStencil8;
|
||||
break;
|
||||
|
||||
case FloatType:
|
||||
|
||||
if ( device && device.features.has( GPUFeatureName.Depth32FloatStencil8 ) === false ) {
|
||||
|
||||
console.error( 'WebGPURenderer: Depth textures with DepthStencilFormat + FloatType can only be used with the "depth32float-stencil8" GPU feature.' );
|
||||
|
||||
}
|
||||
|
||||
formatGPU = GPUTextureFormat.Depth32FloatStencil8;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error( 'WebGPURenderer: Unsupported texture type with DepthStencilFormat.', type );
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error( 'WebGPURenderer: Unsupported texture format.', format );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return formatGPU;
|
||||
|
||||
}
|
||||
|
||||
export default WebGPUTextureUtils;
|
||||
93
node_modules/three/examples/jsm/renderers/webgpu/utils/WebGPUUtils.js
generated
vendored
Normal file
93
node_modules/three/examples/jsm/renderers/webgpu/utils/WebGPUUtils.js
generated
vendored
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