Link

Comparação entre Vulkan e OpenGL

Vulkan é uma API C99 (KHRONOS, 2018) e, assim como o OpenGL, é baseada em pontos de entrada de função livre (KARLSSON, 2016). Entretanto, o OpenGL é baseado em uma máquina de estado global que está ligada ao contexto atual do OpenGL (DARBY, 2014). Todas as configurações (por exemplo, glLineWidth()) são alimentadas pelas funções globais para o contexto em execução e esse contexto lembra tudo até que a sua configuração seja substituída por uma nova ou ele seja destruído. Vulkan não possui um contexto ou uma máquina de estado. Seus status e dados são ligados a um objeto de instância. Muitos dados também são passados entre as funções usando um número de enumerações – ao contrário do OpenGL, Vulkan é fortemente tipado. Vulkan também não está preso ao paradigma de que “algo será desenhado na tela”. Por exemplo, um aplicativo pode exigir uma renderização fora da tela, mas também pode não exigir a renderização. Diferente do OpenGL, Vulkan pode ser usado para operações puramente computacionais – como normalmente esperaríamos do OpenCL (MICHAUD, 2017).

Vulkan é considerada uma API de mais baixo nível, comparada às API mais antigas. Nas duas últimas décadas, a maioria das APIs gráficas foi de alto nível, como OpenGL e Direct3D 11 (e anterior), o que significa que há uma quantidade maior de abstração. Isso geralmente facilita o trabalho dos programadores, ao custo de algumas otimizações de desempenho. No entanto, alguns desenvolvedores queriam maneiras de extrair mais desempenho do hardware e basicamente pediram acesso de “baixo nível” ao hardware. Isso significa mais trabalho em alguns casos, mas também pode melhorar o desempenho se soubermos o que estamos fazendo.

No OpenGL, a camada de aplicação é mais fina em comparação com a camada de driver, já que a automação do driver OpenGL leva em conta o gerenciamento de recursos e o rastreamento de estados. Vulkan é o oposto disso. Isso garante que o driver esteja mais próximo do hardware com menos sobrecarga (PAWEL, 2016b). É responsabilidade do aplicativo gerenciar lógica, recursos e estados. Por exemplo, o gerenciamento de memória na API Vulkan é muito mais explícito do que nas APIs anteriores. Os desenvolvedores podem alocar e desalocar memória no Vulkan, enquanto no OpenGL o gerenciamento de memória é oculto do programador. Os drivers OpenGL decidem sobre o posicionamento dos recursos de acordo com uma heurística interna, que varia entre os fornecedores, e pode produzir posicionamento abaixo do ideal ou comportamentos inesperados se, por exemplo, o driver decidir mover o recurso posteriormente (HECTOR, 2015; KUBISCH, 2016).

A inovação mais importante da API da Vulkan é o princípio do controle explícito. Como mencionado anteriormente, um grande problema com o OpenGL é a sobrecarga do driver. O OpenGL permite que o programador altere o estado a qualquer momento, o que pode resultar em enormes custos de desempenho, especialmente quando o programador altera o estado de renderização do OpenGL muito próximo de um comando de desenho ou computação. Em contraste, no Vulkan o programador deve informar explicitamente ao driver tudo o que ele fará antecipadamente. Essa explicitação simplifica o driver da GPU e favorece a consistência de vários fornecedores, o que torna o Vulkan muito portátil e flexível. Além disso, o controle explícito reduz a sobrecarga e a latência do driver, o que leva a uma carga de CPU reduzida e, no final, a um melhor desempenho (HECTOR, 2015).

O processo de submissão de trabalhos do OpenGL não é direto e é dependente do agendador do driver. No Vulkan, por outro lado, os trabalhos são enviados antecipadamente assim que são entregues ao driver. Isso faz com que o Vulkan seja altamente previsível quando comparado ao OpenGL (SINGH, 2016).

Os drivers Vulkan não fazem validação das chamadas de desenho (exceto no nível do sistema operacional). Esta é uma das principais razões pelas quais a API Vulkan é mais eficiente que o OpenGL. Cada chamada do OpenGL tem que passar por uma série de verificações de estado e código de validação que verifica por possível comportamento indefinido1. Isso adiciona sobrecarga às chamadas de desenho (EKSTRAND, 2016).

1 É possível limitar isso por meio de extensões como GL_KHR_no_error, mas o suporte para essa extensão é limitado e não faz muita diferença na maioria das implementações (DAVIS, 2016).

