Skip to content

Commit

Permalink
Resize huge textures for iOS devices
Browse files Browse the repository at this point in the history
Browsers on iOS devices can crash if huge or many textures are
used in a room. Perhaps huge VRAM usage may cause it. We already
reported it to the webkit devs.

Until the root issue is fixed on iOS end, we resize huge texture
images in the low material quality mode as workaround. It isn't
a perfect solution but it should mitigate the problem.
  • Loading branch information
takahirox committed Jun 29, 2022
1 parent 56fd019 commit 1bd0082
Showing 1 changed file with 64 additions and 3 deletions.
67 changes: 64 additions & 3 deletions src/loaders/HubsTextureLoader.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,81 @@
import { isIOS as detectIOS } from "../utils/is-mobile";

// Disable ImageBitmap for Firefox so far because
// createImageBitmap() with option fails on Firefox due to the bug.
// Three.js ImageBitmapLoader passes {colorSpaceConversion: 'none'} option.
// Without the option, the rendering result can be wrong if image file has ICC profiles.
// See https://github.com/mrdoob/three.js/pull/21336
const HAS_IMAGE_BITMAP = window.createImageBitmap !== undefined && /Firefox/.test(navigator.userAgent) === false;
export const TEXTURES_FLIP_Y = !HAS_IMAGE_BITMAP;
const isIOS = detectIOS();

// Browsers on iOS devices can crash if huge or many textures are used in a room.
// Perhaps huge VRAM usage may cause it. We already reported it to the webkit devs.
// Until the root issue is fixed on iOS end, we resize huge texture images in the
// low material quality mode as workaround. It isn't a perfect solution but it
// should mitigate the problem.
// Also see
// - https://github.com/mozilla/hubs/issues/5295
// - https://bugs.webkit.org/show_bug.cgi?id=241478

const IOS_TEXTURE_MAX_WIDTH = 2048;
const IOS_TEXTURE_MAX_HEIGHT = 2048;

function resizeIfNeeded(texture) {
if (!isIOS || window.APP.store.state.preferences.materialQualitySetting !== "low") {
return texture;
}

const image = texture.image;

// Just in case.
if (!image || image.width === undefined || image.height === undefined) {
return texture;
}

if (image.width <= IOS_TEXTURE_MAX_WIDTH && image.height <= IOS_TEXTURE_MAX_HEIGHT) {
return texture;
}

const conversionRatio = Math.min(IOS_TEXTURE_MAX_WIDTH / image.width, IOS_TEXTURE_MAX_HEIGHT / image.height);

const newWidth = Math.round(image.width * conversionRatio);
const newHeight = Math.round(image.height * conversionRatio);

const useOffscreenCanvas = typeof OffscreenCanvas !== "undefined";
const canvas = useOffscreenCanvas ? new OffscreenCanvas(newWidth, newHeight) : document.createElement("canvas");
canvas.width = newWidth;
canvas.height = newHeight;
const context = canvas.getContext("2d");
context.drawImage(image, 0, 0, newWidth, newHeight);

texture.image = useOffscreenCanvas ? canvas.transferToImageBitmap() : canvas;

if (image.close !== undefined) {
image.close();
}

texture.format = THREE.RGBAFormat;
texture.type = THREE.UnsignedByteType;
return texture;
}

export default class HubsTextureLoader extends THREE.TextureLoader {
constructor(manager) {
super(manager);
}

load(url, onLoad, onProgress, onError) {
const callback = texture => {
resizeIfNeeded(texture);
if (onLoad) {
onLoad(texture);
}
};

const texture = HAS_IMAGE_BITMAP
? this.loadImageBitmapTexture(url, onLoad, onProgress, onError)
: super.load(url, onLoad, onProgress, onError);
? this._loadImageBitmapTexture(url, callback, onProgress, onError)
: super.load(url, callback, onProgress, onError);

texture.onUpdate = function() {
// Delete texture data once it has been uploaded to the GPU
Expand All @@ -31,7 +92,7 @@ export default class HubsTextureLoader extends THREE.TextureLoader {
});
}

loadImageBitmapTexture(url, onLoad, onProgress, onError) {
_loadImageBitmapTexture(url, onLoad, onProgress, onError) {
const texture = new THREE.Texture();
const loader = new THREE.ImageBitmapLoader(this.manager);
loader.setCrossOrigin(this.crossOrigin);
Expand Down

0 comments on commit 1bd0082

Please sign in to comment.