WebGLAttributeUtils.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. import { IntType } from 'three';
  2. let _id = 0;
  3. class DualAttributeData {
  4. constructor( attributeData, dualBuffer ) {
  5. this.buffers = [ attributeData.bufferGPU, dualBuffer ];
  6. this.type = attributeData.type;
  7. this.bufferType = attributeData.bufferType;
  8. this.pbo = attributeData.pbo;
  9. this.byteLength = attributeData.byteLength;
  10. this.bytesPerElement = attributeData.BYTES_PER_ELEMENT;
  11. this.version = attributeData.version;
  12. this.isInteger = attributeData.isInteger;
  13. this.activeBufferIndex = 0;
  14. this.baseId = attributeData.id;
  15. }
  16. get id() {
  17. return `${ this.baseId }|${ this.activeBufferIndex }`;
  18. }
  19. get bufferGPU() {
  20. return this.buffers[ this.activeBufferIndex ];
  21. }
  22. get transformBuffer() {
  23. return this.buffers[ this.activeBufferIndex ^ 1 ];
  24. }
  25. switchBuffers() {
  26. this.activeBufferIndex ^= 1;
  27. }
  28. }
  29. class WebGLAttributeUtils {
  30. constructor( backend ) {
  31. this.backend = backend;
  32. }
  33. createAttribute( attribute, bufferType ) {
  34. const backend = this.backend;
  35. const { gl } = backend;
  36. const array = attribute.array;
  37. const usage = attribute.usage || gl.STATIC_DRAW;
  38. const bufferAttribute = attribute.isInterleavedBufferAttribute ? attribute.data : attribute;
  39. const bufferData = backend.get( bufferAttribute );
  40. let bufferGPU = bufferData.bufferGPU;
  41. if ( bufferGPU === undefined ) {
  42. bufferGPU = this._createBuffer( gl, bufferType, array, usage );
  43. bufferData.bufferGPU = bufferGPU;
  44. bufferData.bufferType = bufferType;
  45. bufferData.version = bufferAttribute.version;
  46. }
  47. //attribute.onUploadCallback();
  48. let type;
  49. if ( array instanceof Float32Array ) {
  50. type = gl.FLOAT;
  51. } else if ( array instanceof Uint16Array ) {
  52. if ( attribute.isFloat16BufferAttribute ) {
  53. type = gl.HALF_FLOAT;
  54. } else {
  55. type = gl.UNSIGNED_SHORT;
  56. }
  57. } else if ( array instanceof Int16Array ) {
  58. type = gl.SHORT;
  59. } else if ( array instanceof Uint32Array ) {
  60. type = gl.UNSIGNED_INT;
  61. } else if ( array instanceof Int32Array ) {
  62. type = gl.INT;
  63. } else if ( array instanceof Int8Array ) {
  64. type = gl.BYTE;
  65. } else if ( array instanceof Uint8Array ) {
  66. type = gl.UNSIGNED_BYTE;
  67. } else if ( array instanceof Uint8ClampedArray ) {
  68. type = gl.UNSIGNED_BYTE;
  69. } else {
  70. throw new Error( 'THREE.WebGLBackend: Unsupported buffer data format: ' + array );
  71. }
  72. let attributeData = {
  73. bufferGPU,
  74. bufferType,
  75. type,
  76. byteLength: array.byteLength,
  77. bytesPerElement: array.BYTES_PER_ELEMENT,
  78. version: attribute.version,
  79. pbo: attribute.pbo,
  80. isInteger: type === gl.INT || type === gl.UNSIGNED_INT || type === gl.UNSIGNED_SHORT || attribute.gpuType === IntType,
  81. id: _id ++
  82. };
  83. if ( attribute.isStorageBufferAttribute || attribute.isStorageInstancedBufferAttribute ) {
  84. // create buffer for tranform feedback use
  85. const bufferGPUDual = this._createBuffer( gl, bufferType, array, usage );
  86. attributeData = new DualAttributeData( attributeData, bufferGPUDual );
  87. }
  88. backend.set( attribute, attributeData );
  89. }
  90. updateAttribute( attribute ) {
  91. const backend = this.backend;
  92. const { gl } = backend;
  93. const array = attribute.array;
  94. const bufferAttribute = attribute.isInterleavedBufferAttribute ? attribute.data : attribute;
  95. const bufferData = backend.get( bufferAttribute );
  96. const bufferType = bufferData.bufferType;
  97. const updateRanges = attribute.isInterleavedBufferAttribute ? attribute.data.updateRanges : attribute.updateRanges;
  98. gl.bindBuffer( bufferType, bufferData.bufferGPU );
  99. if ( updateRanges.length === 0 ) {
  100. // Not using update ranges
  101. gl.bufferSubData( bufferType, 0, array );
  102. } else {
  103. for ( let i = 0, l = updateRanges.length; i < l; i ++ ) {
  104. const range = updateRanges[ i ];
  105. gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT,
  106. array, range.start, range.count );
  107. }
  108. bufferAttribute.clearUpdateRanges();
  109. }
  110. gl.bindBuffer( bufferType, null );
  111. bufferData.version = bufferAttribute.version;
  112. }
  113. destroyAttribute( attribute ) {
  114. const backend = this.backend;
  115. const { gl } = backend;
  116. if ( attribute.isInterleavedBufferAttribute ) {
  117. backend.delete( attribute.data );
  118. }
  119. const attributeData = backend.get( attribute );
  120. gl.deleteBuffer( attributeData.bufferGPU );
  121. backend.delete( attribute );
  122. }
  123. async getArrayBufferAsync( attribute ) {
  124. const backend = this.backend;
  125. const { gl } = backend;
  126. const bufferAttribute = attribute.isInterleavedBufferAttribute ? attribute.data : attribute;
  127. const { bufferGPU } = backend.get( bufferAttribute );
  128. const array = attribute.array;
  129. const byteLength = array.byteLength;
  130. gl.bindBuffer( gl.COPY_READ_BUFFER, bufferGPU );
  131. const writeBuffer = gl.createBuffer();
  132. gl.bindBuffer( gl.COPY_WRITE_BUFFER, writeBuffer );
  133. gl.bufferData( gl.COPY_WRITE_BUFFER, byteLength, gl.STREAM_READ );
  134. gl.copyBufferSubData( gl.COPY_READ_BUFFER, gl.COPY_WRITE_BUFFER, 0, 0, byteLength );
  135. await backend.utils._clientWaitAsync();
  136. const dstBuffer = new attribute.array.constructor( array.length );
  137. gl.getBufferSubData( gl.COPY_WRITE_BUFFER, 0, dstBuffer );
  138. gl.deleteBuffer( writeBuffer );
  139. return dstBuffer.buffer;
  140. }
  141. _createBuffer( gl, bufferType, array, usage ) {
  142. const bufferGPU = gl.createBuffer();
  143. gl.bindBuffer( bufferType, bufferGPU );
  144. gl.bufferData( bufferType, array, usage );
  145. gl.bindBuffer( bufferType, null );
  146. return bufferGPU;
  147. }
  148. }
  149. export default WebGLAttributeUtils;