Lidando com criação de perfil para jogos para dispositivos móveis com Unity e Arm

MARK HARKNESS / UNITY TECHNOLOGIESSenior Software Engineer
Mar 11, 2021|11 Min
Lidando com criação de perfil para jogos para dispositivos móveis com Unity e Arm
Esta página da Web foi automaticamente traduzida para sua conveniência. Não podemos garantir a precisão ou a confiabilidade do conteúdo traduzido. Se tiver dúvidas sobre a precisão do conteúdo traduzido, consulte a versão oficial em inglês da página da Web.

Aprenda a lidar com problemas de desempenho móvel com ferramentas de criação de perfil da Unity e da Arm. Saiba mais sobre como criar perfis com o Unity, como otimizar quedas de desempenho e dicas e truques para aproveitar ao máximo os recursos do seu jogo.

Neste blog, examinamos como identificar problemas de desempenho em um jogo para dispositivos móveis por meio do uso de ferramentas de criação de perfil da Unity e da Arm. Também apresentamos as melhores práticas para otimizar o conteúdo de jogos para dispositivos móveis.

Para identificar problemas de desempenho no seu jogo, você deve primeiro testá-lo em vários dispositivos diferentes. A melhor maneira de fazer isso é capturar um perfil de desempenho em um dispositivo real. Ferramentas como oUnity Profilereo Frame Debuggerpodem fornecer excelentes informações sobre onde os elementos do seu jogo estão consumindo seus recursos. Além disso, ferramentas comoo Arm Mobile Studiopermitem capturar dados de atividade do contador de desempenho do dispositivo, para que você possa ver exatamente como seu jogo está usando os recursos da CPU e da GPU. Embora o dispositivo que usamos tenha uma GPU Mali, os conceitos apresentados aqui também se aplicam a outras GPUs móveis.

Exemplo de teste

O jogo que estamos testando é um RPG de ação, onde o jogador deve lutar contra ondas de NPCs inimigos com ataques corpo a corpo e mágicos. Esse tipo de jogo pode rapidamente se tornar dependente da GPU em um dispositivo móvel, com um número crescente de inimigos na tela, bem como múltiplos efeitos visuais de partículas e pós-processamento.

Criação de perfil com Unity Profiler e Frame Debugger

Executamos o jogo no Unity Profiler para identificar qualquer lentidão no desempenho. Encontramos alguns suspeitos de alta prioridade, pós-processamento e corrigimos picos de Timestep e instanciação.

Pós-processamento

Os efeitosde pós-processamentoforam a causa central do baixo desempenho da CPU do jogo.

A câmera de renderização está demorando muito e ultrapassando o limite do quadro
A câmera de renderização está demorando muito e ultrapassando o limite do quadro

De todos os efeitos de pós-processamento, a passagem de bloom, que faz áreas claras na cena brilharem, foi o mais desgastante.

Na captura de tela acima, você pode ver que a Render Camera está demorando muito e ultrapassando o limite do quadro. O thread principal então aguarda até que os comandos de renderização sejam concluídos antes de preparar o próximo quadro. Vamos dar uma olhada no Unity Frame Debugger para descobrir o que está acontecendo.

Visualizando o Frame Debugger com o dispositivo em resolução de tela cheia
Visualizando o Frame Debugger com o dispositivo em resolução de tela cheia

A primeira coisa a notar no Frame Debugger é que o jogo está sendo renderizado na resolução de tela cheia do dispositivo. Para um dispositivo móvel comum, isso coloca uma pressão indevida na GPU do dispositivo, dada a complexidade do conteúdo. Reduzir a resolução para algo mais razoável, como 1080p ou mesmo 720p, reduziria significativamente os custos de renderização do jogo, especialmente os efeitos de pós-processamento.

Visualizar o sorteio pede a pirâmide de flores
Visualizar o sorteio pede a pirâmide de flores

O próximo ponto de observação é que o efeito bloom ocorre em 25 chamadas de sorteio para a pirâmide bloom. Cada chamada de desenho representa um buffer de destino com um tamanho começando na metade da resolução do dispositivo de tela cheia. Essa resolução é então reduzida pela metade a cada iteração. Reduzir a resolução de renderização inicial é uma maneira de reduzir o número potencial de iterações. Outra alternativa seria modificar o código-fonte do efeito bloom para reduzir o número de iterações que ocorrem e impor algum limite sensato. Entretanto, neste caso, seria melhor desabilitar os efeitos de pós-processamento por enquanto, devido ao tempo considerável que leva para lidar com esses efeitos. Isto é, pelo menos até que o resto do jogo possa rodar suavemente a 30 quadros por segundo.

