webGLRenderTargetWrapper.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. import { RenderTargetWrapper } from "../renderTargetWrapper.js";
  2. /** @internal */
  3. export class WebGLRenderTargetWrapper extends RenderTargetWrapper {
  4. constructor(isMulti, isCube, size, engine, context) {
  5. super(isMulti, isCube, size, engine);
  6. /**
  7. * @internal
  8. */
  9. this._framebuffer = null;
  10. /**
  11. * @internal
  12. */
  13. this._depthStencilBuffer = null;
  14. // eslint-disable-next-line @typescript-eslint/naming-convention
  15. /**
  16. * @internal
  17. */
  18. // eslint-disable-next-line @typescript-eslint/naming-convention
  19. this._MSAAFramebuffer = null;
  20. // Multiview
  21. /**
  22. * @internal
  23. */
  24. this._colorTextureArray = null;
  25. /**
  26. * @internal
  27. */
  28. this._depthStencilTextureArray = null;
  29. /**
  30. * @internal
  31. */
  32. this._disposeOnlyFramebuffers = false;
  33. /**
  34. * @internal
  35. */
  36. this._currentLOD = 0;
  37. this._context = context;
  38. }
  39. _cloneRenderTargetWrapper() {
  40. let rtw = null;
  41. if (this._colorTextureArray && this._depthStencilTextureArray) {
  42. rtw = this._engine.createMultiviewRenderTargetTexture(this.width, this.height);
  43. rtw.texture.isReady = true;
  44. }
  45. else {
  46. rtw = super._cloneRenderTargetWrapper();
  47. }
  48. return rtw;
  49. }
  50. _swapRenderTargetWrapper(target) {
  51. super._swapRenderTargetWrapper(target);
  52. target._framebuffer = this._framebuffer;
  53. target._depthStencilBuffer = this._depthStencilBuffer;
  54. target._MSAAFramebuffer = this._MSAAFramebuffer;
  55. target._colorTextureArray = this._colorTextureArray;
  56. target._depthStencilTextureArray = this._depthStencilTextureArray;
  57. this._framebuffer = this._depthStencilBuffer = this._MSAAFramebuffer = this._colorTextureArray = this._depthStencilTextureArray = null;
  58. }
  59. /**
  60. * Creates the depth/stencil texture
  61. * @param comparisonFunction Comparison function to use for the texture
  62. * @param bilinearFiltering true if bilinear filtering should be used when sampling the texture
  63. * @param generateStencil true if the stencil aspect should also be created
  64. * @param samples sample count to use when creating the texture
  65. * @param format format of the depth texture
  66. * @param label defines the label to use for the texture (for debugging purpose only)
  67. * @returns the depth/stencil created texture
  68. */
  69. createDepthStencilTexture(comparisonFunction = 0, bilinearFiltering = true, generateStencil = false, samples = 1, format = 14, label) {
  70. if (this._depthStencilBuffer) {
  71. const engine = this._engine;
  72. // Dispose previous depth/stencil render buffers and clear the corresponding attachment.
  73. // Next time this framebuffer is bound, the new depth/stencil texture will be attached.
  74. const currentFrameBuffer = engine._currentFramebuffer;
  75. const gl = this._context;
  76. engine._bindUnboundFramebuffer(this._framebuffer);
  77. gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, null);
  78. gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, null);
  79. gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, null);
  80. engine._bindUnboundFramebuffer(currentFrameBuffer);
  81. gl.deleteRenderbuffer(this._depthStencilBuffer);
  82. this._depthStencilBuffer = null;
  83. }
  84. return super.createDepthStencilTexture(comparisonFunction, bilinearFiltering, generateStencil, samples, format, label);
  85. }
  86. /**
  87. * Shares the depth buffer of this render target with another render target.
  88. * @param renderTarget Destination renderTarget
  89. */
  90. shareDepth(renderTarget) {
  91. super.shareDepth(renderTarget);
  92. const gl = this._context;
  93. const depthbuffer = this._depthStencilBuffer;
  94. const framebuffer = renderTarget._MSAAFramebuffer || renderTarget._framebuffer;
  95. const engine = this._engine;
  96. if (renderTarget._depthStencilBuffer && renderTarget._depthStencilBuffer !== depthbuffer) {
  97. gl.deleteRenderbuffer(renderTarget._depthStencilBuffer);
  98. }
  99. renderTarget._depthStencilBuffer = depthbuffer;
  100. const attachment = renderTarget._generateStencilBuffer ? gl.DEPTH_STENCIL_ATTACHMENT : gl.DEPTH_ATTACHMENT;
  101. engine._bindUnboundFramebuffer(framebuffer);
  102. gl.framebufferRenderbuffer(gl.FRAMEBUFFER, attachment, gl.RENDERBUFFER, depthbuffer);
  103. engine._bindUnboundFramebuffer(null);
  104. }
  105. /**
  106. * Binds a texture to this render target on a specific attachment
  107. * @param texture The texture to bind to the framebuffer
  108. * @param attachmentIndex Index of the attachment
  109. * @param faceIndexOrLayer The face or layer of the texture to render to in case of cube texture or array texture
  110. * @param lodLevel defines the lod level to bind to the frame buffer
  111. */
  112. _bindTextureRenderTarget(texture, attachmentIndex = 0, faceIndexOrLayer, lodLevel = 0) {
  113. if (!texture._hardwareTexture) {
  114. return;
  115. }
  116. const framebuffer = this._framebuffer;
  117. const engine = this._engine;
  118. const currentFB = engine._currentFramebuffer;
  119. engine._bindUnboundFramebuffer(framebuffer);
  120. if (engine.webGLVersion > 1) {
  121. const gl = this._context;
  122. const attachment = gl["COLOR_ATTACHMENT" + attachmentIndex];
  123. if (texture.is2DArray || texture.is3D) {
  124. faceIndexOrLayer = faceIndexOrLayer ?? this.layerIndices?.[attachmentIndex] ?? 0;
  125. gl.framebufferTextureLayer(gl.FRAMEBUFFER, attachment, texture._hardwareTexture.underlyingResource, lodLevel, faceIndexOrLayer);
  126. }
  127. else if (texture.isCube) {
  128. // if face index is not specified, try to query it from faceIndices
  129. // default is face 0
  130. faceIndexOrLayer = faceIndexOrLayer ?? this.faceIndices?.[attachmentIndex] ?? 0;
  131. gl.framebufferTexture2D(gl.FRAMEBUFFER, attachment, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndexOrLayer, texture._hardwareTexture.underlyingResource, lodLevel);
  132. }
  133. else {
  134. gl.framebufferTexture2D(gl.FRAMEBUFFER, attachment, gl.TEXTURE_2D, texture._hardwareTexture.underlyingResource, lodLevel);
  135. }
  136. }
  137. else {
  138. // Default behavior (WebGL)
  139. const gl = this._context;
  140. const attachment = gl["COLOR_ATTACHMENT" + attachmentIndex + "_WEBGL"];
  141. const target = faceIndexOrLayer !== undefined ? gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndexOrLayer : gl.TEXTURE_2D;
  142. gl.framebufferTexture2D(gl.FRAMEBUFFER, attachment, target, texture._hardwareTexture.underlyingResource, lodLevel);
  143. }
  144. engine._bindUnboundFramebuffer(currentFB);
  145. }
  146. /**
  147. * Set a texture in the textures array
  148. * @param texture the texture to set
  149. * @param index the index in the textures array to set
  150. * @param disposePrevious If this function should dispose the previous texture
  151. */
  152. setTexture(texture, index = 0, disposePrevious = true) {
  153. super.setTexture(texture, index, disposePrevious);
  154. this._bindTextureRenderTarget(texture, index);
  155. }
  156. /**
  157. * Sets the layer and face indices of every render target texture
  158. * @param layers The layer of the texture to be set (make negative to not modify)
  159. * @param faces The face of the texture to be set (make negative to not modify)
  160. */
  161. setLayerAndFaceIndices(layers, faces) {
  162. super.setLayerAndFaceIndices(layers, faces);
  163. if (!this.textures || !this.layerIndices || !this.faceIndices) {
  164. return;
  165. }
  166. // the length of this._attachments is the right one as it does not count the depth texture, in case we generated it
  167. const textureCount = this._attachments?.length ?? this.textures.length;
  168. for (let index = 0; index < textureCount; index++) {
  169. const texture = this.textures[index];
  170. if (!texture) {
  171. // The target type was probably -1 at creation time and setTexture has not been called yet for this index
  172. continue;
  173. }
  174. if (texture.is2DArray || texture.is3D) {
  175. this._bindTextureRenderTarget(texture, index, this.layerIndices[index]);
  176. }
  177. else if (texture.isCube) {
  178. this._bindTextureRenderTarget(texture, index, this.faceIndices[index]);
  179. }
  180. else {
  181. this._bindTextureRenderTarget(texture, index);
  182. }
  183. }
  184. }
  185. /**
  186. * Set the face and layer indices of a texture in the textures array
  187. * @param index The index of the texture in the textures array to modify
  188. * @param layer The layer of the texture to be set
  189. * @param face The face of the texture to be set
  190. */
  191. setLayerAndFaceIndex(index = 0, layer, face) {
  192. super.setLayerAndFaceIndex(index, layer, face);
  193. if (!this.textures || !this.layerIndices || !this.faceIndices) {
  194. return;
  195. }
  196. const texture = this.textures[index];
  197. if (texture.is2DArray || texture.is3D) {
  198. this._bindTextureRenderTarget(this.textures[index], index, this.layerIndices[index]);
  199. }
  200. else if (texture.isCube) {
  201. this._bindTextureRenderTarget(this.textures[index], index, this.faceIndices[index]);
  202. }
  203. }
  204. dispose(disposeOnlyFramebuffers = this._disposeOnlyFramebuffers) {
  205. const gl = this._context;
  206. if (!disposeOnlyFramebuffers) {
  207. if (this._colorTextureArray) {
  208. this._context.deleteTexture(this._colorTextureArray);
  209. this._colorTextureArray = null;
  210. }
  211. if (this._depthStencilTextureArray) {
  212. this._context.deleteTexture(this._depthStencilTextureArray);
  213. this._depthStencilTextureArray = null;
  214. }
  215. }
  216. if (this._framebuffer) {
  217. gl.deleteFramebuffer(this._framebuffer);
  218. this._framebuffer = null;
  219. }
  220. if (this._depthStencilBuffer) {
  221. gl.deleteRenderbuffer(this._depthStencilBuffer);
  222. this._depthStencilBuffer = null;
  223. }
  224. if (this._MSAAFramebuffer) {
  225. gl.deleteFramebuffer(this._MSAAFramebuffer);
  226. this._MSAAFramebuffer = null;
  227. }
  228. super.dispose(disposeOnlyFramebuffers);
  229. }
  230. }
  231. //# sourceMappingURL=webGLRenderTargetWrapper.js.map