瀏覽代碼

Reduce the main thread blocking time on load scene

Images are decoded on worker threads now to reduce the blocking time of the main thread. The decoded ImageBitmap instead of the HTMLImageElement is then passed to gl.texImage2D. Moreover, non-cubemap images are always splitted into 2 parts to be uploaded to the texture instead of being splitted with considering the width of them so that the main thread will not be blocked continuously for so long.

createImageBitmap and fetch APIs are used:
- createImageBitmap(Blob) is used to decode images on worker threads.
- fetch() is used to get BLOB from images.
pull/998/head
Quicksilver0218 3 年之前
committed by GitHub
父節點
當前提交
65e6a98946
沒有發現已知的金鑰在資料庫的簽署中 GPG 金鑰 ID: 4AEE18F83AFDEB23
共有 1 個檔案被更改,包括 19 行新增30 行删除
  1. +19
    -30
      src/js/libpannellum.js

+ 19
- 30
src/js/libpannellum.js 查看文件

@@ -382,6 +382,7 @@ function Renderer(container) {
program.texCoordLocation = gl.getAttribLocation(program, 'a_texCoord');
gl.enableVertexAttribArray(program.texCoordLocation);

const promises = [];
if (imageType != 'multires') {
// Provide texture coordinates for rectangle
if (!texCoordBuffer)
@@ -421,52 +422,40 @@ function Renderer(container) {
// Upload images to texture depending on type
if (imageType == 'cubemap') {
// Load all six sides of the cube map
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image[1]);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_X, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image[3]);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Y, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image[4]);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image[5]);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Z, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image[0]);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image[2]);
promises.push(fetch(image[1].src).then(res => res.blob()).then(blob => createImageBitmap(blob)).then(bitmap => gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, bitmap)).finally(() => URL.revokeObjectURL(image[1].src)));
promises.push(fetch(image[3].src).then(res => res.blob()).then(blob => createImageBitmap(blob)).then(bitmap => gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_X, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, bitmap)).finally(() => URL.revokeObjectURL(image[3].src)));
promises.push(fetch(image[4].src).then(res => res.blob()).then(blob => createImageBitmap(blob)).then(bitmap => gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Y, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, bitmap)).finally(() => URL.revokeObjectURL(image[4].src)));
promises.push(fetch(image[5].src).then(res => res.blob()).then(blob => createImageBitmap(blob)).then(bitmap => gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, bitmap)).finally(() => URL.revokeObjectURL(image[5].src)));
promises.push(fetch(image[0].src).then(res => res.blob()).then(blob => createImageBitmap(blob)).then(bitmap => gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Z, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, bitmap)).finally(() => URL.revokeObjectURL(image[0].src)));
promises.push(fetch(image[2].src).then(res => res.blob()).then(blob => createImageBitmap(blob)).then(bitmap => gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, bitmap)).finally(() => URL.revokeObjectURL(image[2].src)));
} else {
if (image.width <= maxWidth) {
gl.uniform1i(gl.getUniformLocation(program, 'u_splitImage'), 0);
// Upload image to the texture
gl.texImage2D(glBindType, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image);
} else {
// Image needs to be split into two parts due to texture size limits
gl.uniform1i(gl.getUniformLocation(program, 'u_splitImage'), 1);

// Draw image on canvas
var cropCanvas = document.createElement('canvas');
cropCanvas.width = image.width / 2;
cropCanvas.height = image.height;
var cropContext = cropCanvas.getContext('2d');
cropContext.drawImage(image, 0, 0);
const blobPromise = fetch(image.src).then(res => res.blob());
blobPromise.finally(() => URL.revokeObjectURL(image.src));

// Upload first half of image to the texture
var cropImage = cropContext.getImageData(0, 0, image.width / 2, image.height);
gl.texImage2D(glBindType, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, cropImage);
// Split the image into two parts to split the blocking time of the main thread
gl.uniform1i(gl.getUniformLocation(program, 'u_splitImage'), 1);
// Upload first half of image to the texture
promises.push(blobPromise.then(blob => createImageBitmap(blob, 0, 0, image.width / 2, image.height)).then(bitmap => gl.texImage2D(glBindType, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, bitmap)));

// Upload second half of image to the texture
promises.push(blobPromise.then(blob => createImageBitmap(blob, image.width / 2, 0, image.width / 2, image.height)).then(bitmap => {
// Create and bind texture for second half of image
program.texture2 = gl.createTexture();
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(glBindType, program.texture2);
gl.uniform1i(gl.getUniformLocation(program, 'u_image1'), 1);

// Upload second half of image to the texture
cropContext.drawImage(image, -image.width / 2, 0);
cropImage = cropContext.getImageData(0, 0, image.width / 2, image.height);
gl.texImage2D(glBindType, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, cropImage);

// Set parameters for rendering any size
gl.texParameteri(glBindType, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(glBindType, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(glBindType, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(glBindType, gl.TEXTURE_MAG_FILTER, gl.LINEAR);

gl.texImage2D(glBindType, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, bitmap);

// Reactivate first texture unit
gl.activeTexture(gl.TEXTURE0);
}
}));
}

// Set parameters for rendering any size
@@ -521,7 +510,7 @@ function Renderer(container) {
throw {type: 'webgl error'};
}

callback();
Promise.all(promises).then(() => callback());
};

/**


Loading…
取消
儲存