|
@@ -1,476 +1,375 @@
|
|
-import { GPUTextureFormat, GPUAddressMode, GPUFilterMode, GPUTextureDimension, GPUFeatureName } from './constants.js';
|
|
|
|
-import { VideoTexture, CubeTexture, Texture, NearestFilter, NearestMipmapNearestFilter, NearestMipmapLinearFilter, LinearFilter, RepeatWrapping, MirroredRepeatWrapping, RGB_ETC2_Format, RGBA_ETC2_EAC_Format,
|
|
|
|
- RGBAFormat, RedFormat, RGFormat, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, UnsignedByteType, FloatType, HalfFloatType, SRGBColorSpace, DepthFormat, DepthStencilFormat, DepthTexture,
|
|
|
|
|
|
+import {
|
|
|
|
+ GPUTextureFormat, GPUAddressMode, GPUFilterMode, GPUTextureDimension, GPUFeatureName
|
|
|
|
+} from './WebGPUConstants.js';
|
|
|
|
+
|
|
|
|
+import {
|
|
|
|
+ CubeTexture, Texture,
|
|
|
|
+ NearestFilter, NearestMipmapNearestFilter, NearestMipmapLinearFilter, LinearFilter,
|
|
|
|
+ RepeatWrapping, MirroredRepeatWrapping,
|
|
|
|
+ RGB_ETC2_Format, RGBA_ETC2_EAC_Format,
|
|
|
|
+ RGBAFormat, 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_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
|
|
|
|
|
|
+ RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_10x10_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, UnsignedIntType, UnsignedShortType, UnsignedInt248Type,
|
|
|
|
+ NeverCompare, AlwaysCompare, LessCompare, LessEqualCompare, EqualCompare, GreaterEqualCompare, GreaterCompare, NotEqualCompare
|
|
} from 'three';
|
|
} from 'three';
|
|
-import WebGPUTextureUtils from './WebGPUTextureUtils.js';
|
|
|
|
|
|
|
|
-class WebGPUTextures {
|
|
|
|
|
|
+import WebGPUTextureMipmapUtils from './WebGPUTextureMipmapUtils.js';
|
|
|
|
|
|
- constructor( device, properties, info ) {
|
|
|
|
|
|
+const _compareToWebGPU = {
|
|
|
|
+ [ NeverCompare ]: 'never',
|
|
|
|
+ [ AlwaysCompare ]: 'less',
|
|
|
|
+ [ LessCompare ]: 'equal',
|
|
|
|
+ [ LessEqualCompare ]: 'less-equal',
|
|
|
|
+ [ EqualCompare ]: 'greater',
|
|
|
|
+ [ GreaterEqualCompare ]: 'not-equal',
|
|
|
|
+ [ GreaterCompare ]: 'greater-equal',
|
|
|
|
+ [ NotEqualCompare ]: 'always'
|
|
|
|
+};
|
|
|
|
|
|
- this.device = device;
|
|
|
|
- this.properties = properties;
|
|
|
|
- this.info = info;
|
|
|
|
|
|
+class WebGPUTextureUtils {
|
|
|
|
+
|
|
|
|
+ constructor( backend ) {
|
|
|
|
+
|
|
|
|
+ this.backend = backend;
|
|
|
|
+
|
|
|
|
+ this.mipmapUtils = null;
|
|
|
|
|
|
this.defaultTexture = null;
|
|
this.defaultTexture = null;
|
|
- this.depthDefaultTexture = null;
|
|
|
|
- this.defaultVideoTexture = null;
|
|
|
|
this.defaultCubeTexture = null;
|
|
this.defaultCubeTexture = null;
|
|
- this.defaultSampler = null;
|
|
|
|
-
|
|
|
|
- this.samplerCache = new Map();
|
|
|
|
- this.utils = null;
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- getDefaultSampler() {
|
|
|
|
|
|
+ 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: texture.anisotropy
|
|
|
|
+ };
|
|
|
|
|
|
- if ( this.defaultSampler === null ) {
|
|
|
|
|
|
+ if ( texture.isDepthTexture && texture.compareFunction !== null ) {
|
|
|
|
|
|
- this.defaultSampler = this.device.createSampler( {} );
|
|
|
|
|
|
+ samplerDescriptorGPU.compare = _compareToWebGPU[ texture.compareFunction ];
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- return this.defaultSampler;
|
|
|
|
|
|
+ textureGPU.sampler = device.createSampler( samplerDescriptorGPU );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- getDefaultDepthTexture() {
|
|
|
|
|
|
+ createDefaultTexture( texture ) {
|
|
|
|
|
|
- if ( this.depthDefaultTexture === null ) {
|
|
|
|
|
|
+ let textureGPU;
|
|
|
|
|
|
- const depthTexture = new DepthTexture();
|
|
|
|
- depthTexture.image.width = 1;
|
|
|
|
- depthTexture.image.height = 1;
|
|
|
|
|
|
+ if ( texture.isCubeTexture ) {
|
|
|
|
+
|
|
|
|
+ textureGPU = this._getDefaultCubeTextureGPU();
|
|
|
|
|
|
- this._uploadTexture( depthTexture );
|
|
|
|
|
|
+ } else {
|
|
|
|
|
|
- this.depthDefaultTexture = this.getTextureGPU( depthTexture );
|
|
|
|
|
|
+ textureGPU = this._getDefaultTextureGPU();
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- return this.depthDefaultTexture;
|
|
|
|
|
|
+ this.backend.get( texture ).texture = textureGPU;
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- getDefaultTexture() {
|
|
|
|
-
|
|
|
|
- if ( this.defaultTexture === null ) {
|
|
|
|
|
|
+ createTexture( texture ) {
|
|
|
|
|
|
- const texture = new Texture();
|
|
|
|
- texture.minFilter = NearestFilter;
|
|
|
|
- texture.magFilter = NearestFilter;
|
|
|
|
|
|
+ const backend = this.backend;
|
|
|
|
+ const textureData = backend.get( texture );
|
|
|
|
|
|
- this._uploadTexture( texture );
|
|
|
|
|
|
+ if ( textureData.initialized ) {
|
|
|
|
|
|
- this.defaultTexture = this.getTextureGPU( texture );
|
|
|
|
|
|
+ throw new Error( 'WebGPUTextureUtils: Texture already initialized.' );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- return this.defaultTexture;
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
|
|
+ const { width, height, depth } = this._getSize( texture );
|
|
|
|
|
|
- getDefaultVideoTexture() {
|
|
|
|
|
|
+ const needsMipmaps = this._needsMipmaps( texture );
|
|
|
|
+ const dimension = this._getDimension( texture );
|
|
|
|
+ const mipLevelCount = this._getMipLevelCount( texture, width, height, needsMipmaps );
|
|
|
|
+ const format = texture.internalFormat || this._getFormat( texture );
|
|
|
|
+ //const sampleCount = texture.isRenderTargetTexture || texture.isDepthTexture ? backend.utils.getSampleCount() : 1;
|
|
|
|
+ const sampleCount = 1;
|
|
|
|
|
|
- if ( this.defaultVideoTexture === null ) {
|
|
|
|
|
|
+ let usage = GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST;
|
|
|
|
|
|
- const video = document.getElementById( 'video' );
|
|
|
|
|
|
+ if ( texture.isCompressedTexture !== true ) {
|
|
|
|
|
|
- const texture = new VideoTexture( video );
|
|
|
|
- texture.minFilter = NearestFilter;
|
|
|
|
- texture.magFilter = NearestFilter;
|
|
|
|
|
|
+ usage |= GPUTextureUsage.RENDER_ATTACHMENT;
|
|
|
|
|
|
- this._uploadVideoTexture( texture );
|
|
|
|
|
|
+ }
|
|
|
|
|
|
- this.defaultVideoTexture = this.getTextureGPU( texture );
|
|
|
|
|
|
+ const textureDescriptorGPU = {
|
|
|
|
+ label: texture.name,
|
|
|
|
+ size: {
|
|
|
|
+ width: width,
|
|
|
|
+ height: height,
|
|
|
|
+ depthOrArrayLayers: depth,
|
|
|
|
+ },
|
|
|
|
+ mipLevelCount: mipLevelCount,
|
|
|
|
+ sampleCount: sampleCount,
|
|
|
|
+ dimension: dimension,
|
|
|
|
+ format: format,
|
|
|
|
+ usage: usage
|
|
|
|
+ };
|
|
|
|
|
|
- }
|
|
|
|
|
|
+ // texture creation
|
|
|
|
|
|
- return this.defaultVideoTexture;
|
|
|
|
|
|
+ if ( texture.isVideoTexture ) {
|
|
|
|
|
|
- }
|
|
|
|
|
|
+ const video = texture.source.data;
|
|
|
|
+ const videoFrame = new VideoFrame( video );
|
|
|
|
|
|
- getDefaultCubeTexture() {
|
|
|
|
|
|
+ textureDescriptorGPU.size.width = videoFrame.displayWidth;
|
|
|
|
+ textureDescriptorGPU.size.height = videoFrame.displayHeight;
|
|
|
|
|
|
- if ( this.defaultCubeTexture === null ) {
|
|
|
|
|
|
+ videoFrame.close();
|
|
|
|
|
|
- const texture = new CubeTexture();
|
|
|
|
- texture.minFilter = NearestFilter;
|
|
|
|
- texture.magFilter = NearestFilter;
|
|
|
|
|
|
+ textureData.externalTexture = video;
|
|
|
|
|
|
- this._uploadTexture( texture );
|
|
|
|
|
|
+ } else {
|
|
|
|
|
|
- this.defaultCubeTexture = this.getTextureGPU( texture );
|
|
|
|
|
|
+ textureData.texture = backend.device.createTexture( textureDescriptorGPU );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- return this.defaultCubeTexture;
|
|
|
|
|
|
+ textureData.initialized = true;
|
|
|
|
+
|
|
|
|
+ textureData.needsMipmaps = needsMipmaps;
|
|
|
|
+ textureData.textureDescriptorGPU = textureDescriptorGPU;
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- getTextureGPU( texture ) {
|
|
|
|
|
|
+ destroyTexture( texture ) {
|
|
|
|
+
|
|
|
|
+ const backend = this.backend;
|
|
|
|
+ const textureData = backend.get( texture );
|
|
|
|
|
|
- const textureProperties = this.properties.get( texture );
|
|
|
|
|
|
+ textureData.texture.destroy();
|
|
|
|
|
|
- return textureProperties.textureGPU;
|
|
|
|
|
|
+ backend.delete( texture );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- getSampler( texture ) {
|
|
|
|
|
|
+ destroySampler( texture ) {
|
|
|
|
|
|
- const textureProperties = this.properties.get( texture );
|
|
|
|
|
|
+ const backend = this.backend;
|
|
|
|
+ const textureData = backend.get( texture );
|
|
|
|
|
|
- return textureProperties.samplerGPU;
|
|
|
|
|
|
+ delete textureData.sampler;
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
updateTexture( texture ) {
|
|
updateTexture( texture ) {
|
|
|
|
|
|
- let needsUpdate = false;
|
|
|
|
-
|
|
|
|
- const textureProperties = this.properties.get( texture );
|
|
|
|
-
|
|
|
|
- if ( texture.version > 0 && textureProperties.version !== texture.version ) {
|
|
|
|
|
|
+ const textureData = this.backend.get( texture );
|
|
|
|
|
|
- const image = texture.image;
|
|
|
|
|
|
+ const { needsMipmaps, textureDescriptorGPU } = textureData;
|
|
|
|
|
|
- if ( image === undefined ) {
|
|
|
|
-
|
|
|
|
- console.warn( 'THREE.WebGPURenderer: Texture marked for update but image is undefined.' );
|
|
|
|
|
|
+ // transfer texture data
|
|
|
|
|
|
- } else if ( image.complete === false ) {
|
|
|
|
|
|
+ if ( texture.isDataTexture || texture.isDataArrayTexture || texture.isData3DTexture ) {
|
|
|
|
|
|
- console.warn( 'THREE.WebGPURenderer: Texture marked for update but image is incomplete.' );
|
|
|
|
|
|
+ this._copyBufferToTexture( texture.image, textureData.texture, textureDescriptorGPU, needsMipmaps );
|
|
|
|
|
|
- } else {
|
|
|
|
|
|
+ } else if ( texture.isCompressedTexture ) {
|
|
|
|
|
|
- // texture init
|
|
|
|
|
|
+ this._copyCompressedBufferToTexture( texture.mipmaps, textureData.texture, textureDescriptorGPU );
|
|
|
|
|
|
- if ( textureProperties.initialized === undefined ) {
|
|
|
|
|
|
+ } else if ( texture.isCubeTexture ) {
|
|
|
|
|
|
- textureProperties.initialized = true;
|
|
|
|
|
|
+ if ( texture.image.length === 6 ) {
|
|
|
|
|
|
- const disposeCallback = onTextureDispose.bind( this );
|
|
|
|
- textureProperties.disposeCallback = disposeCallback;
|
|
|
|
|
|
+ this._copyCubeMapToTexture( texture.image, texture, textureData.texture, textureDescriptorGPU, needsMipmaps );
|
|
|
|
|
|
- texture.addEventListener( 'dispose', disposeCallback );
|
|
|
|
|
|
+ }
|
|
|
|
|
|
- this.info.memory.textures ++;
|
|
|
|
|
|
+ } else if ( texture.isRenderTargetTexture ) {
|
|
|
|
|
|
- }
|
|
|
|
|
|
+ if ( needsMipmaps === true ) this._generateMipmaps( textureData.texture, textureDescriptorGPU );
|
|
|
|
|
|
- //
|
|
|
|
|
|
+ } else if ( texture.isVideoTexture ) {
|
|
|
|
|
|
- if ( texture.isVideoTexture ) {
|
|
|
|
|
|
+ const video = texture.source.data;
|
|
|
|
|
|
- needsUpdate = this._uploadVideoTexture( texture );
|
|
|
|
|
|
+ textureData.externalTexture = video;
|
|
|
|
|
|
- } else {
|
|
|
|
|
|
+ } else if ( texture.image !== null ) {
|
|
|
|
|
|
- needsUpdate = this._uploadTexture( texture );
|
|
|
|
|
|
+ this._copyImageToTexture( texture.image, texture, textureData.texture, textureDescriptorGPU, needsMipmaps );
|
|
|
|
|
|
- }
|
|
|
|
|
|
+ } else {
|
|
|
|
|
|
- }
|
|
|
|
|
|
+ console.warn( 'WebGPUTextureUtils: Unable to update texture.' );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- // if the texture is used for RTT, it's necessary to init it once so the binding
|
|
|
|
- // group's resource definition points to the respective GPUTexture
|
|
|
|
-
|
|
|
|
- if ( textureProperties.initializedRTT === false ) {
|
|
|
|
-
|
|
|
|
- textureProperties.initializedRTT = true;
|
|
|
|
- needsUpdate = true;
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
|
|
+ //
|
|
|
|
|
|
- return needsUpdate;
|
|
|
|
|
|
+ textureData.version = texture.version;
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- updateSampler( texture ) {
|
|
|
|
-
|
|
|
|
- const array = [];
|
|
|
|
|
|
+ _getDefaultTextureGPU() {
|
|
|
|
|
|
- array.push( texture.wrapS );
|
|
|
|
- array.push( texture.wrapT );
|
|
|
|
- array.push( texture.wrapR );
|
|
|
|
- array.push( texture.magFilter );
|
|
|
|
- array.push( texture.minFilter );
|
|
|
|
- array.push( texture.anisotropy );
|
|
|
|
|
|
+ let defaultTexture = this.defaultTexture;
|
|
|
|
|
|
- const key = array.join();
|
|
|
|
- let samplerGPU = this.samplerCache.get( key );
|
|
|
|
|
|
+ if ( defaultTexture === null ) {
|
|
|
|
|
|
- if ( samplerGPU === undefined ) {
|
|
|
|
|
|
+ const texture = new Texture();
|
|
|
|
+ texture.minFilter = NearestFilter;
|
|
|
|
+ texture.magFilter = NearestFilter;
|
|
|
|
|
|
- samplerGPU = this.device.createSampler( {
|
|
|
|
- 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: texture.anisotropy
|
|
|
|
- } );
|
|
|
|
|
|
+ this.createTexture( texture );
|
|
|
|
|
|
- this.samplerCache.set( key, samplerGPU );
|
|
|
|
|
|
+ this.defaultTexture = defaultTexture = texture;
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- const textureProperties = this.properties.get( texture );
|
|
|
|
- textureProperties.samplerGPU = samplerGPU;
|
|
|
|
|
|
+ return this.backend.get( defaultTexture ).texture;
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- initRenderTarget( renderTarget ) {
|
|
|
|
-
|
|
|
|
- const properties = this.properties;
|
|
|
|
- const renderTargetProperties = properties.get( renderTarget );
|
|
|
|
-
|
|
|
|
- if ( renderTargetProperties.initialized === undefined ) {
|
|
|
|
-
|
|
|
|
- const device = this.device;
|
|
|
|
|
|
+ _getDefaultCubeTextureGPU() {
|
|
|
|
|
|
- const width = renderTarget.width;
|
|
|
|
- const height = renderTarget.height;
|
|
|
|
|
|
+ let defaultCubeTexture = this.defaultTexture;
|
|
|
|
|
|
- const texture = renderTarget.texture;
|
|
|
|
|
|
+ if ( defaultCubeTexture === null ) {
|
|
|
|
|
|
- const colorTextureFormat = texture.internalFormat || this._getFormat( texture );
|
|
|
|
- const label = texture.name ? '_' + texture.name : '';
|
|
|
|
- const needsMipmaps = this._needsMipmaps( texture );
|
|
|
|
- const mipLevelCount = this._getMipLevelCount( texture, width, height, needsMipmaps );
|
|
|
|
-
|
|
|
|
- const colorTextureGPU = device.createTexture( {
|
|
|
|
- label: 'renderTarget' + label,
|
|
|
|
- size: {
|
|
|
|
- width: width,
|
|
|
|
- height: height,
|
|
|
|
- depthOrArrayLayers: 1
|
|
|
|
- },
|
|
|
|
- mipLevelCount: mipLevelCount,
|
|
|
|
- format: colorTextureFormat,
|
|
|
|
- usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST
|
|
|
|
- } );
|
|
|
|
-
|
|
|
|
- this.info.memory.textures ++;
|
|
|
|
-
|
|
|
|
- renderTargetProperties.colorTextureGPU = colorTextureGPU;
|
|
|
|
- renderTargetProperties.colorTextureFormat = colorTextureFormat;
|
|
|
|
-
|
|
|
|
- // When the ".texture" or ".depthTexture" property of a render target is used as a map,
|
|
|
|
- // the renderer has to find the respective GPUTexture objects to setup the bind groups.
|
|
|
|
- // Since it's not possible to see just from a texture object whether it belongs to a render
|
|
|
|
- // target or not, we need the initializedRTT flag.
|
|
|
|
-
|
|
|
|
- const textureProperties = properties.get( texture );
|
|
|
|
- textureProperties.textureGPU = colorTextureGPU;
|
|
|
|
- textureProperties.initializedRTT = false;
|
|
|
|
-
|
|
|
|
- if ( renderTarget.depthBuffer === true ) {
|
|
|
|
|
|
+ const texture = new CubeTexture();
|
|
|
|
+ texture.minFilter = NearestFilter;
|
|
|
|
+ texture.magFilter = NearestFilter;
|
|
|
|
|
|
- const depthTextureFormat = renderTarget.depthTexture !== null ? this._getFormat( renderTarget.depthTexture ) : GPUTextureFormat.Depth24PlusStencil8;
|
|
|
|
|
|
+ this.createTexture( texture );
|
|
|
|
|
|
- const depthTextureGPU = device.createTexture( {
|
|
|
|
- label: 'renderTarget' + label + '_depthBuffer',
|
|
|
|
- size: {
|
|
|
|
- width: width,
|
|
|
|
- height: height,
|
|
|
|
- depthOrArrayLayers: 1
|
|
|
|
- },
|
|
|
|
- format: depthTextureFormat,
|
|
|
|
- usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST
|
|
|
|
- } );
|
|
|
|
|
|
+ this.defaultCubeTexture = defaultCubeTexture = texture;
|
|
|
|
|
|
- this.info.memory.textures ++;
|
|
|
|
|
|
+ }
|
|
|
|
|
|
- renderTargetProperties.depthTextureGPU = depthTextureGPU;
|
|
|
|
- renderTargetProperties.depthTextureFormat = depthTextureFormat;
|
|
|
|
|
|
+ return this.backend.get( defaultCubeTexture ).texture;
|
|
|
|
|
|
- if ( renderTarget.depthTexture !== null ) {
|
|
|
|
|
|
+ }
|
|
|
|
|
|
- const depthTextureProperties = properties.get( renderTarget.depthTexture );
|
|
|
|
- depthTextureProperties.textureGPU = depthTextureGPU;
|
|
|
|
- depthTextureProperties.initializedRTT = false;
|
|
|
|
|
|
+ _copyImageToTexture( image, texture, textureGPU, textureDescriptorGPU, needsMipmaps, originDepth ) {
|
|
|
|
|
|
- }
|
|
|
|
|
|
+ if ( this._isHTMLImage( image ) ) {
|
|
|
|
|
|
- }
|
|
|
|
|
|
+ this._getImageBitmapFromHTML( image, texture ).then( imageBitmap => {
|
|
|
|
|
|
- //
|
|
|
|
|
|
+ this._copyExternalImageToTexture( imageBitmap, textureGPU, textureDescriptorGPU, needsMipmaps, originDepth );
|
|
|
|
|
|
- const disposeCallback = onRenderTargetDispose.bind( this );
|
|
|
|
- renderTargetProperties.disposeCallback = disposeCallback;
|
|
|
|
|
|
+ } );
|
|
|
|
|
|
- renderTarget.addEventListener( 'dispose', disposeCallback );
|
|
|
|
|
|
+ } else {
|
|
|
|
|
|
- //
|
|
|
|
|
|
+ // assume ImageBitmap
|
|
|
|
|
|
- renderTargetProperties.initialized = true;
|
|
|
|
|
|
+ this._copyExternalImageToTexture( image, textureGPU, textureDescriptorGPU, needsMipmaps, originDepth );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- dispose() {
|
|
|
|
|
|
+ _isHTMLImage( image ) {
|
|
|
|
|
|
- this.samplerCache.clear();
|
|
|
|
|
|
+ return ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- _convertAddressMode( value ) {
|
|
|
|
-
|
|
|
|
- let addressMode = GPUAddressMode.ClampToEdge;
|
|
|
|
-
|
|
|
|
- if ( value === RepeatWrapping ) {
|
|
|
|
-
|
|
|
|
- addressMode = GPUAddressMode.Repeat;
|
|
|
|
|
|
+ _copyCubeMapToTexture( images, texture, textureGPU, textureDescriptorGPU, needsMipmaps ) {
|
|
|
|
|
|
- } else if ( value === MirroredRepeatWrapping ) {
|
|
|
|
-
|
|
|
|
- addressMode = GPUAddressMode.MirrorRepeat;
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
|
|
+ for ( let i = 0; i < 6; i ++ ) {
|
|
|
|
|
|
- return addressMode;
|
|
|
|
|
|
+ const image = images[ i ];
|
|
|
|
|
|
- }
|
|
|
|
|
|
+ if ( image.isDataTexture ) {
|
|
|
|
|
|
- _convertFilterMode( value ) {
|
|
|
|
|
|
+ this._copyBufferToTexture( image.image, textureGPU, textureDescriptorGPU, needsMipmaps, i );
|
|
|
|
|
|
- let filterMode = GPUFilterMode.Linear;
|
|
|
|
|
|
+ } else {
|
|
|
|
|
|
- if ( value === NearestFilter || value === NearestMipmapNearestFilter || value === NearestMipmapLinearFilter ) {
|
|
|
|
|
|
+ this._copyImageToTexture( image, texture, textureGPU, textureDescriptorGPU, needsMipmaps, i );
|
|
|
|
|
|
- filterMode = GPUFilterMode.Nearest;
|
|
|
|
|
|
+ }
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- return filterMode;
|
|
|
|
-
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- _uploadVideoTexture( texture ) {
|
|
|
|
|
|
+ _copyExternalImageToTexture( image, textureGPU, textureDescriptorGPU, needsMipmaps, originDepth = 0 ) {
|
|
|
|
|
|
- const device = this.device;
|
|
|
|
|
|
+ const device = this.backend.device;
|
|
|
|
|
|
- const textureProperties = this.properties.get( texture );
|
|
|
|
-
|
|
|
|
- const textureGPU = device.importExternalTexture( {
|
|
|
|
- source: texture.source.data
|
|
|
|
- } );
|
|
|
|
-
|
|
|
|
- textureProperties.textureGPU = textureGPU;
|
|
|
|
- //textureProperties.version = texture.version; // @TODO: Force update for now, study a better solution soon using native VideoTexture.update() to fix warns
|
|
|
|
|
|
+ device.queue.copyExternalImageToTexture(
|
|
|
|
+ {
|
|
|
|
+ source: image
|
|
|
|
+ }, {
|
|
|
|
+ texture: textureGPU,
|
|
|
|
+ mipLevel: 0,
|
|
|
|
+ origin: { x: 0, y: 0, z: originDepth }
|
|
|
|
+ }, {
|
|
|
|
+ width: image.width,
|
|
|
|
+ height: image.height,
|
|
|
|
+ depthOrArrayLayers: 1
|
|
|
|
+ }
|
|
|
|
+ );
|
|
|
|
|
|
- return true;
|
|
|
|
|
|
+ if ( needsMipmaps ) this._generateMipmaps( textureGPU, textureDescriptorGPU, originDepth );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- _uploadTexture( texture ) {
|
|
|
|
-
|
|
|
|
- let needsUpdate = false;
|
|
|
|
-
|
|
|
|
- const device = this.device;
|
|
|
|
- const image = texture.image;
|
|
|
|
-
|
|
|
|
- const textureProperties = this.properties.get( texture );
|
|
|
|
-
|
|
|
|
- const { width, height, depth } = this._getSize( texture );
|
|
|
|
- const needsMipmaps = this._needsMipmaps( texture );
|
|
|
|
- const dimension = this._getDimension( texture );
|
|
|
|
- const mipLevelCount = this._getMipLevelCount( texture, width, height, needsMipmaps );
|
|
|
|
- const format = texture.internalFormat || this._getFormat( texture );
|
|
|
|
-
|
|
|
|
- let usage = GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST;
|
|
|
|
|
|
+ _generateMipmaps( textureGPU, textureDescriptorGPU, baseArrayLayer ) {
|
|
|
|
|
|
- if ( needsMipmaps ) {
|
|
|
|
|
|
+ if ( this.mipmapUtils === null ) {
|
|
|
|
|
|
- // current mipmap generation requires RENDER_ATTACHMENT
|
|
|
|
-
|
|
|
|
- usage |= GPUTextureUsage.RENDER_ATTACHMENT;
|
|
|
|
|
|
+ this.mipmapUtils = new WebGPUTextureMipmapUtils( this.backend.device );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- const textureGPUDescriptor = {
|
|
|
|
- label: texture.name,
|
|
|
|
- size: {
|
|
|
|
- width: width,
|
|
|
|
- height: height,
|
|
|
|
- depthOrArrayLayers: depth,
|
|
|
|
- },
|
|
|
|
- mipLevelCount: mipLevelCount,
|
|
|
|
- sampleCount: 1,
|
|
|
|
- dimension: dimension,
|
|
|
|
- format: format,
|
|
|
|
- usage: usage
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- // texture creation
|
|
|
|
-
|
|
|
|
- let textureGPU = textureProperties.textureGPU;
|
|
|
|
-
|
|
|
|
- if ( textureGPU === undefined ) {
|
|
|
|
-
|
|
|
|
- textureGPU = device.createTexture( textureGPUDescriptor );
|
|
|
|
-
|
|
|
|
- needsUpdate = true;
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // transfer texture data
|
|
|
|
-
|
|
|
|
- if ( texture.isDataTexture || texture.isDataArrayTexture || texture.isData3DTexture ) {
|
|
|
|
-
|
|
|
|
- this._copyBufferToTexture( image, textureGPU, textureGPUDescriptor, needsMipmaps );
|
|
|
|
-
|
|
|
|
- } else if ( texture.isCompressedTexture ) {
|
|
|
|
-
|
|
|
|
- this._copyCompressedBufferToTexture( texture.mipmaps, textureGPU, textureGPUDescriptor );
|
|
|
|
|
|
+ this.mipmapUtils.generateMipmaps( textureGPU, textureDescriptorGPU, baseArrayLayer );
|
|
|
|
|
|
- } else if ( texture.isCubeTexture ) {
|
|
|
|
-
|
|
|
|
- if ( image.length === 6 ) {
|
|
|
|
-
|
|
|
|
- this._copyCubeMapToTexture( image, texture, textureGPU, textureGPUDescriptor, needsMipmaps );
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- } else if ( texture.isRenderTargetTexture ) {
|
|
|
|
-
|
|
|
|
- if ( needsMipmaps === true ) this._generateMipmaps( textureGPU, textureGPUDescriptor );
|
|
|
|
-
|
|
|
|
- } else if ( texture.isDepthTexture !== true && image !== null ) {
|
|
|
|
|
|
+ }
|
|
|
|
|
|
- this._copyImageToTexture( image, texture, textureGPU, textureGPUDescriptor, needsMipmaps );
|
|
|
|
|
|
+ _getImageBitmapFromHTML( image, texture ) {
|
|
|
|
|
|
- }
|
|
|
|
|
|
+ const width = image.width;
|
|
|
|
+ const height = image.height;
|
|
|
|
|
|
- //
|
|
|
|
|
|
+ const options = {};
|
|
|
|
|
|
- textureProperties.textureGPU = textureGPU;
|
|
|
|
- textureProperties.version = texture.version;
|
|
|
|
|
|
+ options.imageOrientation = ( texture.flipY === true ) ? 'flipY' : 'none';
|
|
|
|
+ options.premultiplyAlpha = ( texture.premultiplyAlpha === true ) ? 'premultiply' : 'default';
|
|
|
|
|
|
- return needsUpdate;
|
|
|
|
|
|
+ return createImageBitmap( image, 0, 0, width, height, options );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- _copyBufferToTexture( image, textureGPU, textureGPUDescriptor, needsMipmaps, originDepth = 0 ) {
|
|
|
|
|
|
+ _copyBufferToTexture( image, textureGPU, textureDescriptorGPU, needsMipmaps, originDepth = 0 ) {
|
|
|
|
|
|
// @TODO: Consider to use GPUCommandEncoder.copyBufferToTexture()
|
|
// @TODO: Consider to use GPUCommandEncoder.copyBufferToTexture()
|
|
// @TODO: Consider to support valid buffer layouts with other formats like RGB
|
|
// @TODO: Consider to support valid buffer layouts with other formats like RGB
|
|
|
|
|
|
|
|
+ const device = this.backend.device;
|
|
|
|
+
|
|
const data = image.data;
|
|
const data = image.data;
|
|
|
|
|
|
- const bytesPerTexel = this._getBytesPerTexel( textureGPUDescriptor.format );
|
|
|
|
|
|
+ const bytesPerTexel = this._getBytesPerTexel( textureDescriptorGPU.format );
|
|
const bytesPerRow = image.width * bytesPerTexel;
|
|
const bytesPerRow = image.width * bytesPerTexel;
|
|
|
|
|
|
- this.device.queue.writeTexture(
|
|
|
|
|
|
+ device.queue.writeTexture(
|
|
{
|
|
{
|
|
texture: textureGPU,
|
|
texture: textureGPU,
|
|
mipLevel: 0,
|
|
mipLevel: 0,
|
|
@@ -487,55 +386,17 @@ class WebGPUTextures {
|
|
depthOrArrayLayers: ( image.depth !== undefined ) ? image.depth : 1
|
|
depthOrArrayLayers: ( image.depth !== undefined ) ? image.depth : 1
|
|
} );
|
|
} );
|
|
|
|
|
|
- if ( needsMipmaps === true ) this._generateMipmaps( textureGPU, textureGPUDescriptor, originDepth );
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- _copyCubeMapToTexture( images, texture, textureGPU, textureGPUDescriptor, needsMipmaps ) {
|
|
|
|
-
|
|
|
|
- for ( let i = 0; i < 6; i ++ ) {
|
|
|
|
-
|
|
|
|
- const image = images[ i ];
|
|
|
|
-
|
|
|
|
- if ( image.isDataTexture ) {
|
|
|
|
-
|
|
|
|
- this._copyBufferToTexture( image.image, textureGPU, textureGPUDescriptor, needsMipmaps, i );
|
|
|
|
-
|
|
|
|
- } else {
|
|
|
|
-
|
|
|
|
- this._copyImageToTexture( image, texture, textureGPU, textureGPUDescriptor, needsMipmaps, i );
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
|
|
+ if ( needsMipmaps === true ) this._generateMipmaps( textureGPU, textureDescriptorGPU, originDepth );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- _copyExternalImageToTexture( image, textureGPU, textureGPUDescriptor, needsMipmaps, originDepth = 0 ) {
|
|
|
|
-
|
|
|
|
- this.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 ( needsMipmaps ) this._generateMipmaps( textureGPU, textureGPUDescriptor, originDepth );
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- _copyCompressedBufferToTexture( mipmaps, textureGPU, textureGPUDescriptor ) {
|
|
|
|
|
|
+ _copyCompressedBufferToTexture( mipmaps, textureGPU, textureDescriptorGPU ) {
|
|
|
|
|
|
// @TODO: Consider to use GPUCommandEncoder.copyBufferToTexture()
|
|
// @TODO: Consider to use GPUCommandEncoder.copyBufferToTexture()
|
|
|
|
|
|
- const blockData = this._getBlockData( textureGPUDescriptor.format );
|
|
|
|
|
|
+ const device = this.backend.device;
|
|
|
|
+
|
|
|
|
+ const blockData = this._getBlockData( textureDescriptorGPU.format );
|
|
|
|
|
|
for ( let i = 0; i < mipmaps.length; i ++ ) {
|
|
for ( let i = 0; i < mipmaps.length; i ++ ) {
|
|
|
|
|
|
@@ -546,7 +407,7 @@ class WebGPUTextures {
|
|
|
|
|
|
const bytesPerRow = Math.ceil( width / blockData.width ) * blockData.byteLength;
|
|
const bytesPerRow = Math.ceil( width / blockData.width ) * blockData.byteLength;
|
|
|
|
|
|
- this.device.queue.writeTexture(
|
|
|
|
|
|
+ device.queue.writeTexture(
|
|
{
|
|
{
|
|
texture: textureGPU,
|
|
texture: textureGPU,
|
|
mipLevel: i
|
|
mipLevel: i
|
|
@@ -567,18 +428,6 @@ class WebGPUTextures {
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- _generateMipmaps( textureGPU, textureGPUDescriptor, baseArrayLayer ) {
|
|
|
|
-
|
|
|
|
- if ( this.utils === null ) {
|
|
|
|
-
|
|
|
|
- this.utils = new WebGPUTextureUtils( this.device ); // only create this helper if necessary
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- this.utils.generateMipmaps( textureGPU, textureGPUDescriptor, baseArrayLayer );
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
_getBlockData( format ) {
|
|
_getBlockData( format ) {
|
|
|
|
|
|
// this method is only relevant for compressed texture formats
|
|
// this method is only relevant for compressed texture formats
|
|
@@ -616,6 +465,74 @@ class WebGPUTextures {
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ _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;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ _getSize( texture ) {
|
|
|
|
+
|
|
|
|
+ const image = texture.image;
|
|
|
|
+
|
|
|
|
+ let width, height, depth;
|
|
|
|
+
|
|
|
|
+ if ( texture.isCubeTexture ) {
|
|
|
|
+
|
|
|
|
+ const faceImage = image.length > 0 ? image[ 0 ].image || image[ 0 ] : null;
|
|
|
|
+
|
|
|
|
+ width = faceImage ? faceImage.width : 1;
|
|
|
|
+ height = faceImage ? faceImage.height : 1;
|
|
|
|
+ depth = 6; // one image for each side of the cube map
|
|
|
|
+
|
|
|
|
+ } else if ( image !== null ) {
|
|
|
|
+
|
|
|
|
+ width = image.width;
|
|
|
|
+ height = image.height;
|
|
|
|
+ depth = ( image.depth !== undefined ) ? image.depth : 1;
|
|
|
|
+
|
|
|
|
+ } else {
|
|
|
|
+
|
|
|
|
+ width = height = depth = 1;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return { width, height, depth };
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ _needsMipmaps( texture ) {
|
|
|
|
+
|
|
|
|
+ return ( texture.isCompressedTexture !== true ) && ( texture.generateMipmaps === true ) && ( texture.minFilter !== NearestFilter ) && ( texture.minFilter !== LinearFilter );
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
_getBytesPerTexel( format ) {
|
|
_getBytesPerTexel( format ) {
|
|
|
|
|
|
if ( format === GPUTextureFormat.R8Unorm ) return 1;
|
|
if ( format === GPUTextureFormat.R8Unorm ) return 1;
|
|
@@ -648,6 +565,28 @@ class WebGPUTextures {
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ _getMipLevelCount( texture, width, height, needsMipmaps ) {
|
|
|
|
+
|
|
|
|
+ let mipLevelCount;
|
|
|
|
+
|
|
|
|
+ if ( texture.isCompressedTexture ) {
|
|
|
|
+
|
|
|
|
+ mipLevelCount = texture.mipmaps.length;
|
|
|
|
+
|
|
|
|
+ } else if ( needsMipmaps ) {
|
|
|
|
+
|
|
|
|
+ mipLevelCount = Math.floor( Math.log2( Math.max( width, height ) ) ) + 1;
|
|
|
|
+
|
|
|
|
+ } else {
|
|
|
|
+
|
|
|
|
+ mipLevelCount = 1; // a texture without mipmaps has a base mip (mipLevel 0)
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return mipLevelCount;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
_getFormat( texture ) {
|
|
_getFormat( texture ) {
|
|
|
|
|
|
const format = texture.format;
|
|
const format = texture.format;
|
|
@@ -656,7 +595,11 @@ class WebGPUTextures {
|
|
|
|
|
|
let formatGPU;
|
|
let formatGPU;
|
|
|
|
|
|
- if ( texture.isCompressedTexture === true ) {
|
|
|
|
|
|
+ if ( texture.isRenderTargetTexture === true || texture.isFramebufferTexture === true ) {
|
|
|
|
+
|
|
|
|
+ formatGPU = GPUTextureFormat.BGRA8Unorm;
|
|
|
|
+
|
|
|
|
+ } else if ( texture.isCompressedTexture === true ) {
|
|
|
|
|
|
switch ( format ) {
|
|
switch ( format ) {
|
|
|
|
|
|
@@ -875,176 +818,6 @@ class WebGPUTextures {
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- _isHTMLImage( image ) {
|
|
|
|
-
|
|
|
|
- return ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement );
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- _copyImageToTexture( image, texture, textureGPU, textureGPUDescriptor, needsMipmaps, originDepth ) {
|
|
|
|
-
|
|
|
|
- if ( this._isHTMLImage( image ) ) {
|
|
|
|
-
|
|
|
|
- this._getImageBitmapFromHTML( image, texture ).then( imageBitmap => {
|
|
|
|
-
|
|
|
|
- this._copyExternalImageToTexture( imageBitmap, textureGPU, textureGPUDescriptor, needsMipmaps, originDepth );
|
|
|
|
-
|
|
|
|
- } );
|
|
|
|
-
|
|
|
|
- } else {
|
|
|
|
-
|
|
|
|
- // assume ImageBitmap
|
|
|
|
-
|
|
|
|
- this._copyExternalImageToTexture( image, textureGPU, textureGPUDescriptor, needsMipmaps, originDepth );
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- _getImageBitmapFromHTML( image, texture ) {
|
|
|
|
-
|
|
|
|
- const width = image.width;
|
|
|
|
- const height = image.height;
|
|
|
|
-
|
|
|
|
- const options = {};
|
|
|
|
-
|
|
|
|
- options.imageOrientation = ( texture.flipY === true ) ? 'flipY' : 'none';
|
|
|
|
- options.premultiplyAlpha = ( texture.premultiplyAlpha === true ) ? 'premultiply' : 'default';
|
|
|
|
-
|
|
|
|
- return createImageBitmap( image, 0, 0, width, height, options );
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- _getImageBitmap( image, texture ) {
|
|
|
|
-
|
|
|
|
- const width = image.width;
|
|
|
|
- const height = image.height;
|
|
|
|
-
|
|
|
|
- if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||
|
|
|
|
- ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ) {
|
|
|
|
-
|
|
|
|
- const options = {};
|
|
|
|
-
|
|
|
|
- options.imageOrientation = ( texture.flipY === true ) ? 'flipY' : 'none';
|
|
|
|
- options.premultiplyAlpha = ( texture.premultiplyAlpha === true ) ? 'premultiply' : 'default';
|
|
|
|
-
|
|
|
|
- return createImageBitmap( image, 0, 0, width, height, options );
|
|
|
|
-
|
|
|
|
- } else {
|
|
|
|
-
|
|
|
|
- // assume ImageBitmap
|
|
|
|
-
|
|
|
|
- return Promise.resolve( image );
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- _getMipLevelCount( texture, width, height, needsMipmaps ) {
|
|
|
|
-
|
|
|
|
- let mipLevelCount;
|
|
|
|
-
|
|
|
|
- if ( texture.isCompressedTexture ) {
|
|
|
|
-
|
|
|
|
- mipLevelCount = texture.mipmaps.length;
|
|
|
|
-
|
|
|
|
- } else if ( needsMipmaps ) {
|
|
|
|
-
|
|
|
|
- mipLevelCount = Math.floor( Math.log2( Math.max( width, height ) ) ) + 1;
|
|
|
|
-
|
|
|
|
- } else {
|
|
|
|
-
|
|
|
|
- mipLevelCount = 1; // a texture without mipmaps has a base mip (mipLevel 0)
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return mipLevelCount;
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- _getSize( texture ) {
|
|
|
|
-
|
|
|
|
- const image = texture.image;
|
|
|
|
-
|
|
|
|
- let width, height, depth;
|
|
|
|
-
|
|
|
|
- if ( texture.isCubeTexture ) {
|
|
|
|
-
|
|
|
|
- const faceImage = image.length > 0 ? image[ 0 ].image || image[ 0 ] : null;
|
|
|
|
-
|
|
|
|
- width = faceImage ? faceImage.width : 1;
|
|
|
|
- height = faceImage ? faceImage.height : 1;
|
|
|
|
- depth = 6; // one image for each side of the cube map
|
|
|
|
-
|
|
|
|
- } else if ( image !== null ) {
|
|
|
|
-
|
|
|
|
- width = image.width;
|
|
|
|
- height = image.height;
|
|
|
|
- depth = ( image.depth !== undefined ) ? image.depth : 1;
|
|
|
|
-
|
|
|
|
- } else {
|
|
|
|
-
|
|
|
|
- width = height = depth = 1;
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return { width, height, depth };
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- _needsMipmaps( texture ) {
|
|
|
|
-
|
|
|
|
- return ( texture.isCompressedTexture !== true ) && ( texture.generateMipmaps === true ) && ( texture.minFilter !== NearestFilter ) && ( texture.minFilter !== LinearFilter );
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-function onRenderTargetDispose( event ) {
|
|
|
|
-
|
|
|
|
- const renderTarget = event.target;
|
|
|
|
- const properties = this.properties;
|
|
|
|
-
|
|
|
|
- const renderTargetProperties = properties.get( renderTarget );
|
|
|
|
-
|
|
|
|
- renderTarget.removeEventListener( 'dispose', renderTargetProperties.disposeCallback );
|
|
|
|
-
|
|
|
|
- renderTargetProperties.colorTextureGPU.destroy();
|
|
|
|
- properties.remove( renderTarget.texture );
|
|
|
|
-
|
|
|
|
- this.info.memory.textures --;
|
|
|
|
-
|
|
|
|
- if ( renderTarget.depthBuffer === true ) {
|
|
|
|
-
|
|
|
|
- renderTargetProperties.depthTextureGPU.destroy();
|
|
|
|
-
|
|
|
|
- this.info.memory.textures --;
|
|
|
|
-
|
|
|
|
- if ( renderTarget.depthTexture !== null ) {
|
|
|
|
-
|
|
|
|
- properties.remove( renderTarget.depthTexture );
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- properties.remove( renderTarget );
|
|
|
|
-
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-function onTextureDispose( event ) {
|
|
|
|
-
|
|
|
|
- const texture = event.target;
|
|
|
|
-
|
|
|
|
- const textureProperties = this.properties.get( texture );
|
|
|
|
- textureProperties.textureGPU.destroy();
|
|
|
|
-
|
|
|
|
- texture.removeEventListener( 'dispose', textureProperties.disposeCallback );
|
|
|
|
-
|
|
|
|
- this.properties.remove( texture );
|
|
|
|
-
|
|
|
|
- this.info.memory.textures --;
|
|
|
|
-
|
|
|
|
}
|
|
}
|
|
|
|
|
|
-export default WebGPUTextures;
|
|
|
|
|
|
+export default WebGPUTextureUtils;
|