Passo de tempo fixo

Outra melhoria para o projeto seria reduzir a frequência do intervalo de tempo fixo. Podemos ver que atualmente ele é curto o suficiente para ser chamado várias vezes por quadro; por padrão, o Unity define isso como 0,02 ou 50 Hz. Você pode tentar um valorde intervalo de tempo fixode 0,04 para títulos para dispositivos móveis com o objetivo de 30 fps. O motivo para isso é que, em 0,333, que corresponderia a 30 fps, há a chance de que um quadro tenha um pico de tempo e você acabe com duas chamadas no próximo quadro. Isso significa que demora mais – e você nunca consegue quebrar o ciclo de um quadro um pouco mais longo. O usuário também pode definir ointervalo de tempo máximo permitidopara evitar que qualquer recuperação demore mais do que o tempo desejado.

Essa duração do Timestep afeta scripts que usam a função FixedUpdate e quaisquer sistemas internos do Unity que atualizam no intervalo de atualização fixo, por exemplo, física e animação.

Timeline usando um Timestep fixo
Timeline usando um Timestep fixo

Para os propósitos deste projeto, apenas a física eo Cinemachinecontribuíram bastante para o tempo gasto, cerca de 3 ms por chamada; uma chamada que significa que o sistema foi totalmente atualizado (embora ser chamado mais 5 vezes significasse que isso poderia adicionar até 15 ms por quadro de tempo desperdiçado).

FixedUpdate.PhysicsFixedUpdate ficou lento devido aos efeitos de pós-processamento
FixedUpdate.PhysicsFixedUpdate ficou lento devido aos efeitos de pós-processamento

Isso ocorre devido aos efeitos lentos do pós-processamento. Desligá-los reduz o tempo gasto, no entanto, a recomendação anterior de reduzir a frequência fixa do Timestep para evitar trabalho desnecessário para a CPU ainda é válida.

Picos de instanciação

Durante a criação de perfil, picos podem ser vistos no tempo do quadro. Rastreá-los na visualização de hierarquia do criador de perfil da CPU mostra que eles derivam da instanciação de NPCs.

Rastreamento de picos de instanciação na hierarquia do profiler da CPU
Rastreamento de picos de instanciação na hierarquia do profiler da CPU

A solução mais comum para isso é instanciar os caracteres com antecedência e mantê-los em um estado ocioso, em algum tipo depool de objetos. Esses NPCs podem então ser obtidos do pool sem custo de instanciação. Se for necessário mais, o pool pode ser expandido conforme necessário.

O mesmo problema também é visto quando habilidades estão sendo usadas, pois elas também estão instanciando objetos.

Picos de instanciação da CPU
Picos de instanciação da CPU

O agrupamento de objetos é a maneira mais fácil de resolver esses problemas. Isso pode afetar os tempos de carregamento, mas permite uma taxa de quadros muito mais suave em tempo de execução, o que é o menor dos dois males neste caso.

Criação de perfil com o Arm Mobile Studio

Também usamoso Arm Mobile Studiopara obter mais informações sobre o comportamento do jogo. Com as ferramentas do Mobile Studio, podemos obter dados de desempenho de contraatividade da CPU e da GPU, para que possamos ver exatamente como o jogo está usando os recursos do dispositivo.

Você pode baixar o Arm Mobile Studio gratuitamenteaqui. Há 4 ferramentas incluídas:

  • Consultor de desempenho– para gerar relatórios fáceis de ler e obter conselhos de otimização
  • Streamline– um criador de perfil de desempenho abrangente para capturar toda a atividade do contador
  • Mali Offline Compiler– para verificar como um programa shader funcionaria em uma GPU Mali
  • Graphics Analyzer– para depurar chamadas de API gráfica e analisar como o conteúdo foi renderizado
Consultor de Desempenho

O Performance Advisor nos fornece um rápido resumo do desempenho do jogo e deve ser usado como uma verificação regular de integridade. É rápido gerar um relatório, principalmente se você integrá-lo a um fluxo de trabalho de integração contínua, juntamente com seu sistema de compilação noturna. O Performance Advisor nos fornece um rápido resumo do desempenho do jogo e deve ser usado como uma verificação regular de integridade. É rápido gerar um relatório, principalmente se você integrá-lo a um fluxo de trabalho de integração contínua, juntamente com seu sistema de compilação noturna.

Consultor de Desempenho - Resumo de Captura
Consultor de Desempenho - Resumo de Captura

