-
-
Notifications
You must be signed in to change notification settings - Fork 644
-
-
Notifications
You must be signed in to change notification settings - Fork 644
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
Implement batch drawing on WebGL #591
Comments
- Platformer CPU usage went down from 30% to 24% on my MBA - The same patch is needed for fillRect - The next big win will come from batching [#591]
The referenced commit is not batching. All I did was reuse buffers in The process of batching involves keeping a record of everything you want to draw which uses the same texture, then constructing the triangle vertices/texture coordinates/indices, and sending the whole thing in a single This will make tile layers very fast (an entire map layer can be drawn in a single command), and sprites that use the same texture atlas will get the same benefit. |
Ah yes, i did mis understand your original post. But regardless this will definitely help :) |
It's a good first step, I agree. Thinking this morning how to structure the batching API, it seems natural to use So I want to rename
My second favorite is explicit batching, where something has to create a new Batcher, add items to draw, then flush the Batcher when ready. IMHO, this will be harder to get working with sprite objects, since there's really no "dividing line" between how sprites should be grouped. TMX has ObjectGroup for this purpose, but there's no guarantee that each object uses the same texture. The implementation of this As you might tell from this last description, the texture batching will actually "undo" a lot of the @agmcleod @obiot Please weigh in with your thoughts, especially in regard to how I want to redesign the Texture Atlas. |
My only concern with the second one is it could be limiting in some way. The first method is the one a developer at big viking games used, adding a webgl renderer to their canvas-like api. Similar to what we're doing really. |
Implicit batching is by far easier to manage. And if you cram everything into a single texture atlas (all tile sets, all sprites) then you can theoretically get the best possible performance by executing a single |
Yep exactly. Been trying to get better practice at doing so. Nicer to see a shorter list of files getting uploaded when i SCP stuff to my site. |
😋 Also there's something to be said about at least exposing an API to allow custom batching operations. Just in case someone actually wants to manage it themselves for some reason. |
I'll start this one. ;) |
- Precalculate the texture regions - Added a new uvMap to each region for WebGL
- Destination coordinates are only useful when trimming is used - melonJS does not support trimming
|
But merge "ticket-620" into master first ;)
|
- The WebGL Renderer adds a texture buffer, UV map, and index buffer to the atlas (these will be used later by the WebGL batcher)
The next step is adding the batcher to the WebGL Renderer. I think this won't be too much trouble. It just needs to do a little bit of memory accounting to avoid GC. I'll start with ~1KB memory buffers, and do the usual growth by 2x pattern (never shrinking). Second, I don't want to change the function signature for me.video.renderer.bindTexture(texture.getRegion(name)).drawImage(texture, x, y, ...); That's the best thing I can think of... Otherwise it should be really straightforward. |
On the other hand ... The |
Nice work on this so far jason. Do you think using instanceof and checking for different parameter types might duplicate/increase logic in the method? Could potentially refactor it into two methods if you think it would be worth it. |
It won't cause any duplicate logic, the code to select source coordinates will be different. It will also be the cleanest interface, IMHO. (This is probably the design I imagined when I proposed the batcher. I've just forgotten about the details.) Anyway, let's try it with |
This part of the work is actually quite involved (more than I had imagined!) It will require some shader rewrites. The best case scenario is the batcher uploads all of the textures, vertex buffers, UV maps, index buffers, etc to the GPU on the first frame, then only needs to provide transformation matrices for all of the sprites on each frame update. Some new points need to be addressed:
|
- It wasn't a 3D matrix (a 3D matrix is 4x4) - The only difference with me.Matrix2d is that me.Matrix3d also stored the hidden row to make the matrix square (required by WebGL) - This patch adds the equivalent hidden row storage to me.Matrix2d - Fixed me.Matrix2d.translate() - Some optimizations in me.Matrix2d Breaking changes: - me.Matrix2d.set() now requires all 9 arguments instead of only 6 - me.video.renderer.transform() now requires a me.Matrix2d instance instead of individual number arguments
- Fixes fragment shader compilation on some systems
… uniforms! - That was easier than I imagined. ;) - This should make it nicer to work with when building custom compositors!
- This change allows multiple shaders programs to be created; the singleton API is no longer used for shader program storage - Also fixes a missing description in documentation
- No need for a createShader method - Lookup the texture unit within the uploadTexture method
Alright, I think it's finally in a pretty stable state! The stuff I did tonight focuses on customizability of the WebGL environment. I don't want to tie any users down in regards to how they use WebGL. So now it's possible to use an entirely custom Compositor class by passing the Another important change is that the Most of my TODO lists are already done, which is exciting! And I heard today from @ldd that his tests show a nice improvement in rendering speed. Apparently in his tests, CanvasRenderer is capable of 142 objects max and WebGLRenderer is capable of over 500. This is a good start, but I want more! :) |
- This shows a potential optimization path; melonJS should only use known regions, so we can remove this safety net code! - Requires Texture [atlas] support for TMX tilesets and bitmap fonts, at the very least
…spritesheet some redundant code to be removed later.
- Lots of new FIXME comments :\ - The attributes and uniforms need to be configured as part of the `Compositor.useShader` function (maybe with a callback?) - The lines feel like they are rendered with poor precision; they are drawn perfectly on pixel boundaries without antialiasing...
- It seems the WebGLRenderer.setColor() overwrites the alpha channel, even for colors that don't specify an alpha component. - Maybe we should "fix" this in CanvasRenderer.setColor(); use the same me.Color code there
With the last few commits, stroke (line rendering) is finally in place. It's not efficient, though. At first glance, it appears that the depth buffer can make it very efficient; we just need a way to get the Z-coordinate information into the compositor. That will likely depend on the work in #637 In the meantime, there are a few FIXME comments that need to be addressed (especially with how the uniform variables are set, and the attribute bindings are handled). Second to that, getting fonts working (and in particular replacing the RTT thing in the debugPanel) is a priority for release. There's also a weird ghosting effect seen on the debugPanel with WebGLRenderer. That needs to be investigated further. |
…WebGL - Changes me.Font API to accept a Renderer reference (was Context2D reference) - renderer.drawFont() is now private - renderer.measureText() is gone! Use me.Font.measureText() - TODO: Create a second texture cache for font textures, so we aren't creating thousands of new textures each frame in the font_test example - XXX: Adds a new renderer.fontContext2D reference that we probably don't want to keep Replace this with the secondary texture cache - XXX: find a better way to integrate renderer.drawFont() and me.Font.draw() using the renderer.fontContext2D hack SUCKS!
Started working on font support in WebGL. The hack in the branch is pretty ugly, but it does make the me.Font API consistent! (Solves #619) It's currently very slow with the font_text example, because it spends most of its time creating and uploading massive textures. 😆 The secondary texture cache (proposed in the commit) will help that a little bit. A better way to support fonts in WebGL will be important long-term, but this will work for 2.1! |
Awesome! For now we can recommend keeping usage of the me.Font api simple, or to use Canvas instead :) |
…webgl renderer this "FIXME" was just bothering me :P:P:P
@parasyte if you don't mind, could you maybe create one or several small tickets to better identify what's left to be done for this one ? |
oh sorry, missed that, but for my defense this ticket is super long now ;P |
did you guys see that ? |
Closing this. Followup ticket is #637 |
This should reduce heavy usage of buffers, and number of draw calls required. Leading to a performance boost.
The text was updated successfully, but these errors were encountered: