DDSWithoutD3DX Sample Update

Over the past few releases of the DirectX SDK, I’ve been working on updating our documentation for the DDS file format. The DDSWithoutD3DX and DDSWithoutD3DX11 samples in the DirectX SDK (June 2010) release demonstrate the details of interpreting the DDS file format for basic 2D textures and 2D texture arrays for Direct3D 9, Direct3D 10.x, and Direct3D 11. Since the June release, I’ve been expanding the sample to support cubemaps, volume textures, and 1D textures. In the process I also found a number of minor issues with the DDSTextureLoader code and the DDS.H header.

Attached to this post is a ZIP containing an updated DDS.H, DDSTextureLoader.cpp, and DDSTextureLoader.h which you can drop into the DDSWithoutD3DX11 sample code in the DirectX SDK (June 2010). Note that the DDSWithoutD3DX sample is very similiar if you are looking to use it with Direct3D 10.x instead of Direct3D 11, although there are some additional complexities when dealing with cubemap arrays which are supported by the Direct3D 10.1 API with D3D10_FEATURE_LEVEL_10_1 hardware, but not the Direct3D 10.0 API or D3D10_FEATURE_LEVEL_10_0 hardware.

Update: A recent inquiry about the DDS file format has brought up an area of common confusion when parsing these files w.r.t. to the pitch alignment of uncompressed pixel data (there are different rules for computing the sizes of block compressed DXT/BC formats and the packed R8G8_B8G8/G8R8_G8B8 pixel formats). The DDS file format always uses byte alignment for the pitch of uncompressed data, but the original DrawDraw structures used to define the format document that the pitch should be DWORD aligned. With many common texture formats and sizes, these computations yield the same results but for 16-bit and 24-bit per pixel formats, these results do not agree.  This is further complicated by the fact that many DDS writers (including D3DX) do not set a PITCH value in the header, so DDS readers have to compute one from assumptions. The recommendation is to use byte-alignment (which is what the DDSWithoutD3DX samples do), but you may want to support a legacy compatabilty flag on your DDS reader that will compute DWORD aligned pitch values should you encounter content that uses the incorrect “DWORD” alignment. You can also side-step this issue by prefering the use of block compressed (DXT/BC) or 32-bit per pixel formats–16-bit and 24-bit per pixel formats are not supported by Direct3D 10.x or 11 in any case. It is also important than when copying the data from the DDS structure into a Direct3D resource that you do not assume the pitch values will match, so you must support copying line-by-line (or use initData for Direct3D 10.x & 11 which is what the DDSWithoutD3DX sample demonstrates).

Update 2: I found a minor problem with legacy cubemap DDS files. I was over-validating legacy volume map DDS files for having the ‘right’ flags set in dwCaps2, which are often missing.

Update 3: Minor issue, but BC4 formats should be 4 BitsPerPixel. Doesn’t affect the functionality because GetSurfaceInfo has special handling for BC4 formats already, but in the interest of avoiding future cut & paste issues I’ve fixed it in another refresh of the source.

See also The DDS File Format Lives and DDS Update and 10:10:10:2 problems

Update 4: For Direct3D 11 only applications, consider using the DDSTextureLoader included in DirectXTK instead.

DDSTextureLoader Updates August

Comments (3)

  1. Dear Sir!

    It looks like this loader would incorrectly interpret L8 textures.

    Such textures have a proper pattern, but invalid colors.

    Great blog!

    Thank you very much.

  2. walbourn says:

    There is no direct luminance equivalent in DXGI. Therefore L8 is loaded as DXGI_FORMAT_R8_UNORM, L16 is loaded as DXGI_FORMAT_R16_UNORM, and L8A8 is loaded as DXGI_FORMAT_R8G8_UNORM becuase those are the only formats that match the original data.

    To render these 'correctly' you'll need to have a pixel shader with a swizzle that replicates the channels as appropriate: for L8, you would use '.rrr'. For L16 you would use ".rrr", for L8A8 you'd use ".rrrg"

    Otherwise you should use some offline tool to convert the L8, L16, L8A8 cases to some other format with the RGB values replicated. That would expand the size of your resource though so a shader-based solution is a lot more efficient.

  3. I highly appreciate the answer.