Browse Source

Batching of the main instanced drawcall

sdf
A.Olokhtonov 3 weeks ago
parent
commit
8a4e87f4c6
  1. 31
      client/webgl_draw.js
  2. 4
      client/webgl_geometry.js
  3. 2
      client/webgl_shaders.js

31
client/webgl_draw.js

@ -274,13 +274,21 @@ async function draw(state, context, animate, ts) {
} }
// TODO: what do we do with this // TODO: what do we do with this
const circle_lod = Math.ceil(Math.min(7, 1 + Math.sqrt(state.canvas.zoom))); const circle_lod = Math.round(Math.min(7, 3 * Math.sqrt(state.canvas.zoom)));
const circle_data = geometry_good_circle_and_dummy(circle_lod); const circle_data = geometry_good_circle_and_dummy(circle_lod);
// "Static" data upload // "Static" data upload
if (segment_count > 0) { if (segment_count > 0) {
const pr = programs['main']; const pr = programs['main'];
const nbatches = 10;
const batches = [];
for (let i = 0; i < nbatches; ++i) {
batches.push(Math.floor(segment_count / nbatches * i));
}
batches.push(segment_count);
gl.clear(gl.DEPTH_BUFFER_BIT); // draw strokes above the images gl.clear(gl.DEPTH_BUFFER_BIT); // draw strokes above the images
gl.useProgram(pr.program); gl.useProgram(pr.program);
@ -319,11 +327,6 @@ async function draw(state, context, animate, ts) {
// Circle meshes (shared for all instances) // Circle meshes (shared for all instances)
gl.vertexAttribPointer(pr.locations['a_pos'], 2, gl.FLOAT, false, 2 * 4, context.instance_data_points.size * 4 + context.instance_data_ids.size * 4 + round_to_pow2(context.instance_data_pressures.size, 4)); gl.vertexAttribPointer(pr.locations['a_pos'], 2, gl.FLOAT, false, 2 * 4, context.instance_data_points.size * 4 + context.instance_data_ids.size * 4 + round_to_pow2(context.instance_data_pressures.size, 4));
// Points (a, b) and stroke ids are stored in separate cpu buffers so that points can be reused (look at stride and offset values)
gl.vertexAttribPointer(pr.locations['a_a'], 2, gl.FLOAT, false, 2 * 4, 0);
gl.vertexAttribPointer(pr.locations['a_b'], 2, gl.FLOAT, false, 2 * 4, 2 * 4);
gl.vertexAttribIPointer(pr.locations['a_stroke_id'], 1, gl.INT, 4, context.instance_data_points.size * 4);
gl.vertexAttribPointer(pr.locations['a_pressure'], 2, gl.UNSIGNED_BYTE, true, 1, context.instance_data_points.size * 4 + context.instance_data_ids.size * 4);
gl.vertexAttribDivisor(pr.locations['a_pos'], 0); gl.vertexAttribDivisor(pr.locations['a_pos'], 0);
gl.vertexAttribDivisor(pr.locations['a_a'], 1); gl.vertexAttribDivisor(pr.locations['a_a'], 1);
@ -331,8 +334,18 @@ async function draw(state, context, animate, ts) {
gl.vertexAttribDivisor(pr.locations['a_stroke_id'], 1); gl.vertexAttribDivisor(pr.locations['a_stroke_id'], 1);
gl.vertexAttribDivisor(pr.locations['a_pressure'], 1); gl.vertexAttribDivisor(pr.locations['a_pressure'], 1);
// Static draw (everything already bound) for (let b = 0; b < batches.length - 1; ++b) {
gl.drawElementsInstanced(gl.TRIANGLES, circle_data.indices.size, gl.UNSIGNED_INT, 0, segment_count); const batch_from = batches[b];
const batch_size = batches[b + 1] - batch_from;
// Points (a, b) and stroke ids are stored in separate cpu buffers so that points can be reused (look at stride and offset values)
gl.vertexAttribPointer(pr.locations['a_a'], 2, gl.FLOAT, false, 2 * 4, batch_from * 2 * 4);
gl.vertexAttribPointer(pr.locations['a_b'], 2, gl.FLOAT, false, 2 * 4, batch_from * 2 * 4 + 2 * 4);
gl.vertexAttribIPointer(pr.locations['a_stroke_id'], 1, gl.INT, 4, context.instance_data_points.size * 4 + batch_from * 4);
gl.vertexAttribPointer(pr.locations['a_pressure'], 2, gl.UNSIGNED_BYTE, true, 1, context.instance_data_points.size * 4 + context.instance_data_ids.size * 4 + batch_from);
gl.drawElementsInstanced(gl.TRIANGLES, circle_data.indices.size, gl.UNSIGNED_INT, 0, batch_size);
}
// I don't really know why I need to do this, but it // I don't really know why I need to do this, but it
// makes background patter drawcall work properly // makes background patter drawcall work properly
@ -540,6 +553,8 @@ async function draw(state, context, animate, ts) {
document.getElementById('debug-stats').innerHTML = ` document.getElementById('debug-stats').innerHTML = `
<span>Strokes onscreen: ${context.clipped_indices.size}</span> <span>Strokes onscreen: ${context.clipped_indices.size}</span>
<span>Segments onscreen: ${segment_count}</span> <span>Segments onscreen: ${segment_count}</span>
<span>Total vertices: ${segment_count * circle_data.indices.size}</span>
<span>Circle LOD: ${circle_lod}</span>
<span>Canvas offset: (${Math.round(state.canvas.offset.x * 100) / 100}, ${Math.round(state.canvas.offset.y * 100) / 100})</span> <span>Canvas offset: (${Math.round(state.canvas.offset.x * 100) / 100}, ${Math.round(state.canvas.offset.y * 100) / 100})</span>
<span>Canvas zoom level: ${state.canvas.zoom_level}</span> <span>Canvas zoom level: ${state.canvas.zoom_level}</span>
<span>Canvas zoom: ${Math.round(state.canvas.zoom * 100) / 100}</span>`; <span>Canvas zoom: ${Math.round(state.canvas.zoom * 100) / 100}</span>`;

4
client/webgl_geometry.js

@ -549,7 +549,7 @@ function geometry_line_segments_with_two_circles(circle_segments) {
} }
function geometry_good_circle_and_dummy(lod) { function geometry_good_circle_and_dummy(lod) {
const total_points = 3 * Math.pow(2, lod - 1) + 4; // 3, 6, 12, 24, ... + Dummy for line segment const total_points = 3 * Math.pow(2, lod) + 4; // 3, 6, 12, 24, ... + Dummy for line segment
const total_indices = 3 * (Math.pow(3, lod + 1) - 1) / 2 + 6; // 3, 3 + 9, 3 + 9 + 18, ... + Dummy for line segment const total_indices = 3 * (Math.pow(3, lod + 1) - 1) / 2 + 6; // 3, 3 + 9, 3 + 9 + 18, ... + Dummy for line segment
const points = tv_create(Float32Array, total_points * 2); const points = tv_create(Float32Array, total_points * 2);
const indices = tv_create(Uint32Array, total_indices); const indices = tv_create(Uint32Array, total_indices);
@ -576,7 +576,7 @@ function geometry_good_circle_and_dummy(lod) {
let last_base = 3; let last_base = 3;
let last_offset = 0; let last_offset = 0;
for (let i = 0; i < lod; ++i) { for (let i = 0; i <= lod; ++i) {
// generate 3 * Math.pow(2, i) points on a circle // generate 3 * Math.pow(2, i) points on a circle
const npoints = 3 * Math.pow(2, i); const npoints = 3 * Math.pow(2, i);
const base = indices.size; const base = indices.size;

2
client/webgl_shaders.js

@ -322,8 +322,10 @@ function init_webgl(state, context) {
gl.enable(gl.BLEND); gl.enable(gl.BLEND);
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
/*
gl.enable(gl.DEPTH_TEST); gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.NOTEQUAL); gl.depthFunc(gl.NOTEQUAL);
*/
context.gpu_timer_ext = gl.getExtension('EXT_disjoint_timer_query_webgl2'); context.gpu_timer_ext = gl.getExtension('EXT_disjoint_timer_query_webgl2');
if (context.gpu_timer_ext === null) { if (context.gpu_timer_ext === null) {

Loading…
Cancel
Save