-
Notifications
You must be signed in to change notification settings - Fork 411
ResourceUploadBatch
This provides a helper for uploading resources such as textures to GPU memory. This class also handles automatic generation of mipmaps using shaders on the GPU.
Related tutorial: Sprites and textures
#include "ResourceUploadBatch.h"
This helper is typically used during load and setup as follows which ends with a wait to ensure the GPU is ready before rendering is started. You start with a call to Begin, and then queue one or more upload operations. The End method returns a C++11 std::future
which you use to complete the upload asynchronously.
ResourceUploadBatch upload(device);
upload.Begin();
DX::ThrowIfFailed(
CreateDDSTextureFromFile(device, upload, L"mytexture.dds",
tex.ReleaseAndGetAddressOf())
);
spriteBatch = std::make_unique<SpriteBatch>(device, upload, pd);
spriteFont = std::make_unique<SpriteFont>(device, upload,
L"myfont.spritefont",
resourceDescriptors->GetCpuHandle(Descriptors::TextFont),
resourceDescriptors->GetGpuHandle(Descriptors::TextFont));
...
// Upload the resources to the GPU.
auto finish = upload.End(commandQueue);
// Wait for the upload thread to terminate
finish.wait();
You can also use the class to upload data to your own manually created resources which need to be in the D3D12_RESOURCE_STATE_COPY_DEST
state. The helper supports queuing a resource barrier to transition the state after uploading using the Transition method.
ResourceUploadBatch upload(device);
upload.Begin();
auto desc = CD3DX12_RESOURCE_DESC(
D3D12_RESOURCE_DIMENSION_TEXTURE2D,
D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT,
c_texture_size, c_texture_size, 1, 1,
DXGI_FORMAT_R8G8_SNORM,
1, 0,
D3D12_TEXTURE_LAYOUT_UNKNOWN, D3D12_RESOURCE_FLAG_NONE);
CD3DX12_HEAP_PROPERTIES defaultHeapProperties(D3D12_HEAP_TYPE_DEFAULT);
DX::ThrowIfFailed(device->CreateCommittedResource(
&defaultHeapProperties,
D3D12_HEAP_FLAG_NONE,
&desc,
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
IID_GRAPHICS_PPV_ARGS(tex.ReleaseAndGetAddressOf())));
D3D12_SUBRESOURCE_DATA initData = { mydata, c_texture_size * 2, 0 };
upload.Upload(tex.Get(), 0, &initData, 1);
upload.Transition(tex.Get(),
D3D12_RESOURCE_STATE_COPY_DEST,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
...
// Upload the resources to the GPU.
auto finish = upload.End(commandQueue);
// Wait for the upload thread to terminate
finish.wait();
The data submitted to Upload is copied to a temporary
D3D12_HEAP_TYPE_UPLOAD
resource which is released when the upload is complete, so you don't need to keep the source buffer active beyond the call toUpload
.
DirectX 11 supported auto-generation of mipmaps for specific formats. This feature relied entirely on the driver, so the quality of auto-generated mipmaps was highly variable. DirectX 12 does not implement this feature, leaving it as an "exercise to the implementer". DirectX Tool Kit does this with ResourceUploadBatch
.
To use it, you must create the texture with reserved mipmaps in the D3D12_RESOURCE_STATE_COPY_DEST
state, load the image data into top-level mip, transition the resource to the D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
state, and then queue the mipmap generation using GenerateMips as follows:
ResourceUploadBatch upload(device);
upload.Begin();
auto desc = CD3DX12_RESOURCE_DESC(
D3D12_RESOURCE_DIMENSION_TEXTURE2D,
D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT,
c_texture_size, c_texture_size, 1, c_mipmap_count,
DXGI_FORMAT_R8G8B8A8_UNORM,
1, 0,
D3D12_TEXTURE_LAYOUT_UNKNOWN, D3D12_RESOURCE_FLAG_NONE);
CD3DX12_HEAP_PROPERTIES defaultHeapProperties(D3D12_HEAP_TYPE_DEFAULT);
DX::ThrowIfFailed(device->CreateCommittedResource(
&defaultHeapProperties,
D3D12_HEAP_FLAG_NONE,
&desc,
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
IID_GRAPHICS_PPV_ARGS(tex.ReleaseAndGetAddressOf())));
D3D12_SUBRESOURCE_DATA initData = { mydata, c_texture_size * 4, 0 };
upload.Upload(tex.Get(), 0, &initData, 1);
upload.Transition(tex.Get(),
D3D12_RESOURCE_STATE_COPY_DEST,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
upload.GenerateMips(tex.Get());
...
// Upload the resources to the GPU.
auto finish = upload.End(commandQueue);
// Wait for the upload thread to terminate
finish.wait();
The GenerateMips function uses a DirectCompute shader to perform the mip-generation using bi-linear interpolation. The resource format must be UAV compatible (RGBA, F16, F32, etc.), BGRA, BGRX, RGBA sRGB, or BGRA sRGB. Otherwise a C++ exception is generated.
Note: High-quality mipmap generation is best done offline, stored in
DDS
files, and then loaded in full at a runtime using DDSTextureLoader.
Each ResourceUploadBatch instance only supports submitting content from one thread at a time, but you can simultaneously submit content on multiple threads if you create a separate ResourceUploadBatch instance per command-list.
Work Submission in Direct3D 12
Resource uploading is done for 'static' resources where the data is going to reside in GPU memory and be reused. For 'dynamic' data explicit uploading is not needed as the memory is allocated by GraphicsMemory, is both accessible to CPU and GPU, and will be released once the frame is completed.
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