Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions src/core/CoreTextureManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -407,8 +407,7 @@ export class CoreTextureManager extends EventEmitter {
return;
}

texture.setSourceState('loading');
texture.setCoreCtxState('loading');
texture.setState('loading');

// if we're not initialized, just queue the texture into the priority queue
if (this.initialized === false) {
Expand Down Expand Up @@ -462,6 +461,10 @@ export class CoreTextureManager extends EventEmitter {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const texture = this.priorityQueue.shift()!;
texture.getTextureData().then(() => {
if (texture.state === 'failed') {
return;
}

this.uploadTexture(texture);
});
}
Expand All @@ -484,6 +487,10 @@ export class CoreTextureManager extends EventEmitter {
const texture = this.downloadTextureSourceQueue.shift()!;
queueMicrotask(() => {
texture.getTextureData().then(() => {
if (texture.state === 'failed') {
return;
}

this.enqueueUploadTexture(texture);
});
});
Expand Down
8 changes: 4 additions & 4 deletions src/core/renderers/canvas/CanvasCoreTexture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,22 @@ export class CanvasCoreTexture extends CoreContextTexture {
| undefined;

load(): void {
this.textureSource.setCoreCtxState('loading');
this.textureSource.setState('loading');

this.onLoadRequest()
.then((size) => {
this.textureSource.setCoreCtxState('loaded', size);
this.textureSource.setState('loaded', size);
this.updateMemSize();
})
.catch((err) => {
this.textureSource.setCoreCtxState('failed', err as Error);
this.textureSource.setState('failed', err as Error);
});
}

free(): void {
this.image = undefined;
this.tintCache = undefined;
this.textureSource.setCoreCtxState('freed');
this.textureSource.setState('freed');
this.setTextureMemUse(0);
}

Expand Down
10 changes: 5 additions & 5 deletions src/core/renderers/webgl/WebGlCoreCtxTexture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,12 @@ export class WebGlCoreCtxTexture extends CoreContextTexture {
}

this.state = 'loading';
this.textureSource.setCoreCtxState('loading');
this.textureSource.setState('loading');
this._nativeCtxTexture = this.createNativeCtxTexture();

if (this._nativeCtxTexture === null) {
this.state = 'failed';
this.textureSource.setCoreCtxState(
this.textureSource.setState(
'failed',
new Error('Could not create WebGL Texture'),
);
Expand All @@ -110,15 +110,15 @@ export class WebGlCoreCtxTexture extends CoreContextTexture {
this._h = height;
// Update the texture source's width and height so that it can be used
// for rendering.
this.textureSource.setCoreCtxState('loaded', { width, height });
this.textureSource.setState('loaded', { width, height });
})
.catch((err) => {
// If the texture has been freed while loading, return early.
if (this.state === 'freed') {
return;
}
this.state = 'failed';
this.textureSource.setCoreCtxState('failed', err);
this.textureSource.setState('failed', err);
console.error(err);
});
}
Expand Down Expand Up @@ -248,7 +248,7 @@ export class WebGlCoreCtxTexture extends CoreContextTexture {
return;
}
this.state = 'freed';
this.textureSource.setCoreCtxState('freed');
this.textureSource.setState('freed');
this._w = 0;
this._h = 0;
if (!this._nativeCtxTexture) {
Expand Down
2 changes: 1 addition & 1 deletion src/core/textures/ColorTexture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export class ColorTexture extends Texture {
pixelData[3] = (this.color >>> 24) & 0xff; // Alpha
}

this.setSourceState('loaded', { width: 1, height: 1 });
this.setState('fetched', { width: 1, height: 1 });

return {
data: pixelData,
Expand Down
6 changes: 3 additions & 3 deletions src/core/textures/ImageTexture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,14 +232,14 @@ export class ImageTexture extends Texture {
try {
resp = await this.determineImageTypeAndLoadImage();
} catch (e) {
this.setSourceState('failed', e as Error);
this.setState('failed', e as Error);
return {
data: null,
};
}

if (resp.data === null) {
this.setSourceState('failed', Error('ImageTexture: No image data'));
this.setState('failed', Error('ImageTexture: No image data'));
return {
data: null,
};
Expand All @@ -257,7 +257,7 @@ export class ImageTexture extends Texture {
}

// we're loaded!
this.setSourceState('loaded', {
this.setState('fetched', {
width,
height,
});
Expand Down
2 changes: 1 addition & 1 deletion src/core/textures/NoiseTexture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export class NoiseTexture extends Texture {
pixelData8[i + 3] = 255;
}

this.setSourceState('loaded');
this.setState('fetched');

return {
data: new ImageData(pixelData8, width, height),
Expand Down
2 changes: 1 addition & 1 deletion src/core/textures/RenderTexture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export class RenderTexture extends Texture {
}

override async getTextureSource(): Promise<TextureData> {
this.setSourceState('loaded');
this.setState('fetched');

return {
data: null,
Expand Down
80 changes: 63 additions & 17 deletions src/core/textures/SubTexture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* limitations under the License.
*/

import type { Dimensions } from '../../common/CommonTypes.js';
import { assertTruthy } from '../../utils.js';
import type { CoreTextureManager } from '../CoreTextureManager.js';
import { ImageTexture } from './ImageTexture.js';
Expand All @@ -26,6 +27,7 @@ import {
type TextureData,
type TextureFailedEventHandler,
type TextureLoadedEventHandler,
type TextureState,
} from './Texture.js';

/**
Expand Down Expand Up @@ -95,12 +97,10 @@ export class SubTexture extends Texture {
// Resolve parent texture from cache or fallback to provided texture
this.parentTexture = txManager.resolveParentTexture(this.props.texture);

if (this.parentTexture.state === 'freed') {
this.txManager.loadTexture(this.parentTexture);
if (this.renderableOwners.size > 0) {
this.parentTexture.setRenderableOwner(this, true);
}

this.parentTexture.setRenderableOwner(this, true);

// If parent texture is already loaded / failed, trigger loaded event manually
// so that users get a consistent event experience.
// We do this in a microtask to allow listeners to be attached in the same
Expand All @@ -109,12 +109,21 @@ export class SubTexture extends Texture {
const parentTx = this.parentTexture;
if (parentTx.state === 'loaded') {
this.onParentTxLoaded(parentTx, parentTx.dimensions!);
} else if (parentTx.state === 'fetching') {
this.onParentTxFetching();
} else if (parentTx.state === 'fetched') {
this.onParentTxFetched();
} else if (parentTx.state === 'loading') {
this.onParentTxLoading();
} else if (parentTx.state === 'failed') {
this.onParentTxFailed(parentTx, parentTx.error!);
} else if (parentTx.state === 'freed') {
this.onParentTxFreed();
}

parentTx.on('fetched', this.onParentTxFetched);
parentTx.on('loading', this.onParentTxLoading);
parentTx.on('fetching', this.onParentTxFetching);
parentTx.on('loaded', this.onParentTxLoaded);
parentTx.on('failed', this.onParentTxFailed);
parentTx.on('freed', this.onParentTxFreed);
Expand All @@ -124,38 +133,75 @@ export class SubTexture extends Texture {
private onParentTxLoaded: TextureLoadedEventHandler = () => {
// We ignore the parent's passed dimensions, and simply use the SubTexture's
// configured dimensions (because that's all that matters here)
this.setSourceState('loaded', {
this.forwardParentTxState('loaded', {
width: this.props.width,
height: this.props.height,
});

// If the parent already has a ctxTexture, we can set the core ctx state
if (this.parentTexture.ctxTexture !== undefined) {
this.setCoreCtxState('loaded', {
width: this.props.width,
height: this.props.height,
});
}
// free our source, if any
this.freeTextureData();
};

private onParentTxFailed: TextureFailedEventHandler = (target, error) => {
this.setSourceState('failed', error);
this.forwardParentTxState('failed', error);
this.free();
};

private onParentTxFetched = () => {
this.forwardParentTxState('fetched', {
width: this.props.width,
height: this.props.height,
});
};

private onParentTxFetching = () => {
this.forwardParentTxState('fetching');
};

private onParentTxLoading = () => {
this.forwardParentTxState('loading');
};

private onParentTxFreed = () => {
this.setSourceState('freed');
this.forwardParentTxState('freed');
this.free();
};

private forwardParentTxState(
state: TextureState,
errorOrDimensions?: Error | Dimensions,
) {
this.setState(state, errorOrDimensions);
}

override onChangeIsRenderable(isRenderable: boolean): void {
// Propagate the renderable owner change to the parent texture
this.parentTexture.setRenderableOwner(this, isRenderable);
}

override async getTextureSource(): Promise<TextureData> {
// Check if parent texture is loaded
return {
data: this.props,
};
return new Promise((resolve, reject) => {
if (this.parentTexture.state === 'loaded') {
resolve({
data: this.props,
});
}

this.parentTexture.once('loaded', (target, data) => {
resolve({
data: this.props,
});
});

this.parentTexture.once('failed', (target, error) => {
reject(error);
});

this.parentTexture.once('freed', () => {
reject(new Error('Parent texture was freed'));
});
});
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
Expand Down
Loading