Browse Source

Faster clipping

ssao
A.Olokhtonov 1 year ago
parent
commit
e41997563f
  1. 1
      client/index.js
  2. 22
      client/math.js
  3. 50
      client/webgl_draw.js
  4. 4
      client/webgl_shaders.js

1
client/index.js

@ -173,6 +173,7 @@ function main() {
}, },
'players': {}, 'players': {},
'onscreen_segments': [],
}; };
const context = { const context = {

22
client/math.js

@ -207,8 +207,19 @@ function quad_onscreen(screen, bbox) {
return false; return false;
} }
function quad_fully_onscreen(screen, bbox) {
if (screen.x1 < bbox.x1 && screen.x2 > bbox.x2 && screen.y1 < bbox.y1 && screen.y2 > bbox.y2) {
return true;
}
return false;
}
function segments_onscreen(state, context) { function segments_onscreen(state, context) {
const result = []; // TODO: handle stroke width
state.onscreen_segments.length = 0;
const screen_topleft = screen_to_canvas(state, {'x': 0, 'y': 0}); const screen_topleft = screen_to_canvas(state, {'x': 0, 'y': 0});
const screen_bottomright = screen_to_canvas(state, {'x': context.canvas.width, 'y': context.canvas.height}); const screen_bottomright = screen_to_canvas(state, {'x': context.canvas.width, 'y': context.canvas.height});
const screen_topright = { 'x': screen_bottomright.x, 'y': screen_topleft.y }; const screen_topright = { 'x': screen_bottomright.x, 'y': screen_topleft.y };
@ -221,21 +232,20 @@ function segments_onscreen(state, context) {
const event = state.events[i]; const event = state.events[i];
if (event.type === EVENT.STROKE && !event.deleted) { if (event.type === EVENT.STROKE && !event.deleted) {
if (quad_onscreen(screen, event.bbox)) { if (quad_onscreen(screen, event.bbox)) {
const fully_onscreen = quad_fully_onscreen(screen, event.bbox);
for (let j = 0; j < event.points.length - 1; ++j) { for (let j = 0; j < event.points.length - 1; ++j) {
const a = event.points[j + 0]; const a = event.points[j + 0];
const b = event.points[j + 1]; const b = event.points[j + 1];
if (segment_interesects_quad(a, b, screen_topleft, screen_bottomright, screen_topright, screen_bottomleft)) { if (fully_onscreen || segment_interesects_quad(a, b, screen_topleft, screen_bottomright, screen_topright, screen_bottomleft)) {
let base = head + j * 4; let base = head + j * 4;
// We draw quads as [1, 2, 3, 4, 3, 2] // We draw quads as [1, 2, 3, 4, 3, 2]
result.push(base + 0, base + 1, base + 2); state.onscreen_segments.push(base + 0, base + 1, base + 2);
result.push(base + 3, base + 2, base + 1); state.onscreen_segments.push(base + 3, base + 2, base + 1);
} }
} }
} }
head += (event.points.length - 1) * 4; head += (event.points.length - 1) * 4;
} }
} }
return result;
} }

50
client/webgl_draw.js

@ -12,8 +12,12 @@ function draw(state, context) {
const width = window.innerWidth; const width = window.innerWidth;
const height = window.innerHeight; const height = window.innerHeight;
const frame_start = performance.now(); let query = null;
const sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
if (context.gpu_timer_ext !== null) {
query = gl.createQuery();
gl.beginQuery(context.gpu_timer_ext.TIME_ELAPSED_EXT, query);
}
let locations; let locations;
let buffers; let buffers;
@ -64,11 +68,17 @@ function draw(state, context) {
context.static_upload_from = context.static_serializer.offset; context.static_upload_from = context.static_serializer.offset;
} }
const indices = segments_onscreen(state, context); const before_clip = performance.now();
segments_onscreen(state, context);
const after_clip = performance.now();
console.debug('clip', after_clip - before_clip);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers['b_packed_static_index']); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers['b_packed_static_index']);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint32Array(indices), gl.DYNAMIC_DRAW); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint32Array(state.onscreen_segments), gl.DYNAMIC_DRAW);
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_INT, 0); const after_index_uploads = performance.now();
console.debug('index upload', after_index_uploads - after_clip);
gl.drawElements(gl.TRIANGLES, state.onscreen_segments.length, gl.UNSIGNED_INT, 0);
} }
if (dynamic_points > 0) { if (dynamic_points > 0) {
@ -89,7 +99,7 @@ function draw(state, context) {
gl.drawArrays(gl.TRIANGLES, 0, dynamic_points); gl.drawArrays(gl.TRIANGLES, 0, dynamic_points);
} }
/*
const next_tick = () => { const next_tick = () => {
const wait_status = gl.clientWaitSync(sync, 0, 0); const wait_status = gl.clientWaitSync(sync, 0, 0);
const frame_end = performance.now(); const frame_end = performance.now();
@ -104,8 +114,36 @@ function draw(state, context) {
} }
setTimeout(next_tick, 0); setTimeout(next_tick, 0);
*/
if (context.gpu_timer_ext) {
gl.endQuery(context.gpu_timer_ext.TIME_ELAPSED_EXT);
const next_tick = () => {
if (query) {
// At some point in the future, after returning control to the browser
const available = gl.getQueryParameter(query, gl.QUERY_RESULT_AVAILABLE);
const disjoint = gl.getParameter(context.gpu_timer_ext.GPU_DISJOINT_EXT);
if (available && !disjoint) {
// See how much time the rendering of the object took in nanoseconds.
const timeElapsed = gl.getQueryParameter(query, gl.QUERY_RESULT);
console.debug(timeElapsed / 1000000);
}
if (available || disjoint) {
// Clean up the query object.
gl.deleteQuery(query);
// Don't re-enter this polling loop.
query = null;
} else {
setTimeout(next_tick, 0);
}
}
}
setTimeout(next_tick, 0);
}
// Images // Images
// locations = context.locations['image']; // locations = context.locations['image'];
// buffers = context.buffers['image']; // buffers = context.buffers['image'];

4
client/webgl_shaders.js

@ -80,7 +80,7 @@ const sdf_fs_src = `#version 300 es
// float alpha = 1.0 - step(0.0, dist); // float alpha = 1.0 - step(0.0, dist);
if (u_debug_mode == 1) { if (u_debug_mode == 1) {
FragColor = vec4(1.0, 0.0, 0.0, 0.5); FragColor = vec4(1.0, 0.0, 0.0, 0.1);
} else { } else {
FragColor = vec4(v_color * alpha, alpha); FragColor = vec4(v_color * alpha, alpha);
// FragColor = vec4(v_color * alpha, 0.1 + alpha); // FragColor = vec4(v_color * alpha, 0.1 + alpha);
@ -140,6 +140,8 @@ 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);
context.gpu_timer_ext = gl.getExtension('EXT_disjoint_timer_query_webgl2');
const quad_vs = create_shader(gl, gl.VERTEX_SHADER, tquad_vs_src); const quad_vs = create_shader(gl, gl.VERTEX_SHADER, tquad_vs_src);
const quad_fs = create_shader(gl, gl.FRAGMENT_SHADER, tquad_fs_src); const quad_fs = create_shader(gl, gl.FRAGMENT_SHADER, tquad_fs_src);

Loading…
Cancel
Save