Michael-Lfx / GPU_Tuning

MIT License
9 stars 0 forks source link

[Metal] nextDrawable #7

Open Michael-Lfx opened 5 years ago

Michael-Lfx commented 5 years ago

nextDrawable 调用时机、性能影响

@chenqiu10241983

Always acquire a drawable as late as possible; preferably, immediately before encoding an on-screen render pass. A frame’s CPU work may include dynamic data updates and off-screen render passes that you can perform before acquiring a drawable.

参考

Michael-Lfx commented 5 years ago

这意思是说在encoding an on-screen render pass之前就需要调用nextDrawable嘛?

是的。画在View这次绘制需要配置nextDrawable.textureMTLRenderPassDescriptor.colorAttachments[0].texture,同时要配置MTLCommandBuffer::presentDrawable:drawable

Michael-Lfx commented 5 years ago

我理解真正开始需要drawable的时刻是CommandBuffer已经开始GPU的执行,在encoding之前不用获得nextDrawable吧?

同上。CommandBuffer开始执行前需要明确Encoder要用的各类资源的状态,一旦Encoder:: endEncoding,被使用的资源修改其状态是无效的,不然状态不一致。虽然CommandBuffer确实是在GPU调度它后才会往id <CAMetalDrawable>读写颜色、深度模版数据。

Michael-Lfx commented 5 years ago

放encoding过程后面nextDrawable的话CPU用时还会变少。那这文档里的说法就有点奇怪呀

画到View这次怎么做到放在encoding过程后面?

bhlzlx commented 5 years ago

先不说具体怎么写代码处理,先聊下这个官方文档的动机,我猜它应该是想减少 应用层 持有它的时间,即 Metal 层把使用权交给你,持有时间 + 渲染时间 + 呈现时间,呈现完毕,metal层即可回收此资源 ,减少持有时间也许可以少让metal层少分配那么一个纹理资源呢,我没有深入探究,只是猜也许。。。它可以用两个drawable循环使用来实现三重缓冲的功能。

chenqiu1024 commented 5 years ago

放encoding过程后面nextDrawable的话CPU用时还会变少。那这文档里的说法就有点奇怪呀

画到View这次怎么做到放在encoding过程后面?

形如这样的代码结构:

_currentMTLCommandBuffer = [_mtlCommandQueue commandBuffer];
[_currentMTLCommandBuffer enqueue];

CAMetalLayer* metalLayer = (CAMetalLayer*)self.layer;
// 下面两句放在编码渲染过程之前:
id<CAMetalDrawable> caMTLDrawable = [metalLayer nextDrawable];
_renderPassDescriptor.colorAttachments[0].texture = caMTLDrawable.texture;

// Encode rendering commands ...

// 但是放在encoding后面好像也没错:
//    id<CAMetalDrawable> caMTLDrawable = [metalLayer nextDrawable];
//    _renderPassDescriptor.colorAttachments[0].texture = caMTLDrawable.texture;

[_currentMTLCommandBuffer presentDrawable:caMTLDrawable];
[_currentMTLCommandBuffer commit];
bhlzlx commented 5 years ago

我认为这个“好像没错”的这个情况,你应该持保留态度,因为官方文档这里写很明白,在这个 pass 开始之前就应该获取到,为了能睡好觉,我们应该严格按文档的说明来的。按我在 vulkan上的编码经验上来看,我觉得后者应该会有问题的,当然也不排除 metal 内有什么错误纠正,或者有错并不明显,你可以截一帧拿 render command encoder 看看,一定要慎重啊。

Michael-Lfx commented 5 years ago

// 但是放在encoding后面好像也没错: // id caMTLDrawable = [metalLayer nextDrawable]; // _renderPassDescriptor.colorAttachments[0].texture = caMTLDrawable.texture;

测试了多久、怎么测试的、什么业务场景?为方便讨论,相关完整代码贴出来吧。

chenqiu1024 commented 5 years ago

的确在通常情况下是不能这样用的

-[MTLDebugRenderCommandEncoder validateFramebufferWithRenderPipelineState:]:1222: failed assertion `For color attachment 0, the renderPipelineState pixelFormat must be MTLPixelFormatInvalid, as no texture is set.'