Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
Reduzindo travamentos decorrentes de compilações de shader (pipeline)
Aviso
Esta página se aplica apenas aos renderizadores Forward+ e Mobile, não ao Compatibility. Os ubershaders e a pré-compilação de pipeline dependem de funcionalidades disponíveis apenas em APIs gráficas modernas de baixo nível (Vulkan, Direct3D 12, Metal). O renderizador Compatibility usa OpenGL 3.3, OpenGL ES 3.0 ou WebGL 2.0, dependendo da plataforma. Essas versões carecem da funcionalidade para implementar efetivamente ubershaders e pré-compilação de pipeline.
Para evitar travamentos de shader no Compatibility, você precisa usar a abordagem legada de pré-carregar materiais, shaders e partículas, exibindo-os por pelo menos um quadro no frustum de visualização quando o nível está carregando.
A compilação de pipeline, também comumente conhecida como compilação de shader, é uma operação cara exigida pela engine para ser capaz de desenhar qualquer tipo de conteúdo com a GPU.
Shaders e materiais no Godot passam por várias etapas antes de poderem ser executados pela GPU.
Em termos mais precisos, a compilação de shader envolve a tradução do código GLSL gerado pelo Godot para um formato intermediário que pode ser compartilhado entre sistemas (como o SPIR-V ao usar o Vulkan). No entanto, esse formato não pode ser usado diretamente pela GPU.
A compilação de pipeline é a etapa em que o driver da GPU converte o formato intermediário do shader (o resultado da compilação do shader) em algo que a GPU possa realmente usar para renderização. Os drivers geralmente mantêm um cache de pipelines armazenado em algum lugar do sistema para evitar a repetição do processo toda vez que um jogo é executado. Esse cache geralmente é excluído quando o driver é atualizado.
Os pipelines contêm mais informações do que apenas o código do shader, o que significa que, para cada shader, pode haver dezenas de pipelines ou mais! Isso dificulta a compilação antecipada por parte de uma engine, tanto porque seria muito lenta quanto porque consumiria muita memória. Além disso, essa etapa só pode ser executada no sistema do usuário e é muito difícil compartilhar o resultado entre usuários, a menos que eles tenham exatamente o mesmo hardware e versão de driver.
Antes do Godot 4.4, não havia outra solução para a compilação de pipelines a não ser gerá-los quando um objeto aparecia na visão da câmera, levando ao infame shader stutter (engasgos de shader) ou travamentos que ocorrem apenas durante a primeira jogada. Com o Godot 4.4, novos mecanismos foram introduzidos para mitigar os travamentos decorrentes da compilação de pipelines.
Ubershaders: A Godot faz uso de constantes de especialização, um recurso que permite ao driver otimizar o código de um pipeline em torno de um conjunto de parâmetros como iluminação, qualidade de sombra, etc. Constantes de especialização são usadas para otimizar um shader limitando recursos desnecessários. Alterar uma constante de especialização requer a recompilação do pipeline. Ubershaders são uma versão especial do shader que é capaz de alterar essas constantes durante a renderização, o que significa que a Godot pode pré-compilar apenas um pipeline com antecedência e compilar as versões mais otimizadas em segundo plano durante o gameplay. Isso reduz significativamente a quantidade de pipelines que precisam ser criados.
Pré-compilação de pipeline: Ao usar ubershaders, a engine pode pré-compilar pipelines com antecedência em vários lugares, como quando malhas são carregadas ou quando nós são adicionados à cena. Ao fazer parte do processo de carregamento de recursos, os pipelines podem até ser pré-compilados em múltiplas threads em segundo plano, se possível, durante telas de carregamento ou até mesmo durante o gameplay.
A partir do Godot 4.4, o Godot detectará quais pipelines são necessários e os pré-compilará em tempo de carregamento. Esse sistema de detecção é majoritariamente automático, mas depende do RenderingServer ver evidências de todos os shaders, malhas ou recursos de renderização em tempo de carregamento. Por exemplo, se você carregar uma malha e um shader enquanto o jogo está rodando, o pipeline para essa combinação de malha/shader não será compilado até que a malha/shader seja carregada. Da mesma forma, ações como ativar MSAA ou instanciar um nó VoxelGI enquanto o jogo está rodando acionarão recompilações de pipeline.
Monitores de pré-compilação de pipeline
Compilar pipelines antecipadamente é o principal mecanismo que o Godot utiliza para mitigar engasgos de shader, mas não é uma solução perfeita. Estar ciente das situações que podem levar a travamentos de pipeline pode ser muito útil, e as soluções alternativas são bastante diretas em comparação com as versões anteriores. Essas soluções alternativas podem se tornar menos necessárias ao longo do tempo com futuras versões do Godot, conforme mais técnicas de detecção forem implementadas.
O depurador da Godot oferece monitores para rastrear a quantidade de pipelines criados pelo jogo e o passo que disparou sua compilação. Você pode ficar de olho nesses monitores enquanto o jogo roda para identificar possíveis fontes de travamentos (stutters) de shader sem ter que limpar o cache do seu driver toda vez que desejar testar. Aumentos repentinos nesses valores fora das telas de carregamento podem aparecer como engasgos durante o gameplay na primeira vez que alguém joga o jogo em seu sistema. Recomenda-se que você dê uma olhada nesses monitores para identificar possíveis fontes de travamento para seus jogadores, já que você pode não conseguir experimentá-los sem deletar o cache do seu driver ou testar em um sistema mais fraco.
Compilações de pipeline de um dos projetos de demonstração.
Nota
Podemos ver os pipelines compilados durante a jogabilidade e verificar quais etapas poderiam possivelmente causar engasgos. Note que esses valores apenas aumentarão e nunca diminuirão, pois os pipelines excluídos não são rastreados por esses monitores e os pipelines podem ser apagados e recriados durante a jogabilidade.
Canvas: Compilado ao desenhar um nó 2D. A engine atualmente não possui pré-compilação para elementos 2D e os travamentos aparecerão quando o nó 2D for desenhado pela primeira vez.
Mesh: Compilado como parte do carregamento de uma malha 3D e identificação de quais pipelines podem ser pré-compilados a partir de suas propriedades. Isso pode levar a travamentos (stutters) se uma malha for carregada durante o jogo, mas eles podem ser mitigados se a malha for carregada usando uma thread em segundo plano. Modificadores que fazem parte de nós, como sobreposições de materiais, não podem ser compilados nesta etapa.
Surface: Compilado quando um quadro está prestes a ser desenhado e objetos 3D foram instanciados na árvore de cena pela primeira vez. Isso também pode incluir a compilação para nós que sequer estão visíveis na árvore de cena. O engasgo ocorrerá apenas no primeiro quadro em que o nó for adicionado à cena, o que não resultará em um travamento óbvio se acontecer logo após uma tela de carregamento.
Draw: Compilado sob demanda quando um objeto 3D precisa ser desenhado e um ubershader não foi pré-compilado antecipadamente. A engine é incapaz de pré-compilar este pipeline por ter acionado um caso que ainda não foi coberto ou devido a uma modificação feita no código da engine. Leva a travamentos durante a jogabilidade. Isso é idêntico às versões do Godot anteriores à 4.4. Se você vir compilações aqui, por favor informe aos desenvolvedores, já que isso nunca deveria acontecer com o sistema de Ubershader. Certifique-se de anexar um projeto de reprodução mínima ao fazê-lo.
Especialização: Compilado em segundo plano durante o gameplay para otimizar a taxa de quadros. Incapaz de causar travamentos, mas pode resultar em taxas de quadros reduzidas se houver muitas ocorrendo por quadro.
Recursos de pré-compilação de pipeline
O Godot oferece muitos recursos de renderização que não são necessariamente usados por todos os jogos. Infelizmente, a pré-compilação de pipeline não tem como saber antecipadamente se um recurso específico é utilizado por um projeto. Alguns desses recursos só podem ser detectados quando um usuário adiciona um nó à cena ou altera uma configuração específica no projeto ou no ambiente. O sistema de pré-compilação de pipeline rastreará esses recursos à medida que forem encontrados pela primeira vez e ativará a pré-compilação deles para quaisquer malhas ou superfícies que forem criadas posteriormente.
Se o seu jogo faz uso desses recursos, certifique-se de ter uma cena que os utilize o mais cedo possível antes de carregar a maioria dos assets. Essa cena pode ser muito simples e fará o trabalho, desde que utilize os recursos que o jogo planeja usar. Ela pode até ser renderizada fora da tela por pelo menos um quadro, se necessário, ex.: cobrindo-a com um nó ColorRect ou usando um SubViewport localizado fora dos limites da janela.
Você também deve ter em mente que alterar qualquer um desses recursos durante a jogabilidade resultará em travamentos imediatos. Certifique-se de alterar esses recursos apenas a partir de telas de configuração, se necessário, e insira telas de carregamento e mensagens quando as alterações forem aplicadas.
MSAA Level: Ativado quando o nível de MSAA 3D é alterado nas configurações do projeto. Infelizmente, o uso de diferentes níveis de MSAA em diferentes viewports levará a travamentos, pois a engine só rastreia um nível por vez para realizar a pré-compilação.
Reflection Probes: Ativado quando um nó ReflectionProbe é colocado na cena.
Separate Specular: Enabled when using effects like subsurface scattering or a compositor effect that relies on sampling the specularity directly from the screen.
Motion Vectors: Ativado ao usar efeitos como TAA, FSR2 ou um efeito de compositor que exija vetores de movimento (como desfoque de movimento).
Normal e Roughness: Ativado ao usar SDFGI, VoxelGI, reflexos no espaço da tela, SSAO, SSIL ou ao usar o
normal_roughness_bufferem um shader personalizado ou CompositorEffect.Lightmaps: Ativado quando um nó LightmapGI é colocado na cena e um nó usa um lightmap bakeado.
VoxelGI: Ativado quando um nó VoxelGI é colocado na cena.
SDFGI: Ativado quando o WorldEnvironment ativa o SDFGI.
Multiview: Ativado para projetos XR.
Sombras de 16/32 bits: Ativado quando a configuração da precisão de profundidade dos mapas de sombra é alterada nas configurações do projeto.
Omni Shadow Dual Paraboloid: Ativado quando uma luz omni projeta sombras e usa o modo de parabolóide duplo.
Omni Shadow Cubemap: Ativado quando uma luz omni projeta sombras e usa o modo cubemap (que é o padrão).
If você presenciar travamentos durante a jogabilidade e os monitores relatarem um aumento repentino nas compilações durante a etapa Surface, é muito provável que um recurso não tenha sido ativado antecipadamente. Garantir que esse efeito esteja ativado enquanto carrega seu jogo provavelmente mitigará o problema.
Instanciação de pré-compilação de pipeline
Uma fonte comum de travamentos em jogos é o fato de que alguns efeitos só são instanciados na cena por causa de interações que só acontecem durante a jogabilidade. Por exemplo, se você tem um efeito de partícula que só é adicionado à cena por meio de um script quando um jogador realiza uma ação. Mesmo que a cena seja pré-carregada, a engine pode ser incapaz de pré-compilar os pipelines até que o efeito seja adicionado à cena pelo menos uma vez.
Felizmente, é possível para o Godot 4.4 e posteriores pré-compilar esses pipelines, desde que a cena seja instanciada pelo menos uma vez na cena, mesmo que esteja completamente invisível ou fora da visão da câmera.
Nó de projétil oculto anexado ao jogador em um dos projetos de demonstração. Isso ajuda a engine a pré-compilar os pipelines do efeito antecipadamente.
Se você está ciente de quaisquer efeitos que são adicionados à cena dinamicamente durante a jogabilidade e está vendo aumentos repentinos no monitor de compilações quando esses efeitos aparecem, uma solução alternativa é anexar uma versão oculta do efeito em algum lugar onde seja garantido que apareça.
Por exemplo, se o personagem do jogador é capaz de causar algum tipo de explosão, você pode anexar o efeito como um filho do jogador como um nó invisível. Certifique-se de desativar o script anexado ao nó oculto ou de ocultar quaisquer outros nós que possam causar problemas, o que pode ser feito ativando Editable Children (Filhos Editáveis) no nó.
Pré-calculador de shader
Desde o Godot 4.5, você pode optar por fazer o bake de shaders na exportação para melhorar o tempo inicial de inicialização. Isso geralmente não resolverá travamentos existentes, mas reduzirá o tempo necessário para carregar o jogo pela primeira vez. Este é especialmente o caso ao usar Direct3D 12 ou Metal, que têm tempos de compilação de shader iniciais significativamente mais lentos que o Vulkan devido ao passo de conversão necessário. Os próprios shaders da Godot usam GLSL e SPIR-V, mas Direct3D 12 e Metal usam formatos diferentes.
Nota
O gerador de shader só pode compilar o código-fonte para o formato intermediário (SPIR-V para Vulkan, DXIL para Direct3D 12, MIL para Metal). Ele não pode compilar o formato intermediário para a pipeline final, pois isso depende do driver da GPU e do hardware.
O assador de shader não substitui a pré-compilação de pipeline, mas visa complementá-la.
Quando ativado, o assador de shader agrupará o código do shader compilado no PCK, o que faz com que a etapa de compilação do shader seja totalmente pulada. A desvantagem é que a exportação demorará um pouco mais. O arquivo PCK ficará maior por alguns megabytes.
O assador de shader vem desativado por padrão, mas você pode ativá-lo em cada predefinição de exportação na janela de Exportação marcando a opção de exportação Shader Baker > Enabled.
Note que o assamento de shader só será capaz de exportar shaders para drivers suportados pela plataforma na qual o editor está rodando atualmente:
O editor rodando no Windows pode exportar shaders para Vulkan e Direct3D 12.
O editor rodando no macOS pode exportar shaders para Vulkan e Metal.
O editor rodando no Linux pode exportar shaders apenas para Vulkan.
O editor rodando no Android pode exportar shaders apenas para Vulkan.
O assador de shader só exportará shaders que correspondam à configuração de projeto rendering/rendering_device/driver para a plataforma de destino.
Nota
O assador de shader é suportado apenas para os renderizadores Forward+ e Mobile. Ele não terá efeito se o projeto utilizar o renderizador Compatibility, ou para usuários que fazem uso do fallback do Compatibility devido ao seu hardware não suportar os renderizadores Forward+ ou Mobile.
Isso também significa que o assador de shader não é suportado na plataforma web, já que a plataforma web suporta apenas o renderizador Compatibility.
Adicionalmente, o assador de shader não é suportado ao exportar um projeto usando o argumento de linha de comando --headless command line argument, já que o Godot não pode acessar a GPU ao rodar no modo headless.