Skip to content

WICTextureLoader

Chuck Walbourn edited this page Apr 13, 2020 · 57 revisions

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 get WINCODEC_ERR_COMPONENTNOTFOUND on older versions of Windows trying to use WICTextureLoader to load DDS files. Use DDSTextureLoader instead.

A standalone version is included in the DirectXTex package.

Related tutorial: Sprites and textures

Header

#include <WICTextureLoader.h>

Initialization

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, COINITBASE_MULTITHREADED);
  if (FAILED(hr))
      // error
#endif

Functions

CreateWICTextureFromMemory

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);

CreateWICTextureFromFile

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);

CreateWICTextureFromMemoryEx, CreateWICTextureFromFileEx

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, and WIC_LOADER_IGNORE_SRGB, WIC_LOADER_MIP_AUTOGEN, and WIC_LOADER_MIP_RESERVE.

HRESULT CreateWICTextureFromMemoryEx(
    ID3D12Device* d3dDevice,
    ResourceUploadBatch& resourceUpload,
    const uint8_t* wicData,
    size_t wicDataSize,
    size_t maxsize,
    D3D12_RESOURCE_FLAGS resFlags,
    unsigned int loadFlags,
    ID3D12Resource** texture);

HRESULT CreateWICTextureFromFileEx(
    ID3D12Device* d3dDevice,
    ResourceUploadBatch& resourceUpload,
    const wchar_t* szFileName,
    size_t maxsize,
    D3D12_RESOURCE_FLAGS resFlags,
    unsigned int loadFlags,
    ID3D12Resource** texture);

The DDS_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 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 previously bool forceSRGB and bool generateMips.

Non-upload versions

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 the Load functions.

Parameters

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.

Resource states

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);

Example

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);

// Create the GPU upload buffer.
ComPtr<ID3D12Resource> uploadHeap;
DX::ThrowIfFailed(
    device->CreateCommittedResource(
        &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
        D3D12_HEAP_FLAG_NONE,
        &CD3DX12_RESOURCE_DESC::Buffer(uploadBufferSize),
        D3D12_RESOURCE_STATE_GENERIC_READ,
        nullptr,
        IID_PPV_ARGS(uploadHeap.GetAddressOf())));

UpdateSubresources(commandList, tex.Get(), uploadHeap.Get(),
    0, 0, 1, &subresource);
commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(tex.Get(),
    D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE));

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.

sRGB

  • 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 to WIC_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.
  • Setting loadFlags to WIC_LOADER_FORCE_SRGB will force conversion of the DXGI_FORMAT to one of DXGI_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 the sRGB chunk is found, it is assumed to be gamma 2.2.

Remarks

  • 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.

  • The conversion tables are designed so that they prefer to convert to RGB if a conversion is required. 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.

WIC2

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

Threading model

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

Windows Store apps

For information on using WICTextureLoader from a Windows Store app or a Universal Windows Platform (UWP) app, see here

Further reading

Uploading Texture Data Through Buffers

Linear-Space Lighting (i.e. Gamma)

Chapter 24. The Importance of Being Linear, GPU Gems 3

Gamma-correct rendering

For Use

  • Universal Windows Platform apps
  • Windows desktop apps
  • Windows 11
  • Windows 10
  • Xbox One
  • Xbox Series X|S

Architecture

  • x86
  • x64
  • ARM64

For Development

  • Visual Studio 2022
  • Visual Studio 2019 (16.11)
  • clang/LLVM v12 - v18
  • MinGW 12.2, 13.2
  • CMake 3.20

Related Projects

DirectX Tool Kit for DirectX 11

DirectXMesh

DirectXTex

DirectXMath

Tools

Test Suite

Model Viewer

Content Exporter

DxCapsViewer

See also

DirectX Landing Page

Clone this wiki locally