Warn users that do not invoke "close()"

PiperOrigin-RevId: 532507235
This commit is contained in:
Sebastian Schmidt 2023-05-16 10:44:01 -07:00 committed by Copybara-Service
parent d53fbf2aeb
commit 024f782cd9
2 changed files with 46 additions and 4 deletions

View File

@ -16,6 +16,9 @@
import {assertNotNull, MPImageShaderContext} from '../../../../tasks/web/vision/core/image_shader_context'; import {assertNotNull, MPImageShaderContext} from '../../../../tasks/web/vision/core/image_shader_context';
/** Number of instances a user can keep alive before we raise a warning. */
const INSTANCE_COUNT_WARNING_THRESHOLD = 250;
/** The underlying type of the image. */ /** The underlying type of the image. */
enum MPImageType { enum MPImageType {
/** Represents the native `ImageData` type. */ /** Represents the native `ImageData` type. */
@ -52,6 +55,12 @@ export type MPImageContainer = ImageData|ImageBitmap|WebGLTexture;
export class MPImage { export class MPImage {
private gl?: WebGL2RenderingContext; private gl?: WebGL2RenderingContext;
/**
* A counter to track the number of instances of MPImage that own resources..
* This is used to raise a warning if the user does not close the instances.
*/
private static instancesBeforeWarning = INSTANCE_COUNT_WARNING_THRESHOLD;
/** @hideconstructor */ /** @hideconstructor */
constructor( constructor(
private readonly containers: MPImageContainer[], private readonly containers: MPImageContainer[],
@ -64,7 +73,16 @@ export class MPImage {
readonly width: number, readonly width: number,
/** Returns the height of the image. */ /** Returns the height of the image. */
readonly height: number, readonly height: number,
) {} ) {
if (this.ownsImageBitmap || this.ownsWebGLTexture) {
--MPImage.instancesBeforeWarning;
if (MPImage.instancesBeforeWarning === 0) {
console.error(
'You seem to be creating MPImage instances without invoking ' +
'.close(). This leaks resources.');
}
}
}
/** Returns whether this `MPImage` contains a mask of type `ImageData`. */ /** Returns whether this `MPImage` contains a mask of type `ImageData`. */
hasImageData(): boolean { hasImageData(): boolean {
@ -391,6 +409,9 @@ export class MPImage {
const gl = this.getGL(); const gl = this.getGL();
gl.deleteTexture(this.getContainer(MPImageType.WEBGL_TEXTURE)!); gl.deleteTexture(this.getContainer(MPImageType.WEBGL_TEXTURE)!);
} }
// User called close(). We no longer issue warning.
MPImage.instancesBeforeWarning = -1;
} }
} }

View File

@ -16,6 +16,9 @@
import {assertNotNull, MPImageShaderContext} from '../../../../tasks/web/vision/core/image_shader_context'; import {assertNotNull, MPImageShaderContext} from '../../../../tasks/web/vision/core/image_shader_context';
/** Number of instances a user can keep alive before we raise a warning. */
const INSTANCE_COUNT_WARNING_THRESHOLD = 250;
/** The underlying type of the image. */ /** The underlying type of the image. */
enum MPMaskType { enum MPMaskType {
/** Represents the native `UInt8Array` type. */ /** Represents the native `UInt8Array` type. */
@ -47,6 +50,12 @@ export type MPMaskContainer = Uint8Array|Float32Array|WebGLTexture;
export class MPMask { export class MPMask {
private gl?: WebGL2RenderingContext; private gl?: WebGL2RenderingContext;
/**
* A counter to track the number of instances of MPMask that own resources.
* This is used to raise a warning if the user does not close the instances.
*/
private static instancesBeforeWarning = INSTANCE_COUNT_WARNING_THRESHOLD;
/** @hideconstructor */ /** @hideconstructor */
constructor( constructor(
private readonly containers: MPMaskContainer[], private readonly containers: MPMaskContainer[],
@ -58,7 +67,16 @@ export class MPMask {
readonly width: number, readonly width: number,
/** Returns the height of the mask. */ /** Returns the height of the mask. */
readonly height: number, readonly height: number,
) {} ) {
if (this.ownsWebGLTexture) {
--MPMask.instancesBeforeWarning;
if (MPMask.instancesBeforeWarning === 0) {
console.error(
'You seem to be creating MPMask instances without invoking ' +
'.close(). This leaks resources.');
}
}
}
/** Returns whether this `MPMask` contains a mask of type `Uint8Array`. */ /** Returns whether this `MPMask` contains a mask of type `Uint8Array`. */
hasUint8Array(): boolean { hasUint8Array(): boolean {
@ -88,8 +106,8 @@ export class MPMask {
/** /**
* Returns the underlying mask as a single channel `Float32Array`. Note that * Returns the underlying mask as a single channel `Float32Array`. Note that
* this involves an expensive GPU to CPU transfer if the current mask is only * this involves an expensive GPU to CPU transfer if the current mask is
* available as a `WebGLTexture`. * only available as a `WebGLTexture`.
* *
* @return The current mask as a Float32Array. * @return The current mask as a Float32Array.
*/ */
@ -311,6 +329,9 @@ export class MPMask {
const gl = this.getGL(); const gl = this.getGL();
gl.deleteTexture(this.getContainer(MPMaskType.WEBGL_TEXTURE)!); gl.deleteTexture(this.getContainer(MPMaskType.WEBGL_TEXTURE)!);
} }
// User called close(). We no longer issue warning.
MPMask.instancesBeforeWarning = -1;
} }
} }