O OpenGL foi originalmente criado para workstations gráficas fixas com renderizadores diretos single-threaded e memória dividida. Inicialmente não foram feitas considerações sobre arquitetura de CPU multi-core e multithreading. Como consequência disso é muito difícil aproveitar os recursos de threading para melhor utilizar a CPU. Em contrapartida, o Vulkan é especialmente projetado para permitir que os desenvolvedores explorem totalmente seu recurso multithreading de maneira transparente, sem estados globais implícitos. Trabalhos sob diferentes threads permanecem separados do momento em que são criados e enviados para execução. Buffers de comando podem ser gravados simultaneamente e enviados através de vários threads. No OpenGL, não apenas os comandos são registrados em um único thread, mas são gravados implicitamente pelo driver e enviados ao hardware sem nenhum controle dos desenvolvedores (KHRONOS, 2015).

O OpenGL usa a linguagem GLSL de alto nível para escrever shaders. Isso força cada driver OpenGL a implementar seu próprio compilador para GLSL que é executado no tempo de execução do aplicativo para converter os shaders do programa no código de máquina da GPU. Os drivers Vulkan aceitam shaders já traduzidos em uma linguagem binária de representação intermediária e de mais baixo nível chamada SPIR-V (Standard Portable Intermediate Representation). Versões mais recentes do OpenGL também aceitam shaders no formato SPIR-V.

Como mencionado anteriormente, SPIR-V é uma linguagem intermediária de formato bytecode. Isso significa que não escrevemos shaders diretamente utilizando essa linguagem. Para gerarmos os shaders nesse formato precisamos utilizar uma ferramenta que converta o shader escrito utilizando alguma linguagem de alto nível, como GLSL ou HLSL, no formato de bytecode do SPIR-V.

A vantagem da linguagem SPIR-V em relação à GLSL é que os compiladores escritos por fornecedores de GPU para transformar o código do shader que está em um formato de bytecode em código nativo são significativamente menos complexos. O passado mostrou que, com a sintaxe legível por humanos, como a GLSL, alguns fornecedores de GPU eram bastante flexíveis com sua interpretação do padrão. Com um formato direto de bytecode como o SPIR-V, é esperado que isso seja evitado (OVERVOORDE, 2018). Além disso, ao permitir a pré-compilação do shader, a velocidade de inicialização da aplicação é melhorada e uma maior variedade de shaders por cena pode ser usada. Um driver Vulkan só precisa otimizar a GPU e a geração de código, o que permite uma manutenção mais fácil do driver e pacotes de drivers menores (KESSENICH, 2015).

Embora o SPIR-V como linguagem seja compatível com GLSL, não é possível escrever um único shader (sem #defines) que possa ser consumido tanto pelo Vulkan e quanto pelo OpenGL. Isso porque, seus modelos de ligação de recursos são muito diferentes, portanto, geralmente precisamos manter pelo menos as definições de recursos em arquivos diferentes (KHRONOS, 2019a).

O SPIR-V também requer uma especificação muito mais explícita que a GLSL, o que geralmente significa que, se usarmos GLSL como sua fonte inicial compilada no SPIR- V, também será necessário fornecer especificações explícitas semelhantes. Por exemplo, precisamos usar qualificadores de localização em todas as entradas e saídas entre estágios do pipeline (KHRONOS, 2019a).

O Vulkan unifica recursos gráficos e de computação para vários tipos de plataformas em uma única API. Antes do Vullkan, os desenvolvedores tinham a API de gráficos OpenGL para ambientes de desktop e OpenGL ES para plataformas móveis. Geralmente, novos recursos do OpenGL aparecem primeiro em versões baseadas em desktop e, posteriormente, são disponibilizados para o OpenGL ES. Por outro lado, Vulkan suporta plataformas móveis nativamente. O Vulkan é ideal para placas gráficas de última geração, bem como para hardware gráfico em dispositivos móveis. A tabela abaixo apresenta as caracteríticas pricipais do OpenGL e Vulkan.


OpenGLVulkan
Originalmente criado para workstations gráficas com renderizadores diretos e memória dividida.Uma melhor correspondência para plataformas modernas, incluindo plataformas móveis com memória unificada.
Uma única máquina de estado global.Baseado em objetos sem um estado global.
Drivers complexos levam a sobrecarga de driver e imprevisibilidade entre fornecedores.Drivers simplificados para maior eficiência, baixa sobrecarga e portabilidade entre fornecedores.
O driver lida com a validação de estado, rastreamento de dependência, verificação de erros. Isso pode limitar e randomizar o desempenho.A aplicação tem controle direto e previsível sobre a GPU por meio de uma API explícita.
O modelo de threading obsoleto não permite a geração de comandos gráficos paralelamente à execução do comando.API projetada para plataformas multi-core e multi-thread. Vários buffers de comando podem ser criados em paralelo.
O compilador da linguagem de shader faz parte do driver e suporta apenas o GLSL. O código do shader deve ser enviado ao driver.SPIR-V é o novo alvo do compilador, permitindo flexibilidade de linguagem front-end e confiabilidade.
APIs separadas para os mercados de desktop e dispositivos móveis.API unificada para plataformas móveis, de desktop, de console e embarcadas.

Adaptado de Khronos (2015).


Anterior Próximo