WebGPUTextureUtils.js 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619
  1. import {
  2. GPUTextureFormat, GPUAddressMode, GPUFilterMode, GPUTextureDimension, GPUFeatureName, GPUTextureViewDimension
  3. } from './WebGPUConstants.js';
  4. import { ColorManagement } from '../../../math/ColorManagement.js';
  5. import WebGPUTexturePassUtils from './WebGPUTexturePassUtils.js';
  6. import {
  7. ByteType, ShortType,
  8. NearestFilter, NearestMipmapNearestFilter, NearestMipmapLinearFilter,
  9. RepeatWrapping, MirroredRepeatWrapping,
  10. RGB_ETC2_Format, RGBA_ETC2_EAC_Format,
  11. RGBAFormat, RGBFormat, RedFormat, RGFormat, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, UnsignedByteType, FloatType, HalfFloatType, SRGBTransfer, DepthFormat, DepthStencilFormat,
  12. 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,
  13. RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_10x10_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, UnsignedIntType, UnsignedShortType, UnsignedInt248Type, UnsignedInt5999Type,
  14. NeverCompare, AlwaysCompare, LessCompare, LessEqualCompare, EqualCompare, GreaterEqualCompare, GreaterCompare, NotEqualCompare, IntType, RedIntegerFormat, RGIntegerFormat, RGBAIntegerFormat,
  15. UnsignedInt101111Type, RGBA_BPTC_Format, RGB_ETC1_Format, RGB_S3TC_DXT1_Format, RED_RGTC1_Format, SIGNED_RED_RGTC1_Format, RED_GREEN_RGTC2_Format, SIGNED_RED_GREEN_RGTC2_Format,
  16. R11_EAC_Format, SIGNED_R11_EAC_Format, RG11_EAC_Format, SIGNED_RG11_EAC_Format,
  17. Compatibility
  18. } from '../../../constants.js';
  19. import { CubeTexture } from '../../../textures/CubeTexture.js';
  20. import { Texture } from '../../../textures/Texture.js';
  21. import { warn, error } from '../../../utils.js';
  22. const _compareToWebGPU = {
  23. [ NeverCompare ]: 'never',
  24. [ LessCompare ]: 'less',
  25. [ EqualCompare ]: 'equal',
  26. [ LessEqualCompare ]: 'less-equal',
  27. [ GreaterCompare ]: 'greater',
  28. [ GreaterEqualCompare ]: 'greater-equal',
  29. [ AlwaysCompare ]: 'always',
  30. [ NotEqualCompare ]: 'not-equal'
  31. };
  32. const _flipMap = [ 0, 1, 3, 2, 4, 5 ];
  33. /**
  34. * A WebGPU backend utility module for managing textures.
  35. *
  36. * @private
  37. */
  38. class WebGPUTextureUtils {
  39. /**
  40. * Constructs a new utility object.
  41. *
  42. * @param {WebGPUBackend} backend - The WebGPU backend.
  43. */
  44. constructor( backend ) {
  45. /**
  46. * A reference to the WebGPU backend.
  47. *
  48. * @type {WebGPUBackend}
  49. */
  50. this.backend = backend;
  51. /**
  52. * A reference to the pass utils.
  53. *
  54. * @type {?WebGPUTexturePassUtils}
  55. * @default null
  56. */
  57. this._passUtils = null;
  58. /**
  59. * A dictionary for managing default textures. The key
  60. * is the texture format, the value the texture object.
  61. *
  62. * @type {Object<string,Texture>}
  63. */
  64. this.defaultTexture = {};
  65. /**
  66. * A dictionary for managing default cube textures. The key
  67. * is the texture format, the value the texture object.
  68. *
  69. * @type {Object<string,CubeTexture>}
  70. */
  71. this.defaultCubeTexture = {};
  72. /**
  73. * A default video frame.
  74. *
  75. * @type {?VideoFrame}
  76. * @default null
  77. */
  78. this.defaultVideoFrame = null;
  79. /**
  80. * A cache of shared texture samplers.
  81. *
  82. * @type {Map<string, Object>}
  83. */
  84. this._samplerCache = new Map();
  85. }
  86. /**
  87. * Creates a GPU sampler for the given texture.
  88. *
  89. * @param {Texture} texture - The texture to create the sampler for.
  90. * @return {string} The current sampler key.
  91. */
  92. updateSampler( texture ) {
  93. const backend = this.backend;
  94. const samplerKey = texture.minFilter + '-' + texture.magFilter + '-' +
  95. texture.wrapS + '-' + texture.wrapT + '-' + ( texture.wrapR || '0' ) + '-' +
  96. texture.anisotropy + '-' + ( texture.compareFunction || 0 );
  97. let samplerData = this._samplerCache.get( samplerKey );
  98. if ( samplerData === undefined ) {
  99. const samplerDescriptorGPU = {
  100. addressModeU: this._convertAddressMode( texture.wrapS ),
  101. addressModeV: this._convertAddressMode( texture.wrapT ),
  102. addressModeW: this._convertAddressMode( texture.wrapR ),
  103. magFilter: this._convertFilterMode( texture.magFilter ),
  104. minFilter: this._convertFilterMode( texture.minFilter ),
  105. mipmapFilter: this._convertFilterMode( texture.minFilter ),
  106. maxAnisotropy: 1
  107. };
  108. // Depth textures without compare function must use non-filtering (nearest) sampling
  109. if ( texture.isDepthTexture && texture.compareFunction === null ) {
  110. samplerDescriptorGPU.magFilter = GPUFilterMode.Nearest;
  111. samplerDescriptorGPU.minFilter = GPUFilterMode.Nearest;
  112. samplerDescriptorGPU.mipmapFilter = GPUFilterMode.Nearest;
  113. }
  114. // anisotropy can only be used when all filter modes are set to linear.
  115. if ( samplerDescriptorGPU.magFilter === GPUFilterMode.Linear && samplerDescriptorGPU.minFilter === GPUFilterMode.Linear && samplerDescriptorGPU.mipmapFilter === GPUFilterMode.Linear ) {
  116. samplerDescriptorGPU.maxAnisotropy = texture.anisotropy;
  117. }
  118. if ( texture.isDepthTexture && texture.compareFunction !== null && backend.hasCompatibility( Compatibility.TEXTURE_COMPARE ) ) {
  119. samplerDescriptorGPU.compare = _compareToWebGPU[ texture.compareFunction ];
  120. }
  121. const sampler = backend.device.createSampler( samplerDescriptorGPU );
  122. samplerData = { sampler, usedTimes: 0 };
  123. this._samplerCache.set( samplerKey, samplerData );
  124. }
  125. const textureData = backend.get( texture );
  126. if ( textureData.sampler !== samplerData.sampler ) {
  127. // check if previous sampler is unused so it can be deleted
  128. if ( textureData.sampler !== undefined ) {
  129. const oldSamplerData = this._samplerCache.get( textureData.samplerKey );
  130. oldSamplerData.usedTimes --;
  131. if ( oldSamplerData.usedTimes === 0 ) {
  132. this._samplerCache.delete( textureData.samplerKey );
  133. }
  134. }
  135. // update to new sampler data
  136. textureData.samplerKey = samplerKey;
  137. textureData.sampler = samplerData.sampler;
  138. samplerData.usedTimes ++;
  139. }
  140. return samplerKey;
  141. }
  142. /**
  143. * Creates a default texture for the given texture that can be used
  144. * as a placeholder until the actual texture is ready for usage.
  145. *
  146. * @param {Texture} texture - The texture to create a default texture for.
  147. */
  148. createDefaultTexture( texture ) {
  149. let textureGPU;
  150. const format = getFormat( texture );
  151. if ( texture.isCubeTexture ) {
  152. textureGPU = this._getDefaultCubeTextureGPU( format );
  153. } else {
  154. textureGPU = this._getDefaultTextureGPU( format );
  155. }
  156. this.backend.get( texture ).texture = textureGPU;
  157. }
  158. /**
  159. * Defines a texture on the GPU for the given texture object.
  160. *
  161. * @param {Texture} texture - The texture.
  162. * @param {Object} [options={}] - Optional configuration parameter.
  163. */
  164. createTexture( texture, options = {} ) {
  165. const backend = this.backend;
  166. const textureData = backend.get( texture );
  167. if ( textureData.initialized ) {
  168. throw new Error( 'WebGPUTextureUtils: Texture already initialized.' );
  169. }
  170. if ( texture.isExternalTexture ) {
  171. textureData.texture = texture.sourceTexture;
  172. textureData.initialized = true;
  173. return;
  174. }
  175. if ( options.needsMipmaps === undefined ) options.needsMipmaps = false;
  176. if ( options.levels === undefined ) options.levels = 1;
  177. if ( options.depth === undefined ) options.depth = 1;
  178. const { width, height, depth, levels } = options;
  179. if ( texture.isFramebufferTexture ) {
  180. if ( options.renderTarget ) {
  181. options.format = this.backend.utils.getCurrentColorFormat( options.renderTarget );
  182. } else {
  183. options.format = this.backend.utils.getPreferredCanvasFormat();
  184. }
  185. }
  186. const dimension = this._getDimension( texture );
  187. const format = texture.internalFormat || options.format || getFormat( texture, backend.device );
  188. textureData.format = format;
  189. const { samples, primarySamples, isMSAA } = backend.utils.getTextureSampleData( texture );
  190. let usage = GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC;
  191. if ( texture.isStorageTexture === true ) {
  192. usage |= GPUTextureUsage.STORAGE_BINDING;
  193. }
  194. if ( texture.isCompressedTexture !== true && texture.isCompressedArrayTexture !== true && format !== GPUTextureFormat.RGB9E5UFloat ) {
  195. usage |= GPUTextureUsage.RENDER_ATTACHMENT;
  196. }
  197. const textureDescriptorGPU = {
  198. label: texture.name,
  199. size: {
  200. width: width,
  201. height: height,
  202. depthOrArrayLayers: depth,
  203. },
  204. mipLevelCount: levels,
  205. sampleCount: primarySamples,
  206. dimension: dimension,
  207. format: format,
  208. usage: usage
  209. };
  210. // texture creation
  211. if ( format === undefined ) {
  212. warn( 'WebGPURenderer: Texture format not supported.' );
  213. this.createDefaultTexture( texture );
  214. return;
  215. }
  216. if ( texture.isCubeTexture ) {
  217. textureDescriptorGPU.textureBindingViewDimension = GPUTextureViewDimension.Cube;
  218. }
  219. try {
  220. textureData.texture = backend.device.createTexture( textureDescriptorGPU );
  221. } catch ( e ) {
  222. warn( 'WebGPURenderer: Failed to create texture with descriptor:', textureDescriptorGPU );
  223. this.createDefaultTexture( texture );
  224. return;
  225. }
  226. if ( isMSAA ) {
  227. const msaaTextureDescriptorGPU = Object.assign( {}, textureDescriptorGPU );
  228. msaaTextureDescriptorGPU.label = msaaTextureDescriptorGPU.label + '-msaa';
  229. msaaTextureDescriptorGPU.sampleCount = samples;
  230. msaaTextureDescriptorGPU.mipLevelCount = 1; // See https://www.w3.org/TR/webgpu/#texture-creation
  231. textureData.msaaTexture = backend.device.createTexture( msaaTextureDescriptorGPU );
  232. }
  233. textureData.initialized = true;
  234. textureData.textureDescriptorGPU = textureDescriptorGPU;
  235. }
  236. /**
  237. * Destroys the GPU data for the given texture object.
  238. *
  239. * @param {Texture} texture - The texture.
  240. * @param {boolean} [isDefaultTexture=false] - Whether the texture uses a default GPU texture or not.
  241. */
  242. destroyTexture( texture, isDefaultTexture = false ) {
  243. const backend = this.backend;
  244. const textureData = backend.get( texture );
  245. if ( textureData.texture !== undefined && isDefaultTexture === false ) textureData.texture.destroy();
  246. if ( textureData.msaaTexture !== undefined ) textureData.msaaTexture.destroy();
  247. backend.delete( texture );
  248. }
  249. /**
  250. * Generates mipmaps for the given texture.
  251. *
  252. * @param {Texture} texture - The texture.
  253. * @param {?GPUCommandEncoder} [encoder=null] - An optional command encoder used to generate mipmaps.
  254. */
  255. generateMipmaps( texture, encoder = null ) {
  256. const textureData = this.backend.get( texture );
  257. if ( texture.isCubeTexture ) {
  258. for ( let i = 0; i < 6; i ++ ) {
  259. this._generateMipmaps( textureData.texture, textureData.textureDescriptorGPU, i, encoder );
  260. }
  261. } else {
  262. const depth = texture.image.depth || 1;
  263. for ( let i = 0; i < depth; i ++ ) {
  264. this._generateMipmaps( textureData.texture, textureData.textureDescriptorGPU, i, encoder );
  265. }
  266. }
  267. }
  268. /**
  269. * Returns the color buffer representing the color
  270. * attachment of the default framebuffer.
  271. *
  272. * @return {GPUTexture} The color buffer.
  273. */
  274. getColorBuffer() {
  275. const backend = this.backend;
  276. const canvasTarget = backend.renderer.getCanvasTarget();
  277. const { width, height } = backend.getDrawingBufferSize();
  278. const samples = backend.renderer.currentSamples;
  279. const colorTexture = canvasTarget.colorTexture;
  280. const colorTextureData = backend.get( colorTexture );
  281. if ( colorTexture.width === width && colorTexture.height === height && colorTexture.samples === samples ) {
  282. return colorTextureData.texture;
  283. }
  284. // recreate
  285. let colorBuffer = colorTextureData.texture;
  286. if ( colorBuffer ) colorBuffer.destroy();
  287. colorBuffer = backend.device.createTexture( {
  288. label: 'colorBuffer',
  289. size: {
  290. width: width,
  291. height: height,
  292. depthOrArrayLayers: 1
  293. },
  294. sampleCount: backend.utils.getSampleCount( backend.renderer.currentSamples ),
  295. format: backend.utils.getPreferredCanvasFormat(),
  296. usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC
  297. } );
  298. //
  299. colorTexture.source.width = width;
  300. colorTexture.source.height = height;
  301. colorTexture.samples = samples;
  302. colorTextureData.texture = colorBuffer;
  303. return colorBuffer;
  304. }
  305. /**
  306. * Returns the depth buffer representing the depth
  307. * attachment of the default framebuffer.
  308. *
  309. * @param {boolean} [depth=true] - Whether depth is enabled or not.
  310. * @param {boolean} [stencil=false] - Whether stencil is enabled or not.
  311. * @return {GPUTexture} The depth buffer.
  312. */
  313. getDepthBuffer( depth = true, stencil = false ) {
  314. const backend = this.backend;
  315. const canvasTarget = backend.renderer.getCanvasTarget();
  316. const { width, height } = backend.getDrawingBufferSize();
  317. const samples = backend.renderer.currentSamples;
  318. const depthTexture = canvasTarget.depthTexture;
  319. if ( depthTexture.width === width &&
  320. depthTexture.height === height &&
  321. depthTexture.samples === samples &&
  322. depthTexture.depth === depth &&
  323. depthTexture.stencil === stencil ) {
  324. return backend.get( depthTexture ).texture;
  325. }
  326. //
  327. const depthTextureGPU = backend.get( depthTexture ).texture;
  328. let format, type;
  329. if ( stencil ) {
  330. format = DepthStencilFormat;
  331. type = UnsignedInt248Type;
  332. } else if ( depth ) {
  333. format = DepthFormat;
  334. type = UnsignedIntType;
  335. }
  336. if ( depthTextureGPU !== undefined ) {
  337. if ( depthTexture.image.width === width && depthTexture.image.height === height && depthTexture.format === format && depthTexture.type === type && depthTexture.samples === samples ) {
  338. return depthTextureGPU;
  339. }
  340. this.destroyTexture( depthTexture );
  341. }
  342. // recreate
  343. depthTexture.name = 'depthBuffer';
  344. depthTexture.format = format;
  345. depthTexture.type = type;
  346. depthTexture.image.width = width;
  347. depthTexture.image.height = height;
  348. depthTexture.samples = samples;
  349. this.createTexture( depthTexture, { width, height } );
  350. return backend.get( depthTexture ).texture;
  351. }
  352. /**
  353. * Uploads the updated texture data to the GPU.
  354. *
  355. * @param {Texture} texture - The texture.
  356. * @param {Object} [options={}] - Optional configuration parameter.
  357. */
  358. updateTexture( texture, options ) {
  359. const textureData = this.backend.get( texture );
  360. const mipmaps = texture.mipmaps;
  361. const { textureDescriptorGPU } = textureData;
  362. if ( texture.isRenderTargetTexture || ( textureDescriptorGPU === undefined /* unsupported texture format */ ) )
  363. return;
  364. // transfer texture data
  365. if ( texture.isDataTexture ) {
  366. if ( mipmaps.length > 0 ) {
  367. for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
  368. const mipmap = mipmaps[ i ];
  369. this._copyBufferToTexture( mipmap, textureData.texture, textureDescriptorGPU, 0, texture.flipY, 0, i );
  370. }
  371. } else {
  372. this._copyBufferToTexture( options.image, textureData.texture, textureDescriptorGPU, 0, texture.flipY );
  373. }
  374. } else if ( texture.isArrayTexture || texture.isDataArrayTexture || texture.isData3DTexture ) {
  375. for ( let i = 0; i < options.image.depth; i ++ ) {
  376. this._copyBufferToTexture( options.image, textureData.texture, textureDescriptorGPU, i, texture.flipY, i );
  377. }
  378. } else if ( texture.isCompressedTexture || texture.isCompressedArrayTexture ) {
  379. this._copyCompressedBufferToTexture( texture.mipmaps, textureData.texture, textureDescriptorGPU );
  380. } else if ( texture.isCubeTexture ) {
  381. this._copyCubeMapToTexture( texture, textureData.texture, textureDescriptorGPU );
  382. } else {
  383. if ( mipmaps.length > 0 ) {
  384. for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
  385. const mipmap = mipmaps[ i ];
  386. this._copyImageToTexture( mipmap, textureData.texture, textureDescriptorGPU, 0, texture.flipY, texture.premultiplyAlpha, i );
  387. }
  388. } else {
  389. this._copyImageToTexture( options.image, textureData.texture, textureDescriptorGPU, 0, texture.flipY, texture.premultiplyAlpha );
  390. }
  391. }
  392. //
  393. textureData.version = texture.version;
  394. }
  395. /**
  396. * Returns texture data as a typed array.
  397. *
  398. * @async
  399. * @param {Texture} texture - The texture to copy.
  400. * @param {number} x - The x coordinate of the copy origin.
  401. * @param {number} y - The y coordinate of the copy origin.
  402. * @param {number} width - The width of the copy.
  403. * @param {number} height - The height of the copy.
  404. * @param {number} faceIndex - The face index.
  405. * @return {Promise<TypedArray>} A Promise that resolves with a typed array when the copy operation has finished.
  406. */
  407. async copyTextureToBuffer( texture, x, y, width, height, faceIndex ) {
  408. const device = this.backend.device;
  409. const textureData = this.backend.get( texture );
  410. const textureGPU = textureData.texture;
  411. const format = textureData.textureDescriptorGPU.format;
  412. const bytesPerTexel = this._getBytesPerTexel( format );
  413. let bytesPerRow = width * bytesPerTexel;
  414. bytesPerRow = Math.ceil( bytesPerRow / 256 ) * 256; // Align to 256 bytes
  415. const readBuffer = device.createBuffer(
  416. {
  417. size: ( ( height - 1 ) * bytesPerRow ) + ( width * bytesPerTexel ), // see https://github.com/mrdoob/three.js/issues/31658#issuecomment-3229442010
  418. usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
  419. }
  420. );
  421. const encoder = device.createCommandEncoder();
  422. encoder.copyTextureToBuffer(
  423. {
  424. texture: textureGPU,
  425. origin: { x, y, z: faceIndex },
  426. },
  427. {
  428. buffer: readBuffer,
  429. bytesPerRow: bytesPerRow
  430. },
  431. {
  432. width: width,
  433. height: height
  434. }
  435. );
  436. const typedArrayType = this._getTypedArrayType( format );
  437. device.queue.submit( [ encoder.finish() ] );
  438. await readBuffer.mapAsync( GPUMapMode.READ );
  439. const buffer = readBuffer.getMappedRange();
  440. return new typedArrayType( buffer );
  441. }
  442. /**
  443. * Frees all internal resources.
  444. */
  445. dispose() {
  446. this._samplerCache.clear();
  447. }
  448. /**
  449. * Returns the default GPU texture for the given format.
  450. *
  451. * @private
  452. * @param {string} format - The GPU format.
  453. * @return {GPUTexture} The GPU texture.
  454. */
  455. _getDefaultTextureGPU( format ) {
  456. let defaultTexture = this.defaultTexture[ format ];
  457. if ( defaultTexture === undefined ) {
  458. const texture = new Texture();
  459. texture.minFilter = NearestFilter;
  460. texture.magFilter = NearestFilter;
  461. this.createTexture( texture, { width: 1, height: 1, format } );
  462. this.defaultTexture[ format ] = defaultTexture = texture;
  463. }
  464. return this.backend.get( defaultTexture ).texture;
  465. }
  466. /**
  467. * Returns the default GPU cube texture for the given format.
  468. *
  469. * @private
  470. * @param {string} format - The GPU format.
  471. * @return {GPUTexture} The GPU texture.
  472. */
  473. _getDefaultCubeTextureGPU( format ) {
  474. let defaultCubeTexture = this.defaultCubeTexture[ format ];
  475. if ( defaultCubeTexture === undefined ) {
  476. const texture = new CubeTexture();
  477. texture.minFilter = NearestFilter;
  478. texture.magFilter = NearestFilter;
  479. this.createTexture( texture, { width: 1, height: 1, depth: 6 } );
  480. this.defaultCubeTexture[ format ] = defaultCubeTexture = texture;
  481. }
  482. return this.backend.get( defaultCubeTexture ).texture;
  483. }
  484. /**
  485. * Uploads cube texture image data to the GPU memory.
  486. *
  487. * @private
  488. * @param {CubeTexture} texture - The cube texture.
  489. * @param {GPUTexture} textureGPU - The GPU texture.
  490. * @param {Object} textureDescriptorGPU - The GPU texture descriptor.
  491. */
  492. _copyCubeMapToTexture( texture, textureGPU, textureDescriptorGPU ) {
  493. const images = texture.images;
  494. const mipmaps = texture.mipmaps;
  495. for ( let i = 0; i < 6; i ++ ) {
  496. const image = images[ i ];
  497. const flipIndex = texture.flipY === true ? _flipMap[ i ] : i;
  498. if ( image.isDataTexture ) {
  499. this._copyBufferToTexture( image.image, textureGPU, textureDescriptorGPU, flipIndex, texture.flipY );
  500. } else {
  501. this._copyImageToTexture( image, textureGPU, textureDescriptorGPU, flipIndex, texture.flipY, texture.premultiplyAlpha );
  502. }
  503. for ( let j = 0; j < mipmaps.length; j ++ ) {
  504. const mipmap = mipmaps[ j ];
  505. const image = mipmap.images[ i ];
  506. if ( image.isDataTexture ) {
  507. this._copyBufferToTexture( image.image, textureGPU, textureDescriptorGPU, flipIndex, texture.flipY, 0, j + 1 );
  508. } else {
  509. this._copyImageToTexture( image, textureGPU, textureDescriptorGPU, flipIndex, texture.flipY, texture.premultiplyAlpha, j + 1 );
  510. }
  511. }
  512. }
  513. }
  514. /**
  515. * Uploads texture image data to the GPU memory.
  516. *
  517. * @private
  518. * @param {HTMLImageElement|ImageBitmap|HTMLCanvasElement} image - The image data.
  519. * @param {GPUTexture} textureGPU - The GPU texture.
  520. * @param {Object} textureDescriptorGPU - The GPU texture descriptor.
  521. * @param {number} originDepth - The origin depth.
  522. * @param {boolean} flipY - Whether to flip texture data along their vertical axis or not.
  523. * @param {boolean} premultiplyAlpha - Whether the texture should have its RGB channels premultiplied by the alpha channel or not.
  524. * @param {number} [mipLevel=0] - The mip level where the data should be copied to.
  525. */
  526. _copyImageToTexture( image, textureGPU, textureDescriptorGPU, originDepth, flipY, premultiplyAlpha, mipLevel = 0 ) {
  527. const device = this.backend.device;
  528. const width = ( mipLevel > 0 ) ? image.width : textureDescriptorGPU.size.width;
  529. const height = ( mipLevel > 0 ) ? image.height : textureDescriptorGPU.size.height;
  530. try {
  531. device.queue.copyExternalImageToTexture(
  532. {
  533. source: image,
  534. flipY: flipY
  535. }, {
  536. texture: textureGPU,
  537. mipLevel: mipLevel,
  538. origin: { x: 0, y: 0, z: originDepth },
  539. premultipliedAlpha: premultiplyAlpha
  540. }, {
  541. width: width,
  542. height: height,
  543. depthOrArrayLayers: 1
  544. }
  545. );
  546. // try/catch has been added to fix bad video frame data on certain devices, see #32391
  547. } catch ( _ ) {}
  548. }
  549. /**
  550. * Returns the pass utils singleton.
  551. *
  552. * @private
  553. * @return {WebGPUTexturePassUtils} The utils instance.
  554. */
  555. _getPassUtils() {
  556. let passUtils = this._passUtils;
  557. if ( passUtils === null ) {
  558. this._passUtils = passUtils = new WebGPUTexturePassUtils( this.backend.device );
  559. }
  560. return passUtils;
  561. }
  562. /**
  563. * Generates mipmaps for the given GPU texture.
  564. *
  565. * @private
  566. * @param {GPUTexture} textureGPU - The GPU texture object.
  567. * @param {Object} textureDescriptorGPU - The texture descriptor.
  568. * @param {number} [baseArrayLayer=0] - The index of the first array layer accessible to the texture view.
  569. * @param {?GPUCommandEncoder} [encoder=null] - An optional command encoder used to generate mipmaps.
  570. */
  571. _generateMipmaps( textureGPU, textureDescriptorGPU, baseArrayLayer = 0, encoder = null ) {
  572. this._getPassUtils().generateMipmaps( textureGPU, textureDescriptorGPU, baseArrayLayer, encoder );
  573. }
  574. /**
  575. * Flip the contents of the given GPU texture along its vertical axis.
  576. *
  577. * @private
  578. * @param {GPUTexture} textureGPU - The GPU texture object.
  579. * @param {Object} textureDescriptorGPU - The texture descriptor.
  580. * @param {number} [originDepth=0] - The origin depth.
  581. */
  582. _flipY( textureGPU, textureDescriptorGPU, originDepth = 0 ) {
  583. this._getPassUtils().flipY( textureGPU, textureDescriptorGPU, originDepth );
  584. }
  585. /**
  586. * Uploads texture buffer data to the GPU memory.
  587. *
  588. * @private
  589. * @param {Object} image - An object defining the image buffer data.
  590. * @param {GPUTexture} textureGPU - The GPU texture.
  591. * @param {Object} textureDescriptorGPU - The GPU texture descriptor.
  592. * @param {number} originDepth - The origin depth.
  593. * @param {boolean} flipY - Whether to flip texture data along their vertical axis or not.
  594. * @param {number} [depth=0] - The depth offset when copying array or 3D texture data.
  595. * @param {number} [mipLevel=0] - The mip level where the data should be copied to.
  596. */
  597. _copyBufferToTexture( image, textureGPU, textureDescriptorGPU, originDepth, flipY, depth = 0, mipLevel = 0 ) {
  598. // @TODO: Consider to use GPUCommandEncoder.copyBufferToTexture()
  599. // @TODO: Consider to support valid buffer layouts with other formats like RGB
  600. const device = this.backend.device;
  601. const data = image.data;
  602. const bytesPerTexel = this._getBytesPerTexel( textureDescriptorGPU.format );
  603. const bytesPerRow = image.width * bytesPerTexel;
  604. device.queue.writeTexture(
  605. {
  606. texture: textureGPU,
  607. mipLevel: mipLevel,
  608. origin: { x: 0, y: 0, z: originDepth }
  609. },
  610. data,
  611. {
  612. offset: image.width * image.height * bytesPerTexel * depth,
  613. bytesPerRow
  614. },
  615. {
  616. width: image.width,
  617. height: image.height,
  618. depthOrArrayLayers: 1
  619. } );
  620. if ( flipY === true ) {
  621. this._flipY( textureGPU, textureDescriptorGPU, originDepth );
  622. }
  623. }
  624. /**
  625. * Uploads compressed texture data to the GPU memory.
  626. *
  627. * @private
  628. * @param {Array<Object>} mipmaps - An array with mipmap data.
  629. * @param {GPUTexture} textureGPU - The GPU texture.
  630. * @param {Object} textureDescriptorGPU - The GPU texture descriptor.
  631. */
  632. _copyCompressedBufferToTexture( mipmaps, textureGPU, textureDescriptorGPU ) {
  633. // @TODO: Consider to use GPUCommandEncoder.copyBufferToTexture()
  634. const device = this.backend.device;
  635. const blockData = this._getBlockData( textureDescriptorGPU.format );
  636. const isArrayTexture = textureDescriptorGPU.size.depthOrArrayLayers > 1;
  637. for ( let i = 0; i < mipmaps.length; i ++ ) {
  638. const mipmap = mipmaps[ i ];
  639. const width = mipmap.width;
  640. const height = mipmap.height;
  641. const depth = isArrayTexture ? textureDescriptorGPU.size.depthOrArrayLayers : 1;
  642. const bytesPerRow = Math.ceil( width / blockData.width ) * blockData.byteLength;
  643. const bytesPerImage = bytesPerRow * Math.ceil( height / blockData.height );
  644. for ( let j = 0; j < depth; j ++ ) {
  645. device.queue.writeTexture(
  646. {
  647. texture: textureGPU,
  648. mipLevel: i,
  649. origin: { x: 0, y: 0, z: j }
  650. },
  651. mipmap.data,
  652. {
  653. offset: j * bytesPerImage,
  654. bytesPerRow,
  655. rowsPerImage: Math.ceil( height / blockData.height )
  656. },
  657. {
  658. width: Math.ceil( width / blockData.width ) * blockData.width,
  659. height: Math.ceil( height / blockData.height ) * blockData.height,
  660. depthOrArrayLayers: 1
  661. }
  662. );
  663. }
  664. }
  665. }
  666. /**
  667. * This method is only relevant for compressed texture formats. It returns a block
  668. * data descriptor for the given GPU compressed texture format.
  669. *
  670. * @private
  671. * @param {string} format - The GPU compressed texture format.
  672. * @return {Object} The block data descriptor.
  673. */
  674. _getBlockData( format ) {
  675. if ( format === GPUTextureFormat.BC1RGBAUnorm || format === GPUTextureFormat.BC1RGBAUnormSRGB ) return { byteLength: 8, width: 4, height: 4 }; // DXT1
  676. if ( format === GPUTextureFormat.BC2RGBAUnorm || format === GPUTextureFormat.BC2RGBAUnormSRGB ) return { byteLength: 16, width: 4, height: 4 }; // DXT3
  677. if ( format === GPUTextureFormat.BC3RGBAUnorm || format === GPUTextureFormat.BC3RGBAUnormSRGB ) return { byteLength: 16, width: 4, height: 4 }; // DXT5
  678. if ( format === GPUTextureFormat.BC4RUnorm || format === GPUTextureFormat.BC4RSnorm ) return { byteLength: 8, width: 4, height: 4 }; // RGTC1
  679. if ( format === GPUTextureFormat.BC5RGUnorm || format === GPUTextureFormat.BC5RGSnorm ) return { byteLength: 16, width: 4, height: 4 }; // RGTC2
  680. if ( format === GPUTextureFormat.BC6HRGBUFloat || format === GPUTextureFormat.BC6HRGBFloat ) return { byteLength: 16, width: 4, height: 4 }; // BPTC (float)
  681. if ( format === GPUTextureFormat.BC7RGBAUnorm || format === GPUTextureFormat.BC7RGBAUnormSRGB ) return { byteLength: 16, width: 4, height: 4 }; // BPTC (unorm)
  682. if ( format === GPUTextureFormat.ETC2RGB8Unorm || format === GPUTextureFormat.ETC2RGB8UnormSRGB ) return { byteLength: 8, width: 4, height: 4 };
  683. if ( format === GPUTextureFormat.ETC2RGB8A1Unorm || format === GPUTextureFormat.ETC2RGB8A1UnormSRGB ) return { byteLength: 8, width: 4, height: 4 };
  684. if ( format === GPUTextureFormat.ETC2RGBA8Unorm || format === GPUTextureFormat.ETC2RGBA8UnormSRGB ) return { byteLength: 16, width: 4, height: 4 };
  685. if ( format === GPUTextureFormat.EACR11Unorm ) return { byteLength: 8, width: 4, height: 4 };
  686. if ( format === GPUTextureFormat.EACR11Snorm ) return { byteLength: 8, width: 4, height: 4 };
  687. if ( format === GPUTextureFormat.EACRG11Unorm ) return { byteLength: 16, width: 4, height: 4 };
  688. if ( format === GPUTextureFormat.EACRG11Snorm ) return { byteLength: 16, width: 4, height: 4 };
  689. if ( format === GPUTextureFormat.ASTC4x4Unorm || format === GPUTextureFormat.ASTC4x4UnormSRGB ) return { byteLength: 16, width: 4, height: 4 };
  690. if ( format === GPUTextureFormat.ASTC5x4Unorm || format === GPUTextureFormat.ASTC5x4UnormSRGB ) return { byteLength: 16, width: 5, height: 4 };
  691. if ( format === GPUTextureFormat.ASTC5x5Unorm || format === GPUTextureFormat.ASTC5x5UnormSRGB ) return { byteLength: 16, width: 5, height: 5 };
  692. if ( format === GPUTextureFormat.ASTC6x5Unorm || format === GPUTextureFormat.ASTC6x5UnormSRGB ) return { byteLength: 16, width: 6, height: 5 };
  693. if ( format === GPUTextureFormat.ASTC6x6Unorm || format === GPUTextureFormat.ASTC6x6UnormSRGB ) return { byteLength: 16, width: 6, height: 6 };
  694. if ( format === GPUTextureFormat.ASTC8x5Unorm || format === GPUTextureFormat.ASTC8x5UnormSRGB ) return { byteLength: 16, width: 8, height: 5 };
  695. if ( format === GPUTextureFormat.ASTC8x6Unorm || format === GPUTextureFormat.ASTC8x6UnormSRGB ) return { byteLength: 16, width: 8, height: 6 };
  696. if ( format === GPUTextureFormat.ASTC8x8Unorm || format === GPUTextureFormat.ASTC8x8UnormSRGB ) return { byteLength: 16, width: 8, height: 8 };
  697. if ( format === GPUTextureFormat.ASTC10x5Unorm || format === GPUTextureFormat.ASTC10x5UnormSRGB ) return { byteLength: 16, width: 10, height: 5 };
  698. if ( format === GPUTextureFormat.ASTC10x6Unorm || format === GPUTextureFormat.ASTC10x6UnormSRGB ) return { byteLength: 16, width: 10, height: 6 };
  699. if ( format === GPUTextureFormat.ASTC10x8Unorm || format === GPUTextureFormat.ASTC10x8UnormSRGB ) return { byteLength: 16, width: 10, height: 8 };
  700. if ( format === GPUTextureFormat.ASTC10x10Unorm || format === GPUTextureFormat.ASTC10x10UnormSRGB ) return { byteLength: 16, width: 10, height: 10 };
  701. if ( format === GPUTextureFormat.ASTC12x10Unorm || format === GPUTextureFormat.ASTC12x10UnormSRGB ) return { byteLength: 16, width: 12, height: 10 };
  702. if ( format === GPUTextureFormat.ASTC12x12Unorm || format === GPUTextureFormat.ASTC12x12UnormSRGB ) return { byteLength: 16, width: 12, height: 12 };
  703. }
  704. /**
  705. * Converts the three.js uv wrapping constants to GPU address mode constants.
  706. *
  707. * @private
  708. * @param {number} value - The three.js constant defining a uv wrapping mode.
  709. * @return {string} The GPU address mode.
  710. */
  711. _convertAddressMode( value ) {
  712. let addressMode = GPUAddressMode.ClampToEdge;
  713. if ( value === RepeatWrapping ) {
  714. addressMode = GPUAddressMode.Repeat;
  715. } else if ( value === MirroredRepeatWrapping ) {
  716. addressMode = GPUAddressMode.MirrorRepeat;
  717. }
  718. return addressMode;
  719. }
  720. /**
  721. * Converts the three.js filter constants to GPU filter constants.
  722. *
  723. * @private
  724. * @param {number} value - The three.js constant defining a filter mode.
  725. * @return {string} The GPU filter mode.
  726. */
  727. _convertFilterMode( value ) {
  728. let filterMode = GPUFilterMode.Linear;
  729. if ( value === NearestFilter || value === NearestMipmapNearestFilter || value === NearestMipmapLinearFilter ) {
  730. filterMode = GPUFilterMode.Nearest;
  731. }
  732. return filterMode;
  733. }
  734. /**
  735. * Returns the bytes-per-texel value for the given GPU texture format.
  736. *
  737. * @private
  738. * @param {string} format - The GPU texture format.
  739. * @return {number} The bytes-per-texel.
  740. */
  741. _getBytesPerTexel( format ) {
  742. // 8-bit formats
  743. if ( format === GPUTextureFormat.R8Unorm ||
  744. format === GPUTextureFormat.R8Snorm ||
  745. format === GPUTextureFormat.R8Uint ||
  746. format === GPUTextureFormat.R8Sint ) return 1;
  747. // 16-bit formats
  748. if ( format === GPUTextureFormat.R16Uint ||
  749. format === GPUTextureFormat.R16Sint ||
  750. format === GPUTextureFormat.R16Float ||
  751. format === GPUTextureFormat.RG8Unorm ||
  752. format === GPUTextureFormat.RG8Snorm ||
  753. format === GPUTextureFormat.RG8Uint ||
  754. format === GPUTextureFormat.RG8Sint ) return 2;
  755. // 32-bit formats
  756. if ( format === GPUTextureFormat.R32Uint ||
  757. format === GPUTextureFormat.R32Sint ||
  758. format === GPUTextureFormat.R32Float ||
  759. format === GPUTextureFormat.RG16Uint ||
  760. format === GPUTextureFormat.RG16Sint ||
  761. format === GPUTextureFormat.RG16Float ||
  762. format === GPUTextureFormat.RGBA8Unorm ||
  763. format === GPUTextureFormat.RGBA8UnormSRGB ||
  764. format === GPUTextureFormat.RGBA8Snorm ||
  765. format === GPUTextureFormat.RGBA8Uint ||
  766. format === GPUTextureFormat.RGBA8Sint ||
  767. format === GPUTextureFormat.BGRA8Unorm ||
  768. format === GPUTextureFormat.BGRA8UnormSRGB ||
  769. // Packed 32-bit formats
  770. format === GPUTextureFormat.RGB9E5UFloat ||
  771. format === GPUTextureFormat.RGB10A2Unorm ||
  772. format === GPUTextureFormat.RG11B10UFloat ||
  773. format === GPUTextureFormat.Depth32Float ||
  774. format === GPUTextureFormat.Depth24Plus ||
  775. format === GPUTextureFormat.Depth24PlusStencil8 ||
  776. format === GPUTextureFormat.Depth32FloatStencil8 ) return 4;
  777. // 64-bit formats
  778. if ( format === GPUTextureFormat.RG32Uint ||
  779. format === GPUTextureFormat.RG32Sint ||
  780. format === GPUTextureFormat.RG32Float ||
  781. format === GPUTextureFormat.RGBA16Uint ||
  782. format === GPUTextureFormat.RGBA16Sint ||
  783. format === GPUTextureFormat.RGBA16Float ) return 8;
  784. // 128-bit formats
  785. if ( format === GPUTextureFormat.RGBA32Uint ||
  786. format === GPUTextureFormat.RGBA32Sint ||
  787. format === GPUTextureFormat.RGBA32Float ) return 16;
  788. }
  789. /**
  790. * Returns the corresponding typed array type for the given GPU texture format.
  791. *
  792. * @private
  793. * @param {string} format - The GPU texture format.
  794. * @return {TypedArray.constructor} The typed array type.
  795. */
  796. _getTypedArrayType( format ) {
  797. if ( format === GPUTextureFormat.R8Uint ) return Uint8Array;
  798. if ( format === GPUTextureFormat.R8Sint ) return Int8Array;
  799. if ( format === GPUTextureFormat.R8Unorm ) return Uint8Array;
  800. if ( format === GPUTextureFormat.R8Snorm ) return Int8Array;
  801. if ( format === GPUTextureFormat.RG8Uint ) return Uint8Array;
  802. if ( format === GPUTextureFormat.RG8Sint ) return Int8Array;
  803. if ( format === GPUTextureFormat.RG8Unorm ) return Uint8Array;
  804. if ( format === GPUTextureFormat.RG8Snorm ) return Int8Array;
  805. if ( format === GPUTextureFormat.RGBA8Uint ) return Uint8Array;
  806. if ( format === GPUTextureFormat.RGBA8Sint ) return Int8Array;
  807. if ( format === GPUTextureFormat.RGBA8Unorm || format === GPUTextureFormat.RGBA8UnormSRGB ) return Uint8Array;
  808. if ( format === GPUTextureFormat.RGBA8Snorm ) return Int8Array;
  809. if ( format === GPUTextureFormat.R16Uint ) return Uint16Array;
  810. if ( format === GPUTextureFormat.R16Sint ) return Int16Array;
  811. if ( format === GPUTextureFormat.RG16Uint ) return Uint16Array;
  812. if ( format === GPUTextureFormat.RG16Sint ) return Int16Array;
  813. if ( format === GPUTextureFormat.RGBA16Uint ) return Uint16Array;
  814. if ( format === GPUTextureFormat.RGBA16Sint ) return Int16Array;
  815. if ( format === GPUTextureFormat.R16Float ) return Uint16Array;
  816. if ( format === GPUTextureFormat.RG16Float ) return Uint16Array;
  817. if ( format === GPUTextureFormat.RGBA16Float ) return Uint16Array;
  818. if ( format === GPUTextureFormat.R32Uint ) return Uint32Array;
  819. if ( format === GPUTextureFormat.R32Sint ) return Int32Array;
  820. if ( format === GPUTextureFormat.R32Float ) return Float32Array;
  821. if ( format === GPUTextureFormat.RG32Uint ) return Uint32Array;
  822. if ( format === GPUTextureFormat.RG32Sint ) return Int32Array;
  823. if ( format === GPUTextureFormat.RG32Float ) return Float32Array;
  824. if ( format === GPUTextureFormat.RGBA32Uint ) return Uint32Array;
  825. if ( format === GPUTextureFormat.RGBA32Sint ) return Int32Array;
  826. if ( format === GPUTextureFormat.RGBA32Float ) return Float32Array;
  827. if ( format === GPUTextureFormat.BGRA8Unorm || format === GPUTextureFormat.BGRA8UnormSRGB ) return Uint8Array;
  828. if ( format === GPUTextureFormat.RGB10A2Unorm ) return Uint32Array;
  829. if ( format === GPUTextureFormat.RGB9E5UFloat ) return Uint32Array;
  830. if ( format === GPUTextureFormat.RG11B10UFloat ) return Uint32Array;
  831. if ( format === GPUTextureFormat.Depth32Float ) return Float32Array;
  832. if ( format === GPUTextureFormat.Depth24Plus ) return Uint32Array;
  833. if ( format === GPUTextureFormat.Depth24PlusStencil8 ) return Uint32Array;
  834. if ( format === GPUTextureFormat.Depth32FloatStencil8 ) return Float32Array;
  835. }
  836. /**
  837. * Returns the GPU dimensions for the given texture.
  838. *
  839. * @private
  840. * @param {Texture} texture - The texture.
  841. * @return {string} The GPU dimension.
  842. */
  843. _getDimension( texture ) {
  844. let dimension;
  845. if ( texture.is3DTexture || texture.isData3DTexture ) {
  846. dimension = GPUTextureDimension.ThreeD;
  847. } else {
  848. dimension = GPUTextureDimension.TwoD;
  849. }
  850. return dimension;
  851. }
  852. }
  853. /**
  854. * Returns the GPU format for the given texture.
  855. *
  856. * @param {Texture} texture - The texture.
  857. * @param {?GPUDevice} [device=null] - The GPU device which is used for feature detection.
  858. * It is not necessary to apply the device for most formats.
  859. * @return {string} The GPU format.
  860. */
  861. export function getFormat( texture, device = null ) {
  862. const format = texture.format;
  863. const type = texture.type;
  864. const colorSpace = texture.colorSpace;
  865. const transfer = ColorManagement.getTransfer( colorSpace );
  866. let formatGPU;
  867. if ( texture.isCompressedTexture === true || texture.isCompressedArrayTexture === true ) {
  868. switch ( format ) {
  869. case RGB_S3TC_DXT1_Format:
  870. case RGBA_S3TC_DXT1_Format:
  871. formatGPU = ( transfer === SRGBTransfer ) ? GPUTextureFormat.BC1RGBAUnormSRGB : GPUTextureFormat.BC1RGBAUnorm;
  872. break;
  873. case RGBA_S3TC_DXT3_Format:
  874. formatGPU = ( transfer === SRGBTransfer ) ? GPUTextureFormat.BC2RGBAUnormSRGB : GPUTextureFormat.BC2RGBAUnorm;
  875. break;
  876. case RGBA_S3TC_DXT5_Format:
  877. formatGPU = ( transfer === SRGBTransfer ) ? GPUTextureFormat.BC3RGBAUnormSRGB : GPUTextureFormat.BC3RGBAUnorm;
  878. break;
  879. case RED_RGTC1_Format:
  880. formatGPU = GPUTextureFormat.BC4RUnorm;
  881. break;
  882. case SIGNED_RED_RGTC1_Format:
  883. formatGPU = GPUTextureFormat.BC4RSnorm;
  884. break;
  885. case RED_GREEN_RGTC2_Format:
  886. formatGPU = GPUTextureFormat.BC5RGUnorm;
  887. break;
  888. case SIGNED_RED_GREEN_RGTC2_Format:
  889. formatGPU = GPUTextureFormat.BC5RGSnorm;
  890. break;
  891. case RGBA_BPTC_Format:
  892. formatGPU = ( transfer === SRGBTransfer ) ? GPUTextureFormat.BC7RGBAUnormSRGB : GPUTextureFormat.BC7RGBAUnorm;
  893. break;
  894. case RGB_ETC2_Format:
  895. case RGB_ETC1_Format:
  896. formatGPU = ( transfer === SRGBTransfer ) ? GPUTextureFormat.ETC2RGB8UnormSRGB : GPUTextureFormat.ETC2RGB8Unorm;
  897. break;
  898. case RGBA_ETC2_EAC_Format:
  899. formatGPU = ( transfer === SRGBTransfer ) ? GPUTextureFormat.ETC2RGBA8UnormSRGB : GPUTextureFormat.ETC2RGBA8Unorm;
  900. break;
  901. case R11_EAC_Format:
  902. formatGPU = GPUTextureFormat.EACR11Unorm;
  903. break;
  904. case SIGNED_R11_EAC_Format:
  905. formatGPU = GPUTextureFormat.EACR11Snorm;
  906. break;
  907. case RG11_EAC_Format:
  908. formatGPU = GPUTextureFormat.EACRG11Unorm;
  909. break;
  910. case SIGNED_RG11_EAC_Format:
  911. formatGPU = GPUTextureFormat.EACRG11Snorm;
  912. break;
  913. case RGBA_ASTC_4x4_Format:
  914. formatGPU = ( transfer === SRGBTransfer ) ? GPUTextureFormat.ASTC4x4UnormSRGB : GPUTextureFormat.ASTC4x4Unorm;
  915. break;
  916. case RGBA_ASTC_5x4_Format:
  917. formatGPU = ( transfer === SRGBTransfer ) ? GPUTextureFormat.ASTC5x4UnormSRGB : GPUTextureFormat.ASTC5x4Unorm;
  918. break;
  919. case RGBA_ASTC_5x5_Format:
  920. formatGPU = ( transfer === SRGBTransfer ) ? GPUTextureFormat.ASTC5x5UnormSRGB : GPUTextureFormat.ASTC5x5Unorm;
  921. break;
  922. case RGBA_ASTC_6x5_Format:
  923. formatGPU = ( transfer === SRGBTransfer ) ? GPUTextureFormat.ASTC6x5UnormSRGB : GPUTextureFormat.ASTC6x5Unorm;
  924. break;
  925. case RGBA_ASTC_6x6_Format:
  926. formatGPU = ( transfer === SRGBTransfer ) ? GPUTextureFormat.ASTC6x6UnormSRGB : GPUTextureFormat.ASTC6x6Unorm;
  927. break;
  928. case RGBA_ASTC_8x5_Format:
  929. formatGPU = ( transfer === SRGBTransfer ) ? GPUTextureFormat.ASTC8x5UnormSRGB : GPUTextureFormat.ASTC8x5Unorm;
  930. break;
  931. case RGBA_ASTC_8x6_Format:
  932. formatGPU = ( transfer === SRGBTransfer ) ? GPUTextureFormat.ASTC8x6UnormSRGB : GPUTextureFormat.ASTC8x6Unorm;
  933. break;
  934. case RGBA_ASTC_8x8_Format:
  935. formatGPU = ( transfer === SRGBTransfer ) ? GPUTextureFormat.ASTC8x8UnormSRGB : GPUTextureFormat.ASTC8x8Unorm;
  936. break;
  937. case RGBA_ASTC_10x5_Format:
  938. formatGPU = ( transfer === SRGBTransfer ) ? GPUTextureFormat.ASTC10x5UnormSRGB : GPUTextureFormat.ASTC10x5Unorm;
  939. break;
  940. case RGBA_ASTC_10x6_Format:
  941. formatGPU = ( transfer === SRGBTransfer ) ? GPUTextureFormat.ASTC10x6UnormSRGB : GPUTextureFormat.ASTC10x6Unorm;
  942. break;
  943. case RGBA_ASTC_10x8_Format:
  944. formatGPU = ( transfer === SRGBTransfer ) ? GPUTextureFormat.ASTC10x8UnormSRGB : GPUTextureFormat.ASTC10x8Unorm;
  945. break;
  946. case RGBA_ASTC_10x10_Format:
  947. formatGPU = ( transfer === SRGBTransfer ) ? GPUTextureFormat.ASTC10x10UnormSRGB : GPUTextureFormat.ASTC10x10Unorm;
  948. break;
  949. case RGBA_ASTC_12x10_Format:
  950. formatGPU = ( transfer === SRGBTransfer ) ? GPUTextureFormat.ASTC12x10UnormSRGB : GPUTextureFormat.ASTC12x10Unorm;
  951. break;
  952. case RGBA_ASTC_12x12_Format:
  953. formatGPU = ( transfer === SRGBTransfer ) ? GPUTextureFormat.ASTC12x12UnormSRGB : GPUTextureFormat.ASTC12x12Unorm;
  954. break;
  955. case RGBAFormat:
  956. formatGPU = ( transfer === SRGBTransfer ) ? GPUTextureFormat.RGBA8UnormSRGB : GPUTextureFormat.RGBA8Unorm;
  957. break;
  958. default:
  959. error( 'WebGPURenderer: Unsupported texture format.', format );
  960. }
  961. } else {
  962. switch ( format ) {
  963. case RGBAFormat:
  964. switch ( type ) {
  965. case ByteType:
  966. formatGPU = GPUTextureFormat.RGBA8Snorm;
  967. break;
  968. case ShortType:
  969. formatGPU = GPUTextureFormat.RGBA16Sint;
  970. break;
  971. case UnsignedShortType:
  972. formatGPU = GPUTextureFormat.RGBA16Uint;
  973. break;
  974. case UnsignedIntType:
  975. formatGPU = GPUTextureFormat.RGBA32Uint;
  976. break;
  977. case IntType:
  978. formatGPU = GPUTextureFormat.RGBA32Sint;
  979. break;
  980. case UnsignedByteType:
  981. formatGPU = ( transfer === SRGBTransfer ) ? GPUTextureFormat.RGBA8UnormSRGB : GPUTextureFormat.RGBA8Unorm;
  982. break;
  983. case HalfFloatType:
  984. formatGPU = GPUTextureFormat.RGBA16Float;
  985. break;
  986. case FloatType:
  987. formatGPU = GPUTextureFormat.RGBA32Float;
  988. break;
  989. default:
  990. error( 'WebGPURenderer: Unsupported texture type with RGBAFormat.', type );
  991. }
  992. break;
  993. case RGBFormat:
  994. switch ( type ) {
  995. case UnsignedInt5999Type:
  996. formatGPU = GPUTextureFormat.RGB9E5UFloat;
  997. break;
  998. case UnsignedInt101111Type:
  999. formatGPU = GPUTextureFormat.RG11B10UFloat;
  1000. break;
  1001. default:
  1002. error( 'WebGPURenderer: Unsupported texture type with RGBFormat.', type );
  1003. }
  1004. break;
  1005. case RedFormat:
  1006. switch ( type ) {
  1007. case ByteType:
  1008. formatGPU = GPUTextureFormat.R8Snorm;
  1009. break;
  1010. case ShortType:
  1011. formatGPU = GPUTextureFormat.R16Sint;
  1012. break;
  1013. case UnsignedShortType:
  1014. formatGPU = GPUTextureFormat.R16Uint;
  1015. break;
  1016. case UnsignedIntType:
  1017. formatGPU = GPUTextureFormat.R32Uint;
  1018. break;
  1019. case IntType:
  1020. formatGPU = GPUTextureFormat.R32Sint;
  1021. break;
  1022. case UnsignedByteType:
  1023. formatGPU = GPUTextureFormat.R8Unorm;
  1024. break;
  1025. case HalfFloatType:
  1026. formatGPU = GPUTextureFormat.R16Float;
  1027. break;
  1028. case FloatType:
  1029. formatGPU = GPUTextureFormat.R32Float;
  1030. break;
  1031. default:
  1032. error( 'WebGPURenderer: Unsupported texture type with RedFormat.', type );
  1033. }
  1034. break;
  1035. case RGFormat:
  1036. switch ( type ) {
  1037. case ByteType:
  1038. formatGPU = GPUTextureFormat.RG8Snorm;
  1039. break;
  1040. case ShortType:
  1041. formatGPU = GPUTextureFormat.RG16Sint;
  1042. break;
  1043. case UnsignedShortType:
  1044. formatGPU = GPUTextureFormat.RG16Uint;
  1045. break;
  1046. case UnsignedIntType:
  1047. formatGPU = GPUTextureFormat.RG32Uint;
  1048. break;
  1049. case IntType:
  1050. formatGPU = GPUTextureFormat.RG32Sint;
  1051. break;
  1052. case UnsignedByteType:
  1053. formatGPU = GPUTextureFormat.RG8Unorm;
  1054. break;
  1055. case HalfFloatType:
  1056. formatGPU = GPUTextureFormat.RG16Float;
  1057. break;
  1058. case FloatType:
  1059. formatGPU = GPUTextureFormat.RG32Float;
  1060. break;
  1061. default:
  1062. error( 'WebGPURenderer: Unsupported texture type with RGFormat.', type );
  1063. }
  1064. break;
  1065. case DepthFormat:
  1066. switch ( type ) {
  1067. case UnsignedShortType:
  1068. formatGPU = GPUTextureFormat.Depth16Unorm;
  1069. break;
  1070. case UnsignedIntType:
  1071. formatGPU = GPUTextureFormat.Depth24Plus;
  1072. break;
  1073. case FloatType:
  1074. formatGPU = GPUTextureFormat.Depth32Float;
  1075. break;
  1076. default:
  1077. error( 'WebGPURenderer: Unsupported texture type with DepthFormat.', type );
  1078. }
  1079. break;
  1080. case DepthStencilFormat:
  1081. switch ( type ) {
  1082. case UnsignedInt248Type:
  1083. formatGPU = GPUTextureFormat.Depth24PlusStencil8;
  1084. break;
  1085. case FloatType:
  1086. if ( device && device.features.has( GPUFeatureName.Depth32FloatStencil8 ) === false ) {
  1087. error( 'WebGPURenderer: Depth textures with DepthStencilFormat + FloatType can only be used with the "depth32float-stencil8" GPU feature.' );
  1088. }
  1089. formatGPU = GPUTextureFormat.Depth32FloatStencil8;
  1090. break;
  1091. default:
  1092. error( 'WebGPURenderer: Unsupported texture type with DepthStencilFormat.', type );
  1093. }
  1094. break;
  1095. case RedIntegerFormat:
  1096. switch ( type ) {
  1097. case IntType:
  1098. formatGPU = GPUTextureFormat.R32Sint;
  1099. break;
  1100. case UnsignedIntType:
  1101. formatGPU = GPUTextureFormat.R32Uint;
  1102. break;
  1103. default:
  1104. error( 'WebGPURenderer: Unsupported texture type with RedIntegerFormat.', type );
  1105. }
  1106. break;
  1107. case RGIntegerFormat:
  1108. switch ( type ) {
  1109. case IntType:
  1110. formatGPU = GPUTextureFormat.RG32Sint;
  1111. break;
  1112. case UnsignedIntType:
  1113. formatGPU = GPUTextureFormat.RG32Uint;
  1114. break;
  1115. default:
  1116. error( 'WebGPURenderer: Unsupported texture type with RGIntegerFormat.', type );
  1117. }
  1118. break;
  1119. case RGBAIntegerFormat:
  1120. switch ( type ) {
  1121. case IntType:
  1122. formatGPU = GPUTextureFormat.RGBA32Sint;
  1123. break;
  1124. case UnsignedIntType:
  1125. formatGPU = GPUTextureFormat.RGBA32Uint;
  1126. break;
  1127. default:
  1128. error( 'WebGPURenderer: Unsupported texture type with RGBAIntegerFormat.', type );
  1129. }
  1130. break;
  1131. default:
  1132. error( 'WebGPURenderer: Unsupported texture format.', format );
  1133. }
  1134. }
  1135. return formatGPU;
  1136. }
  1137. export default WebGPUTextureUtils;
粤ICP备19079148号