Skip to content

Commit 38c4213

Browse files
committed
code style, clean up some very old stuff, fallback to non-instanced for the 0.05%
1 parent 3f1e425 commit 38c4213

File tree

2 files changed

+107
-88
lines changed

2 files changed

+107
-88
lines changed

src/PenSkin.js

+107-83
Original file line numberDiff line numberDiff line change
@@ -75,42 +75,84 @@ class PenSkin extends Skin {
7575
// tw: keep track of native size
7676
this._nativeSize = renderer.getNativeSize();
7777

78-
// tw: create the extra data structures needed to buffer pen
79-
this._resetAttributeIndex();
80-
this.attribute_data = new Float32Array(PEN_ATTRIBUTE_BUFFER_SIZE);
81-
8278
const NO_EFFECTS = 0;
8379
/** @type {twgl.ProgramInfo} */
8480
this._lineShader = this._renderer._shaderManager.getShader(ShaderManager.DRAW_MODE.line, NO_EFFECTS);
8581

86-
// tw: draw region used to preserve texture when resizing
82+
// Draw region used to preserve texture when resizing
8783
this._drawTextureShader = this._renderer._shaderManager.getShader(ShaderManager.DRAW_MODE.default, NO_EFFECTS);
8884
/** @type {object} */
8985
this._drawTextureRegionId = {
9086
enter: () => this._enterDrawTexture(),
9187
exit: () => this._exitDrawTexture()
9288
};
9389

90+
this.a_position_glbuffer = gl.createBuffer();
9491
this.a_position_loc = gl.getAttribLocation(this._lineShader.program, 'a_position');
95-
gl.bindBuffer(gl.ARRAY_BUFFER, this.a_position_glbuffer = gl.createBuffer());
96-
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
97-
1, 0,
98-
0, 0,
99-
1, 1,
100-
1, 1,
101-
0, 0,
102-
0, 1
103-
]), gl.STATIC_DRAW);
10492

93+
this.attribute_glbuffer = gl.createBuffer();
94+
this.attribute_index = 0;
10595
this.a_lineColor_loc = gl.getAttribLocation(this._lineShader.program, 'a_lineColor');
10696
this.a_lineThicknessAndLength_loc = gl.getAttribLocation(this._lineShader.program, 'a_lineThicknessAndLength');
10797
this.a_penPoints_loc = gl.getAttribLocation(this._lineShader.program, 'a_penPoints');
108-
gl.bindBuffer(gl.ARRAY_BUFFER, this.attribute_buffer = gl.createBuffer());
109-
gl.bufferData(gl.ARRAY_BUFFER, this.attribute_data.length * 4, gl.STREAM_DRAW);
11098

111-
if (!gl.drawArraysInstanced) {
112-
// Fallback to ANGLE_instanced_arrays
113-
this.instanced_arrays_ext = gl.getExtension('ANGLE_instanced_arrays');
99+
if (gl.drawArraysInstanced) {
100+
// WebGL2 has native instanced rendering
101+
this.instancedRendering = true;
102+
this.glDrawArraysInstanced = gl.drawArraysInstanced.bind(gl);
103+
this.glVertexAttribDivisor = gl.vertexAttribDivisor.bind(gl);
104+
} else {
105+
// WebGL1 may have instanced rendering through the ANGLE_instanced_arrays extension
106+
const instancedArraysExtension = gl.getExtension('ANGLE_instanced_arrays');
107+
if (instancedArraysExtension) {
108+
this.instancedRendering = true;
109+
this.glDrawArraysInstanced = instancedArraysExtension.drawElementsInstancedANGLE.bind(
110+
instancedArraysExtension
111+
);
112+
this.glVertexAttribDivisor = instancedArraysExtension.vertexAttribDivisorANGLE.bind(
113+
instancedArraysExtension
114+
);
115+
} else {
116+
this.instancedRendering = false;
117+
}
118+
}
119+
120+
if (this.instancedRendering) {
121+
gl.bindBuffer(gl.ARRAY_BUFFER, this.a_position_glbuffer);
122+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
123+
1, 0,
124+
0, 0,
125+
1, 1,
126+
1, 1,
127+
0, 0,
128+
0, 1
129+
]), gl.STATIC_DRAW);
130+
131+
this.attribute_data = new Float32Array(PEN_ATTRIBUTE_BUFFER_SIZE);
132+
gl.bindBuffer(gl.ARRAY_BUFFER, this.attribute_glbuffer);
133+
gl.bufferData(gl.ARRAY_BUFFER, this.attribute_data.length * 4, gl.STREAM_DRAW);
134+
} else {
135+
const positionBuffer = new Float32Array(PEN_ATTRIBUTE_BUFFER_SIZE / PEN_ATTRIBUTE_STRIDE * 2);
136+
for (let i = 0; i < positionBuffer.length; i += 12) {
137+
positionBuffer[i + 0] = 1;
138+
positionBuffer[i + 1] = 0;
139+
positionBuffer[i + 2] = 0;
140+
positionBuffer[i + 3] = 0;
141+
positionBuffer[i + 4] = 1;
142+
positionBuffer[i + 5] = 1;
143+
positionBuffer[i + 6] = 1;
144+
positionBuffer[i + 7] = 1;
145+
positionBuffer[i + 8] = 0;
146+
positionBuffer[i + 9] = 0;
147+
positionBuffer[i + 10] = 0;
148+
positionBuffer[i + 11] = 1;
149+
}
150+
gl.bindBuffer(gl.ARRAY_BUFFER, this.a_position_glbuffer);
151+
gl.bufferData(gl.ARRAY_BUFFER, positionBuffer, gl.STATIC_DRAW);
152+
153+
this.attribute_data = new Float32Array(PEN_ATTRIBUTE_BUFFER_SIZE);
154+
gl.bindBuffer(gl.ARRAY_BUFFER, this.attribute_glbuffer);
155+
gl.bufferData(gl.ARRAY_BUFFER, this.attribute_data.length * 4, gl.STREAM_DRAW);
114156
}
115157

