-
Notifications
You must be signed in to change notification settings - Fork 452
DDS I O Functions
DirectXTex |
---|
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
Returns the TexMetadata structure from a .DDS
file.
HRESULT GetMetadataFromDDSMemory( const void* pSource, size_t size,
DDS_FLAGS flags, TexMetadata& metadata );
HRESULT GetMetadataFromDDSFile( const wchar_t* szFile,
DDS_FLAGS flags, TexMetadata& metadata );
HRESULT GetMetadataFromDDSMemoryEx( const void* pSource, size_t size,
DDS_FLAGS flags, TexMetadata& metadata,
DDSMetaData* ddPixelFormat );
HRESULT GetMetadataFromDDSFileEx( const wchar_t* szFile,
DDS_FLAGS flags, TexMetadata& metadata,
DDSMetaData* ddPixelFormat );
Loads a .DDS
file (including performing any necessary legacy conversions).
HRESULT LoadFromDDSMemory( const void* pSource, size_t size,
DDS_FLAGS flags, TexMetadata* metadata, ScratchImage& image );
HRESULT LoadFromDDSFile( _In_z_ const wchar_t* szFile,
DDS_FLAGS flags, TexMetadata* metadata, ScratchImage& image );
HRESULT LoadFromDDSMemoryEx( const void* pSource, size_t size,
DDS_FLAGS flags, TexMetadata* metadata,
DDSMetaData* ddPixelFormat, ScratchImage& image );
HRESULT LoadFromDDSFileEx( const wchar_t* szFile,
DDS_FLAGS flags, TexMetadata* metadata,
DDSMetaData* ddPixelFormat, ScratchImage& image );
Saves a single image or a set of images to a .DDS
file.
HRESULT SaveToDDSMemory( const Image& image, DDS_FLAGS flags,
Blob& blob );
HRESULT SaveToDDSMemory( const Image* images, size_t nimages,
const TexMetadata& metadata, DDS_FLAGS flags, Blob& blob );
HRESULT SaveToDDSFile( const Image& image, DDS_FLAGS flags,
const wchar_t* szFile );
HRESULT SaveToDDSFile( const Image* images, size_t nimages,
const TexMetadata& metadata, DDS_FLAGS flags, const wchar_t* szFile );
Helper functions for creating your own 'magic value' + DDS_HEADER
structure. The smallest valid header is 128 bytes. The "DX10" extended header is 148 bytes. If pDestination
is nullptr, it will return the amount of memory required.
HRESULT EncodeDDSHeader( const TexMetadata& metadata, DDS_FLAGS flags,
void* pDestination, size_t maxsize,
size_t& required);
For the load functions, the metadata parameter can be nullptr as this information is also available in the returned ScratchImage.
The flags parameter is one of the DDS_FLAGS
below. By default use DDS_FLAGS_NONE
.
The Ex versions of the metadata and load functions return the original DDS pixel format via the optional ddPixelFormat
parameter. This will always be the "DX10" extended version for non-legacy DDS files which can be evaluated using the DDSMetaData::IsDX10 helper method.
Use caution when examining the values of the
DDSMetaData
structure as they come directly from the file. The ddPixelFormat.size parameter can be either a 0 or 32 depending on the original writer of the file header.
Keep in mind that the original pixel format is subject to numerous conversions and options so the
DXGI_FORMAT
value returned should always be used to interpret the returned image instead of the originalDDPIXELFORMAT
structure information.
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
-
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_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 if expansion would be required. -
DDS_FLAGS_NO_R10B10G10A2_FIXUP
- By default, the loader uses a work-around for a long-standing issue with the D3DXDDS
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'. See this blog post for more information. -
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_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 inHRESULT_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_PERMISSIVE
is used for loading some variants of DDS files that have unusual values in the header. For example, the Unreal Tournament 2004 game has a writer that uses a value of '0' instead of '32' as the size of theDDPIXELFORMAT
structure. Some files even use '24'. In both cases, the full header data size is correct. In other cases, the mipcount in the header is set to a value that is too large for the actual size of the top-level image. This flag allows these variant legacy DX9 DDS files to be loaded instead of rejected as malformed. -
DDS_FLAGS_IGNORE_MIPS
is used to load only the first mip-level from a DDS file even if it specifies a mipchain. This is useful for loading some otherwise invalid files that are missing data. -
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 savingDDS
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. -
DDS_FLAGS_FORCE_DX9_LEGACY
- When savingDDS
files, never use the 'DX10' header extension. This will return a failure if it can't encode the metadata using legacy DX9 headers. -
DDS_FLAGS_ALLOW_LARGE_FILES
- When readingDDS
files, the codec will check if the sizes exceed known Direct3D hardware limitations (larger than 16k texture dimension for example) and return a failure if the resource is too large to be supported. For tools scenarios expected to process large images on the CPU (likely using x64 native memory sizes), you can use this flag to skip the additional bounds checks. Even with this enabled, however, theDDS
file format is limited to 4 GB.
By default, DDS format content that maps directly to a DXGI format is returned as such.
D3DFMT | DXGI |
---|---|
D3DFMT_A8B8G8R8 | DXGI_FORMAT_R8G8B8A8_UNORM |
D3DFMT_A2B10G10R10* | DXGI_FORMAT_R10G10B10A2_UNORM |
D3DFMT_G16R16 | DXGI_FORMAT_R16G16_UNORM |
D3DFMT_A8 | DXGI_FORMAT_A8_UNORM |
D3DFMT_Q8W8V8U8 | DXGI_FORMAT_R8G8B8A8_SNORM |
D3DFMT_V16U16 | DXGI_FORMAT_R16G16_SNORM |
D3DFMT_V8U8 | DXGI_FORMAT_R8G8_SNORM |
"DXT1" | DXGI_FORMAT_BC1_UNORM |
"DXT2" | DXGI_FORMAT_BC2_UNORM + TEX_ALPHA_MODE_PREMULTIPLIED |
"DXT3" | DXGI_FORMAT_BC2_UNORM |
"DXT4" | DXGI_FORMAT_BC3_UNORM + TEX_ALPHA_MODE_PREMULTIPLIED |
"DXT5" | DXGI_FORMAT_BC3_UNORM |
"ATI1" "BC4U" |
DXGI_FORMAT_BC4_UNORM |
"BC4S" | DXGI_FORMAT_BC4_SNORM |
"ATI2" "BC5U" |
DXGI_FORMAT_BC5_UNORM |
"BC5S" | DXGI_FORMAT_BC5_SNORM |
"RGBG" | DXGI_FORMAT_R8G8_B8G8_UNORM |
"GRGB" | DXGI_FORMAT_G8R8_G8B8_UNORM |
"YUY2" | DXGI_FORMAT_YUY2 |
D3DFMT_A16B16G16R16 | DXGI_FORMAT_R16G16B16A16_UNORM |
D3DFMT_Q16W16V16U16 | DXGI_FORMAT_R16G16B16A16_SNORM |
D3DFMT_R16F | DXGI_FORMAT_R16_FLOAT |
D3DFMT_G16R16F | DXGI_FORMAT_R16G16_FLOAT |
D3DFMT_A16B16G16R16F | DXGI_FORMAT_R16G16B16A16_FLOAT |
D3DFMT_R32F | DXGI_FORMAT_R32_FLOAT |
D3DFMT_G32R32F | DXGI_FORMAT_R32G32_FLOAT |
D3DFMT_A32B32G32R32F | DXGI_FORMAT_R32G32B32A32_FLOAT |
"DX10" | DDS_HEADER_DXT10.dxgiFormat |
D3DFMT | DXGI | DDS_FLAGS_FORCE_RGB |
---|---|---|
D3DFMT_A8R8G8B8 | DXGI_FORMAT_B8G8R8A8_UNORM | DXGI_FORMAT_R8G8B8A8_UNORM |
D3DFMT_X8R8G8B8 | DXGI_FORMAT_B8G8R8X8_UNORM | DXGI_FORMAT_R8G8B8A8_UNORM |
D3DFMT | DXGI | DDS_FLAGS_EXPAND_LUMINANCE |
---|---|---|
D3DFMT_A8L8 | DXGI_FORMAT_R8G8_UNORM | DXGI_FORMAT_R8G8B8A8_UNORM |
D3DFMT_L16 | DXGI_FORMAT_R16_UNORM | DXGI_FORMAT_R16G16B16A16_UNORM |
D3DFMT_L8 | DXGI_FORMAT_R8_UNORM | DXGI_FORMAT_R8G8B8A8_UNORM |
D3DFMT | DXGI | DDS_FLAGS_NO_16BPP |
---|---|---|
D3DFMT_A1R5G5B5 | DXGI_FORMAT_B5G5R5A1_UNORM | DXGI_FORMAT_R8G8B8A8_UNORM |
D3DFMT_R5G6B5 | DXGI_FORMAT_B5G6R5_UNORM | DXGI_FORMAT_R8G8B8A8_UNORM |
D3DFMT_A4R4G4B4 | DXGI_FORMAT_B4G4R4A4_UNORM | DXGI_FORMAT_R8G8B8A8_UNORM |
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 for writing is to prefer to use 'legacy' DirectDraw pixel formats when possible.
Many older Direct3D 9 formats that do not directly map to DXGI formats are converted at load-time.
D3DFMT | Conversion |
---|---|
D3DFMT_R8G8B8 | DXGI_FORMAT_R8G8B8A8_UNORM (α=1) |
D3DFMT_X8B8G8R8 | DXGI_FORMAT_R8G8B8A8_UNORM (α=1) |
D3DFMT_A2R10G10B10* | DXGI_FORMAT_R10G10B10A2_UNORM |
D3DFMT_X1R5G5B5 | DXGI_FORMAT_B5G5R5A1_UNORM |
D3DFMT_A8R3G3B2 | DXGI_FORMAT_R8G8B8A8_UNORM |
D3DFMT_R3G3B2 | DXGI_FORMAT_R8G8B8A8_UNORM (α=1) |
D3DFMT_P8 | DXGI_FORMAT_R8G8B8A8_UNORM (α=1) |
D3DFMT_A8P8 | DXGI_FORMAT_R8G8B8A8_UNORM |
D3DFMT_A4L4 | DXGI_FORMAT_B4G4R4A4_UNORM |
D3DFMT_UYVY | DXGI_FORMAT_YUY2 |
There's no DXGI format equivalent or obvious conversion for
D3DFMT_CxV8U8
,D3DFMT_L6V5U5
,D3DFMT_X8L8V8U8
, orD3DFMT_A2W10V10U10
.
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.
File access and permissions (Windows Runtime apps)
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);
}
});
});
}
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
All content and source code for this package are subject to the terms of the MIT License.
This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.
- Universal Windows Platform apps
- Windows desktop apps
- Windows 11
- Windows 10
- Windows 8.1
- Xbox One
- Xbox Series X|S
- Windows Subsystem for Linux
- x86
- x64
- ARM64
- Visual Studio 2022
- Visual Studio 2019 (16.11)
- clang/LLVM v12 - v18
- GCC 10.5, 11.4, 12.3
- MinGW 12.2, 13.2
- CMake 3.20
DirectX Tool Kit for DirectX 11