View in English

  • Global Nav Open Menu Global Nav Close Menu
  • Apple Developer
Search
Cancel
  • Apple Developer
  • News
  • Discover
  • Design
  • Develop
  • Distribute
  • Support
  • Account
Only search within “”

Quick Links

5 Quick Links

Vídeos

Abrir menu Fechar menu
  • Coleções
  • Tópicos
  • Todos os vídeos
  • Sobre

Mais vídeos

  • Sobre
  • Resumo
  • Transcrição
  • Código
  • Explore jogos feitos com o Metal 4

    Saiba como otimizar o mecanismo do seu jogo com os últimos avanços do Metal 4. Abordaremos como unificar a codificação de comandos para minimizar a sobrecarga na CPU, aumentar o gerenciamento de recursos gráficos para compatibilidade com cenas grandes e maximizar seu orçamento para memória e carregar rapidamente bibliotecas grandes de configurações do pipeline. Para aproveitar ao máximo esta sessão, primeiro assista ao vídeo “Conheça o Metal 4”.

    Capítulos

    • 0:00 - Introdução
    • 1:33 - Codificar com mais eficiência
    • 8:42 - Aumentar o gerenciamento de recursos
    • 17:24 - Carregar pipelines rapidamente
    • 31:25 - Próximas etapas

    Recursos

    • Human Interface Guidelines: Designing for games
    • Metal binary archives
    • Reading and writing to sparse textures
    • Resource synchronization
    • Synchronizing resource accesses between multiple passes with a fence
    • Synchronizing resource accesses with earlier passes with a consumer-based queue barrier
    • Synchronizing resource accesses with subsequent passes with a producer-based queue barrier
    • Synchronizing resource accesses within a single pass with an intrapass barrier
    • Understanding the Metal 4 core API
    • Using a render pipeline to render primitives
    • Using the Metal 4 compilation API
      • Vídeo HD
      • Vídeo SD

    Vídeos relacionados

    WWDC25

    • Aprimore jogos com o Metal 4
    • Combine o aprendizado de máquina e os gráficos do Metal 4
    • Conheça o Metal 4
    • Melhore ainda mais seus jogos
    • Novidades na renderização no Metal para apps imersivos

    Tech Talks

    • Tune CPU job scheduling for Apple silicon games
  • Buscar neste vídeo...

    Olá! Meu nome é Jason! E eu sou Yang. Somos GPU Driver Engineers. Neste vídeo, apresentaremos como acelerar o mecanismo de jogo com o Metal 4. Esta é a segunda sessão na série de quatro partes para apresentar a próxima grande versão da API Metal. Antes de seguirmos com os jogos Metal 4, confira "Conhecer o Metal 4" para saber o que o Metal 4 tem a oferecer. Depois, confira "Vá além com os jogos Metal 4" para saber mais sobre as novas APIs Metal FX e Metal Raytracing. Não percar a sessão "Aprendizado de máquina no Metal 4" sobre a integração de ML. Vamos ver o Metal 4.

    O Metal 4 visa mecanismo de jogo atual. Jogos como Assassin's Creed Shadows da Ubisoft criam personagens e ambientes detalhados para que os jogadores se sintam nos mundos de fantasia. Eles transmitem gigabytes de geometria e texturas detalhadas, renderizados com milhares de sombreadores para aproveitar o poder computacional com o Apple Silicon. Os jogos do futuro serão ainda mais minuciosos e precisarão de uma API gráfica que se adapte à tarefa. É o Metal 4.

    O Metal 4 contém alguns avanços importantes no Metal para jogos. Inclui codificação de comando eficiente e gerenciamento de recursos dimensionado para acelerar o fluxo principal, além de carregamento de pipeline rápido para os jogadores irem direto para os jogos. Meu colega e eu vamos abordar como melhor usar esses recursos. Nos quadros, chamadas de desenho, despachos de kernel, blits e trabalho de traçado de raios são usados na codificação. A codificação Metal 4 serve para enfrentar esse desafio graças a sua eficiência e simultaneidade.

    O Metal 4 unifica as operações mais comuns em duas classes de codificador para se fazer mais com cada codificador. Os Alocadores de Comando permitem que você gerencie as alocações de memória durante a codificação. Os buffers de comando permitem codificar em vários threads.

    Em "Conhecer o Metal 4", vimos como duas classes de codificador, renderizar e computar, tratam a codificação de comandos. Para usá-las com eficiência, sincronize dependências de dados entre operações de computação e use mapas de anexos para remapear saídas de sombreador de fragmento. Pode-se codificar as operações de computação, despachos de kernel, blits e compilações de estrutura de aceleração em um codificador. Sem outra sincronização, os comandos são executados simultaneamente. Assim, as cargas de trabalho sem dependências usam melhor os recursos da GPU. Se for necessário executar comandos na passagem em série devido à dependência, expresse isso com a Barreira de Passagem. A barreira garante que a GPU aguarde até que todos os blits no codificador sejam concluídos antes que os despachos comecem. Este é um exemplo de como sincronizar o acesso direto de um blit até um despacho. O blit copyFromBuffer atualiza o buffer1, então codifique uma barreira. Depois, codifique um despacho que usa os dados no buffer1. Isso é codificação unificada. Trabalhe integralmente em um codificador e use barreiras para expressar dependências. O Metal 4 também atualizou a renderização. O mapeamento de anexos de cores controla a correspondência entre saídas de cores de um pipeline de renderização e anexos do codificador de renderização. Em vez de associar pipelines a um layout de destino de renderização fixo, forneça um mapa de anexo colorido. Quando for definir um pipeline, altere o mapa em vez de alternar codificadores. Suponha que você tenha um pipeline Metal com uma função fragment que atrai três anexos. Sem o mapeamento de anexos de cor, você criaria um codificador de renderização com três anexos. A função fragment retorna três saídas de cores e o codificador direciona essas saídas para os anexos correspondentes na memória de bloco. Na próxima chamada, talvez precise de um pipeline que grave em outro conjunto de saídas. Com anexos diferentes, você precisaria criar um codificador de renderização para corresponder às saídas de cores. Com o mapeamento de anexos, um segundo codificador não é necessário. O codificador de renderização tem todos os anexos de cor necessários para os pipelines. O mapa de anexos de cor converte a saída de sombreamento em anexos específicos. Para implementar o mapeamento, configure um descritor de passagem de renderização que ofereça suporte ao mapeamento. Em seguida, crie o superconjunto completo de anexos que serão usados. Para configurar em qual anexo o codificador desenhará, crie o mapa de anexo e defina as entradas de remapeamento. Em cada entrada, defina um índice lógico para indicar a saída do sombreador e um índice físico para indicar o índice de anexo. Crie esses objetos de mapeamento antes de codificar e reutilize-os a cada quadro. Com um pipeline de renderização, associe um mapa de anexo de cor. Se um pipeline desenhar em anexos diferentes, alterne para um mapa de anexos de cor diferente. O mapeamento de anexos de cor pode reduzir o número de codificadores de renderização no jogo. Isso diminui a sobrecarga de codificação e melhora a eficiência da GPU, reduzindo as passagens de renderização.

    O Metal 4 permite mais controle nas alocações de memória.

    Os alocadores de comando permitem reutilizar a memória do buffer de comando e evitar alocações dinâmicas. A memória do alocador cresce com a codificação. Redefina os alocadores assim que terminar a execução dos comandos da GPU. Redefinir libera a memória de comando para reutilização em outra codificação de comando. Use alocadores para evitar o bloqueio da codificação durante a conclusão do trabalho da GPU. Quando você codifica em um novo alocador de comandos, ele aloca memória para os comandos. Essa memória de comando é o trabalho feito na GPU, portanto, aguarde até a conclusão do trabalho para redefinir. Ao concluir o trabalho da GPU, reinicie o alocador de comando. Isso marca imediatamente a memória como disponível. Para codificar enquanto a GPU trabalha, use um segundo alocador de comando. Isso evita o bloqueio da codificação na conclusão do trabalho da GPU. É importante redefinir um alocador quando o trabalho da GPU terminar. A memória do alocador cresce para oferecer suporte até a redefinição. Se você não planeja codificar mais nenhum trabalho em um alocador, libere-o para reduzir o espaço ocupado. Os alocadores não são seguros para threads. Use alocadores diferentes para threads diferentes. Isso é importante na paralelização da codificação de cena. Os buffers de comando do Metal 4 permitem dividir a codificação em vários threads. Na codificação de thread único, você codificaria uma comandos para um ou mais buffers de comando em sequência. Aproveite a CPU multi-core do Apple Silicon e inicie vários buffers de comando em vários threads, cada um com um alocador de comandos diferente. Você pode usar a flexibilidade aprimorada do codificador do Metal 4 para distribuir a codificação de blits, despachos e trabalho de estrutura de aceleração. Quando terminar de codificar os buffers, você poderá enviá-los com uma única chamada de confirmação. O Metal 4 permite confirmar os codificadores de renderização como uma passagem na GPU. Suponha que você tenha um passagem de renderização demorada. Dividir a codificação em codificadores de renderização separados, leva a GPU a executar passagens de renderização separadas. A passagem gera sobrecarga ao armazenar e carregar resultados intermediários.

    O Metal 4 fornece a opção Suspend/Resume para mesclar vários codificadores. Basta suspender um codificador de renderização em um buffer e retomá-lo em outro buffer. Quando terminar de codificar os buffers de comando, envie-os sequencialmente em uma única chamada. Enviar os codificadores de renderização em uma confirmação instrui o Metal a mesclar as passagens. No caso, crie o primeiro codificador com opções de suspensão. A Metal mesclará o codificador com futuros codificadores. Use um buffer de comando diferente em cada codificador. O codificador do meio tem opções de retomada e suspensão. Crie o codificador final apenas com opções de retomada. Confirme os três buffers de comandos codificados juntos. Pronto! As passagens de renderização estão mescladas. Use o Metal 4 para melhorar a eficiência da codificação reduzindo o número de codificadores, reutilizando a memória de comando e codificando em vários threads. Para saber mais sobre a codificação de comandos do Metal 4, consulte o artigo no site Apple Developer. Agora que abordei a codificação eficiente, vamos ver o gerenciamento eficiente de recursos. O Metal 4 tem alguns recursos interessantes para ajudar a gerenciar as funcionalidades. As tabelas de argumentos e os conjuntos residentes permitem dimensionar a associação de milhares de recursos. O Metal 4 permite que você gerencie os recursos de desenho e controle as dependências. As barreiras de fila permitem expressar as dependências de recursos. Os pools de visualização de textura e os heaps sparse de posicionamento ajudam a gerenciar a memória de recursos grandes. Aumentar a complexidade dos sombreadores indica que um modelo sem associação é apropriado para o volume de recursos. Com um único buffer de argumento, o sombreador acessa milhares de recursos, incluindo buffers, texturas, modelos, estados de pipeline, etc. Os pontos de associação indexados ainda são usados em recursos root-level.

    Use tabelas de argumento para associar recursos por índice. Durante a codificação, defina qual tabela deve ser usada pela próxima chamada ou despacho. Há recursos para sombreadores como argumentos de função indexada. Na hora da chamada e do despacho, o Metal reúne argumentos. É seguro definir um recurso para um índice de associação entre chamadas de desenho. Pode-se definir uma única tabela de argumento em várias etapas.

    Criar tabelas de argumento antes da codificação permite tirar a associação de recursos do caminho crítico. Pode-se anexar uma tabela de argumento a vários codificadores. Use tabelas de argumento com buffers para dimensionar as necessidades de associação de recursos. A próxima etapa para acessar os recursos nos sombreadores é torná-los visíveis na GPU. Quando precisar de um recurso na GPU, adicione-o a um conjunto residente. Isso inclui pipelines, buffers, textures e drawables. Os conjuntos residentes permitem agrupar muitos recursos e torná-los visíveis ao mesmo tempo. Anexe-os a um buffer de comando que seja confirmado ou diretamente à fila de comandos. Se um conjunto residente não mudar muito com o tempo, prefira anexá-lo à fila de comandos. Se um conjunto residente for alterado com frequência, anexe-o aos buffers de comando apropriados. Pode levar tempo para preparar recursos grandes para a GPU. Você pode pedir ao Metal para criar os recursos de um conjunto previamente. Prefira ter menos conjuntos residentes com mais recursos cada. Isso melhora o desempenho, permitindo que o Metal processe os recursos em massa. Saiba mais sobre conjuntos residentes no artigo no site Apple Developer e a sessão "Fazer a portabilidade de jogos avançados para as plataformas da Apple" do ano passado. O Metal 4 permite o controle sobre a residência de recursos também em superfícies drawable do jogo. Envie o conteúdo renderizado do jogo para a tela, renderizando as superfícies drawable em uma CAMetalLayer. Cada camada do Metal têm um conjunto residente dinâmico. Adicione-o à fila de comandos para criar textures na camada residentes. Adicione o conjunto residente só uma vez. A CAMetalLayer vai atualizá-lo. No Metal 4, você também precisa sincronizar a renderização com o drawable. Em cada quadro, depois de obter o próximo drawable, codifique uma espera na fila de comandos antes de renderizar no drawable. Depois de confirmar o trabalho de renderização, codifique um sinal para o drawable na fila.

    Chame present para enviar o conteúdo do quadro para a tela assim que a renderização for concluída. Para reduzir a sobrecarga de rastreamento, o Metal 4 deixa você sincronizar os recursos. No início, abordei como usar Barreiras de Passagem em codificadores. As Barreiras de Fila, por outro lado, expressam uma dependência de dados entre codificadores na mesma fila.

    Filtram barreiras por estágios do Metal. Cada comando em um codificador está associado a um ou mais estágios de execução. Chamadas de desenho em codificadores de renderização geram sombreamento de vértice e fragmento. As GPUs Apple Silicon agrupam todos os vértice, seguidos por todo o sombreamento de fragmentos. Os comandos do Metal 4 correspondem aos estágios da estrutura de expedição, blit e aceleração. É importante escolher as etapas para evitar o excesso de sincronização. No exemplo, a passagem de computação executa simulação atmosférica no despacho de kernel. Ela grava resultados na textura na memória. A passagem desenha a cena. O sombreamento de fragmento requer que os resultados da simulação se misturem com a luz, mas o trabalho de vértice ficar livre para se sobrepor à computação. Sincronize o acesso com resultados da simulação codificando uma barreira dos estágios de despacho da fila para o estágio de fragmento. Para implementar o exemplo, codifique o despacho em um codificador de computação. No codificador, adicione uma barreira após o despacho do estágio de fila e antes do estágio de fragmento. Depois da barreira, codifique chamadas de desenho. O Metal garante que qualquer trabalho de estágio de fragmento não seja executado até que o trabalho de estágio de despacho esteja concluído.

    Para ajudar você a encontrar os melhores lugares para suas barreiras, o depurador do Metal mostra as localizações com codificadores e estágios a que eles se aplicam. Use isso para maximizar a simultaneidade mantendo as dependências de dados.

    Para saber mais sobre como sincronizar recursos usando barreiras do Metal, leia os artigos completos no site Apple Developer.

    O streaming de texture e buffer permite gerenciar o espaço ocupado pela memória de milhares de recursos. O Metal 4 permite que transmitir buffers e textures de modo eficiente. Crie texture views leves e gerencie o espaço ocupado com o recurso Placement Sparse. Os jogos modernos criam centenas de texture views e texture buffer views por quadro. TextureViewPools permitem que você pré-aloque a memória para conter todas as texture views. Você pode criar texture views leves em qualquer índice no pool. Isso não causa alocações dinâmicas, portanto, você pode criá-las durante a codificação. Use o ID de recurso da view texture para associá-lo a um buffer ou tabela de argumentos. Veja como implementar isso. Crie um texture view pool previamente. No caso, o texture view pool criado tem memória alocada para 500 texture views. Defina uma view no índice desejado no texture view pool. Use o MTLResourceID retornado para associar a texture view a uma tabela de argumento. Os recursos que você precisa associar podem ocupar muita memória. Recursos Sparse são ótimos para recursos de alta fidelidade que talvez não caibam todos na memória. Eles dissociam a criação de recursos do suporte de memória. Com placement sparse, você tem controle sobre como os recursos são mapeados para as páginas do heap. Quando se atualiza mapeamentos de memória dos recursos, as APIs na fila de comandos do Metal 4 permitem sincronizar as atualizações com outros trabalhos da GPU. A memória em um heap de posicionamento é organizada como uma sequência de blocos. Você controla a atribuição desses blocos a buffers e textures sparse. Libere memória para recursos Sparse mapeando intervalos de bytes ou regiões de pixel para blocos sparse.

    Ao criar um heap de posicionamento, considere os tamanhos de página sparse que os recursos precisarão. Página maiores têm benefícios de desempenho em operações de mapeamento e desmapeamento, mas usam mais memória de preenchimento e alinhamento. O heap permitirá todos os tamanhos de página sparse até o máximo especificado. O exemplo escolhe um tamanho máximo de 64 kB. Depois de criar um heap de posicionamento, crie os recursos sparse. A criação de buffers e textures sparse de posicionamento é feita em Metal Device. Nos buffers, alinhe o tamanho do buffer com múltiplos de sparseTileSize. O dispositivo fornece consulta para executar a conversão. Defina placementSparsePageSize ao chamar o buffer com length ou em um texture descriptor. A propriedade informa o Metal Device que um heap de posicionamento fornecerá o suporte de memória. Quando se cria um buffer sparse de posicionamento, ele não tem memória de suporte. Atribua blocos a intervalos de buffer com operações de mapeamento de atualização. Atribua blocos de um heap de posicionamento a um buffer especificando uma operação de mapeamento de atualização. Forneça deslocamento inicial, comprimento e deslocamento de bloco no heap para atribuir ao intervalo de buffer. Envie a operação de mapeamento em uma fila de comandos do Metal 4.

    Para saber mais sobre como trabalhar com recursos sparse, confira o artigo no site Apple Developer. Outro desafio para os jogos modernos é gerenciar grandes bibliotecas de estados de pipeline. Mas agora, é a vez do Yang. Obrigado, Jason. Os jogos modernos precisam gerar milhares de pipelines para criar visuais complexos e dinâmicos. Carregar pipelines rapidamente é crucial para eliminar travamentos de conclusão de sombreador e reduzir o tempo para carregar o jogo. Carregue pipelines rapidamente no Metal 4 reutilizando as compilações de pipeline de renderização. Você também pode compilar pipelines no dispositivo com um novo nível de paralelismo. Compilar pipelines com antecedência permite reduzir o tempo de carregamento do pipeline até perto de zero. Mostrarei como reutilizar as compilações de pipeline de renderização com estados de pipeline de renderização flexíveis. Você cria um jogo de construção em que os jogadores podem colocar casas ao redor do mapa. Quando o jogador colocar uma casa, o jogo deve renderizar a casa no estilo holograma, então ele precisa de um pipeline com um estado de mesclagem aditiva. O jogador coloca a casa. A casa começa a ser construída. Para renderizar a casa com transparência, para mostrar o andamento, é preciso outro pipeline com estado de mesclagem transparente. Finalmente, quando a casa for terminada, ele renderizará a casa com um terceiro pipeline com um estado de mesclagem opaco. Compile os três pipelines com o estado completo fornecendo as configurações completas do pipeline após a criação. Comece com uma função vertex e a função fragment, e as configurações de anexo de cor para as casas holográfica, transparente e opaca. A configuração de anexo de cor representa uma parte do descritor que afeta a gravação de saídas de sombreador de fragmento para anexos de cor. Isso inclui o formato de pixel dos anexos, as máscaras corretas e os estados de mesclagem. Crie um descritor de pipeline de renderização que faça referência à função vertex, à função fragment e à configuração opaca. Com esse descritor, crie o pipeline opaco contendo um binário vertex, um corpo binário fragmento e uma parte de saída de fragmento. Trocando a configuração de anexo de cor no descritor, você pode criar de forma semelhante o pipeline transparente e o pipeline de holograma. A maioria dos binários nesses três pipelines são iguais, apenas a parte da saída do fragmento é diferente. Em uma visualização de linha do tempo da CPU, você compila o pipeline opaco completo e o pipeline transparente, seguido pelo de holograma. A CPU gasta muito tempo recompilando principalmente o mesmo pipeline, exceto para a parte de saída de fragmento. Com o Metal 4, agora você pode reutilizar a maior parte da conclusão do pipeline criando um pipeline não especializado. Use configurações de anexo de cor diferentes para obter os pipelines finais especializados. Isso pode realmente poupar tempo de conclusão do pipeline de renderização. Para conseguir isso, crie um pipeline não especializado. Comece com o mesmo descritor, mas em vez de fornecer a configuração real do anexo de cor, defina cada campo como não especializado. Para fazer isso, percorra todos os descritores de anexo de cor e defina pixelFormat, writeMask e blendingState com valores não especializados correspondentes. O pipeline não especializado contém um binário vertex, o corpo binário do fragmento e a parte de saída do fragmento padrão. A saída de fragmento padrão funciona para alguns casos, mas, frequentemente, você precisará substituí-la especializando o pipeline. Crie o pipeline especializado com o pipeline não especializado e um novo descritor de pipeline de renderização. Desta vez, defina a configuração do anexo de cor no descritor com os valores reais necessários. O pipeline especializado contém uma saída de fragmento correspondente substituindo a saída de fragmento padrão. A nova saída de fragmento pode ser gerada com muita rapidez, e você não precisa passar outra vez pela compilação completa do sombreador. Volto ao exemplo da especialização do pipeline transparente. Comece definindo as propriedades não especializadas anteriores no descritor. Ative o estado de mesclagem e defina subestados de mesclagem. O código define o pipeline para fazer mesclagem alfa pré-multiplicada. Instancie o pipeline especializado usando o novo descritor com o pipeline não especializado. O jogo pode estar criando milhares de pipelines de renderização de estado. Maximize a redução do tempo de carregamento. Crie todo o pipeline de renderização não especializado e especialize-o depois. Depois, você pode notar que há uma pequena sobrecarga de desempenho da GPU. Grande parte dela pode vir do trabalho desnecessário do corpo do fragmento compartilhado. Por exemplo, se um sombreador de fragmento grava em quatro canais de cores e o anexo de cor tem apenas um canal, o compilador não consegue mais otimizar os canais não utilizados. Há também uma pequena sobrecarga causada pelo salto do corpo binário do fragmento para a parte de saída do fragmento. A sobrecarga geralmente é pequena, mas pode ser grande em alguns sombreadores. Identifique sombreadores importantes e compile com o estado completo para que o jogador aproveite tempos de carregamento curtos e ótima taxa de quadros. Você pode usar Instruments Metal System Trace para classificar os sombreadores de fragmento especializados mais caros. Recapitulando, veja a melhor forma de incorporar estados flexíveis do pipeline de renderização ao jogo. Compile cada pipeline de renderização não especializado e especialize-o conforme necessário. Se houver queda de desempenho, use o Metal System Trace da Instrument para traçar o perfil do seu jogo e identificar pipelines importantes. Nesse caso, compile uma versão básica em segundo plano e use-a para substituir uma versão especializada quando estiver pronta. Para saber mais sobre os estados flexíveis do pipeline de renderização, confira este artigo no site Apple Developer.

    Depois da reutilização, reduza ainda mais o tempo de carregamento do pipeline paralisando sua própria compilação em dispositivo. Alguns jogos podem usar um único thread para carregar pipelines durante o jogo. Este é o único thread de compilação que cria os pipelines que o jogo está prestes a usar. Este um thread de renderização que executa o trabalho de renderização de quadro repetido, como a codificação. Se os pipelines necessários não estiverem prontos, o jogo pode travar. Você pode acelerar o carregamento do pipeline adicionando outro thread de compilação. A compilação do pipeline termina mais cedo. Se você não tiver cuidado com a prioridade de threads, o jogo ainda pode perder os intervalos atuais. Depois de definir a prioridade do thread de conclusão como um valor menor ao do thread de renderização, o problema desaparece. Agora o jogador desfruta de uma jogabilidade contínua. Veja como adicionar a conclusão de multithreaded ao jogo. Use as APIs de conclusão do Metal 4. O compilador é capaz de ir ainda mais longe no Metal 4. Você pode usar Grand Central Dispatch ou criar seu próprio pool de threads, dependendo da opção que encaixa melhor na arquitetura do jogo. Não importa a escolha, lembre-se de definir uma prioridade apropriada. O Metal respeitará a prioridade das tarefas de compilação. Grand Central Dispatch é a maneira mais fácil de transmitir compilações de multithreaded. Se desejar que a compilação herde a prioridade do thread de chamada, use grupos de despacho com os métodos assíncronos fornecidos pelo compilador. Os métodos assíncronos são aqueles com um manipulador de conclusão. O Metal executará automaticamente esses métodos simultaneamente. Se desejar personalizar a prioridade da compilação, crie uma fila de despacho simultânea com uma qualidade de serviço personalizada ou classe QoS. Em pré-aquecimento e streaming de pipeline, recomendamos que o defina como padrão. Para enviar testes de conclusão a uma fila de despacho, invoque métodos de sincronização em bloco e envie-os para a fila via dispatch_async. Os métodos síncronos são aqueles sem manipulador de conclusão.

    Crie seu próprio pool de threads se isso se encaixar melhor na arquitetura do jogo. Use uma propriedade maximumConcurrentCompletionTestCount no Metal Device como a contagem de threads para um pool de threads. Defina a contagem de threads padrão como 2, pois é a simultaneidade máxima em sistemas operacionais que não dão suporte a essa propriedade. É importante também definir uma classe adequada de QoS para os tópicos de compilação para evitar a inanição de outros threads importantes no jogo. Defina a QoS como padrão para pré-aquecimento e streaming de pipeline. É isso. Você pode começar a enviar tarefas de compilação para seu pool de threads. Para obter mais informações sobre as melhores maneiras de paralisar e priorizar a compilação de pipeline, confira estes artigos no site Apple Developer. A compilação de multithreaded no dispositivo pode reduzir o tempo de compilação. Para reduzi-lo a quase zero, o caminho a seguir é a pré-compilação de pipelines no desenvolvimento. Para compilar pipelines com antecedência, os jogos usam um fluxo de trabalho completo. O fluxo de trabalho começa colhendo as configurações de pipeline usadas no jogo, executando o jogo com alguma instrumentação. Os resultados são alimentados na cadeia de ferramentas da GPU para criar binários da GPU. Em tempo de execução, o jogo procura os binários da GPU pré-compilados para criar pipelines rapidamente. O Metal 4 facilita a coleta de sua configuração de pipeline online e a busca por binários pré-compilados em seu jogo para envio. No Metal 4, a maneira mais fácil de coletar uma configuração de pipeline é serializar um script de pipeline. Um script de pipeline é um arquivo formatado em JSON. Ele contém uma representação textual dos descritores de pipeline criados no dispositivo. Serializar um script é fácil com um serializador de conjunto de dados de pipeline no Metal 4. Depois de associar esse objeto ao compilador, ele registrará automaticamente os descritores para os pipelines criados. Em seguida, você pode serializar os descritores em um script de pipeline. Crie o serializador de conjunto de dados de pipeline com um descritor. Defina a configuração como CaptureDescriptors. Isso informa ao serializador para rastrear apenas descritores de pipeline e reduz o espaço na memória. Use um descritor para criar o serializador de conjunto de dados de pipeline. Em seguida, anexe um serializador ao descritor do compilador usado para criar o compilador. Depois de criar o compilador, use-o para criar pipelines como de costume. O serializador registrará automaticamente os descritores de pipeline usados. Quando terminar de coletar, chame serializeAsPipelinesScriptWithError para serializar os pipelines gravados em um script de pipeline. O valor de retorno é um NSData. Use seu método favorito para enviá-lo de volta ao seu sistema de desenvolvimento. Este exemplo apenas o grava em um arquivo no disco. Defina o sufixo do arquivo como mtl4-json. Esse é o sufixo esperado pela cadeia de ferramentas da GPU. Depois de coletar as configurações de pipeline, a próxima etapa é criar os binários. Alimente o script de configuração de pipeline e bibliotecas Metal IR para metal-tt. Ele produzirá os binários da GPU empacotados em um arquivo do Metal. Antes de alimentar o script de pipeline coletado para metal-tt, abra o script e modifique o caminho das bibliotecas Metal IR para corresponder ao caminho no sistema de desenvolvimento. Para obter mais informações sobre o formato de script de configuração de pipeline, abra a página do manual deste comando. Em seguida, basta executar o comando metal-tt na tela para criar um arquivo para iOS. Agora que você pré-compilou os binários, o jogo precisará procurá-los em tempo de execução. O Metal 4 facilita ainda mais a criação de pipelines direto de binários da GPU em um arquivo. Basta usar o mesmo descritor que você usaria para compilar em dispositivo para recuperar os estados do pipeline. Por exemplo, crie um objeto MTL4Archive fornecendo o URL para o arquivo. Consulte o estado do pipeline diretamente do objeto archive com um descritor de pipeline.

    A pesquisa no arquivo pode falhar por vários motivos, como nenhum pipeline correspondente, sistema operacional ou arquitetura de GPU incompatíveis. Você mesmo precisa lidar com essas falhas no Metal 4. O exemplo aqui recai sobre a compilação no dispositivo, então o jogo ainda tem um estado de pipeline necessário daqui para frente.

    Veja a linha do tempo da CPU para o jogo de exemplo novamente com uma conclusão multithreaded no dispositivo. Quando se adota a conclusão antecipada, o tempo de carregamento do pipeline diminui para quase zero. Para saber mais sobre a conclusão antecipada, confira estes artigos no site Apple Developer. Recapitulando. O Metal 4 oferece ótimas maneiras de carregar estados de pipeline mais rápidos. Reutilize os resultados da compilação usando a especialização de pipeline. Acelere ainda mais a compilação com multithreading. Obtenha tempos de carregamento menores adotando a compilação antecipada com um fluxo de trabalho de coleta e pesquisa simplificado. Apreciamos mostrar muitas maneiras de usar as APIs do Metal 4 para criar a próxima geração de jogos de alto desempenho. Baixe o novo Xcode para a otimizar a codificação, o gerenciamento de recursos e o carregamento de pipelines. Incluímos exemplos de projetos e artigos detalhados para apoiar sua jornada. Para continuar explorando o que o Metal 4 tem a oferecer, confira as outras sessões desta série. Agradecemos sua participação.

    • 0:01 - Synchronize access to a buffer within an encoder

      // Synchronize access to a buffer within an encoder
      
      id<MTL4ComputeCommandEncoder> encoder = [commandBuffer computeCommandEncoder];
      
      [encoder copyFromBuffer:src sourceOffset:0 toBuffer:buffer1 destinationOffset:0 size:64];
      
      [encoder barrierAfterEncoderStages:MTLStageBlit 
                     beforeEncoderStages:MTLStageDispatch
                       visibilityOptions:MTL4VisibilityOptionDevice];
      
      [encoder setComputePipelineState:pso];
      
      [argTable setAddress:buffer1.gpuAddress atIndex:0];
      [encoder setArgumentTable:argTable];
      [encoder dispatchThreads:threadsPerGrid threadsPerThreadgroup:threadsPerThreadgroup];
      
      [encoder endEncoding];code snippet.
    • 4:29 - Configure superset of color attachments

      // Configure superset of color attachments
      
      MTL4RenderPassDescriptor *desc = [MTLRenderPassDescriptor renderPassDescriptor];
      
      desc.supportColorAttachmentMapping = YES;
      
      desc.colorAttachments[0].texture = colortex0;
      desc.colorAttachments[1].texture = colortex1;
      desc.colorAttachments[2].texture = colortex2;
      desc.colorAttachments[3].texture = colortex3;
      desc.colorAttachments[4].texture = colortex4;
    • 4:38 - Set color attachment map entries

      // Set color attachment map entries
      
      MTLLogicalToPhysicalColorAttachmentMap* myAttachmentRemap = [MTLLogicalToPhysicalColorAttachmentMap new];
      
      [myAttachmentRemap setPhysicalIndex:0 forLogicalIndex:0];
      [myAttachmentRemap setPhysicalIndex:3 forLogicalIndex:1];
      [myAttachmentRemap setPhysicalIndex:4 forLogicalIndex:2];
    • 4:57 - Set a color attachment map per pipeline

      // Set a color attachment map per pipeline
      
      [renderEncoder setRenderPipelineState:myPipeline];
      [renderEncoder setColorAttachmentMap:myAttachmentRemap];
      // Draw with myPipeline
      
      [renderEncoder setRenderPipelineState:myPipeline2];
      [renderEncoder setColorAttachmentMap:myAttachmentRemap2];
      // Draw with myPipeline2
    • 8:03 - Encode a single render pass with 3 render encoders

      // Encode a single render pass with 3 render encoders with suspend/resume options
      
      
      id<MTL4RenderCommandEncoder> enc0 = [cmdbuf0 renderCommandEncoderWithDescriptor:desc options:MTL4RenderEncoderOptionSuspending];
      
      id<MTL4RenderCommandEncoder> enc1 = [cmdbuf1 renderCommandEncoderWithDescriptor:desc options:MTL4RenderEncoderOptionResuming | MTL4RenderEncoderOptionSuspending];
      
      id<MTL4RenderCommandEncoder> enc2 = [cmdbuf2 renderCommandEncoderWithDescriptor:desc options:MTL4RenderEncoderOptionResuming];
      
      
      id<MTL4CommandBuffer> cmdbufs[] = { cmdbuf0, cmdbuf1, cmdbuf2 };
      [commandQueue commit:cmdbufs count:3]
    • 11:48 - Synchronize drawable contents

      // Synchronize drawable contents
      
      id<MTLDrawable> drawable = [metalLayer nextDrawable];
      [queue waitForDrawable:drawable];
      
      // ... encode render commands to commandBuffer ...
      [queue commit:&commandBuffer count:1];
      
      [queue signalDrawable:drawable];
      
      [drawable present];
    • 13:25 - Encode a queue barrier to synchronize data

      // Encode a queue barrier to synchronize data
      
      id<MTL4ComputeCommandEncoder> compute = [commandBuffer computeCommandEncoder];
      
      [compute dispatchThreadgroups:threadGrid threadsPerThreadgroup:threadsPerThreadgroup];
      
      [compute endEncoding];
      
      
      id<MTL4RenderCommandEncoder> render = [commandBuffer renderCommandEncoderWithDescriptor:des];
      
      [render barrierAfterQueueStages:MTLStageDispatch
                         beforeStages:MTLStageFragment
                    visibilityOptions:MTL4VisibilityOptionDevice];
      
      [renderCommandEncoder drawPrimitives:MTLPrimitiveTypeTriangle
                               vertexStart:vertexStart
                               vertexCount:vertexCount];
      
      [render endEncoding];
    • 14:57 - Create a texture view pool

      // Create a texture view pool
      
      MTLResourceViewPoolDescriptor *desc = [[MTLResourceViewPoolDescriptor alloc] init]; 
      desc.resourceCount = 500;
       
      id <MTLTextureViewPool> myTextureViewPool =  
          [myDevice newTextureViewPoolWithDescriptor:myTextureViewPoolDescriptor 
                                               error:nullptr];
    • 15:07 - Set a texture view

      // Set a texture view
      
      MTLResourceID myTextureView = [myTextureViewPool setTextureView:myTexture  
                                                           descriptor:myTextureViewDescriptor  
                                                              atIndex:5];
      
      [myArgumentTable setTexture:myTextureView 
                          atIndex:0];
    • 16:01 - Choose appropriate sparse page size

      MTLHeapDescriptor *desc = [MTLHeapDescriptor new];    
      desc.type = MTLHeapTypePlacement;
      desc.storageMode = MTLStorageModePrivate;
      desc.maxCompatiblePlacementSparsePageSize = MTLSparsePageSize64;
      desc.size = alignedHeapSize;
      
      id<MTLHeap> heap = [device newHeapWithDescriptor:desc];
    • 17:05 - Update buffer mappings

      // Update buffer mappings
      
      MTL4UpdateSparseBufferMappingOperation bufferOperation;
      
      bufferOperation.mode = MTLSparseTextureMappingModeMap;  
      bufferOperation.bufferRange.location = bufferOffsetInTiles;
      bufferOperation.bufferRange.length = length;
      bufferOperation.heapOffset = heapOffsetInTiles;
      
      [cmdQueue updateBufferMappings:myBuf heap:myHeap operations:&bufferOperation count:1];
    • 20:41 - Set unspecialized configuration

      // In MTL4RenderPipelineColorAttachmentDescriptor
      // Set unspecialized configuration
      
      pipelineDescriptor.colorAttachments[i].pixelFormat   = MTLPixelFormatUnspecialized;
      pipelineDescriptor.colorAttachments[i].writeMask     = MTLColorWriteMaskUnspecialized;
      pipelineDescriptor.colorAttachments[i].blendingState = MTL4BlendStateUnspecialized;
    • 21:40 - Create a specialized transparent pipeline

      // Create a specialized transparent pipeline
      
      // Set the previously unspecialized properties
      pipelineDescriptor.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
      pipelineDescriptor.colorAttachments[0].writeMask =
          MTLColorWriteMaskRed | MTLColorWriteMaskGreen | MTLColorWriteMaskBlue;
      pipelineDescriptor.colorAttachments[0].blendingState = MTL4BlendStateEnabled;
      
      pipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorOne;
      pipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = 
          MTLBlendFactorOneMinusSourceAlpha;
      pipelineDescriptor.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
      
      id<MTLRenderPipelineState> transparentPipeline = 
          [compiler newRenderPipelineStateBySpecializationWithDescriptor:pipelineDescriptor
                                                                pipeline:unspecializedPipeline
                                                                   error:&error];
      
      // Similarly, create the specialized opaque and hologram pipelines
    • 26:22 - Determine thread count

      // Determine thread count
      NSInteger numThreads = 2;
      if (@available(macOS 13.3, iOS 19, visionOS 3, tvOS 19, *))
      {
          numThreads = [device maximumConcurrentCompilationTaskCount];
      }
    • 26:30 - Set a proper QoS class for your compilation threads

      // Create thread pool
      for (NSInteger i = 0; i < numThreads; ++i)
      {
          // Creating a thread with a QoS class DEFAULT
          pthread_attr_set_qos_class_np(&attr, QOS_CLASS_DEFAULT, 0) ;
          pthread_create(&threadIds[i], &attr, entryPoint, NULL);
          pthread_attr_destroy(&attr);
      }
    • 28:24 - Harvest pipeline configuration scripts

      // Harvest pipeline configuration scripts with the pipeline data set serializer
      
      // Create a pipeline data set serializer that only captures descriptors
      MTL4PipelineDataSetSerializerDescriptor *desc = [MTL4PipelineDataSetSerializerDescriptor new];
      desc.configuration = MTL4PipelineDataSetSerializerConfigurationCaptureDescriptors;
      id<MTL4PipelineDataSetSerializer> serializer =
          [device newPipelineDataSetSerializerWithDescriptor:desc];
      
      // Set the pipeline data set serializer when creating the compiler
      MTL4CompilerDescriptor *compilerDesc = [MTL4CompilerDescriptor new];
      [compilerDesc setPipelineDataSetSerializer:serializer];
      id<MTL4Compiler> compiler = [device newCompilerWithDescriptor:compilerDesc error:nil];
      
      // Create pipelines using the compiler as usual
      
      // Serialize the descriptors as a pipeline script
      NSData *data = [serializer serializeAsPipelinesScriptWithError:&err];
      
      // Write the pipeline script data to disk
      NSString *path = [NSString pathWithComponents:@[folder, @"pipelines.mtl4-json"]];
      BOOL success = [data writeToFile:path options:NSDataWritingAtomic error:&err];
    • 30:28 - Query pipeline state from MTLArchive

      // Query pipeline state from MTLArchive
      
      id<MTL4Archive> archive = [device newArchiveWithURL:archiveURL error:&error];
      
      id<MTLRenderPipelineState> pipeline = 
          [archive newRenderPipelineStateWithDescriptor:descriptor error:&error];
      
      if (pipeline == nil)
      {
          // handle lookup miss
      		pipeline = [compiler newRenderPipelineStateWithDescriptor:descriptor 
                                                compilerTaskOptions:nil 
      }
    • 0:00 - Introdução
    • Esta é a segunda de uma série de quatro partes no Metal 4, a nova API gráfica da Apple criada para mecanismos de jogos modernos. O Metal 4 aprimora a codificação de comandos, o gerenciamento de recursos e o carregamento de pipeline. Ele atende às demandas de jogos atuais e futuros, que transmitem gigabytes de geometria detalhada e texturas, renderizadas com milhares de sombreadores, para aproveitar todo o poder da computação que o Apple Silicon oferece. Assista também às outras partes da série para saber mais sobre MetalFX, traçado de raios e integração de aprendizado de máquina.

    • 1:33 - Codificar com mais eficiência
    • O Metal 4 foi projetado para aumentar a eficiência da GPU otimizando a codificação de comandos. Ele apresenta duas classes principais de codificadores, renderização e computação, que agora podem processar as operações de jogos mais comuns. Use o Metal 4 para melhorar a eficiência da codificação reduzindo o número de codificadores, reutilizando a memória de comando e codificando em vários threads.

    • 8:42 - Aumentar o gerenciamento de recursos
    • O Metal 4 tem alguns recursos interessantes para ajudar a gerenciar as funcionalidades. As tabelas de argumentos e os conjuntos residentes permitem dimensionar a associação de milhares de recursos. O Metal 4 permite gerenciar os recursos de desenho e dá controle sobre dependências. As barreiras de filas permitem expressar as dependências de recursos. Os pools de visualização de textura e os heaps esparsos de posicionamento ajudam a gerenciar a memória de recursos grandes.

    • 17:24 - Carregar pipelines rapidamente
    • Os jogos modernos precisam criar milhares de pipelines para criar visuais complexos e dinâmicos. Carregar muitos pipelines com rapidez é crucial para eliminar travamentos na compilação dos sombreadores e reduzir o tempo de carregamento do jogo. Para fazer isso no Metal 4, reutilize suas compilações de pipeline de renderização, compile os pipelines no dispositivo com um novo nível de paralelismo e com antecedência para que o tempo de carregamento seja reduzido para quase 0.

    • 31:25 - Próximas etapas
    • As APIs do Metal 4 foram projetadas para você criar a próxima geração de jogos de alto desempenho. Você pode conferir a documentação no site do desenvolvedor, testar os projetos de exemplo e baixar o novo Xcode para começar.

Developer Footer

  • Vídeos
  • WWDC25
  • Explore jogos feitos com o Metal 4
  • Open Menu Close Menu
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • Icon Composer
    • SF Symbols
    Open Menu Close Menu
    • Accessibility
    • Accessories
    • App Store
    • Audio & Video
    • Augmented Reality
    • Business
    • Design
    • Distribution
    • Education
    • Fonts
    • Games
    • Health & Fitness
    • In-App Purchase
    • Localization
    • Maps & Location
    • Machine Learning & AI
    • Open Source
    • Security
    • Safari & Web
    Open Menu Close Menu
    • Documentation
    • Sample Code
    • Tutorials
    • Downloads
    • Forums
    • Videos
    Open Menu Close Menu
    • Support Articles
    • Contact Us
    • Bug Reporting
    • System Status
    Open Menu Close Menu
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles
    • Feedback Assistant
    Open Menu Close Menu
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program
    • News Partner Program
    • Video Partner Program
    • Security Bounty Program
    • Security Research Device Program
    Open Menu Close Menu
    • Meet with Apple
    • Apple Developer Centers
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Academies
    • WWDC
    Get the Apple Developer app.
    Copyright © 2025 Apple Inc. All rights reserved.
    Terms of Use Privacy Policy Agreements and Guidelines