-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
Combine line shaders #10894
Combine line shaders #10894
Conversation
3477b5d
to
3a90a46
Compare
13afd42
to
3ac84fa
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice! Left a few questions but nothing major, glad to see such a consolidation.
#pragma mapbox: initialize lowp float floorwidth | ||
#pragma mapbox: initialize lowp vec4 dash_from | ||
#pragma mapbox: initialize lowp vec4 dash_to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any risk of crossing the GL_MAX_VERTEX_ATTRIB for low-end devices for native? I recall that a common denominator for es 2 is 8 (safe to use). We are at 9 from this PR, I'm not sure if after this change all of these #pragma
s may be used at once but there might be ways to consolidate them if that's a possibility. (Refer https://chromium.googlesource.com/angle/angle/+/HEAD/doc/ResourceLimits.md.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a really good point! I was thinking to wrap these too with #ifdefs but it had some issues, maybe this pragma is evaluated before them? I'll check how else could I wrap these.
Edit: I realized wrapping doesn't matter because we need to consider the edge case where all of the attributes are used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems very important to respect these limits, but just out of curiosity: since this PR consolidates but does not change the functionality, it should be possible to overcome this with judicious ifdef's or similar, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've looked into this a bit more and noticed that the shader for the dash line had also more than 8 attributes. It could be an issue on old devices, but since it was already implemented like that, this PR probably won't cause more issues.
If I understand it correctly #pragma mapbox
will only produce attributes when the property is calculated. So with the attributes above, the cases when there could be more than 8 only happens when both gradient and dash are enabled, and at least 4 properties are calculated. Otherwise I think it should work fine.
For those cases maybe it would be good to implement a validation which was discussed here: #4879
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rreusser I think yes but also this PR enables the combined usage of dash and gradients, so technically it extends the scope of the shader a bit and might use more attributes when both of them are used at the same time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe for now dash and gradient combined usage could be still disabled. On older devices it could be done with two passes to overcome the limitation, which could be implemented later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And another possible workaround: maybe I could pack a_linesofar
, a_uv_x
, and a_split_index
into a vec3 and upload them as a single attribute. The downside is that they need an extra operation to unpack them, but this way we would have the same amount of attributes as we had before in line_sdf.vertex.glsl
.
What do you think?
Edit: I've pushed up the changes for this idea.
const values = []; | ||
if (hasDash(layer)) values.push('RENDER_LINE_DASH'); | ||
if (layer.paint.get('line-gradient')) values.push('RENDER_LINE_GRADIENT'); | ||
return values; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a blocker for this PR and could be deferred, but wondering if these new shader variants are still compiled as part of the shader pre-compilation step (introduced by commit b93d709), if it's not we should add a follow up ticket to look at that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've checked it now and I think it does. At least in painter.js
I can see the program in the cache
and the keying also depends on these define values. (I've actually written this based on the circleDefinesValues
which are used in a similar way.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for checking that one! That makes sense.
d1aafc6
to
f9e8e73
Compare
@astojilj also noted that it would be better for perfomance to keep the line uniform values separated in |
f9e8e73
to
0c5b453
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks for looking at the attribute limit.
@endanke can you share a benchmark run result for this PR (comparing this and the previous commit) (using benchmap-js), just to make sure there are no unexpected performance regressions? |
@mourner Thanks for the note, I was just wondering which tool should we use for the benchmarks! |
@mourner attached the test results |
Looks great! 👏 👏 Just a quick check: if this PR did have a detrimental effect on performance, would we expect it to show up in the benchmarks? From what I understand, we gauge two things: 1) js load time (this PR saves some bytes, but I guess not enough to show up), and 2) speed index, which scores based on how long it takes pixels to reach their final color (which I suspect may be limited by tile loading and bucket processing and perhaps not by GPU performance) An idea: once the map loads and we're all done computing load time and speed index, maybe we could set I love the benchmarks; I just want to be careful not to read into them something that we're not actually measuring. cc @ansis |
@rreusser fair point and I agree it's a good idea to measure the GPU time specifically.
I've ran it 5 times for both commits using Google Chrome 92.0.4515.107. The results on average are:
As I understand this metric is in nanoseconds, so the change doesn't seem too drastic. Of course it's a very specific environment, so it would be better to run something similar in our test environment. |
Thanks for testing that out! 👏 I know I'm being pedantic, but I'm admittedly trying to help make sure we're all very clear on what the benchmarks do and don't measure. I suppose what the above benchmarks tell us is that the change in bytes loaded and… probably mostly shader compilation doesn't impact performance. As far as the GPU goes, I guess the number of line fragments will probably always be so small that it's unlikely to impact overall rendering even if we really try to accurately measure the difference. (This makes me think I should benchmark fog since that probably does have a measurable impact on rendering) |
@rreusser no worries at all, I agree it's important to evaluate these changes! I'll also make some further tests in GL-Native, including a case where a large amount of lines are rendered at the same time. Maybe we could use similar stress tests for different layer types as well. |
This PR combines the dash array, gradient, and regular line style related shaders. It will make the long-term maintenance easier and also enable the combined usage of dash array with gradient fills.
I've purposefully kept the separate shader for the
line-pattern
property, because currently we don't have a use-case for it's combined usage with the other types. It has also a bit more different fragment shader that the other 3 variations.Visual changes: See the newly added render test expectation for the combined usage of
line-gradient
andline-dasharray
.API changes: This PR will remove the
Disabled by line-dasharray
requirement from theline-gradient
property.GL-Native: I'll implement the native port.
Launch Checklist
@mapbox/map-design-team
@mapbox/static-apis
if this PR includes style spec API or visual changes@mapbox/gl-native
if this PR includes shader changes or needs a native portmapbox-gl-js
changelog:<changelog>Add support for combined usage of line-gradient and line-dasharray</changelog>
@mapbox/map-design-team @mapbox/static-apis