在MetalKit中使用纹理的屏幕外绘图示例

时间:2016-07-06 12:39:42

标签: macos metal

我在使用金属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
}

非常感谢温和的建议

ķ。

0 个答案:

没有答案