ios - MTKView - 一次绘制两个 View

标签 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 并在不进行两次工作的情况下进行绘制?

最佳答案

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

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

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

关于ios - MTKView - 一次绘制两个 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51861512/

相关文章:

ios - 我可以为已批准且正在生产的订阅添加免费试用期 (iTunes Connect) 吗?

javascript - 如何在屏幕中缩放适合高度固定大小的子级 css 仅允许 javascript

ios - 从 UIWebView 打开 UIViewController

ios - 从 xcode 中的注释映射访问结构参数

iphone - 在xCode中引用来自不同目标的类以进行iPhone单元测试

ios - Swift:构建还是不构建

ios - 检查数组是否为 nil/或是否已在 Swift/iOS 中加载?

ios - UICollectionViewCell 的 UiTextField,在 UICollectionViewController 中重叠

iphone - 通过代码从 consol 中清除 NSlog 生成的日志

xcode - 文件名旁边的 '!'(感叹号)在 Xcode 中代表什么