Skip to content

Commit

Permalink
Fix worker status set error and can't throw error bug (#1652)
Browse files Browse the repository at this point in the history
* fix: worker status set error

---------

Co-authored-by: GuoLei1990 <[email protected]>
  • Loading branch information
gz65555 and GuoLei1990 authored Jul 24, 2023
1 parent fbd5e82 commit ecc44a1
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 51 deletions.
73 changes: 48 additions & 25 deletions packages/loader/src/ktx2/KTX2Loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ import { TranscodeResult } from "./transcoder/AbstractTranscoder";
import { BinomialLLCTranscoder } from "./transcoder/BinomialLLCTranscoder";
import { KhronosTranscoder } from "./transcoder/KhronosTranscoder";

@resourceLoader(AssetType.KTX, ["ktx2"])
@resourceLoader(AssetType.KTX2, ["ktx2"])
export class KTX2Loader extends Loader<Texture2D | TextureCube> {
private static _isBinomialInit: boolean = false;
private static _binomialLLCTranscoder: BinomialLLCTranscoder;
private static _khronosTranscoder: KhronosTranscoder;
private static _supportedMap = {
Expand All @@ -47,12 +48,11 @@ export class KTX2Loader extends Loader<Texture2D | TextureCube> {
private static _decideTargetFormat(
engine: Engine,
ktx2Container: KTX2Container,
formatPriorities?: KTX2TargetFormat[]
priorityFormats?: KTX2TargetFormat[]
): KTX2TargetFormat {
// @ts-ignore
const renderer = engine._hardwareRenderer as WebGLRenderer;
const renderer = (engine as any)._hardwareRenderer;

const targetFormat = this._detectSupportedFormat(renderer, formatPriorities) as KTX2TargetFormat;
const targetFormat = this._detectSupportedFormat(renderer, priorityFormats) as KTX2TargetFormat;

if (
targetFormat === KTX2TargetFormat.PVRTC &&
Expand All @@ -68,32 +68,32 @@ export class KTX2Loader extends Loader<Texture2D | TextureCube> {
Logger.warn("Can't support any compressed texture, downgrade to RGBA8");
return KTX2TargetFormat.R8G8B8A8;
}
// TODO support bc7: https://github.com/galacean/engine/issues/1371
return targetFormat;
}

private static _detectSupportedFormat(
renderer: any,
formatPriorities: KTX2TargetFormat[] = [
priorityFormats: KTX2TargetFormat[] = [
KTX2TargetFormat.ASTC,
KTX2TargetFormat.ETC,
KTX2TargetFormat.BC7,
KTX2TargetFormat.BC1_BC3,
KTX2TargetFormat.PVRTC
]
): KTX2TargetFormat | null {
for (let i = 0; i < formatPriorities.length; i++) {
const capabilities = this._supportedMap[formatPriorities[i]];
for (let i = 0; i < priorityFormats.length; i++) {
const capabilities = this._supportedMap[priorityFormats[i]];
for (let j = 0; j < capabilities.length; j++) {
if (renderer.canIUse(capabilities[j])) {
return formatPriorities[i];
return priorityFormats[i];
}
}
}
return null;
}

private static _getBinomialLLCTranscoder(workerCount: number = 4) {
KTX2Loader._isBinomialInit = true;
return (this._binomialLLCTranscoder ??= new BinomialLLCTranscoder(workerCount));
}

Expand All @@ -104,10 +104,7 @@ export class KTX2Loader extends Loader<Texture2D | TextureCube> {
override initialize(engine: Engine, configuration: EngineConfiguration): Promise<void> {
if (configuration.ktx2Loader) {
const options = configuration.ktx2Loader;
if (
// @ts-ignore
KTX2Loader._detectSupportedFormat(engine._hardwareRenderer, options.formatPriorities) === KTX2TargetFormat.ASTC
) {
if (this._isKhronosSupported(options.priorityFormats, engine)) {
return KTX2Loader._getKhronosTranscoder(options.workerCount).init();
} else {
return KTX2Loader._getBinomialLLCTranscoder(options.workerCount).init();
Expand All @@ -124,15 +121,15 @@ export class KTX2Loader extends Loader<Texture2D | TextureCube> {
): AssetPromise<Texture2D | TextureCube> {
return this.request<ArrayBuffer>(item.url!, { type: "arraybuffer" }).then((buffer) => {
const ktx2Container = new KTX2Container(buffer);
const formatPriorities = item.params?.formatPriorities;
const formatPriorities = item.params?.priorityFormats;
const targetFormat = KTX2Loader._decideTargetFormat(resourceManager.engine, ktx2Container, formatPriorities);
let transcodeResultPromise: Promise<any>;
if (targetFormat === KTX2TargetFormat.ASTC && ktx2Container.isUASTC) {
const khronosWorker = KTX2Loader._getKhronosTranscoder();
transcodeResultPromise = khronosWorker.init().then(() => khronosWorker.transcode(ktx2Container));
} else {
if (KTX2Loader._isBinomialInit || !KhronosTranscoder.transcoderMap[targetFormat] || !ktx2Container.isUASTC) {
const binomialLLCWorker = KTX2Loader._getBinomialLLCTranscoder();
transcodeResultPromise = binomialLLCWorker.init().then(() => binomialLLCWorker.transcode(buffer, targetFormat));
} else {
const khronosWorker = KTX2Loader._getKhronosTranscoder();
transcodeResultPromise = khronosWorker.init().then(() => khronosWorker.transcode(ktx2Container));
}
return transcodeResultPromise.then((result) => {
const { width, height, faces } = result;
Expand Down Expand Up @@ -168,7 +165,7 @@ export class KTX2Loader extends Loader<Texture2D | TextureCube> {
});
}

private _getEngineTextureFormat(basisFormat: KTX2TargetFormat, transcodeResult: TranscodeResult) {
private _getEngineTextureFormat(basisFormat: KTX2TargetFormat, transcodeResult: TranscodeResult): TextureFormat {
const { hasAlpha } = transcodeResult;
switch (basisFormat) {
case KTX2TargetFormat.ASTC:
Expand All @@ -178,21 +175,47 @@ export class KTX2Loader extends Loader<Texture2D | TextureCube> {
case KTX2TargetFormat.BC7:
return TextureFormat.BC7;
case KTX2TargetFormat.BC1_BC3:
return hasAlpha ? TextureFormat.BC1 : TextureFormat.BC3;
return hasAlpha ? TextureFormat.BC3 : TextureFormat.BC1;
case KTX2TargetFormat.PVRTC:
return hasAlpha ? TextureFormat.PVRTC_RGBA4 : TextureFormat.PVRTC_RGB4;
case KTX2TargetFormat.R8G8B8A8:
return TextureFormat.R8G8B8A8;
}
}

private _isKhronosSupported(
priorityFormats: KTX2TargetFormat[] | KTX2TargetFormat[][] = [
KTX2TargetFormat.ASTC,
KTX2TargetFormat.ETC,
KTX2TargetFormat.BC7,
KTX2TargetFormat.BC1_BC3,
KTX2TargetFormat.PVRTC,
KTX2TargetFormat.R8G8B8A8
],
engine: any
): boolean {
const supportedList = new Array<KTX2TargetFormat>();
if (Array.isArray(priorityFormats[0])) {
for (let i = 0; i < priorityFormats.length; i++) {
supportedList.push(
KTX2Loader._detectSupportedFormat(engine._hardwareRenderer, <KTX2TargetFormat[]>priorityFormats[i])
);
}
} else {
supportedList.push(
KTX2Loader._detectSupportedFormat(engine._hardwareRenderer, <KTX2TargetFormat[]>priorityFormats)
);
}
return supportedList.every((format) => KhronosTranscoder.transcoderMap[format]);
}
}

/**
* KTX2 loader params interface.
*/
export interface KTX2Params {
/** Transcoder Format priorities, default is ASTC/ETC/DXT/PVRTC/RGBA8. */
formatPriorities: KTX2TargetFormat[];
/** Priority transcoding format queue, default is ASTC/ETC/DXT/PVRTC/RGBA8. */
priorityFormats: KTX2TargetFormat[];
}

declare module "@galacean/engine-core" {
Expand All @@ -201,8 +224,8 @@ declare module "@galacean/engine-core" {
ktx2Loader?: {
/** Worker count for transcoder, default is 4. */
workerCount?: number;
/** Transcoder Format priorities, default is ASTC/ETC/DXT/PVRTC/RGBA8. */
formatPriorities?: KTX2TargetFormat[];
/** Pre-initialization according to the priority transcoding format queue, default is ASTC/ETC/DXT/PVRTC/RGBA8. */
priorityFormats?: KTX2TargetFormat[] | KTX2TargetFormat[][];
};
}
}
40 changes: 23 additions & 17 deletions packages/loader/src/ktx2/WorkerPool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,23 @@ export class WorkerPool<T = any, U = any> {

/**
* Post message to worker.
* @param message - message which posted to worker
* @returns return a promise of message
* @param message - Message which posted to worker
* @returns Return a promise of message
*/
postMessage(message: T): Promise<U> {
return new Promise((resolve, reject) => {
const workerId = this._getIdleWorkerId();
if (workerId !== -1) {
this._workerStatus |= 1 << workerId;
const workerItems = this._workerItems;
Promise.resolve(workerItems[workerId] ?? this._initWorker(workerId)).then(() => {
this._workerStatus |= 1 << workerId;
const workerItem = workerItems[workerId];
workerItem.resolve = resolve;
workerItem.reject = reject;
workerItem.worker.postMessage(message);
});
Promise.resolve(workerItems[workerId] ?? this._initWorker(workerId))
.then(() => {
const workerItem = workerItems[workerId];
workerItem.resolve = resolve;
workerItem.reject = reject;
workerItem.worker.postMessage(message);
})
.catch(reject);
} else {
this._taskQueue.push({ resolve, reject, message });
}
Expand All @@ -70,7 +72,6 @@ export class WorkerPool<T = any, U = any> {
private _initWorker(workerId: number): Promise<Worker> {
return Promise.resolve(this._workerCreator()).then((worker) => {
worker.addEventListener("message", this._onMessage.bind(this, workerId));
worker.addEventListener("error", this._onError.bind(this, workerId));
this._workerItems[workerId] = { worker, resolve: null, reject: null };
return worker;
});
Expand All @@ -83,13 +84,14 @@ export class WorkerPool<T = any, U = any> {
return -1;
}

private _onError(workerId, e: ErrorEvent) {
this._workerItems[workerId].reject(e);
this._nextTask(workerId);
}

private _onMessage(workerId: number, msg: U) {
this._workerItems[workerId].resolve(msg);
private _onMessage(workerId: number, msg: MessageEvent<U>) {
// onerror of web worker can't catch error in promise
const error = (msg.data as ErrorMessageData).error;
if (error) {
this._workerItems[workerId].reject(error);
} else {
this._workerItems[workerId].resolve(msg.data);
}
this._nextTask(workerId);
}

Expand All @@ -106,6 +108,10 @@ export class WorkerPool<T = any, U = any> {
}
}

interface ErrorMessageData {
error: unknown;
}

interface WorkerItem<U> {
worker: Worker;
resolve: (item: U | PromiseLike<U>) => void;
Expand Down
12 changes: 5 additions & 7 deletions packages/loader/src/ktx2/transcoder/BinomialLLCTranscoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,10 @@ export class BinomialLLCTranscoder extends AbstractTranscoder {
}

transcode(buffer: ArrayBuffer, format: KTX2TargetFormat): Promise<TranscodeResult> {
return this._transcodeWorkerPool
.postMessage({
buffer,
format,
type: "transcode"
})
.then((ev) => ev.data);
return this._transcodeWorkerPool.postMessage({
buffer,
format,
type: "transcode"
});
}
}
4 changes: 2 additions & 2 deletions packages/loader/src/ktx2/transcoder/KhronosTranscoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ export class KhronosTranscoder extends AbstractTranscoder {
messageData[faceIndex] = mipmapData;
}

return this._transcodeWorkerPool.postMessage(postMessageData).then((message) => {
decodedData.faces = message.data;
return this._transcodeWorkerPool.postMessage(postMessageData).then((data) => {
decodedData.faces = data;
decodedData.hasAlpha = true;
return decodedData;
});
Expand Down

0 comments on commit ecc44a1

Please sign in to comment.