-
Notifications
You must be signed in to change notification settings - Fork 411
Textures
DirectX 12 textures are typically loaded into video memory which is not necessarily accessible to the CPU. For DirectX Tool Kit for DirectX 12, this is typically done by using the ID3D12Resource
interface and the ResourceUploadBatch helper is used to transfer the texture data from the CPU to the GPU.
The first step is to create an ID3D12Resource
interface. This can be done directly in code or by using the DDSTextureLoader / WICTextureLoader.
// This creates a 1x1 texture in RGBA format
D3D12_RESOURCE_DESC txtDesc = {};
txtDesc.MipLevels = txtDesc.DepthOrArraySize = 1;
txtDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
txtDesc.Width = 1;
txtDesc.Height = 1;
txtDesc.SampleDesc.Count = 1;
txtDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
Microsoft::WRL::ComPtr<ID3D12Resource> texture;
DX::ThrowIfFailed(
device->CreateCommittedResource(
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
D3D12_HEAP_FLAG_NONE,
&txtDesc,
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
IID_GRAPHICS_PPV_ARGS(texture.ReleaseAndGetAddressOf())));
After creating the resource, the texture data needs to be created. It can be done programmatically or by loading from disk or the network. Ideally you load 'fully cooked' textures including mipmaps and formatted in Direct3D specific formats like the Block Compressed formats from DDS
files using DDSTextureLoader. You can load general images using WICTextureLoader. The Create*Texture*
functions will take a ResourceUploadBatch for the next step in the process, while the Load*Texture*
functions return the texture data in system memory instead.
static const uint32_t s_whitePixel = 0xFFFFFFFF;
D3D12_SUBRESOURCE_DATA textureData = {};
textureData.pData = &s_whitePixel;
textureData.RowPitch = txtDesc.Width * 4;
textureData.SlicePitch = txtDesc.Height * txtDesc.Width * 4;
After creating the resource and the texture data, the data needs to be uploaded to the GPU accessible memory for rendering. The ResourceUploadBatch helper can be used to manage one or more uploads in a batch, or it can be done manually using something like the D3DX12 helper UpdateSubresources
using your own D3D12_HEAP_TYPE_UPLOAD
resource.
ResourceUploadBatch resourceUpload(device);
resourceUpload.Begin();
resourceUpload.Upload(texture.Get(), 0, &textureData, 1);
resourceUpload.Transition(
texture.Get(),
D3D12_RESOURCE_STATE_COPY_DEST,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
auto uploadResourcesFinished = resourceUpload.End(m_deviceResources->GetCommandQueue());
uploadResourcesFinished.wait();
The ResourceUploadBatch
helper can also handle the resource barrier to transition from the loading state (D3D12_RESOURCE_STATE_COPY_DEST
) that the original resource was created in to a rendering state (D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
) at the appropriate time. Otherwise you need to do the transition manually.
Once the resource has been created and the data uploaded to the GPU, binding to the rendering pipeline requires a descriptor. All the descriptors are created into one or more heaps. This can be managed using the DescriptorHeap class. Once created, you use an index to reference the descriptor, so it can be useful to manage it with an enum
enum Descriptors
{
Texture,
Count
};
m_resourceDescriptors = std::make_unique<DescriptorHeap>(device,
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE,
Descriptors::Count);
You can use the DirectXHelpers or create the descriptor itself manually.
CreateShaderResourceView(
device,
texture.Get(),
m_resourceDescriptors->GetCpuHandle(Descriptors::Texture));
For more dynamic scenarios like complex models, etc. you can make use of the DescriptorPile class.
In order to render, you must set the descriptor heap to the command list:
ID3D12DescriptorHeap* heaps[] = { m_resourceDescriptors->Heap() };
commandList->SetDescriptorHeaps(_countof(heaps), heaps);
From there, the final step is to use the appropriate descriptor index for your root signature or Effects.
SimpleTexture12 sample for PC, UWP, Xbox One XDK
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