1 | "use strict";
|
2 | var constants = require("@pixi/constants"), extensions = require("@pixi/extensions"), math = require("@pixi/math"), settings = require("@pixi/settings"), Framebuffer = require("./Framebuffer.js"), GLFramebuffer = require("./GLFramebuffer.js");
|
3 | const tempRectangle = new math.Rectangle();
|
4 | class FramebufferSystem {
|
5 | |
6 |
|
7 |
|
8 | constructor(renderer) {
|
9 | this.renderer = renderer, this.managedFramebuffers = [], this.unknownFramebuffer = new Framebuffer.Framebuffer(10, 10), this.msaaSamples = null;
|
10 | }
|
11 |
|
12 | contextChange() {
|
13 | this.disposeAll(!0);
|
14 | const gl = this.gl = this.renderer.gl;
|
15 | if (this.CONTEXT_UID = this.renderer.CONTEXT_UID, this.current = this.unknownFramebuffer, this.viewport = new math.Rectangle(), this.hasMRT = !0, this.writeDepthTexture = !0, this.renderer.context.webGLVersion === 1) {
|
16 | let nativeDrawBuffersExtension = this.renderer.context.extensions.drawBuffers, nativeDepthTextureExtension = this.renderer.context.extensions.depthTexture;
|
17 | settings.settings.PREFER_ENV === constants.ENV.WEBGL_LEGACY && (nativeDrawBuffersExtension = null, nativeDepthTextureExtension = null), nativeDrawBuffersExtension ? gl.drawBuffers = (activeTextures) => nativeDrawBuffersExtension.drawBuffersWEBGL(activeTextures) : (this.hasMRT = !1, gl.drawBuffers = () => {
|
18 | }), nativeDepthTextureExtension || (this.writeDepthTexture = !1);
|
19 | } else
|
20 | this.msaaSamples = gl.getInternalformatParameter(gl.RENDERBUFFER, gl.RGBA8, gl.SAMPLES);
|
21 | }
|
22 | |
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 | bind(framebuffer, frame, mipLevel = 0) {
|
29 | const { gl } = this;
|
30 | if (framebuffer) {
|
31 | const fbo = framebuffer.glFramebuffers[this.CONTEXT_UID] || this.initFramebuffer(framebuffer);
|
32 | this.current !== framebuffer && (this.current = framebuffer, gl.bindFramebuffer(gl.FRAMEBUFFER, fbo.framebuffer)), fbo.mipLevel !== mipLevel && (framebuffer.dirtyId++, framebuffer.dirtyFormat++, fbo.mipLevel = mipLevel), fbo.dirtyId !== framebuffer.dirtyId && (fbo.dirtyId = framebuffer.dirtyId, fbo.dirtyFormat !== framebuffer.dirtyFormat ? (fbo.dirtyFormat = framebuffer.dirtyFormat, fbo.dirtySize = framebuffer.dirtySize, this.updateFramebuffer(framebuffer, mipLevel)) : fbo.dirtySize !== framebuffer.dirtySize && (fbo.dirtySize = framebuffer.dirtySize, this.resizeFramebuffer(framebuffer)));
|
33 | for (let i = 0; i < framebuffer.colorTextures.length; i++) {
|
34 | const tex = framebuffer.colorTextures[i];
|
35 | this.renderer.texture.unbind(tex.parentTextureArray || tex);
|
36 | }
|
37 | if (framebuffer.depthTexture && this.renderer.texture.unbind(framebuffer.depthTexture), frame) {
|
38 | const mipWidth = frame.width >> mipLevel, mipHeight = frame.height >> mipLevel, scale = mipWidth / frame.width;
|
39 | this.setViewport(
|
40 | frame.x * scale,
|
41 | frame.y * scale,
|
42 | mipWidth,
|
43 | mipHeight
|
44 | );
|
45 | } else {
|
46 | const mipWidth = framebuffer.width >> mipLevel, mipHeight = framebuffer.height >> mipLevel;
|
47 | this.setViewport(0, 0, mipWidth, mipHeight);
|
48 | }
|
49 | } else
|
50 | this.current && (this.current = null, gl.bindFramebuffer(gl.FRAMEBUFFER, null)), frame ? this.setViewport(frame.x, frame.y, frame.width, frame.height) : this.setViewport(0, 0, this.renderer.width, this.renderer.height);
|
51 | }
|
52 | |
53 |
|
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 | setViewport(x, y, width, height) {
|
60 | const v = this.viewport;
|
61 | x = Math.round(x), y = Math.round(y), width = Math.round(width), height = Math.round(height), (v.width !== width || v.height !== height || v.x !== x || v.y !== y) && (v.x = x, v.y = y, v.width = width, v.height = height, this.gl.viewport(x, y, width, height));
|
62 | }
|
63 | |
64 |
|
65 |
|
66 |
|
67 | get size() {
|
68 | return this.current ? { x: 0, y: 0, width: this.current.width, height: this.current.height } : { x: 0, y: 0, width: this.renderer.width, height: this.renderer.height };
|
69 | }
|
70 | |
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 | clear(r, g, b, a, mask = constants.BUFFER_BITS.COLOR | constants.BUFFER_BITS.DEPTH) {
|
80 | const { gl } = this;
|
81 | gl.clearColor(r, g, b, a), gl.clear(mask);
|
82 | }
|
83 | |
84 |
|
85 |
|
86 |
|
87 |
|
88 |
|
89 | initFramebuffer(framebuffer) {
|
90 | const { gl } = this, fbo = new GLFramebuffer.GLFramebuffer(gl.createFramebuffer());
|
91 | return fbo.multisample = this.detectSamples(framebuffer.multisample), framebuffer.glFramebuffers[this.CONTEXT_UID] = fbo, this.managedFramebuffers.push(framebuffer), framebuffer.disposeRunner.add(this), fbo;
|
92 | }
|
93 | |
94 |
|
95 |
|
96 |
|
97 |
|
98 | resizeFramebuffer(framebuffer) {
|
99 | const { gl } = this, fbo = framebuffer.glFramebuffers[this.CONTEXT_UID];
|
100 | if (fbo.stencil) {
|
101 | gl.bindRenderbuffer(gl.RENDERBUFFER, fbo.stencil);
|
102 | let stencilFormat;
|
103 | this.renderer.context.webGLVersion === 1 ? stencilFormat = gl.DEPTH_STENCIL : framebuffer.depth && framebuffer.stencil ? stencilFormat = gl.DEPTH24_STENCIL8 : framebuffer.depth ? stencilFormat = gl.DEPTH_COMPONENT24 : stencilFormat = gl.STENCIL_INDEX8, fbo.msaaBuffer ? gl.renderbufferStorageMultisample(
|
104 | gl.RENDERBUFFER,
|
105 | fbo.multisample,
|
106 | stencilFormat,
|
107 | framebuffer.width,
|
108 | framebuffer.height
|
109 | ) : gl.renderbufferStorage(gl.RENDERBUFFER, stencilFormat, framebuffer.width, framebuffer.height);
|
110 | }
|
111 | const colorTextures = framebuffer.colorTextures;
|
112 | let count = colorTextures.length;
|
113 | gl.drawBuffers || (count = Math.min(count, 1));
|
114 | for (let i = 0; i < count; i++) {
|
115 | const texture = colorTextures[i], parentTexture = texture.parentTextureArray || texture;
|
116 | this.renderer.texture.bind(parentTexture, 0), i === 0 && fbo.msaaBuffer && (gl.bindRenderbuffer(gl.RENDERBUFFER, fbo.msaaBuffer), gl.renderbufferStorageMultisample(
|
117 | gl.RENDERBUFFER,
|
118 | fbo.multisample,
|
119 | parentTexture._glTextures[this.CONTEXT_UID].internalFormat,
|
120 | framebuffer.width,
|
121 | framebuffer.height
|
122 | ));
|
123 | }
|
124 | framebuffer.depthTexture && this.writeDepthTexture && this.renderer.texture.bind(framebuffer.depthTexture, 0);
|
125 | }
|
126 | |
127 |
|
128 |
|
129 |
|
130 |
|
131 |
|
132 | updateFramebuffer(framebuffer, mipLevel) {
|
133 | const { gl } = this, fbo = framebuffer.glFramebuffers[this.CONTEXT_UID], colorTextures = framebuffer.colorTextures;
|
134 | let count = colorTextures.length;
|
135 | gl.drawBuffers || (count = Math.min(count, 1)), fbo.multisample > 1 && this.canMultisampleFramebuffer(framebuffer) ? fbo.msaaBuffer = fbo.msaaBuffer || gl.createRenderbuffer() : fbo.msaaBuffer && (gl.deleteRenderbuffer(fbo.msaaBuffer), fbo.msaaBuffer = null, fbo.blitFramebuffer && (fbo.blitFramebuffer.dispose(), fbo.blitFramebuffer = null));
|
136 | const activeTextures = [];
|
137 | for (let i = 0; i < count; i++) {
|
138 | const texture = colorTextures[i], parentTexture = texture.parentTextureArray || texture;
|
139 | this.renderer.texture.bind(parentTexture, 0), i === 0 && fbo.msaaBuffer ? (gl.bindRenderbuffer(gl.RENDERBUFFER, fbo.msaaBuffer), gl.renderbufferStorageMultisample(
|
140 | gl.RENDERBUFFER,
|
141 | fbo.multisample,
|
142 | parentTexture._glTextures[this.CONTEXT_UID].internalFormat,
|
143 | framebuffer.width,
|
144 | framebuffer.height
|
145 | ), gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, fbo.msaaBuffer)) : (gl.framebufferTexture2D(
|
146 | gl.FRAMEBUFFER,
|
147 | gl.COLOR_ATTACHMENT0 + i,
|
148 | texture.target,
|
149 | parentTexture._glTextures[this.CONTEXT_UID].texture,
|
150 | mipLevel
|
151 | ), activeTextures.push(gl.COLOR_ATTACHMENT0 + i));
|
152 | }
|
153 | if (activeTextures.length > 1 && gl.drawBuffers(activeTextures), framebuffer.depthTexture && this.writeDepthTexture) {
|
154 | const depthTexture = framebuffer.depthTexture;
|
155 | this.renderer.texture.bind(depthTexture, 0), gl.framebufferTexture2D(
|
156 | gl.FRAMEBUFFER,
|
157 | gl.DEPTH_ATTACHMENT,
|
158 | gl.TEXTURE_2D,
|
159 | depthTexture._glTextures[this.CONTEXT_UID].texture,
|
160 | mipLevel
|
161 | );
|
162 | }
|
163 | if ((framebuffer.stencil || framebuffer.depth) && !(framebuffer.depthTexture && this.writeDepthTexture)) {
|
164 | fbo.stencil = fbo.stencil || gl.createRenderbuffer();
|
165 | let stencilAttachment, stencilFormat;
|
166 | this.renderer.context.webGLVersion === 1 ? (stencilAttachment = gl.DEPTH_STENCIL_ATTACHMENT, stencilFormat = gl.DEPTH_STENCIL) : framebuffer.depth && framebuffer.stencil ? (stencilAttachment = gl.DEPTH_STENCIL_ATTACHMENT, stencilFormat = gl.DEPTH24_STENCIL8) : framebuffer.depth ? (stencilAttachment = gl.DEPTH_ATTACHMENT, stencilFormat = gl.DEPTH_COMPONENT24) : (stencilAttachment = gl.STENCIL_ATTACHMENT, stencilFormat = gl.STENCIL_INDEX8), gl.bindRenderbuffer(gl.RENDERBUFFER, fbo.stencil), fbo.msaaBuffer ? gl.renderbufferStorageMultisample(
|
167 | gl.RENDERBUFFER,
|
168 | fbo.multisample,
|
169 | stencilFormat,
|
170 | framebuffer.width,
|
171 | framebuffer.height
|
172 | ) : gl.renderbufferStorage(gl.RENDERBUFFER, stencilFormat, framebuffer.width, framebuffer.height), gl.framebufferRenderbuffer(gl.FRAMEBUFFER, stencilAttachment, gl.RENDERBUFFER, fbo.stencil);
|
173 | } else
|
174 | fbo.stencil && (gl.deleteRenderbuffer(fbo.stencil), fbo.stencil = null);
|
175 | }
|
176 | |
177 |
|
178 |
|
179 |
|
180 | canMultisampleFramebuffer(framebuffer) {
|
181 | return this.renderer.context.webGLVersion !== 1 && framebuffer.colorTextures.length <= 1 && !framebuffer.depthTexture;
|
182 | }
|
183 | |
184 |
|
185 |
|
186 |
|
187 |
|
188 | detectSamples(samples) {
|
189 | const { msaaSamples } = this;
|
190 | let res = constants.MSAA_QUALITY.NONE;
|
191 | if (samples <= 1 || msaaSamples === null)
|
192 | return res;
|
193 | for (let i = 0; i < msaaSamples.length; i++)
|
194 | if (msaaSamples[i] <= samples) {
|
195 | res = msaaSamples[i];
|
196 | break;
|
197 | }
|
198 | return res === 1 && (res = constants.MSAA_QUALITY.NONE), res;
|
199 | }
|
200 | |
201 |
|
202 |
|
203 |
|
204 |
|
205 |
|
206 |
|
207 |
|
208 |
|
209 |
|
210 |
|
211 | blit(framebuffer, sourcePixels, destPixels) {
|
212 | const { current, renderer, gl, CONTEXT_UID } = this;
|
213 | if (renderer.context.webGLVersion !== 2 || !current)
|
214 | return;
|
215 | const fbo = current.glFramebuffers[CONTEXT_UID];
|
216 | if (!fbo)
|
217 | return;
|
218 | if (!framebuffer) {
|
219 | if (!fbo.msaaBuffer)
|
220 | return;
|
221 | const colorTexture = current.colorTextures[0];
|
222 | if (!colorTexture)
|
223 | return;
|
224 | fbo.blitFramebuffer || (fbo.blitFramebuffer = new Framebuffer.Framebuffer(current.width, current.height), fbo.blitFramebuffer.addColorTexture(0, colorTexture)), framebuffer = fbo.blitFramebuffer, framebuffer.colorTextures[0] !== colorTexture && (framebuffer.colorTextures[0] = colorTexture, framebuffer.dirtyId++, framebuffer.dirtyFormat++), (framebuffer.width !== current.width || framebuffer.height !== current.height) && (framebuffer.width = current.width, framebuffer.height = current.height, framebuffer.dirtyId++, framebuffer.dirtySize++);
|
225 | }
|
226 | sourcePixels || (sourcePixels = tempRectangle, sourcePixels.width = current.width, sourcePixels.height = current.height), destPixels || (destPixels = sourcePixels);
|
227 | const sameSize = sourcePixels.width === destPixels.width && sourcePixels.height === destPixels.height;
|
228 | this.bind(framebuffer), gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo.framebuffer), gl.blitFramebuffer(
|
229 | sourcePixels.left,
|
230 | sourcePixels.top,
|
231 | sourcePixels.right,
|
232 | sourcePixels.bottom,
|
233 | destPixels.left,
|
234 | destPixels.top,
|
235 | destPixels.right,
|
236 | destPixels.bottom,
|
237 | gl.COLOR_BUFFER_BIT,
|
238 | sameSize ? gl.NEAREST : gl.LINEAR
|
239 | ), gl.bindFramebuffer(gl.READ_FRAMEBUFFER, framebuffer.glFramebuffers[this.CONTEXT_UID].framebuffer);
|
240 | }
|
241 | |
242 |
|
243 |
|
244 |
|
245 |
|
246 | disposeFramebuffer(framebuffer, contextLost) {
|
247 | const fbo = framebuffer.glFramebuffers[this.CONTEXT_UID], gl = this.gl;
|
248 | if (!fbo)
|
249 | return;
|
250 | delete framebuffer.glFramebuffers[this.CONTEXT_UID];
|
251 | const index = this.managedFramebuffers.indexOf(framebuffer);
|
252 | index >= 0 && this.managedFramebuffers.splice(index, 1), framebuffer.disposeRunner.remove(this), contextLost || (gl.deleteFramebuffer(fbo.framebuffer), fbo.msaaBuffer && gl.deleteRenderbuffer(fbo.msaaBuffer), fbo.stencil && gl.deleteRenderbuffer(fbo.stencil)), fbo.blitFramebuffer && this.disposeFramebuffer(fbo.blitFramebuffer, contextLost);
|
253 | }
|
254 | |
255 |
|
256 |
|
257 |
|
258 | disposeAll(contextLost) {
|
259 | const list = this.managedFramebuffers;
|
260 | this.managedFramebuffers = [];
|
261 | for (let i = 0; i < list.length; i++)
|
262 | this.disposeFramebuffer(list[i], contextLost);
|
263 | }
|
264 | |
265 |
|
266 |
|
267 |
|
268 |
|
269 |
|
270 |
|
271 | forceStencil() {
|
272 | const framebuffer = this.current;
|
273 | if (!framebuffer)
|
274 | return;
|
275 | const fbo = framebuffer.glFramebuffers[this.CONTEXT_UID];
|
276 | if (!fbo || fbo.stencil && framebuffer.stencil)
|
277 | return;
|
278 | framebuffer.stencil = !0;
|
279 | const w = framebuffer.width, h = framebuffer.height, gl = this.gl, stencil = fbo.stencil = gl.createRenderbuffer();
|
280 | gl.bindRenderbuffer(gl.RENDERBUFFER, stencil);
|
281 | let stencilAttachment, stencilFormat;
|
282 | this.renderer.context.webGLVersion === 1 ? (stencilAttachment = gl.DEPTH_STENCIL_ATTACHMENT, stencilFormat = gl.DEPTH_STENCIL) : framebuffer.depth ? (stencilAttachment = gl.DEPTH_STENCIL_ATTACHMENT, stencilFormat = gl.DEPTH24_STENCIL8) : (stencilAttachment = gl.STENCIL_ATTACHMENT, stencilFormat = gl.STENCIL_INDEX8), fbo.msaaBuffer ? gl.renderbufferStorageMultisample(gl.RENDERBUFFER, fbo.multisample, stencilFormat, w, h) : gl.renderbufferStorage(gl.RENDERBUFFER, stencilFormat, w, h), gl.framebufferRenderbuffer(gl.FRAMEBUFFER, stencilAttachment, gl.RENDERBUFFER, stencil);
|
283 | }
|
284 |
|
285 | reset() {
|
286 | this.current = this.unknownFramebuffer, this.viewport = new math.Rectangle();
|
287 | }
|
288 | destroy() {
|
289 | this.renderer = null;
|
290 | }
|
291 | }
|
292 | FramebufferSystem.extension = {
|
293 | type: extensions.ExtensionType.RendererSystem,
|
294 | name: "framebuffer"
|
295 | };
|
296 | extensions.extensions.add(FramebufferSystem);
|
297 | exports.FramebufferSystem = FramebufferSystem;
|
298 |
|