diff --git a/packages/dev/core/src/Engines/abstractEngine.ts b/packages/dev/core/src/Engines/abstractEngine.ts index 5d0270856b4..397634b3627 100644 --- a/packages/dev/core/src/Engines/abstractEngine.ts +++ b/packages/dev/core/src/Engines/abstractEngine.ts @@ -2554,6 +2554,11 @@ export abstract class AbstractEngine { */ public readonly onDisposeObservable = new Observable(); + /** + * An event triggered when a global cleanup of all effects is required + */ + public readonly onReleaseEffectsObservable = new Observable(); + /** * Dispose and release all associated resources */ diff --git a/packages/dev/core/src/Engines/thinEngine.ts b/packages/dev/core/src/Engines/thinEngine.ts index 4c92ec91247..73b8845b345 100644 --- a/packages/dev/core/src/Engines/thinEngine.ts +++ b/packages/dev/core/src/Engines/thinEngine.ts @@ -4041,13 +4041,8 @@ export class ThinEngine extends AbstractEngine { * Force the engine to release all cached effects. This means that next effect compilation will have to be done completely even if a similar effect was already compiled */ public releaseEffects() { - const keys = Object.keys(this._compiledEffects); - for (const name of keys) { - const effect = this._compiledEffects[name]; - effect.dispose(true); - } - this._compiledEffects = {}; + this.onReleaseEffectsObservable.notifyObservers(this); } /** diff --git a/packages/dev/core/src/Engines/webgpuEngine.ts b/packages/dev/core/src/Engines/webgpuEngine.ts index 3de6ee7e671..0ac3add06f3 100644 --- a/packages/dev/core/src/Engines/webgpuEngine.ts +++ b/packages/dev/core/src/Engines/webgpuEngine.ts @@ -2202,6 +2202,8 @@ export class WebGPUEngine extends ThinWebGPUEngine { } this._compiledEffects = {}; + + this.onReleaseEffectsObservable.notifyObservers(this); } public _deletePipelineContext(pipelineContext: IPipelineContext): void { diff --git a/packages/dev/core/src/Materials/effect.ts b/packages/dev/core/src/Materials/effect.ts index 0221fb24cf9..f3f78e586ec 100644 --- a/packages/dev/core/src/Materials/effect.ts +++ b/packages/dev/core/src/Materials/effect.ts @@ -151,6 +151,12 @@ export class Effect implements IDisposable { */ public static LogShaderCodeOnCompilationError = true; + /** + * Gets or sets a boolean indicating that effect ref counting is disabled + * If true, the effect will persist in memory until engine is disposed + */ + public static PersistentMode: boolean = false; + /** * Use this with caution * See ClearCodeCache function comments @@ -384,6 +390,14 @@ export class Effect implements IDisposable { (this._pipelineContext as any).program.__SPECTOR_rebuildProgram = this._rebuildProgram.bind(this); } } + + this._engine.onReleaseEffectsObservable.addOnce(() => { + if (this.isDisposed) { + return; + } + + this.dispose(true); + }); } /** @internal */ @@ -1485,6 +1499,9 @@ export class Effect implements IDisposable { if (force) { this._refCount = 0; } else { + if (Effect.PersistentMode) { + return; + } this._refCount--; } diff --git a/packages/dev/core/src/Particles/webgl2ParticleSystem.ts b/packages/dev/core/src/Particles/webgl2ParticleSystem.ts index 886cd899f38..fab2303dd8e 100644 --- a/packages/dev/core/src/Particles/webgl2ParticleSystem.ts +++ b/packages/dev/core/src/Particles/webgl2ParticleSystem.ts @@ -1,7 +1,6 @@ import type { VertexBuffer, Buffer } from "../Buffers/buffer"; import type { ThinEngine } from "../Engines/thinEngine"; -import type { IEffectCreationOptions } from "../Materials/effect"; -import { Effect } from "../Materials/effect"; +import type { Effect, IEffectCreationOptions } from "../Materials/effect"; import type { IGPUParticleSystemPlatform } from "./IGPUParticleSystemPlatform"; import { CustomParticleEmitter } from "./EmitterTypes/customParticleEmitter"; @@ -146,7 +145,7 @@ export class WebGL2ParticleSystem implements IGPUParticleSystemPlatform { } this._updateEffectOptions.defines = defines; - this._updateEffect = new Effect("gpuUpdateParticles", this._updateEffectOptions, this._engine); + this._updateEffect = this._engine.createEffect("gpuUpdateParticles", this._updateEffectOptions, this._engine); return new UniformBufferEffectCommonAccessor(this._updateEffect); }