engine.multiRender.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. import { InternalTexture, InternalTextureSource } from "../../Materials/Textures/internalTexture.js";
  2. import { Logger } from "../../Misc/logger.js";
  3. import { ThinEngine } from "../thinEngine.js";
  4. ThinEngine.prototype.restoreSingleAttachment = function () {
  5. const gl = this._gl;
  6. this.bindAttachments([gl.BACK]);
  7. };
  8. ThinEngine.prototype.restoreSingleAttachmentForRenderTarget = function () {
  9. const gl = this._gl;
  10. this.bindAttachments([gl.COLOR_ATTACHMENT0]);
  11. };
  12. ThinEngine.prototype.buildTextureLayout = function (textureStatus) {
  13. const gl = this._gl;
  14. const result = [];
  15. for (let i = 0; i < textureStatus.length; i++) {
  16. if (textureStatus[i]) {
  17. result.push(gl["COLOR_ATTACHMENT" + i]);
  18. }
  19. else {
  20. result.push(gl.NONE);
  21. }
  22. }
  23. return result;
  24. };
  25. ThinEngine.prototype.bindAttachments = function (attachments) {
  26. const gl = this._gl;
  27. gl.drawBuffers(attachments);
  28. };
  29. ThinEngine.prototype.unBindMultiColorAttachmentFramebuffer = function (rtWrapper, disableGenerateMipMaps = false, onBeforeUnbind) {
  30. this._currentRenderTarget = null;
  31. // If MSAA, we need to bitblt back to main texture
  32. const gl = this._gl;
  33. const attachments = rtWrapper._attachments;
  34. const count = attachments.length;
  35. if (rtWrapper._MSAAFramebuffer) {
  36. gl.bindFramebuffer(gl.READ_FRAMEBUFFER, rtWrapper._MSAAFramebuffer);
  37. gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, rtWrapper._framebuffer);
  38. for (let i = 0; i < count; i++) {
  39. const texture = rtWrapper.textures[i];
  40. for (let j = 0; j < count; j++) {
  41. attachments[j] = gl.NONE;
  42. }
  43. attachments[i] = gl[this.webGLVersion > 1 ? "COLOR_ATTACHMENT" + i : "COLOR_ATTACHMENT" + i + "_WEBGL"];
  44. gl.readBuffer(attachments[i]);
  45. gl.drawBuffers(attachments);
  46. gl.blitFramebuffer(0, 0, texture.width, texture.height, 0, 0, texture.width, texture.height, gl.COLOR_BUFFER_BIT, gl.NEAREST);
  47. }
  48. for (let i = 0; i < count; i++) {
  49. attachments[i] = gl[this.webGLVersion > 1 ? "COLOR_ATTACHMENT" + i : "COLOR_ATTACHMENT" + i + "_WEBGL"];
  50. }
  51. gl.drawBuffers(attachments);
  52. }
  53. for (let i = 0; i < count; i++) {
  54. const texture = rtWrapper.textures[i];
  55. if (texture?.generateMipMaps && !disableGenerateMipMaps && !texture?.isCube && !texture?.is3D) {
  56. this._bindTextureDirectly(gl.TEXTURE_2D, texture, true);
  57. gl.generateMipmap(gl.TEXTURE_2D);
  58. this._bindTextureDirectly(gl.TEXTURE_2D, null);
  59. }
  60. }
  61. if (onBeforeUnbind) {
  62. if (rtWrapper._MSAAFramebuffer) {
  63. // Bind the correct framebuffer
  64. this._bindUnboundFramebuffer(rtWrapper._framebuffer);
  65. }
  66. onBeforeUnbind();
  67. }
  68. this._bindUnboundFramebuffer(null);
  69. };
  70. ThinEngine.prototype.createMultipleRenderTarget = function (size, options, initializeBuffers = true) {
  71. let generateMipMaps = false;
  72. let generateDepthBuffer = true;
  73. let generateStencilBuffer = false;
  74. let generateDepthTexture = false;
  75. let depthTextureFormat = 15;
  76. let textureCount = 1;
  77. const defaultType = 0;
  78. const defaultSamplingMode = 3;
  79. const defaultUseSRGBBuffer = false;
  80. const defaultFormat = 5;
  81. const defaultTarget = 3553;
  82. let types = [];
  83. let samplingModes = [];
  84. let useSRGBBuffers = [];
  85. let formats = [];
  86. let targets = [];
  87. let faceIndex = [];
  88. let layerIndex = [];
  89. let layers = [];
  90. const rtWrapper = this._createHardwareRenderTargetWrapper(true, false, size);
  91. if (options !== undefined) {
  92. generateMipMaps = options.generateMipMaps === undefined ? false : options.generateMipMaps;
  93. generateDepthBuffer = options.generateDepthBuffer === undefined ? true : options.generateDepthBuffer;
  94. generateStencilBuffer = options.generateStencilBuffer === undefined ? false : options.generateStencilBuffer;
  95. generateDepthTexture = options.generateDepthTexture === undefined ? false : options.generateDepthTexture;
  96. textureCount = options.textureCount || 1;
  97. if (options.types) {
  98. types = options.types;
  99. }
  100. if (options.samplingModes) {
  101. samplingModes = options.samplingModes;
  102. }
  103. if (options.useSRGBBuffers) {
  104. useSRGBBuffers = options.useSRGBBuffers;
  105. }
  106. if (options.formats) {
  107. formats = options.formats;
  108. }
  109. if (options.targetTypes) {
  110. targets = options.targetTypes;
  111. }
  112. if (options.faceIndex) {
  113. faceIndex = options.faceIndex;
  114. }
  115. if (options.layerIndex) {
  116. layerIndex = options.layerIndex;
  117. }
  118. if (options.layerCounts) {
  119. layers = options.layerCounts;
  120. }
  121. if (this.webGLVersion > 1 &&
  122. (options.depthTextureFormat === 13 ||
  123. options.depthTextureFormat === 17 ||
  124. options.depthTextureFormat === 16 ||
  125. options.depthTextureFormat === 14 ||
  126. options.depthTextureFormat === 18)) {
  127. depthTextureFormat = options.depthTextureFormat;
  128. }
  129. }
  130. rtWrapper.label = options?.label ?? "MultiRenderTargetWrapper";
  131. const gl = this._gl;
  132. // Create the framebuffer
  133. const framebuffer = gl.createFramebuffer();
  134. this._bindUnboundFramebuffer(framebuffer);
  135. const width = size.width || size;
  136. const height = size.height || size;
  137. const textures = [];
  138. const attachments = [];
  139. const useStencilTexture = this.webGLVersion > 1 &&
  140. generateDepthTexture &&
  141. (options.depthTextureFormat === 13 ||
  142. options.depthTextureFormat === 17 ||
  143. options.depthTextureFormat === 18);
  144. const depthStencilBuffer = this._setupFramebufferDepthAttachments(!useStencilTexture && generateStencilBuffer, !generateDepthTexture && generateDepthBuffer, width, height);
  145. rtWrapper._framebuffer = framebuffer;
  146. rtWrapper._depthStencilBuffer = depthStencilBuffer;
  147. rtWrapper._generateDepthBuffer = !generateDepthTexture && generateDepthBuffer;
  148. rtWrapper._generateStencilBuffer = !useStencilTexture && generateStencilBuffer;
  149. rtWrapper._attachments = attachments;
  150. for (let i = 0; i < textureCount; i++) {
  151. let samplingMode = samplingModes[i] || defaultSamplingMode;
  152. let type = types[i] || defaultType;
  153. let useSRGBBuffer = useSRGBBuffers[i] || defaultUseSRGBBuffer;
  154. const format = formats[i] || defaultFormat;
  155. const target = targets[i] || defaultTarget;
  156. const layerCount = layers[i] ?? 1;
  157. if (type === 1 && !this._caps.textureFloatLinearFiltering) {
  158. // if floating point linear (gl.FLOAT) then force to NEAREST_SAMPLINGMODE
  159. samplingMode = 1;
  160. }
  161. else if (type === 2 && !this._caps.textureHalfFloatLinearFiltering) {
  162. // if floating point linear (HALF_FLOAT) then force to NEAREST_SAMPLINGMODE
  163. samplingMode = 1;
  164. }
  165. const filters = this._getSamplingParameters(samplingMode, generateMipMaps);
  166. if (type === 1 && !this._caps.textureFloat) {
  167. type = 0;
  168. Logger.Warn("Float textures are not supported. Render target forced to TEXTURETYPE_UNSIGNED_BYTE type");
  169. }
  170. useSRGBBuffer = useSRGBBuffer && this._caps.supportSRGBBuffers && (this.webGLVersion > 1 || this.isWebGPU);
  171. const isWebGL2 = this.webGLVersion > 1;
  172. const attachment = gl[isWebGL2 ? "COLOR_ATTACHMENT" + i : "COLOR_ATTACHMENT" + i + "_WEBGL"];
  173. attachments.push(attachment);
  174. if (target === -1) {
  175. continue;
  176. }
  177. const texture = new InternalTexture(this, InternalTextureSource.MultiRenderTarget);
  178. textures[i] = texture;
  179. gl.activeTexture(gl["TEXTURE" + i]);
  180. gl.bindTexture(target, texture._hardwareTexture.underlyingResource);
  181. gl.texParameteri(target, gl.TEXTURE_MAG_FILTER, filters.mag);
  182. gl.texParameteri(target, gl.TEXTURE_MIN_FILTER, filters.min);
  183. gl.texParameteri(target, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  184. gl.texParameteri(target, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  185. const internalSizedFormat = this._getRGBABufferInternalSizedFormat(type, format, useSRGBBuffer);
  186. const internalFormat = this._getInternalFormat(format);
  187. const webGLTextureType = this._getWebGLTextureType(type);
  188. if (isWebGL2 && (target === 35866 || target === 32879)) {
  189. if (target === 35866) {
  190. texture.is2DArray = true;
  191. }
  192. else {
  193. texture.is3D = true;
  194. }
  195. texture.baseDepth = texture.depth = layerCount;
  196. gl.texImage3D(target, 0, internalSizedFormat, width, height, layerCount, 0, internalFormat, webGLTextureType, null);
  197. }
  198. else if (target === 34067) {
  199. // We have to generate all faces to complete the framebuffer
  200. for (let i = 0; i < 6; i++) {
  201. gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internalSizedFormat, width, height, 0, internalFormat, webGLTextureType, null);
  202. }
  203. texture.isCube = true;
  204. }
  205. else {
  206. gl.texImage2D(gl.TEXTURE_2D, 0, internalSizedFormat, width, height, 0, internalFormat, webGLTextureType, null);
  207. }
  208. if (generateMipMaps) {
  209. gl.generateMipmap(target);
  210. }
  211. // Unbind
  212. this._bindTextureDirectly(target, null);
  213. texture.baseWidth = width;
  214. texture.baseHeight = height;
  215. texture.width = width;
  216. texture.height = height;
  217. texture.isReady = true;
  218. texture.samples = 1;
  219. texture.generateMipMaps = generateMipMaps;
  220. texture.samplingMode = samplingMode;
  221. texture.type = type;
  222. texture._useSRGBBuffer = useSRGBBuffer;
  223. texture.format = format;
  224. this._internalTexturesCache.push(texture);
  225. }
  226. if (generateDepthTexture && this._caps.depthTextureExtension) {
  227. // Depth texture
  228. const depthTexture = new InternalTexture(this, InternalTextureSource.Depth);
  229. let depthTextureType = 5;
  230. let glDepthTextureInternalFormat = gl.DEPTH_COMPONENT16;
  231. let glDepthTextureFormat = gl.DEPTH_COMPONENT;
  232. let glDepthTextureType = gl.UNSIGNED_SHORT;
  233. let glDepthTextureAttachment = gl.DEPTH_ATTACHMENT;
  234. if (this.webGLVersion < 2) {
  235. glDepthTextureInternalFormat = gl.DEPTH_COMPONENT;
  236. }
  237. else {
  238. if (depthTextureFormat === 14) {
  239. depthTextureType = 1;
  240. glDepthTextureType = gl.FLOAT;
  241. glDepthTextureInternalFormat = gl.DEPTH_COMPONENT32F;
  242. }
  243. else if (depthTextureFormat === 18) {
  244. depthTextureType = 0;
  245. glDepthTextureType = gl.FLOAT_32_UNSIGNED_INT_24_8_REV;
  246. glDepthTextureInternalFormat = gl.DEPTH32F_STENCIL8;
  247. glDepthTextureFormat = gl.DEPTH_STENCIL;
  248. glDepthTextureAttachment = gl.DEPTH_STENCIL_ATTACHMENT;
  249. }
  250. else if (depthTextureFormat === 16) {
  251. depthTextureType = 0;
  252. glDepthTextureType = gl.UNSIGNED_INT;
  253. glDepthTextureInternalFormat = gl.DEPTH_COMPONENT24;
  254. glDepthTextureAttachment = gl.DEPTH_ATTACHMENT;
  255. }
  256. else if (depthTextureFormat === 13 || depthTextureFormat === 17) {
  257. depthTextureType = 12;
  258. glDepthTextureType = gl.UNSIGNED_INT_24_8;
  259. glDepthTextureInternalFormat = gl.DEPTH24_STENCIL8;
  260. glDepthTextureFormat = gl.DEPTH_STENCIL;
  261. glDepthTextureAttachment = gl.DEPTH_STENCIL_ATTACHMENT;
  262. }
  263. }
  264. gl.activeTexture(gl.TEXTURE0);
  265. gl.bindTexture(gl.TEXTURE_2D, depthTexture._hardwareTexture.underlyingResource);
  266. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
  267. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
  268. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  269. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  270. gl.texImage2D(gl.TEXTURE_2D, 0, glDepthTextureInternalFormat, width, height, 0, glDepthTextureFormat, glDepthTextureType, null);
  271. gl.framebufferTexture2D(gl.FRAMEBUFFER, glDepthTextureAttachment, gl.TEXTURE_2D, depthTexture._hardwareTexture.underlyingResource, 0);
  272. depthTexture.baseWidth = width;
  273. depthTexture.baseHeight = height;
  274. depthTexture.width = width;
  275. depthTexture.height = height;
  276. depthTexture.isReady = true;
  277. depthTexture.samples = 1;
  278. depthTexture.generateMipMaps = generateMipMaps;
  279. depthTexture.samplingMode = 1;
  280. depthTexture.format = depthTextureFormat;
  281. depthTexture.type = depthTextureType;
  282. textures[textureCount] = depthTexture;
  283. this._internalTexturesCache.push(depthTexture);
  284. }
  285. rtWrapper.setTextures(textures);
  286. if (initializeBuffers) {
  287. gl.drawBuffers(attachments);
  288. }
  289. this._bindUnboundFramebuffer(null);
  290. rtWrapper.setLayerAndFaceIndices(layerIndex, faceIndex);
  291. this.resetTextureCache();
  292. return rtWrapper;
  293. };
  294. ThinEngine.prototype.updateMultipleRenderTargetTextureSampleCount = function (rtWrapper, samples, initializeBuffers = true) {
  295. if (this.webGLVersion < 2 || !rtWrapper || !rtWrapper.texture) {
  296. return 1;
  297. }
  298. if (rtWrapper.samples === samples) {
  299. return samples;
  300. }
  301. const count = rtWrapper._attachments.length;
  302. if (count === 0) {
  303. return 1;
  304. }
  305. const gl = this._gl;
  306. samples = Math.min(samples, this.getCaps().maxMSAASamples);
  307. // Dispose previous render buffers
  308. const useDepthStencil = !!rtWrapper._depthStencilBuffer;
  309. if (useDepthStencil) {
  310. gl.deleteRenderbuffer(rtWrapper._depthStencilBuffer);
  311. rtWrapper._depthStencilBuffer = null;
  312. }
  313. if (rtWrapper._MSAAFramebuffer) {
  314. gl.deleteFramebuffer(rtWrapper._MSAAFramebuffer);
  315. rtWrapper._MSAAFramebuffer = null;
  316. }
  317. if (samples > 1 && typeof gl.renderbufferStorageMultisample === "function") {
  318. const framebuffer = gl.createFramebuffer();
  319. if (!framebuffer) {
  320. throw new Error("Unable to create multi sampled framebuffer");
  321. }
  322. rtWrapper._MSAAFramebuffer = framebuffer;
  323. this._bindUnboundFramebuffer(framebuffer);
  324. const attachments = [];
  325. for (let i = 0; i < count; i++) {
  326. const texture = rtWrapper.textures[i];
  327. const hardwareTexture = texture._hardwareTexture;
  328. hardwareTexture.releaseMSAARenderBuffers();
  329. }
  330. for (let i = 0; i < count; i++) {
  331. const texture = rtWrapper.textures[i];
  332. const hardwareTexture = texture._hardwareTexture;
  333. const attachment = gl[this.webGLVersion > 1 ? "COLOR_ATTACHMENT" + i : "COLOR_ATTACHMENT" + i + "_WEBGL"];
  334. const colorRenderbuffer = this._createRenderBuffer(texture.width, texture.height, samples, -1 /* not used */, this._getRGBABufferInternalSizedFormat(texture.type, texture.format, texture._useSRGBBuffer), attachment);
  335. if (!colorRenderbuffer) {
  336. throw new Error("Unable to create multi sampled framebuffer");
  337. }
  338. hardwareTexture.addMSAARenderBuffer(colorRenderbuffer);
  339. texture.samples = samples;
  340. attachments.push(attachment);
  341. }
  342. if (initializeBuffers) {
  343. gl.drawBuffers(attachments);
  344. }
  345. }
  346. else {
  347. this._bindUnboundFramebuffer(rtWrapper._framebuffer);
  348. }
  349. if (useDepthStencil) {
  350. rtWrapper._depthStencilBuffer = this._setupFramebufferDepthAttachments(rtWrapper._generateStencilBuffer, rtWrapper._generateDepthBuffer, rtWrapper.texture.width, rtWrapper.texture.height, samples);
  351. }
  352. this._bindUnboundFramebuffer(null);
  353. return samples;
  354. };
  355. //# sourceMappingURL=engine.multiRender.js.map