我正在尝试在现有纹理的顶部放置许多叠加层(纹理)。在大多数情况下,这工作正常。
但是,对于我的生活,我无法弄清楚为什么在我drawRect
的MTKView
. 一切似乎都很好;theTexture
在循环放置叠加层后,我会(在内核着色器中)进行进一步处理。出于某种原因,我觉得这种编码提前结束了,而且还没有完成足够的工作。
澄清一下,一切开始都很好,但大约 5 秒后,闪烁开始并逐渐恶化。出于调试目的(现在,无论如何),循环只运行一次——只有一个覆盖元素。theTexture
每次开始之前,输入纹理 ( ) 都是真实的(使用 storageModeMTLStorageModeManaged
和 usage的描述符创建MTLTextureUsageUnknown
)。
我还尝试将编码器实例化/结束填充到循环中;没有不同。
有人可以帮我看看我做错了什么吗?
id<MTLTexture> theTexture; // valid input texture as "background"
MTLRenderPassDescriptor *myRenderPassDesc = [MTLRenderPassDescriptor renderPassDescriptor];
myRenderPassDesc.colorAttachments[0].texture = theTexture;
myRenderPassDesc.colorAttachments[0].storeAction = MTLStoreActionStore;
myRenderPassDesc.colorAttachments[0].loadAction = MTLLoadActionLoad;
id<MTLRenderCommandEncoder> myEncoder = [commandBuffer renderCommandEncoderWithDescriptor:myRenderPassDesc];
MTLViewport viewPort = {0.0, 0.0, 1920.0, 1080.0, -1.0, 1.0};
vector_uint2 imgSize = vector2((u_int32_t)1920,(u_int32_t)1080);
[myEncoder setViewport:viewPort];
[myEncoder setRenderPipelineState:metalVertexPipelineState];
for (OverlayWrapper *ow in overlays) {
id<MTLTexture> overlayTexture = ow.overlayTexture;
VertexRenderSet *v = [ow getOverlayVertexInfoPtr];
NSUInteger vSize = v->metalVertexCount*sizeof(AAPLVertex);
id<MTLBuffer> mBuff = [self.device newBufferWithBytes:v->metalVertices
length:vSize
options:MTLResourceStorageModeShared];
[myEncoder setVertexBuffer:mBuff offset:0 atIndex:0];
[myEncoder setVertexBytes:&imgSize length:sizeof(imgSize) atIndex:1];
[myEncoder setFragmentTexture:overlayTexture atIndex:0];
[myEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:v->metalVertexCount];
}
[myEncoder endEncoding];
// do more work (kernel shader) with "theTexture"...
更新#1:
我附上了一个“好”框架的图像,显示了顶点区域(右下角)。我的编码器负责将绿色替代“图像”theTexture
以 30fps 的速度放置在视频帧的顶部,它确实这样做了。只是为了澄清,theTexture
为每一帧创建(来自 CoreVideo 像素缓冲区)。在这个编码器之后,我只从theTexture
内核着色器中读取来调整亮度——一切都很好。
我的问题必须存在于其他地方,因为视频帧停止流动(尽管音频继续播放),并且一旦插入此编码器,我最终会在 2 或 3 个先前的帧之间交替(因此,闪烁)。我现在相信我的视频像素缓冲区供应商无意中被这个“覆盖”供应商所取代。
如果我注释掉整个顶点渲染器,我的视频帧就会很好地流过;这不是我的视频帧供应商的问题。
更新#2:
这是我的渲染管道的声明:
MTLRenderPipelineDescriptor *p = [[MTLRenderPipelineDescriptor alloc] init];
if (!p)
return nil;
p.label = @"Vertex Mapping Pipeline";
p.vertexFunction = [metalLibrary newFunctionWithName:@"vertexShader"];
p.fragmentFunction = [metalLibrary newFunctionWithName:@"samplingShader"];
p.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
NSError *error;
metalVertexPipelineState = [self.device newRenderPipelineStateWithDescriptor:p
error:&error];
if (error || !metalVertexPipelineState)
return nil;
这是用于创建的纹理描述符theTexture
:
metalTextureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
width:width
height:height
mipmapped:NO];
metalTextureDescriptor.storageMode = MTLStorageModePrivate;
metalTextureDescriptor.usage = MTLTextureUsageUnknown;
由于这个原因,我没有包含AAPLVertex
和 顶点/片段函数:如果我只是在我的渲染代码中注释掉OverlayWrapper
循环(即,甚至不设置顶点缓冲区或绘制图元),视频帧仍然会闪烁。从该编码器“运行”的时间开始,视频仍在播放,但只有 2-3 帧左右在连续循环中播放。
我还在 之后添加了此代码,[... endEncoding]
并将纹理使用更改为MTLStorageModeManaged
- 仍然,没有骰子:
id<MTLBlitCommandEncoder> blitEncoder = [commandBuffer blitCommandEncoder];
[blitEncoder synchronizeResource:crossfadeOutput];
[blitEncoder endEncoding];
澄清一些事情:随后的计算机着色器theTexture
仅用于输入。这些是视频帧;因此,theTexture
每次都重新创建。在它经过这个渲染阶段之前,它有一个真正的“背景”
更新#3:
我得到了这个工作,如果通过非常规的方式。
我使用这个顶点着色器将我的叠加层渲染到新创建的空白纹理的透明背景上,特别是我loadAction
的MTLLoadActionClear
clearColor 为 (0,0,0,0)。
然后我将这个生成的纹理与我theTexture
的内核着色器混合。我不应该这样做,但它有效!