Просмотр исходного кода

WGSLNodeBuilder: Introduce `generateStorageTextureLoad` (#33029)

sunag 4 дней назад
Родитель
Сommit
d76b5d0031

+ 22 - 0
src/nodes/accessors/StorageTextureNode.js

@@ -162,6 +162,28 @@ class StorageTextureNode extends TextureNode {
 
 	}
 
+	/**
+	 * Generates the snippet for the storage texture.
+	 *
+	 * @param {NodeBuilder} builder - The current node builder.
+	 * @param {string} textureProperty - The texture property.
+	 * @param {string} uvSnippet - The uv snippet.
+	 * @param {?string} levelSnippet - The level snippet.
+	 * @param {?string} biasSnippet - The bias snippet.
+	 * @param {?string} depthSnippet - The depth snippet.
+	 * @param {?string} compareSnippet - The compare snippet.
+	 * @param {?Array<string>} gradSnippet - The grad snippet.
+	 * @param {?string} offsetSnippet - The offset snippet.
+	 * @return {string} The generated code snippet.
+	 */
+	generateSnippet( builder, textureProperty, uvSnippet, levelSnippet, biasSnippet, depthSnippet, compareSnippet, gradSnippet, offsetSnippet ) {
+
+		const texture = this.value;
+
+		return builder.generateStorageTextureLoad( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet, offsetSnippet );
+
+	}
+
 	/**
 	 * Convenience method for configuring a read/write node access.
 	 *

+ 36 - 21
src/renderers/webgpu/nodes/WGSLNodeBuilder.js

@@ -582,7 +582,7 @@ class WGSLNodeBuilder extends NodeBuilder {
 	}
 
 	/**
-	 * Generates the WGSL snippet that reads a single texel from a texture without sampling or filtering.
+	 * Generates the WGSL snippet that reads a single texel from a storage texture.
 	 *
 	 * @param {Texture} texture - The texture.
 	 * @param {string} textureProperty - The name of the texture uniform in the shader.
@@ -592,11 +592,7 @@ class WGSLNodeBuilder extends NodeBuilder {
 	 * @param {?string} offsetSnippet - A WGSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture.
 	 * @return {string} The WGSL snippet.
 	 */
-	generateTextureLoad( texture, textureProperty, uvIndexSnippet, levelSnippet, depthSnippet, offsetSnippet ) {
-
-		const isStorageTexture = texture.isStorageTexture === true;
-
-		if ( levelSnippet === null && ! isStorageTexture ) levelSnippet = '0u';
+	generateStorageTextureLoad( texture, textureProperty, uvIndexSnippet, levelSnippet, depthSnippet, offsetSnippet ) {
 
 		if ( offsetSnippet ) {
 
@@ -608,33 +604,52 @@ class WGSLNodeBuilder extends NodeBuilder {
 
 		if ( depthSnippet ) {
 
-			// Storage textures don't take a level parameter in WGSL
-			if ( isStorageTexture ) {
+			snippet = `textureLoad( ${ textureProperty }, ${ uvIndexSnippet }, ${ depthSnippet } )`;
 
-				snippet = `textureLoad( ${ textureProperty }, ${ uvIndexSnippet }, ${ depthSnippet } )`;
+		} else {
 
-			} else {
+			snippet = `textureLoad( ${ textureProperty }, ${ uvIndexSnippet } )`;
 
-				snippet = `textureLoad( ${ textureProperty }, ${ uvIndexSnippet }, ${ depthSnippet }, u32( ${ levelSnippet } ) )`;
+		}
 
-			}
+		return snippet;
 
-		} else {
+	}
+
+	/**
+	 * Generates the WGSL snippet that reads a single texel from a texture without sampling or filtering.
+	 *
+	 * @param {Texture} texture - The texture.
+	 * @param {string} textureProperty - The name of the texture uniform in the shader.
+	 * @param {string} uvIndexSnippet - A WGSL snippet that represents texture coordinates used for sampling.
+	 * @param {?string} levelSnippet - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture.
+	 * @param {?string} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample.
+	 * @param {?string} offsetSnippet - A WGSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture.
+	 * @return {string} The WGSL snippet.
+	 */
+	generateTextureLoad( texture, textureProperty, uvIndexSnippet, levelSnippet, depthSnippet, offsetSnippet ) {
 
-			// Storage textures don't take a level parameter in WGSL
-			if ( isStorageTexture ) {
+		if ( levelSnippet === null ) levelSnippet = '0u';
 
-				snippet = `textureLoad( ${ textureProperty }, ${ uvIndexSnippet } )`;
+		if ( offsetSnippet ) {
 
-			} else {
+			uvIndexSnippet = `${ uvIndexSnippet } + ${ offsetSnippet }`;
 
-				snippet = `textureLoad( ${ textureProperty }, ${ uvIndexSnippet }, u32( ${ levelSnippet } ) )`;
+		}
 
-				if ( this.renderer.backend.compatibilityMode && texture.isDepthTexture ) {
+		let snippet;
 
-					snippet += '.x';
+		if ( depthSnippet ) {
 
-				}
+			snippet = `textureLoad( ${ textureProperty }, ${ uvIndexSnippet }, ${ depthSnippet }, u32( ${ levelSnippet } ) )`;
+
+		} else {
+
+			snippet = `textureLoad( ${ textureProperty }, ${ uvIndexSnippet }, u32( ${ levelSnippet } ) )`;
+
+			if ( this.renderer.backend.compatibilityMode && texture.isDepthTexture ) {
+
+				snippet += '.x';
 
 			}
 

+ 0 - 39
test/unit/src/nodes/accessors/StorageTextureNode.tests.js

@@ -1,39 +0,0 @@
-import { storageTexture } from '../../../../../src/nodes/accessors/StorageTextureNode.js';
-import { NodeAccess } from '../../../../../src/nodes/core/constants.js';
-import StorageTexture from '../../../../../src/renderers/common/StorageTexture.js';
-
-export default QUnit.module( 'Nodes', () => {
-
-	QUnit.module( 'Accessors', () => {
-
-		QUnit.module( 'StorageTextureNode', () => {
-
-			QUnit.test( 'clone preserves access property', ( assert ) => {
-
-				const texture = new StorageTexture( 512, 512 );
-				const node = storageTexture( texture ).setAccess( NodeAccess.READ_ONLY );
-
-				assert.strictEqual( node.access, NodeAccess.READ_ONLY, 'original has READ_ONLY access' );
-
-				const cloned = node.clone();
-
-				assert.strictEqual( cloned.access, NodeAccess.READ_ONLY, 'cloned node preserves READ_ONLY access' );
-
-			} );
-
-			QUnit.test( 'clone preserves READ_WRITE access', ( assert ) => {
-
-				const texture = new StorageTexture( 512, 512 );
-				const node = storageTexture( texture ).setAccess( NodeAccess.READ_WRITE );
-
-				const cloned = node.clone();
-
-				assert.strictEqual( cloned.access, NodeAccess.READ_WRITE, 'cloned node preserves READ_WRITE access' );
-
-			} );
-
-		} );
-
-	} );
-
-} );

+ 0 - 69
test/unit/src/renderers/webgpu/nodes/WGSLNodeBuilder.tests.js

@@ -1,69 +0,0 @@
-import WGSLNodeBuilder from '../../../../../../src/renderers/webgpu/nodes/WGSLNodeBuilder.js';
-
-export default QUnit.module( 'Renderers', () => {
-
-	QUnit.module( 'WebGPU', () => {
-
-		QUnit.module( 'Nodes', () => {
-
-			QUnit.module( 'WGSLNodeBuilder', () => {
-
-				// generateTextureLoad is essentially a pure function (texture info -> WGSL string)
-				// The only 'this' access is renderer.backend.compatibilityMode for a depth texture edge case
-				// We test the real method with minimal context to verify WGSL output
-
-				QUnit.test( 'generateTextureLoad omits level for storage textures', ( assert ) => {
-
-					const context = {
-						renderer: { backend: { compatibilityMode: false } }
-					};
-
-					const storageTexture = { isStorageTexture: true };
-
-					const snippet = WGSLNodeBuilder.prototype.generateTextureLoad.call(
-						context,
-						storageTexture,
-						'testTexture',
-						'uvec2(0, 0)',
-						null, // levelSnippet
-						null, // depthSnippet
-						null // offsetSnippet
-					);
-
-					// Storage textures should NOT have level parameter (WGSL spec)
-					assert.notOk( snippet.includes( 'u32(' ), 'storage texture load should not include level parameter' );
-					assert.strictEqual( snippet, 'textureLoad( testTexture, uvec2(0, 0) )', 'correct WGSL for storage texture' );
-
-				} );
-
-				QUnit.test( 'generateTextureLoad includes level for regular textures', ( assert ) => {
-
-					const context = {
-						renderer: { backend: { compatibilityMode: false } }
-					};
-
-					const regularTexture = { isStorageTexture: false };
-
-					const snippet = WGSLNodeBuilder.prototype.generateTextureLoad.call(
-						context,
-						regularTexture,
-						'testTexture',
-						'uvec2(0, 0)',
-						null, // levelSnippet - should default to '0u'
-						null,
-						null
-					);
-
-					// Regular textures SHOULD have level parameter
-					assert.ok( snippet.includes( 'u32( 0u )' ), 'regular texture load should include default level parameter' );
-					assert.strictEqual( snippet, 'textureLoad( testTexture, uvec2(0, 0), u32( 0u ) )' );
-
-				} );
-
-			} );
-
-		} );
-
-	} );
-
-} );

+ 0 - 6
test/unit/three.source.unit.js

@@ -265,12 +265,6 @@ import './src/renderers/webgl/WebGLTextures.tests.js';
 import './src/renderers/webgl/WebGLUniforms.tests.js';
 import './src/renderers/webgl/WebGLUtils.tests.js';
 
-//src/renderers/webgpu/nodes
-import './src/renderers/webgpu/nodes/WGSLNodeBuilder.tests.js';
-
-//src/nodes/accessors
-import './src/nodes/accessors/StorageTextureNode.tests.js';
-
 
 //src/scenes
 import './src/scenes/Fog.tests.js';

粤ICP备19079148号