我在使用金属API加速我的图形方面取得了巨大的成功,但是在尝试绘制纹理以便以后重复使用时我被卡住了。
我试图获得相同的结果来绘制到Quartz中的CGlayer,然后在绘制之前将其粘贴到屏幕(理想情况下在某个位置)。
一个简单的例子真的很有帮助。或者,这个简单的类演示了这个问题。绘制顶点缓冲区。屏幕外顶点缓冲区(在第一个渲染过程中绘制)不是:
import MetalKit
类MetalView:MTKView {
var offscreen_vertex_buffer: MTLBuffer!
var vertex_buffer: MTLBuffer!
var rps: MTLRenderPipelineState! = nil
var offscreenTexture:MTLTexture!
var outTexture:MTLTexture!
override func drawRect(dirtyRect: NSRect) {
super.drawRect(dirtyRect)
//triggers the render function on first draw
render()
}
func render() {
sampleCount = 4
layer?.opaque = false
layer?.magnificationFilter = kCAFilterNearest
framebufferOnly = false
device = MTLCreateSystemDefaultDevice()
createBuffer()
registerShaders()
sendToGPU()
}
struct Vertex {
var position: vector_float4
var color: vector_float4
};
func createBuffer() {
//triangle /\
let vertex_data = [Vertex(position: [-1.0, -1.0, 0.0, 1.0], color: [1, 0, 0, 1]),
Vertex(position: [ 1.0, -1.0, 0.0, 1.0], color: [0, 1, 0, 1]),
Vertex(position: [ 0.0, 1.0, 0.0, 1.0], color: [0, 0, 1, 1])]
vertex_buffer = device!.newBufferWithBytes(vertex_data, length: sizeof(Vertex) * 3, options:[])
//upside down triangle \/
let offscreen_vertex_data = [Vertex(position: [-1.0, 1.0, 0.0, 1.0], color: [1, 0, 0, 1]),
Vertex(position: [ 1.0, 1.0, 0.0, 1.0], color: [1, 1, 0, 1]),
Vertex(position: [ 0.0, -1.0, 0.0, 1.0], color: [0, 0, 1, 1])]
offscreen_vertex_buffer = device!.newBufferWithBytes(offscreen_vertex_data, length: sizeof(Vertex) * 3, options:[])
}
func registerShaders() {
let library = device!.newDefaultLibrary()!
let vertex_func = library.newFunctionWithName("vertex_func")
let frag_func = library.newFunctionWithName("fragment_func")
let rpld = MTLRenderPipelineDescriptor()
rpld.vertexFunction = vertex_func
rpld.fragmentFunction = frag_func
rpld.colorAttachments[0].pixelFormat = .BGRA8Unorm
rpld.colorAttachments[0].blendingEnabled = true
rpld.sampleCount = 4
rpld.colorAttachments[0].rgbBlendOperation = MTLBlendOperation.Add
rpld.colorAttachments[0].alphaBlendOperation = MTLBlendOperation.Add
rpld.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactor.SourceAlpha
rpld.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactor.SourceAlpha
rpld.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactor.OneMinusSourceAlpha
rpld.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactor.OneMinusSourceAlpha
do {
try rps = device!.newRenderPipelineStateWithDescriptor(rpld)
} catch let error {
self.print("\(error)")
}
}
func sendToGPU() {
/*
* first pass should render the upside down triangle: \/ to 'outTexture'
*/
if let renderPassDescriptor = MakeTexturePassDescripter() {
let command_buffer = device!.newCommandQueue().commandBuffer()
let command_encoder = command_buffer.renderCommandEncoderWithDescriptor(renderPassDescriptor)
command_encoder.setRenderPipelineState(rps)
command_encoder.setVertexBuffer(offscreen_vertex_buffer, offset: 0, atIndex: 0)
command_encoder.drawPrimitives(.Triangle, vertexStart: 0, vertexCount: 3, instanceCount: 1)
command_encoder.endEncoding()
command_buffer.commit()
command_buffer.waitUntilCompleted()
}
if let rpd = currentRenderPassDescriptor, drawable = currentDrawable {
rpd.colorAttachments[0].clearColor = MTLClearColorMake(0.5, 0.5, 0.5, 0.1)
let command_buffer = device!.newCommandQueue().commandBuffer()
let command_encoder = command_buffer.renderCommandEncoderWithDescriptor(rpd)
command_encoder.setRenderPipelineState(rps)
//draw a triangle: /\
command_encoder.setVertexBuffer(vertex_buffer, offset: 0, atIndex: 0)
command_encoder.drawPrimitives(.Triangle, vertexStart: 0, vertexCount: 3, instanceCount: 1)
// calculate total bytes of 'outTexture'
let bytesPerPixel:Int = 4
let bytesPerRow:Int = bytesPerPixel * Int(frame.size.width)
let imageByteCount = outTexture.width * outTexture.height * bytesPerPixel
// full screen region
// this might have to be MTLRegionMake2D(0, 0, 2 * Int(frame.size.width), 2 * Int(frame.size.height)) in retina display
let region:MTLRegion = MTLRegionMake2D(0, 0, Int(frame.size.width), Int(frame.size.height))
// An empty buffer that will contain entire image frame
var src = [UInt8](count: Int(imageByteCount), repeatedValue: 0)
// Fill the buffer with the bytes from the texture
outTexture.getBytes(&src, bytesPerRow: bytesPerRow, fromRegion: region, mipmapLevel: 0)
//replace the drawable texture with the buffer info
drawable.texture.replaceRegion(region, mipmapLevel: 0, withBytes: src, bytesPerRow: bytesPerRow)
command_encoder.endEncoding()
command_buffer.presentDrawable(drawable)
command_buffer.commit()
/*
* draws the triangle from the vertex_buffer /\
* but not the offscreen triangle from the first render pass
* arrgh!
*/
}
}
func CreateTexture(texture_width:Int, texture_height:Int) -> MTLTexture?
{
//------------------------------------------------------------
// offscreen texture descriptor
//------------------------------------------------------------
let offscreenTextureDesc =
MTLTextureDescriptor.texture2DDescriptorWithPixelFormat(
.BGRA8Unorm,
width: texture_width,
height: texture_height,
mipmapped: false)
offscreenTextureDesc.storageMode = .Private
offscreenTextureDesc.textureType = .Type2DMultisample
offscreenTextureDesc.sampleCount = 4
offscreenTextureDesc.usage = .RenderTarget
//------------------------------------------------------------
// texture on device to be written to..
//------------------------------------------------------------
var texture:MTLTexture? = nil
texture = device!.newTextureWithDescriptor(offscreenTextureDesc)
texture?.label = "offscreenTexture.A"
return texture
}
func CreateOutTexture(texture_width:Int, texture_height:Int) -> MTLTexture?
{
//------------------------------------------------------------
// offscreen texture destination for AA multisample
//------------------------------------------------------------
let offscreenTextureDesc =
MTLTextureDescriptor.texture2DDescriptorWithPixelFormat(
.BGRA8Unorm,
width: texture_width,
height: texture_height,
mipmapped: false)
offscreenTextureDesc.textureType = .Type2D
offscreenTextureDesc.usage = .RenderTarget
//------------------------------------------------------------
// texture on device to be written to..
//------------------------------------------------------------
return device!.newTextureWithDescriptor(offscreenTextureDesc)
}
func MakeTexturePassDescripter() -> MTLRenderPassDescriptor?
{
if (offscreenTexture == nil)
{
offscreenTexture = CreateTexture(Int(self.frame.size.width), texture_height: Int(self.frame.size.height))
}
if (outTexture == nil)
{
//destination texture of 4 sample count AA
outTexture = CreateOutTexture(Int(self.frame.size.width), texture_height: Int(self.frame.size.height))
}
var texturePassDescriptor:MTLRenderPassDescriptor? = nil
texturePassDescriptor = MTLRenderPassDescriptor()
texturePassDescriptor!.colorAttachments[0].texture = offscreenTexture
texturePassDescriptor!.colorAttachments[0].resolveTexture = outTexture
texturePassDescriptor!.colorAttachments[0].storeAction = MTLStoreAction.MultisampleResolve
texturePassDescriptor!.colorAttachments[0].clearColor =
MTLClearColor(red: 0.0, green: 0.0, blue: 1.0, alpha: 1.0)
texturePassDescriptor!.colorAttachments[0].loadAction = .Clear
return texturePassDescriptor
}
非常感谢温和的建议
ķ。