aboutsummaryrefslogtreecommitdiff
path: root/demo/d3d12/NvCoDx12CircularResourceHeap.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'demo/d3d12/NvCoDx12CircularResourceHeap.cpp')
-rw-r--r--demo/d3d12/NvCoDx12CircularResourceHeap.cpp204
1 files changed, 204 insertions, 0 deletions
diff --git a/demo/d3d12/NvCoDx12CircularResourceHeap.cpp b/demo/d3d12/NvCoDx12CircularResourceHeap.cpp
new file mode 100644
index 0000000..040b159
--- /dev/null
+++ b/demo/d3d12/NvCoDx12CircularResourceHeap.cpp
@@ -0,0 +1,204 @@
+/* Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
+* NVIDIA CORPORATION and its licensors retain all intellectual property
+* and proprietary rights in and to this software, related documentation
+* and any modifications thereto. Any use, reproduction, disclosure or
+* distribution of this software and related documentation without an express
+* license agreement from NVIDIA CORPORATION is strictly prohibited. */
+
+#include "NvCoDx12CircularResourceHeap.h"
+
+namespace nvidia {
+namespace Common {
+
+Dx12CircularResourceHeap::Dx12CircularResourceHeap():
+ m_fence(nullptr),
+ m_device(nullptr),
+ m_blockFreeList(sizeof(Block), __alignof(Block), 16),
+ m_blocks(nullptr)
+{
+ m_back.m_block = nullptr;
+ m_back.m_position = nullptr;
+ m_front.m_block = nullptr;
+ m_front.m_position = nullptr;
+}
+
+Dx12CircularResourceHeap::~Dx12CircularResourceHeap()
+{
+ _freeBlockListResources(m_blocks);
+}
+
+void Dx12CircularResourceHeap::_freeBlockListResources(const Block* start)
+{
+ if (start)
+ {
+ {
+ ID3D12Resource* resource = start->m_resource;
+ resource->Unmap(0, nullptr);
+ resource->Release();
+ }
+ for (Block* block = start->m_next; block != start; block = block->m_next)
+ {
+ ID3D12Resource* resource = block->m_resource;
+ resource->Unmap(0, nullptr);
+ resource->Release();
+ }
+ }
+}
+
+int Dx12CircularResourceHeap::init(ID3D12Device* device, const Desc& desc, Dx12CounterFence* fence)
+{
+ assert(m_blocks == nullptr);
+ assert(desc.m_blockSize > 0);
+
+ m_fence = fence;
+ m_desc = desc;
+ m_device = device;
+
+ return NV_OK;
+}
+
+void Dx12CircularResourceHeap::addSync(uint64_t signalValue)
+{
+ assert(signalValue == m_fence->getCurrentValue());
+ PendingEntry entry;
+ entry.m_completedValue = signalValue;
+ entry.m_cursor = m_front;
+ m_pendingQueue.push_back(entry);
+}
+
+void Dx12CircularResourceHeap::updateCompleted()
+{
+ const uint64_t completedValue = m_fence->getCompletedValue();
+ while (!m_pendingQueue.empty())
+ {
+ const PendingEntry& entry = m_pendingQueue.front();
+ if (entry.m_completedValue <= completedValue)
+ {
+ m_back = entry.m_cursor;
+ m_pendingQueue.pop_front();
+ }
+ else
+ {
+ break;
+ }
+ }
+}
+
+Dx12CircularResourceHeap::Block* Dx12CircularResourceHeap::_newBlock()
+{
+ D3D12_RESOURCE_DESC desc;
+
+ desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
+ desc.Alignment = 0;
+ desc.Width = m_desc.m_blockSize;
+ desc.Height = 1;
+ desc.DepthOrArraySize = 1;
+ desc.MipLevels = 1;
+ desc.Format = DXGI_FORMAT_UNKNOWN;
+ desc.SampleDesc.Count = 1;
+ desc.SampleDesc.Quality = 0;
+ desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
+ desc.Flags = D3D12_RESOURCE_FLAG_NONE;
+
+ ComPtr<ID3D12Resource> resource;
+ int res = m_device->CreateCommittedResource(&m_desc.m_heapProperties, m_desc.m_heapFlags, &desc, m_desc.m_initialState, nullptr, IID_PPV_ARGS(&resource));
+ if (NV_FAILED(res))
+ {
+ printf("Resource allocation failed");
+ return nullptr;
+ }
+
+ uint8_t* data = nullptr;
+ if (m_desc.m_heapProperties.Type == D3D12_HEAP_TYPE_READBACK)
+ {
+ }
+ else
+ {
+ // Map it, and keep it mapped
+ resource->Map(0, nullptr, (void**)&data);
+ }
+
+ // We have no blocks -> so lets allocate the first
+ Block* block = (Block*)m_blockFreeList.allocate();
+ block->m_next = nullptr;
+
+ block->m_resource = resource.Detach();
+ block->m_start = data;
+ return block;
+}
+
+Dx12CircularResourceHeap::Cursor Dx12CircularResourceHeap::allocate(size_t size, size_t alignment)
+{
+ const size_t blockSize = getBlockSize();
+
+ assert(size <= blockSize);
+
+ // If nothing is allocated add the first block
+ if (m_blocks == nullptr)
+ {
+ Block* block = _newBlock();
+ if (!block)
+ {
+ Cursor cursor = {};
+ return cursor;
+ }
+ m_blocks = block;
+ // Make circular
+ block->m_next = block;
+
+ // Point front and back to same position, as currently it is all free
+ m_back = { block, block->m_start };
+ m_front = m_back;
+ }
+
+ // If front and back are in the same block then front MUST be ahead of back (as that defined as
+ // an invariant and is required for block insertion to be possible
+ Block* block = m_front.m_block;
+
+ // Check the invariant
+ assert(block != m_back.m_block || m_front.m_position >= m_back.m_position);
+
+ {
+ uint8_t* cur = (uint8_t*)((size_t(m_front.m_position) + alignment - 1) & ~(alignment - 1));
+ // Does the the allocation fit?
+ if (cur + size <= block->m_start + blockSize)
+ {
+ // It fits
+ // Move the front forward
+ m_front.m_position = cur + size;
+ Cursor cursor = { block, cur };
+ return cursor;
+ }
+ }
+
+ // Okay I can't fit into current block...
+
+ // If the next block contains front, we need to add a block, else we can use that block
+ if (block->m_next == m_back.m_block)
+ {
+ Block* newBlock = _newBlock();
+ // Insert into the list
+ newBlock->m_next = block->m_next;
+ block->m_next = newBlock;
+ }
+
+ // Use the block we are going to add to
+ block = block->m_next;
+ uint8_t* cur = (uint8_t*)((size_t(block->m_start) + alignment - 1) & ~(alignment - 1));
+ // Does the the allocation fit?
+ if (cur + size > block->m_start + blockSize)
+ {
+ printf("Couldn't fit into a free block(!) Alignment breaks it?");
+ Cursor cursor = {};
+ return cursor;
+ }
+ // It fits
+ // Move the front forward
+ m_front.m_block = block;
+ m_front.m_position = cur + size;
+ Cursor cursor = { block, cur };
+ return cursor;
+}
+
+} // namespace Common
+} // namespace nvidia