Skip to content

Commit 980d7ca

Browse files
committed
Updated builds.
1 parent a4fb5e0 commit 980d7ca

9 files changed

+598
-54
lines changed

build/three.cjs

Lines changed: 178 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7139,6 +7139,14 @@ class Texture extends EventDispatcher {
71397139
*/
71407140
this.userData = {};
71417141

7142+
/**
7143+
* This can be used to only update a subregion or specific rows of the texture (for example, just the
7144+
* first 3 rows). Use the `addUpdateRange()` function to add ranges to this array.
7145+
*
7146+
* @type {Array<Object>}
7147+
*/
7148+
this.updateRanges = [];
7149+
71427150
/**
71437151
* This starts at `0` and counts how many times {@link Texture#needsUpdate} is set to `true`.
71447152
*
@@ -7249,6 +7257,27 @@ class Texture extends EventDispatcher {
72497257

72507258
}
72517259

7260+
/**
7261+
* Adds a range of data in the data texture to be updated on the GPU.
7262+
*
7263+
* @param {number} start - Position at which to start update.
7264+
* @param {number} count - The number of components to update.
7265+
*/
7266+
addUpdateRange( start, count ) {
7267+
7268+
this.updateRanges.push( { start, count } );
7269+
7270+
}
7271+
7272+
/**
7273+
* Clears the update ranges.
7274+
*/
7275+
clearUpdateRanges() {
7276+
7277+
this.updateRanges.length = 0;
7278+
7279+
}
7280+
72527281
/**
72537282
* Returns a new texture with copied values from this instance.
72547283
*
@@ -20120,6 +20149,15 @@ class Mesh extends Object3D {
2012020149
*/
2012120150
this.morphTargetInfluences = undefined;
2012220151

20152+
/**
20153+
* The number of instances of this mesh.
20154+
* Can only be used with {@link WebGPURenderer}.
20155+
*
20156+
* @type {number}
20157+
* @default 1
20158+
*/
20159+
this.count = 1;
20160+
2012320161
this.updateMorphTargets();
2012420162

2012520163
}
@@ -24069,6 +24107,15 @@ class Sprite extends Object3D {
2406924107
*/
2407024108
this.center = new Vector2( 0.5, 0.5 );
2407124109

24110+
/**
24111+
* The number of instances of this sprite.
24112+
* Can only be used with {@link WebGPURenderer}.
24113+
*
24114+
* @type {number}
24115+
* @default 1
24116+
*/
24117+
this.count = 1;
24118+
2407224119
}
2407324120

