A set of tools and extensions that allow sharing page-aligned memory allocation between different graphics APIs and provide view interop for them. This library helps ZERO10 to reduce memory traffic in its computer vision pipelines.
This library introduces a GraphicsDataProvider protocol. Every type that conforms to it allows to make a view of its contents as:
vImage_BufferCVPixelBufferMLMultiArrayMTLBufferMTLTexture
By default, these types are vImage_Buffer, CGContext, CGImage, CVPixelBuffer, IOSurface, MTLTexture, and UIImage.
That means it is possible to create an IOSurface and reinterpret its contents, such as CVPixelBuffer or vImage_Buffer.
let vImageBuffer: vImage_Buffer = try ioSurface.vImageBufferView()
let pixelBuffer: CVPixelBuffer = try vImageBuffer.cvPixelBufferView(cvPixelFormat: .type_32BGRA)
let texture: MTLTexture = try vImageBuffer.mtlTextureView(
device: context.device,
pixelFormat: .bgra8Unorm,
usage: [.shaderRead, .shaderWrite]
)This is quite handy as it allows for the reduction of boilerplate code as well as memory copy operations.
In some cases, it is impossible to make an MTLBuffer or MTLTexture view on some graphics data as it is requires the allocation pointer of the data to be page-aligned. This requirement is done because internally, before the creation of MTLBuffer, Metal marks certain memory pages as accessible to GPU, and the shared memory address beginning should align with the page address.
To overcome such situations, MTLSharedGraphicsBuffer is provided. Inside, this class encapsulates the allocation of page-aligned memory and initialises an MTLBuffer, MTLTexture, vImage_Buffer, CVPixelBuffer and CGContext in such a way so they look at the same memory.
Given that, you can do such tricks as combining CoreGraphics rendering with Metal without memory transfers:
let context = try MTLContext()
let sharedBuffer = try MTLSharedGraphicsBuffer(
device: context.device,
width: 600,
height: 600,
pixelFormat: .bgra8Unorm
)
let rect = CGRect(
x: 125,
y: 125,
width: 300,
height: 300
)
let whiteColor = CGColor(
red: 1,
green: 1,
blue: 1,
alpha: 1
)
// Draw with CoreGraphics
sharedBuffer.cgContext.setFillColor(whiteColor)
sharedBuffer.cgContext.fill(rect)
// Continue with Metal
try context.schedule { commandBuffer in
someFancyMetalFilter.encode(
source: sharedBuffer.texture,
destination: resultTexture,
in: commandBuffer
)
}SharedGraphicsTools is licensed under MIT license.
