-
Notifications
You must be signed in to change notification settings - Fork 411
WICTextureLoader
DirectXTK |
---|
A Direct3D 12 2D texture loader that uses Windows Imaging Component (WIC) to load a bitmap (BMP
, JPEG
, PNG
, TIFF
, GIF
, HD Photo, or other WIC supported file container), resize if needed, format convert to a standard DXGI format if required, and then create a 2D texture. It can also optionally auto-generate mipmaps.
This loader does not support array textures, 1D textures, 3D volume textures, cubemaps, or cubemap arrays. For these scenarios, use the .DDS
file format and DDSTextureLoader instead.
DDSTextureLoader is recommended for fully "precooked" textures for maximum performance and image quality, but this loader can be useful for creating simple 2D texture from standard image files at runtime.
On Windows 10, you can load simple 2D textures in BC1, BC2, or BC3 pixel format
DDS
files using WIC as there is a basic DDS built-in codec present. All other pixel formats and resource types will fail, and you'll getWINCODEC_ERR_COMPONENTNOTFOUND
on older versions of Windows trying to use WICTextureLoader to loadDDS
files. Use DDSTextureLoader instead.
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.
Related tutorial: Sprites and textures
#include <WICTextureLoader.h>
The library assumes that the client code will have already called CoInitialize
, CoInitializeEx
, or Windows::Foundation::Initialize
as needed by the application before calling any Windows Imaging Component functionality.
For a Universal Windows Platform (UWP) app using /ZW
, the Windows Runtime and COM is initialized by the C/C++ Run-Time. For C++/WinRT applications, this is done by calling winrt::init_apartment();
.
For a classic Windows desktop application you have to do this explicitly:
#if (_WIN32_WINNT >= 0x0A00 /*_WIN32_WINNT_WIN10*/)
Microsoft::WRL::Wrappers::RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);
if (FAILED(initialize))
// error
#else
HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
if (FAILED(hr))
// error
#endif
Loads a WIC-supported bitmap file from a memory buffer. It creates a Direct3D 12 resource from it. The texture data upload is queued to the provided ResourceUploadBatch.
HRESULT CreateWICTextureFromMemory(
ID3D12Device* d3dDevice,
ResourceUploadBatch& resourceUpload,
const uint8_t* wicData,
size_t wicDataSize,
ID3D12Resource** texture,
bool generateMips = false,
size_t maxsize = 0);
Loads a WIC-supported bitmap file from disk, creates a Direct3D 12 resource from it. The texture data upload is queued to the provided ResourceUploadBatch.
HRESULT CreateWICTextureFromFile(
ID3D12Device* d3dDevice,
ResourceUploadBatch& resourceUpload,
const wchar_t* szFileName,
ID3D12Resource** texture,
bool generateMips = false,
size_t maxsize = 0);
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 WIC_LOADER_DEFAULT
, WIC_LOADER_FORCE_SRGB
, WIC_LOADER_IGNORE_SRGB
, WIC_LOADER_SRGB_DEFAULT
, WIC_LOADER_MIP_AUTOGEN
, WIC_LOADER_MIP_RESERVE
, WIC_LOADER_FIT_POW2
, WIC_LOADER_MAKE_SQUARE
, and/or WIC_LOADER_FORCE_RGBA32
.
HRESULT CreateWICTextureFromMemoryEx(
ID3D12Device* d3dDevice,
ResourceUploadBatch& resourceUpload,
const uint8_t* wicData,
size_t wicDataSize,
size_t maxsize,
D3D12_RESOURCE_FLAGS resFlags,
WIC_LOADER_FLAGS loadFlags,
ID3D12Resource** texture);
HRESULT CreateWICTextureFromFileEx(
ID3D12Device* d3dDevice,
ResourceUploadBatch& resourceUpload,
const wchar_t* szFileName,
size_t maxsize,
D3D12_RESOURCE_FLAGS resFlags,
WIC_LOADER_FLAGS loadFlags,
ID3D12Resource** texture);
The WIC_LOADER_FORCE_SRGB
, WIC_LOADER_IGNORE_SRGB
, and WIC_LOADER_SRGB_DEFAULT
flags are detailed below under sRGB.
The WIC_LOADER_MIP_AUTOGEN
is the same as the generateMips parameter for the non-Ex versions which creates space for the additional mipchains and then auto-generates them from the base image.
The WIC_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 WIC_LOADER_FIT_POW2
and/or WIC_LOADER_MAKE_SQUARE
flags can be used to force the image to be resized to a power-of-2 size and/or be made a square texture that has width == height. These flags are most useful for the Direct3D 9 legacy version of WICTextureLoader, but are supported in all versions.
The WIC_LOADER_FORCE_RGBA32
flag is explained under Pixel format conversions.
The
loadFlags
parameter was previouslybool forceSRGB
andbool generateMips
.
The Create
functions 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:
- LoadWICTextureFromMemory
- LoadWICTextureFromFile
- LoadWICTextureFromMemoryEx
- LoadWICTextureFromFileEx
These functions create the texture resource and return the initialization data in decodedData
which is pointed into by subresource
. They don't support mipmaps generation, but do support reserving space for mipmaps.
The
Create
functions are not included in the stand-alone copy of WICTextureLoader12 that is included with DirectXTex, only theLoad
functions.
To automatically generate mipmaps, set the generateMips parameter to true or set loadFlags to WIC_LOADER_MIP_AUTOGEN
. Note that automatic mipmap generation for Direct3D 12 is not supported by the runtime or driver, and is implemented in ResourceUploadBatch.
For all these functions above, the maxsize parameter provides an upper limit on the size of the resulting texture. If given a 0, the functions assume a maximum size of D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION
(16384). If the bitmap file contains a larger image, it will be resized using WIC at load-time to provide scaling.
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 bitmap, and ResourceUploadBatch performs the upload as well as generates mipmaps using a compute shader--non-DDS file formats do not include mipmap chains.
ComPtr<ID3D12Resource> tex;
ResourceUploadBatch resourceUpload(device);
resourceUpload.Begin();
DX::ThrowIfFailed(
CreateWICTextureFromFile(device, resourceUpload, L"texture.bmp",
tex.ReleaseAndGetAddressOf(), true)
);
// 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[]> decodedData;
D3D12_SUBRESOURCE_DATA subresource;
DX::ThrowIfFailed(
LoadWICTextureFromFile(device, L"texture.bmp", tex.ReleaseAndGetAddressOf(),
decodedData, subresource));
const UINT64 uploadBufferSize = GetRequiredIntermediateSize(tex.Get(), 0, 1);
CD3DX12_HEAP_PROPERTIES heapProps(D3D12_HEAP_TYPE_UPLOAD);
auto desc = CD3DX12_RESOURCE_DESC::Buffer(uploadBufferSize);
// Create the GPU upload buffer.
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, 1, &subresource);
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.
Here's a snippet for loading a texture forcing use of DXGI_FORMAT_*_SRGB
via a loader flag, but is otherwise the same as the call above:
DX::ThrowIfFailed(
CreateWICTextureFromFileEx(device, resourceUpload, L"texture.bmp",
0,
D3D12_RESOURCE_FLAG_NONE,
WIC_LOADER_FORCE_SRGB | WIC_LOADER_MIP_AUTOGEN,
tex.ReleaseAndGetAddressOf())
);
-
While there is no explicit 'sRGB' pixel format defined for WIC, the load functions will check for known metadata tags and may return
DXGI_FORMAT_*_SRGB
formats if there are equivalents of the same size and channel configuration available. Setting loadFlags toWIC_LOADER_IGNORE_SRGB
will ignore this metadata.- For PNG, this is indicated by
/sRGB/RenderingIntent
set to 1. - For JPG this is
/app1/ifd/exif/{ushort=40961}
set to 1. - For TIFF this is
/ifd/exif/{ushort=40961}
set to 1.
- For PNG, this is indicated by
-
Setting loadFlags to
WIC_LOADER_FORCE_SRGB
will force conversion of theDXGI_FORMAT
to one ofDXGI_FORMAT_*_SRGB
formats if it exist. This is useful for loading sRGB content for linearly-correct rendering that lacks the metadata tags to indicate sRGB colorspace. Note that no pixel data conversion takes place. -
gAMA
chunks in PNGs are ignored. If thesRGB
chunk is found, it is assumed to be gamma 2.2. -
By default, the lack of explicit 'sRGB' metadata implies the format is linear (i.e. not sRGB). Setting loadFlags to
WIC_LOADER_SRGB_DEFAULT
will reverse this assumption.
WIC has built-in support for doing pixel format conversions.
If the loadFlags include WIC_LOADER_FORCE_RGBA32
, then the result is always a DXGI_FORMAT_R8G8B8A8_UNORM
texture by converting to GUID_WICPixelFormat32bppRGBA
. If WIC_LOADER_FORCE_SRGB
is also set, the result with be set to DXGI_FORMAT_R8G8B8A8_UNORM_SRGB
.
The conversion tables are designed so that they prefer to convert to RGB if a conversion is required as a general preferance for DXGI 1.0 supporting formats supported by WDDM 1.0 drivers. The majority of Direct3D 11 devices actually support BGR DXGI 1.1 formats so we use them when they are the best match. For example, GUID_WICPixelFormat32bppBGRA
loads directly as DXGI_FORMAT_B8G8R8A8_UNORM
, but GUID_WICPixelFormat32bppPBGRA
converts to DXGI_FORMAT_R8G8B8A8_UNORM
.
GUID_WICPixelFormatBlackWhite
is always converted to a greyscale DXGI_FORMAT_R8_UNORM
since DXGI_FORMAT_R1_UNORM
is not supported by Direct3D.
GUID_WICPixelFormat32bppRGBE
is an 8:8:8:8 format, which does not match DXGI_FORMAT_R9G9B9E5_SHAREDEXP
. This WIC pixel format is therefore converted to GUID_WICPixelFormat128bppRGBAFloat
and returns as DXGI_FORMAT_R32G32B32A32_FLOAT
.
If the format is unsupported for auto-gen mipmaps by the device or if a copy command queue was provided to the ResourceUploadBatch, then a request for autogen mips via generateMips or WIC_LOADER_MIP_AUTOGEN
will be ignored.
WICTextureLoader cannot load .TGA
/.HDR
files unless the system has a 3rd party WIC codec installed. You must use the DirectXTex library for TGA
/HDR
file format support without relying on an add-on WIC codec.
Since WIC2 is available on Windows 10, it is always used by DirectX Tool Kit for DirectX 12.
See Windows Imaging Component and Windows 8
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
For information on using WICTextureLoader 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 easily with the following code:
ComPtr<ID3D12Resource> res;
HRESULT hr = CreateWICTextureFromFile( d3dDevice.Get(), resourceUpload, L"LOGO.BMP",
res.GetAddressOf());
DX::ThrowIfFailed(hr);
auto desc = res->GetDesc();
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)
desc.MipLevels
is the number of mip levels (or 1 if there are no mips)
desc.DepthOrArraySize
is the number of textures in the array (or 1 if this not an array)
desc.Format
is the DXGI format of the texture resource
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