@swf2es/context3d 0.1.20 → 0.1.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,13 @@
1
1
  import { INDIRECT_BANK } from "../agal.js";
2
- import { compressedFormat, FRAGMENT_CONSTANTS, MOST_BACK_BUFFER, MOST_CUBE, profileLimits, SAMPLER_FILTERS, SAMPLER_MIPS, SAMPLER_SLOTS, SAMPLER_WRAPS, ScissorBoundsError, screenPixels, TEXEL_BYTES, TextureBindingError, VERTEX_CONSTANTS, VERTEX_FORMATS, VERTEX_SLOTS, VertexOffsetError, } from "../backend.js";
2
+ import { compressedFormat, FRAGMENT_CONSTANTS, MOST_CUBE, profileLimits, SAMPLER_FILTERS, SAMPLER_MIPS, SAMPLER_SLOTS, SAMPLER_WRAPS, ScissorBoundsError, screenPixels, TEXEL_BYTES, TextureBindingError, VERTEX_CONSTANTS, VERTEX_FORMATS, VERTEX_SLOTS, VertexOffsetError, } from "../backend.js";
3
3
  import { GlState } from "../device/state.js";
4
4
  import { blockBytes } from "../dxt.js";
5
5
  import { Context3DError } from "../errors.js";
6
- import { uploadBuffer, uploadBufferBytes, } from "./buffers.js";
6
+ import { configureBackBuffer, presentBackBuffer, unconfigureBackBuffer } from "./back-buffer.js";
7
+ import { allocateBuffer } from "./buffers.js";
7
8
  import { resourceLimits } from "./limits.js";
8
9
  import { createCopyProgram, uploadProgram, } from "./programs.js";
10
+ import { readBackBuffer } from "./readback.js";
9
11
  import { BLEND_FUNCTIONS, DEPTH_FUNCTIONS, range, STENCIL_FUNCTIONS, StencilState, } from "./state.js";
10
12
  import { allocateMultisample, deleteMultisample, resolveTarget, selectSamples, targetFramebuffer, } from "./targets.js";
11
13
  import { storageFormat, uploadCompressedLevel, uploadTexture, uploadTextureBytes, } from "./textures.js";
@@ -41,9 +43,14 @@ function constants(registers) {
41
43
  writing: 0,
42
44
  };
43
45
  }