Durante os primeiros 2 minutos do jogo, o Performance Advisor nos diz que estamos com uma média de apenas 17 quadros por segundo. A seção verde no início do gráfico de análise de taxa de quadros indica onde o jogo está carregando e, de repente, o gráfico fica azul, indicando que o jogo ficou limitado a fragmentos, e permanece assim o tempo todo. Isso significa que a GPU do dispositivo está com dificuldade para processar cargas de trabalho de fragmentos, o que sugere que o jogo está solicitando muito trabalho ou que não está processando pixels de forma eficiente.

Como adicionamos anotações de região ao jogo, o gráfico de análise de taxa de quadros mostra nossos nomes de região personalizados. Onde o gráfico mostra um marcador rotulado com 'S', o Performance Advisor fez uma captura de tela do jogo para nos ajudar a identificar o que está acontecendo na tela naquele momento. Você pode configurar capturas de tela para serem feitas quando o fps cair abaixo de um valor especificado. Aqui, como o fps permanece baixo o tempo todo, o Performance Advisor faz uma captura de tela no intervalo padrão de cada 200 quadros.

Dê uma olhada no gráfico de ciclos de GPU por quadro, onde adicionamosum orçamentode 28 milhões de ciclos por quadro para este dispositivo. Estimamos que esse é o número máximo de ciclos que este dispositivo deve ser capaz de suportar, mantendo uma taxa de quadros de 30 fps. Aqui, podemos ver que o número de ciclos de GPU excede significativamente esse orçamento e que o número de ciclos aumenta com o tempo.

Consultor de desempenho - ciclos de GPU por quadro
Consultor de desempenho - ciclos de GPU por quadro

O Performance Advisor fornece consultoria de otimização quando encontra um problema. Se observarmos o gráfico de ciclos de shader por quadro, veremos que o número de ciclos do mecanismo de execução é alto. Dentro de um núcleo de shader Mali, o mecanismo de execução é responsável por processar operações aritméticas. O Performance Advisor sinalizou isso como um problema e nos aconselha a reduzir a computação em shaders.

Consultor de desempenho - Ciclos de shader por quadro
Consultor de desempenho - Ciclos de shader por quadro

Existe uma solução simples para isso. Você pode reduzir a precisão das variáveis do shader para mediump, em vez de highp, sem nenhuma alteração perceptível na tela. Isso reduzirá significativamente o custo do shader. Para obter informações sobre como fazer isso, consulteTipos de dados e precisão do shaderem nossa documentação. Além disso, como descobrimos anteriormente com o Frame Debugger da Unity, o jogo está atualmente renderizando na resolução de tela cheia do dispositivo. Quaisquer alterações que fizermos para reduzir a resolução de renderização do jogo (para 1080p ou 720p) também reduzirão o custo de sombreamento de fragmentos.

Métricas de conteúdo

Estabelecemos um orçamento de 500.000 vértices por quadro para este dispositivo. O orçamento é excedido em cerca de 45 segundos e o número aumenta constantemente ao longo do tempo.

Consultor de desempenho - Vértices por quadro
Consultor de desempenho - Vértices por quadro

Observando o gráfico de primitivas por quadro, notamos que o número total de primitivas sendo processadas aumenta ao longo do tempo, embora o número de primitivas visíveis permaneça relativamente constante. Nos primeiros 2 minutos do jogo, os únicos objetos novos que são criados são os NPCs inimigos, que são destruídos por uma explosão de raios do nosso herói. Isso sugere que quando os inimigos são destruídos, sua geometria ainda está presente, mesmo que não seja visível.

Consultor de Desempenho - Primitivas por quadro
Consultor de Desempenho - Primitivas por quadro

Há vários motivos pelos quais a GPU pode não ser capaz de lidar com as demandas do jogo, então precisamos explorar mais a fundo a ferramenta de criação de perfil da Arm com o Streamline. O Streamline nos contará mais sobre essa carga de trabalho pesada de fragmentos e, observando os outros contadores, podemos encontrar pistas sobre como aliviar a carga.

Simplifique a análise

Observando a mesma seção do jogo no Streamline, podemos explorar uma série de gráficos que mostram a atividade do contador da GPU para os diferentes estágios de geometria e processamento de pixels. Isso ilustra como o conteúdo do jogo é processado pela GPU e se há processamento desnecessário.

As GPUs baseadas em Mali adotam uma abordagem baseada em blocos para processar cargas de trabalho gráficas, onde o espaço da tela é dividido em blocos, e cada bloco é processado até a conclusão em ordem. Para cada bloco, o processamento de geometria é executado primeiro e, então, os pixels são coloridos durante o processamento de pixels.

