กรอบการประมวลผลภาพที่ใช้โลหะ
MTIImageMTIImageMTIImageCVPixelBufferSwiftAppleSiliconMetalPetal เป็นกรอบการประมวลผลภาพที่ใช้โลหะที่ออกแบบมาเพื่อให้การประมวลผลแบบเรียลไทม์สำหรับภาพนิ่งและวิดีโอพร้อมอินเทอร์เฟซการเขียนโปรแกรมที่ใช้งานง่าย
บทนี้ครอบคลุมแนวคิดหลักของ MetalPetal และจะช่วยให้คุณเข้าใจดีขึ้นเกี่ยวกับการออกแบบการใช้งานการใช้งานผลกระทบและแนวทางปฏิบัติที่ดีที่สุด
MetalPetal ได้รับการออกแบบโดยคำนึงถึงเป้าหมายต่อไปนี้
ใช้งานง่าย API
ให้ความสะดวกสบาย APIs และหลีกเลี่ยงข้อผิดพลาดทั่วไป
ผลงาน
ใช้ CPU, GPU และหน่วยความจำอย่างมีประสิทธิภาพ
ความสามารถในการขยายได้
ง่ายต่อการสร้างตัวกรองที่กำหนดเองรวมถึงปลั๊กอินหน่วยประมวลผลภาพที่กำหนดเองของคุณ
น่าเกรงขาม
มอบประสบการณ์ของเหลวสำหรับโปรแกรมเมอร์ที่รวดเร็ว
แนวคิดหลักบางอย่างของ MetalPetal นั้นคล้ายคลึงกับกรอบภาพหลักของ Apple มาก
ให้บริบทการประเมินผลสำหรับการแสดงผล MTIImage s นอกจากนี้ยังเก็บแคชและข้อมูลของรัฐจำนวนมากดังนั้นจึงมีประสิทธิภาพมากขึ้นในการนำบริบทกลับมาใช้ใหม่เมื่อใดก็ตามที่เป็นไปได้
วัตถุ MTIImage เป็นตัวแทนของภาพที่จะประมวลผลหรือผลิต มันแสดงข้อมูลบิตแมปรูปภาพโดยตรงแทนมันมีข้อมูลทั้งหมดที่จำเป็นในการสร้างภาพหรือ MTLTexture ที่แม่นยำยิ่งขึ้น ประกอบด้วยสองส่วนสูตรของวิธีการผลิตพื้นผิว ( MTIImagePromise ) และข้อมูลอื่น ๆ เช่นวิธีการที่บริบทแคชภาพ ( cachePolicy ) และวิธีการสุ่มตัวอย่างพื้นผิว ( samplerDescriptor )
MTIFilter การประมวลผลภาพและพารามิเตอร์ใด ๆ ที่ควบคุมผลกระทบนั้น มันสร้างวัตถุ MTIImage เป็นเอาต์พุต ในการใช้ตัวกรองคุณสร้างวัตถุตัวกรองตั้งค่ารูปภาพอินพุตและพารามิเตอร์จากนั้นเข้าถึงภาพเอาต์พุต โดยทั่วไปคลาสตัวกรองจะเป็นเคอร์เนลแบบคงที่ ( MTIKernel ) เมื่อคุณเข้าถึงคุณสมบัติ outputImage มันจะขอเคอร์เนลด้วยภาพอินพุตและพารามิเตอร์เพื่อสร้างเอาต์พุต MTIImage
MTIKernel แสดงถึงรูทีนการประมวลผลภาพ MTIKernel มีหน้าที่รับผิดชอบในการสร้างการแสดงผลที่สอดคล้องกันหรือการคำนวณสถานะไปป์ไลน์สำหรับตัวกรองเช่นเดียวกับการสร้าง MTIImagePromise สำหรับ MTIImage
MetalPetal ทำการปรับให้เหมาะสมมากสำหรับคุณภายใต้ประทุน
มันแคชฟังก์ชั่นโดยอัตโนมัติสถานะเคอร์เนลสถานะตัวอย่าง ฯลฯ
มันใช้คุณสมบัติโลหะเช่นการผสมที่ตั้งโปรแกรมได้เป้าหมายการเรนเดอร์ที่ไม่มีหน่วยความจำกองทรัพยากรและเฉดสีโลหะเพื่อให้การเรนเดอร์รวดเร็วและมีประสิทธิภาพ บน MacOS MetalPetal ยังสามารถใช้ประโยชน์จากสถาปัตยกรรม TBDR ของ Apple Silicon
ก่อนการเรนเดอร์ MetalPetal สามารถตรวจสอบกราฟการเรนเดอร์ภาพของคุณและหาจำนวนพื้นผิวระดับกลางที่จำเป็นในการแสดงการเรนเดอร์หน่วยความจำพลังงานและเวลา
นอกจากนี้ยังสามารถจัดระเบียบกราฟการเรนเดอร์รูปภาพอีกครั้งหากสามารถต่อ“ สูตร” หลายสูตรเพื่อกำจัดผ่านการเรนเดอร์ซ้ำซ้อน ( MTIContext.isRenderGraphOptimizationEnabled )
วัตถุ MTIImage นั้นไม่เปลี่ยนรูปซึ่งหมายความว่าสามารถใช้ร่วมกันได้อย่างปลอดภัยระหว่างเธรด
อย่างไรก็ตามวัตถุ MTIFilter นั้นไม่แน่นอนและไม่สามารถใช้ร่วมกันได้อย่างปลอดภัยระหว่างเธรด
MTIContext มีรัฐและแคชจำนวนมาก มีกลไกการใช้เธรดที่ปลอดภัยสำหรับวัตถุ MTIContext ทำให้ปลอดภัยที่จะแบ่งปันวัตถุ MTIContext ระหว่างเธรด
ฟังก์ชั่นจุดสุดยอดและส่วนที่ปรับแต่งได้อย่างสมบูรณ์
การสนับสนุน MRT (หลายเป้าหมายการเรนเดอร์)
ประสิทธิภาพที่ดีขึ้นโดยทั่วไป (จำเป็นต้องมีข้อมูลมาตรฐานโดยละเอียด)
เมทริกซ์สี
การค้นหาสี
ใช้ตารางการค้นหาสีเพื่อแมปสีในภาพ
ความทึบแสง
การรับสัมผัสเชื้อ
ความอิ่มตัว
ความสว่าง
ตัดกัน
กลับสี
การสั่นสะเทือน
ปรับความอิ่มตัวของภาพในขณะที่รักษาโทนสีผิวที่น่าพอใจ
เส้นโค้งเสียง RGB
โหมดผสมผสาน
ผสมกับหน้ากาก
เปลี่ยนรูป
พืชผล
พิกเซล
คอมโพสิตหลายชั้น
MPS Convolution
MPS Gaussian Blur
คำจำกัดความของสมาชิกสภาผู้แทนราษฎร
MPS Sobel
MPS Unsharp Mask
MPS Box เบลอ
การทำให้ผิวเรียบสูง
Clahe (การปรับฮิสโตแกรมแบบปรับความคมชัด จำกัด )
เลนส์เบลอ (bokeh blur hexagonal)
พื้นผิวเบลอ
การบิดเบือนนูน
Chroma Key Blend
Halftone สี
หน้าจอจุด
มุมกลม (เส้นโค้งวงกลม/ต่อเนื่อง)
ตัวกรองภาพหลักทั้งหมด
MTIImage คุณสามารถสร้างวัตถุ MTIImage จากแหล่งข้อมูลภาพเกือบทุกชนิดรวมถึง:
URL S การอ้างอิงไฟล์รูปภาพที่จะโหลดCVImageBufferRef หรือ CVPixelBufferRef )CIImageMDLTexture 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 หากคุณต้องการย้ายกระบวนการเข้ารหัสคำสั่ง GPU ออกจากเธรดหลักคุณสามารถใช้ MTIThreadSafeImageView คุณสามารถกำหนด MTIImage ให้กับ MTIThreadSafeImageView ในเธรดใด ๆ
MetalPetal มี API Swift ที่ปลอดภัยสำหรับการเชื่อมต่อตัวกรอง คุณสามารถใช้ => ตัวดำเนินการในฟังก์ชัน FilterGraph.makeImage เพื่อเชื่อมต่อตัวกรองและรับภาพเอาต์พุต
นี่คือตัวอย่างบางส่วน:
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
} คุณสามารถเชื่อมต่อตัวกรอง unary ( MTIUnaryFilter ) โดยตรงโดยใช้ =>
สำหรับตัวกรองที่มีหลายอินพุตคุณต้องเชื่อมต่อกับหนึ่งใน inputPorts
=> ผู้ประกอบการทำงานเฉพาะในวิธีการ FilterGraph.makeImage
เอาต์พุตตัวกรองหนึ่งตัวเท่านั้นสามารถเชื่อมต่อกับ output ได้
ทำงานกับ 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 ( )ส่งออกวิดีโอ:
VIDEAIO เป็นสิ่งจำเป็นสำหรับตัวอย่างต่อไปนี้
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
} )วิดีโอเป็นสิ่งจำเป็นสำหรับตัวอย่างนี้
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
} โปรดดูที่ CameraFilterView.swift ในโครงการตัวอย่างสำหรับข้อมูลเพิ่มเติมเกี่ยวกับการดูตัวอย่างและบันทึกวิดีโอสดที่กรอง
นำ MTIContext กลับมาใช้ใหม่เมื่อใดก็ตามที่เป็นไปได้
บริบทเป็นวัตถุเฮฟวี่เวทดังนั้นหากคุณสร้างหนึ่งให้ทำเร็วที่สุดเท่าที่จะทำได้และนำกลับมาใช้ใหม่ทุกครั้งที่คุณต้องการแสดงภาพ
ใช้ MTIImage.cachePolicy อย่างชาญฉลาด
ใช้ MTIImageCachePolicyTransient เมื่อคุณไม่ต้องการรักษาผลลัพธ์การเรนเดอร์ของภาพตัวอย่างเช่นเมื่อภาพเป็นเพียงผลลัพธ์ระดับกลางในห่วงโซ่ตัวกรองดังนั้นพื้นผิวพื้นฐานของผลลัพธ์การเรนเดอร์สามารถนำกลับมาใช้ใหม่ได้ มันเป็นตัวเลือกที่มีประสิทธิภาพมากที่สุด อย่างไรก็ตามเมื่อคุณขอให้บริบทแสดงภาพที่แสดงผลก่อนหน้านี้มันอาจแสดงภาพนั้นอีกครั้งเนื่องจากพื้นผิวพื้นฐานได้ถูกนำมาใช้ซ้ำ
โดยค่าเริ่มต้นภาพเอาต์พุตของตัวกรองมีนโยบาย transient
ใช้ MTIImageCachePolicyPersistent เมื่อคุณต้องการป้องกันไม่ให้พื้นผิวพื้นฐานถูกนำมาใช้ซ้ำ
โดยค่าเริ่มต้นรูปภาพที่สร้างจากแหล่งภายนอกมีนโยบาย persistent
เข้าใจว่า MTIFilter.outputImage เป็นคุณสมบัติการคำนวณ
ทุกครั้งที่คุณถามตัวกรองสำหรับภาพเอาต์พุตตัวกรองอาจให้วัตถุอิมเมจเอาต์พุตใหม่แม้ว่าอินพุตจะเหมือนกันกับการโทรก่อนหน้า ดังนั้นนำภาพเอาต์พุตกลับมาใช้ใหม่เมื่อเป็นไปได้
ตัวอย่างเช่น,
// ╭→ filterB
// filterA ─┤
// ╰→ filterC
//
// filterB and filterC use filterA's output as their input.ในสถานการณ์นี้วิธีแก้ปัญหาต่อไปนี้:
let filterOutputImage = filterA . outputImage
filterB . inputImage = filterOutputImage
filterC . inputImage = filterOutputImageดีกว่า:
filterB . inputImage = filterA . outputImage
filterC . inputImage = filterA . outputImage หากคุณต้องการรวม MTIShaderLib.h ในไฟล์ .metal ของคุณคุณจะต้องเพิ่มพา ธ ของไฟล์ MTIShaderLib.h ไปยัง Metal Compiler - Header Search Paths ( MTL_HEADER_SEARCH_PATHS )
ตัวอย่างเช่นหากคุณใช้ cocoapods คุณสามารถตั้งค่า MTL_HEADER_SEARCH_PATHS เป็น ${PODS_CONFIGURATION_BUILD_DIR}/MetalPetal/MetalPetal.framework/Headers หรือ ${PODS_ROOT}/MetalPetal/Frameworks/MetalPetal/Shaders หากคุณใช้ Swift Package Manager ให้ตั้งค่า MTL_HEADER_SEARCH_PATHS เป็น $(HEADER_SEARCH_PATHS)
MetalPetal มีกลไกในตัวเพื่อเข้ารหัสอาร์กิวเมนต์ฟังก์ชั่น Shader สำหรับคุณ คุณสามารถส่งอาร์กิวเมนต์ฟังก์ชั่น shader เป็น name: value ไปยัง MTIRenderPipelineKernel.apply(toInputImages:parameters:outputDescriptors:) , MTIRenderCommand(kernel:geometry:images:parameters:)
ตัวอย่างเช่นพจนานุกรมพารามิเตอร์สำหรับฟังก์ชั่นโลหะ vibranceAdjust สามารถ:
// 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 ) ]])
{
...
}
ประเภทอาร์กิวเมนต์ฟังก์ชัน Shader และประเภทที่สอดคล้องกันที่จะใช้ในพจนานุกรมพารามิเตอร์แสดงอยู่ด้านล่าง
| ประเภทอาร์กิวเมนต์ฟังก์ชัน shader | ฉับพลัน | วัตถุประสงค์ -C |
|---|---|---|
| ลอย | ลอย | ลอย |
| int | INT32 | int |
| uint | uint32 | uint |
| บูล | บูล | บูล |
| SIMD (float2, float4, float4x4, int4 ฯลฯ ) | SIMD (พร้อม MetalPetal/Swift ) / mtivector | Mtivercector |
| โครงสร้าง | ข้อมูล / mtidatabuffer | NSDATA / MTIDATABUFFER |
| อื่น ๆ (ลอย *, struct *ฯลฯ ) ไม่เปลี่ยนรูป | ข้อมูล / mtidatabuffer | NSDATA / MTIDATABUFFER |
| อื่น ๆ (ลอย *, struct *ฯลฯ ) ที่ไม่แน่นอน | mtidatabuffer | mtidatabuffer |
ในการสร้างตัวกรองที่กำหนดเองคุณสามารถ subclass MTIUnaryImageRenderingFilter และแทนที่วิธีการในหมวดหมู่ SubclassingHooks ตัวอย่าง: MTIPixellateFilter , MTIVibranceFilter , MTIUnpremultiplyAlphaFilter , MTIPremultiplyAlphaFilter ฯลฯ
// 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 ) )
}
} ในการสร้างตัวกรองที่ซับซ้อนมากขึ้นสิ่งที่คุณต้องทำคือสร้างเคอร์เนล ( MTIRenderPipelineKernel / MTIComputePipelineKernel / MTIMPSKernel ) จากนั้นใช้เคอร์เนลกับภาพอินพุต ตัวอย่าง: MTIChromaKeyBlendFilter , MTIBlendWithMaskFilter , MTIColorLookupFilter ฯลฯ
@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 คุณสามารถใช้ MTIRenderCommand เพื่อออกหลายสายการดึงในการแสดงผลเดียว
// 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 ] )นอกจากนี้คุณยังสามารถสร้างตัวบ่งชี้เอาต์พุตหลายตัวเพื่อส่งออกหลายภาพในการเรนเดอร์หนึ่งครั้ง (MRT, ดู https://en.wikipedia.org/wiki/multiple_render_targets)
เมื่อ MTIVertex ไม่สามารถตอบสนองความต้องการของคุณได้คุณสามารถใช้โปรโตคอล MTIGeometry เพื่อให้ข้อมูลจุดสุดยอดที่กำหนดเองของคุณกับตัวเข้ารหัสคำสั่ง
ใช้ MTIRenderCommand API เพื่อออกการดึงสายและส่งผ่าน MTIGeometry ที่กำหนดเองของคุณ
ในสถานการณ์ที่หายากคุณอาจต้องการเข้าถึงพื้นผิวพื้นฐานโดยตรงใช้เคอร์เนล MPS หลายตัวในการเรนเดอร์หนึ่งครั้งทำการเรนเดอร์ 3 มิติหรือเข้ารหัสคำสั่งเรนเดอร์ด้วยตัวเอง
โปรโตคอล MTIImagePromise ให้การเข้าถึงโดยตรงไปยังพื้นผิวพื้นฐานและบริบทการเรนเดอร์สำหรับขั้นตอนใน MetalPetal
คุณสามารถสร้างแหล่งอินพุตใหม่หรือหน่วยประมวลผลที่กำหนดเองได้อย่างสมบูรณ์โดยใช้โปรโตคอล MTIImagePromise คุณจะต้องนำเข้าโมดูลเพิ่มเติมเพื่อทำเช่นนั้น
วัตถุประสงค์ -C
@import MetalPetal.Extension;
ฉับพลัน
// CocoaPods
import MetalPetal.Extension
// Swift Package Manager
import MetalPetalObjectiveC.Extension
ดูการใช้งานของ MTIComputePipelineKernel , MTICLAHELUTRecipe หรือ MTIImage เช่น
หากมีการใช้ช่องอัลฟ่าในภาพมีการแสดงทั่วไปสองรายการที่มีอยู่: อัลฟ่าที่ไม่สมบูรณ์ (ตรง/ไม่เกี่ยวข้อง) และอัลฟ่า premultiplied (เกี่ยวข้อง)
ด้วยอัลฟ่าที่ไม่ได้มีส่วนร่วมส่วนประกอบ RGB แสดงถึงสีของพิกเซลโดยไม่คำนึงถึงความทึบของมัน
ด้วยอัลฟ่า premultiplied ส่วนประกอบ RGB แสดงสีของพิกเซลปรับความทึบของมันโดยการคูณ
Metalpetal จัดการประเภทอัลฟ่าอย่างชัดเจน คุณมีความรับผิดชอบในการจัดหาประเภทอัลฟ่าที่ถูกต้องในระหว่างการสร้างภาพ
มีสามประเภทอัลฟ่าใน MetalPetal
MTIAlphaType.nonPremultiplied : ค่าอัลฟ่าในภาพไม่ได้มีความสมบูรณ์
MTIAlphaType.premultiplied : ค่าอัลฟ่าในภาพเป็น premultiplied
MTIAlphaType.alphaIsOne : ไม่มีช่องอัลฟ่าในภาพหรือภาพทึบแสง
โดยทั่วไปแล้ววัตถุ CGImage , CVPixelBuffer และ CIImage มีช่องอัลฟ่าก่อนกำหนด แนะนำให้ใช้ MTIAlphaType.alphaIsOne อย่างยิ่งหากภาพทึบแสงเช่น CVPixelBuffer จากฟีดกล้องหรือ CGImage ที่โหลดจากไฟล์ jpg
คุณสามารถเรียกได้ unpremultiplyingAlpha() หรือ premultiplyingAlpha() บน MTIImage เพื่อแปลงประเภทอัลฟ่าของภาพ
ด้วยเหตุผลด้านประสิทธิภาพการตรวจสอบประเภทของอัลฟ่าจะเกิดขึ้นในการดีบักบิลด์เท่านั้น
ตัวกรองส่วนใหญ่ใน MetalPetal ยอมรับภาพอัลฟ่าและภาพทึบแสงที่ไม่สมบูรณ์และภาพอัลฟ่าที่ไม่ได้ส่งออก
ตัวกรองที่มีคุณสมบัติ outputAlphaType ยอมรับอินพุตของอัลฟ่าทั้งหมด และคุณสามารถใช้ outputAlphaType เพื่อระบุประเภทอัลฟ่าของภาพเอาต์พุต
เช่น MTIBlendFilter , MTIMultilayerCompositingFilter , MTICoreImageUnaryFilter , MTIRGBColorSpaceConversionFilter
ตัวกรองที่ไม่ได้ปรับเปลี่ยนสีจริงมีกฎการจัดการอัลฟ่าซึ่งหมายความว่าประเภทอัลฟ่าของภาพเอาต์พุตจะเหมือนกันกับภาพอินพุต
เช่น MTITransformFilter , MTICropFilter , MTIPixellateFilter , MTIBulgeDistortionFilter
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับประเภทอัลฟ่าและการแต่งเพลงอัลฟ่าโปรดดูบทความเชิงโต้ตอบที่น่าทึ่งนี้โดย Bartosz Ciechanowski
พื้นที่สีมีความสำคัญสำหรับการประมวลผลภาพ ค่าตัวเลขของส่วนประกอบสีแดงสีเขียวและสีน้ำเงินไม่มีความหมายหากไม่มีพื้นที่สี
ก่อนที่จะดำเนินการต่อเกี่ยวกับวิธีที่ MetalPetal จัดการกับพื้นที่สีคุณอาจต้องการทราบว่าพื้นที่สีคืออะไรและมีผลต่อการเป็นตัวแทนของค่าสีอย่างไร มีบทความมากมายบนเว็บที่อธิบายพื้นที่สีเพื่อเริ่มต้นคำแนะนำคือพื้นที่สี - โดย Bartosz Ciechanowski
ซอฟต์แวร์และเฟรมเวิร์กที่แตกต่างกันมีวิธีการจัดการพื้นที่สีที่แตกต่างกัน ตัวอย่างเช่น Photoshop มี SRGB IEC61966-2.1 พื้นที่ทำงานสีที่ใช้งานได้ในขณะที่ภาพหลักโดยค่าเริ่มต้นใช้พื้นที่ใช้งานสี SRGB เชิงเส้น
พื้นผิวโลหะไม่เก็บข้อมูลพื้นที่สีใด ๆ ไว้กับพวกเขา การจัดการพื้นที่สีส่วนใหญ่ใน MetalPetal เกิดขึ้นระหว่างอินพุต ( MTIImage(...) ) และเอาต์พุต ( MTIContext.render... ) ของข้อมูลภาพ
การระบุพื้นที่สีสำหรับอินพุตหมายความว่า MetalPetal ควรแปลงค่าสีต้นทางเป็นพื้นที่สีที่ระบุในระหว่างการสร้างพื้นผิว
เมื่อโหลดจาก URL หรือ CGImage คุณสามารถระบุพื้นที่สีที่คุณต้องการให้ข้อมูลพื้นผิวอยู่ด้วยโดยใช้ MTICGImageLoadingOptions หากคุณไม่ได้ระบุตัวเลือกใด ๆ เมื่อโหลดภาพอุปกรณ์จะใช้พื้นที่สี RGB ( MTICGImageLoadingOptions.default ) พื้นที่สี nil การปิดการจับคู่สีนี่คือเทียบเท่ากับการใช้พื้นที่สีของภาพอินพุตเพื่อสร้าง MTICGImageLoadingOptions หากโมเดลของพื้นที่สีที่ระบุไม่ใช่ RGB พื้นที่สี RGB ของอุปกรณ์จะใช้เป็นทางเลือก
เมื่อโหลดจาก CIImage คุณสามารถระบุพื้นที่สีที่คุณต้องการให้ข้อมูลพื้นผิวโดยใช้ MTICIImageRenderingOptions หากคุณไม่ได้ระบุตัวเลือกใด ๆ เมื่อโหลด CIImage จะใช้พื้นที่สี RGB ของอุปกรณ์ ( MTICIImageRenderingOptions.default ) พื้นที่สี nil การปิดใช้งานการจับคู่สีค่าสีจะถูกโหลดในพื้นที่สีทำงานของ CIContext
เมื่อระบุพื้นที่สีสำหรับเอาต์พุตพื้นที่สีจะทำหน้าที่เหมือนแท็กที่ใช้ในการสื่อสารกับส่วนที่เหลือของระบบเกี่ยวกับวิธีการแสดงค่าสีในเอาต์พุต ไม่มีการแปลงพื้นที่สีจริง
คุณสามารถระบุพื้นที่สีของเอาต์พุต CGImage โดยใช้ MTIContext.makeCGImage... หรือ MTIContext.startTaskTo... วิธีการที่มีพารามิเตอร์ colorSpace
คุณสามารถระบุพื้นที่สีของเอาต์พุต CIImage โดยใช้ MTICIImageCreationOptions
MetalPetal สันนิษฐานว่าค่าสีเอาต์พุตอยู่ในพื้นที่อุปกรณ์สี RGB เมื่อไม่มีการระบุพื้นที่สีเอาต์พุต
CVPixelBuffer MetalPetal ใช้ CVMetalTextureCache และ IOSurface เพื่อแมป CVPixelBuffer S โดยตรงกับพื้นผิวโลหะ ดังนั้นคุณไม่สามารถระบุพื้นที่สีสำหรับการโหลดหรือแสดงผลไปยัง CVPixelBuffer อย่างไรก็ตามคุณสามารถระบุได้ว่าจะใช้พื้นผิวที่มีรูปแบบ SRGB Pixel สำหรับการแมปหรือไม่
ในโลหะถ้าชื่อรูปแบบพิกเซลมีคำต่อท้าย _sRGB ดังนั้นการบีบอัดแกมม่า SRGB และการบีบอัดจะถูกนำไปใช้ในระหว่างการอ่านและการเขียนค่าสีในพิกเซล นั่นหมายถึงพื้นผิวที่มีรูปแบบพิกเซล _sRGB ถือว่าค่าสีที่เก็บคือ SRGB Gamma ที่แก้ไขเมื่อค่าสีถูกอ่านใน shader, การแปลง SRGB เป็นเชิงเส้น RGB จะดำเนินการ เมื่อค่าสีถูกเขียนใน shader การแปลงเชิงเส้น RGB เป็น SRGB จะดำเนินการ
คุณสามารถใช้ MTIRGBColorSpaceConversionFilter เพื่อทำการแปลงพื้นที่สี ฟังก์ชั่นการแปลงพื้นที่สียังมีอยู่ใน MTIShaderLib.h
metalpetal::sRGBToLinear (SRGB IEC61966-2.1 ถึง SRGB เชิงเส้น)metalpetal::linearToSRGB (เชิงเส้น SRGB ถึง SRGB IEC61966-2.1)metalpetal::linearToITUR709 (เชิงเส้น SRGB ถึง ITU-R 709)metalpetal::ITUR709ToLinear (ITU-R 709 ถึง SRGB เชิงเส้น) คุณสามารถใช้ MTISCNSceneRenderer เพื่อสร้าง MTIImage s จาก SCNScene คุณอาจต้องการจัดการกับพื้นที่สี RGB เชิงเส้นของ SceneKit Renderer ดูที่ปัญหา #76 ภาพจาก SceneKit นั้นมืดกว่าปกติ
คุณสามารถใช้ MTISKSceneRenderer เพื่อสร้าง MTIImage s จาก SKScene
คุณสามารถสร้าง MTIImage s จาก CIImage s
คุณสามารถแสดง MTIImage ไปยัง CIImage โดยใช้ MTIContext
คุณสามารถใช้ CIFilter โดยตรงกับ MTICoreImageKernel หรือคลาส MTICoreImageUnaryFilter (Swift เท่านั้น)
ดู MetalPetaljs
ด้วย MetalPetalJS คุณสามารถสร้างท่อส่งและตัวกรองโดยใช้ JavaScript ทำให้สามารถดาวน์โหลดตัวกรอง/เรนเดอร์ของคุณจาก "The Cloud"
ขอแนะนำให้คุณใช้ APIs ที่ยอมรับ MTICGImageLoadingOptions เพื่อโหลด CGImage s และรูปภาพจาก URL แทนที่จะใช้ APIs ที่ยอมรับ MTKTextureLoaderOption
เมื่อคุณใช้ APIs ที่ยอมรับ MTKTextureLoaderOption , metalpetal โดยค่าเริ่มต้นใช้ MTIDefaultTextureLoader เพื่อโหลด CGImage s, รูปภาพจาก URL และรูปภาพชื่อ MTIDefaultTextureLoader ใช้ MTKTextureLoader ภายในและมีวิธีแก้ปัญหาบางอย่างสำหรับความไม่สอดคล้องกันและข้อบกพร่องของ MTKTextureLoader ในราคาที่มีประสิทธิภาพเล็กน้อย นอกจากนี้คุณยังสามารถสร้างตัวโหลดพื้นผิวของคุณเองได้โดยใช้โปรโตคอล MTITextureLoader จากนั้นกำหนดคลาส texture loader ของคุณให้กับ MTIContextOptions.textureLoaderClass เมื่อสร้าง MTIContext
คุณสามารถใช้ cocoapods เพื่อติดตั้งเวอร์ชันล่าสุด
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'
Swiftให้การเพิ่มเติมเฉพาะอย่างรวดเร็วและการปรับเปลี่ยน API Objective-C เพื่อปรับปรุงการทำแผนที่ให้เป็น Swift แนะนำเป็นอย่างยิ่งหากคุณใช้ Swift
AppleSiliconจัดเตรียมไลบรารี Shader เริ่มต้นที่รวบรวมในภาษาโลหะแรเงา v2.3 ซึ่งจำเป็นสำหรับการเปิดใช้งานการสนับสนุนการผสมที่ตั้งโปรแกรมได้บน Apple Silicon Mac
การเพิ่มการพึ่งพาแพ็คเกจลงในแอปของคุณ
MetalPetal สามารถทำงานบนเครื่องจำลองด้วย Xcode 11+ และ MacOS 10.15+
MetalPerformanceShaders.framework ไม่สามารถใช้งานได้ในเครื่องจำลองดังนั้นตัวกรองที่พึ่งพา MetalPerformanceShaders เช่น MTIMPSGaussianBlurFilter , MTICLAHEFilter ไม่ทำงาน
Simulator รองรับคุณสมบัติที่น้อยลงหรือขีด จำกัด การใช้งานที่แตกต่างจาก Apple GPU จริง ดูการพัฒนาแอพโลหะที่ทำงานในตัวจำลองเพื่อดูรายละเอียด
หากคุณดู MTIImage อย่างรวดเร็วมันจะแสดงกราฟภาพที่คุณสร้างขึ้นเพื่อสร้างภาพนั้น

ทำไมวัตถุประสงค์ C?
ขอบคุณที่พิจารณาการมีส่วนร่วมกับ MetalPetal โปรดอ่านแนวทางการสนับสนุนของเรา
MetalPetal ได้รับอนุญาตจาก MIT ใบอนุญาต
ไฟล์ในไดเรกทอรี /MetalPetalExamples ได้รับใบอนุญาตภายใต้ใบอนุญาตแยกต่างหาก license.md
เอกสารคือ CC-by-4.0