I often tend to do a lot of premature optimazation when dealing with graphics. There are a few principles I always try to follow:
- Keep the number of D3D components to a minimum. (Render states, buffers, shaders, etc.)
- Only bind components if absolutely necessary. (Not bound already, etc.)
- Specialize the components as much as possible. (Only set necessary BindFlags, etc.)
This lead me to building very elaborate wrappers for managing the created components and the current pipeling state. Not only does this consume a lot of my valuable development time, it also adds another big layer of complexity.
And worst of all: I don't even know if it is all worth the trouble.
Some of my optimization considerations may already be implemented on a lower level and I am just replicating them, additionally wasting time on the CPU. Other considerations may be completely unnecessary, since the effect on performance is negligible.
So my questions are:
- Which of the above guidelines are valid and to which extent should I follow them?
- How does the GPU handle state changes?
- What happens if I change a state that is never used? (No draw call being made while it is active.)
- What are the actual performance penalties for binding the various different components?
- What other performance considerations should be made?
Please don't just tell me, that I just should not care about performance until I hit actual limits. While that is obviously true from a practical point of view, I am mainly interested in the theory. I somehow need to combat the urge of building the optimal graphics framework and I don't think I can do that with the usualy "premature optimization lecture".
Managing components
I am currently writing DirectX 11 applications in C# using SlimDX as a managed wrapper. It is a very low level wrapper and my current abstraction is built on top of it.
There are some obvious advantages when using a Direct3D abstraction. Setting up the environment, loading shaders, setting constants and drawing a mesh is much simpler and uses a lot less code. Also, since it manages creation and disposing of most components they can be automatically reused everywhere and I almost completely avoid memory leaks.
- How do you usually manage all the graphics components and resources?
- Can you recommend any managed wrappers doing something similar to my example below?
Here is an example of my current implementation. I am quite happy with the interface. It has enough flexibility for my needs and is very simple to use and understand:
// Init D3D environment
var window = new RenderForm();
var d3d = new Direct3D(window, GraphicsSettings.Default);
var graphics = new GraphicsManager(d3d.Device);
// Load assets
var mesh = GeometryPackage.FromFile(d3d, "teapot.gp");
var texture = Texture.FromFile(d3d, "bricks.dds");
// Render states
graphics.SetViewports(new Viewport(0, 0, 800, 600);
graphics.SetRasterizer(wireFrame: false, culling: CullMode.Back);
graphics.SetDepthState(depthEnabled: true, depthWriteEnabled: true);
graphics.SetBlendState(BlendMethod.Transparency);
// Input layout
graphics.SetLayout("effect.fx", "VS", "vs_4_0",
new InputElement("POSITION", 0, Format.R32G32B32_Float, 0),
new InputElement("TEXCOORD", 0, Format.R32G32_Float, 0)
);
// Vertex shader
graphics.SetShader(Shader.Vertex, "effect.fx", "VS", "vs_4_0");
graphics.SetConstants(Shader.Vertex, 0, 4, stream => stream.Write(wvpMatrix));
// Pixel shader
graphics.SetShader(Shader.Pixel, "effect.fx", "PS", "ps_4_0");
graphics.SetTexture(Shader.Pixel, 0, texture);
graphics.SetSampler(Shader.Pixel, 0, Sampler.AnisotropicWrap);
graphics.SetConstants(Shader.Pixel, 0, 1, stream => stream.Write(new Color4(1, 0, 1, 0);
d3d.Run(() =>
{
// Draw and present
d3d.BackBuffer.Clear(new Color4(1, 0, 0.5f, 1));
graphics.SetOutput(d3d.BackBuffer);
graphics.Draw(mesh);
d3d.Present();
}