2407424121
/**
@@ -48399,6 +48446,8 @@ const TEXTURE_FILTER = {
4839948446
LinearMipmapLinearFilter: LinearMipmapLinearFilter
4840048447
};
4840148448

48449+
const _errorMap = new WeakMap();
48450+
4840248451
/**
4840348452
* A loader for loading images as an [ImageBitmap]{@link https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmap}.
4840448453
* An `ImageBitmap` provides an asynchronous and resource efficient pathway to prepare
@@ -48409,7 +48458,7 @@ const TEXTURE_FILTER = {
4840948458
*
4841048459
* You need to set the equivalent options via {@link ImageBitmapLoader#setOptions} instead.
4841148460
*
48412-
* Also note that unlike {@link FileLoader}, this loader does not avoid multiple concurrent requests to the same URL.
48461+
* Also note that unlike {@link FileLoader}, this loader avoids multiple concurrent requests to the same URL only if `Cache` is enabled.
4841348462
*
4841448463
* ```js
4841548464
* const loader = new THREE.ImageBitmapLoader();
@@ -48509,15 +48558,27 @@ class ImageBitmapLoader extends Loader {
4850948558

4851048559
cached.then( imageBitmap => {
4851148560

48512-
if ( onLoad ) onLoad( imageBitmap );
48561+
// check if there is an error for the cached promise
48562+
48563+
if ( _errorMap.has( cached ) === true ) {
48564+
48565+
if ( onError ) onError( _errorMap.get( cached ) );
4851348566

48514-
scope.manager.itemEnd( url );
48567+
scope.manager.itemError( url );
48568+
scope.manager.itemEnd( url );
4851548569

48516-
} ).catch( e => {
48570+
} else {
48571+
48572+
if ( onLoad ) onLoad( imageBitmap );
48573+
48574+
scope.manager.itemEnd( url );
48575+
48576+
return imageBitmap;
4851748577

48518-
if ( onError ) onError( e );
48578+
}
4851948579

4852048580
} );
48581+
4852148582
return;
4852248583

4852348584
}
@@ -48561,6 +48622,8 @@ class ImageBitmapLoader extends Loader {
4856148622

4856248623
if ( onError ) onError( e );
4856348624

48625+
_errorMap.set( promise, e );
48626+
4856448627
Cache.remove( url );
4856548628

4856648629
scope.manager.itemError( url );
@@ -68784,6 +68847,115 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
6878468847

6878568848
}
6878668849

68850+
function getRow( index, rowLength, componentStride ) {
68851+
68852+
return Math.floor( Math.floor( index / componentStride ) / rowLength );
68853+
68854+
}
68855+
68856+
function updateTexture( texture, image, glFormat, glType ) {
68857+
68858+
const componentStride = 4; // only RGBA supported
68859+
68860+
const updateRanges = texture.updateRanges;
68861+
68862+
if ( updateRanges.length === 0 ) {
68863+
68864+
state.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, image.width, image.height, glFormat, glType, image.data );
68865+
68866+
} else {
68867+
68868+
// Before applying update ranges, we merge any adjacent / overlapping
68869+
// ranges to reduce load on `gl.texSubImage2D`. Empirically, this has led
68870+
// to performance improvements for applications which make heavy use of
68871+
// update ranges. Likely due to GPU command overhead.
68872+
//
68873+
// Note that to reduce garbage collection between frames, we merge the
68874+
// update ranges in-place. This is safe because this method will clear the
68875+
// update ranges once updated.
68876+
68877+
updateRanges.sort( ( a, b ) => a.start - b.start );
68878+
68879+
// To merge the update ranges in-place, we work from left to right in the
68880+
// existing updateRanges array, merging ranges. This may result in a final
68881+
// array which is smaller than the original. This index tracks the last
68882+
// index representing a merged range, any data after this index can be
68883+
// trimmed once the merge algorithm is completed.
68884+
let mergeIndex = 0;
68885+
68886+
for ( let i = 1; i < updateRanges.length; i ++ ) {
68887+
68888+
const previousRange = updateRanges[ mergeIndex ];
68889+
const range = updateRanges[ i ];
68890+
68891+
// Only merge if in the same row and overlapping/adjacent
68892+
const previousEnd = previousRange.start + previousRange.count;
68893+
const currentRow = getRow( range.start, image.width, componentStride );
68894+
const previousRow = getRow( previousRange.start, image.width, componentStride );
68895+
68896+
// We add one here to merge adjacent ranges. This is safe because ranges
68897+
// operate over positive integers.
68898+
if (
68899+
range.start <= previousEnd + 1 &&
68900+
currentRow === previousRow &&
68901+
getRow( range.start + range.count - 1, image.width, componentStride ) === currentRow // ensure range doesn't spill
68902+
) {
68903+
68904+
previousRange.count = Math.max(
68905+
previousRange.count,
68906+
range.start + range.count - previousRange.start
68907+
);
68908+
68909+
} else {
68910+
68911+
++ mergeIndex;
68912+
updateRanges[ mergeIndex ] = range;
68913+
68914+
}
68915+
68916+
68917+
}
68918+
68919+
// Trim the array to only contain the merged ranges.
68920+
updateRanges.length = mergeIndex + 1;
68921+
68922+
const currentUnpackRowLen = _gl.getParameter( _gl.UNPACK_ROW_LENGTH );
68923+
const currentUnpackSkipPixels = _gl.getParameter( _gl.UNPACK_SKIP_PIXELS );
68924+
const currentUnpackSkipRows = _gl.getParameter( _gl.UNPACK_SKIP_ROWS );
68925+
68926+
_gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, image.width );
68927+
68928+
for ( let i = 0, l = updateRanges.length; i < l; i ++ ) {
68929+
68930+
const range = updateRanges[ i ];
68931+
68932+
const pixelStart = Math.floor( range.start / componentStride );
68933+
const pixelCount = Math.ceil( range.count / componentStride );
68934+
68935+
const x = pixelStart % image.width;
68936+
const y = Math.floor( pixelStart / image.width );
68937+
68938+
// Assumes update ranges refer to contiguous memory
68939+
const width = pixelCount;
68940+
const height = 1;
68941+
68942+
_gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, x );
68943+
_gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, y );
68944+
68945+
state.texSubImage2D( _gl.TEXTURE_2D, 0, x, y, width, height, glFormat, glType, image.data );
68946+
68947+
}
68948+
68949+
texture.clearUpdateRanges();
68950+
68951+
_gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, currentUnpackRowLen );
68952+
_gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, currentUnpackSkipPixels );
68953+
_gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, currentUnpackSkipRows );
68954+
68955+
}
68956+
68957+
}
68958+
6878768959
function uploadTexture( textureProperties, texture, slot ) {
6878868960

6878968961
let textureType = _gl.TEXTURE_2D;
@@ -68897,7 +69069,7 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
6889769069

6889869070
if ( dataReady ) {
6889969071

68900-
state.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, image.width, image.height, glFormat, glType, image.data );
69072+
updateTexture( texture, image, glFormat, glType );
6890169073

6890269074
}
6890369075

build/three.core.js

Lines changed: 68 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7137,6 +7137,14 @@ class Texture extends EventDispatcher {
71377137
*/
71387138
this.userData = {};
71397139