GPUs baseadas em Mali processando cargas de trabalho gráficas
GPUs baseadas em Mali processando cargas de trabalho gráficas

Já sabemos que a GPU do dispositivo está sobrecarregada com cargas de trabalho de fragmentos, então precisamos procurar maneiras de reduzir a pressão no estágio de processamento de pixels.

Uma maneira de reduzir a carga de processamento de pixels é diminuir a complexidade da geometria que é enviada para processamento de pixels em primeiro lugar. Geometrias completamente fora da tela ou voltadas para trás são eliminadas antes do processamento de pixels, mas pequenos triângulos que cobrem apenas parcialmente quads de pixels 2×2 podem prejudicar a eficiência dos fragmentos e ter alto custo de largura de banda por pixel de saída.

Os gráficosde uso de geometria do Malietaxa de eliminação de geometria do Malino Streamline mostram a eficiência com que a GPU processa a geometria. Podemos ver o número de primitivas sendo enviadas para a GPU e quantas delas são selecionadas durante o processamento da geometria. O trabalho selecionado nesta fase não será passado para o processamento de pixels. Esta é uma boa notícia, mas poderíamos organizar o conteúdo de forma mais eficiente, para que primitivos não visíveis não sejam transmitidos.

Gráficos de uso de geometria do Mali e taxa de descarte de geometria do Mali no Streamline
Gráficos de uso de geometria do Mali e taxa de descarte de geometria do Mali no Streamline

No gráficode uso da geometria do Mali, podemos ver que 1,07 milhão de primitivas entram no processamento de geometria (linha laranja) no período selecionado (cerca de 0,05 segundos), mas 700.000 primitivas são eliminadas nesta fase (linha vermelha).

O gráficoda taxa de seleção geométrica do Malimostra por que eles são selecionados. Cerca de metade é selecionada pelo teste de faceamento (linha laranja), o que é esperado, pois esses são os triângulos voltados para trás dos nossos objetos 3D . O que é mais preocupante é que 31,9% dos primitivos são eliminados pelo teste de amostra (linha roxa) – idealmente, esse número deve ser inferior a 5%. O teste de amostra indica que esses primitivos eram muito pequenos para serem rasterizados, falhando em atingir um único ponto de amostra e, portanto, considerados invisíveis. Isso pode acontecer quando objetos com malhas complexas são posicionados longe da câmera e os triângulos na malha são muito pequenos para serem visíveis. Números mais altos podem indicar que as malhas dos objetos do jogo são muito complexas para sua posição na tela.

Esse problema piora para primitivos que são grandes o suficiente para passar no teste de amostra, mas ainda cobrem apenas alguns pixels. Esses 'microtriângulos' são passados para o processamento de pixels e são caros para processar. Isso ocorre porque, durante o sombreamento de fragmentos, os triângulos são rasterizados em manchas de pixels de dois por dois, chamadas de quadrantes. Pequenos triângulos atingem apenas um subconjunto de pixels dentro de um quad, mas o quad inteiro deve ser enviado para processamento. Isso significa que o shader de fragmento será executado com faixas ociosas no hardware, tornando a execução do shader menos eficiente.

Pequenos triângulos atingindo um subconjunto de pixels dentro de um quad
Pequenos triângulos atingindo um subconjunto de pixels dentro de um quad

Para verificar se temos um problema com microtriângulos, podemos usar o gráficoMali Core Workload Propertyno Streamline para monitorar a eficiência da cobertura. O ideal é que seja inferior a 10%. Podemos ver aqui que em alguns trechos a taxa de cobertura parcial (linha verde) é muito alta, acima de 70%. Esse valor sugere que o conteúdo tem uma alta densidade de microtriângulos, o que confirma o problema sinalizado anteriormente pela alta taxa de seleção de amostras.

Gráfico de propriedades da carga de trabalho principal do Mali
Gráfico de propriedades da carga de trabalho principal do Mali

A geometria que aparece na tela precisa ter o tamanho adequado para sua posição. Um cenário complexo e distante não precisa ser muito detalhado, pois não contribui muito para a cena. Poderíamos usar malhas de nível de detalhe (LOD)para objetos que estão mais distantes da câmera, para reduzir a complexidade e economizar poder de processamento e largura de banda da DRAM. Ou, em vez de usar geometria, poderíamos usar texturas e mapas normais para construir detalhes de superfície para objetos.

Analisando shaders

