13 ID3D12CommandQueue* queue,
size_t size,
17 assert(device !=
nullptr);
19 m_commandQueue = queue;
20 m_uploader = uploader;
23 ConfigureFromBufferType(type);
27 D3D12_HEAP_TYPE heapType,
28 D3D12_RESOURCE_STATES resourceState)
29 :
BufferBase(), m_heapType(heapType), m_resourceState(resourceState) {
30 assert(device !=
nullptr);
37 m_device(std::move(other.m_device)),
38 m_commandQueue(other.m_commandQueue),
39 m_uploader(other.m_uploader),
40 m_buffer(std::move(other.m_buffer)),
41 m_heapType(other.m_heapType),
42 m_resourceState(other.m_resourceState),
43 m_currentState(other.m_currentState),
44 m_mappedData(other.m_mappedData),
45 m_constantData(std::move(other.m_constantData)),
46 m_frameSerial(other.m_frameSerial),
47 m_frameAddress(other.m_frameAddress) {
48 other.m_commandQueue =
nullptr;
49 other.m_uploader =
nullptr;
50 other.m_mappedData =
nullptr;
51 other.m_frameSerial = 0;
52 other.m_frameAddress = 0;
60 BufferBase::operator=(std::move(other));
61 m_device = std::move(other.m_device);
62 m_commandQueue = other.m_commandQueue;
63 m_uploader = other.m_uploader;
64 m_buffer = std::move(other.m_buffer);
65 m_heapType = other.m_heapType;
66 m_resourceState = other.m_resourceState;
67 m_currentState = other.m_currentState;
68 m_mappedData = other.m_mappedData;
69 m_constantData = std::move(other.m_constantData);
70 m_frameSerial = other.m_frameSerial;
71 m_frameAddress = other.m_frameAddress;
73 other.m_commandQueue =
nullptr;
74 other.m_uploader =
nullptr;
75 other.m_mappedData =
nullptr;
76 other.m_frameSerial = 0;
77 other.m_frameAddress = 0;
87void DirectX12Buffer::ConfigureFromBufferType(
BufferType type)
91 m_heapType = D3D12_HEAP_TYPE_DEFAULT;
92 m_resourceState = D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
96 m_heapType = D3D12_HEAP_TYPE_DEFAULT;
97 m_resourceState = D3D12_RESOURCE_STATE_INDEX_BUFFER;
101 m_heapType = D3D12_HEAP_TYPE_UPLOAD;
102 m_resourceState = D3D12_RESOURCE_STATE_GENERIC_READ;
106 m_heapType = D3D12_HEAP_TYPE_DEFAULT;
107 m_resourceState = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
111 m_heapType = D3D12_HEAP_TYPE_DEFAULT;
112 m_resourceState = D3D12_RESOURCE_STATE_COMMON;
117D3D12_RESOURCE_DESC DirectX12Buffer::CreateBufferDesc()
const
119 D3D12_RESOURCE_DESC desc = {};
120 desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
124 desc.DepthOrArraySize = 1;
126 desc.Format = DXGI_FORMAT_UNKNOWN;
127 desc.SampleDesc.Count = 1;
128 desc.SampleDesc.Quality = 0;
129 desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
130 desc.Flags = D3D12_RESOURCE_FLAG_NONE;
140 if (!m_device ||
Size == 0)
146 D3D12_HEAP_PROPERTIES heapProps = {};
147 heapProps.Type = m_heapType;
148 heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
149 heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
150 heapProps.CreationNodeMask = 1;
151 heapProps.VisibleNodeMask = 1;
153 auto desc = CreateBufferDesc();
157 D3D12_RESOURCE_STATES initialState =
158 (data && m_heapType == D3D12_HEAP_TYPE_DEFAULT)
159 ? D3D12_RESOURCE_STATE_COPY_DEST
161 m_currentState = initialState;
162 HRESULT hr = m_device->CreateCommittedResource(
164 D3D12_HEAP_FLAG_NONE,
168 IID_PPV_ARGS(&m_buffer));
179 if (m_heapType == D3D12_HEAP_TYPE_DEFAULT) {
181 UploadToDefaultHeap(data, size);
184 Update(
const_cast<void*
>(data), size);
192bool DirectX12Buffer::UploadToDefaultHeap(
const void* data,
size_t dataSize) {
196 if (!local.
Initialize(m_device.Get(), m_commandQueue))
return false;
200 ID3D12Resource* staging =
nullptr;
202 if (!mapped)
return false;
203 memcpy(mapped, data, dataSize);
205 ID3D12GraphicsCommandList* commandList = uploader->
GetCommandList();
210 if (m_currentState != D3D12_RESOURCE_STATE_COPY_DEST) {
211 D3D12_RESOURCE_BARRIER barrier = {};
212 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
213 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
214 barrier.Transition.pResource = m_buffer.Get();
215 barrier.Transition.StateBefore = m_currentState;
216 barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
217 barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
219 commandList->ResourceBarrier(1, &barrier);
222 commandList->CopyBufferRegion(m_buffer.Get(), 0, staging, 0, dataSize);
225 if (m_resourceState != D3D12_RESOURCE_STATE_COPY_DEST) {
226 D3D12_RESOURCE_BARRIER barrier = {};
227 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
228 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
229 barrier.Transition.pResource = m_buffer.Get();
230 barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
231 barrier.Transition.StateAfter = m_resourceState;
232 barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
234 commandList->ResourceBarrier(1, &barrier);
237 m_currentState = m_resourceState;
239 if (uploader == &local) local.
Flush();
260 m_constantData.clear();
276 if (m_heapType != D3D12_HEAP_TYPE_UPLOAD && m_heapType != D3D12_HEAP_TYPE_READBACK)
279 HRESULT hr = m_buffer->Map(0,
nullptr, &m_mappedData);
294 m_buffer->Unmap(0,
nullptr);
296 m_mappedData =
nullptr;
303 if (!m_buffer || size >
Size || !data)
310 if (m_constantData.size() < size) m_constantData.resize(size);
311 memcpy(m_constantData.data(), data, size);
317 if (m_heapType == D3D12_HEAP_TYPE_UPLOAD) {
319 memcpy(m_mappedData, data, size);
321 UploadToDefaultHeap(data, size);
330struct DeferredObject {
331 Microsoft::WRL::ComPtr<ID3D12Pageable> object;
332 uint64_t fenceValue = 0;
335std::vector<Microsoft::WRL::ComPtr<ID3D12Pageable>> s_untagged;
336std::vector<DeferredObject> s_tagged;
340 Microsoft::WRL::ComPtr<ID3D12Pageable>
object) {
341 if (
object) s_untagged.push_back(std::move(
object));
345 for (
auto&
object : s_untagged)
346 s_tagged.push_back({std::move(
object), fenceValue});
351 std::erase_if(s_tagged, [completedValue](
const DeferredObject& d) {
352 return d.fenceValue <= completedValue;
Backend-agnostic GPU buffer: vertex, index, constant, or resource view target.
void StoreCPUShadowCopy(const void *data, size_t size)
Copies up to 128 bytes into the inline shadow-copy storage, clamping oversized input.
void * GetData() override
DirectX12Buffer(ID3D12Device *device, ID3D12CommandQueue *queue, size_t size, BufferType type, DirectX12UploadContext *uploader=nullptr)
Uploads go through the shared uploader when given, else they block.
static void TagDeferredCleanup(uint64_t fenceValue)
Stamps everything queued since the last call with its retire value.
~DirectX12Buffer() override
bool Initialize(void *Data) override
bool Map() override
Maps the buffer for CPU writes (upload-heap buffers only).
static void DeferCleanup(Microsoft::WRL::ComPtr< ID3D12Pageable > object)
Queues a GPU object for release once the frame that used it is done.
static void ProcessDeferredCleanup(uint64_t completedValue)
Releases every queued object whose fence value has completed.
DirectX12Buffer & operator=(const DirectX12Buffer &)=delete
void * AllocateStaging(uint64_t size, ID3D12Resource **resource)
Returns a mapped upload buffer that lives until the open batch is done.
ID3D12GraphicsCommandList * GetCommandList()
Returns the open copy command list, starting a new batch if needed.
bool Initialize(ID3D12Device *device, ID3D12CommandQueue *queue)
Creates the fence used to track submitted batches.
void Flush()
Submits and blocks until every batch has finished on the GPU.
Backend-facing rendering layer shared by the four graphics backends.
BufferType
GPU buffer usage kind, drives backend binding flags and layout.
Root namespace for everything the engine exposes.