Search code examples
iosobjective-cswiftmetal

Metal off-screen drawing with Multi-Sampling


How do I render primitives into off screen texture, not directly into the screen?

I have a set of triangles and corresponding color, I just want to draw them the same way I do to screen, but into off screen texture, that I can save into a file.

Can anybody show me a code sample of that?


Solution

  • Ok, I realized it myself. This code does the job, with only exception that it draw too huge triangles, but that is a different topic for Vertex function.

    Here is my code:

        let fragmentProgram = defaultLibrary.newFunctionWithName("image_fragmentT")
        let vertexProgram = defaultLibrary.newFunctionWithName("image_vertexT")
    
    
        struct VertexT {
            var x, y, z, w : Float
            var r, g, b, a : Float
        }
    
        let vertexDescriptor = MTLVertexDescriptor()
        vertexDescriptor.attributes[0].offset = 0
        vertexDescriptor.attributes[0].format = .Float4
        vertexDescriptor.attributes[0].bufferIndex = 0
    
        vertexDescriptor.attributes[1].offset = 0
        vertexDescriptor.attributes[1].format = .Float4
        vertexDescriptor.attributes[1].bufferIndex = 0
    
        vertexDescriptor.layouts[0].stepFunction = .PerVertex
        vertexDescriptor.layouts[0].stride = sizeof(VertexT)
    
        let pipelineStateDescriptor = MTLRenderPipelineDescriptor()
        pipelineStateDescriptor.vertexDescriptor = vertexDescriptor
        pipelineStateDescriptor.vertexFunction = vertexProgram
        pipelineStateDescriptor.fragmentFunction = fragmentProgram
        pipelineStateDescriptor.colorAttachments[0].pixelFormat = .RGBA8Unorm;
        pipelineStateDescriptor.colorAttachments[0].blendingEnabled = true
        pipelineStateDescriptor.sampleCount = 4
        pipelineStateDescriptor.colorAttachments[0].rgbBlendOperation =    MTLBlendOperation.Add
        pipelineStateDescriptor.colorAttachments[0].alphaBlendOperation = MTLBlendOperation.Add
        pipelineStateDescriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactor.SourceAlpha
        pipelineStateDescriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactor.SourceAlpha
        pipelineStateDescriptor.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactor.OneMinusSourceAlpha
        pipelineStateDescriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactor.OneMinusSourceAlpha
    
    
        let sampleDesc = MTLTextureDescriptor()
        sampleDesc.textureType = MTLTextureType.Type2DMultisample
        sampleDesc.width = inTexture.width
        sampleDesc.height = inTexture.height
        sampleDesc.sampleCount = 4
        sampleDesc.pixelFormat = .RGBA8Unorm
        sampleDesc.storageMode = .Private
        sampleDesc.usage = .RenderTarget
    
        let sampletex = device.device.newTextureWithDescriptor(sampleDesc)
        let renderPassDescriptor = MTLRenderPassDescriptor()
    
        renderPassDescriptor.colorAttachments[0].texture = sampletex
        renderPassDescriptor.colorAttachments[0].resolveTexture = outTexture
        renderPassDescriptor.colorAttachments[0].loadAction = .Clear
        renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.0)
        renderPassDescriptor.colorAttachments[0].storeAction = .MultisampleResolve
    
        let renderCB = commandQueue.commandBuffer()
    
        let renderCommandEncoder = renderCB.renderCommandEncoderWithDescriptor(renderPassDescriptor)
        let pipelineState = try! device.device.newRenderPipelineStateWithDescriptor(pipelineStateDescriptor)
        renderCommandEncoder.setRenderPipelineState(pipelineState)
    
        let vertexBuf = device.device.newBufferWithLength(triangles.count * 3 * sizeof(VertexT), options: .CPUCacheModeDefaultCache)
    
        var vBufPointer = [VertexT]()
    
        for i in 0..<triangles.count {
    
            // create buffer here
        }
    
        memcpy(vertexBuf.contents(), &vBufPointer, triangles.count * 3 * sizeof(VertexT))
    
        renderCommandEncoder.setVertexBuffer(vertexBuf, offset: 0, atIndex: 0)
        renderCommandEncoder.drawPrimitives(.Triangle, vertexStart: 0, vertexCount: triangles.count * 3)
        renderCommandEncoder.endEncoding()
        renderCB.commit()
        renderCB.waitUntilCompleted()
    

    You image now is in outTexture variable.