Uma estrutura de processamento de imagem baseada no metal.
MTIImageMTIImageMTIImageCVPixelBufferSwiftAppleSilicon da subidaO MetalPetal é uma estrutura de processamento de imagem baseada em metal projetado para fornecer processamento em tempo real para imagens e vídeos estáticos com interfaces de programação fáceis de usar.
Este capítulo abrange os principais conceitos de metaltetal e ajudará você a entender melhor seu design, implementação, implicações de desempenho e práticas recomendadas.
O Metalpettal foi projetado com os seguintes objetivos em mente.
API fácil de usar
Fornece APIs de conveniência e evita armadilhas comuns.
Desempenho
Use CPU, GPU e memória com eficiência.
Extensibilidade
Fácil de criar filtros personalizados, bem como plug -in sua unidade de processamento de imagem personalizada.
Swifty
Fornece uma experiência fluida para programadores rápidos.
Alguns dos principais conceitos de metalpettal são muito semelhantes aos da estrutura de imagem principal da Apple.
Fornece um contexto de avaliação para renderizar MTIImage s. Ele também armazena muitos caches e informações de estado, por isso é mais eficiente reutilizar um contexto sempre que possível.
Um objeto MTIImage é uma representação de uma imagem a ser processada ou produzida. Ele representa diretamente dados de bitmap de imagem, em vez disso, possui todas as informações necessárias para produzir uma imagem ou mais precisamente uma MTLTexture . Consiste em duas partes, uma receita de como produzir a textura ( MTIImagePromise ) e outras informações, como como um contexto armazena em cache a imagem ( cachePolicy ) e como a textura deve ser amostrada ( samplerDescriptor ).
Um MTIFilter representa um efeito de processamento de imagem e quaisquer parâmetros que controlem esse efeito. Produz um objeto MTIImage como saída. Para usar um filtro, você cria um objeto de filtro, define suas imagens e parâmetros de entrada e acessa sua imagem de saída. Normalmente, uma classe de filtro possui um kernel estático ( MTIKernel ), quando você acessa sua propriedade outputImage , ele pede ao kernel com as imagens de entrada e os parâmetros para produzir um MTIImage de saída.
Um MTIKernel representa uma rotina de processamento de imagem. MTIKernel é responsável por criar o estado de renderização ou computação de computação correspondente para o filtro, além de criar o MTIImagePromise para um MTIImage .
O Metalpettal faz muitas otimizações para você sob o capô.
Ele armazena em cache automaticamente as funções, os estados do kernel, os estados do amostrador etc.
Ele utiliza recursos de metal como mistura programável, alvos de renderização sem memória, montes de recursos e shaders de desempenho de metal para tornar a renderização rápida e eficiente. No MacOS, o Metalpetal também pode aproveitar a arquitetura TBDR do Apple Silicon.
Antes de renderizar, o Metalpettal pode examinar seu gráfico de renderização de imagem e descobrir o número mínimo de texturas intermediárias necessárias para fazer a renderização, salvar memória, energia e tempo.
Ele também pode reorganizar o gráfico de renderização da imagem se várias “receitas” puderem ser concatenadas para eliminar passes de renderização redundantes. ( MTIContext.isRenderGraphOptimizationEnabled )
Os objetos MTIImage são imutáveis, o que significa que eles podem ser compartilhados com segurança entre os threads.
No entanto, os objetos MTIFilter são mutáveis e, portanto, não podem ser compartilhados com segurança entre os threads.
Um MTIContext contém muitos estados e caches. Há um mecanismo seguro para objetos MTIContext , tornando seguro compartilhar um objeto MTIContext entre os threads.
Funções totalmente personalizáveis de vértice e fragmento.
Suporte ao MRT (vários alvos de renderização).
Geralmente melhor desempenho. (Dados detalhados de referência necessários)
Matriz colorida
Pesquisa de cores
Usa uma tabela de pesquisa de cores para remapear as cores em uma imagem.
Opacidade
Exposição
Saturação
Brilho
Contraste
Cor invertida
Vibração
Ajusta a saturação de uma imagem, mantendo tons de pele agradáveis.
Curva de tom RGB
Modos de mistura
Misture com máscara
Transformar
Cortar
Pixellaado
Composto multicamada
Convolução dos MPS
MPS Gaussian Blur
Definição de MPS
MPS Sobel
Máscara de MPS nombarp
MPS Box Blur
Alto suavização da pele
Clahe (equalização do histograma adaptativo limitado por contraste)
Lente Blur (bokeh hexagonal Blur)
Blur da superfície
Distorção protuberante
Mistura de chave Chroma
Calão de cores
Tela de ponto
Canto redondo (curva circular/contínua)
Todos os filtros de imagem principais
MTIImage Você pode criar um objeto MTIImage a partir de quase qualquer fonte de dados de imagem, incluindo:
URL referenciando arquivos de imagem a serem carregadosCVImageBufferRef ou CVPixelBufferRef )CIImage da imagem centralMDLTexture let imageFromCGImage = MTIImage ( cgImage : cgImage , isOpaque : true )
let imageFromCIImage = MTIImage ( ciImage : ciImage )
let imageFromCoreVideoPixelBuffer = MTIImage ( cvPixelBuffer : pixelBuffer , alphaType : . alphaIsOne )
let imageFromContentsOfURL = MTIImage ( contentsOf : url )
// unpremultiply alpha if needed
let unpremultipliedAlphaImage = image . unpremultiplyingAlpha ( ) let inputImage = ...
let filter = MTISaturationFilter ( )
filter . saturation = 0
filter . inputImage = inputImage
let outputImage = filter . outputImageMTIImage let options = MTIContextOptions ( )
guard let device = MTLCreateSystemDefaultDevice ( ) , let context = try ? MTIContext ( device : device , options : options ) else {
return
}
let image : MTIImage = ...
do {
try context . render ( image , to : pixelBuffer )
//context.makeCIImage(from: image)
//context.makeCGImage(from: image)
} catch {
print ( error )
}MTIImage let imageView = MTIImageView ( frame : self . view . bounds )
// You can optionally assign a `MTIContext` to the image view. If no context is assigned and `automaticallyCreatesContext` is set to `true` (the default value), a `MTIContext` is created automatically when the image view renders its content.
imageView . context = ...
imageView . image = image Se você quiser mover o processo de codificação do comando GPU para fora do thread principal, você pode usar um MTIThreadSafeImageView . Você pode atribuir um MTIImage a um MTIThreadSafeImageView em qualquer thread.
O Metalpettal possui uma API SWIFT segura para o tipo de conexão. Você pode usar => operador na função FilterGraph.makeImage para conectar filtros e obter a imagem de saída.
Aqui estão alguns exemplos:
let image = try ? FilterGraph . makeImage { output in
inputImage => saturationFilter => exposureFilter => output
} let image = try ? FilterGraph . makeImage { output in
inputImage => saturationFilter => exposureFilter => contrastFilter => blendFilter . inputPorts . inputImage
exposureFilter => blendFilter . inputPorts . inputBackgroundImage
blendFilter => output
} Você pode conectar filtros unários ( MTIUnaryFilter ) diretamente usando => .
Para um filtro com várias entradas, você precisa se conectar a um de seus inputPorts .
=> O operador funciona apenas no método FilterGraph.makeImage .
Uma e apenas um filtro de um filtro pode ser conectada à output .
Trabalhando com AVPlayer :
let context = try MTIContext ( device : device )
let asset = AVAsset ( url : videoURL )
let composition = MTIVideoComposition ( asset : asset , context : context , queue : DispatchQueue . main , filter : { request in
return FilterGraph . makeImage { output in
request . anySourceImage! => filterA => filterB => output
} !
}
let playerItem = AVPlayerItem ( asset : asset )
playerItem . videoComposition = composition . makeAVVideoComposition ( )
player . replaceCurrentItem ( with : playerItem )
player . play ( )Exportar um vídeo:
Videoio é necessário para os seguintes exemplos.
import VideoIO
var configuration = AssetExportSession . Configuration ( fileType : . mp4 , videoSettings : . h264 ( videoSize : composition . renderSize ) , audioSettings : . aac ( channels : 2 , sampleRate : 44100 , bitRate : 128 * 1000 ) )
configuration . videoComposition = composition . makeAVVideoComposition ( )
self . exporter = try ! AssetExportSession ( asset : asset , outputURL : outputURL , configuration : configuration )
exporter . export ( progress : { progress in
} , completion : { error in
} )Videoio é necessário para este exemplo.
import VideoIO
// Setup Image View
let imageView = MTIImageView ( frame : self . view . bounds )
...
// Setup Camera
let camera = Camera ( captureSessionPreset : . hd1920x1080 , configurator : . portraitFrontMirroredVideoOutput )
try camera . enableVideoDataOutput ( on : DispatchQueue . main , delegate : self )
camera . videoDataOutput ? . videoSettings = [ kCVPixelBufferPixelFormatTypeKey as String : kCVPixelFormatType_420YpCbCr8BiPlanarFullRange ]
...
// AVCaptureVideoDataOutputSampleBufferDelegate
let filter = MTIColorInvertFilter ( )
func captureOutput ( _ output : AVCaptureOutput , didOutput sampleBuffer : CMSampleBuffer , from connection : AVCaptureConnection ) {
guard let pixelBuffer = CMSampleBufferGetImageBuffer ( sampleBuffer ) else {
return
}
let inputImage = MTIImage ( cvPixelBuffer : pixelBuffer , alphaType : . alphaIsOne )
filter . inputImage = inputImage
self . imageView . image = filter . outputImage
} Consulte o CameraFilterView.swift no projeto de exemplo para obter mais informações sobre visualização e gravação de vídeo ao vivo filtrado.
Reutilize um MTIContext sempre que possível.
Os contextos são objetos pesados; portanto, se você criar um, faça -o o mais cedo possível e reutilize -o cada vez que precisar renderizar uma imagem.
Use MTIImage.cachePolicy sabiamente.
Use MTIImageCachePolicyTransient quando você não deseja preservar o resultado da renderização de uma imagem, por exemplo, quando a imagem é apenas um resultado intermediário em uma cadeia de filtro, para que a textura subjacente do resultado da renderização possa ser reutilizada. É a opção mais eficiente da memória. No entanto, quando você pede ao contexto que renderize uma imagem renderizada anteriormente, ela pode renderizar essa imagem, pois sua textura subjacente foi reutilizada.
Por padrão, a imagem de saída de um filtro possui a política transient .
Use MTIImageCachePolicyPersistent quando deseja impedir que a textura subjacente seja reutilizada.
Por padrão, as imagens criadas de fontes externas têm a política persistent .
Entenda que MTIFilter.outputImage é uma propriedade de computação.
Cada vez que você solicita um filtro para sua imagem de saída, o filtro pode fornecer um novo objeto de imagem de saída, mesmo que as entradas sejam idênticas à chamada anterior. Portanto, reutilize imagens de saída sempre que possível.
Por exemplo,
// ╭→ filterB
// filterA ─┤
// ╰→ filterC
//
// filterB and filterC use filterA's output as their input.Nesta situação, a seguinte solução:
let filterOutputImage = filterA . outputImage
filterB . inputImage = filterOutputImage
filterC . inputImage = filterOutputImageé melhor do que:
filterB . inputImage = filterA . outputImage
filterC . inputImage = filterA . outputImage Se você deseja incluir o MTIShaderLib.h no seu arquivo .metal , precisará adicionar o caminho do arquivo MTIShaderLib.h à configuração do Metal Compiler - Header Search Paths ( MTL_HEADER_SEARCH_PATHS ).
Por exemplo, se você usar Cocoapods, poderá definir o MTL_HEADER_SEARCH_PATHS como ${PODS_CONFIGURATION_BUILD_DIR}/MetalPetal/MetalPetal.framework/Headers ou ${PODS_ROOT}/MetalPetal/Frameworks/MetalPetal/Shaders Se você usar o Swift Package Manager, defina o MTL_HEADER_SEARCH_PATHS como $(HEADER_SEARCH_PATHS)
O Metalpettal possui um mecanismo interno para codificar argumentos de função do shader para você. Você pode passar os argumentos da função do shader como name: value para o MTIRenderPipelineKernel.apply(toInputImages:parameters:outputDescriptors:) , MTIRenderCommand(kernel:geometry:images:parameters:) , etc.
Por exemplo, o dicionário de parâmetro para a função metal vibranceAdjust pode ser:
// Swift
let amount : Float = 1.0
let vibranceVector = float4 ( 1 , 1 , 1 , 1 )
let parameters = [ " amount " : amount ,
" vibranceVector " : MTIVector ( value : vibranceVector ) ,
" avoidsSaturatingSkinTones " : true ,
" grayColorTransform " : MTIVector ( value : float3 ( 0 , 0 , 0 ) ) ] // vibranceAdjust metal function
fragment float4 vibranceAdjust (...,
constant float & amount [[ buffer( 0 ) ]],
constant float4 & vibranceVector [[ buffer( 1 ) ]],
constant bool & avoidsSaturatingSkinTones [[ buffer( 2 ) ]],
constant float3 & grayColorTransform [[ buffer( 3 ) ]])
{
...
}
Os tipos de argumento da função do shader e os tipos correspondentes a serem usados em um dicionário de parâmetros estão listados abaixo.
| Tipo de argumento da função shader | Swift | Objective-C |
|---|---|---|
| flutuador | Flutuador | flutuador |
| int | Int32 | int |
| uint | Uint32 | uint |
| bool | Bool | bool |
| Simd (float2, float4, float4x4, int4, etc.) | Simd (com MetalPetal/Swift ) / mtivector | Mtivector |
| estrutura | Dados / mtidatabuffer | Nsdata / mtidatabuffer |
| outro (flutuação *, struct *, etc.) imutável | Dados / mtidatabuffer | Nsdata / mtidatabuffer |
| outro (flutuação *, struct *, etc.) mutável | Mtidatabuffer | Mtidatabuffer |
Para construir um filtro unário personalizado, você pode subclasse MTIUnaryImageRenderingFilter e substituir os métodos na categoria SubclassingHooks . Exemplos: MTIPixellateFilter , MTIVibranceFilter , MTIUnpremultiplyAlphaFilter , MTIPremultiplyAlphaFilter , etc.
// Objective-C
@interface MTIPixellateFilter : MTIUnaryImageRenderingFilter
@property ( nonatomic ) float fractionalWidthOfAPixel;
@end
@implementation MTIPixellateFilter
- ( instancetype ) init {
if (self = [ super init ]) {
_fractionalWidthOfAPixel = 0.05 ;
}
return self;
}
+ (MTIFunctionDescriptor *) fragmentFunctionDescriptor {
return [[MTIFunctionDescriptor alloc ] initWithName: @" pixellateEffect " libraryURL: [bundle URLForResource: @" default " withExtension: @" metallib " ]];
}
- ( NSDictionary <NSString *,id> *) parameters {
return @{ @" fractionalWidthOfAPixel " : @(self. fractionalWidthOfAPixel )};
}
@end //Swift
class MTIPixellateFilter : MTIUnaryImageRenderingFilter {
var fractionalWidthOfAPixel : Float = 0.05
override var parameters : [ String : Any ] {
return [ " fractionalWidthOfAPixel " : fractionalWidthOfAPixel ]
}
override class func fragmentFunctionDescriptor ( ) -> MTIFunctionDescriptor {
return MTIFunctionDescriptor ( name : " pixellateEffect " , libraryURL : MTIDefaultLibraryURLForBundle ( Bundle . main ) )
}
} Para criar filtros mais complexos, tudo o que você precisa fazer é criar um kernel ( MTIRenderPipelineKernel / MTIComputePipelineKernel / MTIMPSKernel ), aplique o kernel à (s) imagem (s) de entrada. Exemplos: MTIChromaKeyBlendFilter , MTIBlendWithMaskFilter , MTIColorLookupFilter , etc.
@interface MTIChromaKeyBlendFilter : NSObject <MTIFilter>
@property ( nonatomic , strong , nullable ) MTIImage *inputImage;
@property ( nonatomic , strong , nullable ) MTIImage *inputBackgroundImage;
@property ( nonatomic ) float thresholdSensitivity;
@property ( nonatomic ) float smoothing;
@property ( nonatomic ) MTIColor color;
@end
@implementation MTIChromaKeyBlendFilter
@synthesize outputPixelFormat = _outputPixelFormat;
+ (MTIRenderPipelineKernel *) kernel {
static MTIRenderPipelineKernel *kernel;
static dispatch_once_t onceToken;
dispatch_once (&onceToken, ^{
kernel = [[MTIRenderPipelineKernel alloc ] initWithVertexFunctionDescriptor: [[MTIFunctionDescriptor alloc ] initWithName: MTIFilterPassthroughVertexFunctionName] fragmentFunctionDescriptor: [[MTIFunctionDescriptor alloc ] initWithName: @" chromaKeyBlend " ]];
});
return kernel;
}
- ( instancetype ) init {
if (self = [ super init ]) {
_thresholdSensitivity = 0.4 ;
_smoothing = 0.1 ;
_color = MTIColorMake ( 0.0 , 1.0 , 0.0 , 1.0 );
}
return self;
}
- (MTIImage *) outputImage {
if (!self. inputImage || !self. inputBackgroundImage ) {
return nil ;
}
return [ self .class.kernel applyToInputImages: @[ self .inputImage, self .inputBackgroundImage]
parameters: @{ @" color " : [MTIVector vectorWithFloat4: (simd_float4){self. color . red , self. color . green , self. color . blue ,self. color . alpha }],
@" thresholdSensitivity " : @(self. thresholdSensitivity ),
@" smoothing " : @(self. smoothing )}
outputTextureDimensions: MTITextureDimensionsMake2DFromCGSize ( self .inputImage.size)
outputPixelFormat: self .outputPixelFormat];
}
@end Você pode usar MTIRenderCommand para emitir várias chamadas em um passe de renderização.
// Create a draw call with kernelA, geometryA, and imageA.
let renderCommandA = MTIRenderCommand ( kernel : self . kernelA , geometry : self . geometryA , images : [ imageA ] , parameters : [ : ] )
// Create a draw call with kernelB, geometryB, and imageB.
let renderCommandB = MTIRenderCommand ( kernel : self . kernelB , geometry : self . geometryB , images : [ imageB ] , parameters : [ : ] )
// Create an output descriptor
let outputDescriptor = MTIRenderPassOutputDescriptor ( dimensions : MTITextureDimensions ( width : outputWidth , height : outputHeight , depth : 1 ) , pixelFormat : . bgra8Unorm , loadAction : . clear , storeAction : . store )
// Get the output images, the output image count is equal to the output descriptor count.
let images = MTIRenderCommand . images ( byPerforming : [ renderCommandA , renderCommandB ] , outputDescriptors : [ outputDescriptor ] )Você também pode criar vários descritores de saída para produzir várias imagens em um passe de renderização (MRT, consulte https://en.wikipedia.org/wiki/multiple_render_targets).
Quando MTIVertex não pode atender às suas necessidades, você pode implementar o protocolo MTIGeometry para fornecer seus dados de vértice personalizados ao codificador de comando.
Use a API MTIRenderCommand para emitir chamadas e passe sua MTIGeometry personalizada.
Em cenários raros, você pode acessar diretamente a textura subjacente, usar vários kernels de MPS em um passe de renderização, fazer a renderização em 3D ou codificar os comandos de renderização.
O protocolo MTIImagePromise fornece acesso direto à textura subjacente e ao contexto de renderização para uma etapa no metalpettal.
Você pode criar novas fontes de entrada ou unidades de processamento totalmente personalizadas implementando o protocolo MTIImagePromise . Você precisará importar um módulo adicional para fazê -lo.
Objective-C
@import MetalPetal.Extension;
Swift
// CocoaPods
import MetalPetal.Extension
// Swift Package Manager
import MetalPetalObjectiveC.Extension
Consulte a implementação do MTIComputePipelineKernel , MTICLAHELUTRecipe ou MTIImage , por exemplo.
Se um canal alfa for usado em uma imagem, existem duas representações comuns disponíveis: alfa não multiplicadas (retas/não associadas) e alfa pré -multiplicada (associada).
Com alfa não multiplicado, os componentes RGB representam a cor do pixel, desconsiderando sua opacidade.
Com o alfa pré -multipicado, os componentes RGB representam a cor do pixel, ajustados por sua opacidade por multiplicação.
Metalpettal lida com o tipo alfa explicitamente. Você é responsável por fornecer o tipo alfa correto durante a criação da imagem.
Existem três tipos de alfa em metaltetal.
MTIAlphaType.nonPremultiplied : O valor alfa na imagem não é pré -multiplicado.
MTIAlphaType.premultiplied : O valor alfa na imagem é pré -multiplicado.
MTIAlphaType.alphaIsOne : não há canal alfa na imagem ou a imagem é opaca.
Normalmente, os objetos CGImage , CVPixelBuffer e CIImage têm canais alfa pré -multiplicados. MTIAlphaType.alphaIsOne é fortemente recomendado se a imagem for opaca, por exemplo, um CVPixelBuffer do feed da câmera ou um CGImage carregado de um arquivo jpg .
Você pode chamar unpremultiplyingAlpha() ou premultiplyingAlpha() em um MTIImage para converter o tipo alfa da imagem.
Por razões de desempenho, a validação do tipo alfa ocorre apenas na construção de depuração.
A maioria dos filtros em metaltetal aceita imagens alfa e opacas não multiplicadas e imagens alfa não multiplicadas.
Os filtros com propriedade de outputAlphaType aceitam entradas de todos os tipos alfa. E você pode usar outputAlphaType para especificar o tipo alfa da imagem de saída.
Por exemplo, MTIBlendFilter , MTIMultilayerCompositingFilter , MTICoreImageUnaryFilter , MTIRGBColorSpaceConversionFilter
Os filtros que na verdade não modificam as cores têm regra de manuseio alfa de passagem, isso significa que os tipos alfa das imagens de saída são iguais com as imagens de entrada.
por exemplo, MTITransformFilter , MTICropFilter , MTIPixellateFilter , MTIBulgeDistortionFilter
Para saber mais sobre os tipos alfa e a composição alfa, consulte este incrível artigo interativo de Bartosz Ciecanowski.
Os espaços de cores são vitais para o processamento da imagem. Os valores numéricos dos componentes vermelhos, verdes e azuis não têm significado sem um espaço de cores.
Antes de continuar como o metalpettal lida com espaços de cores, você pode saber o que é um espaço de cores e como isso afeta a representação dos valores de cores. Existem muitos artigos na web explicando espaços de cores, para começar, a sugestão são espaços de cores - de Bartosz Ciechanowski.
Diferentes softwares e estruturas têm diferentes maneiras de lidar com espaços de cores. Por exemplo, o Photoshop possui um SRGB IC61966-2.1 padrão, enquanto a imagem principal, por padrão, usa espaço de cores lineares de trabalho SRGB.
As texturas de metal não armazenam nenhuma informação no espaço de cores com elas. A maior parte do manuseio do espaço de cores no metalpettal ocorre durante a entrada ( MTIImage(...) ) e a saída ( MTIContext.render... ) dos dados da imagem.
Especificar um espaço de cores para uma entrada significa que o Metalpettal deve converter os valores de cor de origem no espaço de cores especificado durante a criação da textura.
Ao carregar a partir de URL ou CGImage , você pode especificar em qual espaço de cores você deseja que os dados de textura estejam, usando MTICGImageLoadingOptions . Se você não especificar nenhuma opção ao carregar uma imagem, o espaço de cores RGB do dispositivo será usado ( MTICGImageLoadingOptions.default ). Um espaço de cores nil desativa a correspondência de cores, esse é o equivalente ao uso do espaço de cores da imagem de entrada para criar MTICGImageLoadingOptions . Se o modelo do espaço de cores especificado não for RGB, o espaço de cores RGB do dispositivo será usado como substituto.
Ao carregar da CIImage , você pode especificar em qual espaço de cores você deseja que os dados de textura estejam, usando MTICIImageRenderingOptions . Se você não especificar nenhuma opção ao carregar uma CIImage , o espaço de cores RGB do dispositivo será usado ( MTICIImageRenderingOptions.default ). Um espaço de cores nil desativa a correspondência de cores, os valores de cores são carregados no espaço de cores de trabalho do CIContext .
Ao especificar um espaço de cores para uma saída, o espaço de cores serve mais como uma tag que é usada para se comunicar com o restante do sistema sobre como representar os valores de cores na saída. Não há conversão real de espaço de cores realizada.
Você pode especificar o espaço de cores de uma saída CGImage usando MTIContext.makeCGImage... ou MTIContext.startTaskTo... métodos com um parâmetro de colorSpace .
Você pode especificar o espaço de cores de um CIImage de saída usando MTICIImageCreationOptions .
O Metalpettal assume que os valores de cor de saída estão no espaço de cores RGB do dispositivo quando nenhum espaço de cor de saída é especificado.
CVPixelBuffer O MetalPetal usa CVMetalTextureCache e IOSurface para mapear diretamente CVPixelBuffer s para texturas de metal. Portanto, você não pode especificar um espaço de cores para carregar ou renderizar para um CVPixelBuffer . No entanto, você pode especificar se deve usar uma textura com um formato SRGB Pixel para o mapeamento.
No metal, se o nome do formato de pixel tiver o sufixo _sRGB , a compressão e descompressão gama SRGB serão aplicadas durante a leitura e a escrita dos valores de cores no pixel. Isso significa que uma textura com o formato _sRGB Pixel assume que os valores de cor que os armazenamentos são corrigidos por SRGB Gamma, quando os valores de cor são lidos em um shader, as conversões SRGB para RGB linear são realizadas. Quando os valores de cores são gravados em um shader, as conversões lineares RGB para SRGB são realizadas.
Você pode usar MTIRGBColorSpaceConversionFilter para executar conversões de espaço em cores. As funções de conversão de espaço de cores também estão disponíveis no MTIShaderLib.h .
metalpetal::sRGBToLinear (srgb iec61966-2.1 para srgb linear)metalpetal::linearToSRGB (SRGB linear para SRGB IEC61966-2.1)metalpetal::linearToITUR709 (SRGB linear para ITU-R 709)metalpetal::ITUR709ToLinear (ITU-R 709 para SRGB linear) Você pode usar MTISCNSceneRenderer para gerar MTIImage s a partir de uma SCNScene . Você pode lidar com o espaço de cores RGB linear do renderizador Scenekit, consulte a edição #76 A imagem do SceneKit é mais escura que o normal.
Você pode usar MTISKSceneRenderer para gerar MTIImage s a partir de uma SKScene .
Você pode criar MTIImage s a partir de CIImage s.
Você pode renderizar um MTIImage a uma CIImage usando um MTIContext .
Você pode usar um CIFilter diretamente com MTICoreImageKernel ou a classe MTICoreImageUnaryFilter . (Somente Swift)
Veja Metalpetaljs
Com o MetalPetalJS, você pode criar pipelines e filtros de renderização usando JavaScript, possibilitando o download de seus filtros/renderizadores de "The Cloud".
Recomenda -se que você use APIs que aceitam MTICGImageLoadingOptions para carregar CGImage S e imagens do URL , em vez de usar APIs que aceitam MTKTextureLoaderOption .
Quando você usa APIs que aceitam MTKTextureLoaderOption , Metalpettal, por padrão, usa MTIDefaultTextureLoader para carregar CGImage s, imagens de URL e imagens nomeadas. MTIDefaultTextureLoader usa MTKTextureLoader internamente e possui algumas soluções alternativas para as inconsistências e bugs do MTKTextureLoader a um pequeno custo de desempenho. Você também pode criar seu próprio carregador de textura implementando o protocolo MTITextureLoader . Em seguida, atribua sua classe de carregador de textura a MTIContextOptions.textureLoaderClass ao criar um MTIContext .
Você pode usar o Cocoapods para instalar a versão mais recente.
use_frameworks!
pod 'MetalPetal'
# Required if you are using Swift.
pod 'MetalPetal/Swift'
# Recommended if you'd like to run MetalPetal on Apple silicon Macs.
pod 'MetalPetal/AppleSilicon'
SwiftFornece adições e modificações específicas para as APIs Objective-C para melhorar seu mapeamento no Swift. Altamente recomendado se você estiver usando o Swift.
AppleSilicon da subidaFornece a biblioteca de shader padrão compilada na linguagem de sombreamento de metal v2.3, necessária para permitir o suporte programável de mistura nos macs de silício Apple.
Adicionando dependências de pacotes ao seu aplicativo
O Metalpettal pode ser executado no simulador com o Xcode 11+ e o MacOS 10.15+.
MetalPerformanceShaders.framework não está disponível no simulador; portanto, os filtros que dependem de MetalPerformanceShaders , como MTIMPSGaussianBlurFilter , MTICLAHEFilter , não funcionam.
O simulador suporta menos recursos ou limites de implementação diferentes do que uma GPU da Apple real. Consulte o desenvolvimento de aplicativos de metal executados no simulador para obter detalhes.
Se você der uma olhada rápida em um MTIImage , ele mostrará o gráfico de imagens que você construiu para produzir essa imagem.

Por que Objective-C?
Obrigado por considerar contribuir com o Metalpettal. Leia nossas diretrizes contribuintes.
Metalpettal é licenciado por MIT. LICENÇA
Os arquivos no diretório /MetalPetalExamples estão licenciados sob uma licença separada. Licença.md
A documentação é licenciada cc-by-4.0.