Nilson Souto 
xissburg 
Venha bater um papo com a 
galera no IRC @ freenode ;) 
#iphonedev 
#iphonedev-chat 
#swift-lang 
##OpenGL 
…
Metal? 
• API gráfica de baixo nível que apresenta uma 
abstração muito próxima à arquitetura das GPUs 
• “bare metal access” 
• “close to the metal” 
• Substitui o OpenGL ES 
• Camada mais fina entre o software e o hardware
Metal? 
• Outras tecnologias semelhantes: 
• AMD Mantle 
• Microsoft DirectX 12 
• OpenGL Next 
• A ideia é produzir APIs diretamente compatíveis com 
as arquiteturas das GPUs modernas 
• Descartar APIs criadas há mais de 20 anos
Conceitos 
• Device 
• Command Queue 
• Command Buffer 
• Command Encoder 
• Buffers 
• Textures 
• Functions 
• Pipeline
Device 
• Representa a GPU 
• Funciona como uma factory para criar command 
queues, buffers, texturas, etc 
• Utilizamos a função 
MTLCreateSystemDefaultDevice para criar uma 
instância
Command Queue 
• Fila de comandos a serem executados pela GPU 
• Através dela podemos criar command buffers, 
depois configurá-los e por fim submetê-los para 
execução
Command Buffer 
• Armazena comandos para serem executados pela 
GPU 
• Em geral, utilizamos um command buffer para 
desenhar um frame de uma animação 
• Possível enfileirar mais que um comando para fazer 
uma renderização em múltiplos passos 
• Podemos ser notificados através de blocos quando 
o comando terminar sua execução
Command Encoder 
• Configura um comando para um command buffer 
• Podemos criar 4 tipos de comandos: 
• Render: um passo de renderização, para desenhar algo na 
tela ou numa textura 
• Compute: permite usar a GPU para fazer cálculos de 
propósito geral (GPGPU) 
• Blit: operações de cópia de memória entre buffers e texturas 
• Parallel: permite codificar vários comandos em múltiplas 
threads
Buffer 
• Representa um buffer de memória que pode ser 
usado pela GPU 
• Pode conter qualquer coisa 
• Por exemplo, utilizamos buffers para armazenar 
vértices (vertex buffers) que formam os triângulos 
que queremos desenhar, matrizes de 
transformação, e dados de iluminação
Texture 
• Representa uma imagem que pode ser utilizada 
pela GPU 
• Pode ser usada para desenhar o conteúdo da 
imagem na tela ou como destino para o resultado 
de uma renderização (render to target) 
• Pode ter uma, duas ou três dimensões
Function 
• Representa um shader 
• Vertex shader 
• Fragment shader 
• Compute kernel 
• Função que é executada diretamente na GPU 
(programmable pipeline) 
• Deve ser escrita usando a Metal Shading Language, 
linguagem baseada no C++11
Pipeline 
• Configura as partes fixas do pipeline gráfico, e.g. 
blending e antialiasing 
• Especifica quais functions devem ser usadas 
• Descreve o formato de dados dos vértices 
• Um command encoder deve especificar o pipeline 
que deve ser utilizado em sua execução
Pipeline
Metal Objects
Criando um Projeto 
• Single View Application
Criando um Projeto 
• Adicionar frameworks
Criando um Projeto 
• Metal.framework e QuartzCore.framework
Criando um Projeto 
• Criar um shader (Metal File)
Codificando… 
• Renomeie o arquivo ViewController.m para 
ViewController.mm para que o compilador o 
interprete como um arquivo do tipo Objective-C++ 
• Assim podemos utilizar o simd.h que possui 
definições de tipos de dados vetoriais como float2, 
float3, float4, float3x3… 
• Bastante útil para declarar a estrutura de dados 
dos vértices e fazer cálculos comuns em 
computação gráfica
Codificando… 
• Imports no ViewController.mm: 
! 
#import "ViewController.h" 
! 
#import <Metal/Metal.h> 
#import <QuartzCore/CAMetalLayer.h> 
#import <simd/simd.h>
Codificando… 
• Cada um dos nossos 3 vértices devem ter uma 
posição (x, y) e uma cor (r, g, b, a) 
! 
typedef struct { 
simd::float2 position; 
simd::float4 color; 
} Vertex;
Codificando… 
• Nossas properties 
! 
@interface ViewController () 
! 
@property (nonatomic, strong) id<MTLDevice> device; 
@property (nonatomic, strong) id<MTLBuffer> vertexBuffer; 
@property (nonatomic, strong) id<MTLRenderPipelineState> 
pipeline; 
@property (nonatomic, strong) id<MTLCommandQueue> 
commandQueue; 
@property (nonatomic, strong) CADisplayLink *displayLink; 
@property (nonatomic, strong) CAMetalLayer *metalLayer; 
! 
@end
Codificando… 
• O CADisplayLink é utilizado para chamar nosso 
método de desenho várias vezes por segundo 
• O CAMetalLayer é um CALayer capaz de 
apresentar o conteúdo desenhado pela GPU na 
tela do dispositivo
Codificando… 
• Criando o device e o metalLayer no viewDidLoad 
self.device = MTLCreateSystemDefaultDevice(); 
! 
self.metalLayer = [CAMetalLayer layer];! 
self.metalLayer.device = self.device;! 
self.metalLayer.pixelFormat = 
MTLPixelFormatBGRA8Unorm;! 
self.metalLayer.framebufferOnly = YES;! 
self.metalLayer.frame = self.view.bounds;! 
[self.view.layer addSublayer:self.metalLayer];
Codificando… 
• Criando o vertexBuffer 
Vertex vertices[3]; 
vertices[0].position = { 0, 0.5}; 
vertices[0].color = {1, 0, 0, 1}; 
vertices[1].position = {-0.5, -0.5}; 
vertices[1].color = {0, 1, 0, 1}; 
vertices[2].position = { 0.5, -0.5}; 
vertices[2].color = {0, 0, 1, 1}; 
! 
self.vertexBuffer = [self.device 
newBufferWithBytes:vertices length:sizeof(vertices) 
options:0];
Codificando… 
• Sistema de coordenadas
Codificando… 
• Descrevendo a estrutura dos vértices 
MTLVertexDescriptor *vertexDescriptor = [[MTLVertexDescriptor 
alloc] init]; 
[vertexDescriptor.attributes objectAtIndexedSubscript:0].format = 
MTLVertexFormatFloat2; 
[vertexDescriptor.attributes objectAtIndexedSubscript: 
0].bufferIndex = 0; 
[vertexDescriptor.attributes objectAtIndexedSubscript:0].offset = 
offsetof(Vertex, position); 
[vertexDescriptor.attributes objectAtIndexedSubscript:1].format = 
MTLVertexFormatFloat4; 
[vertexDescriptor.attributes objectAtIndexedSubscript: 
1].bufferIndex = 0; 
[vertexDescriptor.attributes objectAtIndexedSubscript:1].offset = 
offsetof(Vertex, color);
Codificando… 
• Obtendo referências para as funções do nosso 
shader 
id<MTLLibrary> library = [self.device 
newDefaultLibrary]; 
id<MTLFunction> vertexFunction = [library 
newFunctionWithName:@"basic_vertex"]; 
id<MTLFunction> fragmentFunction = [library 
newFunctionWithName:@"basic_fragment"];
Codificando… 
• Criar o pipeline gráfico 
MTLRenderPipelineDescriptor *pipelineDescriptor = 
[[MTLRenderPipelineDescriptor alloc] init]; 
pipelineDescriptor.vertexDescriptor = vertexDescriptor; 
pipelineDescriptor.vertexFunction = vertexFunction; 
pipelineDescriptor.fragmentFunction = fragmentFunction; 
[pipelineDescriptor.colorAttachments 
objectAtIndexedSubscript:0].pixelFormat = 
self.metalLayer.pixelFormat; 
self.pipeline = [self.device 
newRenderPipelineStateWithDescriptor:pipelineDescriptor 
error:nil];
Codificando… 
• Command queue e display link 
self.commandQueue = [self.device newCommandQueue]; 
! 
self.displayLink = [CADisplayLink 
displayLinkWithTarget:self 
selector:@selector(render)]; 
[self.displayLink addToRunLoop:[NSRunLoop 
mainRunLoop] forMode:NSDefaultRunLoopMode];
Codificando… 
• Agora é só renderizar… 
• Em nosso método render, primeiro obtemos o 
drawable do nosso layer que servirá como alvo da 
renderização 
- (void)render 
{ 
id<CAMetalDrawable> drawable = [self.metalLayer 
nextDrawable];
Codificando… 
• Configuramos um render pass descriptor que será 
usado para criar um command encoder 
MTLRenderPassDescriptor *renderPassDescriptor = 
[[MTLRenderPassDescriptor alloc] init]; 
MTLRenderPassColorAttachmentDescriptor 
*colorAttachment = 
[renderPassDescriptor.colorAttachments 
objectAtIndexedSubscript:0]; 
colorAttachment.texture = drawable.texture; 
colorAttachment.loadAction = MTLLoadActionClear; 
colorAttachment.clearColor = MTLClearColorMake(0, 
0.4, 0.02, 1);
Codificando… 
• Criamos um command buffer e em seguida um 
command encoder… 
id<MTLCommandBuffer> commandBuffer = 
[self.commandQueue commandBuffer]; 
id<MTLRenderCommandEncoder> commandEncoder = 
[commandBuffer 
renderCommandEncoderWithDescriptor:renderPassDescri 
ptor];
Codificando… 
• Configuramos o command encoder 
[commandEncoder 
setRenderPipelineState:self.pipeline]; 
[commandEncoder setVertexBuffer:self.vertexBuffer 
offset:0 atIndex:0]; 
[commandEncoder 
drawPrimitives:MTLPrimitiveTypeTriangle 
vertexStart:0 vertexCount:3]; 
[commandEncoder endEncoding];
Codificando… 
• E finalizamos submetendo o command buffer para 
execução 
[commandBuffer presentDrawable:drawable]; 
[commandBuffer commit];
Codificando… 
• Mas ainda faltam os shaders! 
#include <metal_stdlib> 
using namespace metal; 
! 
struct VertexInput { 
float2 position [[attribute(0)]]; 
float4 color [[attribute(1)]]; 
}; 
! 
struct VertexOutput { 
float4 position [[position]]; 
float4 color; 
};
Codificando… 
• Vertex shader 
vertex VertexOutput basic_vertex(VertexInput in 
[[stage_in]]) { 
VertexOutput out; 
out.position = float4(in.position, 0, 1); 
out.color = in.color; 
return out; 
}
Codificando… 
• Fragment shader 
fragment float4 basic_fragment(VertexOutput in 
[[stage_in]]) { 
return in.color; 
}
Codificando… 
• Pronto!
Ferramentas 
• O Xcode 6 possui poderosas ferramentas de 
debugging para o Metal 
• Permite capturar um frame da app e analisar cada 
buffer, textura, comando, etc 
• Facilita encontrar o que pode estar causando 
problemas obscuros como obter uma tela vazia 
após desenhar vários objetos
Ferramentas
Ferramentas
Projeto exemplo 
• https://github.com/xissburg/MetalExamples
Compatibilidade 
• iOS 8 em diante 
• Não funciona no simulador
Compatibilidade
Compatibilidade
Compatibilidade
Conclusões 
• O Metal apresenta uma API concisa e 
relativamente fácil de usar 
• Permite maior controle sobre a GPU 
• Maior performance, low-overhead 
• Compatibilidade ainda limitada 
• Dificulta desenvolvimento cross-platform
Referências 
• Metal Programming Guide - developer.apple.com 
• Metal Shading Language Guide - 
developer.apple.com 
• http://metalbyexample.com 
• iOS 8 Metal Tutorial with Swift: Getting Started - 
raywenderlich.com
Referências 
• Things that drive me nuts about OpenGL - Rich 
Geldreich's Tech Blog 
• OpenGL 4.5 released, next-gen OpenGL unveiled: 
Cross-platform Mantle killer, DX12 competitor
Obrigado pela atenção! 
• Dúvidas? 
• Sugestões? 
• Comentários?

Metal

  • 2.
    Nilson Souto xissburg Venha bater um papo com a galera no IRC @ freenode ;) #iphonedev #iphonedev-chat #swift-lang ##OpenGL …
  • 3.
    Metal? • APIgráfica de baixo nível que apresenta uma abstração muito próxima à arquitetura das GPUs • “bare metal access” • “close to the metal” • Substitui o OpenGL ES • Camada mais fina entre o software e o hardware
  • 4.
    Metal? • Outrastecnologias semelhantes: • AMD Mantle • Microsoft DirectX 12 • OpenGL Next • A ideia é produzir APIs diretamente compatíveis com as arquiteturas das GPUs modernas • Descartar APIs criadas há mais de 20 anos
  • 5.
    Conceitos • Device • Command Queue • Command Buffer • Command Encoder • Buffers • Textures • Functions • Pipeline
  • 6.
    Device • Representaa GPU • Funciona como uma factory para criar command queues, buffers, texturas, etc • Utilizamos a função MTLCreateSystemDefaultDevice para criar uma instância
  • 7.
    Command Queue •Fila de comandos a serem executados pela GPU • Através dela podemos criar command buffers, depois configurá-los e por fim submetê-los para execução
  • 8.
    Command Buffer •Armazena comandos para serem executados pela GPU • Em geral, utilizamos um command buffer para desenhar um frame de uma animação • Possível enfileirar mais que um comando para fazer uma renderização em múltiplos passos • Podemos ser notificados através de blocos quando o comando terminar sua execução
  • 9.
    Command Encoder •Configura um comando para um command buffer • Podemos criar 4 tipos de comandos: • Render: um passo de renderização, para desenhar algo na tela ou numa textura • Compute: permite usar a GPU para fazer cálculos de propósito geral (GPGPU) • Blit: operações de cópia de memória entre buffers e texturas • Parallel: permite codificar vários comandos em múltiplas threads
  • 10.
    Buffer • Representaum buffer de memória que pode ser usado pela GPU • Pode conter qualquer coisa • Por exemplo, utilizamos buffers para armazenar vértices (vertex buffers) que formam os triângulos que queremos desenhar, matrizes de transformação, e dados de iluminação
  • 11.
    Texture • Representauma imagem que pode ser utilizada pela GPU • Pode ser usada para desenhar o conteúdo da imagem na tela ou como destino para o resultado de uma renderização (render to target) • Pode ter uma, duas ou três dimensões
  • 12.
    Function • Representaum shader • Vertex shader • Fragment shader • Compute kernel • Função que é executada diretamente na GPU (programmable pipeline) • Deve ser escrita usando a Metal Shading Language, linguagem baseada no C++11
  • 13.
    Pipeline • Configuraas partes fixas do pipeline gráfico, e.g. blending e antialiasing • Especifica quais functions devem ser usadas • Descreve o formato de dados dos vértices • Um command encoder deve especificar o pipeline que deve ser utilizado em sua execução
  • 14.
  • 15.
  • 16.
    Criando um Projeto • Single View Application
  • 17.
    Criando um Projeto • Adicionar frameworks
  • 18.
    Criando um Projeto • Metal.framework e QuartzCore.framework
  • 19.
    Criando um Projeto • Criar um shader (Metal File)
  • 20.
    Codificando… • Renomeieo arquivo ViewController.m para ViewController.mm para que o compilador o interprete como um arquivo do tipo Objective-C++ • Assim podemos utilizar o simd.h que possui definições de tipos de dados vetoriais como float2, float3, float4, float3x3… • Bastante útil para declarar a estrutura de dados dos vértices e fazer cálculos comuns em computação gráfica
  • 21.
    Codificando… • Importsno ViewController.mm: ! #import "ViewController.h" ! #import <Metal/Metal.h> #import <QuartzCore/CAMetalLayer.h> #import <simd/simd.h>
  • 22.
    Codificando… • Cadaum dos nossos 3 vértices devem ter uma posição (x, y) e uma cor (r, g, b, a) ! typedef struct { simd::float2 position; simd::float4 color; } Vertex;
  • 23.
    Codificando… • Nossasproperties ! @interface ViewController () ! @property (nonatomic, strong) id<MTLDevice> device; @property (nonatomic, strong) id<MTLBuffer> vertexBuffer; @property (nonatomic, strong) id<MTLRenderPipelineState> pipeline; @property (nonatomic, strong) id<MTLCommandQueue> commandQueue; @property (nonatomic, strong) CADisplayLink *displayLink; @property (nonatomic, strong) CAMetalLayer *metalLayer; ! @end
  • 24.
    Codificando… • OCADisplayLink é utilizado para chamar nosso método de desenho várias vezes por segundo • O CAMetalLayer é um CALayer capaz de apresentar o conteúdo desenhado pela GPU na tela do dispositivo
  • 25.
    Codificando… • Criandoo device e o metalLayer no viewDidLoad self.device = MTLCreateSystemDefaultDevice(); ! self.metalLayer = [CAMetalLayer layer];! self.metalLayer.device = self.device;! self.metalLayer.pixelFormat = MTLPixelFormatBGRA8Unorm;! self.metalLayer.framebufferOnly = YES;! self.metalLayer.frame = self.view.bounds;! [self.view.layer addSublayer:self.metalLayer];
  • 26.
    Codificando… • Criandoo vertexBuffer Vertex vertices[3]; vertices[0].position = { 0, 0.5}; vertices[0].color = {1, 0, 0, 1}; vertices[1].position = {-0.5, -0.5}; vertices[1].color = {0, 1, 0, 1}; vertices[2].position = { 0.5, -0.5}; vertices[2].color = {0, 0, 1, 1}; ! self.vertexBuffer = [self.device newBufferWithBytes:vertices length:sizeof(vertices) options:0];
  • 27.
  • 28.
    Codificando… • Descrevendoa estrutura dos vértices MTLVertexDescriptor *vertexDescriptor = [[MTLVertexDescriptor alloc] init]; [vertexDescriptor.attributes objectAtIndexedSubscript:0].format = MTLVertexFormatFloat2; [vertexDescriptor.attributes objectAtIndexedSubscript: 0].bufferIndex = 0; [vertexDescriptor.attributes objectAtIndexedSubscript:0].offset = offsetof(Vertex, position); [vertexDescriptor.attributes objectAtIndexedSubscript:1].format = MTLVertexFormatFloat4; [vertexDescriptor.attributes objectAtIndexedSubscript: 1].bufferIndex = 0; [vertexDescriptor.attributes objectAtIndexedSubscript:1].offset = offsetof(Vertex, color);
  • 29.
    Codificando… • Obtendoreferências para as funções do nosso shader id<MTLLibrary> library = [self.device newDefaultLibrary]; id<MTLFunction> vertexFunction = [library newFunctionWithName:@"basic_vertex"]; id<MTLFunction> fragmentFunction = [library newFunctionWithName:@"basic_fragment"];
  • 30.
    Codificando… • Criaro pipeline gráfico MTLRenderPipelineDescriptor *pipelineDescriptor = [[MTLRenderPipelineDescriptor alloc] init]; pipelineDescriptor.vertexDescriptor = vertexDescriptor; pipelineDescriptor.vertexFunction = vertexFunction; pipelineDescriptor.fragmentFunction = fragmentFunction; [pipelineDescriptor.colorAttachments objectAtIndexedSubscript:0].pixelFormat = self.metalLayer.pixelFormat; self.pipeline = [self.device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:nil];
  • 31.
    Codificando… • Commandqueue e display link self.commandQueue = [self.device newCommandQueue]; ! self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(render)]; [self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
  • 32.
    Codificando… • Agoraé só renderizar… • Em nosso método render, primeiro obtemos o drawable do nosso layer que servirá como alvo da renderização - (void)render { id<CAMetalDrawable> drawable = [self.metalLayer nextDrawable];
  • 33.
    Codificando… • Configuramosum render pass descriptor que será usado para criar um command encoder MTLRenderPassDescriptor *renderPassDescriptor = [[MTLRenderPassDescriptor alloc] init]; MTLRenderPassColorAttachmentDescriptor *colorAttachment = [renderPassDescriptor.colorAttachments objectAtIndexedSubscript:0]; colorAttachment.texture = drawable.texture; colorAttachment.loadAction = MTLLoadActionClear; colorAttachment.clearColor = MTLClearColorMake(0, 0.4, 0.02, 1);
  • 34.
    Codificando… • Criamosum command buffer e em seguida um command encoder… id<MTLCommandBuffer> commandBuffer = [self.commandQueue commandBuffer]; id<MTLRenderCommandEncoder> commandEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescri ptor];
  • 35.
    Codificando… • Configuramoso command encoder [commandEncoder setRenderPipelineState:self.pipeline]; [commandEncoder setVertexBuffer:self.vertexBuffer offset:0 atIndex:0]; [commandEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3]; [commandEncoder endEncoding];
  • 36.
    Codificando… • Efinalizamos submetendo o command buffer para execução [commandBuffer presentDrawable:drawable]; [commandBuffer commit];
  • 37.
    Codificando… • Masainda faltam os shaders! #include <metal_stdlib> using namespace metal; ! struct VertexInput { float2 position [[attribute(0)]]; float4 color [[attribute(1)]]; }; ! struct VertexOutput { float4 position [[position]]; float4 color; };
  • 38.
    Codificando… • Vertexshader vertex VertexOutput basic_vertex(VertexInput in [[stage_in]]) { VertexOutput out; out.position = float4(in.position, 0, 1); out.color = in.color; return out; }
  • 39.
    Codificando… • Fragmentshader fragment float4 basic_fragment(VertexOutput in [[stage_in]]) { return in.color; }
  • 40.
  • 41.
    Ferramentas • OXcode 6 possui poderosas ferramentas de debugging para o Metal • Permite capturar um frame da app e analisar cada buffer, textura, comando, etc • Facilita encontrar o que pode estar causando problemas obscuros como obter uma tela vazia após desenhar vários objetos
  • 42.
  • 43.
  • 44.
    Projeto exemplo •https://github.com/xissburg/MetalExamples
  • 45.
    Compatibilidade • iOS8 em diante • Não funciona no simulador
  • 46.
  • 47.
  • 48.
  • 49.
    Conclusões • OMetal apresenta uma API concisa e relativamente fácil de usar • Permite maior controle sobre a GPU • Maior performance, low-overhead • Compatibilidade ainda limitada • Dificulta desenvolvimento cross-platform
  • 50.
    Referências • MetalProgramming Guide - developer.apple.com • Metal Shading Language Guide - developer.apple.com • http://metalbyexample.com • iOS 8 Metal Tutorial with Swift: Getting Started - raywenderlich.com
  • 51.
    Referências • Thingsthat drive me nuts about OpenGL - Rich Geldreich's Tech Blog • OpenGL 4.5 released, next-gen OpenGL unveiled: Cross-platform Mantle killer, DX12 competitor
  • 52.
    Obrigado pela atenção! • Dúvidas? • Sugestões? • Comentários?