正确使用MPSImageGaussian金字塔和金属

时间:2019-01-02 10:21:03

标签: ios swift metal metal-performance-shaders

我想使用MPSImageGaussianPyramid,但是对于Metal的用法和mipmaps来说是一个新手。我想使用滤镜生成用于图像处理技术的图像金字塔。

根据我的能力,MPSImageGaussianPyramid创建了一个映射错误的图像,但是在我的代码中,即使要确保正确看到输出,我也很难。是否有使用此过滤器的示例?我的问题是:

  1. 应用滤镜后,如何访问映射的图像?

  2. 是否可以将mipmapped的图像复制到另一个图像进行处理?

  3. 此映射图像比通过自定义滤镜手动创建金字塔要快吗?

谢谢,稍后我将提供一些我无法开始工作的示例代码。

1 个答案:

答案 0 :(得分:3)

关于一般使用MPS内核的一些建议,尤其是图像金字塔过滤器的建议:

  • 如果您要使用内核不止一次,请对其进行缓存并重用,而不是每次需要编码时都创建一个内核。
  • 在下采样时,请考虑将内核的edgeMode属性设置为.clamp,因为超出范围的采样(如高斯金字塔在第一步中所做的那样)将默认返回黑色并人工引入暗像素。
  • 在对高斯金字塔核进行编码时,请始终使用“就地”方法,而不提供后备分配器:

kernel.encode(commandBuffer: commandBuffer, inPlaceTexture: &myTexture)

您注意到,运行图像金字塔内核会将结果放入要进行降采样的纹理的可用mip级别。这意味着您提供的纹理应该已经分配了想要填充的mip级别。因此,您应该确保用于创建纹理的描述符具有适当的mipmapLevelCount(这是通过texture2DDescriptorWithPixelFormat便捷方法来确保的,并且可以使用.allocateMipmaps选项进行间接控制) MTKTextureLoader)。

假设您现在知道如何编码内核并将所需的结果转换为纹理,下面是您的问题的一些答案:

1。应用滤镜后,如何访问mipmapped图片?

使用具有mip滤镜的采样器进行渲染时,可以在着色器中隐式使用mipmap,也可以通过传递类型{{1}的lod_option参数来从特定的mip级别显式采样。 }到level函数:

sample

这适用于计算内核以及渲染功能。如果要从单个Mip级别进行采样,请使用constexpr sampler mySampler(coord::normalized, filter::linear, mip_filter::linear); float4 color = myTexture.sample(mySampler, texCoords, level(selectedLod)) 的Mip过滤器或舍入选定的LOD,而不要使用三线性mip过滤。

2。可以将映射的图像复制到另一个图像进行处理吗?

由于由图像金字塔内核缩减采样的纹理必须已经具有nearest使用标志,因此您可以在选择了一个或多个mip级别的压缩纹理上创建纹理视图 。例如,如果要选择第一个和更高的Mip级别(删除基本级别),可以这样进行:

.pixelFormatView

您还可以使用blit命令编码器从一个纹理复制到另一个纹理,并指定要包括的mip级别。如果您想回收较低的Mip级别使用的内存,则可以释放原始纹理。

如果要使用适用于图像而非纹理的API,则可以用let textureView = myTexture.makeTextureView(pixelFormat: myTexture.pixelFormat, textureType: myTexture.textureType, levels: Range<Int>(uncheckedBounds: (1, myTexture.mipmapLevelCount)), slices: Range<Int>(uncheckedBounds: (0, 1))) MTLTexture包裹起来:

MPSImage

3。与通过自定义滤镜手动创建金字塔相比,此mipmapped图像会更快吗?

几乎可以肯定。 Metal Performance Shaders针对每一代设备进行了调整,并具有多种试探法,可以优化执行速度和能耗。