1

我得到了什么

我正在按照 Apple 示例代码AVCamPhotoFilterMTKView.

我想要做什么

除了上面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并绘制而不做两次工作?

4

1 回答 1

4

如果framebufferOnly将 first 的属性设置MTKView为 false,则可以提交从其可绘制纹理读取的命令。然后,您可以使用 blit 命令编码器从第一个可绘制对象的纹理复制到第二个(如果它们兼容)。否则,您可以将四边形绘制到第二个可绘制对象的纹理上,并将第一个可绘制对象的纹理作为纹理四边形的源。

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

在任何情况下,如果您需要两个视图完美同步更新,您应该presentsWithTransaction为两个视图设置为 true,同步等待(使用-waitUntilScheduled)执行(至少)复制/绘制到可绘制纹理的命令缓冲区,并且然后-present直接调用两个drawable。(也就是说,不要-presentDrawable:在命令缓冲区上使用。)

于 2018-08-15T20:05:14.747 回答