API gráfica de baixo nível de plataforma cruzada

11

Ao criar uma abstração do sistema, é melhor ter APIs diferentes da plataforma ocultas por uma interface comum no nível mais baixo que faça sentido.

Levando em conta as diferentes APIs nativas modernas (sem pipeline de função fixa): OpenGLES 2.0+, OpengGL 3.0+, DirectX 10.0+, Xbox DirectX 9, LibGCM

Se alguém criasse uma API gráfica de baixo nível sem estado para ficar em cima de todas, qual seria a melhor maneira de torná-la a mais fina e rápida possível?

NocturnDragon
fonte
O requisito para a API ser sem estado é interessante. O OpenGL, por exemplo, é stateful, e eu acho que uma API sem estado que envolva isso só faria sentido se fosse de nível muito mais alto, de modo que não seja, por exemplo, necessário empurrar e exibir as mesmas matrizes para cada um superfície que processa.
SpoonMeiser
Evitar alterações de estado inúteis ainda pode ser implementado em um nível superior, como classificar as chamadas de renderização com base em seu estado antes de enviá-las ao dispositivo. E definindo o estado apenas se for diferente do atual.
NocturnDragon
Isso não é apátrida. Talvez eu esteja errado, mas o que penso quando penso em apátrida é uma API em que cada chamada não depende de chamadas anteriores. Isso significa que qualquer informação que normalmente seria armazenada no estado em algum lugar deve ser passada em todas as chamadas que precisam dessa informação. Para o OpenGL, por exemplo, seriam matrizes na pilha, iluminação, buffer z e opções de normalização.
SpoonMeiser
Sim, para cada chamada de desenho que você precisa, os dados de malha, o estado de mesclagem, as texturas a serem vinculadas, os estados de amostragem etc. As otimizações podem ser feitas mais tarde, sem alterar a API. Ou talvez eu estou lendo o seu comentário errado ..
NocturnDragon

Respostas:

6

O nível mais baixo que faz sentido do meu ponto de vista é algo que fala sobre os recursos envolvidos na renderização - vb / ib, superfícies de renderização, texturas, shaders, blocos de estado etc.

O problema aqui é que alguns deles precisam estar em formatos diferentes, dependendo da API - é aí que fica um pouco complicado. A maneira mais fácil de contornar isso é pré-processar os recursos estáticos para a respectiva API. Para os dinâmicos, use apenas shaders para gerá-los - o que torna bastante simples permanecer em formatos nativos.

Tudo o que você faz no nível superior é configurar pipelines com recursos anexados e entregá-los à GPU. Você descobrirá que nem tudo pode ser abstraído dessa maneira, especialmente se você aproveitar os truques específicos do hardware. Mas é um bom começo.

(Nota: se você tratar os truques específicos da plataforma como um tipo especial de recurso, poderá levar esse conceito muito longe).

Então, de certa forma, você criará duas coisas: um gerenciador de recursos de hardware, além de um kit de ferramentas para configurar um DAG desses recursos.

Rachel Blum
fonte
Eu nunca pensei em tratar coisas específicas da plataforma como recursos. Parece uma ótima ideia! Obrigado.
NocturnDragon
10

Dada a ampla variedade de APIs que você deseja cobrir, é provável que a abordagem típica de agrupamento seja ineficiente e propensa a dificuldades no mapeamento de conceitos de API em várias outras APIs que podem ou não suportar funções específicas em graus variados.

Como resultado, a abordagem mais sensata seria criar uma API centrada em recursos . Embora essa abordagem impeça o usuário da API de utilizar todas as funcionalidades disponíveis, ela simplifica bastante a implementação de cada back-end e permite otimizações específicas de back-end que, de outra forma, não seriam possíveis.

Também simplifica bastante o gerenciamento de funcionalidades não suportadas pelo usuário da API; eles não precisam mais verificar se a função X existe e determinar quais recursos são afetados, mas precisam apenas consultar o próprio recurso para ver se ele é suportado pela configuração atual. Mesmo se você suportar modos parciais ou limitados para recursos, o contexto fornecido facilita muito o gerenciamento.

