Tuesday, 27 October 2015

Generating mipmaps for 3D textures

Mip-mapping is very useful, and sometimes we want to generate the mips of a texture in a shader. In DirectX 11 hlsl this is tricky because you can't read from the resource that you're writing to.

For example, you might have a 3D texture that you've filled in with a compute shader. You then want to generate its mipmaps from the original texture. But the ShaderResourceView you created can't be read while you're writing to. It will silently fail - unless you have Direct3D debug output enabled, in which case you'll get a warning.

You probably created the SRV like this:

  D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc;
  ZeroMemory(&srv_desc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
  srv_desc.Format                     = f;
  srv_desc.ViewDimension              = D3D11_SRV_DIMENSION_TEXTURE3D;
  srv_desc.Texture3D.MipLevels        = m;
  srv_desc.Texture3D.MostDetailedMip  = 0;
  d3D11Device->CreateShaderResourceView(texture, &srv_desc,&shaderResourceView);

which means that when you pass it to the hlsl shader, it contains all of the mips from 0 to m-1. What you want instead (or rather, as well), is a SRV for each individual mip:

D3D11_SHADER_RESOURCE_VIEW_DESC mip_srv_desc;
ZeroMemory(&mip_srv_desc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
mip_srv_desc.Format                    = f;
mip_srv_desc.ViewDimension             = D3D11_SRV_DIMENSION_TEXTURE3D;
mip_srv_desc.Texture3D.MipLevels       = 1;
mip_srv_desc.Texture3D.MostDetailedMip = i;
d3D11Device->CreateShaderResourceView(texture, &mip_srv_desc, &mipShaderResourceViews[i]);
Then use these as input to the compute shader.