Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shader compilation speedup #9384

Closed
arindam1993 opened this issue Mar 6, 2020 · 2 comments
Closed

Shader compilation speedup #9384

arindam1993 opened this issue Mar 6, 2020 · 2 comments
Labels
performance ⚡ Speed, stability, CPU usage, memory usage, or power usage

Comments

@arindam1993
Copy link
Contributor

@sgolbabaei and I had a really good session yesterday and discovered some neat optimization opportunities.

The Hypothesis:

Currently, we introduce some jank and take a hit on our load times due to slowness in compiling shaders, which is mostly caused by calling gl.getProgramParameter() to retrieve the number of uniforms and attributes in each program.
Screen Shot 2020-02-27 at 4 02 53 PM
The above screenshot shows it takes roughly 100 ms on a Macbook Pro to render the first frame.

Further investigation showed that querying for attributes is more time consuming than querying for uniforms,
image2
Logically it seems like we can eliminate the call to gl.getProgramParameter() completely since our styling pipeline with ProgramConfiguration + Binders already tracks and computes the necessary attributes and uniforms necessary for runtime styling. We should be able to combine that, with the static data in the shader to extract this metadata ourselves, instead of querying gl.

The Experiment:

For a quick prototype, we created a style with just one layer type, lines. The screenshot above shows timing logs for each gl.getProgramParameter() call. It’s roughly between 10 ~30ms and it seems to scale with the number of attributes.

In line.vertex.glsl there are two fixed attributes a_data and a_pos_normal, by adding a tiny predefined metadata object we can quickly lookup the number of fixed attributes at runtime.

export const shaderMetaData = {
    line: 2,
    lineGradient: 2,
    linePattern: 2,
    lineSDF: 2,
    clippingMask: 1
}

We can likely generate this at compile time with some codegen that analyzes the shader text, rather than updating it by hand.

For calculating the variable attributes, i,e the ones that depend on runtime-styling parameters, we can go through all attribute Binders and sum up the number of vertex attributes.

The Results:

image1

The attribute Query time is down from 10 ~30ms to sub 1ms. 🎉

The experimental branch lives here.

cc @mapbox/gl-core @mapbox/gl-js

@arindam1993 arindam1993 added api 📝 performance ⚡ Speed, stability, CPU usage, memory usage, or power usage and removed api 📝 labels Mar 6, 2020
@kkaefer
Copy link
Member

kkaefer commented Mar 6, 2020

Awesome! That sounds like a good reduction and brings us closer to having GL JS work in the Brave browser's paranoia mode.

We could should find a way to generate the metadata automatically from the GLSL files.

@kkaefer
Copy link
Member

kkaefer commented Mar 6, 2020

As a next step, we already call gl.bindAttribLocation before linking the shader. We still call gl.getAttribLocation to figure out which attributes will actually be in use for DDS. However, we actually know this because we set the corresponding #defines.

For uniforms, it's a little trickier: There's no way to bind uniforms to explicit IDs in WebGL. WebGL 2 uses GLSL ES 3.0, which allows layout qualifiers which we can use to bind them to particular IDs. However, WebGL 2 isn't supported in Safari and IE.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
performance ⚡ Speed, stability, CPU usage, memory usage, or power usage
Projects
None yet
Development

No branches or pull requests

3 participants