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