MTKView-一次绘制两个视图

时间:2018-08-15 15:14:12

标签: ios swift xcode metal metal-performance-shaders

我得到了什么

我正在遵循Apple示例代码 AVCamPhotoFilter MTKView上显示相机供稿。

我要做什么

除了以上MTKView之外,我还需要显示第二个MTKView。但是,第二个将显示与第一个完全相同的内容。因此,我不想重复代码并重复两次。

当前绘制方法

override func draw(_ rect: CGRect) {
        var pixelBuffer: CVPixelBuffer?
        var mirroring = false
        var rotation: Rotation = .rotate0Degrees

        syncQueue.sync {
            pixelBuffer = internalPixelBuffer
            mirroring = internalMirroring
            rotation = internalRotation
        }

        guard let drawable = currentDrawable,
            let currentRenderPassDescriptor = currentRenderPassDescriptor,
            let previewPixelBuffer = pixelBuffer else {
                return
        }

        // Create a Metal texture from the image buffer
        let width = CVPixelBufferGetWidth(previewPixelBuffer)
        let height = CVPixelBufferGetHeight(previewPixelBuffer)

        if textureCache == nil {
            createTextureCache()
        }
        var cvTextureOut: CVMetalTexture?
        CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
                                                  textureCache!,
                                                  previewPixelBuffer,
                                                  nil,
                                                  .bgra8Unorm,
                                                  width,
                                                  height,
                                                  0,
                                                  &cvTextureOut)
        guard let cvTexture = cvTextureOut, let texture = CVMetalTextureGetTexture(cvTexture) else {
                print("Failed to create preview texture")

                CVMetalTextureCacheFlush(textureCache!, 0)
                return
        }

        if texture.width != textureWidth ||
            texture.height != textureHeight ||
            self.bounds != internalBounds ||
            mirroring != textureMirroring ||
            rotation != textureRotation {
            setupTransform(width: texture.width, height: texture.height, mirroring: mirroring, rotation: rotation)
        }

        // Set up command buffer and encoder
        guard let commandQueue = commandQueue else {
            print("Failed to create Metal command queue")
            CVMetalTextureCacheFlush(textureCache!, 0)
            return
        }

        guard let commandBuffer = commandQueue.makeCommandBuffer() else {
            print("Failed to create Metal command buffer")
            CVMetalTextureCacheFlush(textureCache!, 0)
            return
        }

        guard let commandEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: currentRenderPassDescriptor) else {
            print("Failed to create Metal command encoder")
            CVMetalTextureCacheFlush(textureCache!, 0)
            return
        }

        commandEncoder.label = "Preview display"
        commandEncoder.setRenderPipelineState(renderPipelineState!)
        commandEncoder.setVertexBuffer(vertexCoordBuffer, offset: 0, index: 0)
        commandEncoder.setVertexBuffer(textCoordBuffer, offset: 0, index: 1)
        commandEncoder.setFragmentTexture(texture, index: 0)
        commandEncoder.setFragmentSamplerState(sampler, index: 0)
        commandEncoder.drawPrimitives(type: .triangleStrip, vertexStart: 0, vertexCount: 4)
        commandEncoder.endEncoding()

        commandBuffer.present(drawable) // Draw to the screen
        commandBuffer.commit()
    }

问题

有没有一种方法可以将纹理简单地传递到第二个MTKView并进行绘制而无需做两次工作?

1 个答案:

答案 0 :(得分:2)

如果将第一个framebufferOnly的{​​{1}}属性设置为false,则可以提交从其可绘制纹理读取的命令。然后,如果兼容,则可以使用blit命令编码器从第一个可绘制对象的纹理复制到第二个可绘制对象的纹理。否则,您可以在第二个可绘制对象的纹理上绘制一个四边形,以第一个可绘制对象的纹理作为对四边形进行纹理化的源。

我个人认为我希望所有渲染都使用您自己创建的纹理(而不是任何可绘制的纹理)。然后,将其复制/绘制到两个可绘制纹理中。

无论如何,如果您需要两个视图完美同步更新,则应将两个视图的MTKView都设置为true,并同步等待(使用presentsWithTransaction)用于执行命令缓冲区的命令(至少)复制/绘制到可绘制纹理,然后直接在两个可绘制对象上调用-waitUntilScheduled。 (也就是说,不要在命令缓冲区上使用-present。)