WebGPUBindingUtils.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. import {
  2. GPUTextureAspect, GPUTextureViewDimension, GPUBufferBindingType, GPUTextureSampleType
  3. } from './WebGPUConstants.js';
  4. import { FloatType, IntType, UnsignedIntType } from 'three';
  5. class WebGPUBindingUtils {
  6. constructor( backend ) {
  7. this.backend = backend;
  8. }
  9. createBindingsLayout( bindings ) {
  10. const backend = this.backend;
  11. const device = backend.device;
  12. const entries = [];
  13. let index = 0;
  14. for ( const binding of bindings ) {
  15. const bindingGPU = {
  16. binding: index ++,
  17. visibility: binding.visibility
  18. };
  19. if ( binding.isUniformBuffer || binding.isStorageBuffer ) {
  20. const buffer = {}; // GPUBufferBindingLayout
  21. if ( binding.isStorageBuffer ) {
  22. buffer.type = GPUBufferBindingType.Storage;
  23. }
  24. bindingGPU.buffer = buffer;
  25. } else if ( binding.isSampler ) {
  26. const sampler = {}; // GPUSamplerBindingLayout
  27. if ( binding.texture.isDepthTexture ) {
  28. if ( binding.texture.compareFunction !== null ) {
  29. sampler.type = 'comparison';
  30. }
  31. }
  32. bindingGPU.sampler = sampler;
  33. } else if ( binding.isSampledTexture && binding.texture.isVideoTexture ) {
  34. bindingGPU.externalTexture = {}; // GPUExternalTextureBindingLayout
  35. } else if ( binding.isSampledTexture && binding.store ) {
  36. const format = this.backend.get( binding.texture ).texture.format;
  37. const access = binding.access;
  38. bindingGPU.storageTexture = { format, access }; // GPUStorageTextureBindingLayout
  39. } else if ( binding.isSampledTexture ) {
  40. const texture = {}; // GPUTextureBindingLayout
  41. if ( binding.texture.isDepthTexture ) {
  42. texture.sampleType = GPUTextureSampleType.Depth;
  43. } else if ( binding.texture.isDataTexture ) {
  44. const type = binding.texture.type;
  45. if ( type === IntType ) {
  46. texture.sampleType = GPUTextureSampleType.SInt;
  47. } else if ( type === UnsignedIntType ) {
  48. texture.sampleType = GPUTextureSampleType.UInt;
  49. } else if ( type === FloatType ) {
  50. // @TODO: Add support for this soon: backend.hasFeature( 'float32-filterable' )
  51. texture.sampleType = GPUTextureSampleType.UnfilterableFloat;
  52. }
  53. }
  54. if ( binding.isSampledCubeTexture ) {
  55. texture.viewDimension = GPUTextureViewDimension.Cube;
  56. } else if ( binding.texture.isDataArrayTexture ) {
  57. texture.viewDimension = GPUTextureViewDimension.TwoDArray;
  58. } else if ( binding.isSampledTexture3D ) {
  59. texture.viewDimension = GPUTextureViewDimension.ThreeD;
  60. }
  61. bindingGPU.texture = texture;
  62. } else {
  63. console.error( `WebGPUBindingUtils: Unsupported binding "${ binding }".` );
  64. }
  65. entries.push( bindingGPU );
  66. }
  67. return device.createBindGroupLayout( { entries } );
  68. }
  69. createBindings( bindings ) {
  70. const backend = this.backend;
  71. const bindingsData = backend.get( bindings );
  72. // setup (static) binding layout and (dynamic) binding group
  73. const bindLayoutGPU = this.createBindingsLayout( bindings );
  74. const bindGroupGPU = this.createBindGroup( bindings, bindLayoutGPU );
  75. bindingsData.layout = bindLayoutGPU;
  76. bindingsData.group = bindGroupGPU;
  77. bindingsData.bindings = bindings;
  78. }
  79. updateBinding( binding ) {
  80. const backend = this.backend;
  81. const device = backend.device;
  82. const buffer = binding.buffer;
  83. const bufferGPU = backend.get( binding ).buffer;
  84. device.queue.writeBuffer( bufferGPU, 0, buffer, 0 );
  85. }
  86. createBindGroup( bindings, layoutGPU ) {
  87. const backend = this.backend;
  88. const device = backend.device;
  89. let bindingPoint = 0;
  90. const entriesGPU = [];
  91. for ( const binding of bindings ) {
  92. if ( binding.isUniformBuffer ) {
  93. const bindingData = backend.get( binding );
  94. if ( bindingData.buffer === undefined ) {
  95. const byteLength = binding.byteLength;
  96. const usage = GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST;
  97. const bufferGPU = device.createBuffer( {
  98. label: 'bindingBuffer_' + binding.name,
  99. size: byteLength,
  100. usage: usage
  101. } );
  102. bindingData.buffer = bufferGPU;
  103. }
  104. entriesGPU.push( { binding: bindingPoint, resource: { buffer: bindingData.buffer } } );
  105. } else if ( binding.isStorageBuffer ) {
  106. const bindingData = backend.get( binding );
  107. if ( bindingData.buffer === undefined ) {
  108. const attribute = binding.attribute;
  109. //const usage = GPUBufferUsage.STORAGE | GPUBufferUsage.VERTEX | /*GPUBufferUsage.COPY_SRC |*/ GPUBufferUsage.COPY_DST;
  110. //backend.attributeUtils.createAttribute( attribute, usage ); // @TODO: Move it to universal renderer
  111. bindingData.buffer = backend.get( attribute ).buffer;
  112. }
  113. entriesGPU.push( { binding: bindingPoint, resource: { buffer: bindingData.buffer } } );
  114. } else if ( binding.isSampler ) {
  115. const textureGPU = backend.get( binding.texture );
  116. entriesGPU.push( { binding: bindingPoint, resource: textureGPU.sampler } );
  117. } else if ( binding.isSampledTexture ) {
  118. const textureData = backend.get( binding.texture );
  119. let dimensionViewGPU;
  120. if ( binding.isSampledCubeTexture ) {
  121. dimensionViewGPU = GPUTextureViewDimension.Cube;
  122. } else if ( binding.isSampledTexture3D ) {
  123. dimensionViewGPU = GPUTextureViewDimension.ThreeD;
  124. } else if ( binding.texture.isDataArrayTexture ) {
  125. dimensionViewGPU = GPUTextureViewDimension.TwoDArray;
  126. } else {
  127. dimensionViewGPU = GPUTextureViewDimension.TwoD;
  128. }
  129. let resourceGPU;
  130. if ( textureData.externalTexture !== undefined ) {
  131. resourceGPU = device.importExternalTexture( { source: textureData.externalTexture } );
  132. } else {
  133. const aspectGPU = GPUTextureAspect.All;
  134. resourceGPU = textureData.texture.createView( { aspect: aspectGPU, dimension: dimensionViewGPU, mipLevelCount: binding.store ? 1 : textureData.mipLevelCount } );
  135. }
  136. entriesGPU.push( { binding: bindingPoint, resource: resourceGPU } );
  137. }
  138. bindingPoint ++;
  139. }
  140. return device.createBindGroup( {
  141. layout: layoutGPU,
  142. entries: entriesGPU
  143. } );
  144. }
  145. }
  146. export default WebGPUBindingUtils;