From 304f612a2ebece5ecb5088eb95ba38f4ea643340 Mon Sep 17 00:00:00 2001
From: Garrett Johnson
Date: Sun, 5 May 2024 23:59:55 +0900
Subject: [PATCH 1/9] Copy to async implementation from #24466
---
examples/gi_test.html | 286 ++++++++++++++++++++++
examples/webgl_interactive_cubes_gpu.html | 28 ++-
src/renderers/WebGLRenderer.js | 147 ++++++++++-
src/utils.js | 29 ++-
4 files changed, 475 insertions(+), 15 deletions(-)
create mode 100644 examples/gi_test.html
diff --git a/examples/gi_test.html b/examples/gi_test.html
new file mode 100644
index 00000000000000..e4b6679cfc39e3
--- /dev/null
+++ b/examples/gi_test.html
@@ -0,0 +1,286 @@
+
+
+
+ three.js webgl - simple global illumination
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/webgl_interactive_cubes_gpu.html b/examples/webgl_interactive_cubes_gpu.html
index 013f82acaf0ff8..813ce836f6c628 100644
--- a/examples/webgl_interactive_cubes_gpu.html
+++ b/examples/webgl_interactive_cubes_gpu.html
@@ -261,23 +261,27 @@
const pixelBuffer = new Int32Array( 4 );
// read the pixel
- renderer.readRenderTargetPixels( pickingTexture, 0, 0, 1, 1, pixelBuffer );
+ renderer
+ .readRenderTargetPixelsAsync( pickingTexture, 0, 0, 1, 1, pixelBuffer )
+ .then( () => {
- const id = pixelBuffer[ 0 ];
- if ( id !== - 1 ) {
+ const id = pixelBuffer[ 0 ];
+ if ( id !== - 1 ) {
- // move our highlightBox so that it surrounds the picked object
- const data = pickingData[ id ];
- highlightBox.position.copy( data.position );
- highlightBox.rotation.copy( data.rotation );
- highlightBox.scale.copy( data.scale ).add( offset );
- highlightBox.visible = true;
+ // move our highlightBox so that it surrounds the picked object
+ const data = pickingData[ id ];
+ highlightBox.position.copy( data.position );
+ highlightBox.rotation.copy( data.rotation );
+ highlightBox.scale.copy( data.scale ).add( offset );
+ highlightBox.visible = true;
- } else {
+ } else {
- highlightBox.visible = false;
+ highlightBox.visible = false;
- }
+ }
+
+ } );
}
diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js
index 6fe5a52fa19f08..9b37c7d36473f4 100644
--- a/src/renderers/WebGLRenderer.js
+++ b/src/renderers/WebGLRenderer.js
@@ -19,7 +19,9 @@ import {
UnsignedShort5551Type,
WebGLCoordinateSystem,
DisplayP3ColorSpace,
- LinearDisplayP3ColorSpace
+ LinearDisplayP3ColorSpace,
+ RGBAFormat,
+ FloatType
} from '../constants.js';
import { Color } from '../math/Color.js';
import { Frustum } from '../math/Frustum.js';
@@ -54,7 +56,7 @@ import { WebGLUtils } from './webgl/WebGLUtils.js';
import { WebXRManager } from './webxr/WebXRManager.js';
import { WebGLMaterials } from './webgl/WebGLMaterials.js';
import { WebGLUniformsGroups } from './webgl/WebGLUniformsGroups.js';
-import { createCanvasElement } from '../utils.js';
+import { createCanvasElement, probeAsync } from '../utils.js';
import { ColorManagement } from '../math/ColorManagement.js';
class WebGLRenderer {
@@ -2357,6 +2359,147 @@ class WebGLRenderer {
};
+ this.createReadbackBuffer = function ( byteLength ) {
+
+ const glBuffer = _gl.createBuffer();
+
+ _gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );
+ _gl.bufferData( _gl.PIXEL_PACK_BUFFER, byteLength, _gl.STREAM_READ );
+
+ return glBuffer;
+
+ };
+
+ this.readbackPixels = function ( glBuffer, typedarray ) {
+
+ _gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );
+ _gl.getBufferSubData( _gl.PIXEL_PACK_BUFFER, 0, typedarray );
+
+ };
+
+ this.disposeReadbackBuffer = function ( glBuffer ) {
+
+ if ( ! glBuffer || ! Number.isInteger( glBuffer ) ) {
+
+ console.error( 'THREE.WebGLRenderer.disposePixelBuffer: invalid glBuffer.' );
+ return;
+
+ }
+
+ _gl.deleteBuffer( glBuffer );
+
+ };
+
+ this.readRenderTargetPixelsAsync = async function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex, options ) {
+
+ return new Promise( ( resolve, reject ) => {
+
+ if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) {
+
+ console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );
+ reject();
+
+ }
+
+ let framebuffer = properties.get( renderTarget ).__webglFramebuffer;
+
+ if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) {
+
+ framebuffer = framebuffer[ activeCubeFaceIndex ];
+
+ }
+
+ if ( framebuffer ) {
+
+ state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
+
+ try {
+
+ const texture = renderTarget.texture;
+ const textureFormat = texture.format;
+ const textureType = texture.type;
+
+ if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) {
+
+ console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' );
+ reject();
+
+ }
+
+ const halfFloatSupportedByExt = ( textureType === HalfFloatType ) && ( extensions.has( 'EXT_color_buffer_half_float' ) || ( capabilities.isWebGL2 && extensions.has( 'EXT_color_buffer_float' ) ) );
+
+ if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_TYPE ) && // Edge and Chrome Mac < 52 (#9513)
+ ! ( textureType === FloatType && ( capabilities.isWebGL2 || extensions.has( 'OES_texture_float' ) || extensions.has( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox
+ ! halfFloatSupportedByExt ) {
+
+ console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' );
+ reject();
+
+ }
+
+ // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)
+
+ if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {
+
+ const asyncOptions = options || {};
+
+ const glBuffer = ( asyncOptions.glBuffer != undefined ) ? asyncOptions.glBuffer : _gl.createBuffer();
+ const byteOffset = ( asyncOptions.byteOffset != undefined ) ? asyncOptions.byteOffset : 0;
+ const interval = ( asyncOptions.interval != undefined ) ? asyncOptions.interval : 8;
+ const shouldSync = ( asyncOptions.sync != undefined ) ? asyncOptions.sync : true;
+ const shouldReadback = ( asyncOptions.readback != undefined ) ? asyncOptions.readback : true;
+
+ _gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );
+
+ if ( ! asyncOptions.glBuffer )
+ _gl.bufferData( _gl.PIXEL_PACK_BUFFER, buffer.byteLength, _gl.STREAM_READ );
+
+ _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), byteOffset );
+ _gl.flush();
+
+ if ( shouldSync ) {
+
+ const sync = _gl.fenceSync( _gl.SYNC_GPU_COMMANDS_COMPLETE, 0 );
+
+ probeAsync( _gl, sync, interval ).then( () => {
+
+ if ( shouldReadback )
+ this.readbackPixels( glBuffer, buffer );
+
+ resolve( buffer || true );
+
+ } ).finally( () => {
+
+ if ( ! asyncOptions.glBuffer )
+ _gl.deleteBuffer( glBuffer );
+
+ _gl.deleteSync( sync );
+
+ } ).catch( () => reject() );
+
+ } else {
+
+ resolve( false );
+
+ }
+
+ }
+
+ } finally {
+
+ // restore framebuffer of current render target if necessary
+
+ const framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null;
+ state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
+
+ }
+
+ }
+
+ } );
+
+ };
+
this.copyFramebufferToTexture = function ( position, texture, level = 0 ) {
const levelScale = Math.pow( 2, - level );
diff --git a/src/utils.js b/src/utils.js
index 6fd13ca9dee638..494a83aacfcb0e 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -88,4 +88,31 @@ function warnOnce( message ) {
}
-export { arrayMin, arrayMax, arrayNeedsUint32, getTypedArray, createElementNS, createCanvasElement, warnOnce };
+async function probeAsync( gl, sync, interval ) {
+
+ return new Promise( function ( resolveProbe, rejectProbe ) {
+
+ function probe() {
+
+ switch ( gl.clientWaitSync( sync, gl.SYNC_FLUSH_COMMANDS_BIT, 0 ) ) {
+
+ case gl.WAIT_FAILED:
+ rejectProbe(); break;
+
+ case gl.TIMEOUT_EXPIRED:
+ setTimeout( probe, interval ); break;
+
+ default:
+ resolveProbe();
+
+ }
+
+ }
+
+ setTimeout( probe );
+
+ } );
+
+}
+
+export { arrayMin, arrayMax, arrayNeedsUint32, getTypedArray, createElementNS, createCanvasElement, warnOnce, probeAsync };
From 78bec30adcc65acb11777073f0bd570fb5f134ac Mon Sep 17 00:00:00 2001
From: Garrett Johnson
Date: Mon, 6 May 2024 00:11:26 +0900
Subject: [PATCH 2/9] probeSync cleanup
---
src/utils.js | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/src/utils.js b/src/utils.js
index 494a83aacfcb0e..3c333e5085f402 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -88,28 +88,30 @@ function warnOnce( message ) {
}
-async function probeAsync( gl, sync, interval ) {
+function probeAsync( gl, sync, interval ) {
- return new Promise( function ( resolveProbe, rejectProbe ) {
+ return new Promise( function ( resolve, reject ) {
function probe() {
switch ( gl.clientWaitSync( sync, gl.SYNC_FLUSH_COMMANDS_BIT, 0 ) ) {
case gl.WAIT_FAILED:
- rejectProbe(); break;
+ reject();
+ break;
case gl.TIMEOUT_EXPIRED:
- setTimeout( probe, interval ); break;
+ setTimeout( probe, interval );
+ break;
default:
- resolveProbe();
+ resolve();
}
}
- setTimeout( probe );
+ setTimeout( probe, interval );
} );
From 7be074f01a757fab08d89e62b505481009620942 Mon Sep 17 00:00:00 2001
From: Garrett Johnson
Date: Mon, 6 May 2024 00:22:14 +0900
Subject: [PATCH 3/9] More simplification
---
src/renderers/WebGLRenderer.js | 49 +++++++++++-----------------------
1 file changed, 16 insertions(+), 33 deletions(-)
diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js
index 9b37c7d36473f4..f33fb242c19d83 100644
--- a/src/renderers/WebGLRenderer.js
+++ b/src/renderers/WebGLRenderer.js
@@ -2390,7 +2390,7 @@ class WebGLRenderer {
};
- this.readRenderTargetPixelsAsync = async function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex, options ) {
+ this.readRenderTargetPixelsAsync = async function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex ) {
return new Promise( ( resolve, reject ) => {
@@ -2441,47 +2441,30 @@ class WebGLRenderer {
if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {
- const asyncOptions = options || {};
-
- const glBuffer = ( asyncOptions.glBuffer != undefined ) ? asyncOptions.glBuffer : _gl.createBuffer();
- const byteOffset = ( asyncOptions.byteOffset != undefined ) ? asyncOptions.byteOffset : 0;
- const interval = ( asyncOptions.interval != undefined ) ? asyncOptions.interval : 8;
- const shouldSync = ( asyncOptions.sync != undefined ) ? asyncOptions.sync : true;
- const shouldReadback = ( asyncOptions.readback != undefined ) ? asyncOptions.readback : true;
-
+ const interval = 8;
+ const glBuffer = _gl.createBuffer();
_gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );
+ _gl.bufferData( _gl.PIXEL_PACK_BUFFER, buffer.byteLength, _gl.STREAM_READ );
- if ( ! asyncOptions.glBuffer )
- _gl.bufferData( _gl.PIXEL_PACK_BUFFER, buffer.byteLength, _gl.STREAM_READ );
-
- _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), byteOffset );
- _gl.flush();
-
- if ( shouldSync ) {
-
- const sync = _gl.fenceSync( _gl.SYNC_GPU_COMMANDS_COMPLETE, 0 );
+ _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), 0 );
+ // _gl.flush();
- probeAsync( _gl, sync, interval ).then( () => {
+ const sync = _gl.fenceSync( _gl.SYNC_GPU_COMMANDS_COMPLETE, 0 );
+ probeAsync( _gl, sync, interval ).then( () => {
- if ( shouldReadback )
- this.readbackPixels( glBuffer, buffer );
+ this.readbackPixels( glBuffer, buffer );
+ resolve( buffer );
- resolve( buffer || true );
+ } ).finally( () => {
- } ).finally( () => {
+ _gl.deleteBuffer( glBuffer );
+ _gl.deleteSync( sync );
- if ( ! asyncOptions.glBuffer )
- _gl.deleteBuffer( glBuffer );
+ } ).catch( () => {
- _gl.deleteSync( sync );
+ reject();
- } ).catch( () => reject() );
-
- } else {
-
- resolve( false );
-
- }
+ } );
}
From f7c5cd2bcf02a21e4d7724312a30a4b842ae51bd Mon Sep 17 00:00:00 2001
From: Garrett Johnson
Date: Mon, 6 May 2024 00:31:44 +0900
Subject: [PATCH 4/9] Simplification
---
src/renderers/WebGLRenderer.js | 105 ++++++++++++++++-----------------
1 file changed, 51 insertions(+), 54 deletions(-)
diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js
index f33fb242c19d83..b2ef797fc21b17 100644
--- a/src/renderers/WebGLRenderer.js
+++ b/src/renderers/WebGLRenderer.js
@@ -2392,94 +2392,91 @@ class WebGLRenderer {
this.readRenderTargetPixelsAsync = async function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex ) {
- return new Promise( ( resolve, reject ) => {
-
- if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) {
-
- console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );
- reject();
-
- }
-
- let framebuffer = properties.get( renderTarget ).__webglFramebuffer;
+ if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) {
- if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) {
+ console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );
+ // reject();
+ throw new Error();
- framebuffer = framebuffer[ activeCubeFaceIndex ];
+ }
- }
+ let framebuffer = properties.get( renderTarget ).__webglFramebuffer;
- if ( framebuffer ) {
+ if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) {
- state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
+ framebuffer = framebuffer[ activeCubeFaceIndex ];
- try {
+ }
- const texture = renderTarget.texture;
- const textureFormat = texture.format;
- const textureType = texture.type;
+ if ( framebuffer ) {
- if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) {
+ state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
- console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' );
- reject();
+ try {
- }
+ const texture = renderTarget.texture;
+ const textureFormat = texture.format;
+ const textureType = texture.type;
- const halfFloatSupportedByExt = ( textureType === HalfFloatType ) && ( extensions.has( 'EXT_color_buffer_half_float' ) || ( capabilities.isWebGL2 && extensions.has( 'EXT_color_buffer_float' ) ) );
+ if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) {
- if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_TYPE ) && // Edge and Chrome Mac < 52 (#9513)
- ! ( textureType === FloatType && ( capabilities.isWebGL2 || extensions.has( 'OES_texture_float' ) || extensions.has( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox
- ! halfFloatSupportedByExt ) {
+ console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' );
+ // reject();
+ throw new Error();
- console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' );
- reject();
+ }
- }
+ const halfFloatSupportedByExt = ( textureType === HalfFloatType ) && ( extensions.has( 'EXT_color_buffer_half_float' ) || ( capabilities.isWebGL2 && extensions.has( 'EXT_color_buffer_float' ) ) );
- // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)
+ if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_TYPE ) && // Edge and Chrome Mac < 52 (#9513)
+ ! ( textureType === FloatType && ( capabilities.isWebGL2 || extensions.has( 'OES_texture_float' ) || extensions.has( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox
+ ! halfFloatSupportedByExt ) {
- if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {
+ console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' );
+ // reject();
+ throw new Error();
- const interval = 8;
- const glBuffer = _gl.createBuffer();
- _gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );
- _gl.bufferData( _gl.PIXEL_PACK_BUFFER, buffer.byteLength, _gl.STREAM_READ );
+ }
- _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), 0 );
- // _gl.flush();
+ // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)
+ if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {
- const sync = _gl.fenceSync( _gl.SYNC_GPU_COMMANDS_COMPLETE, 0 );
- probeAsync( _gl, sync, interval ).then( () => {
+ const interval = 8;
+ const glBuffer = _gl.createBuffer();
+ _gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );
+ _gl.bufferData( _gl.PIXEL_PACK_BUFFER, buffer.byteLength, _gl.STREAM_READ );
- this.readbackPixels( glBuffer, buffer );
- resolve( buffer );
+ _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), 0 );
+ // _gl.flush();
- } ).finally( () => {
+ const sync = _gl.fenceSync( _gl.SYNC_GPU_COMMANDS_COMPLETE, 0 );
+ await probeAsync( _gl, sync, interval )
- _gl.deleteBuffer( glBuffer );
- _gl.deleteSync( sync );
+ try {
- } ).catch( () => {
+ this.readbackPixels( glBuffer, buffer );
- reject();
+ } finally {
- } );
+ _gl.deleteBuffer( glBuffer );
+ _gl.deleteSync( sync );
}
- } finally {
+ return buffer;
- // restore framebuffer of current render target if necessary
+ }
- const framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null;
- state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
+ } finally {
- }
+ // restore framebuffer of current render target if necessary
+
+ const framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null;
+ state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
}
- } );
+ }
};
From 5b8255b8e01d973afeb1e3e2ee4aca34f20c67db Mon Sep 17 00:00:00 2001
From: Garrett Johnson
Date: Mon, 6 May 2024 00:35:53 +0900
Subject: [PATCH 5/9] Remove tangential functions
---
src/renderers/WebGLRenderer.js | 53 +++++-----------------------------
1 file changed, 7 insertions(+), 46 deletions(-)
diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js
index b2ef797fc21b17..51413bbd248e37 100644
--- a/src/renderers/WebGLRenderer.js
+++ b/src/renderers/WebGLRenderer.js
@@ -2359,49 +2359,16 @@ class WebGLRenderer {
};
- this.createReadbackBuffer = function ( byteLength ) {
-
- const glBuffer = _gl.createBuffer();
-
- _gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );
- _gl.bufferData( _gl.PIXEL_PACK_BUFFER, byteLength, _gl.STREAM_READ );
-
- return glBuffer;
-
- };
-
- this.readbackPixels = function ( glBuffer, typedarray ) {
-
- _gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );
- _gl.getBufferSubData( _gl.PIXEL_PACK_BUFFER, 0, typedarray );
-
- };
-
- this.disposeReadbackBuffer = function ( glBuffer ) {
-
- if ( ! glBuffer || ! Number.isInteger( glBuffer ) ) {
-
- console.error( 'THREE.WebGLRenderer.disposePixelBuffer: invalid glBuffer.' );
- return;
-
- }
-
- _gl.deleteBuffer( glBuffer );
-
- };
-
this.readRenderTargetPixelsAsync = async function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex ) {
if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) {
console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );
- // reject();
throw new Error();
}
let framebuffer = properties.get( renderTarget ).__webglFramebuffer;
-
if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) {
framebuffer = framebuffer[ activeCubeFaceIndex ];
@@ -2418,22 +2385,16 @@ class WebGLRenderer {
const textureFormat = texture.format;
const textureType = texture.type;
- if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) {
+ if ( ! capabilities.textureFormatReadable( textureFormat ) ) {
- console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' );
- // reject();
+ console.error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.' );
throw new Error();
}
- const halfFloatSupportedByExt = ( textureType === HalfFloatType ) && ( extensions.has( 'EXT_color_buffer_half_float' ) || ( capabilities.isWebGL2 && extensions.has( 'EXT_color_buffer_float' ) ) );
-
- if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_TYPE ) && // Edge and Chrome Mac < 52 (#9513)
- ! ( textureType === FloatType && ( capabilities.isWebGL2 || extensions.has( 'OES_texture_float' ) || extensions.has( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox
- ! halfFloatSupportedByExt ) {
+ if ( ! capabilities.textureTypeReadable( textureType ) ) {
- console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' );
- // reject();
+ console.error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.' );
throw new Error();
}
@@ -2445,16 +2406,16 @@ class WebGLRenderer {
const glBuffer = _gl.createBuffer();
_gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );
_gl.bufferData( _gl.PIXEL_PACK_BUFFER, buffer.byteLength, _gl.STREAM_READ );
-
_gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), 0 );
// _gl.flush();
const sync = _gl.fenceSync( _gl.SYNC_GPU_COMMANDS_COMPLETE, 0 );
- await probeAsync( _gl, sync, interval )
+ await probeAsync( _gl, sync, interval );
try {
- this.readbackPixels( glBuffer, buffer );
+ _gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );
+ _gl.getBufferSubData( _gl.PIXEL_PACK_BUFFER, 0, buffer );
} finally {
From af065bc275efc42358934dd57ca4af52db8c2dc7 Mon Sep 17 00:00:00 2001
From: Garrett Johnson
Date: Mon, 6 May 2024 00:41:54 +0900
Subject: [PATCH 6/9] More simplification
---
src/renderers/WebGLRenderer.js | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js
index 51413bbd248e37..80c670bfc3190f 100644
--- a/src/renderers/WebGLRenderer.js
+++ b/src/renderers/WebGLRenderer.js
@@ -2402,15 +2402,16 @@ class WebGLRenderer {
// the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)
if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {
- const interval = 8;
const glBuffer = _gl.createBuffer();
_gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );
_gl.bufferData( _gl.PIXEL_PACK_BUFFER, buffer.byteLength, _gl.STREAM_READ );
_gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), 0 );
+ // TODO: is this needed?
// _gl.flush();
+ // check if the commands have finished every 8 ms
const sync = _gl.fenceSync( _gl.SYNC_GPU_COMMANDS_COMPLETE, 0 );
- await probeAsync( _gl, sync, interval );
+ await probeAsync( _gl, sync, 8 );
try {
From 73ae9b9b7dc2221fe80970115fbb2ef760354ebd Mon Sep 17 00:00:00 2001
From: Garrett Johnson
Date: Mon, 6 May 2024 13:51:20 +0900
Subject: [PATCH 7/9] Convert to thrown errors
---
examples/gi_test.html | 286 ---------------------------------
src/renderers/WebGLRenderer.js | 14 +-
2 files changed, 4 insertions(+), 296 deletions(-)
delete mode 100644 examples/gi_test.html
diff --git a/examples/gi_test.html b/examples/gi_test.html
deleted file mode 100644
index e4b6679cfc39e3..00000000000000
--- a/examples/gi_test.html
+++ /dev/null
@@ -1,286 +0,0 @@
-
-
-
- three.js webgl - simple global illumination
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js
index 80c670bfc3190f..76cd311f596b5c 100644
--- a/src/renderers/WebGLRenderer.js
+++ b/src/renderers/WebGLRenderer.js
@@ -20,8 +20,6 @@ import {
WebGLCoordinateSystem,
DisplayP3ColorSpace,
LinearDisplayP3ColorSpace,
- RGBAFormat,
- FloatType
} from '../constants.js';
import { Color } from '../math/Color.js';
import { Frustum } from '../math/Frustum.js';
@@ -2363,8 +2361,7 @@ class WebGLRenderer {
if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) {
- console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );
- throw new Error();
+ throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );
}
@@ -2387,15 +2384,13 @@ class WebGLRenderer {
if ( ! capabilities.textureFormatReadable( textureFormat ) ) {
- console.error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.' );
- throw new Error();
+ throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.' );
}
if ( ! capabilities.textureTypeReadable( textureType ) ) {
- console.error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.' );
- throw new Error();
+ throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.' );
}
@@ -2406,8 +2401,7 @@ class WebGLRenderer {
_gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );
_gl.bufferData( _gl.PIXEL_PACK_BUFFER, buffer.byteLength, _gl.STREAM_READ );
_gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), 0 );
- // TODO: is this needed?
- // _gl.flush();
+ _gl.flush();
// check if the commands have finished every 8 ms
const sync = _gl.fenceSync( _gl.SYNC_GPU_COMMANDS_COMPLETE, 0 );
From d47524532a6a8003e1c6695ae24852d291057b2d Mon Sep 17 00:00:00 2001
From: Garrett Johnson
Date: Mon, 6 May 2024 13:53:48 +0900
Subject: [PATCH 8/9] Remove comma
---
src/renderers/WebGLRenderer.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js
index 76cd311f596b5c..719c73540993ef 100644
--- a/src/renderers/WebGLRenderer.js
+++ b/src/renderers/WebGLRenderer.js
@@ -19,7 +19,7 @@ import {
UnsignedShort5551Type,
WebGLCoordinateSystem,
DisplayP3ColorSpace,
- LinearDisplayP3ColorSpace,
+ LinearDisplayP3ColorSpace
} from '../constants.js';
import { Color } from '../math/Color.js';
import { Frustum } from '../math/Frustum.js';
From 6ddb37abe3be8d313aab09cd7dc0e2819ec485bb Mon Sep 17 00:00:00 2001
From: Garrett Johnson
Date: Tue, 7 May 2024 12:29:23 +0900
Subject: [PATCH 9/9] Update docs, probe frequency
---
docs/api/en/renderers/WebGLRenderer.html | 15 +++++++++++----
src/renderers/WebGLRenderer.js | 2 +-
2 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/docs/api/en/renderers/WebGLRenderer.html b/docs/api/en/renderers/WebGLRenderer.html
index c80c7eeafcb4bd..3b5617a160cc02 100644
--- a/docs/api/en/renderers/WebGLRenderer.html
+++ b/docs/api/en/renderers/WebGLRenderer.html
@@ -511,16 +511,23 @@
This is a wrapper around
[link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/readPixels WebGLRenderingContext.readPixels]().
-
- See the [example:webgl_interactive_cubes_gpu interactive / cubes / gpu]
- example.
-
For reading out a [page:WebGLCubeRenderTarget WebGLCubeRenderTarget] use
the optional parameter activeCubeFaceIndex to determine which face should
be read.
+
+ [method:Promise readRenderTargetPixelsAsync]( [param:WebGLRenderTarget renderTarget], [param:Float x], [param:Float y], [param:Float width], [param:Float height], [param:TypedArray buffer], [param:Integer activeCubeFaceIndex] )
+
+
+ Asynchronous, non-blocking version of [page:WebGLRenderer.readRenderTargetPixels .readRenderTargetPixels]. The
+ returned promise resolves once the buffer data is ready to be used.
+
+
+ See the [example:webgl_interactive_cubes_gpu interactive / cubes / gpu] example.
+
+
[method:undefined render]( [param:Object3D scene], [param:Camera camera] )
diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js
index 719c73540993ef..7227d7c00553c8 100644
--- a/src/renderers/WebGLRenderer.js
+++ b/src/renderers/WebGLRenderer.js
@@ -2405,7 +2405,7 @@ class WebGLRenderer {
// check if the commands have finished every 8 ms
const sync = _gl.fenceSync( _gl.SYNC_GPU_COMMANDS_COMPLETE, 0 );
- await probeAsync( _gl, sync, 8 );
+ await probeAsync( _gl, sync, 4 );
try {