金属屏外渲染

问题描述 投票:0回答:1

我需要在Metal中实现离屏渲染,并复制到系统内存中。而不在屏幕上绘图。

这段代码工作得很好,但我不确定这是否是一段正确的代码,我需要调用commandBuffer.enqueue吗?

// 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并没有检查渲染是否完成。

或者我应该创建 "managed "而不是 "private "的离屏纹理,然后直接复制到我的缓冲区。

// 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()
metal
1个回答
2
投票

1) 你不需要调用 enqueue 上的命令缓冲区。这用于在多线程方案中明确指定命令缓冲区的顺序的情况,在这里无关紧要。你的命令缓冲区在被提交后会被隐式地enqueued。

2)你确实需要等待命令缓冲区完成后再将其内容复制到系统内存中。通常情况下,GPU和CPU能够异步运行,而不需要互相等待,这是必不可少的,但在你的用例中,你想要的恰恰相反,等待就是让它们保持锁步的方式。

3)如果你不需要渲染后的图像副本作为纹理在GPU上做进一步的工作,你应该可以完全省略完全的blit,前提是你渲染到的纹理是在托管存储模式下。你可以调用 synchronizeResource: 来代替 blit 编码器,这将使渲染工作的结果在系统内存中的纹理副本中可见,然后你可以直接从那里复制。

如果由于某些原因,渲染目标不能在托管存储中(我注意到你使用的是可绘制文件--这些实际上是可绘制文件吗?MTLDrawable视图或图层提供的,如果是的话,为什么?),事实上,你需要将其复制到一个托管的纹理或共享管理的缓冲区,以便在CPU端复制位。

© www.soinside.com 2019 - 2024. All rights reserved.