-
Notifications
You must be signed in to change notification settings - Fork 411
DDSTextureLoader
DirectXTK |
---|
This is a simple light-weight DirectDraw Surface (.dds
) file loader. This is the traditional texture file container for DirectX. This loader performs no pixel data conversions (see Remarks for more details). This is ideal for runtime usage, and supports the full complement of Direct3D 12 texture resources (1D, 2D, volume maps, cubemaps, mipmap levels, texture arrays, cubemap arrays, Block Compressed formats, etc.). It supports both legacy DDPIXELFORMAT
and 'DX10' DXGI_FORMAT
extension header format .dds
files.
A standalone version is included in DirectXTex for Direct3D 9, Direct3D 11, and Direct3D 12. Be sure to add both the
h
andcpp
file to your project.
To load legacy files that require runtime format conversion (i.e. 24bpp RGB files), use DirectXTex or convert them with the texconv utility.
To load FourCC "XBOX" variant
.DDS
files, use XboxDDSTextureLoader, which is supported by the xtexconv utility.
Related tutorial: Sprites and textures
#include <DDSTextureLoader.h>
Loads a .DDS
file assuming the image of the file is located in a memory buffer. Creates a Direct3D 12 resource. The texture data upload is queued to the provided ResourceUploadBatch.
HRESULT CreateDDSTextureFromMemory(
ID3D12Device* device,
ResourceUploadBatch& resourceUpload,
const uint8_t* ddsData,
size_t ddsDataSize,
ID3D12Resource** texture,
bool generateMipsIfMissing = false,
size_t maxsize = 0,
DDS_ALPHA_MODE* alphaMode = nullptr,
bool* isCubeMap = nullptr);
Loads a .DDS
file from disk and creates a Direct3D 12 resource. The texture data upload is queued to the provided ResourceUploadBatch.
HRESULT CreateDDSTextureFromFile(
ID3D12Device* device,
ResourceUploadBatch& resourceUpload,
const wchar_t* szFileName,
ID3D12Resource** texture,
bool generateMipsIfMissing = false,
size_t maxsize = 0,
DDS_ALPHA_MODE* alphaMode = nullptr,
bool* isCubeMap = nullptr);
These versions provide explicit control over the created resource's flags (the standard version default to D3D12_RESOURCE_FLAG_NONE
).
There is also a loadFlags parameter. The flags are DDS_LOADER_DEFAULT
, DDS_LOADER_FORCE_SRGB
, DDS_LOADER_IGNORE_SRGB
, DDS_LOADER_MIP_AUTOGEN
, and DDS_LOADER_MIP_RESERVE
.
HRESULT CreateDDSTextureFromMemoryEx(
ID3D12Device* device,
ResourceUploadBatch& resourceUpload,
const uint8_t* ddsData,
size_t ddsDataSize,
size_t maxsize,
D3D12_RESOURCE_FLAGS resFlags,
DDS_LOADER_FLAGS loadFlags,
ID3D12Resource** texture,
DDS_ALPHA_MODE* alphaMode = nullptr,
bool* isCubeMap = nullptr);
HRESULT CreateDDSTextureFromFileEx(
ID3D12Device* device,
ResourceUploadBatch& resourceUpload,
const wchar_t* szFileName,
size_t maxsize,
D3D12_RESOURCE_FLAGS resFlags,
DDS_LOADER_FLAGS loadFlags,
ID3D12Resource** texture,
DDS_ALPHA_MODE* alphaMode = nullptr,
bool* isCubeMap = nullptr);
The DDS_LOADER_FORCE_SRGB
flag provides an option for working around gamma issues with content that is in the sRGB or similar color space but is not encoded explicitly as an SRGB format. This will force the resource format be one of the of DXGI_FORMAT_*_SRGB
formats if it exist. Note that no pixel data conversion takes place. The DDS_LOADER_IGNORE_SRGB
flag does the opposite; it will force the resource format to not have the _*_SRGB
version.
The DDS_LOADER_MIP_AUTOGEN
is the same as the generateMipsIfMissing parameter for the non-Ex versions which creates space for the additional mipchains and then auto-generates them from the base image.
The DDS_LOADER_MIP_RESERVE
flag is used to create the extra mipchains but leave them uninitialized. This is useful if your application will do the auto-generation through it's own implementation.
The
loadFlags
parameter was previouslybool forceSRGB
andbool generateMipsIfMissing
.
The Create
loaders rely on the ResourceUploadBatch class to manage the GPU upload. For applications where you want to handle the upload directly, you can make use of:
HRESULT LoadDDSTextureFromMemory(
ID3D12Device* d3dDevice,
const uint8_t* ddsData,
size_t ddsDataSize,
ID3D12Resource** texture,
std::vector<D3D12_SUBRESOURCE_DATA>& subresources,
size_t maxsize = 0,
DDS_ALPHA_MODE* alphaMode = nullptr,
bool* isCubeMap = nullptr);
HRESULT LoadDDSTextureFromFile(
ID3D12Device* d3dDevice,
const wchar_t* szFileName,
ID3D12Resource** texture,
std::unique_ptr<uint8_t[]>& ddsData,
std::vector<D3D12_SUBRESOURCE_DATA>& subresources,
size_t maxsize = 0,
DDS_ALPHA_MODE* alphaMode = nullptr,
bool* isCubeMap = nullptr);
HRESULT LoadDDSTextureFromMemoryEx(
ID3D12Device* d3dDevice,
const uint8_t* ddsData,
size_t ddsDataSize,
size_t maxsize,
D3D12_RESOURCE_FLAGS resFlags,
DDS_LOADER_FLAGS loadFlags,
ID3D12Resource** texture,
std::vector<D3D12_SUBRESOURCE_DATA>& subresources,
DDS_ALPHA_MODE* alphaMode = nullptr,
bool* isCubeMap = nullptr);
HRESULT LoadDDSTextureFromFileEx(
ID3D12Device* d3dDevice,
const wchar_t* szFileName,
size_t maxsize,
D3D12_RESOURCE_FLAGS resFlags,
DDS_LOADER_FLAGS loadFlags,
ID3D12Resource** texture,
std::unique_ptr<uint8_t[]>& ddsData,
std::vector<D3D12_SUBRESOURCE_DATA>& subresources,
DDS_ALPHA_MODE* alphaMode = nullptr,
bool* isCubeMap = nullptr);
These functions create the texture resource and return the initialization data in ddsData
which is pointed into by the vector of subresources
. The ddsData
object "owns" the memory, but the exact offsets into the image data for each miplevel/array items/volume slice are returned in subresources
.
Note these functions don't support mipmaps generation, but do support reserving space for mipmaps.
The
Create
functions are not included in the stand-alone copy of DDSTextureLoader12 that is included with DirectXTex, only theLoad
functions.
For cubemaps, this is indicated by the return value of isCubeMap since there's no DirectX resource flag related to cubemaps vs. standard texture arrays in Direct3D 12.
For auto-gen mipmaps for missing or partial mipchains, set the generateMipsIfMissing parameter to true or loadFlags to DDS_LOADER_MIP_AUTOGEN
. Note that automatic mipmap generation for Direct3D 12 is not supported by the runtime or driver, and is implemented in ResourceUploadBatch.
If maxsize parameter non-zero, then all mipmap levels larger than the maxsize are ignored before creating the Direct3D 12 resource. This allows for load-time scaling. If '0', then if the attempt to create the Direct3D 12 resource fails and there are mipmaps present, it will retry assuming a maxsize of D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION
(16384).
The last optional parameter alphaMode is a pointer to return the alpha mode of the .DDS
file, or it can be nullptr. This can be one of the following values to return information about the alpha channel if present in the file:
-
DDS_ALPHA_MODE_UNKNOWN
(0) - This is the default for most.DDS
files if the specific metadata isn't present, and it's up to the application to know if it's really something else. Viewers should assume the alpha channel is intended for 'normal' alpha blending. -
DDS_ALPHA_MODE_STRAIGHT
(1) - This indicates that the alpha channel if present is assumed to be using 'straight' alpha. Viewers should use the alpha channel with 'normal' alpha blending. -
DDS_ALPHA_MODE_PREMULTIPLIED
(2) - This indicates the alpha channel if present is premultiplied alpha. This information is only present if the file is written using the latest version of the "DX10" extended header, or if the file is BC2/BC3 with the "DXT2"/"DXT4" FourCC which are explicitly stored as premultiplied alpha. Viewers should use the alpha channel with premultiplied alpha blending. -
DDS_ALPHA_MODE_OPAQUE
(3) - This indicates that the alpha channel if present is fully opaque for all pixels. Viewers can assume there is no alpha blending. -
DDS_ALPHA_MODE_CUSTOM
(4) - This indicates the alpha channel if present does not contain transparency (neither straight or premultiplied alpha) and instead is encoding some other channel of information. Viewers should not use the alpha channel for blending, and should instead view it as a distinct image channel.
For the Create
functions that utilize ResourceUploadBatch, the texture resources will be in the D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
state if using a Direct command queue.
If using a Compute or Copy command queue, the resource state will be left in D3D12_RESOURCE_STATE_COPY_DEST
.
Requests to generate mips are ignored if the upload batch is set to use a Copy command queue since that does not support the required compute shader functionality.
To render all resources need to be in the proper state. With Windows PC, common state promotion will typically fix this up. For Xbox One where this feature is optional or for other usage scenarios, you need to insert resource barriers for transitioning the resource state.
TransitionResource(commandList, tex.Get(),
D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
This loads a texture, and ResourceUploadBatch performs the upload.
ComPtr<ID3D12Resource> tex;
ResourceUploadBatch resourceUpload(device);
resourceUpload.Begin();
DX::ThrowIfFailed(
CreateDDSTextureFromFile(device, resourceUpload, L"texture.dds",
tex.ReleaseAndGetAddressOf())
);
// Upload the resources to the GPU.
auto uploadResourcesFinished = resourceUpload.End(m_deviceResources->GetCommandQueue());
// Wait for the upload thread to terminate
uploadResourcesFinished.wait();
If handling your own upload, use the Load
functions:
std::unique_ptr<uint8_t[]> ddsData;
std::vector<D3D12_SUBRESOURCE_DATA> subresources;
DX::ThrowIfFailed(
LoadDDSTextureFromFile(device, L"texture.dds", tex.ReleaseAndGetAddressOf(),
ddsData, subresources));
const UINT64 uploadBufferSize = GetRequiredIntermediateSize(tex.Get(), 0,
static_cast<UINT>(subresources.size()));
// Create the GPU upload buffer.
CD3DX12_HEAP_PROPERTIES heapProps(D3D12_HEAP_TYPE_UPLOAD);
auto desc = CD3DX12_RESOURCE_DESC::Buffer(uploadBufferSize);
ComPtr<ID3D12Resource> uploadRes;
DX::ThrowIfFailed(
device->CreateCommittedResource(
&heapProps,
D3D12_HEAP_FLAG_NONE,
&desc,
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(uploadRes.GetAddressOf())));
UpdateSubresources(commandList, tex.Get(), uploadRes.Get(),
0, 0, static_cast<UINT>(subresources.size()), subresources.data());
auto barrier = CD3DX12_RESOURCE_BARRIER::Transition(tex.Get(),
D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
commandList->ResourceBarrier(1, &barrier);
DX::ThrowIfFailed(commandList->Close());
m_deviceResources->GetCommandQueue()->ExecuteCommandLists(1,
CommandListCast(&commandList));
In order to actually render with this texture, you must create a texture heap descriptor and associate it with the loaded resource. Often this is done using the DirectXHelpers function CreateShaderResourceView
:
CreateShaderResourceView(device, tex.Get(),
resourceDescriptors->GetCpuHandle(Descriptors::MyTexture));
Then to draw you use resourceDescriptors->GetGpuHandle(Descriptors::MyTexture)
and set the descriptor heap with SetDescriptorHeaps
. See DescriptorHeap for more information.
This code is based on the legacy DirectX SDK sample DDSWithoutD3DX texture loading code for Direct3D 9 / Direct3D 11.
Auto-gen mipmaps are only supported for 2D non-array textures. If the format is unsupported for auto-gen mipmaps by the device or if a copy command queue was provided to the ResourceUploadBatch, then the request for autogen mips via generateMipsIfMissing or DDS_LOADER_MIP_AUTOGEN
will be ignored.
When applying maxsize and 'stripping' mipmaps on a BC compressed texture, the function may fail if the appropriately sized mipchain is not a muliple-of-4 in width & height as required by Direct3D. The only way to ensure that any given mip meets this requirement is if the top-most level is both a multiple-of-4 and a power-of-2.
Does not support loading depth/stencil formats which are planar for DirectX 12, but not for DirectX 11.
DDSTextureLoader performs no run-time conversions. Therefore, it only loads DDS content that directly maps to a DXGI format:
D3DFMT | DXGI |
---|---|
D3DFMT_A8B8G8R8 | DXGI_FORMAT_R8G8B8A8_UNORM |
D3DFMT_A8R8G8B8 | DXGI_FORMAT_B8G8R8A8_UNORM |
D3DFMT_X8R8G8B8 | DXGI_FORMAT_B8G8R8X8_UNORM |
D3DFMT_A2B10G10R10* | DXGI_FORMAT_R10G10B10A2_UNORM |
D3DFMT_G16R16 | DXGI_FORMAT_R16G16_UNORM |
D3DFMT_A1R5G5B5 | DXGI_FORMAT_B5G5R5A1_UNORM |
D3DFMT_R5G6B5 | DXGI_FORMAT_B5G6R5_UNORM |
D3DFMT_A4R4G4B4 | DXGI_FORMAT_B4G4R4A4_UNORM |
D3DFMT_A8L8 | DXGI_FORMAT_R8G8_UNORM |
D3DFMT_L16 | DXGI_FORMAT_R16_UNORM |
D3DFMT_L8 | DXGI_FORMAT_R8_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" "DXT3" |
DXGI_FORMAT_BC2_UNORM |
"DXT4" "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 |
If there is not a direct mapping to a DXGI supported format, the function fails. You can make use of the DirectXTex library or texconv
tool to convert legacy Direct3D9 .DDS
files to a supported format. Legacy formats which require conversion include:
D3DFMT | Notes |
---|---|
D3DFMT_R8G8B8 | (24bpp RGB) - Use a 32bpp format |
D3DFMT_X8B8G8R8 | (32bpp RGBX) - Use BGRX, BGRA, or RGBA |
D3DFMT_A2R10G10B10 | (BGRA 10:10:10:2) - Use RGBA 10:10:10:2 |
D3DFMT_X1R5G5B5 | (BGR 5:5:5) - Use BGRA 5:5:5:1 or BGR 5:6:5 |
D3DFMT_A8R3G3B2 D3DFMT_R3G3B2 |
(BGR 3:3:2) - Expand to a supported format |
D3DFMT_P8 D3DFMT_A8P8 |
(8-bit palette) - Expand to a supported format |
D3DFMT_A4L4 | (Luminance 4:4) - Expand to a supported format |
D3DFMT_UYVY | (YUV 4:2:2 16bpp) - Swizzle to YUY2 |
There's no DXGI format equivalent or obvious conversion for
D3DFMT_CxV8U8
,D3DFMT_L6V5U5
,D3DFMT_X8L8V8U8
, orD3DFMT_A2W10V10U10
.
Partial cubemaps (i.e. .DDS
files without all six faces defined) are not supported by Direct3D 12.
For information on using DDSTextureLoader from a Windows Store app or a Universal Windows Platform (UWP) app, see here
If the HRESULT
is a success, but you are still having problems using the texture, the next step in debugging is to examine details about the loaded texture. You can do this with the following code:
ComPtr<ID3D12Resource> res;
HRESULT hr = CreateDDSTextureFromFile(d3dDevice.Get(), resourceUpload, L"SEAFLOOR.DDS",
res.GetAddressOf());
DX::ThrowIfFailed(hr);
auto desc = res->GetDesc();
desc.Dimension
is D3D12_RESOURCE_DIMENSION_TEXTURE1D
, D3D12_RESOURCE_DIMENSION_TEXTURE2D
, or D3D12_RESOURCE_DIMENSION_TEXTURE3D
.
desc.Width
is the texture width in pixels (of the top most mip level)
desc.Height
is the texture height in pixels (of the top most mip level) for 2D and 3D textures
desc.DepthOrArraySize
is the number of textures in the array (or 1 if this not an array) for 1D and 2D textures. It is the texture depth (of the top most level) for 3D textures.
desc.MipLevels
is the number of mip levels (or 1 if there are no mips)
desc.Format
is the DXGI format of the texture resource
This function loads both traditional and FourCC "DX10" variant .DDS
files.
The Create
functions require a ResourceUploadBatch so they only support submitting content from one thread at a time. You can load on multiple threads if you create a separate ResourceUploadBatch instance per command-list.
The Load
functions are fully asynchronous.
Work Submission in Direct3D 12
Uploading Texture Data Through Buffers
Linear-Space Lighting (i.e. Gamma)
Chapter 24. The Importance of Being Linear, GPU Gems 3
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
- Xbox One
- Xbox Series X|S
- x86
- x64
- ARM64
- Visual Studio 2022
- Visual Studio 2019 (16.11)
- clang/LLVM v12 - v18
- MinGW 12.2, 13.2
- CMake 3.20