This is a problem that I've been thinking about for a while, and I think I may have found an idea that I like. So, newer graphics APIs like Vulkan put all of the render state in a single giant block and you have to basically recreate the entire state block all at once just to change one state. Direct3D11 has state blocks that are more granular, but Direct3D12 is apparently the same as Vulkan according to Rusky. That's obviously too inefficient, so what we would ideally do is just cache all of the render state generically. Then when the user goes to draw, we flush all of the render state at once.
This idea has advantages and disadvantages to it. The biggest advantage is that redundant state changes are ignored, and GM users are prone to making these, so that's a good thing. Another advantage is that it's clearly going to result in the simplification and deduplication of much of our graphics systems. Things like
d3d_start will then be possible to move to
General/ like Josh has always wanted. Now, one disadvantage I can see right now is that this will mean our graphics are no longer as hookable by user extensions. If a user extension draws its own vertex buffer it won't have any of our render state because none of it has been flushed to the device/context. But that's ok, because the same is true of GMS and we provide flush functions like they do.
@@ Coverage Diff @@ ## master #1636 +/- ## ========================================== + Coverage 18.82% 18.85% +0.03% ========================================== Files 169 165 -4 Lines 16782 16685 -97 ========================================== - Hits 3159 3146 -13 + Misses 13623 13539 -84
|Impacted Files||Coverage Δ|
|... and 10 more|
UNMATCHED: Regression tests have indicated that graphical changes have been introduced. Carefully review the following image comparison for anomalies and adjust the changeset accordingly.
I want to document here an experiment I ran against 48ed55f with GM8.1 and GMS. I've discovered that this is apparently not how GM deals with the 3D shapes functions having repetition. They appear to either maintain their own internal state for repetition on batches or are resetting the state when the batch is flushed.
My experiment basically turns off interpolation. It then draws a d3d floor with repetition greater than 1. It then draws a d3d primitive where I specify repetition in the texture coordinates. What happens in both GM8.1 and GMSv1.4 is that the floor has repetition but the primitive has clamped texturing. What occurs in ENIGMA in this pull request is that both are drawn with repetition, while in master both are drawn without repetition. For now, I find this anomaly acceptable and I don't think many people will notice. We can look a little closer at it again if somebody brings it up, but for now, we know this pull request is no different than our current master.
d3d_set_projection_ortho(0,0,room_width,room_height,0); var tex; tex = background_get_texture(background0); // initially set texture interpolation off texture_set_repeat(false); // following overrides texture repetition somehow for last 2 parameters d3d_draw_floor(0,0,0, room_width/2,room_height,0,tex,3,3); // lets see whether texture repetition is still on d3d_primitive_begin_texture(pr_trianglestrip, tex); d3d_vertex_texture(room_width/2,0,0,0,0); d3d_vertex_texture(room_width/2,room_height,0,0,3); d3d_vertex_texture(room_width,0,0,3,0); d3d_vertex_texture(room_width,room_height,0,3,3); d3d_primitive_end();
Leaving some more research here for people from the future. I did have hugar test out these changes on Linux and he has older drivers that don't support GL2. He didn't have a single problem with these changes by the end of this when I had all the regressions fixed.
I also did some research to discover that Google's ANGLE project is essentially doing what this pull request does for its GLES1 renderer. What they have is a giant block of code that flushes the state starting with features->textures->client state->matrices->shading,materials,&lighting->etc. The only additional thing is they have dirty state tracking like I proposed in #1681.
The D3D9 renderer seems to be a bit messier as it has long and complicated state blocks just for clear.
Also, it seems changing a single state in the D3D9 renderer for ANGLE works like ENIGMA master did prior to this pull request. We can see that changing the zwriteenable state is a function call specific to their D3D9 renderer.
Overall, it looks like ANGLE's D3D renderers are a mess while their OpenGL ones are abstract. So at least ENIGMA has all of its backends abstract rather than just some of them. It sounds in some ways the work being done on ANGLE since 2013 for multiplatform is mirrored a lot by ENIGMA too.