7140+
/**
7141+
* This can be used to only update a subregion or specific rows of the texture (for example, just the
7142+
* first 3 rows). Use the `addUpdateRange()` function to add ranges to this array.
7143+
*
7144+
* @type {Array<Object>}
7145+
*/
7146+
this.updateRanges = [];
7147+
71407148
/**
71417149
* This starts at `0` and counts how many times {@link Texture#needsUpdate} is set to `true`.
71427150
*
@@ -7247,6 +7255,27 @@ class Texture extends EventDispatcher {
72477255

72487256
}
72497257

7258+
/**
7259+
* Adds a range of data in the data texture to be updated on the GPU.
7260+
*
7261+
* @param {number} start - Position at which to start update.
7262+
* @param {number} count - The number of components to update.
7263+
*/
7264+
addUpdateRange( start, count ) {
7265+
7266+
this.updateRanges.push( { start, count } );
7267+
7268+
}
7269+
7270+
/**
7271+
* Clears the update ranges.
7272+
*/
7273+
clearUpdateRanges() {
7274+
7275+
this.updateRanges.length = 0;
7276+
7277+
}
7278+
72507279
/**
72517280
* Returns a new texture with copied values from this instance.
72527281
*
@@ -20118,6 +20147,15 @@ class Mesh extends Object3D {
2011820147
*/
2011920148
this.morphTargetInfluences = undefined;
2012020149

20150+
/**
20151+
* The number of instances of this mesh.
20152+
* Can only be used with {@link WebGPURenderer}.
20153+
*
20154+
* @type {number}
20155+
* @default 1
20156+
*/
20157+
this.count = 1;
20158+
2012120159
this.updateMorphTargets();
2012220160

2012320161
}
@@ -24067,6 +24105,15 @@ class Sprite extends Object3D {
2406724105
*/
2406824106
this.center = new Vector2( 0.5, 0.5 );
2406924107

24108+
/**
24109+
* The number of instances of this sprite.
24110+
* Can only be used with {@link WebGPURenderer}.
24111+
*
24112+
* @type {number}
24113+
* @default 1
24114+
*/
24115+
this.count = 1;
24116+
2407024117
}
2407124118

2407224119
/**
@@ -48397,6 +48444,8 @@ const TEXTURE_FILTER = {
4839748444
LinearMipmapLinearFilter: LinearMipmapLinearFilter
4839848445
};
4839948446

48447+
const _errorMap = new WeakMap();
48448+
4840048449
/**
4840148450
* A loader for loading images as an [ImageBitmap]{@link https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmap}.
4840248451
* An `ImageBitmap` provides an asynchronous and resource efficient pathway to prepare
@@ -48407,7 +48456,7 @@ const TEXTURE_FILTER = {
4840748456
*
4840848457
* You need to set the equivalent options via {@link ImageBitmapLoader#setOptions} instead.
4840948458
*
48410-
* Also note that unlike {@link FileLoader}, this loader does not avoid multiple concurrent requests to the same URL.
48459+
* Also note that unlike {@link FileLoader}, this loader avoids multiple concurrent requests to the same URL only if `Cache` is enabled.
4841148460
*
4841248461
* ```js
4841348462
* const loader = new THREE.ImageBitmapLoader();
@@ -48507,15 +48556,27 @@ class ImageBitmapLoader extends Loader {
4850748556

4850848557
cached.then( imageBitmap => {
4850948558

48510-
if ( onLoad ) onLoad( imageBitmap );
48559+
// check if there is an error for the cached promise
48560+
48561+
if ( _errorMap.has( cached ) === true ) {
48562+
48563+
if ( onError ) onError( _errorMap.get( cached ) );
48564+
48565+
scope.manager.itemError( url );
48566+
scope.manager.itemEnd( url );
4851148567

48512-
scope.manager.itemEnd( url );
48568+
} else {
48569+
48570+
if ( onLoad ) onLoad( imageBitmap );
48571+
48572+
scope.manager.itemEnd( url );
4851348573

48514-
} ).catch( e => {
48574+
return imageBitmap;
4851548575

48516-
if ( onError ) onError( e );
48576+
}
4851748577

4851848578
} );
48579+
4851948580
return;
4852048581

4852148582
}
@@ -48559,6 +48620,8 @@ class ImageBitmapLoader extends Loader {
4855948620

4856048621
if ( onError ) onError( e );
4856148622

48623+
_errorMap.set( promise, e );
48624+
4856248625
Cache.remove( url );
4856348626

4856448627
scope.manager.itemError( url );

build/three.core.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)