【问题标题】:Mipmap sampler in Metal compute kernel (not vertex or fragment shader)Metal 计算内核中的 Mipmap 采样器(不是顶点或片段着色器)
【发布时间】:2018-01-16 02:45:30
【问题描述】:

我有一个源纹理 (480x480),它是在 mipmapped 设置为 true 的情况下创建的(错误检查已删除到这篇文章中),还有一个目标纹理 (100x100):

// source texture
var textureDescriptor = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: MTLPixelFormat.r8Unorm, width: Int(480), height: Int(480), mipmapped: true)
textureDescriptor.usage = .unknown // .shaderWrite .shaderRead
srcTexture = metalDevice!.makeTexture(descriptor: textureDescriptor)
// Dest texture
textureDescriptor = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: MTLPixelFormat.r8Unorm, width: Int(100), height: Int(100), mipmapped: false)
textureDescriptor.usage = .shaderWrite
destTexture = metalDevice!.makeTexture(descriptor: textureDescriptor)

采样器已定义:

let samplerDescriptor = MTLSamplerDescriptor()
samplerDescriptor.magFilter = .linear
samplerDescriptor.minFilter = .linear
samplerDescriptor.rAddressMode = .clampToZero
samplerDescriptor.sAddressMode = .clampToZero
samplerDescriptor.tAddressMode = .clampToZero
samplerDescriptor.normalizedCoordinates = true
textureSampler = metalDevice!.makeSamplerState(descriptor: samplerDescriptor)

我用图像填充了 src 纹理。

然后生成mipmap:

let blitEncoder = metalCommandBuffer!.makeBlitCommandEncoder()
blitEncoder!.pushDebugGroup("Dispatch mipmap kernel")
blitEncoder!.generateMipmaps(for: srcTexture!);
blitEncoder!.popDebugGroup()
blitEncoder!.endEncoding()

并在同一个命令缓冲区中,运行调整大小内核:

let computeEncoder = metalCommandBuffer!.makeComputeCommandEncoder()
computeEncoder!.pushDebugGroup("Dispatch resize image kernel")
computeEncoder!.setComputePipelineState(resizeImagePipeline)
computeEncoder!.setTexture(srcTexture, index: 0)
computeEncoder!.setTexture(destTexture, index: 1)
computeEncoder!.setSamplerState(textureSampler, index: 0)
let threadGroupCount = MTLSizeMake(20, 10, 1)
let threadGroups = MTLSizeMake(destTexture!.width / threadGroupCount.width, destTexture!.height / threadGroupCount.height, 1)
computeEncoder!.dispatchThreadgroups(threadGroups, threadsPerThreadgroup: threadGroupCount)
computeEncoder!.popDebugGroup()
computeEncoder!.endEncoding()

计算内核是(记住,这不是一个片段着色器,它会自动知道如何设置 mipmap 细节级别):

kernel void resizeImage(
texture2d<half, access::sample> sourceTexture [[texture(0)]],
texture2d<half, access::write> destTexture [[texture(1)]],
sampler samp [[sampler(0)]],
uint2 gridPosition [[thread_position_in_grid]])
{
float2 srcSize = float2(sourceTexture.get_width(0),
sourceTexture.get_height(0));
float2 destSize = float2(destTexture.get_width(0),
destTexture.get_height(0));
float2 sourceCoords = float2(gridPosition) / destSize;
/*+ The following attempts all produced a pixelated image
(no edges smoothed out like a fragment shader would)
half4 color = sourceTexture.sample(samp, sourceCoords);
float lod = srcSize.x / destSize.x;
float lod = 0.0;
float lod = 1.0;
float lod = 2.0;
float lod = 3.0;
float lod = 4.0;
float lod = 4.5;
float lod = 5.0;
float lod = 5.5;
*/
float lod = 6.0;
half4 color = sourceTexture.sample(samp, sourceCoords, level(lod));
destTexture.write(color, gridPosition);
}

无论设置什么 lod,我都会得到完全相同的像素化结果。为什么 mipmapping 不起作用? 感谢您提供的任何帮助。

【问题讨论】:

    标签: swift metal compute-shader mipmaps


    【解决方案1】:

    如果您想选择(或偏向)一个 LOD,您的采样器必须指定一个 mip 过滤器(不同于 minmag 过滤器):

    samplerDescriptor.mipFilter = .nearest
    

    在这种情况下使用 .nearest 只会捕捉到最近的 LOD 并使用您似乎正在寻找的双线性过滤从中采样。您还可以指定.linear,它将使用三线性过滤在两个最接近的级别之间进行插值。

    【讨论】:

      猜你喜欢
      • 2019-01-24
      • 2019-07-31
      • 1970-01-01
      • 2018-04-02
      • 2011-05-24
      • 1970-01-01
      • 2018-02-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多