Por meio do relatório do Performance Advisor, descobrimos que nossos shaders poderiam ser muito caros e que poderíamos nos beneficiar reduzindo sua precisão. No Streamline, podemos usar o gráfico de uso variável do Mali para ver o número de ciclos em que a interpolação de 32 bits (alta precisão) ou 16 bits (precisão média) está ativa. Aqui, podemos ver que a interpolação de 32 bits é usada na maioria dos ciclos. Variáveis de 16 bits interpolam duas vezes mais rápido que variáveis de 32 bits e usam metade do espaço nos registradores de shader para armazenar resultados de interpolação, portanto, é recomendado usar entradas variáveis médias (16 bits) para fragmentar shaders sempre que possível.

Gráfico de uso variável do Mali
Gráfico de uso variável do Mali
Análise de shader com o Mali Offline Compiler

Para explorar shaders, podemos usar a ferramenta de compilação offline estática do Arm Mobile Studio para gerar uma análise rápida do programa shader.

Para fazer isso, você precisa pegar o código do shader do arquivo compilado que o Unity fornece e então executar o Mali Offline Compiler nesse arquivo:

1. No Unity, selecione o shader que deseja analisar, diretamente da sua pasta de ativos ou selecionando um material, clicando no ícone de engrenagem e escolhendoSelecionar shader.

2. EscolhaCompilar e mostrar códigono Inspetor. O código do shader compilado será aberto no seu editor de código padrão. Este arquivo contém diversas variantes de código de shader.

3. Copie uma variante de shader de vértice ou fragmento deste arquivo para um novo arquivo e dê a ele uma extensão.vertou.frag. Os shaders de vértice começam com #ifdef VERTEX e os shaders de fragmento começam com #ifdef FRAGMENT. Eles terminam com seus respectivos #endif. (Não inclua as instruções #ifdef e #endif no novo arquivo).

4. Em um terminal de comando, execute o Mali Offline Compiler neste arquivo, especificando a GPU que você deseja testar. Por exemplo: malioc –c Mali-G72 myshader.frag ConsulteIntrodução ao Mali Offline Compilerpara obter mais instruções.

Escolhemos analisar o shader de fragmento que foi responsável pelo efeito de dissolução que ocorre quando os NPCs inimigos morrem. Aqui está o relatório do Mali Offline Compiler, com seções de interesse destacadas:

Relatório do Mali Offline Compiler

Podemos ver que apenas 2% dos cálculos aritméticos são feitos de forma eficiente com precisão de 16 bits. O shader operará de forma mais eficiente se reduzirmos a precisão de highp para mediump. Isso reduz o consumo de energia e a pressão do registro, além de poder dobrar o desempenho. Há situações em que um p alto é sempre necessário, como para cálculos de posição e profundidade, mas em muitos casos há pouca diferença perceptível na tela ao reduzir a precisão para p médio.

O relatório fornece uma análise aproximada do custo do ciclo para as principais unidades funcionais no núcleo do shader Mali. Aqui, podemos ver que a unidade aritmética é a mais utilizada.

Na seção de propriedades do shader, vemos que esse shader contém computação uniforme que depende apenas de constantes literais ou valores uniformes. Isso produz o mesmo resultado para cada thread em uma chamada de desenho ou despacho de computação. O ideal é que esse tipo de computação uniforme seja movido para a lógica do aplicativo na CPU.

Também podemos ver que o shader pode modificar a máscara de cobertura de fragmentos que determina quais pontos de amostra em cada pixel são cobertos por um fragmento, usando a instrução discard para descartar fragmentos abaixo de um limite alfa. Shaders com cobertura modificável devem usar uma atualização tardia do ZS, o que pode reduzir a eficiência dos testes iniciais do ZS e do agendamento de fragmentos para fragmentos posteriores na mesma coordenada. Você deve minimizar o uso de instruções de descarte e alfa para cobertura em shaders de fragmentos sempre que possível. Consulte o guia depráticas recomendadas do Arm Malipara obterconselhos sobre como usar instruções de descarte.

Análise de chamadas da API de gráficos com o Graphics Analyzer

No Graphics Analyzer do Arm Mobile Studio, você pode ver todas as chamadas de API gráfica que o aplicativo fez e percorrê-las uma por uma para ver como a cena é construída. Isso ajuda a identificar objetos que são muito complexos para o tamanho na tela e para a distância da câmera. Aqui estão alguns exemplos que encontramos neste jogo:

A alvenaria no canto mais distante da cena é construída com geometria e usa 2.064 vértices. O detalhe não fica muito visível no resultado final, então isso é processamento desperdiçado.

Amostra de alvenaria em 2064 vértices
Amostra de alvenaria em 2064 vértices