44
- /** An owned WebGL2 context, deliberately independent of the 2D renderer. */
46
+ /**
47
+ * An owned WebGL2 context, deliberately independent of the 2D renderer. Its members that are
48
+ * neither private nor Context3D's are for back-buffer.ts, buffers.ts and readback.ts, which
49
+ * hold parts of it as functions over it.
50
+ */
45
51
  export class WebGLContext3D {
46
52
  gl;
53
+ /** @internal */
47
54
  drawState;
48
55
  width = 0;
49
56
  height = 0;
@@ -51,15 +58,22 @@ export class WebGLContext3D {
51
58
  * The back buffer's storage: its size, or less where the GPU allows less. The SWF still
52
59
  * sees the size it asked for, drawn at this one and stretched to it when presented.
53
60
  */
61
+ /** @internal */
54
62
  drawnWidth = 0;
63
+ /** @internal */
55
64
  drawnHeight = 0;
65
+ /** @internal */
56
66
  gpuMost = null;
57
67
  disposed = false;
58
68
  samplerFormats = true;
59
69
  profile = "baseline";
70
+ /** @internal */
60
71
  buffers = new Map();
72
+ /** @internal */
61
73
  vertexBuffers = 0;
74
+ /** @internal */
62
75
  bufferBytes = 0;
76
+ /** @internal */
63
77
  vertexBufferBytes = 0;
64
78
  programs = new Map();
65
79
  textures = new Map();
@@ -72,6 +86,7 @@ export class WebGLContext3D {
72
86
  copy2D = null;
73
87
  copyCube = null;
74
88
  targetSamples = new Int8Array(10).fill(-1);
89
+ /** @internal */
75
90
  renderTexture = null;
76
91
  renderDepth = false;
77
92
  renderFace = 0;
@@ -90,19 +105,30 @@ export class WebGLContext3D {
90
105
  anisotropy;
91
106
  s3tc;
92
107
  maxAnisotropy = 1;
108
+ /** @internal */
93
109
  vertices = new Array(VERTEX_SLOTS).fill(null);
94
110
  enabledAttributes = 0;
111
+ /** @internal */
95
112
  indexBuffer = null;
113
+ /** @internal */
96
114
  texturesApplied = new Uint8Array(SAMPLER_SLOTS);
97
115
  selected = null;
116
+ /** @internal */
98
117
  framebuffer = null;
118
+ /** @internal */
99
119
  texture = null;
120
+ /** @internal */
100
121
  resolveFramebuffer = null;
122
+ /** @internal */
101
123
  colorBuffer = null;
124
+ /** @internal */
102
125
  resolveDirty = false;
126
+ /** @internal */
103
127
  depthBuffer = null;
128
+ /** @internal */
104
129
  antiAlias = 0;
105
130
  /** The back buffer's pixels to a CSS pixel and to a scissor rectangle's unit. */
131
+ /** @internal */
106
132
  scale = 1;
107
133
  depthWrite = true;
108
134
  depthCompare = "less";
@@ -117,6 +143,7 @@ export class WebGLContext3D {
117
143
  stencilReference = 0;
118
144
  stencilRead = 255;
119
145
  stencilWrite = 255;
146
+ /** @internal */
120
147
  scissor = false;
121
148
  scissorLeft = 0;
122
149
  scissorTop = 0;
@@ -125,9 +152,13 @@ export class WebGLContext3D {
125
152
  scissorOutside = false;
126
153
  vertexConstants = constants(VERTEX_CONSTANTS);
127
154
  fragmentConstants = constants(FRAGMENT_CONSTANTS);
155
+ /** @internal */
128
156
  pixels = new Uint8Array(0);
157
+ /** @internal */
129
158
  topDown = new Uint8Array(0);
159
+ /** @internal */
130
160
  vao;
161
+ /** @internal */
131
162
  limits;
132
163
  dxtEncoder = null;
133
164
  /** The host's whole-level encoder; a refusal retains the TypeScript path. */
@@ -162,11 +193,13 @@ export class WebGLContext3D {
162
193
  gl.frontFace(gl.CW);
163
194
  gl.disable(gl.DITHER);
164
195
  }
196
+ /** @internal */
165
197
  alive() {
166
198
  if (this.disposed || this.gl.isContextLost()) {
167
199
  throw new Context3DError("disposed", "Context3D experiment: context disposed or lost");
168
200
  }
169
201
  }
202
+ /** @internal */
170
203
  target(back = false, discardColor = false) {
171
204
  this.alive();
172
205
  if (!this.framebuffer) {
@@ -189,164 +222,16 @@ export class WebGLContext3D {
189
222
  this.drawState.viewport(0, 0, texture?.width ?? this.drawnWidth, texture?.height ?? this.drawnHeight);
190
223
  }
191
224
  /** Temporary attachments and separate READ/DRAW bindings bypass the hot target cache. */
225
+ /** @internal */
192
226
  bindFramebuffer(target, framebuffer) {
193
227
  this.drawState.forget();
194
228
  this.gl.bindFramebuffer(target, framebuffer);
195
229
  }
196
230
  configure(width, height, depth = false, antiAlias = 0, scale = 1) {
197
- this.alive();
198
- range(32, width - 32, MOST_BACK_BUFFER);
199
- range(32, height - 32, MOST_BACK_BUFFER);
200
- if (this.renderTexture) {
201
- throw new Context3DError("operation", "Context3D experiment: resize while rendering to texture");
202
- }
203
- // AIR preserves color, depth and bindings when the request is unchanged.
204
- // Shadow passes can issue this every frame when returning to the back buffer.
205
- if (this.framebuffer &&
206
- width === this.width &&
207
- height === this.height &&
208
- depth === (this.depthBuffer !== null) &&
209
- antiAlias === this.antiAlias) {
210
- if (scale !== this.scale) {
211
- this.scale = scale;
212
- this.showAt();
213
- this.applyScissor();
214
- }
215
- return;
216
- }
217
- const samples = selectSamples(this.gl, antiAlias, depth);
218
- const gl = this.gl;
219
- const most = this.storageLimit();
220
- const drawnWidth = Math.min(width, most[0]);
221
- const drawnHeight = Math.min(height, most[1]);
222
- const texture = gl.createTexture();
223
- const framebuffer = gl.createFramebuffer();
224
- const depthBuffer = depth ? gl.createRenderbuffer() : null;
225
- const resolveFramebuffer = samples ? gl.createFramebuffer() : null;
226
- const colorBuffer = samples ? gl.createRenderbuffer() : null;
227
- try {
228
- if (!texture ||
229
- !framebuffer ||
230
- (depth && !depthBuffer) ||
231
- (samples && (!resolveFramebuffer || !colorBuffer))) {
232
- throw new Context3DError("operation", "Context3D experiment: cannot allocate back buffer");
233
- }
234
- this.texturesApplied[0] = 0;
235
- gl.activeTexture(gl.TEXTURE0);
236
- gl.bindTexture(gl.TEXTURE_2D, texture);
237
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
238
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
239
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, drawnWidth, drawnHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
240
- this.bindFramebuffer(gl.FRAMEBUFFER, resolveFramebuffer ?? framebuffer);
241
- gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
242
- if (resolveFramebuffer) {
243
- if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) !== gl.FRAMEBUFFER_COMPLETE) {
244
- throw new Context3DError("operation", "Context3D experiment: incomplete resolve buffer");
245
- }
246
- this.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
247
- gl.bindRenderbuffer(gl.RENDERBUFFER, colorBuffer);
248
- gl.renderbufferStorageMultisample(gl.RENDERBUFFER, samples, gl.RGBA8, drawnWidth, drawnHeight);
249
- gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorBuffer);
250
- }
251
- if (depthBuffer) {
252
- gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer);
253
- if (samples) {
254
- gl.renderbufferStorageMultisample(gl.RENDERBUFFER, samples, gl.DEPTH24_STENCIL8, drawnWidth, drawnHeight);
255
- }
256
- else {
257
- gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH24_STENCIL8, drawnWidth, drawnHeight);
258
- }
259
- gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, depthBuffer);
260
- }
261
- gl.bindRenderbuffer(gl.RENDERBUFFER, null);
262
- if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) !== gl.FRAMEBUFFER_COMPLETE) {
263
- throw new Context3DError("operation", "Context3D experiment: incomplete back buffer");
264
- }
265
- }
266
- catch (error) {
267
- gl.deleteTexture(texture);
268
- gl.deleteFramebuffer(framebuffer);
269
- gl.deleteFramebuffer(resolveFramebuffer);
270
- gl.deleteRenderbuffer(depthBuffer);
271
- gl.deleteRenderbuffer(colorBuffer);
272
- gl.bindRenderbuffer(gl.RENDERBUFFER, null);
273
- this.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
274
- throw error;
275
- }
276
- gl.deleteTexture(this.texture);
277
- gl.deleteFramebuffer(this.framebuffer);
278
- gl.deleteFramebuffer(this.resolveFramebuffer);
279
- gl.deleteRenderbuffer(this.depthBuffer);
280
- gl.deleteRenderbuffer(this.colorBuffer);
281
- this.texture = texture;
282
- this.framebuffer = framebuffer;
283
- this.resolveFramebuffer = resolveFramebuffer;
284
- this.colorBuffer = colorBuffer;
285
- this.depthBuffer = depthBuffer;
286
- this.antiAlias = antiAlias;
287
- this.width = width;
288
- this.height = height;
289
- this.drawnWidth = drawnWidth;
290
- this.drawnHeight = drawnHeight;
291
- this.scale = scale;
292
- gl.canvas.width = drawnWidth;
293
- gl.canvas.height = drawnHeight;
294
- this.showAt();
295
- // Readback's storage waits for a read: a back buffer as large as a 4K screen is 33 MB each.
296
- this.pixels = new Uint8Array(0);
297
- this.topDown = new Uint8Array(0);
298
- this.applyScissor();
299
- this.clear(0, 0, 0, 1);
300
- }
301
- /**
302
- * Shown at the size asked for, in CSS pixels, as an unstyled canvas of that size would be,
303
- * divided by its scale: a best-resolution back buffer shows its pixels at the screen's.
304
- */
305
- showAt() {
306
- const style = this.gl.canvas.style;
307
- if (!style) {
308
- return;
309
- }
310
- const plain = this.scale === 1;
311
- style.width = plain && this.drawnWidth === this.width ? "" : `${this.width / this.scale}px`;
312
- style.height = plain && this.drawnHeight === this.height ? "" : `${this.height / this.scale}px`;
313
- }
314
- /** The largest back buffer storage the GPU gives: a texture, a renderbuffer and a viewport. */
315
- storageLimit() {
316
- if (!this.gpuMost) {
317
- const gl = this.gl;
318
- const viewport = gl.getParameter(gl.MAX_VIEWPORT_DIMS);
319
- const side = Math.min(gl.getParameter(gl.MAX_TEXTURE_SIZE), gl.getParameter(gl.MAX_RENDERBUFFER_SIZE));
320
- this.gpuMost = Int32Array.of(Math.min(side, viewport[0]), Math.min(side, viewport[1]));
321
- }
322
- return this.gpuMost;
231
+ configureBackBuffer(this, width, height, depth, antiAlias, scale);
323
232
  }
