UNPKG

13.4 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5var constants = require('@pixi/constants');
6var extensions = require('@pixi/extensions');
7var math = require('@pixi/math');
8var settings = require('@pixi/settings');
9var Framebuffer = require('./Framebuffer.js');
10var GLFramebuffer = require('./GLFramebuffer.js');
11
12const tempRectangle = new math.Rectangle();
13class 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}
355FramebufferSystem.extension = {
356 type: extensions.ExtensionType.RendererSystem,
357 name: "framebuffer"
358};
359extensions.extensions.add(FramebufferSystem);
360
361exports.FramebufferSystem = FramebufferSystem;
362//# sourceMappingURL=FramebufferSystem.js.map