WebGPUBindingUtils.js 4.6 KB

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