Repository navigation
MipMapCount == 0 ? #43
Description
Activity
Adding to this I have also noticed the DDS_HEADER.dwCaps DDSCAPS_MIPMAP flag. DirectXTexDDS.cpp sets this flag if dwMipMapCount is > 1, a truly mipmapped texture, while it basically always sets DDS_HEADER_FLAGS_MIPMAP and sets DDS_HEADER.dwMipMapCount to 1 or more.
The
DDSfile format is not particularly well specified. I have made sure the basics are on MSDN, but it's largely a matter of trying to match "What does the legacyD3DX9,D3DX10, and/orD3DX11library do?". In some places where the original behavior was a little lose, I tried to be a bit more consistent with DirectXTex.In the original
D3DX9code it writes DDS headers as follows:DDS_HEADER Header; memset(&Header, 0x00, sizeof(DDS_HEADER)); Header.dwSize = sizeof(DDS_HEADER); Header.dwFlags = DDS_DDSD_HEIGHT | DDS_DDSD_WIDTH | DDS_DDSD_PIXELFORMAT | DDS_DDSD_CAPS; Header.dwHeight = (DWORD) m_uHeight; Header.dwWidth = (DWORD) m_uWidth; Header.ddpf = pFormatDDPF->ddpf; Header.dwCaps = DDS_CAPS_TEXTURE; if(pFormatDDPF->ddpf.dwFlags & (DDS_DDPF_ALPHAPIXELS | DDS_DDPF_ALPHA)) Header.dwCaps |= DDS_CAPS_ALPHA; if(pFormatDDPF->ddpf.dwFlags & (DDS_DDPF_PALETTEINDEXED8)) Header.dwCaps |= DDS_CAPS_PALETTE; if(m_pMip) { Header.dwFlags |= DDS_DDSD_MIPMAPCOUNT; Header.dwMipMapCount = (DWORD) uMipLevels; Header.dwCaps |= DDS_CAPS_COMPLEX | DDS_CAPS_MIPMAP; } if(m_pFace) { Header.dwCaps |= DDS_CAPS_COMPLEX; Header.dwCaps2 |= DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALLFACES; } if(m_uDepth > 1) { Header.dwFlags |= DDS_DDSD_DEPTH; Header.dwDepth = (DWORD) m_uDepth; Header.dwCaps2 |= DDS_CAPS2_VOLUME; }When reading DDS files,
D3DX9does this with respect to the mipmaps (it readsdwMipMapCountwhether or not the flags includedDDS_DDSD_MIPMAPCOUNT, treating 0 as 1).// Grok levels UINT cMipLevels; cMipLevels = (UINT) pHeader->dwMipMapCount; if(0 == cMipLevels) cMipLevels = 1Therefore that's the behavior I implemented for DirectXTex.
The writing code was rewritten for
D3DX10(and carried forward toD3DX11) to add theDX10extension header but it does the same basic thing. Here's writing a DDS header (you'll note it doesn't bother settingDDS_DDSD_MIPMAPCOUNTat all).ZeroMemory(&fileHeader, sizeof(fileHeader)); fileHeader.dwMagic = MAKEFOURCC('D', 'D', 'S', ' '); fileHeader.header.ddpf = pFormat->ddpf; fileHeader.header.dwCaps = DDS_CAPS_TEXTURE; if (m_cMipmaps > 1) fileHeader.header.dwCaps |= DDS_CAPS_MIPMAP; fileHeader.header.dwFlags |= DDS_DDSD_HEIGHT | DDS_DDSD_WIDTH; fileHeader.header.dwWidth = m_Width; fileHeader.header.dwHeight = m_Height; fileHeader.header.dwLinearSize = m_Stride; fileHeader.header.dwDepth = m_Depth; fileHeader.header.dwMipMapCount = m_cMipmaps; fileHeader.header.dwSize = sizeof(DDS_HEADER); switch(m_ResType) { case D3D10_RESOURCE_DIMENSION_TEXTURE3D: fileHeader.header.dwFlags |= DDS_DDSD_DEPTH; fileHeader.header.dwCaps |= DDS_CAPS_COMPLEX; fileHeader.header.dwCaps2 |= DDS_CAPS2_VOLUME; break; case D3D10_RESOURCE_DIMENSION_TEXTURE2D: if (m_bIsCubemap) { fileHeader.header.dwCaps |= DDS_CAPS_COMPLEX; fileHeader.header.dwCaps2 |= DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALLFACES; } break; case D3D10_RESOURCE_DIMENSION_TEXTURE1D: break; default: VNASSERT(0); break; }The
D3DX10andD3DX11header parsing code is the same as it was inD3DX9with respect to the mipmapcount.The DirectXTex
texconvbehavior is also based on the legacy DirectX SDK command-line tool of the same name, which is why it defaults to generating all mipmaps (i.e.-m 0) when writing out aDDSfile.Great! Thank you for the thorough response, Chuck. It's very appreciated.
This is a question.
When converting textures to DDS using texconv, if you don't want mipmaps, you must specify -m 1. If you specify -m 0, the entire chain is generated and saved.
In the wild it is not uncommon to find DDS' which do not set DDS_HEADER_FLAGS_MIPMAP, and which set dwMipMapCount to 0. DirectXTex seems to want to force the behaviour of always setting that flag, and always having a non-zero value for dwMipMapCount
In DirectXTexDDS.cpp, in DecodeDDSHeader, if dwMipMapCount is 0, it is forced to 1. Then, in _EncodeDDSHeader, if dwMipMapCount is > 0, the DDS_HEADER_FLAGS_MIPMAP flag is set.
Should I take it as read, then, that mipmap-less (no flag, and dwMipMapCount == 0) is a deprecated DDS configuration?