我需要在Metal中通过复制到系统内存来实现屏幕外渲染。而不在屏幕上绘图。
这段代码运行良好,但我不确定它是否正确:
// rendering to offscreen texture
auto commandQueue = [device newCommandQueue];
auto commandBuffer = [commandQueue commandBuffer];
//[commandBuffer enqueue]; // Do I need this command?
id<MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:mtlDescriptor];
// perform encoding
[renderEncoder endEncoding];
[commandBuffer commit];
auto commandBuffer = [commandQueue commandBuffer];
id<MTLBlitCommandEncoder> blitEncoder = [commandBuffer blitCommandEncoder];
// Copying offscreen texture to a new managed texture
[blitEncoder copyFromTexture:drawable.texture sourceSlice:0 sourceLevel:level sourceOrigin:region.origin sourceSize:region.size toTexture:_mtlTexture destinationSlice:0 destinationLevel:level destinationOrigin:{xOffset, yOffset, 0}];
[blitEncoder endEncoding];
[commandBuffer commit];
[commandBuffer WaitUntilCompleted]; // I add waiting to get a fully completed texture for copying.
// Final stage - we copy a texture to our buffer in system memory
getBytes_bytesPerRow_fromRegion_mipmapLevel()
我需要给commandBuffer.enqueue打电话吗?此外,如果我删除commandBuffer.WaitUntilCompleted,我只能得到半帧。看起来getBytes_bytesPerRow_fromRegion_mipmapLevel并没有检查渲染是否完成。
或者我应该创建屏幕外的纹理“管理”而不是“私有”,然后直接复制到我的缓冲区:
// creating offscreen texture "managed"
// rendering to offscreen texture
auto commandQueue = [device newCommandQueue];
auto commandBuffer = [commandQueue commandBuffer];
//[commandBuffer enqueue]; // Do I need this command?
id<MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:mtlDescriptor];
// perform encoding
[renderEncoder endEncoding];
[commandBuffer commit];
[commandBuffer waitUntilCompleted];
// Copying "managed" offscreen texture to my buffer
getBytes_bytesPerRow_fromRegion_mipmapLevel()
发布于 2020-06-15 18:42:46
1)不需要在命令缓冲区调用enqueue
。当您想要在多线程方案中显式指定命令缓冲区的顺序时,可以使用它,这在这里是不相关的。您的命令缓冲区将在提交时隐式入队。
2)在将命令缓冲区的内容复制到系统内存之前,确实需要等待命令缓冲区完成。通常,GPU和CPU能够异步运行而不相互等待是必不可少的,但在您的用例中,您想要的是相反的,等待是您保持它们步调一致的方式。
3)如果不需要渲染图像的副本作为GPU上的进一步工作的纹理,则应该能够完全省略全开blit,前提是要渲染到的纹理处于托管存储模式。您可以改为在blit编码器上调用synchronizeResource:
,这将使渲染工作的结果对系统内存中的纹理副本可见,然后可以直接从该副本进行复制。
如果由于某种原因,渲染目标不能在托管存储中(我注意到您使用的是可绘制的-这些是由视图或层提供的MTLDrawable
,如果是,原因是什么?),您实际上将需要blit到托管纹理或共享/托管缓冲区,以便复制CPU端的位。
https://stackoverflow.com/questions/62385511
复制相似问题