116158
this.onNativeSizeChanged = this.onNativeSizeChanged.bind(this);
@@ -203,8 +245,6 @@ class PenSkin extends Skin {
203245
* Prepare to draw lines in the _lineOnBufferDrawRegionId region.
204246
*/
205247
_enterDrawLineOnBuffer () {
206-
// tw: reset attributes when starting pen drawing
207-
this._resetAttributeIndex();
208248
const gl = this._renderer.gl;
209249

210250
twgl.bindFramebufferInfo(gl, this._framebuffer);
@@ -224,6 +264,8 @@ class PenSkin extends Skin {
224264
gl.bindBuffer(gl.ARRAY_BUFFER, this.a_position_glbuffer);
225265
gl.enableVertexAttribArray(this.a_position_loc);
226266
gl.vertexAttribPointer(this.a_position_loc, 2, gl.FLOAT, false, 2 * 4, 0);
267+
268+
this.attribute_index = 0;
227269
}
228270

229271
/**
@@ -310,10 +352,11 @@ class PenSkin extends Skin {
310352
_drawLineOnBuffer (penAttributes, x0, y0, x1, y1) {
311353
this._renderer.enterDrawRegion(this._lineOnBufferDrawRegionId);
312354

313-
// tw: flush if this line would overflow buffers
314-
// For some reason, looking up the size of a_lineColor with .length is very slow in some browsers.
315-
// We see measurable performance improvements by comparing to a constant instead.
316-
if (this.attribute_index + PEN_ATTRIBUTE_STRIDE > PEN_ATTRIBUTE_BUFFER_SIZE) {
355+
const iters = this.instancedRendering ? 1 : 6;
356+
357+
// For some reason, looking up the size of a buffer through .length can be slow,
358+
// so use a constant instead.
359+
if (this.attribute_index + (PEN_ATTRIBUTE_STRIDE * iters) > PEN_ATTRIBUTE_BUFFER_SIZE) {
317360
this._flushLines();
318361
}
319362

@@ -336,45 +379,40 @@ class PenSkin extends Skin {
336379

337380
// tw: apply renderQuality
338381
const lineThickness = (penAttributes.diameter || DefaultPenAttributes.diameter) * this.renderQuality;
339-
// tw: write pen draws to buffers where they will be flushed later
340-
341-
// Premultiply pen color by pen transparency
342-
this.attribute_data[this.attribute_index] = penColor[0] * penColor[3];
343-
this.attribute_index++;
344-
this.attribute_data[this.attribute_index] = penColor[1] * penColor[3];
345-
this.attribute_index++;
346-
this.attribute_data[this.attribute_index] = penColor[2] * penColor[3];
347-
this.attribute_index++;
348-
this.attribute_data[this.attribute_index] = penColor[3];
349-
this.attribute_index++;
350-
351-
this.attribute_data[this.attribute_index] = lineThickness;
352-
this.attribute_index++;
353-
354-
this.attribute_data[this.attribute_index] = lineLength;
355-
this.attribute_index++;
356-
357-
this.attribute_data[this.attribute_index] = x0;
358-
this.attribute_index++;
359-
this.attribute_data[this.attribute_index] = -y0;
360-
this.attribute_index++;
361-
this.attribute_data[this.attribute_index] = lineDiffX;
362-
this.attribute_index++;
363-
this.attribute_data[this.attribute_index] = -lineDiffY;
364-
this.attribute_index++;
365-
}
366382

367-
// tw: resets indexes in the pen drawing buffers
368-
_resetAttributeIndex () {
369-
this.attribute_index = 0;
383+
for (let i = 0; i < iters; i++) {
384+
// Pen color sent to the GPU is pre-multiplied by transparency
385+
this.attribute_data[this.attribute_index] = penColor[0] * penColor[3];
386+
this.attribute_index++;
387+
this.attribute_data[this.attribute_index] = penColor[1] * penColor[3];
388+
this.attribute_index++;
389+
this.attribute_data[this.attribute_index] = penColor[2] * penColor[3];
390+
this.attribute_index++;
391+
this.attribute_data[this.attribute_index] = penColor[3];
392+
this.attribute_index++;
393+
394+
this.attribute_data[this.attribute_index] = lineThickness;
395+
this.attribute_index++;
396+
397+
this.attribute_data[this.attribute_index] = lineLength;
398+
this.attribute_index++;
399+
400+
this.attribute_data[this.attribute_index] = x0;
401+
this.attribute_index++;
402+
this.attribute_data[this.attribute_index] = -y0;
403+
this.attribute_index++;
404+
this.attribute_data[this.attribute_index] = lineDiffX;
405+
this.attribute_index++;
406+
this.attribute_data[this.attribute_index] = -lineDiffY;
407+
this.attribute_index++;
408+
}
370409
}
371410

372-
// tw: flushes buffered pen lines to the GPU
373411
_flushLines () {
374412
/** @type {WebGLRenderingContext} */
375413
const gl = this._renderer.gl;
376414

377-
gl.bindBuffer(gl.ARRAY_BUFFER, this.attribute_buffer);
415+
gl.bindBuffer(gl.ARRAY_BUFFER, this.attribute_glbuffer);
378416
gl.bufferSubData(gl.ARRAY_BUFFER, 0, new Float32Array(this.attribute_data.buffer, 0, this.attribute_index));
379417

380418
gl.enableVertexAttribArray(this.a_lineColor_loc);
@@ -398,39 +436,25 @@ class PenSkin extends Skin {
398436
PEN_ATTRIBUTE_STRIDE_BYTES, 6 * 4
399437
);
400438

401-
if (this.instanced_arrays_ext) {
402-
// ANGLE_instanced_arrays fallback
403-
this.instanced_arrays_ext.vertexAttribDivisorANGLE(this.a_lineColor_loc, 1);
404-
this.instanced_arrays_ext.vertexAttribDivisorANGLE(this.a_lineThicknessAndLength_loc, 1);
405-
this.instanced_arrays_ext.vertexAttribDivisorANGLE(this.a_penPoints_loc, 1);
406-
407-
this.instanced_arrays_ext.drawArraysInstancedANGLE(
439+
if (this.instancedRendering) {
440+
this.glVertexAttribDivisor(this.a_lineColor_loc, 1);
441+
this.glVertexAttribDivisor(this.a_lineThicknessAndLength_loc, 1);
442+
this.glVertexAttribDivisor(this.a_penPoints_loc, 1);
443+
444+
this.glDrawArraysInstanced(
408445
gl.TRIANGLES,
409446
0, 6,
410447
this.attribute_index / PEN_ATTRIBUTE_STRIDE
411448
);
412-
413-
this.instanced_arrays_ext.vertexAttribDivisorANGLE(this.a_lineColor_loc, 0);
414-
this.instanced_arrays_ext.vertexAttribDivisorANGLE(this.a_lineThicknessAndLength_loc, 0);
415-
this.instanced_arrays_ext.vertexAttribDivisorANGLE(this.a_penPoints_loc, 0);
449+
450+
this.glVertexAttribDivisor(this.a_lineColor_loc, 0);
451+
this.glVertexAttribDivisor(this.a_lineThicknessAndLength_loc, 0);
452+
this.glVertexAttribDivisor(this.a_penPoints_loc, 0);
416453
} else {
417-
gl.vertexAttribDivisor(this.a_lineColor_loc, 1);
418-
gl.vertexAttribDivisor(this.a_lineThicknessAndLength_loc, 1);
419-
gl.vertexAttribDivisor(this.a_penPoints_loc, 1);
420-
421-
gl.drawArraysInstanced(
422-
gl.TRIANGLES,
423-
0, 6,
424-
this.attribute_index / PEN_ATTRIBUTE_STRIDE
425-
);
426-
427-
gl.vertexAttribDivisor(this.a_lineColor_loc, 0);
428-
gl.vertexAttribDivisor(this.a_lineThicknessAndLength_loc, 0);
429-
gl.vertexAttribDivisor(this.a_penPoints_loc, 0);
454+
gl.drawArrays(gl.TRIANGLES, 0, this.attribute_index / PEN_ATTRIBUTE_STRIDE);
430455
}
431456

432-
this._resetAttributeIndex();
433-
457+
this.attribute_index = 0;
434458
this._silhouetteDirty = true;
435459
}
436460

src/RenderWebGL.js

-5
Original file line numberDiff line numberDiff line change
@@ -172,15 +172,10 @@ class RenderWebGL extends EventEmitter {
172172

173173
/** @type {WebGLRenderingContext} */
174174
const gl = this._gl = RenderWebGL._getContext(canvas);
175-
176175
if (!gl) {
177176
throw new Error('Could not get WebGL context: this browser or environment may not support WebGL.');
178177
}
179178

180-
if (!gl.getExtension('ANGLE_instanced_arrays') && !gl.drawArraysInstanced) {
181-
throw new Error('Instanced rendering not supported.');
182-
}
183-
184179
/** @type {RenderWebGL.UseGpuModes} */
185180
this._useGpuMode = RenderWebGL.UseGpuModes.Automatic;
186181

0 commit comments

Comments
 (0)