返回

让像素可见:从 Metal 可绘制纹理中提取 GPU 成果

IOS

从可绘制纹理中读取像素数据

导言

在计算机图形学中,Metal 框架为我们提供了强大的工具来管理和渲染纹理。纹理是图像或数据的集合,它们可以存储在 GPU(图形处理单元)的内存中。当 GPU 完成渲染纹理后,我们需要一种方法来从纹理中获取像素数据,以便 CPU 可以处理这些数据。

本文将逐步指导您完成从 Metal 可绘制纹理中读取像素数据的过程。我们将介绍如何启用纹理的可读性、渲染纹理、将纹理复制到新的缓冲区,以及最终从该缓冲区获取数据。

启用纹理可读性

第一步是启用纹理的可读性。这允许 CPU 读取纹理的数据。要启用可读性,请在创建纹理符时设置 MTLTextureDescriptor 的 storageMode 属性为 MTLStorageModePrivate。

let textureDescriptor = MTLTextureDescriptor()
textureDescriptor.storageMode = .private

渲染纹理

接下来,我们需要渲染纹理。为此,我们使用 MTLCommandBuffer 编码渲染命令。确保在渲染通道中包含纹理作为颜色附件。

let commandBuffer = commandQueue.makeCommandBuffer()

let renderPassDescriptor = MTLRenderPassDescriptor()
renderPassDescriptor.colorAttachments[0].texture = texture

let renderCommandEncoder = commandBuffer?.makeRenderCommandEncoder(descriptor: renderPassDescriptor)
renderCommandEncoder?.endEncoding()

commandBuffer?.commit()
commandBuffer?.waitUntilCompleted()

将纹理复制到新缓冲区

现在纹理已经渲染,我们需要将它复制到一个新的缓冲区中,以便我们可以从 CPU 访问数据。这可以通过使用 MTLBlitCommandEncoder 来完成。

let blitCommandEncoder = commandBuffer?.makeBlitCommandEncoder()

let blitDescriptor = MTLBlitDescriptor()
blitDescriptor.sourceTexture = texture
blitDescriptor.sourceRegion = MTLRegion(origin: MTLOrigin(x: 0, y: 0, z: 0), size: MTLSize(width: texture.width, height: texture.height, depth: 1))
blitDescriptor.destinationTexture = newTexture

blitCommandEncoder?.copy(from: texture, sourceSlice: 0, sourceLevel: 0, sourceOrigin: blitDescriptor.sourceRegion.origin, sourceSize: blitDescriptor.sourceRegion.size, to: newTexture, destinationSlice: 0, destinationLevel: 0, destinationOrigin: blitDescriptor.destinationRegion.origin)

blitCommandEncoder?.endEncoding()

commandBuffer?.commit()
commandBuffer?.waitUntilCompleted()

从新缓冲区获取数据

最后,我们可以从新缓冲区中获取数据。这可以通过将缓冲区映射到 CPU 的内存中来完成。

let data = newTexture.makeTextureView()?.getBytes()

结论

通过遵循这些步骤,您就可以从 Metal 可绘制纹理中获取像素数据。这使您能够在 CPU 上处理和分析渲染的结果。这在图像处理、计算机视觉和其他需要访问纹理数据的应用程序中非常有用。