Added support DrawInstancedPrimitives on OpenGL platforms#4920
Added support DrawInstancedPrimitives on OpenGL platforms#4920tomspilman merged 13 commits intoMonoGame:developfrom
Conversation
|
Looks like the build script is failing? |
|
Just syntax errors in the Android build... |
|
Also errors on the MonoMac build... |
|
You might want to cache the currently bound vbo(s) (with associated offest + attribs) in order to avoid calling glBindBuffer and glVertexAttribPointer redundantly, those are expensive calls. |
|
@tomspilman Should I just set some preprocessor directives to ignore those parts for MonoMac/GLES? MonoMac could handle instanced drawing though, right? The bindings just aren't there... But since it gets dropped some time soon(?) anyway, are preprocessor directives to ignore the breaking changes in this PR for now fine? |
|
@prollin Sounds like a good idea. I'll take a look when I have the time. Note that this wasn't cached before either. |
Yeah...
I don't know myself... @dellis1972 @cra0zy @prollin ? |
|
There are extensions we can check too I think "GL_NV_draw_instanced " and "GL_EXT_draw_instanced". I know GLES 3.0 supports instancing but it can probably wait until we remove OpenTK for that. |
|
Instanced drawing with GL_EXT_draw_instanced, GL_NV_draw_instanced and GL ES 3.0 works a bit different, because you can't use VertexAttribDivisor. You do get an instance identifier in your shader and can use that to do instance specific stuff (for example lookup in an array), you also get that instance id if you draw using the API as it is now (in the state of this PR), but you don't need it because you can set the attribute divisor. IMO it would be weird to use the same API for instanced drawing if we draw with that, because your shader has to be setup to use that instance id. 2 concerns I have with this:
Instanced drawing in DX with an instance ID seems to be possible as well, but not for all feature levels we support (I didn't look into this very much and I don't really know anything about DX). This would probably get really messy. Could be nice to support this in a way though, since most iOS and Android devices could benefit from instanced drawing as well. EDIT: GLES 3.0 supports VertexAttribDivisor! For GL ES 2.0 there is EXT_instanced_arrays that could help us out (if GL_EXT_draw_instanced is also available). Looks like Apple devices support it, but not sure about Android device support, I can't find a lot of information for that... |
|
So I'll just fix the build with |
|
@prollin On second thought I don't think we can do much better. I use the vertexBuffersDirty flag to check if attributes need to be applied. Since you can't change attribute binding without changing a vertex buffer due to how things work in MG with semantics and stuff, the vertexBuffersDirty flag maps 1-1 to if attributes should be applied. And when binding other vertex buffers, the check is done to see if it's not the same one and the dirty flag won't get set if it is. So I don't think we can do more caching there. Correct me if I'm wrong though, because I have a gut feeling I missed some caching opportunity. EDIT: It doesn't take offset into account, so that's an issue right now, I'll fix that. |
|
It definitely would need a bit more work to support proper caching. Having a dirty flag + currentOffset per slot might work. There is also the case where buffers are null (rendering without vbo). |
|
@prollin What do you mean when buffers are null? If you mean the DrawUser* functions, I left that as is, they don't use the ApplyAttribs function. Looks like VertexBufferBinding.VertexOffset was not taken into account in binding before... Is it alright if I fix that in this PR? It matters for caching too. I was thinking about using glDrawElementsInstancedBaseVertex, since that's available in OpenGL 3.2 (which we need for VertexAttribDivisor anyway), but in GLES it requires 3.2 which is higher than what we need for DrawElementsInstanced and VertexAttribDivisor (3.0), so that might make a difference for some devices. If we did use the BaseVertex variant it would mean we wouldn't need to rebind attributes when a different basevertex is passed in sequential draw calls. Should we do the BaseVertex version if it's available? We would have to use the regular version on GLES < 3.2 when we get there, which will require to branch based on GraphicsCapabilities.SupportsInstancedBaseVertex or something. |
|
Exams have me tied up a bit, I'll continue with this in a week or so. I assume there's no rush since an issue for this has been open since 2012 :p |
|
Exams are done, so I can continue with this. @dellis1972 Could you take a look at my comment above? Should I use BaseVertex versions if available? |
|
I think it's better now, can anyone review and/or test for performance penalties compared to develop? |
|
@Jjagg - FYI. This wasn't your build failure... retriggering the build. |
|
I figured as much since I just rebased. |
|
I just tested instanced rendering with a voxel engine I'm working on and performance with this is slightly better than with DirectX. For a 160 000 voxel model I'm getting ~60 fps with DirectX (it's not capped by fixed time step or anything in case anyone is wondering, just a coincidence) and ~65 fps with OpenGL and this branch. Here's a screenshot for interested peeps I think we should also compare performance for a game that does regular rendering with and without the changes of this branch, but I don't have anything lying around that I can use. I'll add some other renderers to the engine, so maybe later I can use it to test that too. I also didn't test mobile, but it uses the same code except it's the OpenTK binding instead of our own so it should Just Work. I think I can easily test Android (with an emulator) with the setup I have. |
|
Looking good. Two things to consider here before we can merge. We have some instancing unit tests in here: https://github.com/MonoGame/MonoGame/blob/develop/Test/Framework/Graphics/GraphicsDeviceTest.cs#L187 You should probably remove/change the It would also be good to verify we didn't break normal GL rendering in any way. If the graphics unit tests work under GL then that would be one good way to do that. |
Sounds good. I'll take another stab at getting GL unit tests running. I couldn't get SDL working last time... I kept getting BadImageFormatException (wrong bitness), and with the other bitness configuration it complained that it couldn't find suitable GL drivers... |
|
@james0x0A Can you try running the instanced rendering tests? They're here: https://github.com/MonoGame/MonoGame/blob/develop/Test/Framework/Graphics/GraphicsDeviceTest.cs#L205-L333 |
|
I am trying that now, but its a bit more complicated. It seems that the test compiles the shader on the fly and all of that is bound up with the content pipeline and mojo shader and so on. |
This gives GraphicsDevice.OpenGL the ability to use multiple vertex buffers when rendering. I also implemented DrawInstancedPrimitives, which was easy after fixing the buffers.
This makes GraphicsDevice on OpenGL support multiple vertex buffers and implements GraphicsDevice.DrawInstancedPrimitives.
@tomspilman |
|
@tomspilman @KonajuGames This has been here for a while. With it passing the GL tests can we get this merged soon? Probably best to wait for after 3.6.1 though, unless the plan is to cherry pick some commits for that. |
Yeah that is the plan... I will just cherry pick a few fixes for 3.6.1. |
|
@tomspilman Can this get merged? Kind of annoying to keep rebasing and it already passed the DesktopGL tests, including the instancing tests. |
|
@Jjagg - Rebase this once more and i'll merge it ASAP! |
|
@tomspilman I merged develop! |
|
Thanks @Jjagg .... next step would be testing this against the new OpenGL unit tests. |
Added support DrawInstancedPrimitives on OpenGL platforms

I made an attempt to implement instanced drawing for OpenGL. There is probably room for optimization in this PR, so it would be nice if someone had a nice hard look at it. I tested this with the xna mesh instancing sample, but there were some minor modifications. Test project link: https://github.com/Jjagg/InstancedSample
Fixes #4875, fixes #913, fixes #5744.