Skip to content

Commit 49ccff0

Browse files
authored
NodeMaterialObserver: Monitor dipose for geometries and textures. (mrdoob#34287)
1 parent 5343fdd commit 49ccff0

1 file changed

Lines changed: 106 additions & 7 deletions

File tree

src/materials/nodes/manager/NodeMaterialObserver.js

Lines changed: 106 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,14 @@ const _materialCache = new WeakMap();
9999
*/
100100
const _geometryCache = new WeakMap();
101101

102+
/**
103+
* Holds the texture data for comparison.
104+
*
105+
* @private
106+
* @type {WeakMap<Texture,Object>}
107+
*/
108+
const _textureCache = new WeakMap();
109+
102110
/**
103111
* This class is used by {@link WebGPURenderer} as management component.
104112
* It's primary purpose is to determine whether render objects require a
@@ -355,6 +363,14 @@ class NodeMaterialObserver {
355363
drawRange: { start: geometry.drawRange.start, count: geometry.drawRange.count }
356364
};
357365

366+
// force refresh on dispose
367+
368+
geometry.addEventListener( 'dispose', () => {
369+
370+
data._version ++;
371+
372+
} );
373+
358374
_geometryCache.set( geometry, data );
359375

360376
}
@@ -363,6 +379,47 @@ class NodeMaterialObserver {
363379

364380
}
365381

382+
/**
383+
* Returns a texture data structure holding the texture state for
384+
* monitoring.
385+
*
386+
* @param {Texture} texture - The texture.
387+
* @return {Object} An object for monitoring the texture.
388+
*/
389+
getTextureData( texture ) {
390+
391+
let data = _textureCache.get( texture );
392+
393+
if ( data === undefined ) {
394+
395+
data = { _version: 0 };
396+
397+
// force refresh on dispose
398+
399+
const onDispose = () => {
400+
401+
data._version ++;
402+
403+
};
404+
405+
if ( texture.renderTarget !== null ) {
406+
407+
texture.renderTarget.addEventListener( 'dispose', onDispose );
408+
409+
} else {
410+
411+
texture.addEventListener( 'dispose', onDispose );
412+
413+
}
414+
415+
_textureCache.set( texture, data );
416+
417+
}
418+
419+
return data;
420+
421+
}
422+
366423
/**
367424
* Returns a material data structure holding the material property values for
368425
* monitoring.
@@ -382,13 +439,17 @@ class NodeMaterialObserver {
382439

383440
const value = material[ property ];
384441

385-
if ( value === null || value === undefined ) continue;
442+
if ( value === undefined ) continue;
443+
444+
if ( value === null ) {
386445

387-
if ( typeof value === 'object' && value.clone !== undefined ) {
446+
data[ property ] = null; // track unset properties
447+
448+
} else if ( typeof value === 'object' && value.clone !== undefined ) {
388449

389450
if ( value.isTexture === true ) {
390451

391-
data[ property ] = { id: value.id, version: 0 };
452+
data[ property ] = { id: value.id, version: 0, cacheVersion: this.getTextureData( value )._version };
392453

393454
} else {
394455

@@ -456,7 +517,35 @@ class NodeMaterialObserver {
456517
if ( property === '_renderId' ) continue;
457518
if ( property === '_version' ) continue;
458519

459-
if ( value.equals !== undefined ) {
520+
if ( value === null || mtlValue === null || mtlValue === undefined ) {
521+
522+
// a property was assigned or removed since the last observation so a new snapshot is required
523+
524+
if ( value !== ( mtlValue === undefined ? null : mtlValue ) ) {
525+
526+
if ( mtlValue === null || mtlValue === undefined ) {
527+
528+
materialData[ property ] = null;
529+
530+
} else if ( mtlValue.isTexture === true ) {
531+
532+
materialData[ property ] = { id: mtlValue.id, version: mtlValue.version, cacheVersion: this.getTextureData( mtlValue )._version };
533+
534+
} else if ( typeof mtlValue === 'object' && mtlValue.clone !== undefined ) {
535+
536+
materialData[ property ] = mtlValue.clone();
537+
538+
} else {
539+
540+
materialData[ property ] = mtlValue;
541+
542+
}
543+
544+
changed = true;
545+
546+
}
547+
548+
} else if ( value.equals !== undefined ) {
460549

461550
if ( value.equals( mtlValue ) === false ) {
462551

@@ -468,10 +557,13 @@ class NodeMaterialObserver {
468557

469558
} else if ( mtlValue.isTexture === true ) {
470559

471-
if ( value.id !== mtlValue.id || value.version !== mtlValue.version ) {
560+
const textureData = this.getTextureData( mtlValue );
561+
562+
if ( value.id !== mtlValue.id || value.version !== mtlValue.version || value.cacheVersion !== textureData._version ) {
472563

473564
value.id = mtlValue.id;
474565
value.version = mtlValue.version;
566+
value.cacheVersion = textureData._version;
475567

476568
changed = true;
477569

@@ -521,6 +613,8 @@ class NodeMaterialObserver {
521613
if ( renderObjectData.geometryId !== geometry.id ) {
522614

523615
renderObjectData.geometryId = geometry.id;
616+
renderObjectData.geometryVersion = this.getGeometryData( geometry )._version;
617+
524618
return false;
525619

526620
}
@@ -692,7 +786,12 @@ class NodeMaterialObserver {
692786

693787
for ( let i = 0; i < lightsData.length; i ++ ) {
694788

695-
if ( renderObjectData.lights[ i ].map !== lightsData[ i ].map ) {
789+
const lightData = renderObjectData.lights[ i ];
790+
791+
if ( lightData.map !== lightsData[ i ].map || lightData.cacheVersion !== lightsData[ i ].cacheVersion ) {
792+
793+
lightData.map = lightsData[ i ].map;
794+
lightData.cacheVersion = lightsData[ i ].cacheVersion;
696795

697796
return false;
698797

@@ -762,7 +861,7 @@ class NodeMaterialObserver {
762861

763862
// only add lights that have a map
764863

765-
lights.push( { map: light.map.version } );
864+
lights.push( { map: light.map.version, cacheVersion: this.getTextureData( light.map )._version } );
766865

767866
}
768867

0 commit comments

Comments
 (0)