Article

Restricting Access to Specific Mipmaps

Set the range of mipmap levels that a sampler can access.

Overview

Sometimes, you want to control the specific mipmap levels that the sampler can read from. For example, you might do this when you haven't provided texture data for all of the mipmaps, and you want to constrain access to the mipmaps that have data. You can configure a sampler to sample from a subset of the texture's mipmaps.

Limit the Sampler when You Create it in Your Metal App

When you configure the MTLSamplerDescriptor object, set the lodMinClamp and lodMaxClamp properties to the range of permitted values. For example, the following code creates a sampler that ignores mipmaps 0, 1, and 2:

MTLSamplerDescriptor *descriptor = [MTLSamplerDescriptor new];
descriptor.minFilter = MTLSamplerMinMagFilterLinear;
descriptor.magFilter = MTLSamplerMinMagFilterLinear;
descriptor.mipFilter = MTLSamplerMipFilterLinear;

descriptor.lodMinClamp = 3.0f;

id<MTLSamplerState> sampler = [_device newSamplerStateWithDescriptor: descriptor];

Limit the Sampler when You Create it in Your Shader

If you create your sampler in your shader, specify the range of mipmap levels that it can access:

constexpr sampler s(filter::linear, mip_filter::linear, lod_clamp(3.0f, MAXFLOAT))

Control Mipmap Selection when You Sample the Texture

On some device objects, you can apply additional constraints on the sample operation itself, passing in dynamic information about which mipmap levels can be sampled.

Not all device objects support clamping at the moment the texture is sampled. Before using this functionality, test the device object for support:

Boolean supportsLODCalculation = [_device supportsFamily:MTLGPUFamilyMac1];

In your shader, call one of the variants of the sample function that takes additional level-of-detail parameters. For example, the following code limits sampling to a specific level or lower in the mipmap chain. The minimum level is passed in as a shader parameter, and used when the shader samples the texture:

fragment float4
samplingShader(RasterizerData in [[stage_in]],
               texture2d<half> colorTexture [[ texture(0) ]],
               constant float &minimumLOD [[buffer(0)]])
{
    constexpr sampler textureSampler (mag_filter::linear,
                                      min_filter::linear,
                                      mip_filter::linear);

    const half4 colorSample = colorTexture.sample(textureSampler,
                                                  in.textureCoordinate,
                                                  min_lod_clamp(minimumLOD));
    
    return float4(colorSample);
}

The Metal Shading Language Guide describes other options for controlling mipmap selection. You can choose to sample a specific mipmap level, specify a minimum mipmap level, bias the selection process that the hardware chooses, or use some combination of these options.

See Also

Mipmap Access

Determining Which Mipmaps the GPU Will Try to Access

Get information at runtime about mipmaps the GPU will sample.

Dynamically Adjusting Texture Level of Detail

Defer generating or loading larger mipmaps until that level of detail is needed.