Encontramos o mesmo problema para os ladrilhos do piso – eles têm 1170 vértices cada, mas mesmo que o objeto esteja próximo da câmera, a cena não se beneficia realmente dessa complexidade. Seria mais eficiente usar um mapa normal aqui, para representar as saliências e bordas angulares, em vez de construí-lo com triângulos. Além disso, podemos ver que esses objetos são desenhados usando chamadas de desenho separadas. Reduzir o número de chamadas de desenho agrupando objetos em lotes ou usando instanciação de objetos pode aumentar o desempenho.

Amostra de piso de ladrilho em 1170 vértices
Amostra de piso de ladrilho em 1170 vértices

Outro exemplo são as estátuas no fundo da cena – 6966 vértices cada. Você pode ver que a malha é bem complexa, o que dará um ótimo resultado visual quando o jogador se aproximar das estátuas, mas dessa posição da câmera, elas dificilmente serão notadas. Economizaria muito poder de processamento usar LODs de malha aqui para representar esses objetos quando eles estão tão distantes da câmera.

Amostra de estátua em 6966 vértices
Amostra de estátua em 6966 vértices

Lembre-se de que reduzir a complexidade de muitos objetos semelhantes resulta em uma grande economia no processamento de geometria, o que subsequentemente reduz a quantidade de sombreamento de fragmentos necessária. Isso não apenas reduzirá a carga de trabalho dos fragmentos e aumentará nossos quadros por segundo, como também reduzirá a pegada de instalação do APK.

Otimizações de jogo

Descobrimos diversas áreas onde poderíamos fazer mudanças no jogo para melhorar o desempenho. Aqui estão os que escolhemos implementar e como fizemos isso.

Passo de tempo fixo

Fixed Timestep é um intervalo independente da taxa de quadros que controla quando os cálculos de física e os eventos FixedUpdate() são executados. Por padrão, isso é definido para rodar a 50 fps. Embora 50 ou até 60 fps sejam sustentáveis em dispositivos móveis de última geração, dispositivos mais comuns rodam a 30 fps, que é o objetivo deste título. Vá emEditar > Configurações do Projetoe depois na CategoriaTempopara definir a propriedadeIntervalo de Tempo Fixocomo 0,04. Isso garantirá que seus cálculos de física, FixedUpdate() e atualizações estejam todos sendo executados em sincronia.

Definir o intervalo de tempo fixo para 0,04 nas configurações do projeto
Definir o intervalo de tempo fixo para 0,04 nas configurações do projeto

Após os ajustes feitos no Timestep fixo no Unity, a parte de atualização fixa do loop do jogo principal foi chamada apenas uma vez por quadro, com uma média de 1,5 ms. Esta é uma grande melhoria em relação aos 12 ms que demorava anteriormente – e uma solução simples para uma armadilha comum de desempenho.

Pasta de Recursos

Na inicialização do aplicativo, os dados de todos os objetos referenciados por cenas integradas ou na pasta Recursos são carregados no cache de ID da instância. Esses ativos são tratados como um grande pacote de ativos, portanto, há metadados e informações de indexação que são sempre carregados na memória. Depois que um ativo deste pacote é usado, ele nunca pode ser descarregado da memória.

O método recomendado para manipular ativos e recursos quando se pretende melhorar o consumo de memória é por meio doSistema de Ativos Endereçáveis, que fornece uma maneira eficiente de descarregar conteúdo que não é mais necessário da memória.

Instanciação de GPU

Em nosso ambiente, temos muitos objetos que aparecem diversas vezes. Paredes, pisos e outros acessórios do ambiente são todos duplicados para construir esta cena. Podemos economizar chamadas de desenho habilitandoa instanciação de GPUno material dos objetos. A instanciação de GPU renderiza malhas idênticas com um pequeno número de chamadas de desenho e permite que cada instância tenha parâmetros diferentes, como cor ou escala. Essa modificação pode melhorar o desempenho da CPU. Abaixo, você pode ver os dados do Performance Advisor antes da ativação da instância da GPU.

Dados antes da instanciação da GPU serem habilitados
Dados antes da instanciação da GPU serem habilitados

E aqui, você pode ver a mesma parte do aplicativo, mas com a instanciação da GPU habilitada – um ganho pequeno, mas mensurável, em direção à nossa meta de 30 fps.

Dados com instanciação de GPU habilitada
Dados com instanciação de GPU habilitada
Renderizar texturas

