Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/flo-bit/shapecraft. flo-bit.dev/shapecraft
Something went wrong. Try again.
35 kB · 1225 lines
JavaScript
at commit da69385e
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226import { GPUTextureFormat, GPUAddressMode, GPUFilterMode, GPUTextureDimension, GPUFeatureName} from './WebGPUConstants.js';
import WebGPUTexturePassUtils from './WebGPUTexturePassUtils.js';
import { ByteType, ShortType, NearestFilter, NearestMipmapNearestFilter, NearestMipmapLinearFilter, RepeatWrapping, MirroredRepeatWrapping, RGB_ETC2_Format, RGBA_ETC2_EAC_Format, RGBAFormat, RGBFormat, RedFormat, RGFormat, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, UnsignedByteType, FloatType, HalfFloatType, SRGBColorSpace, DepthFormat, DepthStencilFormat, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_10x10_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, UnsignedIntType, UnsignedShortType, UnsignedInt248Type, UnsignedInt5999Type, NeverCompare, AlwaysCompare, LessCompare, LessEqualCompare, EqualCompare, GreaterEqualCompare, GreaterCompare, NotEqualCompare, IntType, RedIntegerFormat, RGIntegerFormat, RGBAIntegerFormat, CubeReflectionMapping, CubeRefractionMapping, EquirectangularReflectionMapping, EquirectangularRefractionMapping} from '../../../constants.js';import { CubeTexture } from '../../../textures/CubeTexture.js';import { DepthTexture } from '../../../textures/DepthTexture.js';import { Texture } from '../../../textures/Texture.js';
const _compareToWebGPU = { [ NeverCompare ]: 'never', [ LessCompare ]: 'less', [ EqualCompare ]: 'equal', [ LessEqualCompare ]: 'less-equal', [ GreaterCompare ]: 'greater', [ GreaterEqualCompare ]: 'greater-equal', [ AlwaysCompare ]: 'always', [ NotEqualCompare ]: 'not-equal'};
const _flipMap = [ 0, 1, 3, 2, 4, 5 ];
class WebGPUTextureUtils {
constructor( backend ) {
this.backend = backend;
this._passUtils = null;
this.defaultTexture = {}; this.defaultCubeTexture = {}; this.defaultVideoFrame = null;
this.colorBuffer = null;
this.depthTexture = new DepthTexture(); this.depthTexture.name = 'depthBuffer';
}
createSampler( texture ) {
const backend = this.backend; const device = backend.device;
const textureGPU = backend.get( texture );
const samplerDescriptorGPU = { addressModeU: this._convertAddressMode( texture.wrapS ), addressModeV: this._convertAddressMode( texture.wrapT ), addressModeW: this._convertAddressMode( texture.wrapR ), magFilter: this._convertFilterMode( texture.magFilter ), minFilter: this._convertFilterMode( texture.minFilter ), mipmapFilter: this._convertFilterMode( texture.minFilter ), maxAnisotropy: 1 };
// anisotropy can only be used when all filter modes are set to linear.
if ( samplerDescriptorGPU.magFilter === GPUFilterMode.Linear && samplerDescriptorGPU.minFilter === GPUFilterMode.Linear && samplerDescriptorGPU.mipmapFilter === GPUFilterMode.Linear ) {
samplerDescriptorGPU.maxAnisotropy = texture.anisotropy;
}
if ( texture.isDepthTexture && texture.compareFunction !== null ) {
samplerDescriptorGPU.compare = _compareToWebGPU[ texture.compareFunction ];
}
textureGPU.sampler = device.createSampler( samplerDescriptorGPU );
}
createDefaultTexture( texture ) {
let textureGPU;
const format = getFormat( texture );
if ( texture.isCubeTexture ) {
textureGPU = this._getDefaultCubeTextureGPU( format );
} else if ( texture.isVideoTexture ) {
this.backend.get( texture ).externalTexture = this._getDefaultVideoFrame();
} else {
textureGPU = this._getDefaultTextureGPU( format );
}
this.backend.get( texture ).texture = textureGPU;
}
createTexture( texture, options = {} ) {
const backend = this.backend; const textureData = backend.get( texture );
if ( textureData.initialized ) {
throw new Error( 'WebGPUTextureUtils: Texture already initialized.' );
}
if ( options.needsMipmaps === undefined ) options.needsMipmaps = false; if ( options.levels === undefined ) options.levels = 1; if ( options.depth === undefined ) options.depth = 1;
const { width, height, depth, levels } = options;
if ( texture.isFramebufferTexture ) {
if ( options.renderTarget ) {
options.format = this.backend.utils.getCurrentColorFormat( options.renderTarget );
} else {
options.format = this.backend.utils.getPreferredCanvasFormat();
}
}
const dimension = this._getDimension( texture ); const format = texture.internalFormat || options.format || getFormat( texture, backend.device );
textureData.format = format;
let sampleCount = options.sampleCount !== undefined ? options.sampleCount : 1;
sampleCount = backend.utils.getSampleCount( sampleCount );
const primarySampleCount = texture.isRenderTargetTexture && ! texture.isMultisampleRenderTargetTexture ? 1 : sampleCount;
let usage = GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC;
if ( texture.isStorageTexture === true ) {
usage |= GPUTextureUsage.STORAGE_BINDING;
}
if ( texture.isCompressedTexture !== true && texture.isCompressedArrayTexture !== true ) {
usage |= GPUTextureUsage.RENDER_ATTACHMENT;
}
const textureDescriptorGPU = { label: texture.name, size: { width: width, height: height, depthOrArrayLayers: depth, }, mipLevelCount: levels, sampleCount: primarySampleCount, dimension: dimension, format: format, usage: usage };
// texture creation
if ( texture.isVideoTexture ) {
const video = texture.source.data; const videoFrame = new VideoFrame( video );
textureDescriptorGPU.size.width = videoFrame.displayWidth; textureDescriptorGPU.size.height = videoFrame.displayHeight;
videoFrame.close();
textureData.externalTexture = video;
} else {
if ( format === undefined ) {
console.warn( 'WebGPURenderer: Texture format not supported.' );
return this.createDefaultTexture( texture );
}
textureData.texture = backend.device.createTexture( textureDescriptorGPU );
}
if ( texture.isRenderTargetTexture && sampleCount > 1 && ! texture.isMultisampleRenderTargetTexture ) {
const msaaTextureDescriptorGPU = Object.assign( {}, textureDescriptorGPU );
msaaTextureDescriptorGPU.label = msaaTextureDescriptorGPU.label + '-msaa'; msaaTextureDescriptorGPU.sampleCount = sampleCount;
textureData.msaaTexture = backend.device.createTexture( msaaTextureDescriptorGPU );
}
textureData.initialized = true;
textureData.textureDescriptorGPU = textureDescriptorGPU;
}
destroyTexture( texture ) {
const backend = this.backend; const textureData = backend.get( texture );
textureData.texture.destroy();
if ( textureData.msaaTexture !== undefined ) textureData.msaaTexture.destroy();
backend.delete( texture );
}
destroySampler( texture ) {
const backend = this.backend; const textureData = backend.get( texture );
delete textureData.sampler;
}
generateMipmaps( texture ) {
const textureData = this.backend.get( texture );
if ( texture.isCubeTexture ) {
for ( let i = 0; i < 6; i ++ ) {
this._generateMipmaps( textureData.texture, textureData.textureDescriptorGPU, i );
}
} else {
const depth = texture.image.depth || 1;
for ( let i = 0; i < depth; i ++ ) {
this._generateMipmaps( textureData.texture, textureData.textureDescriptorGPU, i );
}
}
}
getColorBuffer() {
if ( this.colorBuffer ) this.colorBuffer.destroy();
const backend = this.backend; const { width, height } = backend.getDrawingBufferSize();
this.colorBuffer = backend.device.createTexture( { label: 'colorBuffer', size: { width: width, height: height, depthOrArrayLayers: 1 }, sampleCount: backend.utils.getSampleCount( backend.renderer.samples ), format: backend.utils.getPreferredCanvasFormat(), usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC } );
return this.colorBuffer;
}
getDepthBuffer( depth = true, stencil = false ) {
const backend = this.backend; const { width, height } = backend.getDrawingBufferSize();
const depthTexture = this.depthTexture; const depthTextureGPU = backend.get( depthTexture ).texture;
let format, type;
if ( stencil ) {
format = DepthStencilFormat; type = UnsignedInt248Type;
} else if ( depth ) {
format = DepthFormat; type = UnsignedIntType;
}
if ( depthTextureGPU !== undefined ) {
if ( depthTexture.image.width === width && depthTexture.image.height === height && depthTexture.format === format && depthTexture.type === type ) {
return depthTextureGPU;
}
this.destroyTexture( depthTexture );
}
depthTexture.name = 'depthBuffer'; depthTexture.format = format; depthTexture.type = type; depthTexture.image.width = width; depthTexture.image.height = height;
this.createTexture( depthTexture, { sampleCount: backend.utils.getSampleCount( backend.renderer.samples ), width, height } );
return backend.get( depthTexture ).texture;
}
updateTexture( texture, options ) {
const textureData = this.backend.get( texture );
const { textureDescriptorGPU } = textureData;
if ( texture.isRenderTargetTexture || ( textureDescriptorGPU === undefined /* unsupported texture format */ ) ) return;
// transfer texture data
if ( texture.isDataTexture ) {
this._copyBufferToTexture( options.image, textureData.texture, textureDescriptorGPU, 0, texture.flipY );
} else if ( texture.isDataArrayTexture || texture.isData3DTexture ) {
for ( let i = 0; i < options.image.depth; i ++ ) {
this._copyBufferToTexture( options.image, textureData.texture, textureDescriptorGPU, i, texture.flipY, i );
}
} else if ( texture.isCompressedTexture || texture.isCompressedArrayTexture ) {
this._copyCompressedBufferToTexture( texture.mipmaps, textureData.texture, textureDescriptorGPU );
} else if ( texture.isCubeTexture ) {
this._copyCubeMapToTexture( options.images, textureData.texture, textureDescriptorGPU, texture.flipY );
} else if ( texture.isVideoTexture ) {
const video = texture.source.data;
textureData.externalTexture = video;
} else {
this._copyImageToTexture( options.image, textureData.texture, textureDescriptorGPU, 0, texture.flipY );
}
//
textureData.version = texture.version;
if ( texture.onUpdate ) texture.onUpdate( texture );
}
async copyTextureToBuffer( texture, x, y, width, height, faceIndex ) {
const device = this.backend.device;
const textureData = this.backend.get( texture ); const textureGPU = textureData.texture; const format = textureData.textureDescriptorGPU.format; const bytesPerTexel = this._getBytesPerTexel( format );
let bytesPerRow = width * bytesPerTexel; bytesPerRow = Math.ceil( bytesPerRow / 256 ) * 256; // Align to 256 bytes
const readBuffer = device.createBuffer( { size: width * height * bytesPerTexel, usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ } );
const encoder = device.createCommandEncoder();
encoder.copyTextureToBuffer( { texture: textureGPU, origin: { x, y, z: faceIndex }, }, { buffer: readBuffer, bytesPerRow: bytesPerRow }, { width: width, height: height }
);
const typedArrayType = this._getTypedArrayType( format );
device.queue.submit( [ encoder.finish() ] );
await readBuffer.mapAsync( GPUMapMode.READ );
const buffer = readBuffer.getMappedRange();
return new typedArrayType( buffer );
}
_isEnvironmentTexture( texture ) {
const mapping = texture.mapping;
return ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ) || ( mapping === CubeReflectionMapping || mapping === CubeRefractionMapping );
}
_getDefaultTextureGPU( format ) {
let defaultTexture = this.defaultTexture[ format ];
if ( defaultTexture === undefined ) {
const texture = new Texture(); texture.minFilter = NearestFilter; texture.magFilter = NearestFilter;
this.createTexture( texture, { width: 1, height: 1, format } );
this.defaultTexture[ format ] = defaultTexture = texture;
}
return this.backend.get( defaultTexture ).texture;
}
_getDefaultCubeTextureGPU( format ) {
let defaultCubeTexture = this.defaultTexture[ format ];
if ( defaultCubeTexture === undefined ) {
const texture = new CubeTexture(); texture.minFilter = NearestFilter; texture.magFilter = NearestFilter;
this.createTexture( texture, { width: 1, height: 1, depth: 6 } );
this.defaultCubeTexture[ format ] = defaultCubeTexture = texture;
}
return this.backend.get( defaultCubeTexture ).texture;
}
_getDefaultVideoFrame() {
let defaultVideoFrame = this.defaultVideoFrame;
if ( defaultVideoFrame === null ) {
const init = { timestamp: 0, codedWidth: 1, codedHeight: 1, format: 'RGBA', };
this.defaultVideoFrame = defaultVideoFrame = new VideoFrame( new Uint8Array( [ 0, 0, 0, 0xff ] ), init );
}
return defaultVideoFrame;
}
_copyCubeMapToTexture( images, textureGPU, textureDescriptorGPU, flipY ) {
for ( let i = 0; i < 6; i ++ ) {
const image = images[ i ];
const flipIndex = flipY === true ? _flipMap[ i ] : i;
if ( image.isDataTexture ) {
this._copyBufferToTexture( image.image, textureGPU, textureDescriptorGPU, flipIndex, flipY );
} else {
this._copyImageToTexture( image, textureGPU, textureDescriptorGPU, flipIndex, flipY );
}
}
}
_copyImageToTexture( image, textureGPU, textureDescriptorGPU, originDepth, flipY ) {
const device = this.backend.device;
device.queue.copyExternalImageToTexture( { source: image }, { texture: textureGPU, mipLevel: 0, origin: { x: 0, y: 0, z: originDepth } }, { width: image.width, height: image.height, depthOrArrayLayers: 1 } );
if ( flipY === true ) {
this._flipY( textureGPU, textureDescriptorGPU, originDepth );
}
}
_getPassUtils() {
let passUtils = this._passUtils;
if ( passUtils === null ) {
this._passUtils = passUtils = new WebGPUTexturePassUtils( this.backend.device );
}
return passUtils;
}
_generateMipmaps( textureGPU, textureDescriptorGPU, baseArrayLayer = 0 ) {
this._getPassUtils().generateMipmaps( textureGPU, textureDescriptorGPU, baseArrayLayer );
}
_flipY( textureGPU, textureDescriptorGPU, originDepth = 0 ) {
this._getPassUtils().flipY( textureGPU, textureDescriptorGPU, originDepth );
}
_copyBufferToTexture( image, textureGPU, textureDescriptorGPU, originDepth, flipY, depth = 0 ) {
// @TODO: Consider to use GPUCommandEncoder.copyBufferToTexture() // @TODO: Consider to support valid buffer layouts with other formats like RGB
const device = this.backend.device;
const data = image.data;
const bytesPerTexel = this._getBytesPerTexel( textureDescriptorGPU.format ); const bytesPerRow = image.width * bytesPerTexel;
device.queue.writeTexture( { texture: textureGPU, mipLevel: 0, origin: { x: 0, y: 0, z: originDepth } }, data, { offset: image.width * image.height * bytesPerTexel * depth, bytesPerRow }, { width: image.width, height: image.height, depthOrArrayLayers: 1 } );
if ( flipY === true ) {
this._flipY( textureGPU, textureDescriptorGPU, originDepth );
}
}
_copyCompressedBufferToTexture( mipmaps, textureGPU, textureDescriptorGPU ) {
// @TODO: Consider to use GPUCommandEncoder.copyBufferToTexture()
const device = this.backend.device;
const blockData = this._getBlockData( textureDescriptorGPU.format ); const isTextureArray = textureDescriptorGPU.size.depthOrArrayLayers > 1;
for ( let i = 0; i < mipmaps.length; i ++ ) {
const mipmap = mipmaps[ i ];
const width = mipmap.width; const height = mipmap.height; const depth = isTextureArray ? textureDescriptorGPU.size.depthOrArrayLayers : 1;
const bytesPerRow = Math.ceil( width / blockData.width ) * blockData.byteLength; const bytesPerImage = bytesPerRow * Math.ceil( height / blockData.height );
for ( let j = 0; j < depth; j ++ ) {
device.queue.writeTexture( { texture: textureGPU, mipLevel: i, origin: { x: 0, y: 0, z: j } }, mipmap.data, { offset: j * bytesPerImage, bytesPerRow, rowsPerImage: Math.ceil( height / blockData.height ) }, { width: Math.ceil( width / blockData.width ) * blockData.width, height: Math.ceil( height / blockData.height ) * blockData.height, depthOrArrayLayers: 1 } );
}
}
}
_getBlockData( format ) {
// this method is only relevant for compressed texture formats
if ( format === GPUTextureFormat.BC1RGBAUnorm || format === GPUTextureFormat.BC1RGBAUnormSRGB ) return { byteLength: 8, width: 4, height: 4 }; // DXT1 if ( format === GPUTextureFormat.BC2RGBAUnorm || format === GPUTextureFormat.BC2RGBAUnormSRGB ) return { byteLength: 16, width: 4, height: 4 }; // DXT3 if ( format === GPUTextureFormat.BC3RGBAUnorm || format === GPUTextureFormat.BC3RGBAUnormSRGB ) return { byteLength: 16, width: 4, height: 4 }; // DXT5 if ( format === GPUTextureFormat.BC4RUnorm || format === GPUTextureFormat.BC4RSNorm ) return { byteLength: 8, width: 4, height: 4 }; // RGTC1 if ( format === GPUTextureFormat.BC5RGUnorm || format === GPUTextureFormat.BC5RGSnorm ) return { byteLength: 16, width: 4, height: 4 }; // RGTC2 if ( format === GPUTextureFormat.BC6HRGBUFloat || format === GPUTextureFormat.BC6HRGBFloat ) return { byteLength: 16, width: 4, height: 4 }; // BPTC (float) if ( format === GPUTextureFormat.BC7RGBAUnorm || format === GPUTextureFormat.BC7RGBAUnormSRGB ) return { byteLength: 16, width: 4, height: 4 }; // BPTC (unorm)
if ( format === GPUTextureFormat.ETC2RGB8Unorm || format === GPUTextureFormat.ETC2RGB8UnormSRGB ) return { byteLength: 8, width: 4, height: 4 }; if ( format === GPUTextureFormat.ETC2RGB8A1Unorm || format === GPUTextureFormat.ETC2RGB8A1UnormSRGB ) return { byteLength: 8, width: 4, height: 4 }; if ( format === GPUTextureFormat.ETC2RGBA8Unorm || format === GPUTextureFormat.ETC2RGBA8UnormSRGB ) return { byteLength: 16, width: 4, height: 4 }; if ( format === GPUTextureFormat.EACR11Unorm ) return { byteLength: 8, width: 4, height: 4 }; if ( format === GPUTextureFormat.EACR11Snorm ) return { byteLength: 8, width: 4, height: 4 }; if ( format === GPUTextureFormat.EACRG11Unorm ) return { byteLength: 16, width: 4, height: 4 }; if ( format === GPUTextureFormat.EACRG11Snorm ) return { byteLength: 16, width: 4, height: 4 };
if ( format === GPUTextureFormat.ASTC4x4Unorm || format === GPUTextureFormat.ASTC4x4UnormSRGB ) return { byteLength: 16, width: 4, height: 4 }; if ( format === GPUTextureFormat.ASTC5x4Unorm || format === GPUTextureFormat.ASTC5x4UnormSRGB ) return { byteLength: 16, width: 5, height: 4 }; if ( format === GPUTextureFormat.ASTC5x5Unorm || format === GPUTextureFormat.ASTC5x5UnormSRGB ) return { byteLength: 16, width: 5, height: 5 }; if ( format === GPUTextureFormat.ASTC6x5Unorm || format === GPUTextureFormat.ASTC6x5UnormSRGB ) return { byteLength: 16, width: 6, height: 5 }; if ( format === GPUTextureFormat.ASTC6x6Unorm || format === GPUTextureFormat.ASTC6x6UnormSRGB ) return { byteLength: 16, width: 6, height: 6 }; if ( format === GPUTextureFormat.ASTC8x5Unorm || format === GPUTextureFormat.ASTC8x5UnormSRGB ) return { byteLength: 16, width: 8, height: 5 }; if ( format === GPUTextureFormat.ASTC8x6Unorm || format === GPUTextureFormat.ASTC8x6UnormSRGB ) return { byteLength: 16, width: 8, height: 6 }; if ( format === GPUTextureFormat.ASTC8x8Unorm || format === GPUTextureFormat.ASTC8x8UnormSRGB ) return { byteLength: 16, width: 8, height: 8 }; if ( format === GPUTextureFormat.ASTC10x5Unorm || format === GPUTextureFormat.ASTC10x5UnormSRGB ) return { byteLength: 16, width: 10, height: 5 }; if ( format === GPUTextureFormat.ASTC10x6Unorm || format === GPUTextureFormat.ASTC10x6UnormSRGB ) return { byteLength: 16, width: 10, height: 6 }; if ( format === GPUTextureFormat.ASTC10x8Unorm || format === GPUTextureFormat.ASTC10x8UnormSRGB ) return { byteLength: 16, width: 10, height: 8 }; if ( format === GPUTextureFormat.ASTC10x10Unorm || format === GPUTextureFormat.ASTC10x10UnormSRGB ) return { byteLength: 16, width: 10, height: 10 }; if ( format === GPUTextureFormat.ASTC12x10Unorm || format === GPUTextureFormat.ASTC12x10UnormSRGB ) return { byteLength: 16, width: 12, height: 10 }; if ( format === GPUTextureFormat.ASTC12x12Unorm || format === GPUTextureFormat.ASTC12x12UnormSRGB ) return { byteLength: 16, width: 12, height: 12 };
}
_convertAddressMode( value ) {
let addressMode = GPUAddressMode.ClampToEdge;
if ( value === RepeatWrapping ) {
addressMode = GPUAddressMode.Repeat;
} else if ( value === MirroredRepeatWrapping ) {
addressMode = GPUAddressMode.MirrorRepeat;
}
return addressMode;
}
_convertFilterMode( value ) {
let filterMode = GPUFilterMode.Linear;
if ( value === NearestFilter || value === NearestMipmapNearestFilter || value === NearestMipmapLinearFilter ) {
filterMode = GPUFilterMode.Nearest;
}
return filterMode;
}
_getBytesPerTexel( format ) {
// 8-bit formats if ( format === GPUTextureFormat.R8Unorm || format === GPUTextureFormat.R8Snorm || format === GPUTextureFormat.R8Uint || format === GPUTextureFormat.R8Sint ) return 1;
// 16-bit formats if ( format === GPUTextureFormat.R16Uint || format === GPUTextureFormat.R16Sint || format === GPUTextureFormat.R16Float || format === GPUTextureFormat.RG8Unorm || format === GPUTextureFormat.RG8Snorm || format === GPUTextureFormat.RG8Uint || format === GPUTextureFormat.RG8Sint ) return 2;
// 32-bit formats if ( format === GPUTextureFormat.R32Uint || format === GPUTextureFormat.R32Sint || format === GPUTextureFormat.R32Float || format === GPUTextureFormat.RG16Uint || format === GPUTextureFormat.RG16Sint || format === GPUTextureFormat.RG16Float || format === GPUTextureFormat.RGBA8Unorm || format === GPUTextureFormat.RGBA8UnormSRGB || format === GPUTextureFormat.RGBA8Snorm || format === GPUTextureFormat.RGBA8Uint || format === GPUTextureFormat.RGBA8Sint || format === GPUTextureFormat.BGRA8Unorm || format === GPUTextureFormat.BGRA8UnormSRGB || // Packed 32-bit formats format === GPUTextureFormat.RGB9E5UFloat || format === GPUTextureFormat.RGB10A2Unorm || format === GPUTextureFormat.RG11B10UFloat || format === GPUTextureFormat.Depth32Float || format === GPUTextureFormat.Depth24Plus || format === GPUTextureFormat.Depth24PlusStencil8 || format === GPUTextureFormat.Depth32FloatStencil8 ) return 4;
// 64-bit formats if ( format === GPUTextureFormat.RG32Uint || format === GPUTextureFormat.RG32Sint || format === GPUTextureFormat.RG32Float || format === GPUTextureFormat.RGBA16Uint || format === GPUTextureFormat.RGBA16Sint || format === GPUTextureFormat.RGBA16Float ) return 8;
// 128-bit formats if ( format === GPUTextureFormat.RGBA32Uint || format === GPUTextureFormat.RGBA32Sint || format === GPUTextureFormat.RGBA32Float ) return 16;
}
_getTypedArrayType( format ) {
if ( format === GPUTextureFormat.R8Uint ) return Uint8Array; if ( format === GPUTextureFormat.R8Sint ) return Int8Array; if ( format === GPUTextureFormat.R8Unorm ) return Uint8Array; if ( format === GPUTextureFormat.R8Snorm ) return Int8Array; if ( format === GPUTextureFormat.RG8Uint ) return Uint8Array; if ( format === GPUTextureFormat.RG8Sint ) return Int8Array; if ( format === GPUTextureFormat.RG8Unorm ) return Uint8Array; if ( format === GPUTextureFormat.RG8Snorm ) return Int8Array; if ( format === GPUTextureFormat.RGBA8Uint ) return Uint8Array; if ( format === GPUTextureFormat.RGBA8Sint ) return Int8Array; if ( format === GPUTextureFormat.RGBA8Unorm ) return Uint8Array; if ( format === GPUTextureFormat.RGBA8Snorm ) return Int8Array;
if ( format === GPUTextureFormat.R16Uint ) return Uint16Array; if ( format === GPUTextureFormat.R16Sint ) return Int16Array; if ( format === GPUTextureFormat.RG16Uint ) return Uint16Array; if ( format === GPUTextureFormat.RG16Sint ) return Int16Array; if ( format === GPUTextureFormat.RGBA16Uint ) return Uint16Array; if ( format === GPUTextureFormat.RGBA16Sint ) return Int16Array; if ( format === GPUTextureFormat.R16Float ) return Uint16Array; if ( format === GPUTextureFormat.RG16Float ) return Uint16Array; if ( format === GPUTextureFormat.RGBA16Float ) return Uint16Array;
if ( format === GPUTextureFormat.R32Uint ) return Uint32Array; if ( format === GPUTextureFormat.R32Sint ) return Int32Array; if ( format === GPUTextureFormat.R32Float ) return Float32Array; if ( format === GPUTextureFormat.RG32Uint ) return Uint32Array; if ( format === GPUTextureFormat.RG32Sint ) return Int32Array; if ( format === GPUTextureFormat.RG32Float ) return Float32Array; if ( format === GPUTextureFormat.RGBA32Uint ) return Uint32Array; if ( format === GPUTextureFormat.RGBA32Sint ) return Int32Array; if ( format === GPUTextureFormat.RGBA32Float ) return Float32Array;
if ( format === GPUTextureFormat.BGRA8Unorm ) return Uint8Array; if ( format === GPUTextureFormat.BGRA8UnormSRGB ) return Uint8Array; if ( format === GPUTextureFormat.RGB10A2Unorm ) return Uint32Array; if ( format === GPUTextureFormat.RGB9E5UFloat ) return Uint32Array; if ( format === GPUTextureFormat.RG11B10UFloat ) return Uint32Array;
if ( format === GPUTextureFormat.Depth32Float ) return Float32Array; if ( format === GPUTextureFormat.Depth24Plus ) return Uint32Array; if ( format === GPUTextureFormat.Depth24PlusStencil8 ) return Uint32Array; if ( format === GPUTextureFormat.Depth32FloatStencil8 ) return Float32Array;
}
_getDimension( texture ) {
let dimension;
if ( texture.isData3DTexture ) {
dimension = GPUTextureDimension.ThreeD;
} else {
dimension = GPUTextureDimension.TwoD;
}
return dimension;
}
}
export function getFormat( texture, device = null ) {
const format = texture.format; const type = texture.type; const colorSpace = texture.colorSpace;
let formatGPU;
if ( texture.isCompressedTexture === true || texture.isCompressedArrayTexture === true ) {
switch ( format ) {
case RGBA_S3TC_DXT1_Format: formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.BC1RGBAUnormSRGB : GPUTextureFormat.BC1RGBAUnorm; break;
case RGBA_S3TC_DXT3_Format: formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.BC2RGBAUnormSRGB : GPUTextureFormat.BC2RGBAUnorm; break;
case RGBA_S3TC_DXT5_Format: formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.BC3RGBAUnormSRGB : GPUTextureFormat.BC3RGBAUnorm; break;
case RGB_ETC2_Format: formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ETC2RGB8UnormSRGB : GPUTextureFormat.ETC2RGB8Unorm; break;
case RGBA_ETC2_EAC_Format: formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ETC2RGBA8UnormSRGB : GPUTextureFormat.ETC2RGBA8Unorm; break;
case RGBA_ASTC_4x4_Format: formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC4x4UnormSRGB : GPUTextureFormat.ASTC4x4Unorm; break;
case RGBA_ASTC_5x4_Format: formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC5x4UnormSRGB : GPUTextureFormat.ASTC5x4Unorm; break;
case RGBA_ASTC_5x5_Format: formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC5x5UnormSRGB : GPUTextureFormat.ASTC5x5Unorm; break;
case RGBA_ASTC_6x5_Format: formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC6x5UnormSRGB : GPUTextureFormat.ASTC6x5Unorm; break;
case RGBA_ASTC_6x6_Format: formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC6x6UnormSRGB : GPUTextureFormat.ASTC6x6Unorm; break;
case RGBA_ASTC_8x5_Format: formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC8x5UnormSRGB : GPUTextureFormat.ASTC8x5Unorm; break;
case RGBA_ASTC_8x6_Format: formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC8x6UnormSRGB : GPUTextureFormat.ASTC8x6Unorm; break;
case RGBA_ASTC_8x8_Format: formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC8x8UnormSRGB : GPUTextureFormat.ASTC8x8Unorm; break;
case RGBA_ASTC_10x5_Format: formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC10x5UnormSRGB : GPUTextureFormat.ASTC10x5Unorm; break;
case RGBA_ASTC_10x6_Format: formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC10x6UnormSRGB : GPUTextureFormat.ASTC10x6Unorm; break;
case RGBA_ASTC_10x8_Format: formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC10x8UnormSRGB : GPUTextureFormat.ASTC10x8Unorm; break;
case RGBA_ASTC_10x10_Format: formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC10x10UnormSRGB : GPUTextureFormat.ASTC10x10Unorm; break;
case RGBA_ASTC_12x10_Format: formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC12x10UnormSRGB : GPUTextureFormat.ASTC12x10Unorm; break;
case RGBA_ASTC_12x12_Format: formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.ASTC12x12UnormSRGB : GPUTextureFormat.ASTC12x12Unorm; break;
default: console.error( 'WebGPURenderer: Unsupported texture format.', format );
}
} else {
switch ( format ) {
case RGBAFormat:
switch ( type ) {
case ByteType: formatGPU = GPUTextureFormat.RGBA8Snorm; break;
case ShortType: formatGPU = GPUTextureFormat.RGBA16Sint; break;
case UnsignedShortType: formatGPU = GPUTextureFormat.RGBA16Uint; break; case UnsignedIntType: formatGPU = GPUTextureFormat.RGBA32Uint; break;
case IntType: formatGPU = GPUTextureFormat.RGBA32Sint; break;
case UnsignedByteType: formatGPU = ( colorSpace === SRGBColorSpace ) ? GPUTextureFormat.RGBA8UnormSRGB : GPUTextureFormat.RGBA8Unorm; break;
case HalfFloatType: formatGPU = GPUTextureFormat.RGBA16Float; break;
case FloatType: formatGPU = GPUTextureFormat.RGBA32Float; break;
default: console.error( 'WebGPURenderer: Unsupported texture type with RGBAFormat.', type );
}
break;
case RGBFormat:
switch ( type ) {
case UnsignedInt5999Type: formatGPU = GPUTextureFormat.RGB9E5UFloat; break;
default: console.error( 'WebGPURenderer: Unsupported texture type with RGBFormat.', type );
}
break;
case RedFormat:
switch ( type ) {
case ByteType: formatGPU = GPUTextureFormat.R8Snorm; break;
case ShortType: formatGPU = GPUTextureFormat.R16Sint; break;
case UnsignedShortType: formatGPU = GPUTextureFormat.R16Uint; break;
case UnsignedIntType: formatGPU = GPUTextureFormat.R32Uint; break;
case IntType: formatGPU = GPUTextureFormat.R32Sint; break;
case UnsignedByteType: formatGPU = GPUTextureFormat.R8Unorm; break;
case HalfFloatType: formatGPU = GPUTextureFormat.R16Float; break;
case FloatType: formatGPU = GPUTextureFormat.R32Float; break;
default: console.error( 'WebGPURenderer: Unsupported texture type with RedFormat.', type );
}
break;
case RGFormat:
switch ( type ) {
case ByteType: formatGPU = GPUTextureFormat.RG8Snorm; break;
case ShortType: formatGPU = GPUTextureFormat.RG16Sint; break;
case UnsignedShortType: formatGPU = GPUTextureFormat.RG16Uint; break;
case UnsignedIntType: formatGPU = GPUTextureFormat.RG32Uint; break;
case IntType: formatGPU = GPUTextureFormat.RG32Sint; break;
case UnsignedByteType: formatGPU = GPUTextureFormat.RG8Unorm; break;
case HalfFloatType: formatGPU = GPUTextureFormat.RG16Float; break;
case FloatType: formatGPU = GPUTextureFormat.RG32Float; break;
default: console.error( 'WebGPURenderer: Unsupported texture type with RGFormat.', type );
}
break;
case DepthFormat:
switch ( type ) {
case UnsignedShortType: formatGPU = GPUTextureFormat.Depth16Unorm; break;
case UnsignedIntType: formatGPU = GPUTextureFormat.Depth24Plus; break;
case FloatType: formatGPU = GPUTextureFormat.Depth32Float; break;
default: console.error( 'WebGPURenderer: Unsupported texture type with DepthFormat.', type );
}
break;
case DepthStencilFormat:
switch ( type ) {
case UnsignedInt248Type: formatGPU = GPUTextureFormat.Depth24PlusStencil8; break;
case FloatType:
if ( device && device.features.has( GPUFeatureName.Depth32FloatStencil8 ) === false ) {
console.error( 'WebGPURenderer: Depth textures with DepthStencilFormat + FloatType can only be used with the "depth32float-stencil8" GPU feature.' );
}
formatGPU = GPUTextureFormat.Depth32FloatStencil8;
break;
default: console.error( 'WebGPURenderer: Unsupported texture type with DepthStencilFormat.', type );
}
break;
case RedIntegerFormat:
switch ( type ) {
case IntType: formatGPU = GPUTextureFormat.R32Sint; break;
case UnsignedIntType: formatGPU = GPUTextureFormat.R32Uint; break;
default: console.error( 'WebGPURenderer: Unsupported texture type with RedIntegerFormat.', type );
}
break;
case RGIntegerFormat:
switch ( type ) {
case IntType: formatGPU = GPUTextureFormat.RG32Sint; break;
case UnsignedIntType: formatGPU = GPUTextureFormat.RG32Uint; break;
default: console.error( 'WebGPURenderer: Unsupported texture type with RGIntegerFormat.', type );
}
break;
case RGBAIntegerFormat:
switch ( type ) {
case IntType: formatGPU = GPUTextureFormat.RGBA32Sint; break;
case UnsignedIntType: formatGPU = GPUTextureFormat.RGBA32Uint; break;
default: console.error( 'WebGPURenderer: Unsupported texture type with RGBAIntegerFormat.', type );
}
break;
default: console.error( 'WebGPURenderer: Unsupported texture format.', format );
}
}
return formatGPU;
}
export default WebGPUTextureUtils;