Costumo fazer muita otimização prematura ao lidar com gráficos. Existem alguns princípios que sempre tento seguir:
- Mantenha o número de componentes D3D no mínimo. (Estados de renderização, buffers, shaders, etc.)
- Somente ligue componentes se for absolutamente necessário. (Não está vinculado, etc.)
- Especialize os componentes o máximo possível. (Defina apenas as BindFlags necessárias, etc.)
Isso me levou a criar invólucros muito elaborados para gerenciar os componentes criados e o estado atual da tubulação. Isso não apenas consome muito do meu valioso tempo de desenvolvimento, mas também adiciona outra grande camada de complexidade.
E o pior de tudo: nem sei se tudo vale a pena.
Algumas das minhas considerações de otimização já podem ser implementadas em um nível inferior e estou apenas replicando-as, perdendo tempo adicional na CPU. Outras considerações podem ser completamente desnecessárias, pois o efeito no desempenho é insignificante.
Então, minhas perguntas são:
- Quais das diretrizes acima são válidas e em que medida devo segui-las?
- Como a GPU lida com as mudanças de estado?
- O que acontece se eu alterar um estado que nunca é usado? (Nenhuma chamada de empate sendo feita enquanto estiver ativa.)
- Quais são as penalidades de desempenho reais para vincular os vários componentes diferentes?
- Que outras considerações de desempenho devem ser feitas?
Por favor, não me diga apenas que eu não deveria me importar com desempenho até atingir os limites reais. Embora isso seja obviamente verdade do ponto de vista prático, estou principalmente interessado na teoria. De alguma forma, preciso combater o desejo de criar a estrutura gráfica ideal e acho que não posso fazer isso com a habitual "palestra prematura de otimização".
Gerenciando componentes
Atualmente, estou escrevendo aplicativos DirectX 11 em C # usando o SlimDX como um wrapper gerenciado. É um invólucro de nível muito baixo e minha abstração atual é construída sobre ele.
Existem algumas vantagens óbvias ao usar uma abstração do Direct3D. Configurar o ambiente, carregar shaders, definir constantes e desenhar uma malha é muito mais simples e usa muito menos código. Além disso, como ele gerencia a criação e o descarte da maioria dos componentes, eles podem ser reutilizados automaticamente em todos os lugares e evito quase completamente o vazamento de memória.
- Como você geralmente gerencia todos os componentes e recursos gráficos?
- Você pode recomendar que os wrappers gerenciados façam algo semelhante ao meu exemplo abaixo?
Aqui está um exemplo da minha implementação atual. Estou muito feliz com a interface. Possui flexibilidade suficiente para minhas necessidades e é muito simples de usar e entender:
// 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();
}
fonte
Respostas:
Eu gosto da abordagem de abstração descrita por Hodgman nestes tópicos no gamedev.net:
Ele descreve um sistema de renderização em três camadas:
Em conclusão, este modelo resolve os dois problemas de uma só vez.
fonte