Texturas de renderizaçãosão uma maneira de adicionar elementos 3D à sua interface do usuário, assim como muitos outros casos de uso. Se você tiver uma câmera renderizando a textura de renderização, certifique-se de desativá-la quando ela não estiver na tela. Não há necessidade de renderizar algo que o usuário não verá. Use o Graphics Analyzer ou o Frame Debugger do Unity para garantir que essas texturas não estejam sendo atualizadas fora da tela.

Agrupamento de objetos

Em vez de colocar trabalho extra na CPU criando e destruindo os mesmos objetos repetidamente, tenteo pool de objetos. O pool de objetos é um padrão de design que solicita que você crie os objetos necessários antecipadamente, carregando o trabalho da CPU no início. Então, em vez de destruí-los, você pode adicioná-los de volta ao pool para serem reutilizados quando um objeto do mesmo tipo for necessário novamente. Essa é uma maneira fantástica de aliviar o poder de processamento da CPU, para que ela possa trabalhar livremente em tarefas mais importantes para o seu jogo.

Com a mudança para o agrupamento de objetos, não há picos associados às ondas de inimigos que aparecem na tela e que podem ser identificados nas capturas do Unity Profiler, assim como nenhum efeito perceptível na taxa de quadros.

Malhas de nível de detalhe (LOD)

Quando uma malha está na tela, a GPU gasta tempo renderizando todos os triângulos na malha, não importa quão pequenos sejam. Em jogos em que sua câmera ou recursos podem se mover, isso geralmente cria uma situação em que você pode gastar muitos recursos da GPU renderizando triângulos de malhas que são muito pequenos para serem vistos no quadro. Para resolver isso, usemalhas de nível de detalhe (LOD) . Isso permite que seu jogo aproveite malhas menos complexas conforme a câmera se afasta dos ativos, o que diminui a quantidade de complexidade da malha que a GPU deve renderizar e reduz a contagem de vértices por quadro, resultando em triângulos maiores para o processamento de pixels. Isso não apenas melhora a eficiência como também mantém a integridade artística da cena intacta.

Malhas LOD
Malhas LOD

Para outras dicas de otimização de ativos, não deixe de conferir osGuias para Artistas de Jogosda Arm.

Atlas de textura

Quando você sabe que alguns ativos com as mesmas propriedades de material serão usados na mesma cena, você pode agrupá-los. Combine seus dados de textura em um único atlas de textura, o que economizará chamadas de desenho ao desenhá-los de uma só vez e resultará em um espaço menor quando compactado, em comparação a vários arquivos separados.

Precisão de Float vs Half Shader

Ao escrever seus próprios shaders personalizados ou usaro Shader Graph, você pode decidir qual precisão usar: float ou half. Escolher half, sempre que possível, resultará em shaders com melhor desempenho – mas lembre-se de que você provavelmente precisará usar float para qualquer coisa que lide com posições de espaço mundial ou cálculos de profundidade!

Definindo a precisão para metade no gráfico de sombreamento
Definindo a precisão para metade no gráfico de sombreamento
Conjuntos de recursos de processamento integrado vs Post Processing V2

Ao começar a planejar os efeitos de pós-processamento para seu projeto, você tem duas opções para escolher: o conjunto de recursos integrados legados ou o novo conjunto de recursosde Post Processing v2. Abaixo, você pode ver o jogo usando o conjunto de recursos integrados.

GPU Profiler sem Post Processing v2
GPU Profiler sem Post Processing v2

A cada 3–4 quadros, vemos um pico no V-Sync, onde o sistema fica esperando o quadro renderizar. Isso faz com que o jogo caia abaixo de 30 fps consistentemente e desperdice energia no dispositivo. Aqui, no entanto, você pode ver os dados do criador de perfil do jogo usando os mesmos efeitos, desta vez, com o conjunto de recursos de Post Processing v2.

GPU Profiler com Post Processing v2
GPU Profiler com Post Processing v2

Este gráfico do profiler é muito melhor, pois o Post Processing v2 é otimizado para rodar em hardware móvel. Use-o em seu projeto para obter o melhor desempenho de pós-processamento.

Efeitos de pós-processamento

Adicionar efeitos de pós-processamento ao seu jogo pode dar uma boa camada de polimento e profundidade visual ao seu projeto. Mas também é importante equilibrar esses efeitos com o desempenho. Afinal, esses efeitos podem sair caros. Desligá-los em dispositivos de mercado de massa pode economizar muita energia e impedir que o dispositivo esquente nas mãos dos jogadores.

