Consider a situation where there are 3 different buffers describing a particular mesh piece: vBuffer
, nBuffer
, iBuffer
(vertices, normals, and indices) which equate to totalBufferSize
in aggregate.
I want to save these 3 buffers to the same default heap (D3D12_HEAP_TYPE_DEFAULT). I know I still need to use an upload heap (D3D12_HEAP_TYPE_UPLOAD) as an intermediary but I can't figure out how to eliminate extra copies.
Currently my code (which works) does the following:
const D3D12_HEAP_PROPERTIES defaultHeapProperties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT);
const D3D12_HEAP_PROPERTIES uploadHeapProperties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD);
...
const CD3DX12_RESOURCE_DESC resourceDescV = CD3DX12_RESOURCE_DESC::Buffer(totalBufferSize);
DX::ThrowIfFailed(device->CreateCommittedResource(
&defaultHeapProperties,
D3D12_HEAP_FLAG_NONE,
&resourceDescV,
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
IID_PPV_ARGS(meshPart.m_mainBuffer.ReleaseAndGetAddressOf())));
DX::ThrowIfFailed(device->CreateCommittedResource(
&uploadHeapProperties,
D3D12_HEAP_FLAG_NONE,
&resourceDescV,
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(meshPart.m_uploadBuffer.ReleaseAndGetAddressOf())));
uint8_t * bufferStart{};
const CD3DX12_RANGE readRange(0, 0);
DX::ThrowIfFailed(meshPart.m_uploadBuffer->Map(0, &readRange, reinterpret_cast<void **>(&bufferStart)));
// Can these be eliminated?
uint32_t offset{};
std::memcpy(bufferStart, vBuffer.data, vBuffer.totalSize);
offset += vBuffer.totalSize;
std::memcpy(bufferStart + offset, nBuffer.data, nBuffer.totalSize);
offset += nBuffer.totalSize;
std::memcpy(bufferStart + offset, iBuffer.data, iBuffer.totalSize);
D3D12_SUBRESOURCE_DATA bufferData{};
bufferData.pData = bufferStart;
bufferData.RowPitch = totalBufferSize;
bufferData.SlicePitch = totalBufferSize;
UpdateSubresources<1>(commandList, meshPart.m_mainBuffer.Get(), meshPart.m_uploadBuffer.Get(), 0, 0, 1, &bufferData);
CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(meshPart.m_mainBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
commandList->ResourceBarrier(1, &barrier);
However, I'm trying to figure out if I can eliminate those std::memcpy calls. All examples of UpdateSubresources I've seen do not explicitly Map+memcpy into the upload buffer. They just set D3D12_SUBRESOURCE_DATA.pData
directly.
I tried calling using UpdateSubresources<3>
and passing in an array of D3D12_SUBRESOURCE_DATA, each pointing to the beginning of my mesh buffers, but the validation layer didn't like that and threw an exception.
Is it possible to upload all 3 buffers in one step here -- without the explicit Map and memcpy steps?