Skip to content

DDS I O Functions

Chuck Walbourn edited this page Dec 3, 2018 · 13 revisions

These functions perform file I/O for .DDS files. These functions support many legacy Direct3D 9 .DDS files and all Direct3D 10.x/11.x era "DX10" extension .DDS files

GetMetadataFromDDSMemory, GetMetadataFromDDSFile

Returns the TexMetadata structure from a .DDS file.

HRESULT GetMetadataFromDDSMemory( const void* pSource, size_t size,
    DWORD flags, TexMetadata& metadata );

HRESULT GetMetadataFromDDSFile( const wchar_t* szFile,
    DWORD flags, TexMetadata& metadata );

LoadFromDDSMemory, LoadFromDDSFile

Loads a .DDS file (including performing any necessary legacy conversions).

HRESULT LoadFromDDSMemory( const void* pSource, size_t size,
    DWORD flags, TexMetadata* metadata, ScratchImage& image );

HRESULT LoadFromDDSFile( _In_z_ const wchar_t* szFile,
    DWORD flags, TexMetadata* metadata, ScratchImage& image );

SaveToDDSMemory, SaveToDDSFile

Saves a single image or a set of images to a .DDS file.

HRESULT SaveToDDSMemory( const Image& image, DWORD flags,
    Blob& blob );

HRESULT SaveToDDSMemory( const Image* images, size_t nimages,
    const TexMetadata& metadata, DWORD flags, Blob& blob );

HRESULT SaveToDDSFile( const Image& image, DWORD flags,
     const wchar_t* szFile );

HRESULT SaveToDDSFile( const Image* images, size_t nimages,
    const TexMetadata& metadata, DWORD flags, const wchar_t* szFile );

Parameters

For the load functions, the metadata parameter can be nullptr as this information is also available in the returned ScratchImage.

Examples

This is a simple loading example. A DDS file can potentially include any kind of Direct3D resource in any DXGI format, so the TexMetadata info is needed to understand the full content of the file.

TexMetadata info;
auto image = std::make_unique<ScratchImage>();
HRESULT hr = LoadFromDDSFile( L"TEXTURE.DDS",
    DDS_FLAGS_NONE, &info, *image );
if ( FAILED(hr) )
    // error

When saving a DDS file, it can contain one or more images (mipmaps, arrays, volumes, cubemaps, etc.). Therefore, the writer needs the TexMetadata info to know how to interpret the image set.

const Image* img = image->GetImages();
assert( img );
size_t nimg = image->GetImageCount();
assert( nimg > 0 );
HRESULT hr = SaveToDDSFile( img, nimg, image->GetMetadata(),
     DDS_FLAGS_NONE, L"NEW_TEXTURE.DDS" );
if ( FAILED(hr) )
    // error

You can also save data directly from memory without using the intermediate ScratchImage at all. This example assumes a single 2D image is being written out.

Image img;
img.width = /*<width of pixel data>*/;
img.height = /*<height of pixel data>*/;
img.format = /*<any DXGI format>*/;
img.rowPitch = /*<number of bytes in a scanline of the source data>*/;
img.slicePitch = /*<number of bytes in the entire 2D image>*/;
img.pixels = /*<pointer to pixel data>*/;
HRESULT hr = SaveToDDSFile( img, DDS_FLAGS_NONE, L"NEW_TEXTURE.DDS" );
if ( FAILED(hr) )
    // error

