Advance Blender 5.2 web parity through M12-03D
This commit is contained in:
26
web/app/src/workers/asset-catalog-restart-test.worker.ts
Normal file
26
web/app/src/workers/asset-catalog-restart-test.worker.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { loadAssetCatalogIndexedDBSnapshot } from "../storage/asset-catalog-indexeddb";
|
||||
|
||||
const scope = self as unknown as {
|
||||
onmessage: ((event: MessageEvent<{ databaseName: string }>) => void) | null;
|
||||
postMessage: (value: unknown) => void;
|
||||
};
|
||||
|
||||
function openDatabase(name: string): Promise<IDBDatabase> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = indexedDB.open(name);
|
||||
request.onsuccess = () => resolve(request.result);
|
||||
request.onerror = () => reject(request.error ?? new Error("Catalog restart database open failed"));
|
||||
});
|
||||
}
|
||||
|
||||
scope.onmessage = (event): void => {
|
||||
void openDatabase(event.data.databaseName).then(async (database) => {
|
||||
try {
|
||||
return await loadAssetCatalogIndexedDBSnapshot(database);
|
||||
}
|
||||
finally {
|
||||
database.close();
|
||||
}
|
||||
}).then((snapshot) => scope.postMessage({ ok: true, snapshot }))
|
||||
.catch((error) => scope.postMessage({ ok: false, error: error instanceof Error ? error.message : String(error) }));
|
||||
};
|
||||
13
web/app/src/workers/asset-preview-display-test.worker.ts
Normal file
13
web/app/src/workers/asset-preview-display-test.worker.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { displayAssetPreview } from "../assets/AssetPreviewDisplay";
|
||||
|
||||
const scope = self as unknown as {
|
||||
onmessage: ((event: MessageEvent<{ identity: unknown; bytes: ArrayBuffer }>) => void) | null;
|
||||
postMessage: (value: unknown, transfer?: Transferable[]) => void;
|
||||
};
|
||||
|
||||
scope.onmessage = (event): void => {
|
||||
const canvas = new OffscreenCanvas(1, 1);
|
||||
void displayAssetPreview(canvas, "OFFSCREEN_CANVAS_2D", event.data.identity, event.data.bytes)
|
||||
.then((result) => scope.postMessage({ ok: true, receipt: result.receipt, pixels: result.pixels }, [result.pixels.buffer]))
|
||||
.catch((error) => scope.postMessage({ ok: false, error: error instanceof Error ? error.message : String(error) }));
|
||||
};
|
||||
@@ -29,6 +29,12 @@ import {
|
||||
gatePaintPBVHCapability,
|
||||
PAINT_PBVH_WASM_ENTRYPOINT,
|
||||
} from "../../../protocol/paint-pbvh-capability";
|
||||
import {
|
||||
createLibraryMainAppendReceipt,
|
||||
parseLibraryMainAppendRequest,
|
||||
sha256LibraryBytes,
|
||||
type LibraryAppendClosureIR,
|
||||
} from "../../../protocol/library-main-append";
|
||||
|
||||
type WasmModule = {
|
||||
_malloc: (size: number) => number;
|
||||
@@ -39,6 +45,7 @@ type WasmModule = {
|
||||
_web_engine_get_allocated_bytes: () => number;
|
||||
_web_engine_open_blend: (handle: number, data: number, length: number) => number;
|
||||
_web_engine_apply_command: (handle: number, data: number, length: number) => number;
|
||||
_web_engine_append_library_object: (handle: number, source: number, sourceLength: number, metadata: number, metadataLength: number) => number;
|
||||
_web_engine_undo: (handle: number) => number;
|
||||
_web_engine_redo: (handle: number) => number;
|
||||
_web_engine_get_scene_snapshot: (handle: number, data: number, length: number) => number;
|
||||
@@ -603,6 +610,30 @@ function nativeErrorFor(target: WasmModule, fallbackCode: ErrorReport["code"]):
|
||||
return report(mappedCode, message);
|
||||
}
|
||||
|
||||
function assertAppendedClosure(
|
||||
snapshot: ReturnType<typeof parseSceneSnapshotIR>,
|
||||
closure: LibraryAppendClosureIR,
|
||||
): void {
|
||||
const name = (value: string) => value.slice(value.indexOf("/") + 1);
|
||||
const objectId = `object:${name(closure.object)}`;
|
||||
const meshId = `mesh:${name(closure.mesh)}`;
|
||||
const materialId = `material:${name(closure.material)}`;
|
||||
const imageId = `image:${name(closure.image)}`;
|
||||
const object = snapshot.nodes.find((item) => item.id === objectId);
|
||||
const mesh = snapshot.meshes.find((item) => item.id === meshId);
|
||||
const material = snapshot.materials.find((item) => item.id === materialId);
|
||||
const image = snapshot.images.find((item) => item.id === imageId);
|
||||
const materialImageIds = new Set([
|
||||
...(material?.imageIds ?? []),
|
||||
...(material?.nodes?.flatMap((node) => node.imageId ? [node.imageId] : []) ?? []),
|
||||
]);
|
||||
if (!object || object.type !== "MESH" || object.dataId !== meshId || !mesh ||
|
||||
mesh.materialSlotIds?.length !== 1 || mesh.materialSlotIds[0] !== materialId ||
|
||||
!material || !materialImageIds.has(imageId) || !image || image.libraryLinked !== false) {
|
||||
throw report("ASSET_SOURCE_HASH_MISMATCH", "WASM Main append did not publish the expected fully-local dependency closure");
|
||||
}
|
||||
}
|
||||
|
||||
async function initialize(): Promise<WebEngineStatus> {
|
||||
if (module) return status();
|
||||
if (!initializationPromise) {
|
||||
@@ -1316,6 +1347,55 @@ async function handleRequest(event: MessageEvent<WebEngineRequest>): Promise<voi
|
||||
};
|
||||
break;
|
||||
}
|
||||
case "appendLibraryObject": {
|
||||
await initialize();
|
||||
const beforeSnapshot = currentSnapshot ?? (await readSnapshotResult()).snapshot;
|
||||
let appendRequest;
|
||||
try {
|
||||
appendRequest = await parseLibraryMainAppendRequest(request.command.request, beforeSnapshot.revision);
|
||||
const sourceSha256 = await sha256LibraryBytes(request.command.source);
|
||||
if (sourceSha256 !== appendRequest.binding.source.sourceSha256) {
|
||||
throw report("ASSET_SOURCE_HASH_MISMATCH", "library append bytes do not match the bound source SHA-256");
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
reportProtocolError(error, "ASSET_MANIFEST_INVALID");
|
||||
}
|
||||
const metadata = {
|
||||
schemaVersion: appendRequest.schemaVersion,
|
||||
baseRevision: appendRequest.baseRevision,
|
||||
sourceLocator: appendRequest.binding.source.sourceLocator,
|
||||
sourceDataBlockId: appendRequest.binding.sourceDataBlockId,
|
||||
expectedClosure: appendRequest.expectedClosure,
|
||||
};
|
||||
const sourceInput = copyIntoWasm(request.command.source);
|
||||
const metadataInput = copyCommand(metadata);
|
||||
try {
|
||||
if (!module || module._web_engine_append_library_object(
|
||||
handle,
|
||||
sourceInput.pointer,
|
||||
sourceInput.length,
|
||||
metadataInput.pointer,
|
||||
metadataInput.length,
|
||||
) !== 0) {
|
||||
throw nativeError("ASSET_MANIFEST_INVALID");
|
||||
}
|
||||
}
|
||||
finally {
|
||||
module?._free(metadataInput.pointer);
|
||||
module?._free(sourceInput.pointer);
|
||||
}
|
||||
const scene = await readSnapshotResult();
|
||||
assertAppendedClosure(scene.snapshot, appendRequest.expectedClosure);
|
||||
currentSnapshot = scene.snapshot;
|
||||
result = {
|
||||
status: status(),
|
||||
...publishIncrementalScene(scene),
|
||||
delta: readDelta(),
|
||||
libraryAppend: createLibraryMainAppendReceipt(appendRequest, scene.snapshot.revision),
|
||||
};
|
||||
break;
|
||||
}
|
||||
case "generateLOD": {
|
||||
await initialize();
|
||||
const payload = request.command.payload;
|
||||
|
||||
Reference in New Issue
Block a user