GL ES: Otimização de shader de fragmentos

8

Resumo: Eu fico com a desaceleração do FPS assim que tento colorir os sprites (ou seja: multiplique a textura pela cor no shader do fragmento)

Detalhes:

Hardware: iPod touch 4

Estou desenhando 700 sprites na tela usando glDrawArrays. E sim, estou agrupando tudo isso em uma única chamada de empate. A seguir, mostra a estrutura de dados do Vertex:

struct Vertex {
    float Position[2];
    float Color[4];
    float Texture[2];
};

Sim, estou enviando cores com cada vértice porque preciso seletivamente pintar alguns sprites, mas não outros. A seguir está o shader de fragmento que estou usando:

varying lowp vec2 TexCoord;
uniform sampler2D TextureSampler;

void main(void)
{
    gl_FragColor = texture2D( TextureSampler, TexCoord );
}

Até agora está funcionando muito bem, me dando 60 FPS completos !!!

MAS

Assim que eu mudar o sombreador do fragmento para o seguinte (para permitir a coloração):

varying lowp vec4 DestinationColor;
varying lowp vec2 TexCoord;
uniform sampler2D TextureSampler;

void main(void)
{
    gl_FragColor = texture2D( TextureSampler, TexCoord ) * DestinationColor;
}

Usando a seguinte textura png de 64x64, contendo canal alfa, renderizando com glEnable (GL_BLEND):

insira a descrição da imagem aqui

O desempenho cai para 47 FPS apenas devido a essa alteração única {apenas por multiplicação com UM vetor} (FPS medido usando instrumentos xcode e detetive OpenGL). Alguma idéia do que está acontecendo?

Obrigado.

Editar:

Eu também tentei retirar por atributo de cor do vértice:

struct Vertex {
    float Position[2];
    float Texture[2];
};

E modificando o sombreador de fragmento da seguinte maneira:

precision lowp float;
varying lowp vec2 TexCoord;
uniform sampler2D TextureSampler;

void main(void)
{
    gl_FragColor = texture2D( TextureSampler, TexCoord ) * vec4(1.0,0.0,0.0,1.0);
}

Está rodando a 52 FPS para 700 sprites (um ganho de apenas 5 FPS). Portanto, isso não é interpolação, parece que a multiplicação é extremamente cara. Apenas esta multiplicação?

fakhir
fonte
Você tem o vsync ativado? Os números podem significar que, após a alteração, você começa a perder todos os outros vsync, o que leva a 45 FPS em média.
msell
Estou testando no iPhone 4, suponho que o vsync já esteja ativado por padrão. Ele mostra 47 FPS a propósito no xcode Instruments, então acho que o vsync não é realmente um problema. Mas minha verdadeira pergunta é: por que o desempenho fica mais lento e como melhorá-lo?
Fakhir
11
Sua textura tem um canal alfa? Se a textura não possui um canal alfa e o rgb é multiplicado por um vec3, ele é desenhado a 60 fps novamente?
Será
Sim, a textura tem canal alfa. Por favor, veja a textura anexada acima.
Fakhir
2
Monitor SGX 535 de núcleo único e alto DPI com uma GPU que nunca foi desenvolvida para lidar com isso. O desempenho dos gráficos em resolução nativa nesses dispositivos sempre foi péssimo. Você deve reduzir a resolução ou segmentar 30 fps ou direcionar o hardware mais recente. Você está esperando milagres nessa GPU. Não é preciso muito para aquecê-lo.
Sean Middleditch 24/05

Respostas:

2

Eu não acho que o problema de desempenho esteja acontecendo na multiplicação, mas na interpolação do seu DestinationColorentre os triângulos, entre vértices e fragmentos de sombreamento. Você tem quatro floatsegundos para interpolar entre os vértices das árvores, para cada fragmento para cada sprite.

Para 700 sprites de 64x64 pixels cada, são 11468800 operações adicionais por quadro que você está solicitando à GPU para executar. É bem possível que você perca alguns vsyncs e, portanto, caia para 40-ish FPS.

Se você deseja que cada vértice tenha uma cor diferente, então você pode ter gradientes para cada sprite, não terá sorte. Existem outros truques que você pode querer experimentar, mas acho que não é esse o caso.

Como o que você parece estar fazendo é pintar cada sprite, você pode rebaixá-lo DestinationColorpara a uniform, usá-lo diretamente no shader de fragmento e alterá-lo para cada chamada. Dessa forma, nenhuma interpolação ocorrerá. Você perderá todo o lote, mas poderá fazer um lote se os classificar por cor.

Panda Pajama
fonte
Editei a pergunta acima e adicionei alguns detalhes. Basicamente, tentei remover a cor por vértice e simplesmente multiplicar a textura com um vetor CONSTANT, ou seja: gl_FragColor = texture2D (TextureSampler, TexCoord) * vec4 (1.0,0.0,0.0,1.0); . Tem 52 FPS, um ganho de quase 5 FPS. Mas ainda é muito lento em comparação com nenhum tom. Desaceleração de 8 FPS apenas devido a uma multiplicação de vetor único?
Fakhir
3
Mas não é uma multiplicação única - é ~ 11 milhões por quadro.
Maximus Minimus
11
@fakhir A resolução do monitor do iPod Touch 4 é de 960x640 pixels. São 614400 pixels no total. Você deseja renderizar 700 sprites de 64x64 pixels cada. São 2867200 pixels, ou quase 5 vezes a tela inteira. Você provavelmente obteve seus 60 qps originais porque o otimizador descobriu o que estava fazendo e possivelmente amostrou a imagem apenas uma vez, mas não espere que isso aconteça em todos os casos. A programação gráfica móvel é muito mais limitada que a programação de desktop, portanto, aja de acordo.
Panda Pyjama