Related Flags

  • DDS_FLAGS_NONE is the default

  • DDS_FLAGS_LEGACY_DWORD is used for loading some legacy Direct3D 8 era 24bpp .DDS files that use the non-standard DWORD alignment instead of BYTE. There's no reliable way to determine this from the file, so this requires trial-and-error.

  • DDS_FLAGS_BAD_DXTN_TAILS is used for loading some legacy Direct3D 8 era DXTn (aka BC1, BC2, BC3) .DDS files. These older files have partial blocks for mipmap surfaces smaller than 4x4. Using this flag, the last 4x4 blocks are replicated to the smaller blocks and the slightly shorter file length is tolerated. A normal load that results in HRESULT_FROM_WIN32( ERROR_HANDLE_EOF ) might indicate this scenario. Use of this flag for correctly written DDS files is not recommended. This flag only impacts block-compressed formats.

  • DDS_FLAGS_NO_LEGACY_EXPANSION - By default the loader will expand many legacy Direct3D 9 .DDS files to supported formats. The use of this flag prevents expansions that increase the size of the pixels, and will return a failure instead.

  • DDS_FLAGS_NO_R10B10G10A2_FIXUP - By default, the loader uses a work-around for a long-standing issue with the D3DX DDS file format which reverses the RGB bit-masks for 10:10:10:2 formats. If this flag is used, then the loader instead assumes such data was written 'correctly'.

  • DDS_FLAGS_FORCE_RGB - By default we map many BGR formats directly to DXGI 1.1 formats. Use of this flag forces the use of DXGI 1.0 RGB formats instead for improved Direct3D 10.0/Windows Vista RTM/WDDM 1.0 driver support.

  • DDS_FLAGS_NO_16BPP - By default, 5:6:5, 5:5:5:1, and 4:4:4:4 formats are returned as DXGI 1.2 formats. If this flag is used, the loader will expand these to R8G8B8A8 instead.

  • DDS_FLAGS_EXPAND_LUMINANCE - By default, legacy luminance formats are mapped to the same size formats in DXGI (L8 -> R8_UNORM, L16 -> R16_UNORM, A8L8 -> R8G8_UNORM), but this requires some shader swizzling to replicate the original luminance greyscale behavior (.rrr or .rrrg)--this matches the implementation of DDSTextureLoader. Specifying this flag will instead expand these formats on load and replicate the colors to achieve the proper greyscale without any shader changes, but they will be significantly larger (8:8:8:8 or 16:16:16:16).

  • DDS_FLAGS_FORCE_DX10_EXT - When saving DDS files, the writer tries to use legacy Direct3D 9 .DDS file formats if possible rather than the 'DX10' header extension for better compatibility with older tools. Using this flag, the writer will always generate 'DX10' extension header files which are much faster to parse at load-time. These files are compatible with the legacy D3DX10 or D3DX11 library.

  • DDS_FLAGS_FORCE_DX10_EXT_MISC2 - When saving DDS files, always use the 'DX10' header extension and write miscFlags2 data as needed, if even if the resulting file is not compatible with the legacy D3DX10 or D3DX11 libraries.

Remarks

Many older Direct3D 9 formats that do not directly map to DXGI formats are converted at load-time. For example, D3DFMT_R8G8B8 is always converted to DXGI_FORMAT_R8G8B8A8_UNORM since there is no 24bpp DXGI format.

The 'DX10' header is not supported by D3DX9, older Direct3D 9 era texture tools, or the legacy DirectX SDK DXTex.exe tool. Therefore, the default behavior is to prefer to use 'legacy' DirectDraw pixel formats when possible.

Note that for Direct3D 11.1 video formats, only DXGI_FORMAT_YUY2 is supported by Direct3D 9. Legacy DDS files containing FourCC "UYVY" are converted to YUY2 at load-time.

Windows Store apps

File access and permissions (Windows Runtime apps)

Load

If you wish to load a texture from a file that is specified by the user from a WinRT picker, you will need to copy the file locally to a temporary location before you can use LoadFromDDSFile on it. This is because you either won't have file access rights to the user's file location, or the StorageFile is actually not a local file system path (i.e. it's a URL).

// Using C++/CX (/ZW) and the Parallel Patterns Library (PPL)
create_task(openPicker->PickSingleFileAsync()).then([this](StorageFile^ file)
{
    if (file)
    {
        auto tempFolder = Windows::Storage::ApplicationData::Current->TemporaryFolder;
        create_task(file->CopyAsync( tempFolder, file->Name, NameCollisionOption::GenerateUniqueName )).then([this](StorageFile^ tempFile)
        {
            if ( tempFile )
            {
                HRESULT hr = LoadFromDDSFile( ..., tempFile->Path->Data(), ... );
                DX::ThrowIfFailed(hr);
            }
        });
    });
}

Save

For SaveToDDSFile to succeed, the application must have write access to the destination path. For Windows Store apps, the file access permissions are rather restricted so you'll need to make sure you use a fully qualified path to a valid write folder. A good location to use is the app data folder:

auto folder = Windows::Storage::ApplicationData::Current->LocalFolder;
// use folder->Path->Data() as the path base

If you are going to immediately copy it to another location via StorageFolder, then use the app's temporary folder:

auto folder = Windows::Storage::ApplicationData::Current->TemporaryFolder;
// use folder->Path->Data() as the path base

Further reading

The DDS File Format Lives

DDS Programmer's Guide

You can’t perform that action at this time.