Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Optimizing WebGL Applications

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on.

Optimizing WebGL Applications

Avatar for Don Olmstead

Don Olmstead

January 23, 2014

More Decks by Don Olmstead

Other Decks in Programming

Transcript

  1. PlayStation 4 • Released 11/15/13 • Sold over 1 million

    in 24 hours • Sold over 4.2 million units in 2013 • All run WebGL!
  2. Supported platforms • Same codebase runs on multiple platforms •

    PlayStation Hardware ◦ PS3 ◦ PS4 • Browser (development only) ◦ Chrome
  3. How to optimize WebGL applications • Determine where time is

    being spent within the frame • Understand how WebGL content is rendered • Recognize how WebGL works • Optimize how the scene is drawn • Keep work within the animation loop
  4. What’s in a frame? • Have 16.6 ms to do

    all work ◦ 60 knots frames per second • Missing that window results in a dropped frame ◦ Hurts the user experience • Other things can cut into the frame time ◦ Garbage collector ◦ Browser events
  5. Profiling a frame • Profile to find out how much

    time is being spent in a frame ◦ Sampling profiler ▪ Chrome DevTools ◦ Structural profiler ▪ chrome://tracing ▪ Web Tracing Framework • Place markers at different sections
  6. Anatomy of a WebGL call (cont) • Overhead is not

    escapable • Can only make so many calls in a frame • Need to make sure that the rendering calls submitted are optimal
  7. WebGL is a state machine • Most WebGL calls change

    the state ◦ Rendering context ◦ Objects ▪ Textures ▪ Shader programs ▪ Buffers • A call that results in no changes to the underlying object is a redundant call
  8. WebGL call execution var gl; // The WebGLRendering Context var

    prog; // The WebGLProgram // Uniform locations var alphaLocation; var texUnitLocation; function setupProgram() { gl.useProgram(prog); gl.uniform1f(alphaLocation, 0.5); gl.uniform1i(texUnitLocation, 0); } WebGLRenderingContext DEPTH_TEST ENABLED TEXTURE0 0 TEXTURE1 0 . . . PROGRAM 0 WebGLProgram ID 1 uAlpha 0 uTexUnit 0
  9. WebGL call execution var gl; // The WebGLRendering Context var

    prog; // The WebGLProgram // Uniform locations var alphaLocation; var texUnitLocation; function setupProgram() { gl.useProgram(prog); gl.uniform1f(alphaLocation, 0.5); gl.uniform1i(texUnitLocation, 0); } WebGLRenderingContext DEPTH_TEST ENABLED TEXTURE0 0 TEXTURE1 0 . . . PROGRAM ID_1 WebGLProgram ID 1 uAlpha 0 uTexUnit 0
  10. WebGL call execution var gl; // The WebGLRendering Context var

    prog; // The WebGLProgram // Uniform locations var alphaLocation; var texUnitLocation; function setupProgram() { gl.useProgram(prog); gl.uniform1f(alphaLocation, 0.5); gl.uniform1i(texUnitLocation, 0); } WebGLRenderingContext DEPTH_TEST ENABLED TEXTURE0 0 TEXTURE1 0 . . . PROGRAM ID_1 WebGLProgram ID 1 uAlpha 0.5 uTexUnit 0
  11. WebGL call execution var gl; // The WebGLRendering Context var

    prog; // The WebGLProgram // Uniform locations var alphaLocation; var texUnitLocation; function setupProgram() { gl.useProgram(prog); gl.uniform1f(alphaLocation, 0.5); gl.uniform1i(texUnitLocation, 0); } WebGLRenderingContext DEPTH_TEST ENABLED TEXTURE0 0 TEXTURE1 0 . . . PROGRAM ID_1 WebGLProgram ID 1 uAlpha 0.5 uTexUnit 0
  12. Stopping redundant calls • Keep track of state • Compare

    current value to new value ◦ !== let the call go through ◦ === stop the call from being made
  13. Sample(r) implementation trilithium.ShaderUniformSampler = function(location) { this.location_ = location; this.value_

    = 0; }; trilithium.ShaderUniformSampler.prototype.setValue = function(gl, value) { if (this.value_ !== value) { gl.uniform1i(this.location_, value); this.value_ = value; } };
  14. Benefits • Cut down the number of calls to WebGL

    that were being made • Results ◦ Best - ¼ the number of calls ◦ Worst - ½ the number of calls ◦ Average - ⅓ the number of calls • Great speedup
  15. Optimizing the scene • Cull geometry that won’t be seen

    • Submit opaque geometry front to back • Submit transparent geometry back to front • Group submissions with same state
  16. TriLithium scene characteristics • Scene tree is very deep ◦

    Sometimes 26 levels! • Textures were unique ◦ Couldn’t texture sheet everything • Objects weren’t too mobile • Had scissored areas requiring clipping
  17. TriLithium scene optimization • Compute the visible set when the

    tree changes • Cull hierarchy only at nodes with clip rectangles • Cull geometry based on smallest clip rectangle
  18. Keep work within the frame • Events occur outside the

    animation loop ◦ Timeouts ◦ Request responses • If an event triggers a long running script execution a frame can be dropped
  19. TriLithium resource creation • Loading a new view results in

    a large amount of resources being created ◦ Texture resources ◦ Text creation • Need to amortize the cost over several frames to avoid jank
  20. Managing tasks • Resource loads are queued ◦ Image loading

    is a task ◦ Text creation is divided into multiple tasks • Need to time box resource loading ◦ Ensure the rest of the application has time to update ◦ Imperfect as a task cannot be preempted • Total time used is set by the application
  21. Task manager implementation trilithium.TaskScheduler.prototype.runTasksWithinTimeFrame = function(maxTime) { var tasks =

    this.tasks_, performance = window.performance, startTime = performance.now(), timeSpan = 0; while ((tasks.length > 0) && (timeSpan < maxTime)) { trilithium.TaskScheduler.runNextTask_(tasks); timeSpan = performance.now() - startTime; } return timeSpan; };
  22. Conclusion • Can reduce the number of WebGL calls by

    understanding how WebGL works • Optimize the geometry submission based on your application • Keep work on the animation frame to avoid jank