Em termos de criação de um renderizador sem estado (também conhecido como baseado em envio ), normalmente uma chave de 64 bits é usada para compactar e enviar comandos para renderização. A partir desse ponto, há muita flexibilidade em termos de como executar comandos e quais informações enviar, dependendo dos recursos e recursos que você deseja oferecer suporte.

Jason Kozak
fonte
Esta é realmente uma boa idéia. E isso faz parte do design que estou tentando criar, mas o que eu tinha em mente era implementar esses recursos em cima de uma API comum de baixo nível. Mas pode ser que em alguns recursos você ainda precise se aprofundar na API nativa para alguns casos mais específicos.
NocturnDragon
Parte da idéia é evitar a criação de uma API comum de baixo nível e ter que lidar com a quebra de linha com uma abordagem de denominador comum mais baixo. Ao subir um nível de abstração, você restringe um pouco o conjunto de recursos, mas também ganha a capacidade de explorar cada plataforma. Para lidar com a necessidade ocasional de acesso mais profundo, prefiro fornecer um cabeçalho que exponha os cabeçalhos da plataforma e alguns auxiliares internos; pode quebrar versão para versão, mas existe se você precisar.
precisa
1

Para começar, cada API faz as coisas de maneira diferente; portanto, não é necessário dizer que seria difícil agrupar todas as APIs acima. Dito isto, às vezes é necessário fazê-lo: em algum momento, um jogo simplesmente precisa ser executado em mais de uma plataforma, independentemente da dificuldade que é fazer.

Eu acho que a melhor maneira de fazer isso é criar a funcionalidade que pode ser implementada em todas as APIs subjacentes e abstrair isso e somente isso. Se você estiver desenvolvendo um jogo multiplataforma, não implementaria todas as funcionalidades obscuras suportadas por cada API, apenas implementaria o que precisa. Isso também ajuda a manter a API pequena e rápida.

Para evitar que a desordem da implementação de cada API diferente seja compactada na saída, a compilação deve ser feita com arquivos de cabeçalho neutros da plataforma e arquivos de código específicos da plataforma. Em seguida, o arquivo de código específico para a plataforma de destino seria o único compilado mantendo a API pequena.

Sean James
fonte
-4

Você pode querer verificar a biblioteca SDL ou Allegro . Ambas são bibliotecas de jogos de baixo nível e altamente portáteis, que têm uma maneira de conectá-las a um contexto OpenGL para que você possa renderizar seus gráficos lá. SDL tem a fama de ser usado por ele extinto Loki Games para portar alguns jogos populares dos anos 2000 para Linux, e Allegro tem muito tempo correndo e tem uma grande comunidade de desenvolvedores de jogos amadores.

chiguire
fonte
4
Isso realmente não responde à pergunta, sem mencionar que é muito possível agrupar o OpenGL e o DirectX (consulte Ogre3D, Irrlicht etc.).
Jason Kozak
Considere os jogos que você jogou. Quantos deles têm opções para usar o DirectX ou o OpenGL? É assim que muitos criam invólucros para as duas bibliotecas serem capazes de suportar qualquer uma. Você tem uma imaginação limitada. :-P
Ricket
Reconheço que existem alguns jogos que permitem que você escolha se deseja renderizar gráficos com OpenGL ou DirectX, mas a pergunta é sobre uma API de plataforma cruzada. Por isso, acho que a resposta é adequada, editarei o primeiro parágrafo, Apesar.
21410 chiguire
1
a questão é sobre uma API de baixo nível sem estado de plataforma cruzada. SDL e Allegro não têm nada a ver com isso.
NocturnDragon
@NocturnDragon - o título da pergunta é um pouco enganador. À primeira vista, eu esperava que a pergunta fosse sobre as opções de API disponíveis, e presumo que esse respondedor também.
precisa saber é