MPSImageIntegral在图像较小时返回全零

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

我有一个金属着色器,可以处理iPad Pro视频帧以生成彩色附件中的(未显示)RGBA32Float图像。然后,将该纹理通过MPSImageIntegral滤镜放置,该滤镜编码为与着色器相同的命令缓冲区,从而生成具有相同大小和格式的输出图像。在命令缓冲区的完成处理程序中,我使用以下代码读取了过滤图像中的最后一个像素(包含输入图像中所有像素的总和):

let src = malloc(16)    // 4 Floats per pixel * 4 bytes/Float
let region = MTLRegionMake2D(imageWidth - 1, imageHeight - 1, 1, 1) // last pixel in image
outputImage!.getBytes(src!, bytesPerRow: imageWidth * 16, from: region, mipmapLevel: 0)
let sum = src!.bindMemory(to: Float.self, capacity: 4)
NSLog("sum = \(sum[0]), \(sum[1]), \(sum[2]), \(sum[3])")

只要保存输入和过滤后的图像的纹理都与iPad的显示尺寸相同,即2048 x 2732,就可以正常工作,尽管在处理如此大的图像时会很慢。

[为了加快速度,我让着色器仅生成1/4尺寸(512 x 683)RGBA32Float图像,并将相同的尺寸和格式用于滤镜的输出。但是在那种情况下,我读出的总和总是零。

通过在调试器中捕获GPU帧,我可以看到两种情况下的依赖图看起来都相同(除了后一种情况下减小的纹理大小),并且着色器和滤镜在两种情况下均按预期工作输入和过滤后的纹理的外观,如调试器中所示。 所以,当唯一的变化是减小过滤器的输入和输出图像的大小时,为什么我不能再成功地读出过滤后的数据?

我已经尝试过的某些方法,无济于事:

  1. 使用512 x 512(和其他尺寸)的图像,以避免在512 x 683图像中出现可能的填充伪像。
  2. 查看输出图像中间附近的其他像素,根据GPU快照,这些像素也包含非零数据,但是在使用较小图像时读数为0。
  3. 在同一命令缓冲区中使用MTLBlitCommandEncoder将输出像素复制到MTLBuffer,而不是使用getBytes或除了使用getBytes之外,还使用MTLBlitCommandEncoder。 (这是this MacOS question的答案所建议的,该答案并不直接适用于iOS。)
ios metal metal-performance-shaders
1个回答
0
投票

[我发现,如果我将用于将初始RGBA32Float输入图像从.dontCare输入到.store的着色器的颜色附件的渲染过程描述符的storeAction更改,则该代码适用于512 x 683和2048 x 2732的图像。

为什么不使用它,对于较大的图像我还是不知道。

我也不知道为什么这个存储动作很重要,因为过滤后的输出图像已经被成功生成,即使它的输入没有被存储。

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