Skip to content

Commit

Permalink
feat(core): Add factory destroy policy 'never'
Browse files Browse the repository at this point in the history
  • Loading branch information
ibgreen committed Mar 13, 2024
1 parent 8ab6e67 commit 301900a
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 42 deletions.
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ package-lock.json
lerna-debug.log

*/**/yarn.lock
yarn-error.log
!website/yarn.lock

*/**/.yarn/*
*/**/yarn-error.log

.yarn/*
!.yarn/cache
!.yarn/patches
Expand All @@ -36,7 +38,6 @@ yarn-error.log
!.yarn/sdks
!.yarn/versions


.project
.DS_Store
*.zip
Expand Down
41 changes: 22 additions & 19 deletions modules/core/src/adapter/device.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,24 +219,26 @@ export type DeviceProps = {
/** Error handling */
onError?: (error: Error) => unknown;

// DEBUG SETTINGS
// @deprecated Attach to existing context. Rename to handle? Use Device.attach?
gl?: WebGL2RenderingContext | null;

// DEBUG SETTINGS
/** WebGL: Instrument WebGL2RenderingContext (at the expense of performance) */
debug?: boolean;
/** Break on WebGL functions matching these strings */
break?: string[];
/** WebGL: Initialize the SpectorJS WebGL debugger */
spector?: boolean;

// EXPERIMENTAL SETTINGS
/** Set to false to disable WebGL state management instrumentation: TODO- Unclear if still supported / useful */
manageState?: boolean;
/** Initialize all features on startup */
initalizeFeatures?: boolean;
/** Disable specific features */
disabledFeatures?: Partial<Record<DeviceFeature, boolean>>;

/** TODO- Unclear if still supported: Set to false to disable WebGL state management instrumentation */
manageState?: boolean;

// @deprecated Attach to existing context. Rename to handle? Use Device.attach?
gl?: WebGL2RenderingContext | null;
/** Never destroy cached shaders and pipelines */
_factoryDestroyPolicy?: 'unused' | 'never';
};

/**
Expand All @@ -250,17 +252,12 @@ export abstract class Device {
manageState: true,
width: 800, // width are height are only used by headless gl
height: 600,

requestMaxLimits: true,
debug: Boolean(log.get('debug')), // Instrument context (at the expense of performance)
spector: Boolean(log.get('spector')), // Initialize the SpectorJS WebGL debugger
break: [],

// TODO - Change these after confirming things work as expected
initalizeFeatures: true,
disabledFeatures: {
'compilation-status-async-webgl': true
},
// Callbacks
onError: (error: Error) => log.error(error.message),

gl: null,

// alpha: undefined,
// depth: undefined,
Expand All @@ -270,10 +267,16 @@ export abstract class Device {
// preserveDrawingBuffer: undefined,
// failIfMajorPerformanceCaveat: undefined

gl: null,
debug: Boolean(log.get('debug')), // Instrument context (at the expense of performance)
spector: Boolean(log.get('spector')), // Initialize the SpectorJS WebGL debugger
break: (log.get('break') as string[]) || [],

// Callbacks
onError: (error: Error) => log.error(error.message)
// TODO - Change these after confirming things work as expected
initalizeFeatures: true,
disabledFeatures: {
'compilation-status-async-webgl': true
},
_factoryDestroyPolicy: 'unused'
};

get [Symbol.toStringTag](): string {
Expand Down
31 changes: 16 additions & 15 deletions modules/engine/src/lib/pipeline-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,33 @@ import {Device, RenderPipeline, ComputePipeline} from '@luma.gl/core';

export type PipelineFactoryProps = RenderPipelineProps;

type RenderPipelineCacheItem = {pipeline: RenderPipeline; useCount: number};
type ComputePipelineCacheItem = {pipeline: ComputePipeline; useCount: number};

/**
* Efficiently creates / caches pipelines
*/
export class PipelineFactory {
static defaultProps: Required<PipelineFactoryProps> = {...RenderPipeline.defaultProps};

readonly device: Device;

private _hashCounter: number = 0;
private readonly _hashes: Record<string, number> = {};
private readonly _renderPipelineCache: Record<
string,
{pipeline: RenderPipeline; useCount: number}
> = {};
private readonly _computePipelineCache: Record<
string,
{pipeline: ComputePipeline; useCount: number}
> = {};

/** Get the singleton default pipeline factory for the specified device */
static getDefaultPipelineFactory(device: Device): PipelineFactory {
device._lumaData.defaultPipelineFactory =
device._lumaData.defaultPipelineFactory || new PipelineFactory(device);
return device._lumaData.defaultPipelineFactory as PipelineFactory;
}

readonly device: Device;
readonly destroyPolicy: 'unused' | 'never';

private _hashCounter: number = 0;
private readonly _hashes: Record<string, number> = {};
private readonly _renderPipelineCache: Record<string, RenderPipelineCacheItem> = {};
private readonly _computePipelineCache: Record<string, ComputePipelineCacheItem> = {};

constructor(device: Device) {
this.device = device;
this.destroyPolicy = device.props._factoryDestroyPolicy;
}

/** Return a RenderPipeline matching props. Reuses a similar pipeline if already created. */
Expand Down Expand Up @@ -80,8 +79,10 @@ export class PipelineFactory {
pipeline instanceof ComputePipeline ? this._computePipelineCache : this._renderPipelineCache;
cache[hash].useCount--;
if (cache[hash].useCount === 0) {
cache[hash].pipeline.destroy();
delete cache[hash];
if (this.destroyPolicy === 'unused') {
cache[hash].pipeline.destroy();
delete cache[hash];
}
}
}

Expand Down
15 changes: 9 additions & 6 deletions modules/engine/src/lib/shader-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,20 @@ import {Device, Shader, ShaderProps} from '@luma.gl/core';
export class ShaderFactory {
static readonly defaultProps: Required<ShaderProps> = {...Shader.defaultProps};

public readonly device: Device;

private readonly _cache: Record<string, {shader: Shader; useCount: number}> = {};

/** Returns the default ShaderFactory for the given {@link Device}, creating one if necessary. */
static getDefaultShaderFactory(device: Device): ShaderFactory {
device._lumaData.defaultShaderFactory ||= new ShaderFactory(device);
return device._lumaData.defaultShaderFactory as ShaderFactory;
}

public readonly device: Device;
readonly destroyPolicy: 'unused' | 'never';
private readonly _cache: Record<string, {shader: Shader; useCount: number}> = {};

/** @internal */
constructor(device: Device) {
this.device = device;
this.destroyPolicy = device.props._factoryDestroyPolicy;
}

/** Requests a {@link Shader} from the cache, creating a new Shader only if necessary. */
Expand All @@ -47,8 +48,10 @@ export class ShaderFactory {
if (cacheEntry) {
cacheEntry.useCount--;
if (cacheEntry.useCount === 0) {
delete this._cache[key];
cacheEntry.shader.destroy();
if (this.destroyPolicy === 'unused') {
delete this._cache[key];
cacheEntry.shader.destroy();
}
}
}
}
Expand Down

0 comments on commit 301900a

Please sign in to comment.