playcanvas
Version:
PlayCanvas WebGL game engine
79 lines (76 loc) • 3.55 kB
JavaScript
import { Debug } from '../../core/debug.js';
import { pixelFormatInfo, PIXELFORMAT_PVRTC_2BPP_RGB_1, PIXELFORMAT_PVRTC_2BPP_RGBA_1 } from './constants.js';
/**
* A class providing utility functions for textures.
*
* @ignore
*/ class TextureUtils {
/**
* Calculate the dimension of a texture at a specific mip level.
*
* @param {number} dimension - Texture dimension at level 0.
* @param {number} mipLevel - Mip level.
* @returns {number} The dimension of the texture at the specified mip level.
*/ static calcLevelDimension(dimension, mipLevel) {
return Math.max(dimension >> mipLevel, 1);
}
/**
* Calculate the number of mip levels for a texture with the specified dimensions.
*
* @param {number} width - Texture's width.
* @param {number} height - Texture's height.
* @param {number} [depth] - Texture's depth. Defaults to 1.
* @returns {number} The number of mip levels required for the texture.
*/ static calcMipLevelsCount(width, height, depth = 1) {
return 1 + Math.floor(Math.log2(Math.max(width, height, depth)));
}
/**
* Calculate the size in bytes of the texture level given its format and dimensions.
*
* @param {number} width - Texture's width.
* @param {number} height - Texture's height.
* @param {number} depth - Texture's depth.
* @param {number} format - Texture's pixel format PIXELFORMAT_***.
* @returns {number} The number of bytes of GPU memory required for the texture.
*/ static calcLevelGpuSize(width, height, depth, format) {
const formatInfo = pixelFormatInfo.get(format);
Debug.assert(formatInfo !== undefined, `Invalid pixel format ${format}`);
const pixelSize = pixelFormatInfo.get(format)?.size ?? 0;
if (pixelSize > 0) {
return width * height * depth * pixelSize;
}
const blockSize = formatInfo.blockSize ?? 0;
let blockWidth = Math.floor((width + 3) / 4);
const blockHeight = Math.floor((height + 3) / 4);
const blockDepth = Math.floor((depth + 3) / 4);
if (format === PIXELFORMAT_PVRTC_2BPP_RGB_1 || format === PIXELFORMAT_PVRTC_2BPP_RGBA_1) {
blockWidth = Math.max(Math.floor(blockWidth / 2), 1);
}
return blockWidth * blockHeight * blockDepth * blockSize;
}
/**
* Calculate the GPU memory required for a texture.
*
* @param {number} width - Texture's width.
* @param {number} height - Texture's height.
* @param {number} depth - Texture's depth.
* @param {number} format - Texture's pixel format PIXELFORMAT_***.
* @param {boolean} mipmaps - True if the texture includes mipmaps, false otherwise.
* @param {boolean} cubemap - True is the texture is a cubemap, false otherwise.
* @returns {number} The number of bytes of GPU memory required for the texture.
*/ static calcGpuSize(width, height, depth, format, mipmaps, cubemap) {
let result = 0;
while(1){
result += TextureUtils.calcLevelGpuSize(width, height, depth, format);
// we're done if mipmaps aren't required or we've calculated the smallest mipmap level
if (!mipmaps || width === 1 && height === 1 && depth === 1) {
break;
}
width = Math.max(width >> 1, 1);
height = Math.max(height >> 1, 1);
depth = Math.max(depth >> 1, 1);
}
return result * (cubemap ? 6 : 1);
}
}
export { TextureUtils };