Skip to content

Commit

Permalink
fix(core): QuadRenderer dispose method now properly disposes of its i…
Browse files Browse the repository at this point in the history
…nternal resources (#13)

with optional parameter to dispose the renderTarget
  • Loading branch information
daniele-pelagatti authored Nov 23, 2023
1 parent 5222151 commit 8e4473d
Show file tree
Hide file tree
Showing 17 changed files with 160 additions and 20 deletions.
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ const renderer = new WebGLRenderer()

const loader = new HDRJPGLoader(renderer)

const result = loader.load('gainmap.jpeg')
const result = await loader.loadAsync('gainmap.jpeg')
// `result` can be used to populate a Texture

const scene = new Scene()
Expand All @@ -99,6 +99,11 @@ scene.background = result.toDataTexture()
scene.background.mapping = EquirectangularReflectionMapping
scene.background.minFilter = LinearFilter


// result must be manually disposed
// when you are done using it
result.dispose()

```

### Using separate files
Expand Down Expand Up @@ -127,7 +132,7 @@ const renderer = new WebGLRenderer()

const loader = new GainMapLoader(renderer)

const result = loader.load(['sdr.jpeg', 'gainmap.jpeg', 'metadata.json'])
const result = await loader.loadAsync(['sdr.jpeg', 'gainmap.jpeg', 'metadata.json'])
// `result` can be used to populate a Texture

const scene = new Scene()
Expand All @@ -147,6 +152,9 @@ scene.background = result.toDataTexture()
scene.background.mapping = EquirectangularReflectionMapping
scene.background.minFilter = LinearFilter

// result must be manually disposed
// when you are done using it
result.dispose()
```

### Encoding
Expand Down
4 changes: 4 additions & 0 deletions examples/compress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,7 @@ const [sdr, gainMap] = await Promise.all([

// `sdr` will contain a JPEG which can be saved somewhere
// `gainMap` will contain a JPEG which can be saved somewhere

// renderers be manually disposed
encodingResult.sdr.dispose()
encodingResult.gainMap.dispose()
6 changes: 5 additions & 1 deletion examples/decode-from-jpeg-using-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const renderer = new WebGLRenderer()

const loader = new HDRJPGLoader(renderer)

const result = loader.load('gainmap.jpeg')
const result = await loader.loadAsync('gainmap.jpeg')
// `result` can be used to populate a Texture

const scene = new Scene()
Expand All @@ -34,3 +34,7 @@ renderer.render(scene, new PerspectiveCamera())
scene.background = result.toDataTexture()
scene.background.mapping = EquirectangularReflectionMapping
scene.background.minFilter = LinearFilter

// result must be manually disposed
// when you are done using it
result.dispose()
4 changes: 4 additions & 0 deletions examples/decode-from-jpeg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,7 @@ const mesh = new Mesh(
)
scene.add(mesh)
renderer.render(scene, new PerspectiveCamera())

// result must be manually disposed
// when you are done using it
result.dispose()
6 changes: 5 additions & 1 deletion examples/decode-from-separate-data-using-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const renderer = new WebGLRenderer()

const loader = new GainMapLoader(renderer)

const result = loader.load(['sdr.jpeg', 'gainmap.jpeg', 'metadata.json'])
const result = await loader.loadAsync(['sdr.jpeg', 'gainmap.jpeg', 'metadata.json'])
// `result` can be used to populate a Texture

const scene = new Scene()
Expand All @@ -34,3 +34,7 @@ renderer.render(scene, new PerspectiveCamera())
scene.background = result.toDataTexture()
scene.background.mapping = EquirectangularReflectionMapping
scene.background.minFilter = LinearFilter

// result must be manually disposed
// when you are done using it
result.dispose()
4 changes: 4 additions & 0 deletions examples/decode-from-separate-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,7 @@ const mesh = new Mesh(
)
scene.add(mesh)
renderer.render(scene, new PerspectiveCamera())

// result must be manually disposed
// when you are done using it
result.dispose()
5 changes: 5 additions & 0 deletions examples/encode-jpeg-metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,8 @@ const jpeg = await encodeJPEGMetadata({
})

// `jpeg` will be an `Uint8Array` which can be saved somewhere

// encoder must be manually disposed
// when no longer needed
encodingResult.gainMap.dispose()
encodingResult.sdr.dispose()
5 changes: 4 additions & 1 deletion examples/encode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ encodingResult.sdr.render()
encodingResult.gainMap.material.gamma = [1.1, 1.1, 1.1]
encodingResult.gainMap.render()

// must be manually disposed
// do something with encodingResult.gainMap.toArray()
// and encodingResult.sdr.toArray()

// renderers be manually disposed
encodingResult.sdr.dispose()
encodingResult.gainMap.dispose()
12 changes: 12 additions & 0 deletions examples/integrated/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,12 @@
hdrJpgEquirectangularMap.generateMipmaps = false;

hdrJpgEquirectangularMap.needsUpdate = true;
// this must be called manually
// when the gain map has been used
// in this case we also pass `true`
// to the disposeRenderTarget param
// because we don't need the renderTarget anymore
hdrJpg.dispose( true );

}, function ( progress ) {

Expand All @@ -168,6 +174,12 @@
gainMapBackground.generateMipmaps = false;

gainMapBackground.needsUpdate = true;
// this must be called manually
// when the gain map has been used
// in this case we also pass `true`
// to the disposeRenderTarget param
// because we don't need the renderTarget anymore
gainMap.dispose( true );

}, function ( progress ) {

Expand Down
62 changes: 61 additions & 1 deletion src/core/QuadRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ import {
RepeatWrapping,
RGBAFormat,
Scene,
ShaderMaterial,
ShortType,
Texture,
TextureDataType,
UnsignedByteType,
UnsignedIntType,
Expand Down Expand Up @@ -236,6 +238,12 @@ export class QuadRenderer<TType extends TextureDataType, TMaterial extends Mater
return out as TextureDataTypeToBufferType<TType>
}

/**
* Performs a readPixel operation in the renderTarget
* and returns a DataTexture containing the read data
*
* @returns
*/
public toDataTexture () {
return new DataTexture(
this.toArray(),
Expand All @@ -256,14 +264,66 @@ export class QuadRenderer<TType extends TextureDataType, TMaterial extends Mater
/**
* If using a disposable renderer, it will dispose it.
*/
public dispose () {
public disposeOnDemandRenderer () {
this._renderer.setRenderTarget(null)
if (this._rendererIsDisposable) {
this._renderer.dispose()
this._renderer.forceContextLoss()
}
}

/**
* Will dispose of **all** assets used by this renderer.
*
*
* @param disposeRenderTarget will dispose of the renderTarget which will not be usable later
* set this to true if you passed the `renderTarget.texture` to a `PMREMGenerator`
* or are otherwise done with it.
*
* @example
* ```js
* const loader = new HDRJPGLoader(renderer)
* const result = await loader.loadAsync('gainmap.jpeg')
* const mesh = new Mesh(geometry, new MeshBasicMaterial({ map: result.renderTarget.texture }) )
* // DO NOT dispose the renderTarget here,
* // it is used directly in the material
* result.dispose()
* ```
*
* @example
* ```js
* const loader = new HDRJPGLoader(renderer)
* const pmremGenerator = new PMREMGenerator( renderer );
* const result = await loader.loadAsync('gainmap.jpeg')
* const envMap = pmremGenerator.fromEquirectangular(result.renderTarget.texture)
* const mesh = new Mesh(geometry, new MeshStandardMaterial({ envMap }) )
* // renderTarget can be disposed here
* // because it was used to generate a PMREM texture
* result.dispose(true)
* ```
*/
public dispose (disposeRenderTarget?: boolean) {
this.disposeOnDemandRenderer()

if (disposeRenderTarget) {
this.renderTarget.dispose()
}

// dispose shader material texture uniforms
if (this.material instanceof ShaderMaterial) {
Object.values(this.material.uniforms).forEach(v => {
if (v.value instanceof Texture) v.value.dispose()
})
}
// dispose other material properties
Object.values(this.material).forEach(value => {
if (value instanceof Texture) value.dispose()
})

this.material.dispose()
this._quad.geometry.dispose()
}

/**
* Width of the texture
*/
Expand Down
5 changes: 4 additions & 1 deletion src/decode/decode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ import { DecodeParameters } from './types'
* scene.add(mesh)
* renderer.render(scene, new PerspectiveCamera())
*
* // result must be manually disposed
* // when you are done using it
* result.dispose()
*
* @param params
* @returns
Expand Down Expand Up @@ -86,7 +89,7 @@ export const decode = (params: DecodeParameters): InstanceType<typeof QuadRender
try {
quadRenderer.render()
} catch (e) {
quadRenderer.dispose()
quadRenderer.disposeOnDemandRenderer()
throw e
}
return quadRenderer
Expand Down
8 changes: 6 additions & 2 deletions src/decode/loaders/GainMapLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { LoaderBase } from './LoaderBase'
*
* const loader = new GainMapLoader(renderer)
*
* const result = loader.load(['sdr.jpeg', 'gainmap.jpeg', 'metadata.json'])
* const result = await loader.loadAsync(['sdr.jpeg', 'gainmap.jpeg', 'metadata.json'])
* // `result` can be used to populate a Texture
*
* const scene = new Scene()
Expand All @@ -50,6 +50,10 @@ import { LoaderBase } from './LoaderBase'
* scene.background.mapping = EquirectangularReflectionMapping
* scene.background.minFilter = LinearFilter
*
* // result must be manually disposed
* // when you are done using it
* result.dispose()
*
*/
export class GainMapLoader extends LoaderBase<[string, string, string]> {
/**
Expand Down Expand Up @@ -81,7 +85,7 @@ export class GainMapLoader extends LoaderBase<[string, string, string]> {
this.manager.itemEnd(sdrUrl)
this.manager.itemEnd(gainMapUrl)
this.manager.itemEnd(metadataUrl)
quadRenderer.dispose()
quadRenderer.disposeOnDemandRenderer()
}
}

Expand Down
17 changes: 11 additions & 6 deletions src/decode/loaders/HDRJPGLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { LoaderBase } from './LoaderBase'
* @group Loaders
*
* @example
* import { JPEGRLoader } from '@monogrid/gainmap-js'
* import { HDRJPGLoader } from '@monogrid/gainmap-js'
* import {
* EquirectangularReflectionMapping,
* LinearFilter,
Expand All @@ -32,9 +32,9 @@ import { LoaderBase } from './LoaderBase'
*
* const renderer = new WebGLRenderer()
*
* const loader = new JPEGRLoader(renderer)
* const loader = new HDRJPGLoader(renderer)
*
* const result = loader.load('gainmap.jpeg')
* const result = await loader.loadAsync('gainmap.jpeg')
* // `result` can be used to populate a Texture
*
* const scene = new Scene()
Expand All @@ -53,12 +53,16 @@ import { LoaderBase } from './LoaderBase'
* scene.background = result.toDataTexture()
* scene.background.mapping = EquirectangularReflectionMapping
* scene.background.minFilter = LinearFilter
*
* // result must be manually disposed
* // when you are done using it
* result.dispose()
*
*/
export class HDRJPGLoader extends LoaderBase<string> {
/**
* Loads a JPEGR Image
* Loads a JPEG containing gain map metadata
* Renders a normal SDR image if gainmap data is not found
*
* @param url An array in the form of [sdr.jpg, gainmap.jpg, metadata.json]
* @param onLoad Load complete callback, will receive the result
Expand Down Expand Up @@ -90,6 +94,7 @@ export class HDRJPGLoader extends LoaderBase<string> {
} catch (e: unknown) {
// render the SDR version if this is not a gainmap
if (e instanceof XMPMetadataNotFoundError || e instanceof GainMapNotFoundError) {
console.warn(`Failure to reconstruct an HDR image from ${url}: Gain map metadata not found in the file, HDRJPGLoader will render the SDR jpeg`)
metadata = {
gainMapMin: [0, 0, 0],
gainMapMax: [1, 1, 1],
Expand All @@ -108,7 +113,7 @@ export class HDRJPGLoader extends LoaderBase<string> {

if (typeof onLoad === 'function') onLoad(quadRenderer)
this.manager.itemEnd(url)
quadRenderer.dispose()
quadRenderer.disposeOnDemandRenderer()
}, onProgress
, (error: unknown) => {
this.manager.itemError(url)
Expand Down
3 changes: 3 additions & 0 deletions src/decode/loaders/LoaderBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ import { getHTMLImageFromBlob } from '../utils/get-html-image-from-blob'

export class LoaderBase<TUrl = string> extends Loader<QuadRenderer<typeof HalfFloatType, GainMapDecoderMaterial>, TUrl> {
private _renderer: WebGLRenderer
/**
* @private
*/
protected _internalLoadingManager: LoadingManager
/**
*
Expand Down
5 changes: 4 additions & 1 deletion src/encode/encode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ import { EncodingParametersBase } from './types'
* encodingResult.gainMap.material.gamma = [1.1, 1.1, 1.1]
* encodingResult.gainMap.render()
*
* // must be manually disposed
* // do something with encodingResult.gainMap.toArray()
* // and encodingResult.sdr.toArray()
*
* // renderers must be manually disposed
* encodingResult.sdr.dispose()
* encodingResult.gainMap.dispose()
*
Expand Down
11 changes: 9 additions & 2 deletions src/encode/get-gainmap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,18 @@ export const getGainMap = (params: { sdr: InstanceType<typeof QuadRenderer> } &
hdr: dataTexture
})

const quadRenderer = new QuadRenderer(dataTexture.image.width, dataTexture.image.height, UnsignedByteType, LinearSRGBColorSpace, material, renderer)
const quadRenderer = new QuadRenderer(
dataTexture.image.width,
dataTexture.image.height,
UnsignedByteType,
LinearSRGBColorSpace,
material,
renderer
)
try {
quadRenderer.render()
} catch (e) {
quadRenderer.dispose()
quadRenderer.disposeOnDemandRenderer()
throw e
}
return quadRenderer
Expand Down
Loading

0 comments on commit 8e4473d

Please sign in to comment.