324
233
  unconfigure() {
325
- this.alive();
326
- if (this.renderTexture) {
327
- throw new Context3DError("operation", "Context3D experiment: resize while rendering to texture");
328
- }
329
- const gl = this.gl;
330
- gl.deleteTexture(this.texture);
331
- gl.deleteFramebuffer(this.framebuffer);
332
- gl.deleteFramebuffer(this.resolveFramebuffer);
333
- gl.deleteRenderbuffer(this.depthBuffer);
334
- gl.deleteRenderbuffer(this.colorBuffer);
335
- this.drawState.forget();
336
- this.texture = null;
337
- this.framebuffer = null;
338
- this.resolveFramebuffer = null;
339
- this.colorBuffer = null;
340
- this.depthBuffer = null;
341
- this.resolveDirty = false;
342
- this.antiAlias = 0;
343
- this.scale = 1;
344
- this.width = 0;
345
- this.height = 0;
346
- this.drawnWidth = 0;
347
- this.drawnHeight = 0;
348
- this.pixels = new Uint8Array(0);
349
- this.topDown = new Uint8Array(0);
234
+ unconfigureBackBuffer(this);
350
235
  }
351
236
  clear(red, green, blue, alpha, depth = 1, mask = 0xffffffff, stencil = 0) {
352
237
  this.target(false, (mask & 1) !== 0);
@@ -492,6 +377,7 @@ export class WebGLContext3D {
492
377
  }
493
378
  this.applyScissor();
494
379
  }
