renderTargetWrapper.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. import { InternalTextureSource } from "../Materials/Textures/internalTexture.js";
  2. /**
  3. * Wrapper around a render target (either single or multi textures)
  4. */
  5. export class RenderTargetWrapper {
  6. /**
  7. * Gets the depth/stencil texture (if created by a createDepthStencilTexture() call)
  8. */
  9. get depthStencilTexture() {
  10. return this._depthStencilTexture;
  11. }
  12. /**
  13. * Indicates if the depth/stencil texture has a stencil aspect
  14. */
  15. get depthStencilTextureWithStencil() {
  16. return this._depthStencilTextureWithStencil;
  17. }
  18. /**
  19. * Defines if the render target wrapper is for a cube texture or if false a 2d texture
  20. */
  21. get isCube() {
  22. return this._isCube;
  23. }
  24. /**
  25. * Defines if the render target wrapper is for a single or multi target render wrapper
  26. */
  27. get isMulti() {
  28. return this._isMulti;
  29. }
  30. /**
  31. * Defines if the render target wrapper is for a single or an array of textures
  32. */
  33. get is2DArray() {
  34. return this.layers > 0;
  35. }
  36. /**
  37. * Defines if the render target wrapper is for a 3D texture
  38. */
  39. get is3D() {
  40. return this.depth > 0;
  41. }
  42. /**
  43. * Gets the size of the render target wrapper (used for cubes, as width=height in this case)
  44. */
  45. get size() {
  46. return this.width;
  47. }
  48. /**
  49. * Gets the width of the render target wrapper
  50. */
  51. get width() {
  52. return this._size.width || this._size;
  53. }
  54. /**
  55. * Gets the height of the render target wrapper
  56. */
  57. get height() {
  58. return this._size.height || this._size;
  59. }
  60. /**
  61. * Gets the number of layers of the render target wrapper (only used if is2DArray is true and wrapper is not a multi render target)
  62. */
  63. get layers() {
  64. return this._size.layers || 0;
  65. }
  66. /**
  67. * Gets the depth of the render target wrapper (only used if is3D is true and wrapper is not a multi render target)
  68. */
  69. get depth() {
  70. return this._size.depth || 0;
  71. }
  72. /**
  73. * Gets the render texture. If this is a multi render target, gets the first texture
  74. */
  75. get texture() {
  76. return this._textures?.[0] ?? null;
  77. }
  78. /**
  79. * Gets the list of render textures. If we are not in a multi render target, the list will be null (use the texture getter instead)
  80. */
  81. get textures() {
  82. return this._textures;
  83. }
  84. /**
  85. * Gets the face indices that correspond to the list of render textures. If we are not in a multi render target, the list will be null
  86. */
  87. get faceIndices() {
  88. return this._faceIndices;
  89. }
  90. /**
  91. * Gets the layer indices that correspond to the list of render textures. If we are not in a multi render target, the list will be null
  92. */
  93. get layerIndices() {
  94. return this._layerIndices;
  95. }
  96. /**
  97. * Gets the sample count of the render target
  98. */
  99. get samples() {
  100. return this._samples;
  101. }
  102. /**
  103. * Sets the sample count of the render target
  104. * @param value sample count
  105. * @param initializeBuffers If set to true, the engine will make an initializing call to drawBuffers (only used when isMulti=true).
  106. * @param force true to force calling the update sample count engine function even if the current sample count is equal to value
  107. * @returns the sample count that has been set
  108. */
  109. setSamples(value, initializeBuffers = true, force = false) {
  110. if (this.samples === value && !force) {
  111. return value;
  112. }
  113. const result = this._isMulti
  114. ? this._engine.updateMultipleRenderTargetTextureSampleCount(this, value, initializeBuffers)
  115. : this._engine.updateRenderTargetTextureSampleCount(this, value);
  116. this._samples = value;
  117. return result;
  118. }
  119. /**
  120. * Initializes the render target wrapper
  121. * @param isMulti true if the wrapper is a multi render target
  122. * @param isCube true if the wrapper should render to a cube texture
  123. * @param size size of the render target (width/height/layers)
  124. * @param engine engine used to create the render target
  125. * @param label defines the label to use for the wrapper (for debugging purpose only)
  126. */
  127. constructor(isMulti, isCube, size, engine, label) {
  128. this._textures = null;
  129. this._faceIndices = null;
  130. this._layerIndices = null;
  131. /** @internal */
  132. this._samples = 1;
  133. /** @internal */
  134. this._attachments = null;
  135. /** @internal */
  136. this._generateStencilBuffer = false;
  137. /** @internal */
  138. this._generateDepthBuffer = false;
  139. /** @internal */
  140. this._depthStencilTextureWithStencil = false;
  141. this._isMulti = isMulti;
  142. this._isCube = isCube;
  143. this._size = size;
  144. this._engine = engine;
  145. this._depthStencilTexture = null;
  146. this.label = label;
  147. }
  148. /**
  149. * Sets the render target texture(s)
  150. * @param textures texture(s) to set
  151. */
  152. setTextures(textures) {
  153. if (Array.isArray(textures)) {
  154. this._textures = textures;
  155. }
  156. else if (textures) {
  157. this._textures = [textures];
  158. }
  159. else {
  160. this._textures = null;
  161. }
  162. }
  163. /**
  164. * Set a texture in the textures array
  165. * @param texture The texture to set
  166. * @param index The index in the textures array to set
  167. * @param disposePrevious If this function should dispose the previous texture
  168. */
  169. setTexture(texture, index = 0, disposePrevious = true) {
  170. if (!this._textures) {
  171. this._textures = [];
  172. }
  173. if (this._textures[index] === texture) {
  174. return;
  175. }
  176. if (this._textures[index] && disposePrevious) {
  177. this._textures[index].dispose();
  178. }
  179. this._textures[index] = texture;
  180. }
  181. /**
  182. * Sets the layer and face indices of every render target texture bound to each color attachment
  183. * @param layers The layers of each texture to be set
  184. * @param faces The faces of each texture to be set
  185. */
  186. setLayerAndFaceIndices(layers, faces) {
  187. this._layerIndices = layers;
  188. this._faceIndices = faces;
  189. }
  190. /**
  191. * Sets the layer and face indices of a texture in the textures array that should be bound to each color attachment
  192. * @param index The index of the texture in the textures array to modify
  193. * @param layer The layer of the texture to be set
  194. * @param face The face of the texture to be set
  195. */
  196. setLayerAndFaceIndex(index = 0, layer, face) {
  197. if (!this._layerIndices) {
  198. this._layerIndices = [];
  199. }
  200. if (!this._faceIndices) {
  201. this._faceIndices = [];
  202. }
  203. if (layer !== undefined && layer >= 0) {
  204. this._layerIndices[index] = layer;
  205. }
  206. if (face !== undefined && face >= 0) {
  207. this._faceIndices[index] = face;
  208. }
  209. }
  210. /**
  211. * Creates the depth/stencil texture
  212. * @param comparisonFunction Comparison function to use for the texture
  213. * @param bilinearFiltering true if bilinear filtering should be used when sampling the texture
  214. * @param generateStencil true if the stencil aspect should also be created
  215. * @param samples sample count to use when creating the texture
  216. * @param format format of the depth texture
  217. * @param label defines the label to use for the texture (for debugging purpose only)
  218. * @returns the depth/stencil created texture
  219. */
  220. createDepthStencilTexture(comparisonFunction = 0, bilinearFiltering = true, generateStencil = false, samples = 1, format = 14, label) {
  221. this._depthStencilTexture?.dispose();
  222. this._depthStencilTextureWithStencil = generateStencil;
  223. this._depthStencilTextureLabel = label;
  224. this._depthStencilTexture = this._engine.createDepthStencilTexture(this._size, {
  225. bilinearFiltering,
  226. comparisonFunction,
  227. generateStencil,
  228. isCube: this._isCube,
  229. samples,
  230. depthTextureFormat: format,
  231. label,
  232. }, this);
  233. return this._depthStencilTexture;
  234. }
  235. /**
  236. * @deprecated Use shareDepth instead
  237. * @param renderTarget Destination renderTarget
  238. */
  239. _shareDepth(renderTarget) {
  240. this.shareDepth(renderTarget);
  241. }
  242. /**
  243. * Shares the depth buffer of this render target with another render target.
  244. * @param renderTarget Destination renderTarget
  245. */
  246. shareDepth(renderTarget) {
  247. if (this._depthStencilTexture) {
  248. if (renderTarget._depthStencilTexture) {
  249. renderTarget._depthStencilTexture.dispose();
  250. }
  251. renderTarget._depthStencilTexture = this._depthStencilTexture;
  252. renderTarget._depthStencilTextureWithStencil = this._depthStencilTextureWithStencil;
  253. this._depthStencilTexture.incrementReferences();
  254. }
  255. }
  256. /**
  257. * @internal
  258. */
  259. _swapAndDie(target) {
  260. if (this.texture) {
  261. this.texture._swapAndDie(target);
  262. }
  263. this._textures = null;
  264. this.dispose(true);
  265. }
  266. _cloneRenderTargetWrapper() {
  267. let rtw = null;
  268. if (this._isMulti) {
  269. const textureArray = this.textures;
  270. if (textureArray && textureArray.length > 0) {
  271. let generateDepthTexture = false;
  272. let textureCount = textureArray.length;
  273. let depthTextureFormat = -1;
  274. const lastTextureSource = textureArray[textureArray.length - 1]._source;
  275. if (lastTextureSource === InternalTextureSource.Depth || lastTextureSource === InternalTextureSource.DepthStencil) {
  276. generateDepthTexture = true;
  277. depthTextureFormat = textureArray[textureArray.length - 1].format;
  278. textureCount--;
  279. }
  280. const samplingModes = [];
  281. const types = [];
  282. const formats = [];
  283. const targetTypes = [];
  284. const faceIndex = [];
  285. const layerIndex = [];
  286. const layerCounts = [];
  287. const internalTexture2Index = {};
  288. for (let i = 0; i < textureCount; ++i) {
  289. const texture = textureArray[i];
  290. samplingModes.push(texture.samplingMode);
  291. types.push(texture.type);
  292. formats.push(texture.format);
  293. const index = internalTexture2Index[texture.uniqueId];
  294. if (index !== undefined) {
  295. targetTypes.push(-1);
  296. layerCounts.push(0);
  297. }
  298. else {
  299. internalTexture2Index[texture.uniqueId] = i;
  300. if (texture.is2DArray) {
  301. targetTypes.push(35866);
  302. layerCounts.push(texture.depth);
  303. }
  304. else if (texture.isCube) {
  305. targetTypes.push(34067);
  306. layerCounts.push(0);
  307. } /*else if (texture.isCubeArray) {
  308. targetTypes.push(3735928559);
  309. layerCounts.push(texture.depth);
  310. }*/
  311. else if (texture.is3D) {
  312. targetTypes.push(32879);
  313. layerCounts.push(texture.depth);
  314. }
  315. else {
  316. targetTypes.push(3553);
  317. layerCounts.push(0);
  318. }
  319. }
  320. if (this._faceIndices) {
  321. faceIndex.push(this._faceIndices[i] ?? 0);
  322. }
  323. if (this._layerIndices) {
  324. layerIndex.push(this._layerIndices[i] ?? 0);
  325. }
  326. }
  327. const optionsMRT = {
  328. samplingModes,
  329. generateMipMaps: textureArray[0].generateMipMaps,
  330. generateDepthBuffer: this._generateDepthBuffer,
  331. generateStencilBuffer: this._generateStencilBuffer,
  332. generateDepthTexture,
  333. depthTextureFormat,
  334. types,
  335. formats,
  336. textureCount,
  337. targetTypes,
  338. faceIndex,
  339. layerIndex,
  340. layerCounts,
  341. label: this.label,
  342. };
  343. const size = {
  344. width: this.width,
  345. height: this.height,
  346. depth: this.depth,
  347. };
  348. rtw = this._engine.createMultipleRenderTarget(size, optionsMRT);
  349. for (let i = 0; i < textureCount; ++i) {
  350. if (targetTypes[i] !== -1) {
  351. continue;
  352. }
  353. const index = internalTexture2Index[textureArray[i].uniqueId];
  354. rtw.setTexture(rtw.textures[index], i);
  355. }
  356. }
  357. }
  358. else {
  359. const options = {};
  360. options.generateDepthBuffer = this._generateDepthBuffer;
  361. options.generateMipMaps = this.texture?.generateMipMaps ?? false;
  362. options.generateStencilBuffer = this._generateStencilBuffer;
  363. options.samplingMode = this.texture?.samplingMode;
  364. options.type = this.texture?.type;
  365. options.format = this.texture?.format;
  366. options.noColorAttachment = !this._textures;
  367. options.label = this.label;
  368. if (this.isCube) {
  369. rtw = this._engine.createRenderTargetCubeTexture(this.width, options);
  370. }
  371. else {
  372. const size = {
  373. width: this.width,
  374. height: this.height,
  375. layers: this.is2DArray || this.is3D ? this.texture?.depth : undefined,
  376. };
  377. rtw = this._engine.createRenderTargetTexture(size, options);
  378. }
  379. if (rtw.texture) {
  380. rtw.texture.isReady = true;
  381. }
  382. }
  383. return rtw;
  384. }
  385. _swapRenderTargetWrapper(target) {
  386. if (this._textures && target._textures) {
  387. for (let i = 0; i < this._textures.length; ++i) {
  388. this._textures[i]._swapAndDie(target._textures[i], false);
  389. target._textures[i].isReady = true;
  390. }
  391. }
  392. if (this._depthStencilTexture && target._depthStencilTexture) {
  393. this._depthStencilTexture._swapAndDie(target._depthStencilTexture);
  394. target._depthStencilTexture.isReady = true;
  395. }
  396. this._textures = null;
  397. this._depthStencilTexture = null;
  398. }
  399. /** @internal */
  400. _rebuild() {
  401. const rtw = this._cloneRenderTargetWrapper();
  402. if (!rtw) {
  403. return;
  404. }
  405. if (this._depthStencilTexture) {
  406. const samplingMode = this._depthStencilTexture.samplingMode;
  407. const format = this._depthStencilTexture.format;
  408. const bilinear = samplingMode === 2 ||
  409. samplingMode === 3 ||
  410. samplingMode === 11;
  411. rtw.createDepthStencilTexture(this._depthStencilTexture._comparisonFunction, bilinear, this._depthStencilTextureWithStencil, this._depthStencilTexture.samples, format, this._depthStencilTextureLabel);
  412. }
  413. if (this.samples > 1) {
  414. rtw.setSamples(this.samples);
  415. }
  416. rtw._swapRenderTargetWrapper(this);
  417. rtw.dispose();
  418. }
  419. /**
  420. * Releases the internal render textures
  421. */
  422. releaseTextures() {
  423. if (this._textures) {
  424. for (let i = 0; i < this._textures?.length ?? 0; ++i) {
  425. this._textures[i].dispose();
  426. }
  427. }
  428. this._textures = null;
  429. }
  430. /**
  431. * Disposes the whole render target wrapper
  432. * @param disposeOnlyFramebuffers true if only the frame buffers should be released (used for the WebGL engine). If false, all the textures will also be released
  433. */
  434. dispose(disposeOnlyFramebuffers = false) {
  435. if (!disposeOnlyFramebuffers) {
  436. this._depthStencilTexture?.dispose();
  437. this._depthStencilTexture = null;
  438. this.releaseTextures();
  439. }
  440. this._engine._releaseRenderTargetWrapper(this);
  441. }
  442. }
  443. //# sourceMappingURL=renderTargetWrapper.js.map