diff options
Diffstat (limited to 'demo/d3d12/NvCoDx12CircularResourceHeap.cpp')
| -rw-r--r-- | demo/d3d12/NvCoDx12CircularResourceHeap.cpp | 204 |
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 |