Un cadre de traitement d'image basé sur le métal.
MTIImageMTIImageMTIImageCVPixelBufferSwiftAppleSiliconMetalPetal est un cadre de traitement d'image basé sur du métal conçu pour fournir un traitement en temps réel pour l'image et la vidéo fixes avec des interfaces de programmation faciles à utiliser.
Ce chapitre couvre les concepts clés de MetalPetal et vous aidera à mieux comprendre sa conception, sa mise en œuvre, ses implications de performance et ses meilleures pratiques.
MetalPetal est conçu en pensant aux objectifs suivants.
API facile à utiliser
Fournit des API de commodité et évite les pièges communs.
Performance
Utilisez efficacement le processeur, le GPU et la mémoire.
Extensibilité
Facile à créer des filtres personnalisés ainsi que le plugin de votre unité de traitement d'image personnalisée.
Pur
Offre une expérience fluide pour les programmeurs rapides.
Certains des concepts de base de MetalPepal sont très similaires à ceux du cadre d'image de base d'Apple.
Fournit un contexte d'évaluation pour rendre MTIImage s. Il stocke également beaucoup de caches et d'informations d'état, il est donc plus efficace de réutiliser un contexte chaque fois que possible.
Un objet MTIImage est une représentation d'une image à traiter ou à produire. Il représente directement les données de bitmap d'image à la place, il dispose de toutes les informations nécessaires pour produire une image ou plus précisément un MTLTexture . Il se compose de deux parties, une recette de la façon de produire la texture ( MTIImagePromise ) et d'autres informations telles que la façon dont un contexte cache l'image ( cachePolicy ), et comment la texture doit être échantillonnée ( samplerDescriptor ).
Un MTIFilter représente un effet de traitement d'image et tout paramètre qui contrôle cet effet. Il produit un objet MTIImage sous forme de sortie. Pour utiliser un filtre, vous créez un objet filtrant, définissez ses images et paramètres d'entrée, puis accédez à son image de sortie. En règle générale, une classe de filtre possède un noyau statique ( MTIKernel ), lorsque vous accédez à sa propriété outputImage , il demande le noyau avec les images et les paramètres d'entrée pour produire un MTIImage de sortie.
Un MTIKernel représente une routine de traitement d'image. MTIKernel est chargé de créer l'état de rendu ou de calcul du pipeline correspondant pour le filtre, ainsi que de construire le MTIImagePromise pour un MTIImage .
MetalPetal fait beaucoup d'optimisations pour vous sous le capot.
Il cache automatiquement les fonctions, les états du noyau, les états d'échantillonneur, etc.
Il utilise des fonctionnalités métalliques telles que le mélange programmable, les cibles de rendu sans mémoire, les tas de ressources et les shaders de performances métalliques pour rendre le rendu rapide et efficace. Sur le macOS, le métalpapé peut également profiter de l'architecture TBDR du silicium Apple.
Avant le rendu, MetalPetal peut examiner votre graphique de rendu d'image et déterminer le nombre minimal de textures intermédiaires nécessaires pour faire le rendu, économiser la mémoire, l'énergie et le temps.
Il peut également réorganiser le graphique de rendu d'image si plusieurs «recettes» peuvent être concaténées pour éliminer les passes de rendu redondantes. ( MTIContext.isRenderGraphOptimizationEnabled )
Les objets MTIImage sont immuables, ce qui signifie qu'ils peuvent être partagés en toute sécurité entre les fils.
Cependant, les objets MTIFilter sont mutables et ne peuvent donc pas être partagés en toute sécurité entre les fils.
Un MTIContext contient beaucoup d'états et de caches. Il y a un mécanisme de sécurité pour les objets MTIContext , ce qui rend sûr un objet MTIContext parmi les threads.
Fonctions de sommet et de fragment entièrement personnalisables.
MRT (plusieurs cibles de rendu).
Généralement de meilleures performances. (Données de référence détaillées nécessaires)
Matrice de couleur
Recherche de couleurs
Utilise une table de recherche de couleurs pour remapper les couleurs d'une image.
Opacité
Exposition
Saturation
Luminosité
Contraste
Couleur inversée
Vibrance
Ajuste la saturation d'une image tout en gardant des tons de peau agréables.
Courbe de tonalité RVB
Modes de mélange
Mélanger avec un masque
Transformer
Recadrer
Pixellate
Composite multicouche
Convolution MPS
MPS Blur Gaussian
Définition des MPS
MPS Sobel
Masque de non-shif
MPS Box Blur
Lissage de la peau à haut passage
Clahe (égalisation de l'histogramme adaptatif limité au contraste)
Lentilles floues (flou bokeh hexagonal)
Blur de surface
Distorsion des renflements
Mélange de clés de chroma
Couleurs
Écran de points
Coin rond (courbe circulaire / continue)
Tous les filtres d'image de base
MTIImage Vous pouvez créer un objet MTIImage à partir de presque toutes les sources de données d'image, notamment:
URL s référence à des fichiers d'image à chargerCVImageBufferRef ou CVPixelBufferRef )CIImage d'image de baseMDLTexture 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 Si vous souhaitez déplacer le processus d'encodage de la commande GPU hors du thread principal, vous pouvez utiliser un MTIThreadSafeImageView . Vous pouvez attribuer un MTIImage à un MTIThreadSafeImageView dans n'importe quel thread.
MetalPetal possède une API Swift en sécurité pour la connexion des filtres. Vous pouvez utiliser => Opérateur dans FilterGraph.makeImage Fonction pour connecter les filtres et obtenir l'image de sortie.
Voici quelques exemples:
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
} Vous pouvez connecter directement les filtres unaires ( MTIUnaryFilter ) en utilisant => .
Pour un filtre avec plusieurs entrées, vous devez vous connecter à l'un de ses inputPorts .
=> L'opérateur ne fonctionne que dans FilterGraph.makeImage Méthode.
Une et une seule sortie d'un filtre peut être connectée à output .
Travailler avec 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 ( )Exporter une vidéo:
VideoIO est requise pour les exemples suivants.
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 est requise pour cet exemple.
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
} Veuillez vous référer à CameraFilterView.swift dans l'exemple de projet pour en savoir plus sur la prévisualisation et l'enregistrement de la vidéo en direct filtrée.
Réutilisez un MTIContext dans la mesure du possible.
Les contextes sont des objets poids lourds, donc si vous en créez un, faites-le le plus tôt possible et réutilisez-le chaque fois que vous devez rendre une image.
Utilisez sagement MTIImage.cachePolicy sagement.
Utilisez MTIImageCachePolicyTransient lorsque vous ne voulez pas préserver le résultat de rendu d'une image, par exemple lorsque l'image n'est qu'un résultat intermédiaire dans une chaîne de filtre, de sorte que la texture sous-jacente du résultat du rendu peut être réutilisée. C'est l'option la plus efficace de mémoire. Cependant, lorsque vous demandez au contexte de rendre une image précédemment rendue, elle peut renvoyer cette image puisque sa texture sous-jacente a été réutilisée.
Par défaut, l'image de sortie d'un filtre a la stratégie transient .
Utilisez MTIImageCachePolicyPersistent lorsque vous souhaitez empêcher la réutilisation de la texture sous-jacente.
Par défaut, les images créées à partir de sources externes ont la politique persistent .
Comprenez que MTIFilter.outputImage est une propriété de calcul.
Chaque fois que vous demandez à un filtre son image de sortie, le filtre peut vous donner un nouvel objet d'image de sortie même si les entrées sont identiques à l'appel précédent. Réutilisez donc les images de sortie chaque fois que possible.
Par exemple,
// ╭→ filterB
// filterA ─┤
// ╰→ filterC
//
// filterB and filterC use filterA's output as their input.Dans cette situation, la solution suivante:
let filterOutputImage = filterA . outputImage
filterB . inputImage = filterOutputImage
filterC . inputImage = filterOutputImageest meilleur que:
filterB . inputImage = filterA . outputImage
filterC . inputImage = filterA . outputImage Si vous souhaitez inclure le MTIShaderLib.h dans votre fichier .metal , vous devez ajouter le chemin du chemin du fichier MTIShaderLib.h au paramètre Metal Compiler - Header Search Paths ( MTL_HEADER_SEARCH_PATHS ).
Par exemple, si vous utilisez des cocoapodes, vous pouvez définir le MTL_HEADER_SEARCH_PATHS sur ${PODS_CONFIGURATION_BUILD_DIR}/MetalPetal/MetalPetal.framework/Headers ou ${PODS_ROOT}/MetalPetal/Frameworks/MetalPetal/Shaders . Si vous utilisez Swift Package Manager, définissez le MTL_HEADER_SEARCH_PATHS sur $(HEADER_SEARCH_PATHS)
MetalPetal a un mécanisme intégré pour coder les arguments de fonction Shader pour vous. Vous pouvez transmettre les arguments de fonction Shader comme name: value aux MTIRenderPipelineKernel.apply(toInputImages:parameters:outputDescriptors:) , MTIRenderCommand(kernel:geometry:images:parameters:) , etc.
Par exemple, le dictionnaire de paramètres pour la fonction de la fonction vibranceAdjust peut être:
// 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 ) ]])
{
...
}
Les types d'arguments de fonction Shader et les types correspondants à utiliser dans un dictionnaire de paramètres sont répertoriés ci-dessous.
| Type d'argument de fonction de shader | Rapide | Objectif-c |
|---|---|---|
| flotter | Flotter | flotter |
| int | Int32 | int |
| uint | Uint32 | uint |
| bool | Bool | bool |
| simd (float2, float4, float4x4, int4, etc.) | SIMD (avec MetalPetal/Swift ) / Mtivector | Mtivector |
| structure | Données / mtidatabuffer | Nsdata / mtidatabuffer |
| Autre (flottant *, struct *, etc.) immuable | Données / mtidatabuffer | Nsdata / mtidatabuffer |
| Autre (flottant *, struct *, etc.) mutable | Mtidatabuffer | Mtidatabuffer |
Pour construire un filtre unary personnalisé, vous pouvez sous-classer MTIUnaryImageRenderingFilter et remplacer les méthodes dans la catégorie SubclassingHooks . Exemples: 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 ) )
}
} Pour construire des filtres plus complexes, il vous suffit de créer un noyau ( MTIRenderPipelineKernel / MTIComputePipelineKernel / MTIMPSKernel ), puis appliquez le noyau à la ou des images d'entrée. Exemples: 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 Vous pouvez utiliser MTIRenderCommand pour publier plusieurs appels de dessin en un seul laissez-passer.
// 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 ] )Vous pouvez également créer plusieurs descripteurs de sortie pour produire plusieurs images dans un seul Pass (MRT, voir https://en.wikipedia.org/wiki/Multiple_render_targets).
Lorsque MTIVertex ne peut pas répondre à vos besoins, vous pouvez implémenter le protocole MTIGeometry pour fournir vos données de sommet personnalisées au codeur de commande.
Utilisez l'API MTIRenderCommand pour émettre des appels de dessin et passer votre MTIGeometry personnalisée.
Dans de rares scénarios, vous voudrez peut-être accéder directement à la texture sous-jacente, utiliser plusieurs noyaux MPS en un seul rendu, faire un rendu 3D ou coder les commandes de rendu vous-même.
Le protocole MTIImagePromise fournit un accès direct à la texture sous-jacente et au contexte de rendu pour une étape dans le métal.
Vous pouvez créer de nouvelles sources d'entrée ou des unités de traitement entièrement personnalisées en implémentant le protocole MTIImagePromise . Vous devrez importer un module supplémentaire pour le faire.
Objectif-c
@import MetalPetal.Extension;
Rapide
// CocoaPods
import MetalPetal.Extension
// Swift Package Manager
import MetalPetalObjectiveC.Extension
Voir la mise en œuvre de MTIComputePipelineKernel , MTICLAHELUTRecipe ou MTIImage par exemple.
Si un canal alpha est utilisé dans une image, il existe deux représentations communes qui sont disponibles: alpha non-délai (droit / non associé), et alpha prémultiplié (associé).
Avec l'alpha sans mesure, les composants RVB représentent la couleur du pixel, sans tenir compte de son opacité.
Avec l'alpha prémultiplied, les composants RVB représentent la couleur du pixel, ajusté pour son opacité par multiplication.
MetalPetal gère explicitement le type alpha. Vous êtes responsable de fournir le type alpha correct pendant la création d'images.
Il existe trois types alpha dans le métal.
MTIAlphaType.nonPremultiplied : La valeur alpha dans l'image n'est pas prémultiplie.
MTIAlphaType.premultiplied : la valeur alpha dans l'image est prémultiplied.
MTIAlphaType.alphaIsOne : il n'y a pas de canal alpha dans l'image ou l'image est opaque.
En règle générale, les objets CGImage , CVPixelBuffer et CIImage ont des canaux alpha prémultipliés. MTIAlphaType.alphaIsOne est fortement recommandé si l'image est opaque, par exemple un CVPixelBuffer à partir de la flux de la caméra ou un CGImage chargé à partir d'un fichier jpg .
Vous pouvez appeler unpremultiplyingAlpha() ou premultiplyingAlpha() sur un MTIImage pour convertir le type alpha de l'image.
Pour des raisons de performance, la validation de type alpha ne se produit que dans la construction de débogage.
La plupart des filtres en métalpapée acceptent des images alpha et opaques sans mesure des images alpha sans mesure.
Les filtres avec la propriété outputAlphaType acceptent les entrées de tous les types alpha. Et vous pouvez utiliser outputAlphaType pour spécifier le type alpha de l'image de sortie.
par exemple MTIBlendFilter , MTIMultilayerCompositingFilter , MTICoreImageUnaryFilter , MTIRGBColorSpaceConversionFilter
Les filtres qui ne modifient pas réellement les couleurs ont une règle de manutention alpha passthrough, ce qui signifie que les types alpha des images de sortie sont les mêmes avec les images d'entrée.
par exemple MTITransformFilter , MTICropFilter , MTIPixellateFilter , MTIBulgeDistortionFilter
Pour en savoir plus sur les types alpha et le compositing alpha, veuillez vous référer à cet incroyable article interactif de Bartosz Ciechanowski.
Les espaces de couleurs sont essentiels pour le traitement d'image. Les valeurs numériques des composants rouges, vertes et bleus n'ont aucune signification sans espace colorimétrique.
Avant de continuer sur la façon dont MetalPetal gère les espaces de couleurs, vous voudrez peut-être savoir ce qu'est un espace colorimétrique et comment il affecte la représentation des valeurs de couleur. Il existe de nombreux articles sur les espaces de couleurs expliquant les bases, pour commencer, la suggestion est les espaces de couleur - par Bartosz Ciechanowski.
Différents logiciels et cadres ont différentes façons de gérer les espaces de couleurs. Par exemple, Photoshop a un SRGB par défaut IEC61966-2.1 Espace colorimétrique de travail, tandis que Core Image, par défaut, utilise l'espace colorimétrique de travail SRGB linéaire.
Les textures métalliques ne stockent aucune information avec eux. La majeure partie de la manipulation des espaces colorimétriques dans le métal metal se produit pendant l'entrée ( MTIImage(...) ) et la sortie ( MTIContext.render... ) des données d'image.
La spécification d'un espace colorimétrique pour une entrée signifie que le métal metal doit convertir les valeurs de couleur de la source en espace colorimétrique spécifié pendant la création de la texture.
Lors du chargement à partir de URL ou CGImage , vous pouvez spécifier l'espace colorimétrique dans lequel vous souhaitez que les données de texture soient, à l'aide de MTICGImageLoadingOptions . Si vous ne spécifiez aucune option lors du chargement d'une image, l'espace colorimétrique RVB de l'appareil est utilisé ( MTICGImageLoadingOptions.default ). Un espace colorimétrique nil désactive la correspondance des couleurs, c'est l'équivalent de l'utilisation de l'espace colorimétrique de l'image d'entrée pour créer MTICGImageLoadingOptions . Si le modèle de l'espace colorimétrique spécifié n'est pas RVB, l'espace colorimétrique RVB de l'appareil est utilisé comme repli.
Lors du chargement à partir de CIImage , vous pouvez spécifier l'espace colorimétrique dans lequel vous souhaitez que les données de texture soient, en utilisant MTICIImageRenderingOptions . Si vous ne spécifiez aucune option lors du chargement d'un CIImage , l'espace colorimétrique RVB de l'appareil est utilisé ( MTICIImageRenderingOptions.default ). Un espace colorimétrique nil désactive la correspondance des couleurs, les valeurs de couleur sont chargées dans l'espace colorimétrique de travail du CIContext .
Lorsque vous spécifiez un espace colorimétrique pour une sortie, l'espace colorimétrique ressemble plus à une balise qui est utilisée pour communiquer avec le reste du système sur la façon de représenter les valeurs de couleur dans la sortie. Il n'y a pas de conversion réelle de l'espace colorimétrique.
Vous pouvez spécifier l'espace colorimétrique d'un CGImage de sortie à l'aide MTIContext.makeCGImage... ou MTIContext.startTaskTo... avec un paramètre colorSpace .
Vous pouvez spécifier l'espace colorimétrique d'une CIImage de sortie à l'aide de MTICIImageCreationOptions .
MetalPetal suppose que les valeurs de couleur de sortie sont dans l'espace colorimétrique RVB de l'appareil lorsqu'aucun espace colorimétrique de sortie n'est spécifié.
CVPixelBuffer MetalPetal utilise CVMetalTextureCache et IOSurface pour cartographier directement CVPixelBuffer S vers des textures métalliques. Vous ne pouvez donc pas spécifier un espace colorimétrique pour charger ou rendre un CVPixelBuffer . Cependant, vous pouvez spécifier si vous devez utiliser une texture avec un format de pixel SRGB pour le mappage.
En métal, si le nom de format de pixel a le suffixe _sRGB , la compression et la décompression gamma SRGB sont appliquées lors de la lecture et de l'écriture des valeurs de couleur dans le pixel. Cela signifie qu'une texture avec le format de pixel _sRGB suppose que les valeurs de couleur qu'il stocke sont corrigées par le gamma SRGB, lorsque les valeurs de couleur sont lues dans un shader, des conversions SRGB à RVB linéaires sont effectuées. Lorsque les valeurs de couleur sont écrites dans un shader, des conversions RVB à SRGB linéaires sont effectuées.
Vous pouvez utiliser MTIRGBColorSpaceConversionFilter pour effectuer des conversions d'espace colorimétrique. Des fonctions de conversion des espaces colorimétriques sont également disponibles dans MTIShaderLib.h .
metalpetal::sRGBToLinear (SRGB IEC61966-2.1 à SRGB linéaire)metalpetal::linearToSRGB (SRGB linéaire à SRGB IEC61966-2.1)metalpetal::linearToITUR709 (SRGB linéaire à l'UIT-R 709)metalpetal::ITUR709ToLinear (UTU-R 709 à SRGB linéaire) Vous pouvez utiliser MTISCNSceneRenderer pour générer des MTIImage à partir d'un SCNScene . Vous voudrez peut-être gérer l'espace colorimétrique linéaire RVB du Scenekit Renderer, voir le numéro 76 L'image de SceneKit est plus sombre que la normale.
Vous pouvez utiliser MTISKSceneRenderer pour générer des MTIImage à partir d'un SKScene .
Vous pouvez créer MTIImage à partir de CIImage s.
Vous pouvez rendre un MTIImage à un CIImage à l'aide d'un MTIContext .
Vous pouvez utiliser un CIFilter directement avec MTICoreImageKernel ou la classe MTICoreImageUnaryFilter . (Swift seulement)
Voir MetalPetaljs
Avec MetalPetaljs, vous pouvez créer des pipelines et des filtres de rendu à l'aide de JavaScript, ce qui permet de télécharger vos filtres / rendements à partir de "The Cloud".
Il est recommandé d'utiliser des API qui acceptent MTICGImageLoadingOptions pour charger des CGImage et des images à partir de URL , au lieu d'utiliser des API qui acceptent MTKTextureLoaderOption .
Lorsque vous utilisez des API qui acceptent MTKTextureLoaderOption , MetalPetal, par défaut, utilise MTIDefaultTextureLoader pour charger CGImage , les images de URL et les images nommées. MTIDefaultTextureLoader utilise MTKTextureLoader en interne et a des solutions de contournement pour les incohérences et les bogues de MTKTextureLoader à un petit coût de performance. Vous pouvez également créer votre propre chargeur de texture en implémentant le protocole MTITextureLoader . Attribuez ensuite votre classe de chargeur de texture à MTIContextOptions.textureLoaderClass lors de la création d'un MTIContext .
Vous pouvez utiliser CocoAPods pour installer la dernière version.
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'
SwiftFournit des ajouts et des modifications rapides spécifiques aux API Objectif-C pour améliorer leur mappage en Swift. Hautement recommandé si vous utilisez Swift.
AppleSiliconFournit la bibliothèque de shader par défaut compilée dans le langage d'ombrage en métal v2.3 qui est requise pour activer le support de mélange programmable sur les Mac de silicium Apple.
Ajouter des dépendances de package à votre application
MetalPetal peut fonctionner sur Simulator avec Xcode 11+ et MacOS 10.15+.
MetalPerformanceShaders.framework MetalPerformanceShaders MTIMPSGaussianBlurFilter MTICLAHEFilter
Le simulateur prend en charge moins de fonctionnalités ou des limites de mise en œuvre différentes de celles d'un GPU Apple réel. Voir le développement d'applications métalliques qui s'exécutent dans le simulateur pour les détails.
Si vous jetez un coup d'œil sur un MTIImage , il vous montrera le graphique de l'image que vous avez construit pour produire cette image.

Pourquoi objectif-c?
Merci d'avoir envisagé de contribuer au métal. Veuillez lire nos directives contributives.
Le métalpapé métallique est licencié du MIT. LICENCE
Les fichiers du répertoire /MetalPetalExamples sont autorisés sous une licence distincte. Licence.md
La documentation est sous licence CC-BY-4.0.