Depois que as outras otimizações foram implementadas, ainda pudemos ver picos em algumas áreas. Ao usar a busca binária, ligando e desligando coisas, finalmente descobrimos duas coisas: Uma delas era a pilha de pós-processamento que estava sendo usada. Isso ajudou no tempo total, mas a taxa de quadros eventualmente se estabilizou quando desativamos o anti-aliasing, tanto que parte do pós-processamento conseguiu permanecer ativa, mesmo nos dispositivos com as especificações mais baixas que usamos para testar.

GPU Profiler - Exemplo otimizado
GPU Profiler - Exemplo otimizado

Depois de otimizar o jogo, nós o executamos novamente no Arm Mobile Studio para procurar quaisquer diferenças. O relatório do Performance Advisor agora mostra que alcançamos uma média de fps de 28,9 (anteriormente 17) e reduzimos o limite geral dos fragmentos. A atividade de fragmentos ainda é alta em algumas seções do jogo, então ainda temos trabalho a fazer, mas com bons dados para orientar nossa investigação, poderemos otimizar essas seções para melhorar ainda mais o desempenho.

Arm Mobile Studio - Resumo de captura
Arm Mobile Studio - Resumo de captura

O número de vértices por quadro agora está bem abaixo do nosso orçamento de 500.000, e você pode ver quedas regulares onde os NPCs inimigos são destruídos.

Arm Mobile Studio - Vértices por quadro
Arm Mobile Studio - Vértices por quadro

O uso e a seleção de geometria agora são muito mais eficientes, com o número de primitivas visíveis em uma porcentagem muito mais saudável do número de primitivas de entrada. O teste de faceamento é responsável por cerca de 50% dos primitivos eliminados, como esperado, e aqueles eliminados pelo teste de amostra ficam abaixo de 10%, mostrando que reduzimos o número de triângulos muito pequenos.

Taxa de uso e seleção de geometria do Mali
Taxa de uso e seleção de geometria do Mali
Resumindo

Ao usar o Profiler e o Frame Debugger da Unity, juntamente com o Arm Mobile Studio, conseguimos descobrir diversas maneiras de melhorar o desempenho e reduzir a pressão sobre a CPU e a GPU em um dispositivo móvel. Alguns dos problemas que descobrimos poderiam ser evitados em títulos futuros, seguindo um conjunto de práticas recomendadas para conteúdo.

É claro que não queremos que as otimizações reduzam a qualidade dos recursos visuais na tela. Veja como a versão otimizada do jogo se parece em comparação com a versão original.

Teste de desempenho proativo

Os testes de desempenho geralmente acontecem bem tarde no ciclo de desenvolvimento. É ótimo encontrar mais oportunidades de otimização, mas e se não houver tempo para corrigir os problemas antes do prazo de lançamento? É muito mais prático criar conteúdo de forma otimizada para começar. Pode ser útil definir orçamentos de conteúdo em torno da complexidade da malha, da complexidade do shader e da compressão de textura, para dar à sua equipe a melhor chance de projetar com eficiência para dispositivos móveis. Aqui estão alguns recursos que podem ajudar sua equipe:

Depois de saber que a maioria dos seus aplicativos e ativos seguem um conjunto de práticas recomendadas, você pode fazer testes de desempenho regulares durante todo o seu ciclo de desenvolvimento para detectar quaisquer problemas com antecedência suficiente para corrigi-los.

As equipes que usam um sistema de integração contínua podem aproveitar ostestes de desempenho automatizados, disponíveis com a edição profissional do Arm Mobile Studio. Esta edição pode ser executada em vários dispositivos em um conjunto de dispositivos e elimina a complicação da criação de perfil manual. Os dados relatados podem até mesmo ser inseridos em qualquer banco de dados compatível com JSON, para que você possa criar painéis visuais e alertas para monitorar como o desempenho muda ao longo do tempo, sinalizando problemas mais cedo.

Nunca experimentou ferramentas de criação de perfil antes?

O criador de perfil integrado do Unity é um ótimo lugar para começar. Leia sobrecomo criar o perfil do seu aplicativona documentação do Unity . Ou exploreo Frame Debugger, que permite investigar como um quadro individual é construído.

Baixe o Arm Mobile Studiogratuitamente no site do Arm Developer e confira os guias iniciais doPerformance Advisor,Streamline,Mali Offline CompilereGraphics Analyzerpara começar a usar rapidamente.

Entre em contato

Para obter ajuda adicional na criação de perfil com o Profiler e o Frame Debugger do Unity, sinta-se à vontade para fazer perguntas emnosso fórum.

Para obter mais suporte ao trabalhar com dispositivos Mali ou com o Arm Mobile Studio, acesseo Fórum de gráficos e jogos da Arm, onde você pode fazer perguntas. A Arm ficará feliz em ajudar.