瀏覽代碼

WebGPURenderer: copyTextureToTexture subframe upload and new API (#28315)

* align copyTextureToTexture with webglrenderer

* Update webgpu_materials_texture_partialupdate.html

---------
Renaud Rohlinger 1 年之前
父節點
當前提交
a6fba0fc3d

+ 2 - 2
examples/jsm/renderers/common/Renderer.js

@@ -1086,12 +1086,12 @@ class Renderer {
 
 	}
 
-	copyTextureToTexture( position, srcTexture, dstTexture, level = 0 ) {
+	copyTextureToTexture( srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0 ) {
 
 		this._textures.updateTexture( srcTexture );
 		this._textures.updateTexture( dstTexture );
 
-		this.backend.copyTextureToTexture( position, srcTexture, dstTexture, level );
+		this.backend.copyTextureToTexture( srcTexture, dstTexture, srcRegion, dstPosition, level );
 
 	}
 

+ 56 - 6
examples/jsm/renderers/webgl/utils/WebGLTextureUtils.js

@@ -524,41 +524,91 @@ class WebGLTextureUtils {
 
 	}
 
-	copyTextureToTexture( position, srcTexture, dstTexture, level = 0 ) {
+	copyTextureToTexture( srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0 ) {
 
 		const { gl, backend } = this;
 		const { state } = this.backend;
 
-		const width = srcTexture.image.width;
-		const height = srcTexture.image.height;
 		const { textureGPU: dstTextureGPU, glTextureType, glType, glFormat } = backend.get( dstTexture );
 
+
+		let width, height, minX, minY;
+		let dstX, dstY;
+		if ( srcRegion !== null ) {
+
+			width = srcRegion.max.x - srcRegion.min.x;
+			height = srcRegion.max.y - srcRegion.min.y;
+			minX = srcRegion.min.x;
+			minY = srcRegion.min.y;
+
+		} else {
+
+			width = srcTexture.image.width;
+			height = srcTexture.image.height;
+			minX = 0;
+			minY = 0;
+
+		}
+
+		if ( dstPosition !== null ) {
+
+			dstX = dstPosition.x;
+			dstY = dstPosition.y;
+
+		} else {
+
+			dstX = 0;
+			dstY = 0;
+
+		}
+
 		state.bindTexture( glTextureType, dstTextureGPU );
 
 		// As another texture upload may have changed pixelStorei
 		// parameters, make sure they are correct for the dstTexture
+		gl.pixelStorei( gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment );
 		gl.pixelStorei( gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY );
 		gl.pixelStorei( gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha );
 		gl.pixelStorei( gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment );
 
+		const currentUnpackRowLen = gl.getParameter( gl.UNPACK_ROW_LENGTH );
+		const currentUnpackImageHeight = gl.getParameter( gl.UNPACK_IMAGE_HEIGHT );
+		const currentUnpackSkipPixels = gl.getParameter( gl.UNPACK_SKIP_PIXELS );
+		const currentUnpackSkipRows = gl.getParameter( gl.UNPACK_SKIP_ROWS );
+		const currentUnpackSkipImages = gl.getParameter( gl.UNPACK_SKIP_IMAGES );
+
+		const image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[ level ] : srcTexture.image;
+
+		gl.pixelStorei( gl.UNPACK_ROW_LENGTH, image.width );
+		gl.pixelStorei( gl.UNPACK_IMAGE_HEIGHT, image.height );
+		gl.pixelStorei( gl.UNPACK_SKIP_PIXELS, minX );
+		gl.pixelStorei( gl.UNPACK_SKIP_ROWS, minY );
+
+
 		if ( srcTexture.isDataTexture ) {
 
-			gl.texSubImage2D( gl.TEXTURE_2D, level, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data );
+			gl.texSubImage2D( gl.TEXTURE_2D, level, dstX, dstY, width, height, glFormat, glType, image.data );
 
 		} else {
 
 			if ( srcTexture.isCompressedTexture ) {
 
-				gl.compressedTexSubImage2D( gl.TEXTURE_2D, level, position.x, position.y, srcTexture.mipmaps[ 0 ].width, srcTexture.mipmaps[ 0 ].height, glFormat, srcTexture.mipmaps[ 0 ].data );
+				gl.compressedTexSubImage2D( gl.TEXTURE_2D, level, dstX, dstY, image.width, image.height, glFormat, image.data );
 
 			} else {
 
-				gl.texSubImage2D( gl.TEXTURE_2D, level, position.x, position.y, glFormat, glType, srcTexture.image );
+				gl.texSubImage2D( gl.TEXTURE_2D, level, dstX, dstY, glFormat, glType, image );
 
 			}
 
 		}
 
+		gl.pixelStorei( gl.UNPACK_ROW_LENGTH, currentUnpackRowLen );
+		gl.pixelStorei( gl.UNPACK_IMAGE_HEIGHT, currentUnpackImageHeight );
+		gl.pixelStorei( gl.UNPACK_SKIP_PIXELS, currentUnpackSkipPixels );
+		gl.pixelStorei( gl.UNPACK_SKIP_ROWS, currentUnpackSkipRows );
+		gl.pixelStorei( gl.UNPACK_SKIP_IMAGES, currentUnpackSkipImages );
+
 		// Generate mipmaps only when copying level 0
 		if ( level === 0 && dstTexture.generateMipmaps ) gl.generateMipmap( gl.TEXTURE_2D );
 

+ 12 - 2
examples/jsm/renderers/webgpu/WebGPUBackend.js

@@ -1235,8 +1235,18 @@ class WebGPUBackend extends Backend {
 
 	}
 
-	copyTextureToTexture( position, srcTexture, dstTexture, level = 0 ) {
+	copyTextureToTexture( srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0 ) {
 
+		let dstX = 0;
+		let dstY = 0;
+
+		if ( dstPosition !== null ) {
+
+			dstX = dstPosition.x;
+			dstY = dstPosition.y;
+
+		}
+		
 		const encoder = this.device.createCommandEncoder( { label: 'copyTextureToTexture_' + srcTexture.id + '_' + dstTexture.id } );
 
 		const sourceGPU = this.get( srcTexture ).texture;
@@ -1251,7 +1261,7 @@ class WebGPUBackend extends Backend {
 			{
 				texture: destinationGPU,
 				mipLevel: level,
-				origin: { x: position.x, y: position.y, z: position.z }
+				origin: { x: dstX, y: dstY, z: 0 }
 			},
 			[
 				srcTexture.image.width,

+ 1 - 1
examples/webgpu_materials_texture_partialupdate.html

@@ -110,7 +110,7 @@
 
 					// perform copy from src to dest texture to a random position
 
-					renderer.copyTextureToTexture( position, dataTexture, diffuseMap );
+					renderer.copyTextureToTexture( dataTexture, diffuseMap, new THREE.Vector2(), position );
 
 				}