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

Optimize the arcTo function to use gl.LINES #1178

Closed
obiot opened this issue Feb 19, 2023 · 1 comment
Closed

Optimize the arcTo function to use gl.LINES #1178

obiot opened this issue Feb 19, 2023 · 1 comment

Comments

@obiot
Copy link
Member

obiot commented Feb 19, 2023

Currently, batch drawing is only enabled for shapes using gl.LINES as draw mode. Reason being that when batching primitives that use gl.LINE_LOOP or gl.LINE_STRIP it produces "artefacts" with lines being added between the different shapes corresponding starting point and end point.

To fix batch drawing for Circle/Ellipse and RoundedRect, arcTo should be rewritten in a way where we only use gl.LINES. Problem being that it then generates a huge amount of data (since it literally double the amount of vertices, and therefore ends up being a performance killer as well).

Best approach ultimately, would be to use a shader to draw both ellipse and rounded rectangle

For reference here is a quick benchmark that compare rectangle and circle stroke performances:

melonJS 15.0.0 (M1 Max) Stroke (rect) Stroke (circle)
500 op/s 60 fps 60 fps
1000 op/s 60 fps 60 fps
2500 op/s 60 fps 50 fps
5000 op/s 60 fps 25 fps
10000 op/s 60 fps 12 fps
15000 op/s 60 fps 8 fps

As a final note, performances are only dropping when drawing more than 2500 circles per frame.

@obiot
Copy link
Member Author

obiot commented Aug 5, 2023

With this last commit, we conclude for now a series of update and improvements to our WebGL renderer that started with version 14.4, and aimed to improve the API and improve performances drastically. This includes :

  • Enable batching for all primitive drawing operations
  • Proper Path2D-like API implementation (mimicking the canvas native Path2D API)
  • Optimize access to texture and drawing operations
  • Faster implementation of few utility function (including color packing and friends)
  • Fix potential memory leak when saving/restoring the renderer context or when deleting texture
  • Fix how Alpha and globalAlpha values are applied (so that both Canvas and WebGL renderer behaviour match)

As you can see in the table below, we got now up to 81% performance improvements when drawing primitives, and up to 50% improvements when drawing sprites. With the latter now allowing to claim that melonJS can draw 15'000 sprites per frame at 60fps.

Perf Inc   14.4.0 14.5.0 15.0.0 15.3.0 15.9.0 Total
Stroke (circle) 10000 op/s n/a 25% 53% 2% 25% 66%
Stroke (rect) 10000 op/s n/a 15% 75% 0% 0% 75%
Fill (circle) 10000 op/s n/a 25% 25% 0% 0% 25%
Fill (rect) 10000 op/s n/a 3% 81% 0% 0% 81%
Sprite 10000 op/s n/a 17% 17% 0% 0% 17%
Sprite 15000 op/s n/a 19% 19% 38% 0% 50%

Of course there are still room for improvements. Looking at the complete benchmark here, there are still some room to improve primitive drawing especially for circle fill operations. But as far as batching is concerned here we are good enough.

Moving further definitely will require using a proper shader to draw primitive. But in my opinion, unless your game is purely based on drawing thousands of full circle all over the screen, a shader might not be really necessary with the level of performance we have today. but hey, if anyone is up to the task and want to contribute, please do ! :)

@obiot obiot closed this as completed Aug 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant