From e6ec29855fb963a82083aee260b6e1143ea0378d Mon Sep 17 00:00:00 2001 From: sunag Date: Mon, 18 Mar 2024 13:22:04 -0300 Subject: [PATCH] WebGPURenderer: Improve support int/uint textures (#27932) --- examples/jsm/nodes/core/NodeBuilder.js | 21 ++--- .../renderers/webgpu/nodes/WGSLNodeBuilder.js | 8 +- .../webgpu/utils/WebGPUBindingUtils.js | 22 ++++- .../webgpu/utils/WebGPUTextureUtils.js | 89 +++++++++++++++---- 4 files changed, 104 insertions(+), 36 deletions(-) diff --git a/examples/jsm/nodes/core/NodeBuilder.js b/examples/jsm/nodes/core/NodeBuilder.js index 7635342522338b..35ae6643716fd3 100644 --- a/examples/jsm/nodes/core/NodeBuilder.js +++ b/examples/jsm/nodes/core/NodeBuilder.js @@ -15,7 +15,7 @@ import { ColorNodeUniform, Matrix3NodeUniform, Matrix4NodeUniform } from '../../renderers/common/nodes/NodeUniform.js'; -import { REVISION, RenderTarget, NoColorSpace, Color, Vector2, Vector3, Vector4, Float16BufferAttribute } from 'three'; +import { REVISION, RenderTarget, Color, Vector2, Vector3, Vector4, IntType, UnsignedIntType, Float16BufferAttribute } from 'three'; import { stack } from './StackNode.js'; import { getCurrentStack, setCurrentStack } from '../shadernode/ShaderNode.js'; @@ -484,25 +484,18 @@ class NodeBuilder { } - getTextureColorSpaceFromMap( map ) { + getComponentTypeFromTexture( texture ) { - let colorSpace; + const type = texture.type; - if ( map && map.isTexture ) { + if ( texture.isDataTexture ) { - colorSpace = map.colorSpace; - - } else if ( map && map.isWebGLRenderTarget ) { - - colorSpace = map.texture.colorSpace; - - } else { - - colorSpace = NoColorSpace; + if ( type === IntType ) return 'int'; + if ( type === UnsignedIntType ) return 'uint'; } - return colorSpace; + return 'float'; } diff --git a/examples/jsm/renderers/webgpu/nodes/WGSLNodeBuilder.js b/examples/jsm/renderers/webgpu/nodes/WGSLNodeBuilder.js index cd214f7fe0f8a7..66eea30b2a0ad9 100644 --- a/examples/jsm/renderers/webgpu/nodes/WGSLNodeBuilder.js +++ b/examples/jsm/renderers/webgpu/nodes/WGSLNodeBuilder.js @@ -228,7 +228,7 @@ class WGSLNodeBuilder extends NodeBuilder { isUnfilterable( texture ) { - return texture.isDataTexture === true && texture.type === FloatType; + return this.getComponentTypeFromTexture( texture ) !== 'float' || ( texture.isDataTexture === true && texture.type === FloatType ); } @@ -759,11 +759,13 @@ ${ flowData.code } const format = getFormat( texture ); - textureType = 'texture_storage_2d<' + format + ', write>'; + textureType = `texture_storage_2d<${ format }, write>`; } else { - textureType = 'texture_2d'; + const componentPrefix = this.getComponentTypeFromTexture( texture ).charAt( 0 ); + + textureType = `texture_2d<${ componentPrefix }32>`; } diff --git a/examples/jsm/renderers/webgpu/utils/WebGPUBindingUtils.js b/examples/jsm/renderers/webgpu/utils/WebGPUBindingUtils.js index 16169fc49d1d46..cc59d7074c60c0 100644 --- a/examples/jsm/renderers/webgpu/utils/WebGPUBindingUtils.js +++ b/examples/jsm/renderers/webgpu/utils/WebGPUBindingUtils.js @@ -1,7 +1,7 @@ import { GPUTextureAspect, GPUTextureViewDimension, GPUBufferBindingType, GPUTextureSampleType } from './WebGPUConstants.js'; -import { FloatType } from 'three'; +import { FloatType, IntType, UnsignedIntType } from 'three'; class WebGPUBindingUtils { @@ -73,11 +73,25 @@ class WebGPUBindingUtils { texture.sampleType = GPUTextureSampleType.Depth; - } else if ( binding.texture.isDataTexture && binding.texture.type === FloatType ) { + } else if ( binding.texture.isDataTexture ) { - // @TODO: Add support for this soon: backend.hasFeature( 'float32-filterable' ) + const type = binding.texture.type; - texture.sampleType = GPUTextureSampleType.UnfilterableFloat; + if ( type === IntType ) { + + texture.sampleType = GPUTextureSampleType.SInt; + + } else if ( type === UnsignedIntType ) { + + texture.sampleType = GPUTextureSampleType.UInt; + + } else if ( type === FloatType ) { + + // @TODO: Add support for this soon: backend.hasFeature( 'float32-filterable' ) + + texture.sampleType = GPUTextureSampleType.UnfilterableFloat; + + } } diff --git a/examples/jsm/renderers/webgpu/utils/WebGPUTextureUtils.js b/examples/jsm/renderers/webgpu/utils/WebGPUTextureUtils.js index 44162a4a5c6b95..10308594d74a7a 100644 --- a/examples/jsm/renderers/webgpu/utils/WebGPUTextureUtils.js +++ b/examples/jsm/renderers/webgpu/utils/WebGPUTextureUtils.js @@ -10,7 +10,7 @@ import { 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 + NeverCompare, AlwaysCompare, LessCompare, LessEqualCompare, EqualCompare, GreaterEqualCompare, GreaterCompare, NotEqualCompare, IntType, RedIntegerFormat, RGIntegerFormat, RGBAIntegerFormat } from 'three'; import { CubeReflectionMapping, CubeRefractionMapping, EquirectangularReflectionMapping, EquirectangularRefractionMapping, DepthTexture } from 'three'; @@ -38,8 +38,8 @@ class WebGPUTextureUtils { this._passUtils = null; - this.defaultTexture = null; - this.defaultCubeTexture = null; + this.defaultTexture = {}; + this.defaultCubeTexture = {}; this.colorBuffer = null; @@ -79,13 +79,15 @@ class WebGPUTextureUtils { let textureGPU; + const format = getFormat( texture ); + if ( texture.isCubeTexture ) { - textureGPU = this._getDefaultCubeTextureGPU(); + textureGPU = this._getDefaultCubeTextureGPU( format ); } else { - textureGPU = this._getDefaultTextureGPU(); + textureGPU = this._getDefaultTextureGPU( format ); } @@ -111,7 +113,7 @@ class WebGPUTextureUtils { const { width, height, depth, levels } = options; const dimension = this._getDimension( texture ); - const format = texture.internalFormat || getFormat( texture, backend.device ); + const format = texture.internalFormat || options.format || getFormat( texture, backend.device ); let sampleCount = options.sampleCount !== undefined ? options.sampleCount : 1; @@ -422,19 +424,19 @@ class WebGPUTextureUtils { } - _getDefaultTextureGPU() { + _getDefaultTextureGPU( format ) { - let defaultTexture = this.defaultTexture; + let defaultTexture = this.defaultTexture[ format ]; - if ( defaultTexture === null ) { + if ( defaultTexture === undefined ) { const texture = new Texture(); texture.minFilter = NearestFilter; texture.magFilter = NearestFilter; - this.createTexture( texture, { width: 1, height: 1 } ); + this.createTexture( texture, { width: 1, height: 1, format } ); - this.defaultTexture = defaultTexture = texture; + this.defaultTexture[ format ] = defaultTexture = texture; } @@ -442,11 +444,11 @@ class WebGPUTextureUtils { } - _getDefaultCubeTextureGPU() { + _getDefaultCubeTextureGPU( format ) { - let defaultCubeTexture = this.defaultTexture; + let defaultCubeTexture = this.defaultTexture[ format ]; - if ( defaultCubeTexture === null ) { + if ( defaultCubeTexture === undefined ) { const texture = new CubeTexture(); texture.minFilter = NearestFilter; @@ -454,7 +456,7 @@ class WebGPUTextureUtils { this.createTexture( texture, { width: 1, height: 1, depth: 6 } ); - this.defaultCubeTexture = defaultCubeTexture = texture; + this.defaultCubeTexture[ format ] = defaultCubeTexture = texture; } @@ -1026,6 +1028,63 @@ export function getFormat( texture, device = null ) { break; + case RedIntegerFormat: + + switch ( type ) { + + case IntType: + formatGPU = GPUTextureFormat.R32Sint; + break; + + case UnsignedIntType: + formatGPU = GPUTextureFormat.R32Uint; + break; + + default: + console.error( 'WebGPURenderer: Unsupported texture type with RedIntegerFormat.', type ); + + } + + break; + + case RGIntegerFormat: + + switch ( type ) { + + case IntType: + formatGPU = GPUTextureFormat.RG32Sint; + break; + + case UnsignedIntType: + formatGPU = GPUTextureFormat.RG32Uint; + break; + + default: + console.error( 'WebGPURenderer: Unsupported texture type with RGIntegerFormat.', type ); + + } + + break; + + case RGBAIntegerFormat: + + switch ( type ) { + + case IntType: + formatGPU = GPUTextureFormat.RGBA32Sint; + break; + + case UnsignedIntType: + formatGPU = GPUTextureFormat.RGBA32Uint; + break; + + default: + console.error( 'WebGPURenderer: Unsupported texture type with RGBAIntegerFormat.', type ); + + } + + break; + default: console.error( 'WebGPURenderer: Unsupported texture format.', format );