MPSImageGaussianPyramid 与 Metal 的适当使用
Appropriate Usage of MPSImageGaussianPyramid with Metal
我想使用 MPSImageGaussianPyramid
但我对 Metal 的用法和 mipmap 还很陌生。我想用滤镜制作图像金字塔,用于图像处理技术。
根据我能够收集到的信息,MPSImageGaussianPyramid
创建了一个 mipmapped 图像,但是在我的代码中我很难确保我正确地看到了输出。是否有正确使用此过滤器的示例?我的问题是:
应用过滤器后如何访问 mipmap 图像?
是否可以将mipmapped图像复制到另一个图像进行处理?
这个 mipmap 图像会比通过自定义过滤器手动创建金字塔更快吗?
谢谢,我稍后会提供一些我无法开始工作的示例代码。
一般使用 MPS 内核,特别是图像金字塔过滤器的一些建议:
- 如果您要多次使用内核,缓存它并重复使用它,而不是每次需要编码时都创建一个内核。
- 考虑在下采样时将内核的
edgeMode
属性 设置为 .clamp
,因为越界采样(如高斯金字塔在第一步中所做的那样)将 return 默认为黑色并引入人为的暗像素。
- 编码高斯金字塔内核时,始终使用 "in-place" 方法,而不提供后备分配器:
kernel.encode(commandBuffer: commandBuffer, inPlaceTexture: &myTexture)
正如您所注意到的,运行 图像金字塔内核将结果放入正在下采样的纹理的可用 mip 级别中。这意味着您提供的纹理应该已经分配了您想要填充的尽可能多的 mip 级别。因此,您应该确保用于创建纹理的描述符具有适当的 mipmapLevelCount
(这是由 texture2DDescriptorWithPixelFormat
便捷方法确保的,并且可以通过使用 .allocateMipmaps
选项间接控制MTKTextureLoader
).
假设您现在知道如何对内核进行编码并在纹理中获得所需的结果,下面是您问题的一些答案:
1.如何在应用过滤器后访问 mipmap 图像?
您可以在使用具有 mip 过滤器的采样器进行渲染时在着色器中隐式使用 mipmap,或者您可以通过传递 lod_option
类型的参数从特定的 mip 级别显式采样 level
到 sample
函数:
constexpr sampler mySampler(coord::normalized, filter::linear, mip_filter::linear);
float4 color = myTexture.sample(mySampler, texCoords, level(selectedLod))
这适用于计算内核和渲染函数。如果您想从单个 mip 级别进行采样而不是使用三线性 mip 过滤,请使用 nearest
的 mip 过滤器或舍入 selected LOD。
2。是否可以将 mipmap 图像复制到另一个图像进行处理?
由于图像金字塔内核下采样的纹理必须已经具有 .pixelFormatView
使用标志,因此您可以在混合纹理上创建 纹理视图 selects 一个或多个 mip 级别。例如,如果你想 select 第一个和更高的 mip 级别(降低基本级别),你可以这样做:
let textureView = myTexture.makeTextureView(pixelFormat: myTexture.pixelFormat,
textureType: myTexture.textureType,
levels: Range<Int>(uncheckedBounds: (1, myTexture.mipmapLevelCount)),
slices: Range<Int>(uncheckedBounds: (0, 1)))
您还可以使用 blit 命令编码器从一个纹理复制到另一个纹理,指定要包含的 mip 级别。如果您想回收较低 mip 级别使用的内存,这允许您释放原始纹理。
如果您想使用处理图像而不是纹理的 API,您可以用 MPSImage
包裹 MTLTexture
:
let image = MPSImage(texture: myTexture, featureChannels: 4)
3。这个 mipmap 图像会比通过自定义过滤器手动创建金字塔更快吗?
几乎可以肯定。 Metal Performance Shaders 针对每一代设备进行了调整,并具有许多优化执行速度和能源使用的启发式算法。
我想使用 MPSImageGaussianPyramid
但我对 Metal 的用法和 mipmap 还很陌生。我想用滤镜制作图像金字塔,用于图像处理技术。
根据我能够收集到的信息,MPSImageGaussianPyramid
创建了一个 mipmapped 图像,但是在我的代码中我很难确保我正确地看到了输出。是否有正确使用此过滤器的示例?我的问题是:
应用过滤器后如何访问 mipmap 图像?
是否可以将mipmapped图像复制到另一个图像进行处理?
这个 mipmap 图像会比通过自定义过滤器手动创建金字塔更快吗?
谢谢,我稍后会提供一些我无法开始工作的示例代码。
一般使用 MPS 内核,特别是图像金字塔过滤器的一些建议:
- 如果您要多次使用内核,缓存它并重复使用它,而不是每次需要编码时都创建一个内核。
- 考虑在下采样时将内核的
edgeMode
属性 设置为.clamp
,因为越界采样(如高斯金字塔在第一步中所做的那样)将 return 默认为黑色并引入人为的暗像素。 - 编码高斯金字塔内核时,始终使用 "in-place" 方法,而不提供后备分配器:
kernel.encode(commandBuffer: commandBuffer, inPlaceTexture: &myTexture)
正如您所注意到的,运行 图像金字塔内核将结果放入正在下采样的纹理的可用 mip 级别中。这意味着您提供的纹理应该已经分配了您想要填充的尽可能多的 mip 级别。因此,您应该确保用于创建纹理的描述符具有适当的 mipmapLevelCount
(这是由 texture2DDescriptorWithPixelFormat
便捷方法确保的,并且可以通过使用 .allocateMipmaps
选项间接控制MTKTextureLoader
).
假设您现在知道如何对内核进行编码并在纹理中获得所需的结果,下面是您问题的一些答案:
1.如何在应用过滤器后访问 mipmap 图像?
您可以在使用具有 mip 过滤器的采样器进行渲染时在着色器中隐式使用 mipmap,或者您可以通过传递 lod_option
类型的参数从特定的 mip 级别显式采样 level
到 sample
函数:
constexpr sampler mySampler(coord::normalized, filter::linear, mip_filter::linear);
float4 color = myTexture.sample(mySampler, texCoords, level(selectedLod))
这适用于计算内核和渲染函数。如果您想从单个 mip 级别进行采样而不是使用三线性 mip 过滤,请使用 nearest
的 mip 过滤器或舍入 selected LOD。
2。是否可以将 mipmap 图像复制到另一个图像进行处理?
由于图像金字塔内核下采样的纹理必须已经具有 .pixelFormatView
使用标志,因此您可以在混合纹理上创建 纹理视图 selects 一个或多个 mip 级别。例如,如果你想 select 第一个和更高的 mip 级别(降低基本级别),你可以这样做:
let textureView = myTexture.makeTextureView(pixelFormat: myTexture.pixelFormat,
textureType: myTexture.textureType,
levels: Range<Int>(uncheckedBounds: (1, myTexture.mipmapLevelCount)),
slices: Range<Int>(uncheckedBounds: (0, 1)))
您还可以使用 blit 命令编码器从一个纹理复制到另一个纹理,指定要包含的 mip 级别。如果您想回收较低 mip 级别使用的内存,这允许您释放原始纹理。
如果您想使用处理图像而不是纹理的 API,您可以用 MPSImage
包裹 MTLTexture
:
let image = MPSImage(texture: myTexture, featureChannels: 4)
3。这个 mipmap 图像会比通过自定义过滤器手动创建金字塔更快吗?
几乎可以肯定。 Metal Performance Shaders 针对每一代设备进行了调整,并具有许多优化执行速度和能源使用的启发式算法。