Search code examples
iosmetalsampletexture2dmipmaps

Write pixel data to certain mipmap level of texture2d


As you might know, Metal Shading Language allows few ways to read pixel data from texture2d in the kernel function. It can be either simple read(short2 coord) or sample(float2 coord, [different additional parameters]). But I noticed, that when it comes to writing something into texture, there's only write method.

And the problem here is that sample method allows to sample from certain mipmap level which is very convenient. Developer just needs to create a sampler with mipFilter and use normalized coordinates.

But what if I want to write into certain mipmap level of the texture? The thing is that write method doesn't have mipmap parameter the way sample method has and I cannot find any alternative for that.

I'm pretty sure there should be a way to choose mipmap level for writing data to the texture, because Metal Performance Shaders framework has solutions where mipmaps of textures are being populated.

Thanks in advance!


Solution

  • You can do this with texture views.

    The purpose of texture views is to reinterpret the contents of a base texture by selecting a subset of its levels and slices and potentially reading/writing its pixels in a different (but compatible) pixel format.

    The -newTextureViewWithPixelFormat:textureType:levels:slices: method on the MTLTexture protocol returns a new instance of id<MTLTexture> that has the first level specified in the levels range as its base mip level. By creating one view per mip level you wish to write to, you can "target" each level in the original texture.

    For example, to create a texture view on the second mip level of a 2D texture, you might call the method like this:

    id<MTLTexture> viewTexture = 
        [baseTexture newTextureViewWithPixelFormat:baseTexture.pixelFormat
                                       textureType:baseTexture.textureType
                                            levels:NSMakeRange(1, 1)
                                            slices:NSMakeRange(0, 1)];
    

    When binding this new texture as an argument, its mip level 0 will correspond to mip level 1 of its base texture. You can therefore use the ordinary texture write function in a shader to write to the selected mip level:

    myShaderTexture.write(color, coords);