Skip to content

Draw pen lines via fragment shader #438

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

Merged
merged 5 commits into from
Feb 27, 2020

Conversation

adroitwhiz
Copy link
Contributor

@adroitwhiz adroitwhiz commented Apr 19, 2019

Resolves

Kinda resolves #420?
Also resolves scratchfoundation/scratch-gui#4313 [EDIT: and now resolves #306]

Proposed Changes

This changes the PenSkin's line-drawing routine from a primarily vertex-based operation to a fragment-based one. Lines are now drawn via a screen-space pixel shader that provides proper antialiasing.

PenSkin.drawLineOnBuffer() now draws a single axis-aligned quad. The quad's fragment shader, given the endpoints, color, and thickness of the line, properly computes antialiased line coverage for each pixel inside it.

This has two effects:

  1. It gets rid of all the jaggies on the edges of each line
  2. It makes dots truly circular

This still doesn't completely match 2.0. In 2.0, "size 1" lines appear thicker at certain angles, and pen points render at a different offset from pen lines. The former might be worth investigating, but in my opinion the latter behavior is too confusing/annoying to be worth emulating.

On My Machine™, it runs 236783324 at the same speed, suggesting the bottleneck is in the VM now, but more comprehensive benchmarking across different GPUs would be wise.

I've done very little WebGL, so a lot of cleanup/refinement is probably necessary.

Current This PR Scratch 2.0
1-before 1-after 1-scratch2
Pen stroke test
2-before 2-after 2-scratch2
Pen stroke test 2
3-before 3-after 3-scratch2
Pen roundness test

EDIT: This may be a good test project. Make sure to run this multiple times-- there's a lot of weird variance. It looks like most of the time (in both the current code and this PR's) is spent in setUniforms, but fixing that would likely require UBOs, which are a WebGL 2 feature.

@adroitwhiz
Copy link
Contributor Author

It looks like disabling antialiasing (#502) also had an effect on pen lines:
image

Copy link
Contributor

@cwillisf cwillisf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is pretty cool - I like the nicer edges! @fsih and I had some readability & maintenance concerns while going over it, listed below.

@fsih
Copy link
Contributor

fsih commented Feb 4, 2020

@BryceLTaylor We're considering putting in this PR that should improve the appearance of pen lines, but we need to benchmark it first to make sure that it doesn't significantly impact pen performance, especially on devices with lower-power GPUs. Can we work together with you sometime to design benchmarking tests?

@cwillisf @fsih

@adroitwhiz
Copy link
Contributor Author

Review feedback has been addressed!

@adroitwhiz
Copy link
Contributor Author

Also, are you still interested in PenSkin code cleanups (e.g. #450)? There's a lot of unused code (like drawStamp) and unnecessary code (like the rectangle-drawing stuff) that could be removed.

@adroitwhiz
Copy link
Contributor Author

adroitwhiz commented Feb 11, 2020

I've done some benchmarking of my own to compare the performance of:

  • The old line implementation
  • The new line implementation, with the bounds calculation done in JS + uploaded to the vertex shader via a 4x4 matrix uniform
  • The new line implementation, with the bounds calculation done in the vertex shader

All numbers given are lines per second, per this benchmark.

"Workstation" (AMD Ryzen 7 1700 + NVIDIA GTX 780 Ti)

Run # Firefox (old lines) Firefox (new lines; bounds in JS) Firefox (new lines; bounds in VS)
1 44737 43776 49984
2 51013 51552 52207
3 51153 49608 60704
4 57501 52822 55869
5 54206 52198 56861
avg. 51722 49991 55125
Run # Chrome (old lines) Chrome (new lines; bounds in JS) Chrome (new lines; bounds in VS)
1 105232 82110 99655
2 104882 92315 96482
3 102243 85058 93570
4 100148 88413 101246
5 105377 90816 93938
avg. 103576 87742 96978
Run # Chrome SwiftShader (old lines) Chrome SwiftShader (new lines; bounds in JS) Chrome SwiftShader (new lines; bounds in VS)
1 13845 15255 13879
2 13930 15173 14053
3 13979 14622 14083
4 13883 15171 14062
5 13988 15242 14243
avg. 13925 15093 14064
Browser Avg. speedup over old lines (bounds in JS) Avg. speedup over old lines (bounds in VS)
Firefox -3.3% 6.6%
Chrome -15.3% -6.4%
Chrome SwiftShader 8.4% 1.0%

Old laptop (Intel Core 2 Duo T5800 + Intel Express 965)

Note that SwiftShader was enabled by default in Chrome due to GPU blacklisting.

Run # Firefox (old lines) Firefox (new lines; bounds in JS) Firefox (new lines; bounds in VS)
1 4730 3794 5152
2 4359 3437 6106
3 5211 4530 3747
4 5158 4619 3618
5 5380 3833 6065
avg. 4968 4043 4938
Run # Chrome (old lines) Chrome (new lines; bounds in JS) Chrome (new lines; bounds in VS)
1 21631 19560 21992
2 21960 22909 23525
3 22261 20026 23983
4 22721 24325 24186
5 23059 24182 24017
avg. 22326 22200 23541
Run # Chrome SwiftShader (old lines) Chrome SwiftShader (new lines; bounds in JS) Chrome SwiftShader (new lines; bounds in VS)
1 4068 3789 3558
2 6423 5372 4224
3 5570 6439 4371
4 5861 5905 4397
5 6961 6439 4433
avg. 5777 5589 4197
Browser Avg. speedup over old lines (bounds in JS) Avg. speedup over old lines (bounds in VS)
Firefox -18.6% -0.6%
Chrome -0.6% 5.4%
Chrome SwiftShader -3.3% -27.3%

EDIT: a previous version of this post said that Chrome VS was 5.4% slower. This was incorrect--it is 5.4% faster.

In general, it appears that:

  • The new pen line implementation is very slightly slower than the old one, but only by a few percent.
  • Moving the pen line bounds calculation to the vertex shader speeds up Firefox and Chrome on real GPUs, but slows down SwiftShader (Chrome's software renderer).

I'd like to see a benchmark on a low-energy-consumption laptop (like an "ultrabook" and/or Chromebook), which would probably have a CPU comparable to my laptop but a much faster GPU.

Copy link
Contributor

@cwillisf cwillisf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! I do have one question about the vertex coordinates, though.
Thanks for all the benchmarks!

Copy link
Contributor

@cwillisf cwillisf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're going to do a bit more performance testing but the code looks good!

@cwillisf
Copy link
Contributor

Also, are you still interested in PenSkin code cleanups (e.g. #450)? There's a lot of unused code (like drawStamp) and unnecessary code (like the rectangle-drawing stuff) that could be removed.

Sorry -- missed this comment. We're sort of re-evaluating our process for priorities so it's hard to know what should or shouldn't be prioritized until the dust settles. That said, I think code cleanups, such as addressing #450, are welcome but won't necessarily get a high priority. As long as you're OK with that, go for it ;)

@fsih fsih merged commit 8139afd into scratchfoundation:develop Feb 27, 2020
@adroitwhiz adroitwhiz mentioned this pull request Mar 3, 2020
13 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Improve quality of pen Pen is not a perfect circle Can't draw thin, crisp lines with pen
6 participants