Просмотр исходного кода

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
Родитель
Сommit
65e6a98946
Не найден GPG ключ соответствующий данной подписи Идентификатор GPG ключа: 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());
};

/**


Загрузка…
Отмена
Сохранить