“拦截”METAL顶点/片段着色器

时间:2017-09-03 18:04:56

标签: metal metalkit

我目前有一个MTLTexture用于输入,并使用一组20-30个顶点逐段渲染。目前,这是在drawRect的{​​{1}}处理程序的尾端完成的:

MTKView

然而,在做最后的[encoder setVertexBuffer:mBuff offset:0 atIndex:0]; // buffer of vertices [encoder setVertexBytes:&_viewportSize length:sizeof(_viewportSize) atIndex:1]; [encoder setFragmentTexture:inputTexture atIndex:0]; [encoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:_vertexInfo.metalVertexCount]; [encoder endEncoding]; [commandBuffer presentDrawable:self.currentDrawable]; [commandBuffer commit]; 之前,我想拦截生成的纹理(我将把它的一个区域发送到一个单独的presentDrawable)。换句话说,我需要在MTKView调用后访问某种方式的输出MTLTexture

最有效的方法是什么?

一个想法是向中间输出drawPrimitives引入额外的drawPrimitives渲染。我不知道该怎么做,但我会在这个过程中挖出输出纹理。我怀疑这甚至可以在其他地方完成(即屏幕外)。

然后我会使用带有outputTexture的单个质量纹理四边形,然后在其上MTLTexture发出第二个drawPrimitives。该代码将存在于我以前的代码中。

Metal API中可能有一个简单的方法(我缺少),它允许我捕获presentDrawable的输出纹理。

我已经考虑使用drawPrimitives,但在某些MacOSX硬件上存在一些问题。

更新#1: idoogy ,这是您要求的代码:

这是我创建初始“亮度输出”纹理的地方......我们在顶点着色器中进行中飞行:

MTLBlitCommandEncoder

下面,我们在辅助视图的... [encoder setFragmentTexture:brightnessOutput atIndex:0]; [encoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:_vertexInfo.metalVertexCount]; [encoder endEncoding]; for (AltMonitorMTKView *v in self.downstreamOutputs). // ancillary MTKViews [v setInputTexture:brightnessOutput]; __block dispatch_semaphore_t block_sema = d.hostedAssetsSemaphore; [commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer) { dispatch_semaphore_signal(block_sema); }]; [commandBuffer presentDrawable:self.currentDrawable]; [commandBuffer commit]; 处理程序中使用drawRect作为正在传输的纹理,显示它的子区域。我应该提一下,inputTexture被配置为由MTKView绘制而不是与内部计时器一起绘制:

setNeedsDisplay

以上代码似乎可以正常使用。话虽如此,我想我们在Xcode调试器中讲述了一个不同的故事。很明显,我浪费了大量的时间用这种方式做事......那个长命令缓冲区是辅助监视器视图,做了很多等待......

enter image description here

1 个答案:

答案 0 :(得分:2)

这应该是可行的。在commit上调用commandBuffer之前,通过调用[commandBuffer addCompletedHandler:]为命令缓冲区添加完成处理程序,然后在完成处理程序中,从renderPassDescriptor中获取颜色附件。

renderPassDescriptor包含当前要绘制的附件集,并由MTKView自动配置。实际纹理每帧旋转,因为MTKView使用三重缓冲来确保GPU的连续使用,但只要您在完成处理程序中,该特定附件将不会被释放以供将来使用框架,所以你可以安全地阅读,复制它等。

注意:确保快速合理地完成处理程序,否则帧速率会下降(因为MTKView将快速耗尽渲染目标,并且只会坐在那里直到它们被释放)

这是一个让您入门的通用代码段:

// Grab the current render pass descriptor from MTKView so it's accessible from within the completion block:
__block MTLRenderPassDescriptor *renderPassDescriptor = self.renderPassDescriptor;

[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> commandBuffer) {
   // This will be called once the GPU has completed rendering your frame.
   // This is your output texture:
   id <MTLTexture> outputTexture = renderPassDescriptor.colorAttachments[0].texture;
}];
[commandBuffer commit];