380
+ /** @internal */
495
381
  applyScissor() {
496
382
  const gl = this.gl;
497
383
  if (!this.scissor) {
@@ -577,107 +463,9 @@ export class WebGLContext3D {
577
463
  }
578
464
  }
579
465
  createBuffer(count, stride, dynamic = false) {
580
- this.alive();
581
- range(1, count - 1, stride === 0 ? 524287 : 65535);
582
- range(0, stride, 64);
583
- const countLimit = stride === 0 ? this.limits.maxIndexBuffers : this.limits.maxVertexBuffers;
584
- const used = stride === 0 ? this.buffers.size - this.vertexBuffers : this.vertexBuffers;
585
- if (this.buffers.size >= this.limits.maxBuffers || used >= countLimit) {
586
- throw new Context3DError("limit", "Context3D experiment: buffer limit");
587
- }
588
- const bytes = count * (stride === 0 ? 2 : stride * 4);
589
- const usedBytes = stride === 0 ? this.bufferBytes - this.vertexBufferBytes : this.vertexBufferBytes;
590
- const byteLimit = stride === 0 ? this.limits.maxIndexBufferBytes : this.limits.maxVertexBufferBytes;
591
- if (this.bufferBytes + bytes > this.limits.maxBufferBytes || usedBytes + bytes > byteLimit) {
592
- throw new Context3DError("limit", "Context3D experiment: buffer memory limit");
593
- }
594
- const gl = this.gl;
595
- const handle = gl.createBuffer();
596
- if (!handle) {
597
- throw new Context3DError("bufferAllocation", "Context3D experiment: cannot allocate buffer");
598
- }
599
- const target = stride === 0 ? gl.ELEMENT_ARRAY_BUFFER : gl.ARRAY_BUFFER;
600
- if (stride === 0) {
601
- this.indexBuffer = null;
602
- }
603
- gl.bindVertexArray(this.vao);
604
- gl.bindBuffer(target, handle);
605
- gl.bufferData(target, bytes, dynamic ? gl.DYNAMIC_DRAW : gl.STATIC_DRAW);
606
- const state = {
607
- handle,
608
- indices: stride === 0 ? new Uint16Array(count) : null,
609
- uploaded: new Uint8Array(count),
610
- prefix: 0,
611
- version: 0,
612
- checkedVersion: -1,
613
- checkedFirst: 0,
614
- checkedCount: 0,
615
- maximum: -1,
616
- ranges: null,
617
- };
618
- const buffer = {
619
- count,
620
- stride,
621
- upload: (values, start, amount) => {
622
- this.alive();
623
- this.buffer(buffer);
624
- try {
625
- uploadBuffer(gl, this.vao, buffer, state, values, start, amount);
626
- }
627
- finally {
628
- // Source getters can draw before the upload replaces the VAO's index binding.
629
- if (stride === 0) {
630
- this.indexBuffer = null;
631
- }
632
- }
633
- },
634
- uploadBytes: (data, offset, start, amount) => {
635
- this.alive();
636
- this.buffer(buffer);
637
- try {
638
- uploadBufferBytes(gl, this.vao, buffer, state, data, offset, start, amount);
639
- }
640
- finally {
641
- if (stride === 0) {
642
- this.indexBuffer = null;
643
- }
644
- }
645
- },
646
- dispose: () => {
647
- if (!this.buffers.delete(buffer)) {
648
- return;
649
- }
650
- if (this.indexBuffer === handle) {
651
- this.indexBuffer = null;
652
- }
653
- gl.deleteBuffer(handle);
654
- this.bufferBytes -= bytes;
655
- if (stride !== 0) {
656
- this.vertexBuffers--;
657
- this.vertexBufferBytes -= bytes;
658
- }
659
- state.indices = null;
660
- state.ranges = null;
661
- state.uploaded = new Uint8Array(0);
662
- for (let i = 0; i < this.vertices.length; i++) {
663
- const binding = this.vertices[i];
664
- if (binding?.buffer === buffer) {
665
- this.vertices[i] = null;
666
- }
667
- else if (binding?.checkedIndex === state) {
668
- binding.checkedIndex = null;
669
- }
670
- }
671
- },
672
- };
673
- this.buffers.set(buffer, state);
674
- if (stride !== 0) {
675
- this.vertexBuffers++;
676
- this.vertexBufferBytes += bytes;
677
- }
678
- this.bufferBytes += bytes;
679
- return buffer;
466
+ return allocateBuffer(this, count, stride, dynamic);
680
467
  }
468
+ /** @internal */
681
469
  buffer(buffer) {
682
470
  const state = this.buffers.get(buffer);
683
471
  if (!state) {
@@ -1734,77 +1522,11 @@ export class WebGLContext3D {
1734
1522
  }
1735
1523
  }
1736
1524
  }
1737
- resolve() {
1738
- if (!this.resolveFramebuffer) {
1739
- return;
1740
- }
1741
- const gl = this.gl;
1742
- if (this.resolveDirty) {
1743
- this.bindFramebuffer(gl.READ_FRAMEBUFFER, this.framebuffer);
1744
- this.bindFramebuffer(gl.DRAW_FRAMEBUFFER, this.resolveFramebuffer);
1745
- if (this.scissor) {
1746
- gl.disable(gl.SCISSOR_TEST);
1747
- }
1748
- gl.blitFramebuffer(0, 0, this.drawnWidth, this.drawnHeight, 0, 0, this.drawnWidth, this.drawnHeight, gl.COLOR_BUFFER_BIT, gl.NEAREST);
1749
- if (this.scissor) {
1750
- gl.enable(gl.SCISSOR_TEST);
1751
- }
1752
- this.resolveDirty = false;
1753
- }
1754
- this.bindFramebuffer(gl.READ_FRAMEBUFFER, this.resolveFramebuffer);
1755
- }
1756
1525
  read(width = this.width, height = this.height) {
1757
- width = Math.max(0, Math.min(this.width, Math.floor(width) || 0));
1758
- height = Math.max(0, Math.min(this.height, Math.floor(height) || 0));
1759
- this.target(true);
1760
- this.resolve();
1761
- const gl = this.gl;
1762
- const scaleX = this.drawnWidth / this.width;
1763
- const scaleY = this.drawnHeight / this.height;
1764
- const drawnWidth = Math.min(this.drawnWidth, Math.ceil(width * scaleX));
1765
- const drawnHeight = Math.min(this.drawnHeight, Math.ceil(height * scaleY));
1766
- if (this.pixels.length < drawnWidth * drawnHeight * 4) {
1767
- this.pixels = new Uint8Array(drawnWidth * drawnHeight * 4);
1768
- }
1769
- if (this.topDown.length < width * height * 4) {
1770
- this.topDown = new Uint8Array(width * height * 4);
1771
- }
1772
- // GL's rows run bottom-up, so the top-left region starts height rows below the top.
1773
- gl.readPixels(0, this.drawnHeight - drawnHeight, drawnWidth, drawnHeight, gl.RGBA, gl.UNSIGNED_BYTE, this.pixels);
1774
- const row = width * 4;
1775
- if (drawnWidth === width && drawnHeight === height) {
1776
- for (let y = 0; y < height; y++) {
1777
- const from = (height - y - 1) * row;
1778
- this.topDown.set(this.pixels.subarray(from, from + row), y * row);
1779
- }
1780
- return this.topDown;
1781
- }
1782
- // Storage smaller than the back buffer: each pixel is the stored one it falls on.
1783
- const source = new Uint32Array(this.pixels.buffer, 0, drawnWidth * drawnHeight);
1784
- const target = new Uint32Array(this.topDown.buffer, 0, width * height);
1785
- for (let y = 0; y < height; y++) {
1786
- const from = (drawnHeight - 1 - Math.min(drawnHeight - 1, Math.floor(y * scaleY))) * drawnWidth;
1787
- for (let x = 0; x < width; x++) {
1788
- target[y * width + x] = source[from + Math.min(drawnWidth - 1, Math.floor(x * scaleX))];
1789
- }
1790
- }
1791
- return this.topDown;
1526
+ return readBackBuffer(this, width, height);
1792
1527
  }
1793
1528
  present() {
1794
- this.setRenderTarget(null);
1795
- this.target();
1796
- this.resolve();
1797
- const gl = this.gl;
1798
- this.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
1799
- if (this.scissor) {
1800
- gl.disable(gl.SCISSOR_TEST);
1801
- }
1802
- // To the drawing buffer the browser gave, which it may have made smaller than the canvas.
1803
- gl.blitFramebuffer(0, 0, this.drawnWidth, this.drawnHeight, 0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight, gl.COLOR_BUFFER_BIT, gl.NEAREST);
1804
- if (this.scissor) {
1805
- gl.enable(gl.SCISSOR_TEST);
1806
- }
1807
- gl.flush();
1529
+ presentBackBuffer(this);
1808
1530
  }
1809
1531
  dispose() {
1810
1532
  if (this.disposed) {