Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
Generic 3D Models #1289
This pull request attempts to leverage the new generic vertex and index buffer abstractions to generically implement a new 3D model class to replace the old duplicate ones. This pull request continues alongside #1238 and will also make newer and alternative graphics systems easier to support, such as OpenGL ES or Direct3D11, without sacrificing performance, expressiveness, or compatibility as I will demonstrate in the proceeding benchmarks.
Noteworthy changes made
This pull request wouldn't be complete if I didn't run some benchmarks. I clearly ran several games I have to check the performance, but the results I am going to share here are specifically from testing the GMS cubes demo.
Note: I used GPU-Z to monitor VRAM usage and I took the difference in VRAM occupation just before and after closing the game.
Some consistent issues that exist on master too that I want to note that this pr will not be fixing:
This pull request unoptimized
Adjacent primitive combining
This optimization is fairly obvious. If you have two primitives of the same type that have the same vertex format adjacent in the model, you can simply treat them as a single primitive and thus make a single draw call. It was during this step that I had to provide a mechanism to hash the vertex formats for quick comparison.
This optimization is one of the reasons why a function like
I saw some significant speedup in OpenGL1 from this optimization, but less so in Direct3D9 and OpenGL3 due to anomalies in their primitive batching (the fonts etc require a different kind of optimization).
Vertex format caching
This optimization is also fairly obvious, but I actually didn't think it would bring the performance that it did. Originally I was trying to add
As Rusky, Josh, and I discussed privately, this is better than expecting the user to have to worry about deleting and cleaning up vertex formats, which GMS doesn't. So you can freely call
Doing it in the general source is best because it doesn't require that I also add it to each system. Adding it for each peer vertex format would just be redundant, the D3D/OGL backends use the same ids.
Vertex format peer caching
Caching the native peer (in this case the actual vertex declaration) gave another huge performance boost to D3D9. I didn't want to mess up D3D11 so I did not touch it. I will come back to D3D11 later on when I have projection functions working and benchmark how to optimize it. OpenGL1 uses fixed function pipeline and client state so there's no real way to cache the vertex format at all. OpenGL3 is still using a single default VAO and sort of doing what GL1 does, so I didn't want to mess with it yet, but I did get a nice boost by using the cached lookup function for an attribute location.
Adjacent triangle strip combining using degenerates and buffer orphaning
I had reservations about doing this one, even though we did it before as well. Combining all primitive types together using an index buffer, which would also make fans work on mobile, is still an option. But in reality, there is nothing wrong in 2018 with using degenerate triangles to combine strips, even old graphics cards handle this really well.
During this phase, I discovered proper buffer orphaning and realized why TheExDeus had GL_STREAM_DRAW instead of GL_DYNAMIC_DRAW. Originally I did not properly understand the impact on performance this has when combined with buffer orphaning. By doing this first, I got a 50 fps boost in GL3, but then I realized instead of buffer orphaning we can just always call glBufferData because we never care about the previous contents of our buffer. By never calling
@@ Coverage Diff @@ ## master #1289 +/- ## ========================================== + Coverage 15.2% 15.43% +0.22% ========================================== Files 168 167 -1 Lines 17434 17380 -54 ========================================== + Hits 2651 2682 +31 + Misses 14783 14698 -85
This is looking to be a marvelous change. I need to review the principle file (GSmodel.cpp) a little more closely tomorrow. I'm too tired for it right now. I think that's where I'll find any problems with behavior (I'm skeptical of the way you're calling four other functions in each vertex function, and each of those is making the same if-then check and doing something expensive without falsifying the original conditional).
Anyway, I've left some other comments, mostly on readability, inline. I don't see any glaring problems with what you're doing, and the numbers don't lie, either.
Fantastic job on this, and especially good work responding to those comments. I am happy for this to submit in its current state.