uniformBuffer.js 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873
  1. import { Logger } from "../Misc/logger.js";
  2. import { Tools } from "../Misc/tools.js";
  3. import "../Engines/Extensions/engine.uniformBuffer.js";
  4. /**
  5. * Uniform buffer objects.
  6. *
  7. * Handles blocks of uniform on the GPU.
  8. *
  9. * If WebGL 2 is not available, this class falls back on traditional setUniformXXX calls.
  10. *
  11. * For more information, please refer to :
  12. * https://www.khronos.org/opengl/wiki/Uniform_Buffer_Object
  13. */
  14. export class UniformBuffer {
  15. /**
  16. * Instantiates a new Uniform buffer objects.
  17. *
  18. * Handles blocks of uniform on the GPU.
  19. *
  20. * If WebGL 2 is not available, this class falls back on traditional setUniformXXX calls.
  21. *
  22. * For more information, please refer to :
  23. * @see https://www.khronos.org/opengl/wiki/Uniform_Buffer_Object
  24. * @param engine Define the engine the buffer is associated with
  25. * @param data Define the data contained in the buffer
  26. * @param dynamic Define if the buffer is updatable
  27. * @param name to assign to the buffer (debugging purpose)
  28. * @param forceNoUniformBuffer define that this object must not rely on UBO objects
  29. */
  30. constructor(engine, data, dynamic, name, forceNoUniformBuffer = false) {
  31. // Matrix cache
  32. this._valueCache = {};
  33. this._engine = engine;
  34. this._noUBO = !engine.supportsUniformBuffers || forceNoUniformBuffer;
  35. this._dynamic = dynamic;
  36. this._name = name ?? "no-name";
  37. this._data = data || [];
  38. this._uniformLocations = {};
  39. this._uniformSizes = {};
  40. this._uniformArraySizes = {};
  41. this._uniformLocationPointer = 0;
  42. this._needSync = false;
  43. if (this._engine._features.trackUbosInFrame) {
  44. this._buffers = [];
  45. this._bufferIndex = -1;
  46. this._createBufferOnWrite = false;
  47. this._currentFrameId = 0;
  48. }
  49. if (this._noUBO) {
  50. this.updateMatrix3x3 = this._updateMatrix3x3ForEffect;
  51. this.updateMatrix2x2 = this._updateMatrix2x2ForEffect;
  52. this.updateFloat = this._updateFloatForEffect;
  53. this.updateFloat2 = this._updateFloat2ForEffect;
  54. this.updateFloat3 = this._updateFloat3ForEffect;
  55. this.updateFloat4 = this._updateFloat4ForEffect;
  56. this.updateFloatArray = this._updateFloatArrayForEffect;
  57. this.updateArray = this._updateArrayForEffect;
  58. this.updateIntArray = this._updateIntArrayForEffect;
  59. this.updateUIntArray = this._updateUIntArrayForEffect;
  60. this.updateMatrix = this._updateMatrixForEffect;
  61. this.updateMatrices = this._updateMatricesForEffect;
  62. this.updateVector3 = this._updateVector3ForEffect;
  63. this.updateVector4 = this._updateVector4ForEffect;
  64. this.updateColor3 = this._updateColor3ForEffect;
  65. this.updateColor4 = this._updateColor4ForEffect;
  66. this.updateDirectColor4 = this._updateDirectColor4ForEffect;
  67. this.updateInt = this._updateIntForEffect;
  68. this.updateInt2 = this._updateInt2ForEffect;
  69. this.updateInt3 = this._updateInt3ForEffect;
  70. this.updateInt4 = this._updateInt4ForEffect;
  71. this.updateUInt = this._updateUIntForEffect;
  72. this.updateUInt2 = this._updateUInt2ForEffect;
  73. this.updateUInt3 = this._updateUInt3ForEffect;
  74. this.updateUInt4 = this._updateUInt4ForEffect;
  75. }
  76. else {
  77. this._engine._uniformBuffers.push(this);
  78. this.updateMatrix3x3 = this._updateMatrix3x3ForUniform;
  79. this.updateMatrix2x2 = this._updateMatrix2x2ForUniform;
  80. this.updateFloat = this._updateFloatForUniform;
  81. this.updateFloat2 = this._updateFloat2ForUniform;
  82. this.updateFloat3 = this._updateFloat3ForUniform;
  83. this.updateFloat4 = this._updateFloat4ForUniform;
  84. this.updateFloatArray = this._updateFloatArrayForUniform;
  85. this.updateArray = this._updateArrayForUniform;
  86. this.updateIntArray = this._updateIntArrayForUniform;
  87. this.updateUIntArray = this._updateUIntArrayForUniform;
  88. this.updateMatrix = this._updateMatrixForUniform;
  89. this.updateMatrices = this._updateMatricesForUniform;
  90. this.updateVector3 = this._updateVector3ForUniform;
  91. this.updateVector4 = this._updateVector4ForUniform;
  92. this.updateColor3 = this._updateColor3ForUniform;
  93. this.updateColor4 = this._updateColor4ForUniform;
  94. this.updateDirectColor4 = this._updateDirectColor4ForUniform;
  95. this.updateInt = this._updateIntForUniform;
  96. this.updateInt2 = this._updateInt2ForUniform;
  97. this.updateInt3 = this._updateInt3ForUniform;
  98. this.updateInt4 = this._updateInt4ForUniform;
  99. this.updateUInt = this._updateUIntForUniform;
  100. this.updateUInt2 = this._updateUInt2ForUniform;
  101. this.updateUInt3 = this._updateUInt3ForUniform;
  102. this.updateUInt4 = this._updateUInt4ForUniform;
  103. }
  104. }
  105. /**
  106. * Indicates if the buffer is using the WebGL2 UBO implementation,
  107. * or just falling back on setUniformXXX calls.
  108. */
  109. get useUbo() {
  110. return !this._noUBO;
  111. }
  112. /**
  113. * Indicates if the WebGL underlying uniform buffer is in sync
  114. * with the javascript cache data.
  115. */
  116. get isSync() {
  117. return !this._needSync;
  118. }
  119. /**
  120. * Indicates if the WebGL underlying uniform buffer is dynamic.
  121. * Also, a dynamic UniformBuffer will disable cache verification and always
  122. * update the underlying WebGL uniform buffer to the GPU.
  123. * @returns if Dynamic, otherwise false
  124. */
  125. isDynamic() {
  126. return this._dynamic !== undefined;
  127. }
  128. /**
  129. * The data cache on JS side.
  130. * @returns the underlying data as a float array
  131. */
  132. getData() {
  133. return this._bufferData;
  134. }
  135. /**
  136. * The underlying WebGL Uniform buffer.
  137. * @returns the webgl buffer
  138. */
  139. getBuffer() {
  140. return this._buffer;
  141. }
  142. /**
  143. * std140 layout specifies how to align data within an UBO structure.
  144. * See https://khronos.org/registry/OpenGL/specs/gl/glspec45.core.pdf#page=159
  145. * for specs.
  146. * @param size
  147. */
  148. _fillAlignment(size) {
  149. // This code has been simplified because we only use floats, vectors of 1, 2, 3, 4 components
  150. // and 4x4 matrices
  151. // TODO : change if other types are used
  152. let alignment;
  153. if (size <= 2) {
  154. alignment = size;
  155. }
  156. else {
  157. alignment = 4;
  158. }
  159. if (this._uniformLocationPointer % alignment !== 0) {
  160. const oldPointer = this._uniformLocationPointer;
  161. this._uniformLocationPointer += alignment - (this._uniformLocationPointer % alignment);
  162. const diff = this._uniformLocationPointer - oldPointer;
  163. for (let i = 0; i < diff; i++) {
  164. this._data.push(0);
  165. }
  166. }
  167. }
  168. /**
  169. * Adds an uniform in the buffer.
  170. * Warning : the subsequents calls of this function must be in the same order as declared in the shader
  171. * for the layout to be correct ! The addUniform function only handles types like float, vec2, vec3, vec4, mat4,
  172. * meaning size=1,2,3,4 or 16. It does not handle struct types.
  173. * @param name Name of the uniform, as used in the uniform block in the shader.
  174. * @param size Data size, or data directly.
  175. * @param arraySize The number of elements in the array, 0 if not an array.
  176. */
  177. addUniform(name, size, arraySize = 0) {
  178. if (this._noUBO) {
  179. return;
  180. }
  181. if (this._uniformLocations[name] !== undefined) {
  182. // Already existing uniform
  183. return;
  184. }
  185. // This function must be called in the order of the shader layout !
  186. // size can be the size of the uniform, or data directly
  187. let data;
  188. // std140 FTW...
  189. if (arraySize > 0) {
  190. if (size instanceof Array) {
  191. // eslint-disable-next-line no-throw-literal
  192. throw "addUniform should not be use with Array in UBO: " + name;
  193. }
  194. this._fillAlignment(4);
  195. this._uniformArraySizes[name] = { strideSize: size, arraySize };
  196. if (size == 16) {
  197. size = size * arraySize;
  198. }
  199. else {
  200. const perElementPadding = 4 - size;
  201. const totalPadding = perElementPadding * arraySize;
  202. size = size * arraySize + totalPadding;
  203. }
  204. data = [];
  205. // Fill with zeros
  206. for (let i = 0; i < size; i++) {
  207. data.push(0);
  208. }
  209. }
  210. else {
  211. if (size instanceof Array) {
  212. data = size;
  213. size = data.length;
  214. }
  215. else {
  216. size = size;
  217. data = [];
  218. // Fill with zeros
  219. for (let i = 0; i < size; i++) {
  220. data.push(0);
  221. }
  222. }
  223. this._fillAlignment(size);
  224. }
  225. this._uniformSizes[name] = size;
  226. this._uniformLocations[name] = this._uniformLocationPointer;
  227. this._uniformLocationPointer += size;
  228. for (let i = 0; i < size; i++) {
  229. this._data.push(data[i]);
  230. }
  231. this._needSync = true;
  232. }
  233. /**
  234. * Adds a Matrix 4x4 to the uniform buffer.
  235. * @param name Name of the uniform, as used in the uniform block in the shader.
  236. * @param mat A 4x4 matrix.
  237. */
  238. addMatrix(name, mat) {
  239. this.addUniform(name, Array.prototype.slice.call(mat.asArray()));
  240. }
  241. /**
  242. * Adds a vec2 to the uniform buffer.
  243. * @param name Name of the uniform, as used in the uniform block in the shader.
  244. * @param x Define the x component value of the vec2
  245. * @param y Define the y component value of the vec2
  246. */
  247. addFloat2(name, x, y) {
  248. const temp = [x, y];
  249. this.addUniform(name, temp);
  250. }
  251. /**
  252. * Adds a vec3 to the uniform buffer.
  253. * @param name Name of the uniform, as used in the uniform block in the shader.
  254. * @param x Define the x component value of the vec3
  255. * @param y Define the y component value of the vec3
  256. * @param z Define the z component value of the vec3
  257. */
  258. addFloat3(name, x, y, z) {
  259. const temp = [x, y, z];
  260. this.addUniform(name, temp);
  261. }
  262. /**
  263. * Adds a vec3 to the uniform buffer.
  264. * @param name Name of the uniform, as used in the uniform block in the shader.
  265. * @param color Define the vec3 from a Color
  266. */
  267. addColor3(name, color) {
  268. const temp = [color.r, color.g, color.b];
  269. this.addUniform(name, temp);
  270. }
  271. /**
  272. * Adds a vec4 to the uniform buffer.
  273. * @param name Name of the uniform, as used in the uniform block in the shader.
  274. * @param color Define the rgb components from a Color
  275. * @param alpha Define the a component of the vec4
  276. */
  277. addColor4(name, color, alpha) {
  278. const temp = [color.r, color.g, color.b, alpha];
  279. this.addUniform(name, temp);
  280. }
  281. /**
  282. * Adds a vec3 to the uniform buffer.
  283. * @param name Name of the uniform, as used in the uniform block in the shader.
  284. * @param vector Define the vec3 components from a Vector
  285. */
  286. addVector3(name, vector) {
  287. const temp = [vector.x, vector.y, vector.z];
  288. this.addUniform(name, temp);
  289. }
  290. /**
  291. * Adds a Matrix 3x3 to the uniform buffer.
  292. * @param name Name of the uniform, as used in the uniform block in the shader.
  293. */
  294. addMatrix3x3(name) {
  295. this.addUniform(name, 12);
  296. }
  297. /**
  298. * Adds a Matrix 2x2 to the uniform buffer.
  299. * @param name Name of the uniform, as used in the uniform block in the shader.
  300. */
  301. addMatrix2x2(name) {
  302. this.addUniform(name, 8);
  303. }
  304. /**
  305. * Effectively creates the WebGL Uniform Buffer, once layout is completed with `addUniform`.
  306. */
  307. create() {
  308. if (this._noUBO) {
  309. return;
  310. }
  311. if (this._buffer) {
  312. return; // nothing to do
  313. }
  314. // See spec, alignment must be filled as a vec4
  315. this._fillAlignment(4);
  316. this._bufferData = new Float32Array(this._data);
  317. this._rebuild();
  318. this._needSync = true;
  319. }
  320. // The result of this method is used for debugging purpose, as part of the buffer name
  321. // It is meant to more easily know what this buffer is about when debugging
  322. // Some buffers can have a lot of uniforms (several dozens), so the method only returns the first 10 of them
  323. // (should be enough to understand what the buffer is for)
  324. _getNames() {
  325. const names = [];
  326. let i = 0;
  327. for (const name in this._uniformLocations) {
  328. names.push(name);
  329. if (++i === 10) {
  330. break;
  331. }
  332. }
  333. return names.join(",");
  334. }
  335. /** @internal */
  336. _rebuild() {
  337. if (this._noUBO || !this._bufferData) {
  338. return;
  339. }
  340. if (this._dynamic) {
  341. this._buffer = this._engine.createDynamicUniformBuffer(this._bufferData, this._name + "_UniformList:" + this._getNames());
  342. }
  343. else {
  344. this._buffer = this._engine.createUniformBuffer(this._bufferData, this._name + "_UniformList:" + this._getNames());
  345. }
  346. if (this._engine._features.trackUbosInFrame) {
  347. this._buffers.push([this._buffer, this._engine._features.checkUbosContentBeforeUpload ? this._bufferData.slice() : undefined]);
  348. this._bufferIndex = this._buffers.length - 1;
  349. this._createBufferOnWrite = false;
  350. }
  351. }
  352. /** @internal */
  353. _rebuildAfterContextLost() {
  354. if (this._engine._features.trackUbosInFrame) {
  355. this._buffers = [];
  356. this._currentFrameId = 0;
  357. }
  358. this._rebuild();
  359. }
  360. /** @internal */
  361. get _numBuffers() {
  362. return this._buffers.length;
  363. }
  364. /** @internal */
  365. get _indexBuffer() {
  366. return this._bufferIndex;
  367. }
  368. /** Gets the name of this buffer */
  369. get name() {
  370. return this._name;
  371. }
  372. /** Gets the current effect */
  373. get currentEffect() {
  374. return this._currentEffect;
  375. }
  376. _buffersEqual(buf1, buf2) {
  377. for (let i = 0; i < buf1.length; ++i) {
  378. if (buf1[i] !== buf2[i]) {
  379. return false;
  380. }
  381. }
  382. return true;
  383. }
  384. _copyBuffer(src, dst) {
  385. for (let i = 0; i < src.length; ++i) {
  386. dst[i] = src[i];
  387. }
  388. }
  389. /**
  390. * Updates the WebGL Uniform Buffer on the GPU.
  391. * If the `dynamic` flag is set to true, no cache comparison is done.
  392. * Otherwise, the buffer will be updated only if the cache differs.
  393. */
  394. update() {
  395. if (this._noUBO) {
  396. return;
  397. }
  398. this.bindUniformBuffer();
  399. if (!this._buffer) {
  400. this.create();
  401. return;
  402. }
  403. if (!this._dynamic && !this._needSync) {
  404. this._createBufferOnWrite = this._engine._features.trackUbosInFrame;
  405. return;
  406. }
  407. if (this._buffers && this._buffers.length > 1 && this._buffers[this._bufferIndex][1]) {
  408. if (this._buffersEqual(this._bufferData, this._buffers[this._bufferIndex][1])) {
  409. this._needSync = false;
  410. this._createBufferOnWrite = this._engine._features.trackUbosInFrame;
  411. return;
  412. }
  413. else {
  414. this._copyBuffer(this._bufferData, this._buffers[this._bufferIndex][1]);
  415. }
  416. }
  417. this._engine.updateUniformBuffer(this._buffer, this._bufferData);
  418. if (this._engine._features._collectUbosUpdatedInFrame) {
  419. if (!UniformBuffer._UpdatedUbosInFrame[this._name]) {
  420. UniformBuffer._UpdatedUbosInFrame[this._name] = 0;
  421. }
  422. UniformBuffer._UpdatedUbosInFrame[this._name]++;
  423. }
  424. this._needSync = false;
  425. this._createBufferOnWrite = this._engine._features.trackUbosInFrame;
  426. }
  427. _createNewBuffer() {
  428. if (this._bufferIndex + 1 < this._buffers.length) {
  429. this._bufferIndex++;
  430. this._buffer = this._buffers[this._bufferIndex][0];
  431. this._createBufferOnWrite = false;
  432. this._needSync = true;
  433. }
  434. else {
  435. this._rebuild();
  436. }
  437. }
  438. _checkNewFrame() {
  439. if (this._engine._features.trackUbosInFrame && this._currentFrameId !== this._engine.frameId) {
  440. this._currentFrameId = this._engine.frameId;
  441. this._createBufferOnWrite = false;
  442. if (this._buffers && this._buffers.length > 0) {
  443. this._needSync = this._bufferIndex !== 0;
  444. this._bufferIndex = 0;
  445. this._buffer = this._buffers[this._bufferIndex][0];
  446. }
  447. else {
  448. this._bufferIndex = -1;
  449. }
  450. }
  451. }
  452. /**
  453. * Updates the value of an uniform. The `update` method must be called afterwards to make it effective in the GPU.
  454. * @param uniformName Define the name of the uniform, as used in the uniform block in the shader.
  455. * @param data Define the flattened data
  456. * @param size Define the size of the data.
  457. */
  458. updateUniform(uniformName, data, size) {
  459. this._checkNewFrame();
  460. let location = this._uniformLocations[uniformName];
  461. if (location === undefined) {
  462. if (this._buffer) {
  463. // Cannot add an uniform if the buffer is already created
  464. Logger.Error("Cannot add an uniform after UBO has been created. uniformName=" + uniformName);
  465. return;
  466. }
  467. this.addUniform(uniformName, size);
  468. location = this._uniformLocations[uniformName];
  469. }
  470. if (!this._buffer) {
  471. this.create();
  472. }
  473. if (!this._dynamic) {
  474. // Cache for static uniform buffers
  475. let changed = false;
  476. for (let i = 0; i < size; i++) {
  477. // We are checking the matrix cache before calling updateUniform so we do not need to check it here
  478. // Hence the test for size === 16 to simply commit the matrix values
  479. if ((size === 16 && !this._engine._features.uniformBufferHardCheckMatrix) || this._bufferData[location + i] !== Math.fround(data[i])) {
  480. changed = true;
  481. if (this._createBufferOnWrite) {
  482. this._createNewBuffer();
  483. }
  484. this._bufferData[location + i] = data[i];
  485. }
  486. }
  487. this._needSync = this._needSync || changed;
  488. }
  489. else {
  490. // No cache for dynamic
  491. for (let i = 0; i < size; i++) {
  492. this._bufferData[location + i] = data[i];
  493. }
  494. }
  495. }
  496. /**
  497. * Updates the value of an uniform. The `update` method must be called afterwards to make it effective in the GPU.
  498. * @param uniformName Define the name of the uniform, as used in the uniform block in the shader.
  499. * @param data Define the flattened data
  500. * @param size Define the size of the data.
  501. */
  502. updateUniformArray(uniformName, data, size) {
  503. this._checkNewFrame();
  504. const location = this._uniformLocations[uniformName];
  505. if (location === undefined) {
  506. Logger.Error("Cannot add an uniform Array dynamically. Please, add it using addUniform and make sure that uniform buffers are supported by the current engine.");
  507. return;
  508. }
  509. if (!this._buffer) {
  510. this.create();
  511. }
  512. const arraySizes = this._uniformArraySizes[uniformName];
  513. if (!this._dynamic) {
  514. // Cache for static uniform buffers
  515. let changed = false;
  516. let countToFour = 0;
  517. let baseStride = 0;
  518. for (let i = 0; i < size; i++) {
  519. if (this._bufferData[location + baseStride * 4 + countToFour] !== Tools.FloatRound(data[i])) {
  520. changed = true;
  521. if (this._createBufferOnWrite) {
  522. this._createNewBuffer();
  523. }
  524. this._bufferData[location + baseStride * 4 + countToFour] = data[i];
  525. }
  526. countToFour++;
  527. if (countToFour === arraySizes.strideSize) {
  528. for (; countToFour < 4; countToFour++) {
  529. this._bufferData[location + baseStride * 4 + countToFour] = 0;
  530. }
  531. countToFour = 0;
  532. baseStride++;
  533. }
  534. }
  535. this._needSync = this._needSync || changed;
  536. }
  537. else {
  538. // No cache for dynamic
  539. for (let i = 0; i < size; i++) {
  540. this._bufferData[location + i] = data[i];
  541. }
  542. }
  543. }
  544. _cacheMatrix(name, matrix) {
  545. this._checkNewFrame();
  546. const cache = this._valueCache[name];
  547. const flag = matrix.updateFlag;
  548. if (cache !== undefined && cache === flag) {
  549. return false;
  550. }
  551. this._valueCache[name] = flag;
  552. return true;
  553. }
  554. // Update methods
  555. _updateMatrix3x3ForUniform(name, matrix) {
  556. // To match std140, matrix must be realigned
  557. for (let i = 0; i < 3; i++) {
  558. UniformBuffer._TempBuffer[i * 4] = matrix[i * 3];
  559. UniformBuffer._TempBuffer[i * 4 + 1] = matrix[i * 3 + 1];
  560. UniformBuffer._TempBuffer[i * 4 + 2] = matrix[i * 3 + 2];
  561. UniformBuffer._TempBuffer[i * 4 + 3] = 0.0;
  562. }
  563. this.updateUniform(name, UniformBuffer._TempBuffer, 12);
  564. }
  565. _updateMatrix3x3ForEffect(name, matrix) {
  566. this._currentEffect.setMatrix3x3(name, matrix);
  567. }
  568. _updateMatrix2x2ForEffect(name, matrix) {
  569. this._currentEffect.setMatrix2x2(name, matrix);
  570. }
  571. _updateMatrix2x2ForUniform(name, matrix) {
  572. // To match std140, matrix must be realigned
  573. for (let i = 0; i < 2; i++) {
  574. UniformBuffer._TempBuffer[i * 4] = matrix[i * 2];
  575. UniformBuffer._TempBuffer[i * 4 + 1] = matrix[i * 2 + 1];
  576. UniformBuffer._TempBuffer[i * 4 + 2] = 0.0;
  577. UniformBuffer._TempBuffer[i * 4 + 3] = 0.0;
  578. }
  579. this.updateUniform(name, UniformBuffer._TempBuffer, 8);
  580. }
  581. _updateFloatForEffect(name, x) {
  582. this._currentEffect.setFloat(name, x);
  583. }
  584. _updateFloatForUniform(name, x) {
  585. UniformBuffer._TempBuffer[0] = x;
  586. this.updateUniform(name, UniformBuffer._TempBuffer, 1);
  587. }
  588. _updateFloat2ForEffect(name, x, y, suffix = "") {
  589. this._currentEffect.setFloat2(name + suffix, x, y);
  590. }
  591. _updateFloat2ForUniform(name, x, y) {
  592. UniformBuffer._TempBuffer[0] = x;
  593. UniformBuffer._TempBuffer[1] = y;
  594. this.updateUniform(name, UniformBuffer._TempBuffer, 2);
  595. }
  596. _updateFloat3ForEffect(name, x, y, z, suffix = "") {
  597. this._currentEffect.setFloat3(name + suffix, x, y, z);
  598. }
  599. _updateFloat3ForUniform(name, x, y, z) {
  600. UniformBuffer._TempBuffer[0] = x;
  601. UniformBuffer._TempBuffer[1] = y;
  602. UniformBuffer._TempBuffer[2] = z;
  603. this.updateUniform(name, UniformBuffer._TempBuffer, 3);
  604. }
  605. _updateFloat4ForEffect(name, x, y, z, w, suffix = "") {
  606. this._currentEffect.setFloat4(name + suffix, x, y, z, w);
  607. }
  608. _updateFloat4ForUniform(name, x, y, z, w) {
  609. UniformBuffer._TempBuffer[0] = x;
  610. UniformBuffer._TempBuffer[1] = y;
  611. UniformBuffer._TempBuffer[2] = z;
  612. UniformBuffer._TempBuffer[3] = w;
  613. this.updateUniform(name, UniformBuffer._TempBuffer, 4);
  614. }
  615. _updateFloatArrayForEffect(name, array) {
  616. this._currentEffect.setFloatArray(name, array);
  617. }
  618. _updateFloatArrayForUniform(name, array) {
  619. this.updateUniformArray(name, array, array.length);
  620. }
  621. _updateArrayForEffect(name, array) {
  622. this._currentEffect.setArray(name, array);
  623. }
  624. _updateArrayForUniform(name, array) {
  625. this.updateUniformArray(name, array, array.length);
  626. }
  627. _updateIntArrayForEffect(name, array) {
  628. this._currentEffect.setIntArray(name, array);
  629. }
  630. _updateIntArrayForUniform(name, array) {
  631. UniformBuffer._TempBufferInt32View.set(array);
  632. this.updateUniformArray(name, UniformBuffer._TempBuffer, array.length);
  633. }
  634. _updateUIntArrayForEffect(name, array) {
  635. this._currentEffect.setUIntArray(name, array);
  636. }
  637. _updateUIntArrayForUniform(name, array) {
  638. UniformBuffer._TempBufferUInt32View.set(array);
  639. this.updateUniformArray(name, UniformBuffer._TempBuffer, array.length);
  640. }
  641. _updateMatrixForEffect(name, mat) {
  642. this._currentEffect.setMatrix(name, mat);
  643. }
  644. _updateMatrixForUniform(name, mat) {
  645. if (this._cacheMatrix(name, mat)) {
  646. this.updateUniform(name, mat.asArray(), 16);
  647. }
  648. }
  649. _updateMatricesForEffect(name, mat) {
  650. this._currentEffect.setMatrices(name, mat);
  651. }
  652. _updateMatricesForUniform(name, mat) {
  653. this.updateUniform(name, mat, mat.length);
  654. }
  655. _updateVector3ForEffect(name, vector) {
  656. this._currentEffect.setVector3(name, vector);
  657. }
  658. _updateVector3ForUniform(name, vector) {
  659. UniformBuffer._TempBuffer[0] = vector.x;
  660. UniformBuffer._TempBuffer[1] = vector.y;
  661. UniformBuffer._TempBuffer[2] = vector.z;
  662. this.updateUniform(name, UniformBuffer._TempBuffer, 3);
  663. }
  664. _updateVector4ForEffect(name, vector) {
  665. this._currentEffect.setVector4(name, vector);
  666. }
  667. _updateVector4ForUniform(name, vector) {
  668. UniformBuffer._TempBuffer[0] = vector.x;
  669. UniformBuffer._TempBuffer[1] = vector.y;
  670. UniformBuffer._TempBuffer[2] = vector.z;
  671. UniformBuffer._TempBuffer[3] = vector.w;
  672. this.updateUniform(name, UniformBuffer._TempBuffer, 4);
  673. }
  674. _updateColor3ForEffect(name, color, suffix = "") {
  675. this._currentEffect.setColor3(name + suffix, color);
  676. }
  677. _updateColor3ForUniform(name, color) {
  678. UniformBuffer._TempBuffer[0] = color.r;
  679. UniformBuffer._TempBuffer[1] = color.g;
  680. UniformBuffer._TempBuffer[2] = color.b;
  681. this.updateUniform(name, UniformBuffer._TempBuffer, 3);
  682. }
  683. _updateColor4ForEffect(name, color, alpha, suffix = "") {
  684. this._currentEffect.setColor4(name + suffix, color, alpha);
  685. }
  686. _updateDirectColor4ForEffect(name, color, suffix = "") {
  687. this._currentEffect.setDirectColor4(name + suffix, color);
  688. }
  689. _updateColor4ForUniform(name, color, alpha) {
  690. UniformBuffer._TempBuffer[0] = color.r;
  691. UniformBuffer._TempBuffer[1] = color.g;
  692. UniformBuffer._TempBuffer[2] = color.b;
  693. UniformBuffer._TempBuffer[3] = alpha;
  694. this.updateUniform(name, UniformBuffer._TempBuffer, 4);
  695. }
  696. _updateDirectColor4ForUniform(name, color) {
  697. UniformBuffer._TempBuffer[0] = color.r;
  698. UniformBuffer._TempBuffer[1] = color.g;
  699. UniformBuffer._TempBuffer[2] = color.b;
  700. UniformBuffer._TempBuffer[3] = color.a;
  701. this.updateUniform(name, UniformBuffer._TempBuffer, 4);
  702. }
  703. _updateIntForEffect(name, x, suffix = "") {
  704. this._currentEffect.setInt(name + suffix, x);
  705. }
  706. _updateIntForUniform(name, x) {
  707. UniformBuffer._TempBufferInt32View[0] = x;
  708. this.updateUniform(name, UniformBuffer._TempBuffer, 1);
  709. }
  710. _updateInt2ForEffect(name, x, y, suffix = "") {
  711. this._currentEffect.setInt2(name + suffix, x, y);
  712. }
  713. _updateInt2ForUniform(name, x, y) {
  714. UniformBuffer._TempBufferInt32View[0] = x;
  715. UniformBuffer._TempBufferInt32View[1] = y;
  716. this.updateUniform(name, UniformBuffer._TempBuffer, 2);
  717. }
  718. _updateInt3ForEffect(name, x, y, z, suffix = "") {
  719. this._currentEffect.setInt3(name + suffix, x, y, z);
  720. }
  721. _updateInt3ForUniform(name, x, y, z) {
  722. UniformBuffer._TempBufferInt32View[0] = x;
  723. UniformBuffer._TempBufferInt32View[1] = y;
  724. UniformBuffer._TempBufferInt32View[2] = z;
  725. this.updateUniform(name, UniformBuffer._TempBuffer, 3);
  726. }
  727. _updateInt4ForEffect(name, x, y, z, w, suffix = "") {
  728. this._currentEffect.setInt4(name + suffix, x, y, z, w);
  729. }
  730. _updateInt4ForUniform(name, x, y, z, w) {
  731. UniformBuffer._TempBufferInt32View[0] = x;
  732. UniformBuffer._TempBufferInt32View[1] = y;
  733. UniformBuffer._TempBufferInt32View[2] = z;
  734. UniformBuffer._TempBufferInt32View[3] = w;
  735. this.updateUniform(name, UniformBuffer._TempBuffer, 4);
  736. }
  737. _updateUIntForEffect(name, x, suffix = "") {
  738. this._currentEffect.setUInt(name + suffix, x);
  739. }
  740. _updateUIntForUniform(name, x) {
  741. UniformBuffer._TempBufferUInt32View[0] = x;
  742. this.updateUniform(name, UniformBuffer._TempBuffer, 1);
  743. }
  744. _updateUInt2ForEffect(name, x, y, suffix = "") {
  745. this._currentEffect.setUInt2(name + suffix, x, y);
  746. }
  747. _updateUInt2ForUniform(name, x, y) {
  748. UniformBuffer._TempBufferUInt32View[0] = x;
  749. UniformBuffer._TempBufferUInt32View[1] = y;
  750. this.updateUniform(name, UniformBuffer._TempBuffer, 2);
  751. }
  752. _updateUInt3ForEffect(name, x, y, z, suffix = "") {
  753. this._currentEffect.setUInt3(name + suffix, x, y, z);
  754. }
  755. _updateUInt3ForUniform(name, x, y, z) {
  756. UniformBuffer._TempBufferUInt32View[0] = x;
  757. UniformBuffer._TempBufferUInt32View[1] = y;
  758. UniformBuffer._TempBufferUInt32View[2] = z;
  759. this.updateUniform(name, UniformBuffer._TempBuffer, 3);
  760. }
  761. _updateUInt4ForEffect(name, x, y, z, w, suffix = "") {
  762. this._currentEffect.setUInt4(name + suffix, x, y, z, w);
  763. }
  764. _updateUInt4ForUniform(name, x, y, z, w) {
  765. UniformBuffer._TempBufferUInt32View[0] = x;
  766. UniformBuffer._TempBufferUInt32View[1] = y;
  767. UniformBuffer._TempBufferUInt32View[2] = z;
  768. UniformBuffer._TempBufferUInt32View[3] = w;
  769. this.updateUniform(name, UniformBuffer._TempBuffer, 4);
  770. }
  771. /**
  772. * Sets a sampler uniform on the effect.
  773. * @param name Define the name of the sampler.
  774. * @param texture Define the texture to set in the sampler
  775. */
  776. setTexture(name, texture) {
  777. this._currentEffect.setTexture(name, texture);
  778. }
  779. /**
  780. * Sets a sampler uniform on the effect.
  781. * @param name Define the name of the sampler.
  782. * @param texture Define the (internal) texture to set in the sampler
  783. */
  784. bindTexture(name, texture) {
  785. this._currentEffect._bindTexture(name, texture);
  786. }
  787. /**
  788. * Directly updates the value of the uniform in the cache AND on the GPU.
  789. * @param uniformName Define the name of the uniform, as used in the uniform block in the shader.
  790. * @param data Define the flattened data
  791. */
  792. updateUniformDirectly(uniformName, data) {
  793. this.updateUniform(uniformName, data, data.length);
  794. this.update();
  795. }
  796. /**
  797. * Associates an effect to this uniform buffer
  798. * @param effect Define the effect to associate the buffer to
  799. * @param name Name of the uniform block in the shader.
  800. */
  801. bindToEffect(effect, name) {
  802. this._currentEffect = effect;
  803. this._currentEffectName = name;
  804. }
  805. /**
  806. * Binds the current (GPU) buffer to the effect
  807. */
  808. bindUniformBuffer() {
  809. if (!this._noUBO && this._buffer && this._currentEffect) {
  810. this._currentEffect.bindUniformBuffer(this._buffer, this._currentEffectName);
  811. }
  812. }
  813. /**
  814. * Dissociates the current effect from this uniform buffer
  815. */
  816. unbindEffect() {
  817. this._currentEffect = undefined;
  818. this._currentEffectName = undefined;
  819. }
  820. /**
  821. * Sets the current state of the class (_bufferIndex, _buffer) to point to the data buffer passed in parameter if this buffer is one of the buffers handled by the class (meaning if it can be found in the _buffers array)
  822. * This method is meant to be able to update a buffer at any time: just call setDataBuffer to set the class in the right state, call some updateXXX methods and then call udpate() => that will update the GPU buffer on the graphic card
  823. * @param dataBuffer buffer to look for
  824. * @returns true if the buffer has been found and the class internal state points to it, else false
  825. */
  826. setDataBuffer(dataBuffer) {
  827. if (!this._buffers) {
  828. return this._buffer === dataBuffer;
  829. }
  830. for (let b = 0; b < this._buffers.length; ++b) {
  831. const buffer = this._buffers[b];
  832. if (buffer[0] === dataBuffer) {
  833. this._bufferIndex = b;
  834. this._buffer = dataBuffer;
  835. this._createBufferOnWrite = false;
  836. this._currentEffect = undefined;
  837. return true;
  838. }
  839. }
  840. return false;
  841. }
  842. /**
  843. * Disposes the uniform buffer.
  844. */
  845. dispose() {
  846. if (this._noUBO) {
  847. return;
  848. }
  849. const uniformBuffers = this._engine._uniformBuffers;
  850. const index = uniformBuffers.indexOf(this);
  851. if (index !== -1) {
  852. uniformBuffers[index] = uniformBuffers[uniformBuffers.length - 1];
  853. uniformBuffers.pop();
  854. }
  855. if (this._engine._features.trackUbosInFrame && this._buffers) {
  856. for (let i = 0; i < this._buffers.length; ++i) {
  857. const buffer = this._buffers[i][0];
  858. this._engine._releaseBuffer(buffer);
  859. }
  860. }
  861. else if (this._buffer && this._engine._releaseBuffer(this._buffer)) {
  862. this._buffer = null;
  863. }
  864. }
  865. }
  866. /** @internal */
  867. UniformBuffer._UpdatedUbosInFrame = {};
  868. // Pool for avoiding memory leaks
  869. UniformBuffer._MAX_UNIFORM_SIZE = 256;
  870. UniformBuffer._TempBuffer = new Float32Array(UniformBuffer._MAX_UNIFORM_SIZE);
  871. UniformBuffer._TempBufferInt32View = new Int32Array(UniformBuffer._TempBuffer.buffer);
  872. UniformBuffer._TempBufferUInt32View = new Uint32Array(UniformBuffer._TempBuffer.buffer);
  873. //# sourceMappingURL=uniformBuffer.js.map