diff options
| author | Miles Macklin <[email protected]> | 2017-06-09 13:41:15 +1200 |
|---|---|---|
| committer | Miles Macklin <[email protected]> | 2017-06-09 13:41:15 +1200 |
| commit | 688b5f42e9bfe498d7af7075d4d8f4429867f3a3 (patch) | |
| tree | 7e0d0e7c95298f0418723abd92f61ac6e16b055e /demo/d3d12 | |
| parent | Update README.md (diff) | |
| download | flex-1.2.0.beta.1.tar.xz flex-1.2.0.beta.1.zip | |
1.2.0.beta.11.2.0.beta.1
Diffstat (limited to 'demo/d3d12')
55 files changed, 9840 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 diff --git a/demo/d3d12/NvCoDx12CircularResourceHeap.h b/demo/d3d12/NvCoDx12CircularResourceHeap.h new file mode 100644 index 0000000..c88db06 --- /dev/null +++ b/demo/d3d12/NvCoDx12CircularResourceHeap.h @@ -0,0 +1,234 @@ +/* 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. */ + +#ifndef NV_CO_DX12_CIRCULAR_RESOURCE_HEAP_H +#define NV_CO_DX12_CIRCULAR_RESOURCE_HEAP_H + +#include <NvResult.h> +#include <NvCoFreeList.h> +#include "NvCoDx12CounterFence.h" + +#define NOMINMAX +#include <d3d12.h> +#include <wrl.h> +#include <deque> + +using namespace Microsoft::WRL; + +/** \addtogroup common +@{ +*/ + +namespace nvidia { +namespace Common { + +/*! \brief The Dx12CircularResourceHeap is a heap that is suited for size constrained real-time resources allocation that +is transitory in nature. It is designed to allocate resources which are used and discarded, often used where in +previous versions of DirectX the 'DISCARD' flag was used. + +The idea is to have a heap which chunks of resource can be allocated, and used for GPU execution, +and that the heap is able through the addSync/updateCompleted idiom is able to track when the usage of the resources is +completed allowing them to be reused. The heap is arranged as circularly, with new allocations made from the front, and the back +being updated as the GPU updating the back when it is informed anything using prior parts of the heap have completed. In this +arrangement all the heap between the back and the front can be thought of as in use or potentially in use by the GPU. All the heap +from the front back around to the back, is free and can be allocated from. It is the responsibility of the user of the Heap to make +sure the invariant holds, but in most normal usage it does so simply. + +Another feature of the heap is that it does not require upfront knowledge of how big a heap is needed. The backing resources will be expanded +dynamically with requests as needed. The only requirement is that know single request can be larger than m_blockSize specified in the Desc +used to initialize the heap. This is because all the backing resources are allocated to a single size. This limitation means the Dx12CircularResourceHeap +may not be the best use for example for uploading a texture - because it's design is really around transitory uploads or write backs, and so more suited +to constant buffers, vertex buffer, index buffers and the like. + +To upload a texture at program startup it is most likely better to use a Dx12ResourceScopeManager. + +### The addSync/updateCompleted Idiom + +Lots of classes in Nv/Common/Platform/Dx12 use the addSync/update idiom. The idiom enables a class to track GPU progress fairly simply. The +two methods are generally called at a fairly low frequency - say once a frame. The addSync method is given a signalValue that should be the +value generated from nextSignal on the Dx12Fence that is passed on construction of the type. Calling addSync means when this value is hit +ALL previous heap allocations will no longer be used. Thus in practice usage looks something like + +\code{.cpp} + +typedef Dx12CircularResourceHeap Heap; + +Heap::Cursor cursor = heap.allocateVertexBuffer(sizeof(Vertex) * numVerts); +Memory:copy(cursor.m_position, verts, sizeof(Vertex) * numVerts); + +// Do a command using the GPU handle +m_commandList->... +// Do another command using the GPU handle + +m_commandList->... + +// Execute the command list on the command queue +{ + ID3D12CommandList* lists[] = { m_commandList }; + m_commandQueue->ExecuteCommandLists(_countof(lists), lists); +} + +// Add a sync point +const uint64_t signalValue = m_fence.nextSignal(m_commandQueue); +heap.addSync(signalValue) + +// The cursors cannot be used anymore + +// At some later point call updateCompleted. This will see where the GPU is at, and make resources available that the GPU no longer accesses. +heap.updateCompleted(); + +\endcode + +### Implementation + +Front and back can be in the same block, but ONLY if back is behind front, because we have to always be able to insert +new blocks in front of front. So it must be possible to do an block insertion between the two of them. + +|--B---F-----| |----------| + +When B and F are on top of one another it means there is nothing in the list. NOTE this also means that a move of front can never place it +top of the back. + +https://msdn.microsoft.com/en-us/library/windows/desktop/dn899125%28v=vs.85%29.aspx +https://msdn.microsoft.com/en-us/library/windows/desktop/mt426646%28v=vs.85%29.aspx +*/ +class Dx12CircularResourceHeap +{ + protected: + struct Block; + + //NV_CO_DECLARE_CLASS_BASE(Dx12CircularResourceHeap); +public: + /// The alignment used for VERTEX_BUFFER allocations + /// Strictly speaking it seems the hardware can handle 4 byte alignment, but since often in use + /// data will be copied from CPU memory to the allocation, using 16 byte alignment is superior as allows + /// significantly faster memcpy. + /// The sample that shows sizeof(float) - 4 bytes is appropriate is at the link below. + /// https://msdn.microsoft.com/en-us/library/windows/desktop/mt426646%28v=vs.85%29.aspx + enum + { + VERTEX_BUFFER_ALIGNMENT = 16, + }; + + struct Desc + { + void init() + { + { + D3D12_HEAP_PROPERTIES& props = m_heapProperties; + + props.Type = D3D12_HEAP_TYPE_UPLOAD; + props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + props.CreationNodeMask = 1; + props.VisibleNodeMask = 1; + } + m_heapFlags = D3D12_HEAP_FLAG_NONE; + m_initialState = D3D12_RESOURCE_STATE_GENERIC_READ; + m_blockSize = 0; + } + + D3D12_HEAP_PROPERTIES m_heapProperties; + D3D12_HEAP_FLAGS m_heapFlags; + D3D12_RESOURCE_STATES m_initialState; + size_t m_blockSize; + }; + + /// Cursor position + struct Cursor + { + /// Get GpuHandle + inline D3D12_GPU_VIRTUAL_ADDRESS getGpuHandle() const { return m_block->m_resource->GetGPUVirtualAddress() + size_t(m_position - m_block->m_start); } + /// Must have a block and position + inline bool isValid() const { return m_block != nullptr; } + /// Calculate the offset into the underlying resource + inline size_t getOffset() const { return size_t(m_position - m_block->m_start); } + /// Get the underlying resource + inline ID3D12Resource* getResource() const { return m_block->m_resource; } + + Block* m_block; ///< The block index + uint8_t* m_position; ///< The current position + }; + + /// Get the desc used to initialize the heap + inline const Desc& getDesc() const { return m_desc; } + + /// Must be called before used + /// Block size must be at least as large as the _largest_ thing allocated + /// Also note depending on alignment of a resource allocation, the block size might also need to take into account the + /// maximum alignment use. It is a REQUIREMENT that a newly allocated resource block is large enough to hold any + /// allocation taking into account the alignment used. + int init(ID3D12Device* device, const Desc& desc, Dx12CounterFence* fence); + + /// Get the block size + inline size_t getBlockSize() const { return m_desc.m_blockSize; } + + /// Allocate constant buffer of specified size + Cursor allocate(size_t size, size_t alignment); + + /// Allocate a constant buffer + inline Cursor allocateConstantBuffer(size_t size) { return allocate(size, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT); } + /// Allocate a vertex buffer + inline Cursor allocateVertexBuffer(size_t size) { return allocate(size, VERTEX_BUFFER_ALIGNMENT); } + + /// Create filled in constant buffer + inline Cursor newConstantBuffer(const void* data, size_t size) { Cursor cursor = allocateConstantBuffer(size); memcpy(cursor.m_position, data, size); return cursor; } + /// Create in filled in constant buffer + template <typename T> + inline Cursor newConstantBuffer(const T& in) { return newConstantBuffer(&in, sizeof(T)); } + + /// Look where the GPU has got to and release anything not currently used + void updateCompleted(); + /// Add a sync point - meaning that when this point is hit in the queue + /// all of the resources up to this point will no longer be used. + void addSync(uint64_t signalValue); + + /// Get the gpu address of this cursor + D3D12_GPU_VIRTUAL_ADDRESS getGpuHandle(const Cursor& cursor) const { return cursor.m_block->m_resource->GetGPUVirtualAddress() + size_t(cursor.m_position - cursor.m_block->m_start); } + + /// Ctor + Dx12CircularResourceHeap(); + /// Dtor + ~Dx12CircularResourceHeap(); + + protected: + + struct Block + { + ID3D12Resource* m_resource; ///< The mapped resource + uint8_t* m_start; ///< Once created the resource is mapped to here + Block* m_next; ///< Points to next block in the list + }; + struct PendingEntry + { + uint64_t m_completedValue; ///< The value when this is completed + Cursor m_cursor; ///< the cursor at that point + }; + void _freeBlockListResources(const Block* block); + /// Create a new block (with associated resource), do not add the block list + Block* _newBlock(); + + Block* m_blocks; ///< Circular singly linked list of block. nullptr initially + FreeList m_blockFreeList; ///< Free list of actual allocations of blocks + std::deque<PendingEntry> m_pendingQueue; ///< Holds the list of pending positions. When the fence value is greater than the value on the queue entry, the entry is done. + + // Allocation is made from the front, and freed from the back. + Cursor m_back; ///< Current back position. + Cursor m_front; ///< Current front position. + + Desc m_desc; ///< Describes the heap + + Dx12CounterFence* m_fence; ///< The fence to use + ID3D12Device* m_device; ///< The device that resources will be constructed on +}; + +} // namespace Common +} // namespace nvidia + +/** @} */ + +#endif // NV_CO_DX12_CIRCULAR_RESOURCE_HEAP_H diff --git a/demo/d3d12/NvCoDx12CounterFence.cpp b/demo/d3d12/NvCoDx12CounterFence.cpp new file mode 100644 index 0000000..bca181a --- /dev/null +++ b/demo/d3d12/NvCoDx12CounterFence.cpp @@ -0,0 +1,71 @@ +/* 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 "NvCoDx12CounterFence.h" + +namespace nvidia { +namespace Common { + +Dx12CounterFence::~Dx12CounterFence() +{ + if (m_event) + { + CloseHandle(m_event); + } +} + +int Dx12CounterFence::init(ID3D12Device* device, uint64_t initialValue) +{ + m_currentValue = initialValue; + + NV_RETURN_ON_FAIL(device->CreateFence(m_currentValue, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence))); + // Create an event handle to use for frame synchronization. + m_event = CreateEvent(nullptr, FALSE, FALSE, nullptr); + if (m_event == nullptr) + { + int res = HRESULT_FROM_WIN32(GetLastError()); + return NV_FAILED(res) ? res : NV_FAIL; + } + return NV_OK; +} + +uint64_t Dx12CounterFence::nextSignal(ID3D12CommandQueue* commandQueue) +{ + // Increment the fence value. Save on the frame - we'll know that frame is done when the fence value >= + m_currentValue++; + // Schedule a Signal command in the queue. + int res = commandQueue->Signal(m_fence.Get(), m_currentValue); + if (NV_FAILED(res)) + { + printf("Signal failed"); + } + return m_currentValue; +} + +void Dx12CounterFence::waitUntilCompleted(uint64_t completedValue) +{ + // You can only wait for a value that is less than or equal to the current value + assert(completedValue <= m_currentValue); + + // Wait until the previous frame is finished. + while (m_fence->GetCompletedValue() < completedValue) + { + // Make it signal with the current value + HRESULT res = m_fence->SetEventOnCompletion(completedValue, m_event); + if (FAILED(res)) { assert(0); return; } + + WaitForSingleObject(m_event, INFINITE); + } +} + +void Dx12CounterFence::nextSignalAndWait(ID3D12CommandQueue* commandQueue) +{ + waitUntilCompleted(nextSignal(commandQueue)); +} + +} // namespace Common +} // namespace nvidia diff --git a/demo/d3d12/NvCoDx12CounterFence.h b/demo/d3d12/NvCoDx12CounterFence.h new file mode 100644 index 0000000..9add39b --- /dev/null +++ b/demo/d3d12/NvCoDx12CounterFence.h @@ -0,0 +1,82 @@ +/* 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. */ + +#ifndef NV_CO_DX12_COUNTER_FENCE_H +#define NV_CO_DX12_COUNTER_FENCE_H + +#include <NvResult.h> + +#define NOMINMAX +#include <d3d12.h> +#include <stdint.h> +#include <stdio.h> +#include <assert.h> +#include <wrl.h> + +using namespace Microsoft::WRL; + +/** \addtogroup common +@{ +*/ + +namespace nvidia { +namespace Common { + +/*! \brief A class to simplify using Dx12 fences. + +A fence is a mechanism to track GPU work. This is achieved by having a counter that the CPU holds +called the current value. Calling nextSignal will increase the CPU counter, and add a fence +with that value to the commandQueue. When the GPU has completed all the work before the fence it will +update the completed value. This is typically used when +the CPU needs to know the GPU has finished some piece of work has completed. To do this the CPU +can check the completed value, and when it is greater or equal to the value returned by nextSignal the +CPU will know that all the work prior to when the nextSignal was added to the queue will have completed. + +NOTE! This cannot be used across threads, as for amongst other reasons SetEventOnCompletion +only works with a single value. + +Signal on the CommandQueue updates the fence on the GPU side. Signal on the fence object changes +the value on the CPU side (not used here). + +Useful article describing how Dx12 synchronization works: +https://msdn.microsoft.com/en-us/library/windows/desktop/dn899217%28v=vs.85%29.aspx +*/ +class Dx12CounterFence +{ + //NV_CO_DECLARE_CLASS_BASE(Dx12CounterFence); +public: + /// Must be called before used + int init(ID3D12Device* device, uint64_t initialValue = 0); + /// Increases the counter, signals the queue and waits for the signal to be hit + void nextSignalAndWait(ID3D12CommandQueue* queue); + /// Signals with next counter value. Returns the value the signal was called on + uint64_t nextSignal(ID3D12CommandQueue* commandQueue); + /// Get the current value + inline uint64_t getCurrentValue() const { return m_currentValue; } + /// Get the completed value + inline uint64_t getCompletedValue() const { return m_fence->GetCompletedValue(); } + + /// Waits for the the specified value + void waitUntilCompleted(uint64_t completedValue); + + /// Ctor + Dx12CounterFence():m_event(nullptr), m_currentValue(0) {} + /// Dtor + ~Dx12CounterFence(); + + protected: + HANDLE m_event; + ComPtr<ID3D12Fence> m_fence; + uint64_t m_currentValue; +}; + +} // namespace Common +} // namespace nvidia + +/** @} */ + +#endif // NV_CO_DX12_COUNTER_FENCE_H diff --git a/demo/d3d12/NvCoDx12DescriptorHeap.cpp b/demo/d3d12/NvCoDx12DescriptorHeap.cpp new file mode 100644 index 0000000..acda590 --- /dev/null +++ b/demo/d3d12/NvCoDx12DescriptorHeap.cpp @@ -0,0 +1,54 @@ +/* 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 "NvCoDx12DescriptorHeap.h" + +namespace nvidia { +namespace Common { + +Dx12DescriptorHeap::Dx12DescriptorHeap(): + m_size(0), + m_currentIndex(0), + m_descriptorSize(0) +{ +} + +int Dx12DescriptorHeap::init(ID3D12Device* device, int size, D3D12_DESCRIPTOR_HEAP_TYPE type, D3D12_DESCRIPTOR_HEAP_FLAGS flags) +{ + D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {}; + srvHeapDesc.NumDescriptors = size; + srvHeapDesc.Flags = flags; + srvHeapDesc.Type = type; + NV_RETURN_ON_FAIL(device->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&m_heap))); + + m_descriptorSize = device->GetDescriptorHandleIncrementSize(type); + m_size = size; + + return NV_OK; +} + +int Dx12DescriptorHeap::init(ID3D12Device* device, const D3D12_CPU_DESCRIPTOR_HANDLE* handles, int numHandles, D3D12_DESCRIPTOR_HEAP_TYPE type, D3D12_DESCRIPTOR_HEAP_FLAGS flags) +{ + NV_RETURN_ON_FAIL(init(device, numHandles, type, flags)); + D3D12_CPU_DESCRIPTOR_HANDLE dst = m_heap->GetCPUDescriptorHandleForHeapStart(); + + // Copy them all + for (int i = 0; i < numHandles; i++, dst.ptr += m_descriptorSize) + { + D3D12_CPU_DESCRIPTOR_HANDLE src = handles[i]; + if (src.ptr != 0) + { + device->CopyDescriptorsSimple(1, dst, src, type); + } + } + + return NV_OK; +} + +} // namespace Common +} // namespace nvidia + diff --git a/demo/d3d12/NvCoDx12DescriptorHeap.h b/demo/d3d12/NvCoDx12DescriptorHeap.h new file mode 100644 index 0000000..d323ce6 --- /dev/null +++ b/demo/d3d12/NvCoDx12DescriptorHeap.h @@ -0,0 +1,116 @@ +/* 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. */ + +#ifndef NV_CO_DX12_DESCRIPTOR_HEAP_H +#define NV_CO_DX12_DESCRIPTOR_HEAP_H + +#include <NvResult.h> + +#define NOMINMAX +#include <dxgi.h> +#include <d3d12.h> +#include <assert.h> +#include <wrl.h> + +using namespace Microsoft::WRL; + +namespace nvidia { +namespace Common { + +/*! \brief A simple class to manage an underlying Dx12 Descriptor Heap. Allocations are made linearly in order. It is not possible to free +individual allocations, but all allocations can be deallocated with 'deallocateAll'. */ +class Dx12DescriptorHeap +{ + //NV_CO_DECLARE_CLASS_BASE(Dx12DescriptorHeap); +public: + /// Initialize + int init(ID3D12Device* device, int size, D3D12_DESCRIPTOR_HEAP_TYPE type, D3D12_DESCRIPTOR_HEAP_FLAGS flags); + /// Initialize with an array of handles copying over the representation + int init(ID3D12Device* device, const D3D12_CPU_DESCRIPTOR_HANDLE* handles, int numHandles, D3D12_DESCRIPTOR_HEAP_TYPE type, D3D12_DESCRIPTOR_HEAP_FLAGS flags); + + /// Get the total amount of descriptors possible on the heap + inline int getSize() const { return m_size; } + /// Allocate a descriptor. Returns the index, or -1 if none left. + inline int allocate(); + /// Allocate a number of descriptors. Returns the start index (or -1 if not possible) + inline int allocate(int numDescriptors); + + /// Deallocates all allocations, and starts allocation from the start of the underlying heap again + inline void deallocateAll() { m_currentIndex = 0; } + + /// Get the size of each + inline int getDescriptorSize() const { return m_descriptorSize; } + + /// Get the GPU heap start + inline D3D12_GPU_DESCRIPTOR_HANDLE getGpuStart() const { return m_heap->GetGPUDescriptorHandleForHeapStart(); } + /// Get the CPU heap start + inline D3D12_CPU_DESCRIPTOR_HANDLE getCpuStart() const { return m_heap->GetCPUDescriptorHandleForHeapStart(); } + + /// Get the GPU handle at the specified index + inline D3D12_GPU_DESCRIPTOR_HANDLE getGpuHandle(int index) const; + /// Get the CPU handle at the specified index + inline D3D12_CPU_DESCRIPTOR_HANDLE getCpuHandle(int index) const; + + /// Get the underlying heap + inline ID3D12DescriptorHeap* getHeap() const { return m_heap.Get(); } + + /// Ctor + Dx12DescriptorHeap(); + +protected: + ComPtr<ID3D12DescriptorHeap> m_heap; ///< The underlying heap being allocated from + int m_size; ///< Total amount of allocations available on the heap + int m_currentIndex; ///< The current descriptor + int m_descriptorSize; ///< The size of each descriptor +}; + +// --------------------------------------------------------------------------- +int Dx12DescriptorHeap::allocate() +{ + assert(m_currentIndex < m_size); + if (m_currentIndex < m_size) + { + return m_currentIndex++; + } + return -1; +} +// --------------------------------------------------------------------------- +int Dx12DescriptorHeap::allocate(int numDescriptors) +{ + assert(m_currentIndex + numDescriptors <= m_size); + if (m_currentIndex + numDescriptors <= m_size) + { + const int index = m_currentIndex; + m_currentIndex += numDescriptors; + return index; + } + return -1; +} +// --------------------------------------------------------------------------- +inline D3D12_CPU_DESCRIPTOR_HANDLE Dx12DescriptorHeap::getCpuHandle(int index) const +{ + assert(index >= 0 && index < m_size); + D3D12_CPU_DESCRIPTOR_HANDLE start = m_heap->GetCPUDescriptorHandleForHeapStart(); + D3D12_CPU_DESCRIPTOR_HANDLE dst; + dst.ptr = start.ptr + m_descriptorSize * index; + return dst; +} +// --------------------------------------------------------------------------- +inline D3D12_GPU_DESCRIPTOR_HANDLE Dx12DescriptorHeap::getGpuHandle(int index) const +{ + assert(index >= 0 && index < m_size); + D3D12_GPU_DESCRIPTOR_HANDLE start = m_heap->GetGPUDescriptorHandleForHeapStart(); + D3D12_GPU_DESCRIPTOR_HANDLE dst; + dst.ptr = start.ptr + m_descriptorSize * index; + return dst; +} + +} // namespace Common +} // namespace nvidia + + +#endif // NV_CO_DX12_DESCRIPTOR_HEAP_H diff --git a/demo/d3d12/NvCoDx12Handle.h b/demo/d3d12/NvCoDx12Handle.h new file mode 100644 index 0000000..bbe8372 --- /dev/null +++ b/demo/d3d12/NvCoDx12Handle.h @@ -0,0 +1,162 @@ +/* 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. */ + +#ifndef NV_CO_DX12_HANDLE_H +#define NV_CO_DX12_HANDLE_H + +// Dx12 types +#define NOMINMAX +#include <d3d12.h> +#include <stdint.h> + +/** \addtogroup common +@{ +*/ + +namespace nvidia { +namespace Common { + +/*! +\brief Description of how the intended rendering target is arranged. +*/ +struct Dx12TargetInfo +{ + void init() + { + m_numRenderTargets = 1; + m_renderTargetFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; + m_depthStencilFormat = DXGI_FORMAT_D24_UNORM_S8_UINT; + m_numSamples = 1; + m_sampleQuality = 0; + m_sampleMask = ~uint32_t(0); + } + + int m_numRenderTargets; + DXGI_FORMAT m_renderTargetFormats[8]; ///< Format used for render target view access (the actual resource could be different!) + DXGI_FORMAT m_depthStencilFormat; ///< Format to use for depth stencil view access (the actual resource could be different!) + int m_numSamples; ///< The number of multi sample samples + int m_sampleQuality; ///< The multi sample quality + uint32_t m_sampleMask; ///< The sample mask +}; + +#if 0 +/*! +\brief Specifies the kinds of types that can be wrapped in ApiHandle/ApiPtr/ConstPtr types */ +class Dx12SubType { Dx12SubType(); public: +/*! SubTypes for Dx12 */ +enum Enum +{ + UNKNOWN, ///< Unknown + CONTEXT, + DEVICE, + BUFFER, + FLOAT32, + CPU_DESCRIPTOR_HANDLE, + COMMAND_QUEUE, + TARGET_INFO, + COUNT_OF, +}; +}; + +// Handle types +#define NV_DX12_HANDLE_TYPES(x) \ + x(ID3D12Device, DEVICE, DEVICE) \ + x(ID3D12GraphicsCommandList, CONTEXT, CONTEXT) \ + x(ID3D12Resource, BUFFER, BUFFER) \ + x(ID3D12CommandQueue, COMMAND_QUEUE, UNKNOWN ) + +// The 'value' types - ie ones that can be passed as pointers, in addition to the handle types +#define NV_DX12_VALUE_TYPES(x) \ + x(Float32, FLOAT32, UNKNOWN) \ + x(D3D12_CPU_DESCRIPTOR_HANDLE, CPU_DESCRIPTOR_HANDLE, CPU_DESCRIPTOR_HANDLE) \ + x(Dx12TargetInfo, TARGET_INFO, UNKNOWN) + +/*! +\brief A helper class to wrap Dx12 related types to ApiHandle, ApiPtr types, or extract via a cast the Dx12 types back out again. + +Some examples of how to wrap and cast handles and pointers + +\code{.cpp} +ID3D12Device* device = ...; + +\\ To wrap as a handle +ApiHandle handle = Dx12Type::wrap(device); + +\\ To wrap an array or pointer you can use + +Dx12TargetInfo target; +ApiPtr ptr = Dx12Type::wrapPtr(&target); + +\\ If you want to convert a wrapped handle back you can use +ID3D12Device* device = Dx12Type::cast<ID3D12Device>(handle); + +\\ Similarly to get a pointer +Dx12TargetInfo* target = Dx12Type::castPtr<Dx12TargetInfo>(ptr); +\endcode + +*/ +struct Dx12Type +{ + // Used by the macros. NOTE! Should be wrapping type (ie not the actual type - typically with E prefix) + typedef Dx12SubType ScopeSubType; + + /// Get the full type for the subtype + inline static int getType(Dx12SubType::Enum subType) { return (int(ApiType::DX12) << 8) | int(subType); } + /// Get the type via template, needed for arrays + template <typename T> + inline static int getType() { return getType((T*)NV_NULL); } + + /// Implement getType + NV_DX12_HANDLE_TYPES(NV_CO_API_GET_TYPE) + /// Implement getHandle, which will return a TypedApiHandle + NV_DX12_HANDLE_TYPES(NV_CO_API_WRAP) + /// Implement getType for 'value types' (ie structs and others that shouldn't be in a handle) + NV_DX12_VALUE_TYPES(NV_CO_API_GET_VALUE_TYPE) + + /// A template to work around warnings from dereferencing NV_NULL + template <typename T> + inline static int getPtrType() { void* data = NV_NULL; return getType(*(const T*)&data); } + + /// Get a pointer + template <typename T> + inline static ConstApiPtr wrapPtr(const T* in) { return ConstApiPtr(getPtrType<T>(), in); } + template <typename T> + inline static ApiPtr wrapPtr(T* in) { return ApiPtr(getPtrType<T>(), in); } + + /// Get from a handle + template <typename T> + inline static T* cast(const ApiHandle& in) { const int type = getType((T*)NV_NULL); return reinterpret_cast<T*>((type == in.m_type) ? in.m_handle : NV_NULL); } + /// Get from + template <typename T> + inline static const T* cast(const ConstApiPtr& ptr) { const int type = getPtrType<T>(); return reinterpret_cast<const T*>((ptr.m_type == type) ? ptr.getData() : NV_NULL); } + // Get from + template <typename T> + inline static T* cast(const ApiPtr& ptr) { const int type = getPtrType<T>(); return reinterpret_cast<T*>((ptr.m_type == type) ? ptr.getData() : NV_NULL); } + + /// Get the sub type as text + static const Char* getSubTypeText(Dx12SubType::Enum subType); + + /// If the match fails - implement casting. Writes impossible casts to Logger and returns NV_NULL. + static void* handlePtrCast(int fromType, int toType); + static void* handleCast(int fromType, int toType); + /// Called when a cast isn't possible. Will output warnings to log and return NV_NULL + static void castFailure(int fromType, int toType); + /// Log failure + static void logCastFailure(int fromType, int toType); +}; + +/* For generic handles you can use Dx11Handle. If you want the typed handle type use Dx11Type::wrap(texture) */ +typedef WrapApiHandle<Dx12Type> Dx12Handle; + +#endif + +} // namespace Common +} // namespace nvidia + +/** @} */ + +#endif // NV_CO_DX12_HANDLE_H diff --git a/demo/d3d12/NvCoDx12HelperUtil.cpp b/demo/d3d12/NvCoDx12HelperUtil.cpp new file mode 100644 index 0000000..46e2265 --- /dev/null +++ b/demo/d3d12/NvCoDx12HelperUtil.cpp @@ -0,0 +1,89 @@ +/* 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. */ + +// Make the DXGI_DEBUG_D3D12 symbol defined in this compilation unit, to avoid link problems +#define INITGUID + +#include "NvCoDx12HelperUtil.h" + +namespace nvidia { +namespace Common { + +void Dx12HelperUtil::calcSrvDesc(ID3D12Resource* resource, DXGI_FORMAT pixelFormat, D3D12_SHADER_RESOURCE_VIEW_DESC& descOut) +{ + // Get the desc + return calcSrvDesc(resource->GetDesc(), pixelFormat, descOut); +} + +void Dx12HelperUtil::calcSrvDesc(const D3D12_RESOURCE_DESC& desc, DXGI_FORMAT pixelFormat, D3D12_SHADER_RESOURCE_VIEW_DESC& descOut) +{ + + // create SRV + descOut = D3D12_SHADER_RESOURCE_VIEW_DESC(); + + descOut.Format = (pixelFormat == DXGI_FORMAT_UNKNOWN) ? DxFormatUtil::calcFormat(DxFormatUtil::USAGE_SRV, desc.Format) : pixelFormat; + descOut.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + if (desc.DepthOrArraySize == 1) + { + descOut.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + + descOut.Texture2D.MipLevels = desc.MipLevels; + descOut.Texture2D.MostDetailedMip = 0; + descOut.Texture2D.PlaneSlice = 0; + descOut.Texture2D.ResourceMinLODClamp = 0.0f; + } + else if (desc.DepthOrArraySize == 6) + { + descOut.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE; + + descOut.TextureCube.MipLevels = desc.MipLevels; + descOut.TextureCube.MostDetailedMip = 0; + descOut.TextureCube.ResourceMinLODClamp = 0; + } + else + { + descOut.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY; + + descOut.Texture2DArray.ArraySize = desc.DepthOrArraySize; + descOut.Texture2DArray.MostDetailedMip = 0; + descOut.Texture2DArray.MipLevels = desc.MipLevels; + descOut.Texture2DArray.FirstArraySlice = 0; + descOut.Texture2DArray.PlaneSlice = 0; + descOut.Texture2DArray.ResourceMinLODClamp = 0; + } +} + +/* static */void Dx12HelperUtil::reportLiveObjects() +{ + IDXGIDebug* dxgiDebug; + int res = DxDebugUtil::getDebugInterface(&dxgiDebug); + + if (NV_FAILED(res) || !dxgiDebug) + { + printf("Unable to access debug interface -> can't report live objects"); + return; + } + dxgiDebug->ReportLiveObjects(DXGI_DEBUG_D3D12, DXGI_DEBUG_RLO_DETAIL); +} + +/* static */int Dx12HelperUtil::serializeRootSigniture(const D3D12_ROOT_SIGNATURE_DESC& desc, D3D_ROOT_SIGNATURE_VERSION signitureVersion, ComPtr<ID3DBlob>& sigBlobOut) +{ + ComPtr<ID3DBlob> error; + int res = D3D12SerializeRootSignature(&desc, signitureVersion, &sigBlobOut, &error); + if (NV_SUCCEEDED(res)) + { + return res; + } + + char* errorText = (char*)error->GetBufferPointer(); + + printf("Unable to serialize Dx12 signature: %s\n", errorText); + return res; +} + +} // namespace Common +} // namespace nvidia diff --git a/demo/d3d12/NvCoDx12HelperUtil.h b/demo/d3d12/NvCoDx12HelperUtil.h new file mode 100644 index 0000000..1c05253 --- /dev/null +++ b/demo/d3d12/NvCoDx12HelperUtil.h @@ -0,0 +1,52 @@ +/* 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. */ + +#ifndef NV_CO_DX12_HELPER_UTIL_H +#define NV_CO_DX12_HELPER_UTIL_H + +#include <NvResult.h> +#include <NvCoDxFormatUtil.h> +#include <NvCoDxDebugUtil.h> + +#define NOMINMAX +#include <d3d12.h> +#include <stdio.h> +#include <wrl.h> + +using namespace Microsoft::WRL; + +/** \addtogroup common +@{ +*/ + +namespace nvidia { +namespace Common { + +struct Dx12HelperUtil +{ + /// Get a Shader resource view from a resourceDesc + /// If pixelFormat is UNKNOWN, will use the pixelFormat in the resourceDesc + static void calcSrvDesc(const D3D12_RESOURCE_DESC& resourceDesc, DXGI_FORMAT pixelFormat, D3D12_SHADER_RESOURCE_VIEW_DESC& descOut); + + /// Get a Shader resource view from a resource + /// If pixelFormat is UNKNOWN, will use the pixelFormat in the resourceDesc + static void calcSrvDesc(ID3D12Resource* resource, DXGI_FORMAT pixelFormat, D3D12_SHADER_RESOURCE_VIEW_DESC& descOut); + + /// Serializes the root signiture. If any errors occur will write to the log + static int serializeRootSigniture(const D3D12_ROOT_SIGNATURE_DESC& desc, D3D_ROOT_SIGNATURE_VERSION signitureVersion, ComPtr<ID3DBlob>& sigBlobOut); + + /// Reports to the output debug window any live objects, using debug interface. + /// Only works on systems that have "Dxgidebug.dll" + static void reportLiveObjects(); +}; + +} // namespace Common +} // namespace nvidia + +/** @} */ + +#endif // NV_CO_DX12_DEBUG_UTIL_H diff --git a/demo/d3d12/NvCoDx12RenderTarget.cpp b/demo/d3d12/NvCoDx12RenderTarget.cpp new file mode 100644 index 0000000..2ce4d86 --- /dev/null +++ b/demo/d3d12/NvCoDx12RenderTarget.cpp @@ -0,0 +1,324 @@ + +#include "NvCoDx12RenderTarget.h" +#include "appD3D12Ctx.h" + +#include <external/D3D12/include/d3dx12.h> + +namespace nvidia { +namespace Common { + +Dx12RenderTarget::Dx12RenderTarget() +{ + memset(m_srvIndices, -1, sizeof(m_srvIndices)); +} + +int Dx12RenderTarget::init(AppGraphCtxD3D12* renderContext, const Desc& desc) +{ + ID3D12Device* device = renderContext->m_device; + + m_desc = desc; + + // set viewport + { + m_viewport.Width = float(desc.m_width); + m_viewport.Height = float(desc.m_height); + m_viewport.MinDepth = 0; + m_viewport.MaxDepth = 1; + m_viewport.TopLeftX = 0; + m_viewport.TopLeftY = 0; + } + + { + m_scissorRect.left = 0; + m_scissorRect.top = 0; + m_scissorRect.right = desc.m_width; + m_scissorRect.bottom = desc.m_height; + } + + if (desc.m_targetFormat != DXGI_FORMAT_UNKNOWN) + { + D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {}; + heapDesc.NumDescriptors = 1; + heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; + heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; + NV_RETURN_ON_FAIL(device->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&m_descriptorHeapRtv))); + + DXGI_FORMAT resourceFormat = DxFormatUtil::calcResourceFormat(DxFormatUtil::USAGE_TARGET, m_desc.m_usageFlags, desc.m_targetFormat); + DXGI_FORMAT targetFormat = DxFormatUtil::calcFormat(DxFormatUtil::USAGE_TARGET, resourceFormat); + + D3D12_RESOURCE_DESC resourceDesc = CD3DX12_RESOURCE_DESC::Tex2D(resourceFormat, UINT(desc.m_width), UINT(desc.m_height), 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, D3D12_TEXTURE_LAYOUT_UNKNOWN, 0); + D3D12_HEAP_PROPERTIES heapProps = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT); + + // Depending on usage this format may not be right... + D3D12_CLEAR_VALUE clearValue; + clearValue.Format = targetFormat; + clearValue.Color[0] = FLT_MAX; + clearValue.Color[1] = FLT_MAX; + clearValue.Color[2] = FLT_MAX; + clearValue.Color[3] = FLT_MAX; + + NV_RETURN_ON_FAIL(m_renderTarget.initCommitted(device, heapProps, D3D12_HEAP_FLAG_NONE, resourceDesc, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, &clearValue)); + + D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {}; + rtvDesc.Format = targetFormat; + rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; + rtvDesc.Texture2D.MipSlice = 0; + rtvDesc.Texture2D.PlaneSlice = 0; + device->CreateRenderTargetView(m_renderTarget, &rtvDesc, m_descriptorHeapRtv->GetCPUDescriptorHandleForHeapStart()); + } + + // Create the depth stencil descriptor heap + if (desc.m_depthStencilFormat != DXGI_FORMAT_UNKNOWN) + { + D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {}; + heapDesc.NumDescriptors = 1; + heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV; + heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; + NV_RETURN_ON_FAIL(device->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&m_descriptorHeapDsv))); + + DXGI_FORMAT resourceFormat = DxFormatUtil::calcResourceFormat(DxFormatUtil::USAGE_DEPTH_STENCIL, m_desc.m_usageFlags, desc.m_depthStencilFormat); + DXGI_FORMAT depthStencilFormat = DxFormatUtil::calcFormat(DxFormatUtil::USAGE_DEPTH_STENCIL, resourceFormat); + + D3D12_RESOURCE_DESC resourceDesc = CD3DX12_RESOURCE_DESC::Tex2D(resourceFormat, UINT(desc.m_width), UINT(desc.m_height), 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL, D3D12_TEXTURE_LAYOUT_UNKNOWN, 0); + D3D12_HEAP_PROPERTIES heapProps = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT); + + D3D12_CLEAR_VALUE clearValue; + clearValue.Format = depthStencilFormat; + clearValue.DepthStencil.Depth = 1.0f; + clearValue.DepthStencil.Stencil = 0; + NV_RETURN_ON_FAIL(m_depthStencilBuffer.initCommitted(device, heapProps, D3D12_HEAP_FLAG_NONE, resourceDesc, D3D12_RESOURCE_STATE_DEPTH_WRITE, &clearValue)); + + // Create the depth stencil view + D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {}; + dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; + dsvDesc.Format = depthStencilFormat; + dsvDesc.Texture2D.MipSlice = 0; + dsvDesc.Flags = D3D12_DSV_FLAG_NONE; + device->CreateDepthStencilView(m_depthStencilBuffer, &dsvDesc, m_descriptorHeapDsv->GetCPUDescriptorHandleForHeapStart()); + } + + return NV_OK; +} + +/* static */DxFormatUtil::UsageType Dx12RenderTarget::getUsageType(BufferType type) +{ + switch (type) + { + case BUFFER_DEPTH_STENCIL: return DxFormatUtil::USAGE_DEPTH_STENCIL; + case BUFFER_TARGET: return DxFormatUtil::USAGE_TARGET; + default: return DxFormatUtil::USAGE_UNKNOWN; + } +} + +void Dx12RenderTarget::bind(AppGraphCtxD3D12* renderContext) +{ + ID3D12GraphicsCommandList* commandList = renderContext->m_commandList; + + // Work out what is bound + int numTargets = 0; + D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = {}; + D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = {}; + + if (m_renderTarget) + { + rtvHandle = m_descriptorHeapRtv->GetCPUDescriptorHandleForHeapStart(); + numTargets = 1; + } + if (m_depthStencilBuffer) + { + dsvHandle = m_descriptorHeapDsv->GetCPUDescriptorHandleForHeapStart(); + commandList->OMSetRenderTargets(numTargets, &rtvHandle, FALSE, &dsvHandle); + } + else + { + commandList->OMSetRenderTargets(numTargets, &rtvHandle, FALSE, nullptr); + } + + commandList->RSSetViewports(1, &m_viewport); + commandList->RSSetScissorRects(1, &m_scissorRect); +} + + +void Dx12RenderTarget::clear(AppGraphCtxD3D12* renderContext) +{ + ID3D12GraphicsCommandList* commandList = renderContext->m_commandList; + D3D12_RECT rect = { 0, 0, m_desc.m_width, m_desc.m_height }; + + // Clear + if (m_renderTarget) + { + D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = m_descriptorHeapRtv->GetCPUDescriptorHandleForHeapStart(); + commandList->ClearRenderTargetView(rtvHandle, m_desc.m_targetClearColor, 1, &rect); + } + if (m_depthStencilBuffer) + { + D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = m_descriptorHeapDsv->GetCPUDescriptorHandleForHeapStart(); + commandList->ClearDepthStencilView(dsvHandle, D3D12_CLEAR_FLAG_DEPTH, m_desc.m_depthStencilClearDepth, 0, 1, &rect); + } +} + +void Dx12RenderTarget::bindAndClear(AppGraphCtxD3D12* renderContext) +{ + ID3D12GraphicsCommandList* commandList = renderContext->m_commandList; + + // Work out what is bound + int numTargets = 0; + D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = {}; + D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = {}; + + if (m_renderTarget) + { + rtvHandle = m_descriptorHeapRtv->GetCPUDescriptorHandleForHeapStart(); + numTargets = 1; + } + if (m_depthStencilBuffer) + { + dsvHandle = m_descriptorHeapDsv->GetCPUDescriptorHandleForHeapStart(); + commandList->OMSetRenderTargets(numTargets, &rtvHandle, FALSE, &dsvHandle); + } + else + { + commandList->OMSetRenderTargets(numTargets, &rtvHandle, FALSE, nullptr); + } + + commandList->RSSetViewports(1, &m_viewport); + commandList->RSSetScissorRects(1, &m_scissorRect); + + D3D12_RECT rect = { 0, 0, m_desc.m_width, m_desc.m_height }; + + // Clear + if (m_renderTarget) + { + commandList->ClearRenderTargetView(rtvHandle, m_desc.m_targetClearColor, 1, &rect); + } + if (m_depthStencilBuffer) + { + commandList->ClearDepthStencilView(dsvHandle, D3D12_CLEAR_FLAG_DEPTH, m_desc.m_depthStencilClearDepth, 0, 1, &rect); + } +} + +void Dx12RenderTarget::setShadowDefaultLight(FXMVECTOR eye, FXMVECTOR at, FXMVECTOR up) +{ + float sizeX = 50.0f; + float sizeY = 50.0f; + float znear = -200.0f; + float zfar = 200.0f; + + setShadowLightMatrices(eye, at, up, sizeX, sizeY, znear, zfar); +} + +void Dx12RenderTarget::setShadowLightMatrices(FXMVECTOR eye, FXMVECTOR lookAt, FXMVECTOR up, float sizeX, float sizeY, float zNear, float zFar) +{ + m_shadowLightView = XMMatrixLookAtLH(eye, lookAt, up); + m_shadowLightProjection = XMMatrixOrthographicLH(sizeX, sizeY, zNear, zFar); + DirectX::XMMATRIX clip2Tex(0.5, 0, 0, 0, + 0, -0.5, 0, 0, + 0, 0, 1, 0, + 0.5, 0.5, 0, 1); + DirectX::XMMATRIX viewProjection = m_shadowLightView * m_shadowLightProjection; + m_shadowLightWorldToTex = viewProjection * clip2Tex; +} + +void Dx12RenderTarget::toWritable(AppGraphCtxD3D12* renderContext) +{ + Dx12BarrierSubmitter submitter(renderContext->m_commandList); + + m_renderTarget.transition(D3D12_RESOURCE_STATE_RENDER_TARGET, submitter); + m_depthStencilBuffer.transition(D3D12_RESOURCE_STATE_DEPTH_WRITE, submitter); +} + +void Dx12RenderTarget::toReadable(AppGraphCtxD3D12* renderContext) +{ + Dx12BarrierSubmitter submitter(renderContext->m_commandList); + + m_renderTarget.transition(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, submitter); + m_depthStencilBuffer.transition(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, submitter); +} + +DXGI_FORMAT Dx12RenderTarget::getSrvFormat(BufferType type) const +{ + return Dx12Resource::calcFormat(DxFormatUtil::USAGE_SRV, getResource(type)); +} + +DXGI_FORMAT Dx12RenderTarget::getTargetFormat(BufferType type) const +{ + return Dx12Resource::calcFormat(getUsageType(type), getResource(type)); +} + +D3D12_SHADER_RESOURCE_VIEW_DESC Dx12RenderTarget::calcDefaultSrvDesc(BufferType type) const +{ + ID3D12Resource* resource = getResource(type); + + D3D12_RESOURCE_DESC resourceDesc = resource->GetDesc(); + + D3D12_SHADER_RESOURCE_VIEW_DESC desc; + + desc.Format = getSrvFormat(type); + desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + + desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + + desc.Texture2D.MipLevels = resourceDesc.MipLevels; + desc.Texture2D.MostDetailedMip = 0; + desc.Texture2D.PlaneSlice = 0; + desc.Texture2D.ResourceMinLODClamp = 0.0f; + return desc; +} + +int Dx12RenderTarget::allocateSrvView(BufferType type, ID3D12Device* device, Dx12DescriptorHeap& heap, const D3D12_SHADER_RESOURCE_VIEW_DESC* desc) +{ + if (m_srvIndices[type] >= 0) + { + printf("A srv index has already been associated!"); + return m_srvIndices[type]; + } + + if (!desc) + { + // If not set construct a default desc + D3D12_SHADER_RESOURCE_VIEW_DESC defaultDesc = calcDefaultSrvDesc(type); + return allocateSrvView(type, device, heap, &defaultDesc); + } + + // Create the srv for the shadow buffer + ID3D12Resource* resource = getResource(type); + int srvIndex = heap.allocate(); + + if (srvIndex < 0) + { + return srvIndex; + } + + // Create on the the heap + device->CreateShaderResourceView(resource, desc, heap.getCpuHandle(srvIndex)); + + m_srvIndices[type] = srvIndex; + // Return the allocated index + return srvIndex; +} + +void Dx12RenderTarget::setDebugName(BufferType type, const std::wstring& name) +{ + getResource(type).setDebugName(name); +} + +void Dx12RenderTarget::setDebugName(const std::wstring& name) +{ + std::wstring buf(name); + buf += L" [Target]"; + setDebugName(BUFFER_TARGET, buf); + buf = name; + buf += L" [DepthStencil]"; + setDebugName(BUFFER_DEPTH_STENCIL, buf); +} + + +void Dx12RenderTarget::createSrv(ID3D12Device* device, Dx12DescriptorHeap& heap, BufferType type, int descriptorIndex) +{ + D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = calcDefaultSrvDesc(type); + ID3D12Resource* resource = getResource(type); + device->CreateShaderResourceView(resource, &srvDesc, heap.getCpuHandle(descriptorIndex)); +} + +} // namespace Common +} // namespace nvidia diff --git a/demo/d3d12/NvCoDx12RenderTarget.h b/demo/d3d12/NvCoDx12RenderTarget.h new file mode 100644 index 0000000..48e7fd0 --- /dev/null +++ b/demo/d3d12/NvCoDx12RenderTarget.h @@ -0,0 +1,122 @@ +#ifndef NV_CO_DX12_RENDER_TARGET_H +#define NV_CO_DX12_RENDER_TARGET_H + +#include <DirectXMath.h> +#include <NvCoDx12DescriptorHeap.h> +#include <NvCoDx12Resource.h> +#include "appD3D12Ctx.h" +#include "core/maths.h" + +namespace nvidia { +namespace Common { + +using namespace DirectX; + +class Dx12RenderTarget +{ + //NV_CO_DECLARE_POLYMORPHIC_CLASS_BASE(Dx12RenderTarget); +public: + enum BufferType + { + BUFFER_TARGET, + BUFFER_DEPTH_STENCIL, + BUFFER_COUNT_OF, + }; + + struct Desc + { + void init(int width, int height, DXGI_FORMAT targetFormat = DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT depthStencilFormat = DXGI_FORMAT_D32_FLOAT, int usageFlags = 0) + { + m_width = width; + m_height = height; + m_targetFormat = targetFormat; + m_depthStencilFormat = depthStencilFormat; + m_usageFlags = usageFlags; + + const Vec4 clearColor = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX }; + m_targetClearColor = clearColor; + m_depthStencilClearDepth = 1.0; + } + + int m_usageFlags; ///< Usage flags from DxFormatUtil + int m_width; + int m_height; + DXGI_FORMAT m_depthStencilFormat; ///< DXGI_FORMAT_UNKNOWN means don't allocate resource + DXGI_FORMAT m_targetFormat; ///< DXGI_FORMAT_UNKNOWN means don't allocate resource + Vec4 m_targetClearColor; + float m_depthStencilClearDepth; + }; + + int init(AppGraphCtxD3D12* renderContext, const Desc& desc); + + void setShadowDefaultLight(FXMVECTOR eye, FXMVECTOR at, FXMVECTOR up); + void setShadowLightMatrices(FXMVECTOR eye, FXMVECTOR lookAt, FXMVECTOR up, float sizeX, float sizeY, float zNear, float zFar); + + void bind(AppGraphCtxD3D12* renderContext); + + void clear(AppGraphCtxD3D12* renderContext); + void bindAndClear(AppGraphCtxD3D12* renderContext); + + void toWritable(AppGraphCtxD3D12* renderContext); + void toReadable(AppGraphCtxD3D12* renderContext); + + /// Set the debug name + void setDebugName(BufferType type, const std::wstring& name); + /// Set name (plus if depth/target) for all buffers + void setDebugName(const std::wstring& name); + + /// Get the 'primary' buffer type. + BufferType getPrimaryBufferType() const { return m_renderTarget ? BUFFER_TARGET : BUFFER_DEPTH_STENCIL; } + + /// Get the resource by the buffer type + const Dx12ResourceBase& getResource(BufferType type) const { return type == BUFFER_TARGET ? m_renderTarget : m_depthStencilBuffer; } + Dx12Resource& getResource(BufferType type) { return type == BUFFER_TARGET ? m_renderTarget : m_depthStencilBuffer; } + + /// Calculates a default shader resource view + D3D12_SHADER_RESOURCE_VIEW_DESC calcDefaultSrvDesc(BufferType type) const; + + /// Allocates a srv view. Stores the index in m_srvView. If < 0 there isn't an associated srv + /// If the desc isn't set one will be created via calcDefaultSrvDesc + int allocateSrvView(BufferType type, ID3D12Device* device, Dx12DescriptorHeap& heap, const D3D12_SHADER_RESOURCE_VIEW_DESC* desc = nullptr); + + /// Gets the appropriate format for reading as srv + DXGI_FORMAT getSrvFormat(BufferType type) const; + /// Gets the suitable target for rendering to + DXGI_FORMAT getTargetFormat(BufferType type) const; + /// Get the amount of render targets + inline int getNumRenderTargets() const { return m_renderTarget ? 1 : 0; } + + /// Create a srv at the index on the heap for the buffer type + void createSrv(ID3D12Device* device, Dx12DescriptorHeap& heap, BufferType type, int descriptorIndex); + + /// Get an associated srv heap index (as produced by allocateSrvView) + inline int getSrvHeapIndex(BufferType type) const { return m_srvIndices[type]; } + + /// Get the desc + inline const Desc& getDesc() const { return m_desc; } + + Dx12RenderTarget(); + + static DxFormatUtil::UsageType getUsageType(BufferType type); + + int m_srvIndices[BUFFER_COUNT_OF]; + + XMMATRIX m_shadowLightView; + XMMATRIX m_shadowLightProjection; + XMMATRIX m_shadowLightWorldToTex; + + Desc m_desc; + + D3D12_VIEWPORT m_viewport; + D3D12_RECT m_scissorRect; + + Dx12Resource m_renderTarget; + ComPtr<ID3D12DescriptorHeap> m_descriptorHeapRtv; + Dx12Resource m_depthStencilBuffer; + ComPtr<ID3D12DescriptorHeap> m_descriptorHeapDsv; +}; + +} // namespace Common +} // namespace nvidia + +#endif // NV_CO_DX12_RENDER_TARGET_H
\ No newline at end of file diff --git a/demo/d3d12/NvCoDx12Resource.cpp b/demo/d3d12/NvCoDx12Resource.cpp new file mode 100644 index 0000000..e771a15 --- /dev/null +++ b/demo/d3d12/NvCoDx12Resource.cpp @@ -0,0 +1,167 @@ +/* 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 "NvCoDx12Resource.h" + +#include <assert.h> + +#define NOMINMAX +#include <wrl.h> +using namespace Microsoft::WRL; + +namespace nvidia { +namespace Common { + +/* !!!!!!!!!!!!!!!!!!!!!!!!! Dx12BarrierSubmitter !!!!!!!!!!!!!!!!!!!!!!!! */ + +void Dx12BarrierSubmitter::_flush() +{ + assert(m_numBarriers > 0); + + if (m_commandList) + { + m_commandList->ResourceBarrier(UINT(m_numBarriers), m_barriers); + } + m_numBarriers = 0; +} + +D3D12_RESOURCE_BARRIER& Dx12BarrierSubmitter::_expandOne() +{ + _flush(); + return m_barriers[m_numBarriers++]; +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!! Dx12ResourceBase !!!!!!!!!!!!!!!!!!!!!!!! */ + +void Dx12ResourceBase::transition(D3D12_RESOURCE_STATES nextState, Dx12BarrierSubmitter& submitter) +{ + // If there is no resource, then there is nothing to transition + if (!m_resource) + { + return; + } + + if (nextState != m_state) + { + D3D12_RESOURCE_BARRIER& barrier = submitter.expandOne(); + + const UINT subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + const D3D12_RESOURCE_BARRIER_FLAGS flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + + memset(&barrier, 0, sizeof(barrier)); + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Flags = flags; + barrier.Transition.pResource = m_resource; + barrier.Transition.StateBefore = m_state; + barrier.Transition.StateAfter = nextState; + barrier.Transition.Subresource = subresource; + + m_prevState = m_state; + m_state = nextState; + } + else + { + if (nextState == D3D12_RESOURCE_STATE_UNORDERED_ACCESS) + { + D3D12_RESOURCE_BARRIER& barrier = submitter.expandOne(); + + memset(&barrier, 0, sizeof(barrier)); + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; + barrier.UAV.pResource = m_resource; + + m_state = nextState; + } + } +} + +/* static */DXGI_FORMAT Dx12ResourceBase::calcFormat(DxFormatUtil::UsageType usage, ID3D12Resource* resource) +{ + return resource ? DxFormatUtil::calcFormat(usage, resource->GetDesc().Format) : DXGI_FORMAT_UNKNOWN; +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!! Dx12Resource !!!!!!!!!!!!!!!!!!!!!!!! */ + +/* static */void Dx12Resource::setDebugName(ID3D12Resource* resource, const std::wstring& name) +{ + if (resource) + { + resource->SetName(name.c_str()); + } +} + +void Dx12Resource::setDebugName(const std::wstring& name) +{ + setDebugName(m_resource, name); +} + +void Dx12Resource::setDebugName(const wchar_t* name) +{ + if (m_resource) + { + m_resource->SetName(name); + } +} + +void Dx12Resource::setResource(ID3D12Resource* resource, D3D12_RESOURCE_STATES initialState) +{ + if (resource != m_resource) + { + if (resource) + { + resource->AddRef(); + } + if (m_resource) + { + m_resource->Release(); + } + m_resource = resource; + } + m_prevState = initialState; + m_state = initialState; +} + +void Dx12Resource::setResourceNull() +{ + if (m_resource) + { + m_resource->Release(); + m_resource = nullptr; + } +} + +int Dx12Resource::initCommitted(ID3D12Device* device, const D3D12_HEAP_PROPERTIES& heapProps, D3D12_HEAP_FLAGS heapFlags, const D3D12_RESOURCE_DESC& resourceDesc, D3D12_RESOURCE_STATES initState, const D3D12_CLEAR_VALUE * clearValue) +{ + setResourceNull(); + ComPtr<ID3D12Resource> resource; + NV_RETURN_ON_FAIL(device->CreateCommittedResource(&heapProps, heapFlags, &resourceDesc, initState, clearValue, IID_PPV_ARGS(&resource))); + setResource(resource.Get(), initState); + return NV_OK; +} + +ID3D12Resource* Dx12Resource::detach() +{ + ID3D12Resource* resource = m_resource; + m_resource = nullptr; + return resource; +} + +void Dx12Resource::swap(ComPtr<ID3D12Resource>& resourceInOut) +{ + ID3D12Resource* tmp = m_resource; + m_resource = resourceInOut.Detach(); + resourceInOut.Attach(tmp); +} + +void Dx12Resource::setState(D3D12_RESOURCE_STATES state) +{ + m_prevState = state; + m_state = state; +} + + +} // namespace Common +} // namespace nvidia diff --git a/demo/d3d12/NvCoDx12Resource.h b/demo/d3d12/NvCoDx12Resource.h new file mode 100644 index 0000000..9bb8dab --- /dev/null +++ b/demo/d3d12/NvCoDx12Resource.h @@ -0,0 +1,140 @@ +#ifndef NV_CO_DX12_RESOURCE_H +#define NV_CO_DX12_RESOURCE_H + +#include <NvResult.h> +#include <NvCoDxFormatUtil.h> + +#define NOMINMAX +#include <d3d12.h> +#include <string> +#include <wrl.h> + +using namespace Microsoft::WRL; + +namespace nvidia { +namespace Common { + +// Enables more conservative barriers - restoring the state of resources after they are used. +// Should not need to be enabled in normal builds, as the barriers should correctly sync resources +// If enabling fixes an issue it implies regular barriers are not correctly used. +#define NV_CO_ENABLE_CONSERVATIVE_RESOURCE_BARRIERS 0 + +struct Dx12BarrierSubmitter +{ + enum { MAX_BARRIERS = 8 }; + + /// Expand one space to hold a barrier + inline D3D12_RESOURCE_BARRIER& expandOne() { return (m_numBarriers < MAX_BARRIERS) ? m_barriers[m_numBarriers++] : _expandOne(); } + /// Flush barriers to command list + inline void flush() { if (m_numBarriers > 0) _flush(); } + + /// Ctor + inline Dx12BarrierSubmitter(ID3D12GraphicsCommandList* commandList):m_numBarriers(0), m_commandList(commandList) { } + /// Dtor + inline ~Dx12BarrierSubmitter() { flush(); } + + protected: + D3D12_RESOURCE_BARRIER& _expandOne(); + void _flush(); + + ID3D12GraphicsCommandList* m_commandList; + ptrdiff_t m_numBarriers; + D3D12_RESOURCE_BARRIER m_barriers[MAX_BARRIERS]; +}; + +/** The base class for resource types allows for tracking of state. It does not allow for setting of the resource though, such that +an interface can return a Dx12ResourceBase, and a client cant manipulate it's state, but it cannot replace/change the actual resource */ +struct Dx12ResourceBase +{ + /// Add a transition if necessary to the list + void transition(D3D12_RESOURCE_STATES nextState, Dx12BarrierSubmitter& submitter); + /// Get the current state + inline D3D12_RESOURCE_STATES getState() const { return m_state; } + + /// Get the associated resource + inline ID3D12Resource* getResource() const { return m_resource; } + + /// True if a resource is set + inline bool isSet() const { return m_resource != nullptr; } + + /// Coercable into ID3D12Resource + inline operator ID3D12Resource*() const { return m_resource; } + + /// restore previous state +#if NV_CO_ENABLE_CONSERVATIVE_RESOURCE_BARRIERS + inline void restore(Dx12BarrierSubmitter& submitter) { transition(m_prevState, submitter); } +#else + inline void restore(Dx12BarrierSubmitter& submitter) { (void)submitter; } +#endif + + /// Given the usage, flags, and format will return the most suitable format. Will return DXGI_UNKNOWN if combination is not possible + static DXGI_FORMAT calcFormat(DxFormatUtil::UsageType usage, ID3D12Resource* resource); + + /// Ctor + inline Dx12ResourceBase() : + m_state(D3D12_RESOURCE_STATE_COMMON), + m_prevState(D3D12_RESOURCE_STATE_COMMON), + m_resource(nullptr) + {} + + protected: + /// This is protected so as clients cannot slice the class, and so state tracking is lost + ~Dx12ResourceBase() {} + + ID3D12Resource* m_resource; + D3D12_RESOURCE_STATES m_state; + D3D12_RESOURCE_STATES m_prevState; +}; + +struct Dx12Resource: public Dx12ResourceBase +{ + + /// Dtor + ~Dx12Resource() + { + if (m_resource) + { + m_resource->Release(); + } + } + + /// Initialize as committed resource + int initCommitted(ID3D12Device* device, const D3D12_HEAP_PROPERTIES& heapProps, D3D12_HEAP_FLAGS heapFlags, const D3D12_RESOURCE_DESC& resourceDesc, D3D12_RESOURCE_STATES initState, const D3D12_CLEAR_VALUE * clearValue); + + /// Set a resource with an initial state + void setResource(ID3D12Resource* resource, D3D12_RESOURCE_STATES initialState); + /// Make the resource null + void setResourceNull(); + /// Returns the attached resource (with any ref counts) and sets to nullptr on this. + ID3D12Resource* detach(); + + /// Swaps the resource contents with the contents of the smart pointer + void swap(ComPtr<ID3D12Resource>& resourceInOut); + + /// Sets the current state of the resource (the current state is taken to be the future state once the command list has executed) + /// NOTE! This must be used with care, otherwise state tracking can be made incorrect. + void setState(D3D12_RESOURCE_STATES state); + + /// Set the debug name on a resource + static void setDebugName(ID3D12Resource* resource, const std::wstring& name); + + /// Set the the debug name on the resource + void setDebugName(const wchar_t* name); + /// Set the debug name + void setDebugName(const std::wstring& name); +}; + +/// Convenient way to set blobs +struct Dx12Blob : public D3D12_SHADER_BYTECODE +{ + template <size_t SIZE> + inline Dx12Blob(const BYTE(&in)[SIZE]) { pShaderBytecode = in; BytecodeLength = SIZE; } + inline Dx12Blob(const BYTE* in, size_t size) { pShaderBytecode = in; BytecodeLength = size; } + inline Dx12Blob() { pShaderBytecode = nullptr; BytecodeLength = 0; } + inline Dx12Blob(ID3DBlob* blob) { pShaderBytecode = blob->GetBufferPointer(); BytecodeLength = blob->GetBufferSize(); } +}; + +} // namespace Common +} // namespace nvidia + +#endif // NV_CO_DX12_RESOURCE_H diff --git a/demo/d3d12/NvCoDx12ResourceScopeManager.cpp b/demo/d3d12/NvCoDx12ResourceScopeManager.cpp new file mode 100644 index 0000000..268ecab --- /dev/null +++ b/demo/d3d12/NvCoDx12ResourceScopeManager.cpp @@ -0,0 +1,179 @@ +/* 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 "NvCoDx12ResourceScopeManager.h" + +#include <assert.h> + +namespace nvidia { +namespace Common { + +Dx12ResourceScopeManager::Dx12ResourceScopeManager(): + m_fence(nullptr), + m_device(nullptr) +{ +} + +Dx12ResourceScopeManager::~Dx12ResourceScopeManager() +{ + while (!m_entryQueue.empty()) + { + Entry& entry = m_entryQueue.front(); + entry.m_resource->Release(); + m_entryQueue.pop_front(); + } +} + +int Dx12ResourceScopeManager::init(ID3D12Device* device, Dx12CounterFence* fence) +{ + m_fence = fence; + m_device = device; + return NV_OK; +} + +void Dx12ResourceScopeManager::addSync(uint64_t signalValue) +{ + (void)signalValue; + + assert(m_fence->getCurrentValue() == signalValue); +} + +void Dx12ResourceScopeManager::updateCompleted() +{ + const uint64_t completedValue = m_fence->getCompletedValue(); + if (!m_entryQueue.empty()) + { + const Entry& entry = m_entryQueue.front(); + if (entry.m_completedValue >= completedValue) + { + return; + } + entry.m_resource->Release(); + m_entryQueue.pop_front(); + } +} + +ID3D12Resource* Dx12ResourceScopeManager::newUploadResource(const D3D12_RESOURCE_DESC& resourceDesc, const D3D12_CLEAR_VALUE* clearValue) +{ + D3D12_HEAP_PROPERTIES heapProps; + { + heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; + heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + heapProps.CreationNodeMask = 1; + heapProps.VisibleNodeMask = 1; + } + const D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE; + + const D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_GENERIC_READ; + + ComPtr<ID3D12Resource> resource; + int res = m_device->CreateCommittedResource(&heapProps, heapFlags, &resourceDesc, initialState, clearValue, IID_PPV_ARGS(&resource)); + if (NV_FAILED(res)) return nullptr; + + // Get the current fence count + const uint64_t completedValue = m_fence->getCurrentValue(); + + Entry entry; + entry.m_completedValue = completedValue; + entry.m_resource = resource.Detach(); + m_entryQueue.push_back(entry); + + return entry.m_resource; +} + +/* static */void Dx12ResourceScopeManager::copy(const D3D12_SUBRESOURCE_DATA& src, size_t rowSizeInBytes, int numRows, int numSlices, const D3D12_MEMCPY_DEST& dst) +{ + for (int i = 0; i < numSlices; ++i) + { + uint8_t* dstSlice = reinterpret_cast<uint8_t*>(dst.pData) + dst.SlicePitch * i; + const uint8_t* srcSlice = reinterpret_cast<const uint8_t*>(src.pData) + src.SlicePitch * i; + for (int j = 0; j < numRows; ++j) + { + memcpy(dstSlice + dst.RowPitch * j, srcSlice + src.RowPitch * j, rowSizeInBytes); + } + } +} + +int Dx12ResourceScopeManager::upload(ID3D12GraphicsCommandList* commandList, const void* srcDataIn, ID3D12Resource* targetResource, D3D12_RESOURCE_STATES targetState) +{ + // Get the targetDesc + const D3D12_RESOURCE_DESC targetDesc = targetResource->GetDesc(); + // Ensure it is just a regular buffer + assert(targetDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER); + assert(targetDesc.Layout == D3D12_TEXTURE_LAYOUT_ROW_MAJOR); + + // The buffer size is the width + const size_t bufferSize = size_t(targetDesc.Width); + + D3D12_RESOURCE_DESC uploadDesc = targetDesc; + uploadDesc.Flags = D3D12_RESOURCE_FLAG_NONE; + + // Create the upload resource + ID3D12Resource* uploadResource = newUploadResource(uploadDesc); + + // Map it and copy + { + uint8_t* uploadMapped; + NV_RETURN_ON_FAIL(uploadResource->Map(0, nullptr, (void**)&uploadMapped)); + memcpy(uploadMapped, srcDataIn, bufferSize); + uploadResource->Unmap(0, nullptr); + } + + // Add the copy + commandList->CopyBufferRegion(targetResource, 0, uploadResource, 0, bufferSize); + + // Add the barrier + { + D3D12_RESOURCE_BARRIER barrier = {}; + + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + D3D12_RESOURCE_TRANSITION_BARRIER& transition = barrier.Transition; + transition.pResource = targetResource; + transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; + transition.StateAfter = targetState; + transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + + commandList->ResourceBarrier(1, &barrier); + } + + return NV_OK; +} + +void Dx12ResourceScopeManager::add(ID3D12Resource* resource) +{ + assert(resource); + + // Get the current fence count + const uint64_t completedValue = m_fence->getCurrentValue(); + + Entry entry; + entry.m_completedValue = completedValue; + resource->AddRef(); + entry.m_resource = resource; + + m_entryQueue.push_back(entry); +} + +int Dx12ResourceScopeManager::uploadWithState(ID3D12GraphicsCommandList* commandList, const void* srcDataIn, Dx12Resource& target, D3D12_RESOURCE_STATES targetState) +{ + // make sure we are in the correct initial state + if (target.getState() != D3D12_RESOURCE_STATE_COPY_DEST) + { + Dx12BarrierSubmitter submitter(commandList); + target.transition(D3D12_RESOURCE_STATE_COPY_DEST, submitter); + } + // Do the upload + NV_RETURN_ON_FAIL(upload(commandList, srcDataIn, target.getResource(), targetState)); + target.setState(targetState); + return NV_OK; +} + + +} // namespace Common +} // namespace nvidia diff --git a/demo/d3d12/NvCoDx12ResourceScopeManager.h b/demo/d3d12/NvCoDx12ResourceScopeManager.h new file mode 100644 index 0000000..7bd71ff --- /dev/null +++ b/demo/d3d12/NvCoDx12ResourceScopeManager.h @@ -0,0 +1,100 @@ +/* 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. */ + +#ifndef NV_CO_DX12_RESOURCE_SCOPE_MANAGER_H +#define NV_CO_DX12_RESOURCE_SCOPE_MANAGER_H + +#include "NvCoDx12Resource.h" +#include "NvCoDx12CounterFence.h" + +// Dx12 types +#define NOMINMAX +#include <d3d12.h> + +#include <deque> + +/** \addtogroup common +@{ +*/ + +namespace nvidia { +namespace Common { + +/*! \brief A class to manage the lifetime of resources that are transitory (as used only for a single specific piece of GPU work), +but arbitrarily sized - such as textures. + +With Dx12 there is no management for the lifetime of resources within the Api directly. It is the duty of +the application to make sure resources are released when they are no longer being referenced. The Dx12ResourceScopeManager +tries to simplify this management for some common use cases. Firstly when creating a GPU based resource and filling it +with data, the data must first be copied to an upload buffer, and then to the target gpu based buffer. The upload buffer +is only needed whilst copying takes place. The method 'upload' will create a temporary upload buffer, and initiate the +copy into target. + +The upload resource will ONLY BE RELEASED when the fences value is greater than the current value. Assuming the command list +is added to the queue, and the fence is added afterwards (which is the appropriate way), the resources will only be released +after the fence has been hit AND when updateCompleted is called. + +The Dx12ResourceScopeManager is most useful for resource uploads that happen at startup, and might be very large. If you want to +upload constrained sized (like constant buffer) resources quickly and efficiently at runtime you might be better using Dx12CircularResourceHeap. + +The Dx12ResourceScopeManager uses the addSync/updateCompleted idiom, see details in Dx12CircularResourceHeap. + +*/ +class Dx12ResourceScopeManager +{ + //NV_CO_DECLARE_CLASS_BASE(Dx12ResourceScopeManager); +public: + /// Initialize + int init(ID3D12Device* device, Dx12CounterFence* fence); + + /// Allocate constant buffer of specified size + ID3D12Resource* newUploadResource(const D3D12_RESOURCE_DESC& resourceDesc, const D3D12_CLEAR_VALUE* clearValue = nullptr); + /// Do an upload on the specified command list + int upload(ID3D12GraphicsCommandList* commandList, const void* srcDataIn, ID3D12Resource* target, D3D12_RESOURCE_STATES targetState); + /// Upload data to the target, and set state. Will add barriers if target is in the wrong state + int uploadWithState(ID3D12GraphicsCommandList* commandList, const void* srcDataIn, Dx12Resource& target, D3D12_RESOURCE_STATES targetState); + + /// Add a resource, which will be released when updateCompleted has a greater value + void add(ID3D12Resource* resource); + + /// Look where the GPU has got to and release anything not currently used + void updateCompleted(); + /// Add a sync point - meaning that when this point is hit in the queue + /// all of the resources up to this point will no longer be used. + void addSync(uint64_t signalValue); + + /// Get the device associated with this manager + inline ID3D12Device* getDevice() const { return m_device; } + + /// Ctor + Dx12ResourceScopeManager(); + /// Dtor + ~Dx12ResourceScopeManager(); + + /// Copy from src to dst + static void copy(const D3D12_SUBRESOURCE_DATA& src, size_t rowSizeInBytes, int numRows, int numSlices, const D3D12_MEMCPY_DEST& dst); + + protected: + + struct Entry + { + uint64_t m_completedValue; ///< If less than fence value this is completed + ID3D12Resource* m_resource; ///< The mapped resource + }; + + std::deque<Entry> m_entryQueue; + + Dx12CounterFence* m_fence; ///< The fence to use + ID3D12Device* m_device; ///< The device that resources will be constructed on +}; + +} // namespace Common +} // namespace nvidia + +/** @} */ + +#endif // NV_CO_DX12_RESOURCE_SCOPE_MANAGER_H diff --git a/demo/d3d12/NvCoDxDebugUtil.cpp b/demo/d3d12/NvCoDxDebugUtil.cpp new file mode 100644 index 0000000..b5ef17c --- /dev/null +++ b/demo/d3d12/NvCoDxDebugUtil.cpp @@ -0,0 +1,32 @@ +/* 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 "NvCoDxDebugUtil.h" + +namespace nvidia { +namespace Common { + +/* static */int DxDebugUtil::getDebugInterface(IDXGIDebug** debugOut) +{ + HMODULE module = GetModuleHandleA("Dxgidebug.dll"); + if (module) + { + //WINAPI + typedef HRESULT(WINAPI *FuncType)(REFIID riid, void **ppDebug); + FARPROC funcAddr = GetProcAddress(module, "DXGIGetDebugInterface"); + + FuncType debugFunc = (FuncType)funcAddr; + if (debugFunc) + { + return debugFunc(__uuidof(IDXGIDebug), (void**)debugOut); + } + } + return NV_FAIL; +} + +} // namespace Common +} // namespace nvidia diff --git a/demo/d3d12/NvCoDxDebugUtil.h b/demo/d3d12/NvCoDxDebugUtil.h new file mode 100644 index 0000000..8916ecf --- /dev/null +++ b/demo/d3d12/NvCoDxDebugUtil.h @@ -0,0 +1,37 @@ +/* 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. */ + +#ifndef NV_CO_DX_DEBUG_UTIL_H +#define NV_CO_DX_DEBUG_UTIL_H + +#include <NvResult.h> + +#define NOMINMAX +#include <DXGIDebug.h> +#include <wrl.h> + +using namespace Microsoft::WRL; + +/** \addtogroup common +@{ +*/ + +namespace nvidia { +namespace Common { + +struct DxDebugUtil +{ + /// Get the debug interface + static int getDebugInterface(IDXGIDebug** debugOut); +}; + +} // namespace Common +} // namespace nvidia + +/** @} */ + +#endif // NV_CO_DX12_DEBUG_UTIL_H diff --git a/demo/d3d12/NvCoDxFormatUtil.cpp b/demo/d3d12/NvCoDxFormatUtil.cpp new file mode 100644 index 0000000..7facf2e --- /dev/null +++ b/demo/d3d12/NvCoDxFormatUtil.cpp @@ -0,0 +1,173 @@ +/* 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 "NvCoDxFormatUtil.h" + +#include <stdio.h> + +namespace nvidia { +namespace Common { + +/* static */DXGI_FORMAT DxFormatUtil::calcResourceFormat(UsageType usage, int usageFlags, DXGI_FORMAT format) +{ + (void)usage; + if (usageFlags) + { + switch (format) + { + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_D32_FLOAT: return DXGI_FORMAT_R32_TYPELESS; + case DXGI_FORMAT_D24_UNORM_S8_UINT: return DXGI_FORMAT_R24G8_TYPELESS; + default: break; + } + return format; + } + return format; +} + +/* static */DXGI_FORMAT DxFormatUtil::calcFormat(UsageType usage, DXGI_FORMAT format) +{ + switch (usage) + { + case USAGE_COUNT_OF: + case USAGE_UNKNOWN: + { + return DXGI_FORMAT_UNKNOWN; + } + case USAGE_DEPTH_STENCIL: + { + switch (format) + { + case DXGI_FORMAT_D32_FLOAT: + case DXGI_FORMAT_R32_TYPELESS: return DXGI_FORMAT_D32_FLOAT; + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: return DXGI_FORMAT_D24_UNORM_S8_UINT; + case DXGI_FORMAT_R24G8_TYPELESS: return DXGI_FORMAT_D24_UNORM_S8_UINT; + default: break; + } + return format; + } + case USAGE_TARGET: + { + switch (format) + { + case DXGI_FORMAT_D32_FLOAT: + case DXGI_FORMAT_D24_UNORM_S8_UINT: return DXGI_FORMAT_UNKNOWN; + case DXGI_FORMAT_R32_TYPELESS: return DXGI_FORMAT_R32_FLOAT; + default: break; + } + return format; + } + case USAGE_SRV: + { + switch (format) + { + case DXGI_FORMAT_D32_FLOAT: + case DXGI_FORMAT_R32_TYPELESS: return DXGI_FORMAT_R32_FLOAT; + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: return DXGI_FORMAT_R24_UNORM_X8_TYPELESS; + default: break; + } + + return format; + } + } + + printf("Not reachable"); + return DXGI_FORMAT_UNKNOWN; +} + +bool DxFormatUtil::isTypeless(DXGI_FORMAT format) +{ + switch (format) + { + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + case DXGI_FORMAT_R32G32B32_TYPELESS: + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + case DXGI_FORMAT_R32G32_TYPELESS: + case DXGI_FORMAT_R32G8X24_TYPELESS: + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + case DXGI_FORMAT_R16G16_TYPELESS: + case DXGI_FORMAT_R32_TYPELESS: + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + case DXGI_FORMAT_R24G8_TYPELESS: + case DXGI_FORMAT_R8G8_TYPELESS: + case DXGI_FORMAT_R16_TYPELESS: + case DXGI_FORMAT_R8_TYPELESS: + case DXGI_FORMAT_BC1_TYPELESS: + case DXGI_FORMAT_BC2_TYPELESS: + case DXGI_FORMAT_BC3_TYPELESS: + case DXGI_FORMAT_BC4_TYPELESS: + case DXGI_FORMAT_BC5_TYPELESS: + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + case DXGI_FORMAT_BC6H_TYPELESS: + case DXGI_FORMAT_BC7_TYPELESS: + { + return true; + } + default: break; + } + return false; +} + +/* static */int DxFormatUtil::getNumColorChannelBits(DXGI_FORMAT fmt) +{ + switch (fmt) + { + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + case DXGI_FORMAT_R32G32B32A32_FLOAT: + case DXGI_FORMAT_R32G32B32A32_UINT: + case DXGI_FORMAT_R32G32B32A32_SINT: + case DXGI_FORMAT_R32G32B32_TYPELESS: + case DXGI_FORMAT_R32G32B32_FLOAT: + case DXGI_FORMAT_R32G32B32_UINT: + case DXGI_FORMAT_R32G32B32_SINT: + return 32; + + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + case DXGI_FORMAT_R16G16B16A16_FLOAT: + case DXGI_FORMAT_R16G16B16A16_UNORM: + case DXGI_FORMAT_R16G16B16A16_UINT: + case DXGI_FORMAT_R16G16B16A16_SNORM: + case DXGI_FORMAT_R16G16B16A16_SINT: + return 16; + + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + case DXGI_FORMAT_R10G10B10A2_UNORM: + case DXGI_FORMAT_R10G10B10A2_UINT: + case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: + return 10; + + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_R8G8B8A8_UINT: + case DXGI_FORMAT_R8G8B8A8_SNORM: + case DXGI_FORMAT_R8G8B8A8_SINT: + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8X8_UNORM: + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + return 8; + + case DXGI_FORMAT_B5G6R5_UNORM: + case DXGI_FORMAT_B5G5R5A1_UNORM: + return 5; + + case DXGI_FORMAT_B4G4R4A4_UNORM: + return 4; + + default: + return 0; + } +} + + +} // namespace Common +} // namespace nvidia diff --git a/demo/d3d12/NvCoDxFormatUtil.h b/demo/d3d12/NvCoDxFormatUtil.h new file mode 100644 index 0000000..e749ea8 --- /dev/null +++ b/demo/d3d12/NvCoDxFormatUtil.h @@ -0,0 +1,41 @@ +#ifndef NV_CO_DX_FORMAT_UTIL_H +#define NV_CO_DX_FORMAT_UTIL_H + +#define NOMINMAX +#include <dxgi.h> + +namespace nvidia { +namespace Common { + +struct DxFormatUtil +{ + enum UsageType + { + USAGE_UNKNOWN, ///< Generally used to mark an error + USAGE_TARGET, ///< Format should be used when written as target + USAGE_DEPTH_STENCIL, ///< Format should be used when written as depth stencil + USAGE_SRV, ///< Format if being read as srv + USAGE_COUNT_OF, + }; + enum UsageFlag + { + USAGE_FLAG_MULTI_SAMPLE = 0x1, + USAGE_FLAG_SRV = 0x2, + }; + + /// Given the usage, flags, and format will return the most suitable format. Will return DXGI_UNKNOWN if combination is not possible + static DXGI_FORMAT calcFormat(UsageType usage, DXGI_FORMAT format); + /// Calculate appropriate format for creating a buffer for usage and flags + static DXGI_FORMAT calcResourceFormat(UsageType usage, int usageFlags, DXGI_FORMAT format); + /// True if the type is 'typeless' + static bool isTypeless(DXGI_FORMAT format); + + /// Returns number of bits used for color channel for format (for channels with multiple sizes, returns smallest ie RGB565 -> 5) + static int getNumColorChannelBits(DXGI_FORMAT fmt); + +}; + +} // namespace Common +} // namespace nvidia + +#endif // NV_CO_DX12_RESOURCE_H diff --git a/demo/d3d12/NvCoFreeList.cpp b/demo/d3d12/NvCoFreeList.cpp new file mode 100644 index 0000000..72b23b2 --- /dev/null +++ b/demo/d3d12/NvCoFreeList.cpp @@ -0,0 +1,232 @@ +/* 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 "NvCoFreeList.h" + +#include <stdlib.h> +#include <string.h> + +#define DEFAULT_ALIGNMENT 16 + +namespace nvidia { +namespace Common { + +FreeList::~FreeList() +{ + _deallocateBlocks(m_activeBlocks); + _deallocateBlocks(m_freeBlocks); +} + +void FreeList::_init() +{ + m_top = nullptr; + m_end = nullptr; + + m_activeBlocks = nullptr; + m_freeBlocks = nullptr; + + m_freeElements = nullptr; + + m_elementSize = 0; + m_alignment = 1; + m_blockSize = 0; + m_blockAllocationSize = 0; + //m_allocator = nullptr; +} + +void FreeList::_init(size_t elementSize, size_t alignment, size_t elemsPerBlock) +{ + //allocator = allocator ? allocator : MemoryAllocator::getInstance(); + //assert(allocator); + //m_allocator = allocator; + + alignment = (alignment < sizeof(void*)) ? sizeof(void*) : alignment; + + // Alignment must be a power of 2 + assert(((alignment - 1) & alignment) == 0); + + // The elementSize must at least be + elementSize = (elementSize >= alignment) ? elementSize : alignment; + m_blockSize = elementSize * elemsPerBlock; + m_elementSize = elementSize; + m_alignment = alignment; + + // Calculate the block size neeed, correcting for alignment + const size_t alignedBlockSize = (alignment <= DEFAULT_ALIGNMENT) ? + _calcAlignedBlockSize(DEFAULT_ALIGNMENT) : + _calcAlignedBlockSize(alignment); + + // Make the block struct size aligned + m_blockAllocationSize = m_blockSize + alignedBlockSize; + + m_top = nullptr; + m_end = nullptr; + + m_activeBlocks = nullptr; + m_freeBlocks = nullptr; ///< Blocks that there are no allocations in + + m_freeElements = nullptr; +} + +void FreeList::init(size_t elementSize, size_t alignment, size_t elemsPerBlock) +{ + _deallocateBlocks(m_activeBlocks); + _deallocateBlocks(m_freeBlocks); + _init(elementSize, alignment, elemsPerBlock); +} + +void FreeList::_deallocateBlocks(Block* block) +{ + while (block) + { + Block* next = block->m_next; + +#ifdef NV_CO_FREE_LIST_INIT_MEM + Memory::set(block, 0xfd, m_blockAllocationSize); +#endif + + free(block); + block = next; + } +} + +bool FreeList::isValidAllocation(const void* dataIn) const +{ + uint8_t* data = (uint8_t*)dataIn; + + Block* block = m_activeBlocks; + while (block) + { + uint8_t* start = block->m_data; + uint8_t* end = start + m_blockSize; + + if (data >= start && data < end) + { + // Check it's aligned correctly + if ((data - start) % m_elementSize) + { + return false; + } + + // Non allocated data is between top and end + if (data >= m_top && data < m_end) + { + return false; + } + + // It can't be in the free list + Element* ele = m_freeElements; + while (ele) + { + if (ele == (Element*)data) + { + return false; + } + + ele = ele->m_next; + } + return true; + } + + block = block->m_next; + } + // It's not in an active block -> it cannot be a valid allocation + return false; +} + +void* FreeList::_allocate() +{ + Block* block = m_freeBlocks; + if (block) + { + /// Remove from the free blocks + m_freeBlocks = block->m_next; + } + else + { + block = (Block*)malloc(m_blockAllocationSize); + if (!block) + { + // Allocation failed... doh + return nullptr; + } + // Do the alignment + { + size_t fix = (size_t(block) + sizeof(Block) + m_alignment - 1) & ~(m_alignment - 1); + block->m_data = (uint8_t*)fix; + } + } + + // Attach to the active blocks + block->m_next = m_activeBlocks; + m_activeBlocks = block; + + // Set up top and end + m_end = block->m_data + m_blockSize; + + // Return the first element + uint8_t* element = block->m_data; + m_top = element + m_elementSize; + + NV_CO_FREE_LIST_INIT_ALLOCATE(element) + + return element; +} + +void FreeList::deallocateAll() +{ + Block* block = m_activeBlocks; + if (block) + { + // Find the end block + while (block->m_next) + { +#ifdef NV_CO_FREE_LIST_INIT_MEM + Memory::set(block->m_data, 0xfd, m_blockSize); +#endif + block = block->m_next; + } + // Attach to the freeblocks + block->m_next = m_freeBlocks; + // The list is now all freelists + m_freeBlocks = m_activeBlocks; + // There are no active blocks + m_activeBlocks = nullptr; + } + + m_top = nullptr; + m_end = nullptr; +} + +void FreeList::reset() +{ + _deallocateBlocks(m_activeBlocks); + _deallocateBlocks(m_freeBlocks); + + m_top = nullptr; + m_end = nullptr; + + m_activeBlocks = nullptr; + m_freeBlocks = nullptr; + + m_freeElements = nullptr; +} + + +void FreeList::_initAllocate(void* mem) +{ + memset(mem, 0xcd, m_elementSize); +} + +void FreeList::_initDeallocate(void* mem) +{ + memset(mem, 0xfd, m_elementSize); +} + +} // namespace Common +} // namespace nvidia + diff --git a/demo/d3d12/NvCoFreeList.h b/demo/d3d12/NvCoFreeList.h new file mode 100644 index 0000000..2b71c62 --- /dev/null +++ b/demo/d3d12/NvCoFreeList.h @@ -0,0 +1,154 @@ +/* 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. */ + +#ifndef NV_CO_FREELIST_H +#define NV_CO_FREELIST_H + +#include <assert.h> +#include <stdint.h> + +/** \addtogroup common +@{ +*/ + +namespace nvidia { +namespace Common { + +#if NV_DEBUG +# define NV_CO_FREE_LIST_INIT_MEM +#endif + +#ifdef NV_CO_FREE_LIST_INIT_MEM +# define NV_CO_FREE_LIST_INIT_ALLOCATE(ptr) _initAllocate(ptr); +# define NV_CO_FREE_LIST_INIT_DEALLOCATE(ptr) _initDeallocate(ptr); +#else +# define NV_CO_FREE_LIST_INIT_ALLOCATE(ptr) +# define NV_CO_FREE_LIST_INIT_DEALLOCATE(ptr) +#endif + + +/*! \brief A freelist is a simple and fast memory allocator that can allocate and free in any order identically sized blocks. + +\details A free list is a memory allocation system that performs allocations/deallocations very quickly for elements which are +all the same size. +In a freelist all elements are the same size, and elements can be allocated and freed in any order, as long as every deallocation +matches every allocation. Both allocation and deallocation are O(1), and generally just a few instructions. The underlying +memory allocator will allocate in large blocks, with multiple elements amortizing a more costly large allocation against lots +of fast small element allocations. */ +class FreeList +{ + //NV_CO_DECLARE_CLASS_BASE(FreeList); +public: + /// Free elements are held in a singly linked list. The minimum size of an element is therefore a pointer + struct Element + { + Element* m_next; + }; + struct Block + { + Block* m_next; ///< The next block + uint8_t* m_data; ///< The list of the elements each m_elementSize in size + }; + + /// Allocate a single element + inline void* allocate(); + /// Deallocate a block that was previously allocated with allocate + inline void deallocate(void* data); + + /// Returns true if this is from a valid allocation + bool isValidAllocation(const void* dataIn) const; + + /// Get the element size + inline size_t getElementSize() const { return m_elementSize; } + /// Get the total size of each individual block allocation in bytes + inline size_t getBlockSize() const { return m_blockSize; } + + /// Deallocates all elements + void deallocateAll(); + /// Deallocates all, and frees any backing memory (put in initial state) + void reset(); + + /// Initialize. If called on an already initialized heap, the heap will be deallocated. + void init(size_t elementSize, size_t alignment, size_t elemsPerBlock); + + /// Default Ctor + FreeList() { _init(); } + /// Ctor + FreeList(size_t elementSize, size_t alignment, size_t elemsPerBlock) { _init(elementSize, alignment, elemsPerBlock); } + /// Dtor + ~FreeList(); + + protected: + /// Initializes assuming freelist is not constructed + void _init(size_t elementSize, size_t alignment, size_t elemsPerBlock); + void* _allocate(); + void _deallocateBlocks(Block* block); + /// Initializes setting everything to empty (doesn't free anything if already allocated) + void _init(); + + inline static size_t _calcAlignedBlockSize(size_t align) { return (sizeof(Block) + align - 1) & ~(align - 1); } + + void _initAllocate(void* mem); + void _initDeallocate(void* mem); + + uint8_t* m_top; ///< The top position of the current block + uint8_t* m_end; ///< The end of the current block + + Block* m_activeBlocks; ///< The blocks there are potentially allocations from + Block* m_freeBlocks; ///< Blocks that there are no allocations in + + Element* m_freeElements; ///< A singly linked list of elements available + + size_t m_elementSize; + size_t m_alignment; + size_t m_blockSize; + size_t m_blockAllocationSize; ///< The actual allocation size. Maybe bigger than m_blockSize if alignment requires it. + //MemoryAllocator* m_allocator; +}; + +// -------------------------------------------------------------------------- +inline void* FreeList::allocate() +{ + // First see if there are any freeElements ready to go + { + Element* element = m_freeElements; + if (element) + { + m_freeElements = element->m_next; + NV_CO_FREE_LIST_INIT_ALLOCATE(element) + return element; + } + } + if (m_top >= m_end) + { + return _allocate(); + } + void* data = (void*)m_top; + NV_CO_FREE_LIST_INIT_ALLOCATE(data) + + m_top += m_elementSize; + return data; +} +// -------------------------------------------------------------------------- +inline void FreeList::deallocate(void* data) +{ + assert(isValidAllocation(data)); + + NV_CO_FREE_LIST_INIT_DEALLOCATE(data) + + // Put onto the singly linked free element list + Element* ele = (Element*)data; + ele->m_next = m_freeElements; + m_freeElements = ele; +} + +} // namespace Common +} // namespace nvidia + +/** @} */ + +#endif // NV_CO_FREELIST_H
\ No newline at end of file diff --git a/demo/d3d12/NvResult.h b/demo/d3d12/NvResult.h new file mode 100644 index 0000000..27cf936 --- /dev/null +++ b/demo/d3d12/NvResult.h @@ -0,0 +1,137 @@ +/* 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. */ + +#ifndef NV_RESULT_H +#define NV_RESULT_H + +#include <assert.h> + +/** \addtogroup core +@{ +*/ + +/*! Result is designed to be compatible with COM HRESULT. + +It's layout in bits is as follows + +Severity | Facility | Code +---------|----------|----- +31 | 30-16 | 15-0 + +Severity - 1 fail, 0 is success. +Facility is where the error originated from +Code is the code specific to the facility. + +The layout is designed such that failure is a negative number, and success is positive due to Result +being represented by an Int32. + +Result codes have the following style + +1. NV_name +2. NV_s_f_name +3. NV_s_name + +where s is severity as a single letter S - success, and E for error +Style 1 is reserved for NV_OK and NV_FAIL as they are so common and not tied to a facility + +s is S for success, E for error +f is the short version of the facility name + +For the common used NV_OK and NV_FAIL, the name prefix is dropped +It is acceptable to expand 'f' to a longer name to differentiate a name +ie for a facility 'DRIVER' it might make sense to have an error of the form NV_E_DRIVER_OUT_OF_MEMORY */ +typedef int NvResult; + +//! Make a result +#define NV_MAKE_RESULT(sev, fac, code) ((((int)(sev))<<31) | (((int)(fac))<<16) | ((int)(code))) + +//! Will be 0 - for ok, 1 for failure +#define NV_GET_RESULT_SEVERITY(r) ((int)(((NvUInt32)(r)) >> 31)) +//! Will be 0 - for ok, 1 for failure +#define NV_GET_RESULT_FACILITY(r) ((int)(((r) >> 16) & 0x7fff)) +//! Get the result code +#define NV_GET_RESULT_CODE(r) ((int)((r) & 0xffff)) + +#define NV_SEVERITY_ERROR 1 +#define NV_SEVERITY_SUCCESS 0 + +#define NV_MAKE_ERROR(fac, code) NV_MAKE_RESULT(NV_SEVERITY_ERROR, NV_FACILITY_##fac, code) +#define NV_MAKE_SUCCESS(fac, code) NV_MAKE_RESULT(NV_SEVERITY_SUCCESS, NV_FACILITY_##fac, code) + +/*************************** Facilities ************************************/ + +//! General - careful to make compatible with HRESULT +#define NV_FACILITY_GENERAL 0 + +//! Base facility -> so as to not clash with HRESULT values +#define NV_FACILITY_BASE 0x100 + +/*! Facilities numbers must be unique across a project to make the resulting result a unique number! +It can be useful to have a consistent short name for a facility, as used in the name prefix */ +#define NV_FACILITY_DISK (NV_FACILITY_BASE + 1) +#define NV_FACILITY_INTERFACE (NV_FACILITY_BASE + 2) +#define NV_FACILITY_UNKNOWN (NV_FACILITY_BASE + 3) +#define NV_FACILITY_MEMORY (NV_FACILITY_BASE + 4) +#define NV_FACILITY_MISC (NV_FACILITY_BASE + 5) + +/// Base for external facilities. Facilities should be unique across modules. +#define NV_FACILITY_EXTERNAL_BASE 0x200 +#define NV_FACILITY_HAIR (NV_FACILITY_EXTERNAL_BASE + 1) + +/* *************************** Codes **************************************/ + +// Memory +#define NV_E_MEM_OUT_OF_MEMORY NV_MAKE_ERROR(MEMORY, 1) +#define NV_E_MEM_BUFFER_TOO_SMALL NV_MAKE_ERROR(MEMORY, 2) + +//! NV_OK indicates success, and is equivalent to NV_MAKE_RESULT(0, NV_FACILITY_GENERAL, 0) +#define NV_OK 0 +//! NV_FAIL is the generic failure code - meaning a serious error occurred and the call couldn't complete +#define NV_FAIL NV_MAKE_ERROR(GENERAL, 1) + +//! Used to identify a Result that has yet to be initialized. +//! It defaults to failure such that if used incorrectly will fail, as similar in concept to using an uninitialized variable. +#define NV_E_MISC_UNINITIALIZED NV_MAKE_ERROR(MISC, 2) +//! Returned from an async method meaning the output is invalid (thus an error), but a result for the request is pending, and will be returned on a subsequent call with the async handle. +#define NV_E_MISC_PENDING NV_MAKE_ERROR(MISC, 3) +//! Indicates that a handle passed in as parameter to a method is invalid. +#define NV_E_MISC_INVALID_HANDLE NV_MAKE_ERROR(MISC, 4) + +/*! Set NV_HANDLE_RESULT_FAIL(x) to code to be executed whenever an error occurs, and is detected by one of the macros */ +#ifndef NV_HANDLE_RESULT_FAIL +# define NV_HANDLE_RESULT_FAIL(x) +#endif + +/* !!!!!!!!!!!!!!!!!!!!!!!!! Checking codes !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ + +//! Use to test if a result was failure. Never use result != NV_OK to test for failure, as there may be successful codes != NV_OK. +#define NV_FAILED(status) ((status) < 0) +//! Use to test if a result succeeded. Never use result == NV_OK to test for success, as will detect other successful codes as a failure. +#define NV_SUCCEEDED(status) ((status) >= 0) + +//! Helper macro, that makes it easy to add result checking to calls in functions/methods that themselves return Result. +#define NV_RETURN_ON_FAIL(x) { NvResult _res = (x); if (NV_FAILED(_res)) { NV_HANDLE_RESULT_FAIL(_res); return _res; } } +//! Helper macro that can be used to test the return value from a call, and will return in a void method/function +#define NV_RETURN_VOID_ON_FAIL(x) { NvResult _res = (x); if (NV_FAILED(_res)) { NV_HANDLE_RESULT_FAIL(_res); return; } } +//! Helper macro that will return false on failure. +#define NV_RETURN_FALSE_ON_FAIL(x) { NvResult _res = (x); if (NV_FAILED(_res)) { NV_HANDLE_RESULT_FAIL(_res); return false; } } + +//! Helper macro that will assert if the return code from a call is failure, also returns the failure. +#define NV_CORE_ASSERT_ON_FAIL(x) { NvResult _res = (x); if (NV_FAILED(_res)) { assert(false); return _res; } } +//! Helper macro that will assert if the result from a call is a failure, also returns. +#define NV_CORE_ASSERT_VOID_ON_FAIL(x) { NvResult _res = (x); if (NV_FAILED(_res)) { assert(false); return; } } + + +#if __cplusplus +namespace nvidia { +typedef NvResult Result; +} // namespace nvidia +#endif + +/** @} */ + +#endif diff --git a/demo/d3d12/appD3D12Ctx.cpp b/demo/d3d12/appD3D12Ctx.cpp new file mode 100644 index 0000000..944453a --- /dev/null +++ b/demo/d3d12/appD3D12Ctx.cpp @@ -0,0 +1,1210 @@ +/* + * Copyright (c) 2014-2017, 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. + */ + +//direct3d headers +#define NOMINMAX +#include <d3d12.h> +#include <dxgi1_4.h> + +// include the Direct3D Library file +#pragma comment (lib, "d3d12.lib") +#pragma comment (lib, "DXGI.lib") + +#include "appD3D12Ctx.h" + +#include <stdio.h> + +#include <SDL.h> +#include <SDL_video.h> +#include <SDL_syswm.h> + +namespace +{ + // COM object release utilities + template <class T> + void inline COMRelease(T& t) + { + if (t) t->Release(); + t = nullptr; + } + + template <class T> + void inline COMRelease(T& t, UINT arraySize) + { + for (UINT i = 0; i < arraySize; i++) + { + if (t[i]) t[i]->Release(); + t[i] = nullptr; + } + } +} + +AppGraphProfilerD3D12* appGraphCreateProfilerD3D12(AppGraphCtx* ctx); +void appGraphProfilerD3D12FrameBegin(AppGraphProfilerD3D12* profiler); +void appGraphProfilerD3D12FrameEnd(AppGraphProfilerD3D12* profiler); +void appGraphProfilerD3D12Enable(AppGraphProfilerD3D12* profiler, bool enabled); +void appGraphProfilerD3D12Begin(AppGraphProfilerD3D12* profiler, const char* label); +void appGraphProfilerD3D12End(AppGraphProfilerD3D12* profiler, const char* label); +bool appGraphProfilerD3D12Get(AppGraphProfilerD3D12* profiler, const char** plabel, float* cpuTime, float* gpuTime, int index); +void appGraphReleaseProfiler(AppGraphProfilerD3D12* profiler); + +AppGraphCtxD3D12::AppGraphCtxD3D12() +{ + m_profiler = appGraphCreateProfilerD3D12(cast_from_AppGraphCtxD3D12(this)); + + m_targetInfo.init(); + + memset(m_commandAllocators, 0, sizeof(m_commandAllocators)); + memset(m_fenceValues, 0, sizeof(m_fenceValues)); +} + +AppGraphCtxD3D12::~AppGraphCtxD3D12() +{ + AppGraphCtxReleaseRenderTargetD3D12(cast_from_AppGraphCtxD3D12(this)); + + COMRelease(m_device); + COMRelease(m_commandQueue); + COMRelease(m_rtvHeap); + COMRelease(m_dsvHeap); + COMRelease(m_depthSrvHeap); + COMRelease(m_commandAllocators, m_frameCount); + + COMRelease(m_fence); + CloseHandle(m_fenceEvent); + + COMRelease(m_commandList); + + m_dynamicHeapCbvSrvUav.release(); + + appGraphReleaseProfiler(m_profiler); + m_profiler = nullptr; +} + +AppGraphCtx* AppGraphCtxCreateD3D12(int deviceID) +{ + AppGraphCtxD3D12* context = new AppGraphCtxD3D12; + + HRESULT hr = S_OK; + +#if defined(_DEBUG) + // Enable the D3D12 debug layer. + { + ID3D12Debug* debugController; + if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) + { + debugController->EnableDebugLayer(); + } + COMRelease(debugController); + } +#endif + + UINT debugFlags = 0; +#ifdef _DEBUG + debugFlags |= DXGI_CREATE_FACTORY_DEBUG; +#endif + + // enumerate devices + IDXGIFactory4* pFactory = NULL; + CreateDXGIFactory2(debugFlags, IID_PPV_ARGS(&pFactory)); + IDXGIAdapter1* pAdapterTemp = NULL; + IDXGIAdapter1* pAdapter = NULL; + DXGI_ADAPTER_DESC1 adapterDesc; + int adapterIdx = 0; + while (S_OK == pFactory->EnumAdapters1(adapterIdx, &pAdapterTemp)) + { + pAdapterTemp->GetDesc1(&adapterDesc); + + context->m_dedicatedVideoMemory = (size_t)adapterDesc.DedicatedVideoMemory; + + if (deviceID == adapterIdx) + { + pAdapter = pAdapterTemp; + break; + } + else + { + pAdapterTemp->Release(); + } + adapterIdx++; + } + + // create device + if (hr = D3D12CreateDevice(pAdapter, D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), (void**)&context->m_device)) + { + delete context; + return nullptr; + } + + // to disable annoying warning +#if 0 + context->m_device->SetStablePowerState(TRUE); +#endif + + // create command queue + { + D3D12_COMMAND_QUEUE_DESC desc; + desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; + desc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL; + desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; + desc.NodeMask = 0; + + if (hr = context->m_device->CreateCommandQueue(&desc, IID_PPV_ARGS(&context->m_commandQueue))) + { + delete context; + return nullptr; + } + } + + // cleanup adapter and factory + COMRelease(pAdapter); + COMRelease(pFactory); + + // create RTV descriptor heap + { + D3D12_DESCRIPTOR_HEAP_DESC desc = {}; + desc.NumDescriptors = context->m_renderTargetCount; + desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; + desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; + if (hr = context->m_device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&context->m_rtvHeap))) + { + delete context; + return nullptr; + } + context->m_rtvDescriptorSize = context->m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); + } + + // create DSV descriptor heap + { + D3D12_DESCRIPTOR_HEAP_DESC desc = {}; + desc.NumDescriptors = 1; + desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV; + desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; + if (hr = context->m_device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&context->m_dsvHeap))) + { + delete context; + return nullptr; + } + } + + // create depth SRV descriptor heap + { + D3D12_DESCRIPTOR_HEAP_DESC desc = {}; + desc.NumDescriptors = 1; + desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; + desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; + if (hr = context->m_device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&context->m_depthSrvHeap))) + { + delete context; + return nullptr; + } + } + + // Create per frame resources + { + for (UINT idx = 0; idx < context->m_frameCount; idx++) + { + if (hr = context->m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&context->m_commandAllocators[idx]))) + { + delete context; + return nullptr; + } + } + } + + // create dynamic heap + { + context->m_dynamicHeapCbvSrvUav.init(context->m_device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 256u * 1024u); + } + + // Create command list and close it + { + if (hr = context->m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, + context->m_commandAllocators[context->m_frameIndex], nullptr, IID_PPV_ARGS(&context->m_commandList)) + ) + { + delete context; + return nullptr; + } + context->m_commandList->Close(); + } + + // create synchronization objects + { + if (hr = context->m_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&context->m_fence))) + { + delete context; + return nullptr; + } + + context->m_fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); + if (context->m_fenceEvent == nullptr) + { + delete context; + return nullptr; + } + } + + return cast_from_AppGraphCtxD3D12(context); +} + + +void AppGraphCtxInitRenderTargetD3D12(AppGraphCtx* contextIn, SDL_Window* window, bool fullscreen, int numMSAASamples) +{ + auto context = cast_to_AppGraphCtxD3D12(contextIn); + + HWND hWnd = nullptr; + // get Windows handle to this SDL window + SDL_SysWMinfo winInfo; + SDL_VERSION(&winInfo.version); + if (SDL_GetWindowWMInfo(window, &winInfo)) + { + if (winInfo.subsystem == SDL_SYSWM_WINDOWS) + { + hWnd = winInfo.info.win.window; + } + } + context->m_hWnd = hWnd; + context->m_fullscreen = fullscreen; + + HRESULT hr = S_OK; + + UINT debugFlags = 0; +#ifdef _DEBUG + debugFlags |= DXGI_CREATE_FACTORY_DEBUG; +#endif + + // enumerate devices + IDXGIFactory4* pFactory = NULL; + CreateDXGIFactory2(debugFlags, IID_PPV_ARGS(&pFactory)); + + // create the swap chain + for (int i = 0; i < 2; i++) + { + DXGI_SWAP_CHAIN_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.BufferCount = context->m_renderTargetCount; + desc.BufferDesc.Width = context->m_winW; + desc.BufferDesc.Height = context->m_winH; + desc.BufferDesc.Format = context->m_rtv_format; // DXGI_FORMAT_R8G8B8A8_UNORM; + desc.BufferDesc.RefreshRate.Numerator = 0; + desc.BufferDesc.RefreshRate.Denominator = 0; + desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + desc.OutputWindow = context->m_hWnd; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Windowed = context->m_fullscreen ? FALSE : TRUE; + desc.Flags = context->m_fullscreen ? 0u : DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; + + context->m_current_rtvDesc.Format = context->m_rtv_format; + context->m_current_rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; + context->m_current_rtvDesc.Texture2D.MipSlice = 0u; + context->m_current_rtvDesc.Texture2D.PlaneSlice = 0u; + + hr = pFactory->CreateSwapChain(context->m_commandQueue, &desc, (IDXGISwapChain**)&context->m_swapChain); + + if(hr != S_OK) + { + COMRelease(context->m_swapChain); + context->m_fullscreen = false; + continue; + } + + if (!context->m_fullscreen) + { + context->m_swapChainWaitableObject = context->m_swapChain->GetFrameLatencyWaitableObject(); + context->m_swapChain->SetMaximumFrameLatency(context->m_renderTargetCount - 2); + } + else + { + hr = context->m_swapChain->SetFullscreenState(true, nullptr); + if (hr != S_OK) + { + COMRelease(context->m_swapChain); + context->m_fullscreen = false; + continue; + } + DXGI_SWAP_CHAIN_DESC desc = {}; + context->m_swapChain->GetDesc(&desc); + + context->m_winW = desc.BufferDesc.Width; + context->m_winH = desc.BufferDesc.Height; + } + + context->m_frameIndex = context->m_swapChain->GetCurrentBackBufferIndex(); + break; + } + + // configure scissor and viewport + { + context->m_viewport.Width = float(context->m_winW); + context->m_viewport.Height = float(context->m_winH); + context->m_viewport.MaxDepth = 1.f; + + context->m_scissorRect.right = context->m_winW; + context->m_scissorRect.bottom = context->m_winH; + } + + COMRelease(pFactory); + + // create per render target resources + { + D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = context->m_rtvHeap->GetCPUDescriptorHandleForHeapStart(); + + for (UINT idx = 0; idx < context->m_renderTargetCount; idx++) + { + ComPtr<ID3D12Resource> backBuffer; + if (hr = context->m_swapChain->GetBuffer(idx, IID_PPV_ARGS(&backBuffer))) + { + return; + } + context->m_backBuffers[idx].setDebugName(L"Backbuffer"); + context->m_backBuffers[idx].setResource(backBuffer.Get(), D3D12_RESOURCE_STATE_COMMON); + // Assume they are the same thing for now... + context->m_renderTargets[idx] = &context->m_backBuffers[idx]; + + // If we are multi-sampling - create a render target separate from the back buffer + if (context->m_numMsaaSamples > 1) + { + D3D12_HEAP_PROPERTIES heapProps = {}; + heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; + D3D12_RESOURCE_DESC desc = backBuffer->GetDesc(); + + DXGI_FORMAT resourceFormat; + + if (desc.Format == DXGI_FORMAT_R32_FLOAT || desc.Format == DXGI_FORMAT_D32_FLOAT) + { + resourceFormat = DXGI_FORMAT_R32_TYPELESS; + } + else if (desc.Format == DXGI_FORMAT_D24_UNORM_S8_UINT) + { + resourceFormat = DXGI_FORMAT_R24G8_TYPELESS; + } + else + { + resourceFormat = desc.Format; + } + + DXGI_FORMAT targetFormat = nvidia::Common::DxFormatUtil::calcFormat(nvidia::Common::DxFormatUtil::USAGE_TARGET, resourceFormat); + + // Set the target format + context->m_targetInfo.m_renderTargetFormats[0] = targetFormat; + + D3D12_CLEAR_VALUE clearValue = {}; + clearValue.Format = targetFormat; + + desc.Format = resourceFormat; + desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; + desc.SampleDesc.Count = context->m_targetInfo.m_numSamples; + desc.SampleDesc.Quality = context->m_targetInfo.m_sampleQuality; + desc.Alignment = 0; + + context->m_renderTargetResources[idx].initCommitted(context->m_device, heapProps, D3D12_HEAP_FLAG_NONE, desc, D3D12_RESOURCE_STATE_RENDER_TARGET, &clearValue); + context->m_renderTargets[idx] = &context->m_renderTargetResources[idx]; + + context->m_renderTargetResources[idx].setDebugName(L"Render Target"); + } + + context->m_device->CreateRenderTargetView(*context->m_renderTargets[idx], nullptr, rtvHandle); + rtvHandle.ptr += context->m_rtvDescriptorSize; + } + } + + // create the depth stencil + { + D3D12_HEAP_PROPERTIES heapProps = {}; + heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; + heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + heapProps.CreationNodeMask = 0u; + heapProps.VisibleNodeMask = 0u; + + D3D12_RESOURCE_DESC texDesc = {}; + texDesc.MipLevels = 1u; + texDesc.Format = context->m_depth_format; // DXGI_FORMAT_R32_TYPELESS; // DXGI_FORMAT_R24G8_TYPELESS + texDesc.Width = context->m_winW; + texDesc.Height = context->m_winH; + texDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL /*| D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE*/; + texDesc.DepthOrArraySize = 1u; + texDesc.SampleDesc.Count = context->m_targetInfo.m_numSamples; + texDesc.SampleDesc.Quality = context->m_targetInfo.m_sampleQuality; + texDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; + + D3D12_CLEAR_VALUE clearValue; + clearValue.Format = context->m_dsv_format; // DXGI_FORMAT_D32_FLOAT; + clearValue.DepthStencil.Depth = 1.f; + clearValue.DepthStencil.Stencil = 0; + + if (hr = context->m_device->CreateCommittedResource( + &heapProps, + D3D12_HEAP_FLAG_NONE, + &texDesc, + D3D12_RESOURCE_STATE_DEPTH_WRITE, + &clearValue, + IID_PPV_ARGS(&context->m_depthStencil) + )) + { + return; + } + + // create the depth stencil view + D3D12_DEPTH_STENCIL_VIEW_DESC viewDesc = {}; + viewDesc.Format = context->m_dsv_format; // DXGI_FORMAT_D32_FLOAT; + viewDesc.ViewDimension = (context->m_numMsaaSamples>1) ? D3D12_DSV_DIMENSION_TEXTURE2DMS : D3D12_DSV_DIMENSION_TEXTURE2D; + viewDesc.Flags = D3D12_DSV_FLAG_NONE; + viewDesc.Texture2D.MipSlice = 0; + + context->m_current_dsvDesc = viewDesc; + + context->m_device->CreateDepthStencilView(context->m_depthStencil, &viewDesc, context->m_dsvHeap->GetCPUDescriptorHandleForHeapStart()); + + context->m_targetInfo.m_depthStencilFormat = context->m_dsv_format; + } +} + +bool AppGraphCtxUpdateSizeD3D12(AppGraphCtx* contextIn, SDL_Window* window, bool fullscreen, int numMSAASamples) +{ + auto context = cast_to_AppGraphCtxD3D12(contextIn); + + bool sizeChanged = false; + + // sync with window + { + HWND hWnd = nullptr; + // get Windows handle to this SDL window + SDL_SysWMinfo winInfo; + SDL_VERSION(&winInfo.version); + if (SDL_GetWindowWMInfo(window, &winInfo)) + { + if (winInfo.subsystem == SDL_SYSWM_WINDOWS) + { + hWnd = winInfo.info.win.window; + } + } + context->m_hWnd = hWnd; + context->m_fullscreen = fullscreen; + + HRESULT hr = S_OK; + + RECT rc; + GetClientRect(context->m_hWnd, &rc); + UINT width = rc.right - rc.left; + UINT height = rc.bottom - rc.top; + + if (context->m_winW != width || context->m_winH != height) + { + context->m_winW = width; + context->m_winH = height; + sizeChanged = true; + context->m_valid = (context->m_winW != 0 && context->m_winH != 0); + } + } + + context->m_numMsaaSamples = numMSAASamples; + context->m_targetInfo.m_numSamples = numMSAASamples; + + if (sizeChanged) + { + AppGraphCtxReleaseRenderTargetD3D12(cast_from_AppGraphCtxD3D12(context)); + } + if (sizeChanged && context->m_valid) + { + AppGraphCtxInitRenderTargetD3D12(cast_from_AppGraphCtxD3D12(context), window, fullscreen, numMSAASamples); + } + + return context->m_valid; +} + +void AppGraphCtxReleaseRenderTargetD3D12(AppGraphCtx* contextIn) +{ + auto context = cast_to_AppGraphCtxD3D12(contextIn); + + if (context->m_swapChain == nullptr) + { + return; + } + + // need to make sure the pipeline is flushed + for (UINT i = 0; i < context->m_frameCount; i++) + { + // check dependencies + UINT64 fenceCompleted = context->m_fence->GetCompletedValue(); + if (fenceCompleted < context->m_fenceValues[i]) + { + context->m_fence->SetEventOnCompletion(context->m_fenceValues[i], context->m_fenceEvent); + WaitForSingleObjectEx(context->m_fenceEvent, INFINITE, FALSE); + } + } + + BOOL bFullscreen = FALSE; + context->m_swapChain->GetFullscreenState(&bFullscreen, nullptr); + if (bFullscreen == TRUE) context->m_swapChain->SetFullscreenState(FALSE, nullptr); + + COMRelease(context->m_swapChain); + COMRelease(context->m_depthStencil); + + for(int i=0;i!= context->m_renderTargetCount; i++) + context->m_renderTargets[i]->setResourceNull(); + + context->m_valid = false; + context->m_winW = 0u; + context->m_winH = 0u; +} + +void AppGraphCtxReleaseD3D12(AppGraphCtx* context) +{ + if (context == nullptr) return; + + delete cast_to_AppGraphCtxD3D12(context); +} + +void AppGraphCtxFrameStartD3D12(AppGraphCtx* contextIn, AppGraphColor clearColor) +{ + auto context = cast_to_AppGraphCtxD3D12(contextIn); + + // Get back render target index + context->m_renderTargetIndex = context->m_swapChain->GetCurrentBackBufferIndex(); + + // check dependencies + UINT64 fenceCompleted = context->m_fence->GetCompletedValue(); + if (fenceCompleted < context->m_fenceValues[context->m_frameIndex]) + { + context->m_fence->SetEventOnCompletion(context->m_fenceValues[context->m_frameIndex], context->m_fenceEvent); + WaitForSingleObjectEx(context->m_fenceEvent, INFINITE, FALSE); + } + + // The fence ID associated with completion of this frame + context->m_thisFrameFenceID = context->m_frameID + 1; + context->m_lastFenceComplete = context->m_fence->GetCompletedValue(); + + // reset this frame's command allocator + context->m_commandAllocators[context->m_frameIndex]->Reset(); + + // reset command list with this frame's allocator + context->m_commandList->Reset(context->m_commandAllocators[context->m_frameIndex], nullptr); + + appGraphProfilerD3D12FrameBegin(context->m_profiler); + + context->m_commandList->RSSetViewports(1, &context->m_viewport); + context->m_commandList->RSSetScissorRects(1, &context->m_scissorRect); + + { + nvidia::Common::Dx12BarrierSubmitter submitter(context->m_commandList); + context->m_renderTargets[context->m_renderTargetIndex]->transition(D3D12_RESOURCE_STATE_RENDER_TARGET, submitter); + } + + D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = context->m_rtvHeap->GetCPUDescriptorHandleForHeapStart(); + rtvHandle.ptr += context->m_renderTargetIndex * context->m_rtvDescriptorSize; + + D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = context->m_dsvHeap->GetCPUDescriptorHandleForHeapStart(); + context->m_commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, &dsvHandle); + + context->m_commandList->ClearRenderTargetView(rtvHandle, &clearColor.r, 0, nullptr); + context->m_commandList->ClearDepthStencilView(dsvHandle, D3D12_CLEAR_FLAG_DEPTH, 1.f, 0, 0, nullptr); + + /// to simplify interop implementation + context->m_current_renderTarget = context->m_renderTargets[context->m_renderTargetIndex]->getResource(); + context->m_current_rtvHandle = rtvHandle; + context->m_current_dsvHandle = dsvHandle; + context->m_current_depth_srvHandle = context->m_depthSrvHeap->GetCPUDescriptorHandleForHeapStart(); +} + +void AppGraphCtxFramePresentD3D12(AppGraphCtx* contextIn, bool fullsync) +{ + auto context = cast_to_AppGraphCtxD3D12(contextIn); + + // check if now is good time to present + bool shouldPresent = context->m_fullscreen ? true : WaitForSingleObjectEx(context->m_swapChainWaitableObject, 0, TRUE) != WAIT_TIMEOUT; + if (shouldPresent) + { + context->m_swapChain->Present(fullsync, 0); + context->m_renderTargetID++; + } + + appGraphProfilerD3D12FrameEnd(context->m_profiler); + + // signal for this frame id + context->m_frameID++; + context->m_fenceValues[context->m_frameIndex] = context->m_frameID; + context->m_commandQueue->Signal(context->m_fence, context->m_frameID); + + // increment frame index after signal + context->m_frameIndex = (context->m_frameIndex + 1) % context->m_frameCount; + + if (fullsync) + { + // check dependencies + for (int frameIndex = 0; frameIndex < context->m_frameCount; frameIndex++) + { + UINT64 fenceCompleted = context->m_fence->GetCompletedValue(); + if (fenceCompleted < context->m_fenceValues[frameIndex]) + { + context->m_fence->SetEventOnCompletion(context->m_fenceValues[frameIndex], context->m_fenceEvent); + WaitForSingleObjectEx(context->m_fenceEvent, INFINITE, FALSE); + } + } + } +} + +void AppGraphCtxWaitForFramesD3D12(AppGraphCtx* contextIn, unsigned int maxFramesInFlight) +{ + auto context = cast_to_AppGraphCtxD3D12(contextIn); + + unsigned int framesActive = maxFramesInFlight; + while (framesActive >= maxFramesInFlight) + { + // reset count each cycle, and get latest fence value + framesActive = 0u; + UINT64 fenceCompleted = context->m_fence->GetCompletedValue(); + + // determine how many frames are in flight + for (int frameIndex = 0; frameIndex < context->m_frameCount; frameIndex++) + { + if (fenceCompleted < context->m_fenceValues[frameIndex]) + { + framesActive++; + } + } + + if (framesActive >= maxFramesInFlight) + { + // find the active frame with the lowest fence ID + UINT64 minFenceID = 0; + unsigned int minFrameIdx = 0; + for (int frameIndex = 0; frameIndex < context->m_frameCount; frameIndex++) + { + if (fenceCompleted < context->m_fenceValues[frameIndex]) + { + if (minFenceID == 0) + { + minFenceID = context->m_fenceValues[frameIndex]; + minFrameIdx = frameIndex; + } + else if (context->m_fenceValues[frameIndex] < minFenceID) + { + minFenceID = context->m_fenceValues[frameIndex]; + minFrameIdx = frameIndex; + } + } + } + // Wait for min frame + { + unsigned int frameIndex = minFrameIdx; + fenceCompleted = context->m_fence->GetCompletedValue(); + if (fenceCompleted < context->m_fenceValues[frameIndex]) + { + context->m_fence->SetEventOnCompletion(context->m_fenceValues[frameIndex], context->m_fenceEvent); + WaitForSingleObjectEx(context->m_fenceEvent, INFINITE, FALSE); + } + } + } + } +} + +void AppGraphCtxProfileEnableD3D12(AppGraphCtx* contextIn, bool enabled) +{ + auto context = cast_to_AppGraphCtxD3D12(contextIn); + appGraphProfilerD3D12Enable(context->m_profiler, enabled); +} + +void AppGraphCtxProfileBeginD3D12(AppGraphCtx* contextIn, const char* label) +{ + auto context = cast_to_AppGraphCtxD3D12(contextIn); + appGraphProfilerD3D12Begin(context->m_profiler, label); +} + +void AppGraphCtxProfileEndD3D12(AppGraphCtx* contextIn, const char* label) +{ + auto context = cast_to_AppGraphCtxD3D12(contextIn); + appGraphProfilerD3D12End(context->m_profiler, label); +} + +bool AppGraphCtxProfileGetD3D12(AppGraphCtx* contextIn, const char** plabel, float* cpuTime, float* gpuTime, int index) +{ + auto context = cast_to_AppGraphCtxD3D12(contextIn); + return appGraphProfilerD3D12Get(context->m_profiler, plabel, cpuTime, gpuTime, index); +} + +// ******************************* Dynamic descriptor heap ****************************** + +void AppDynamicDescriptorHeapD3D12::init(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE heapType, UINT minHeapSize) +{ + m_device = device; + m_heapSize = minHeapSize; + m_startSlot = 0u; + m_descriptorSize = m_device->GetDescriptorHandleIncrementSize(heapType); + + D3D12_DESCRIPTOR_HEAP_DESC desc = {}; + desc.NumDescriptors = m_heapSize; + desc.Type = heapType; + desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + m_device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&m_heap)); +} + +void AppDynamicDescriptorHeapD3D12::release() +{ + m_device = nullptr; + COMRelease(m_heap); + m_descriptorSize = 0u; + m_startSlot = 0u; + m_heapSize = 0u; +} + +AppDescriptorReserveHandleD3D12 AppDynamicDescriptorHeapD3D12::reserveDescriptors(UINT numDescriptors, UINT64 lastFenceCompleted, UINT64 nextFenceValue) +{ + UINT endSlot = m_startSlot + numDescriptors; + if (endSlot >= m_heapSize) + { + m_startSlot = 0u; + endSlot = numDescriptors; + } + D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle; + D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle; + cpuHandle = m_heap->GetCPUDescriptorHandleForHeapStart(); + cpuHandle.ptr += m_startSlot * m_descriptorSize; + gpuHandle = m_heap->GetGPUDescriptorHandleForHeapStart(); + gpuHandle.ptr += m_startSlot * m_descriptorSize; + + // advance start slot + m_startSlot = endSlot; + + AppDescriptorReserveHandleD3D12 handle = {}; + handle.heap = m_heap; + handle.descriptorSize = m_descriptorSize; + handle.cpuHandle = cpuHandle; + handle.gpuHandle = gpuHandle; + return handle; +} + +// ******************************* Profiler ********************************* + +namespace +{ + struct TimerCPU + { + LARGE_INTEGER oldCount; + LARGE_INTEGER count; + LARGE_INTEGER freq; + TimerCPU() + { + QueryPerformanceCounter(&count); + QueryPerformanceFrequency(&freq); + oldCount = count; + } + double getDeltaTime() + { + QueryPerformanceCounter(&count); + double dt = double(count.QuadPart - oldCount.QuadPart) / double(freq.QuadPart); + oldCount = count; + return dt; + } + }; + + struct TimerGPU + { + ID3D12QueryHeap* m_queryHeap = nullptr; + ID3D12Resource* m_queryReadback = nullptr; + UINT64 m_queryFrequency = 0; + UINT64 m_queryReadbackFenceVal = ~0llu; + + TimerGPU() {} + ~TimerGPU() + { + COMRelease(m_queryHeap); + COMRelease(m_queryReadback); + } + }; + + struct Timer + { + TimerCPU m_cpu; + TimerGPU m_gpu; + + const char* m_label = nullptr; + float m_cpuTime = 0.f; + float m_gpuTime = 0.f; + + Timer() {} + ~Timer() {} + }; + + struct TimerValue + { + const char* m_label = nullptr; + float m_cpuTime = 0.f; + float m_gpuTime = 0.f; + + struct Stat + { + float m_time = 0.f; + float m_maxTime = 0.f; + float m_maxTimeAge = 0.f; + + float m_smoothTime = 0.f; + float m_smoothTimeSum = 0.f; + float m_smoothTimeCount = 0.f; + + Stat() {} + void push(float time) + { + m_time = time; + + if (m_time > m_maxTime) + { + m_maxTime = m_time; + m_maxTimeAge = 0.f; + } + + if (fabsf(m_time - m_maxTime) < 0.25f * m_maxTime) + { + m_smoothTimeSum += m_time; + m_smoothTimeCount += 1.f; + m_smoothTimeSum *= 0.98f; + m_smoothTimeCount *= 0.98f; + m_smoothTime = m_smoothTimeSum / m_smoothTimeCount; + } + } + + float pull(float frameTime) + { + m_maxTimeAge += frameTime; + + if (m_maxTimeAge > 1.f) + { + m_maxTimeAge = 0.f; + m_maxTime = m_time; + m_smoothTimeSum = 0.f; + m_smoothTimeCount = 0.f; + } + return m_smoothTime; + } + }; + + Stat m_cpu; + Stat m_gpu; + + void push(float cpuTime, float gpuTime) + { + m_cpu.push(cpuTime); + m_gpu.push(gpuTime); + } + + void pull(float frameTime) + { + m_cpuTime = m_cpu.pull(frameTime); + m_gpuTime = m_gpu.pull(frameTime); + } + }; + + struct HeapPropsReadback : public D3D12_HEAP_PROPERTIES + { + HeapPropsReadback() + { + Type = D3D12_HEAP_TYPE_READBACK; + CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + CreationNodeMask = 0u; + VisibleNodeMask = 0u; + } + }; + struct ResourceDescBuffer : public D3D12_RESOURCE_DESC + { + ResourceDescBuffer(UINT64 size) + { + Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + Alignment = 0u; + Width = size; + Height = 1u; + DepthOrArraySize = 1u; + MipLevels = 1; + Format = DXGI_FORMAT_UNKNOWN; + SampleDesc.Count = 1u; + SampleDesc.Quality = 0u; + Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + Flags = D3D12_RESOURCE_FLAG_NONE; + } + }; +} + +struct AppGraphProfilerD3D12 +{ + AppGraphCtxD3D12* m_context; + + int m_state = 0; + bool m_enabled = false; + + TimerCPU m_frameTimer; + float m_frameTime = 0.f; + + static const int m_timersCap = 64; + Timer m_timers[m_timersCap]; + int m_timersSize = 0; + + TimerValue m_timerValues[m_timersCap]; + int m_timerValuesSize = 0; + + AppGraphProfilerD3D12(AppGraphCtx* context); + ~AppGraphProfilerD3D12(); +}; + +AppGraphProfilerD3D12::AppGraphProfilerD3D12(AppGraphCtx* context) : m_context(cast_to_AppGraphCtxD3D12(context)) +{ +} + +AppGraphProfilerD3D12::~AppGraphProfilerD3D12() +{ +} + +AppGraphProfilerD3D12* appGraphCreateProfilerD3D12(AppGraphCtx* ctx) +{ + return new AppGraphProfilerD3D12(ctx); +} + +void appGraphReleaseProfiler(AppGraphProfilerD3D12* profiler) +{ + delete profiler; +} + +void appGraphProfilerD3D12FrameBegin(AppGraphProfilerD3D12* p) +{ + p->m_frameTime = (float)p->m_frameTimer.getDeltaTime(); + + if (p->m_state == 0 && p->m_enabled) + { + p->m_timersSize = 0; + + p->m_state = 1; + } +} + +void appGraphProfilerD3D12FrameEnd(AppGraphProfilerD3D12* p) +{ + if (p->m_state == 1) + { + p->m_state = 2; + } +} + +void appGraphProfilerD3D12Enable(AppGraphProfilerD3D12* p, bool enabled) +{ + p->m_enabled = enabled; +} + +void appGraphProfilerD3D12Begin(AppGraphProfilerD3D12* p, const char* label) +{ + if (p->m_state == 1 && p->m_timersSize < p->m_timersCap) + { + auto& timer = p->m_timers[p->m_timersSize++]; + timer.m_label = label; + timer.m_cpu.getDeltaTime(); + + auto device = p->m_context->m_device; + + if (timer.m_gpu.m_queryHeap == nullptr) + { + D3D12_QUERY_HEAP_DESC queryDesc = {}; + queryDesc.Type = D3D12_QUERY_HEAP_TYPE_TIMESTAMP; + queryDesc.Count = 2; + queryDesc.NodeMask = 0; + + device->CreateQueryHeap(&queryDesc, IID_PPV_ARGS(&timer.m_gpu.m_queryHeap)); + + HeapPropsReadback readbackProps; + ResourceDescBuffer resDesc(2 * sizeof(UINT64)); + resDesc.Flags = D3D12_RESOURCE_FLAG_NONE; + + device->CreateCommittedResource(&readbackProps, D3D12_HEAP_FLAG_NONE, + &resDesc, D3D12_RESOURCE_STATE_COPY_DEST, + nullptr, IID_PPV_ARGS(&timer.m_gpu.m_queryReadback)); + } + + p->m_context->m_commandQueue->GetTimestampFrequency(&timer.m_gpu.m_queryFrequency); + + p->m_context->m_commandList->EndQuery(timer.m_gpu.m_queryHeap, D3D12_QUERY_TYPE_TIMESTAMP, 0); + } +} + +void appGraphProfilerD3D12End(AppGraphProfilerD3D12* p, const char* label) +{ + if (p->m_state == 1) + { + Timer* timer = nullptr; + for (int i = 0; i < p->m_timersSize; i++) + { + if (strcmp(p->m_timers[i].m_label, label) == 0) + { + timer = &p->m_timers[i]; + break; + } + } + if (timer) + { + p->m_context->m_commandList->EndQuery(timer->m_gpu.m_queryHeap, D3D12_QUERY_TYPE_TIMESTAMP, 1); + + p->m_context->m_commandList->ResolveQueryData(timer->m_gpu.m_queryHeap, D3D12_QUERY_TYPE_TIMESTAMP, 0, 2, timer->m_gpu.m_queryReadback, 0u); + + timer->m_gpu.m_queryReadbackFenceVal = p->m_context->m_thisFrameFenceID; + + timer->m_cpuTime = (float)timer->m_cpu.getDeltaTime(); + } + } +} + +bool appGraphProfilerD3D12Flush(AppGraphProfilerD3D12* p) +{ + if (p->m_state == 2) + { + for (int i = 0; i < p->m_timersSize; i++) + { + Timer& timer = p->m_timers[i]; + + if (timer.m_gpu.m_queryReadbackFenceVal > p->m_context->m_lastFenceComplete) + { + return false; + } + + UINT64 tsBegin, tsEnd; + { + void* data; + // Read range is nullptr, meaning full read access + D3D12_RANGE readRange; + readRange.Begin = 0u; + readRange.End = 2 * sizeof(UINT64); + timer.m_gpu.m_queryReadback->Map(0u, &readRange, &data); + if (data) + { + auto mapped = (UINT64*)data; + tsBegin = mapped[0]; + tsEnd = mapped[1]; + + D3D12_RANGE writeRange{}; + timer.m_gpu.m_queryReadback->Unmap(0u, &writeRange); + } + } + + timer.m_gpuTime = float(tsEnd - tsBegin) / float(timer.m_gpu.m_queryFrequency); + + // update TimerValue + int j = 0; + for (; j < p->m_timerValuesSize; j++) + { + TimerValue& value = p->m_timerValues[j]; + if (strcmp(value.m_label, timer.m_label) == 0) + { + value.push(timer.m_cpuTime, timer.m_gpuTime); + break; + } + } + if (j >= p->m_timerValuesSize && p->m_timerValuesSize < p->m_timersCap) + { + TimerValue& value = p->m_timerValues[p->m_timerValuesSize++]; + value.m_label = timer.m_label; + value.push(timer.m_cpuTime, timer.m_gpuTime); + } + } + + p->m_state = 0; + } + return false; +} + +bool appGraphProfilerD3D12Get(AppGraphProfilerD3D12* p, const char** plabel, float* cpuTime, float* gpuTime, int index) +{ + appGraphProfilerD3D12Flush(p); + { + if (index < p->m_timerValuesSize) + { + TimerValue& timer = p->m_timerValues[index]; + + timer.pull(p->m_frameTime); + + if (plabel) *plabel = timer.m_label; + if (cpuTime) *cpuTime = timer.m_cpuTime; + if (gpuTime) *gpuTime = timer.m_gpuTime; + + return true; + } + } + return false; +} + +size_t AppGraphCtxDedicatedVideoMemoryD3D12(AppGraphCtx* contextIn) +{ + auto context = cast_to_AppGraphCtxD3D12(contextIn); + return context->m_dedicatedVideoMemory; +} + +void AppGraphCtxBeginGpuWork(AppGraphCtxD3D12* context) +{ + if (context->m_commandListOpenCount == 0) + { + // It's not open so open it + ID3D12GraphicsCommandList* commandList = context->m_commandList; + + commandList->Reset(context->m_commandAllocators[context->m_frameIndex], nullptr); + } + context->m_commandListOpenCount++; +} + +void AppGraphCtxEndGpuWork(AppGraphCtxD3D12* context) +{ + assert(context->m_commandListOpenCount); + ID3D12GraphicsCommandList* commandList = context->m_commandList; + + NV_CORE_ASSERT_VOID_ON_FAIL(commandList->Close()); + { + // Execute the command list. + ID3D12CommandList* commandLists[] = { commandList }; + context->m_commandQueue->ExecuteCommandLists(_countof(commandLists), commandLists); + } + + AppGraphCtxWaitForGPU(context); + + // Dec the count. If >0 it needs to still be open + --context->m_commandListOpenCount; + + // Reopen if needs to be open + if (context->m_commandListOpenCount) + { + // Reopen + context->m_commandList->Reset(context->m_commandAllocators[context->m_frameIndex], nullptr); + } +} + +void AppGraphCtxPrepareRenderTarget(AppGraphCtxD3D12* context) +{ + D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = context->m_rtvHeap->GetCPUDescriptorHandleForHeapStart(); + rtvHandle.ptr += context->m_renderTargetIndex * context->m_rtvDescriptorSize; + + D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = context->m_dsvHeap->GetCPUDescriptorHandleForHeapStart(); + context->m_commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, &dsvHandle); + + // Set necessary state. + context->m_commandList->RSSetViewports(1, &context->m_viewport); + context->m_commandList->RSSetScissorRects(1, &context->m_scissorRect); +} + +void AppGraphCtxWaitForGPU(AppGraphCtxD3D12* context) +{ + context->m_frameID++; + context->m_fenceValues[context->m_frameIndex] = context->m_frameID; + + context->m_commandQueue->Signal(context->m_fence, context->m_frameID); + + for (int frameIndex = 0; frameIndex < context->m_frameCount; frameIndex++) + { + UINT64 fenceCompleted = context->m_fence->GetCompletedValue(); + if (fenceCompleted < context->m_fenceValues[frameIndex]) + { + context->m_fence->SetEventOnCompletion(context->m_fenceValues[frameIndex], context->m_fenceEvent); + WaitForSingleObjectEx(context->m_fenceEvent, INFINITE, FALSE); + } + } +}
\ No newline at end of file diff --git a/demo/d3d12/appD3D12Ctx.h b/demo/d3d12/appD3D12Ctx.h new file mode 100644 index 0000000..4f6ba77 --- /dev/null +++ b/demo/d3d12/appD3D12Ctx.h @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2014-2017, 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. + */ + +#ifndef APP_D3D12_CTX_H +#define APP_D3D12_CTX_H + +#include "../d3d/appGraphCtx.h" +#include "NvCoDx12Resource.h" +#include "NvCoDx12Handle.h" + +struct IDXGISwapChain3; + +struct AppGraphProfilerD3D12; + +struct AppDescriptorReserveHandleD3D12 +{ + ID3D12DescriptorHeap* heap; + UINT descriptorSize; + D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle; + D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle; +}; + +struct AppDynamicDescriptorHeapD3D12 +{ + ID3D12Device* m_device = nullptr; + ID3D12DescriptorHeap* m_heap = nullptr; + UINT m_descriptorSize = 0u; + UINT m_startSlot = 0u; + UINT m_heapSize = 0u; + + void init(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE heapType, UINT minHeapSize); + void release(); + AppDescriptorReserveHandleD3D12 reserveDescriptors(UINT numDescriptors, UINT64 lastFenceCompleted, UINT64 nextFenceValue); + + AppDynamicDescriptorHeapD3D12() {} + ~AppDynamicDescriptorHeapD3D12() { release(); } +}; + +struct AppGraphCtxD3D12 +{ + HWND m_hWnd = nullptr; + + int m_winW = 0; + int m_winH = 0; + bool m_fullscreen = false; + bool m_valid = false; + + size_t m_dedicatedVideoMemory = 0u; + + // D3D12 non-replicated objects + D3D12_VIEWPORT m_viewport = {}; + D3D12_RECT m_scissorRect = {}; + ID3D12Device* m_device = nullptr; + ID3D12CommandQueue* m_commandQueue = nullptr; + + // D3D12 render target pipeline + static const UINT m_renderTargetCount = 6u; + UINT m_renderTargetIndex = 0u; + UINT64 m_renderTargetID = 0u; + IDXGISwapChain3* m_swapChain = nullptr; + HANDLE m_swapChainWaitableObject = nullptr; + ID3D12DescriptorHeap* m_rtvHeap = nullptr; + UINT m_rtvDescriptorSize = 0u; + nvidia::Common::Dx12Resource m_backBuffers[m_renderTargetCount]; + nvidia::Common::Dx12Resource m_renderTargetResources[m_renderTargetCount]; + nvidia::Common::Dx12Resource* m_renderTargets[m_renderTargetCount]; + + ID3D12Resource* m_depthStencil = nullptr; + ID3D12DescriptorHeap* m_dsvHeap = nullptr; + ID3D12DescriptorHeap* m_depthSrvHeap = nullptr; + + // D3D12 frame pipeline objects + static const UINT m_frameCount = 8u; + UINT m_frameIndex = 0u; + UINT64 m_frameID = 0u; + ID3D12CommandAllocator* m_commandAllocators[m_frameCount]; + + // D3D12 synchronization objects + ID3D12Fence* m_fence = nullptr; + HANDLE m_fenceEvent = 0u; + UINT64 m_fenceValues[m_frameCount]; + + // fence values for library synchronization + UINT64 m_lastFenceComplete = 1u; + UINT64 m_thisFrameFenceID = 2u; + + // D3D12 per asset objects + ID3D12GraphicsCommandList* m_commandList = nullptr; + UINT m_commandListOpenCount = 0; + ID3D12Resource* m_current_renderTarget = nullptr; + D3D12_CPU_DESCRIPTOR_HANDLE m_current_rtvHandle; + D3D12_RENDER_TARGET_VIEW_DESC m_current_rtvDesc; + D3D12_CPU_DESCRIPTOR_HANDLE m_current_dsvHandle; + D3D12_DEPTH_STENCIL_VIEW_DESC m_current_dsvDesc; + D3D12_CPU_DESCRIPTOR_HANDLE m_current_depth_srvHandle; + D3D12_SHADER_RESOURCE_VIEW_DESC m_current_depth_srvDesc; + + DXGI_FORMAT m_rtv_format = DXGI_FORMAT_R8G8B8A8_UNORM; + DXGI_FORMAT m_dsv_format = DXGI_FORMAT_D32_FLOAT; + DXGI_FORMAT m_depth_srv_format = DXGI_FORMAT_R32_FLOAT; + DXGI_FORMAT m_depth_format = DXGI_FORMAT_R32_TYPELESS; + + UINT m_numMsaaSamples = 1; + + nvidia::Common::Dx12TargetInfo m_targetInfo; + + AppDynamicDescriptorHeapD3D12 m_dynamicHeapCbvSrvUav; + + AppGraphProfilerD3D12* m_profiler = nullptr; + + AppGraphCtxD3D12(); + ~AppGraphCtxD3D12(); +}; + +inline AppGraphCtxD3D12* cast_to_AppGraphCtxD3D12(AppGraphCtx* appctx) +{ + return (AppGraphCtxD3D12*)(appctx); +} + +inline AppGraphCtx* cast_from_AppGraphCtxD3D12(AppGraphCtxD3D12* appctx) +{ + return (AppGraphCtx*)(appctx); +} + +APP_GRAPH_CTX_API AppGraphCtx* AppGraphCtxCreateD3D12(int deviceID); + +APP_GRAPH_CTX_API bool AppGraphCtxUpdateSizeD3D12(AppGraphCtx* context, SDL_Window* window, bool fullscreen, int numMSAASamples); + +APP_GRAPH_CTX_API void AppGraphCtxReleaseRenderTargetD3D12(AppGraphCtx* context); + +APP_GRAPH_CTX_API void AppGraphCtxReleaseD3D12(AppGraphCtx* context); + +APP_GRAPH_CTX_API void AppGraphCtxFrameStartD3D12(AppGraphCtx* context, AppGraphColor clearColor); + +APP_GRAPH_CTX_API void AppGraphCtxFramePresentD3D12(AppGraphCtx* context, bool fullsync); + +APP_GRAPH_CTX_API void AppGraphCtxWaitForFramesD3D12(AppGraphCtx* context, unsigned int maxFramesInFlight); + +APP_GRAPH_CTX_API void AppGraphCtxProfileEnableD3D12(AppGraphCtx* context, bool enabled); + +APP_GRAPH_CTX_API void AppGraphCtxProfileBeginD3D12(AppGraphCtx* context, const char* label); + +APP_GRAPH_CTX_API void AppGraphCtxProfileEndD3D12(AppGraphCtx* context, const char* label); + +APP_GRAPH_CTX_API bool AppGraphCtxProfileGetD3D12(AppGraphCtx* context, const char** plabel, float* cpuTime, float* gpuTime, int index); + +APP_GRAPH_CTX_API size_t AppGraphCtxDedicatedVideoMemoryD3D12(AppGraphCtx* context); + +APP_GRAPH_CTX_API void AppGraphCtxBeginGpuWork(AppGraphCtxD3D12* context); + +APP_GRAPH_CTX_API void AppGraphCtxEndGpuWork(AppGraphCtxD3D12* context); + +APP_GRAPH_CTX_API void AppGraphCtxPrepareRenderTarget(AppGraphCtxD3D12* context); + +APP_GRAPH_CTX_API void AppGraphCtxWaitForGPU(AppGraphCtxD3D12* context); + +/// ScopeGpuWork is used to handle gpu work that must be synchronized with the CPU. +/// It is guaranteed when scope is released the CPU and GPU will sync. NOTE! This means +/// you don't want to do this as part of render/update unless you have to because it will be slow. +struct ScopeGpuWork +{ + inline ScopeGpuWork(AppGraphCtxD3D12* context) : + m_context(context) + { + AppGraphCtxBeginGpuWork(context); + } + inline ~ScopeGpuWork() + { + AppGraphCtxEndGpuWork(m_context); + } +private: + AppGraphCtxD3D12* m_context; +}; +#endif
\ No newline at end of file diff --git a/demo/d3d12/bufferD3D12.cpp b/demo/d3d12/bufferD3D12.cpp new file mode 100644 index 0000000..b7954ea --- /dev/null +++ b/demo/d3d12/bufferD3D12.cpp @@ -0,0 +1,118 @@ +/* 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 <NvCoDx12HelperUtil.h> +#include <external/D3D12/include/d3dx12.h> + +#include "bufferD3D12.h" + +#include <vector> + +namespace FlexSample { + +int IndexBufferD3D12::init(const RenderStateD3D12& state, int stride, ptrdiff_t numIndices, const void* sysMem) +{ + assert(sysMem); + assert(stride == 4); + const size_t bufferSize = stride * numIndices; + + { + ComPtr<ID3D12Resource> resource; + CD3DX12_HEAP_PROPERTIES defaultHeapProps(D3D12_HEAP_TYPE_DEFAULT); + D3D12_RESOURCE_DESC resourceDesc(CD3DX12_RESOURCE_DESC::Buffer(bufferSize)); + if (sysMem) + { + NV_RETURN_ON_FAIL(state.m_device->CreateCommittedResource(&defaultHeapProps, D3D12_HEAP_FLAG_NONE, &resourceDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, + IID_PPV_ARGS(&resource))); + NV_RETURN_ON_FAIL(state.m_scopeManager->upload(state.m_commandList, sysMem, resource.Get(), D3D12_RESOURCE_STATE_COMMON)); + } + else + { + NV_RETURN_ON_FAIL(state.m_device->CreateCommittedResource(&defaultHeapProps, D3D12_HEAP_FLAG_NONE, &resourceDesc, D3D12_RESOURCE_STATE_COMMON, nullptr, + IID_PPV_ARGS(&resource))); + } + setResource(resource.Get(), D3D12_RESOURCE_STATE_COMMON); + } + + memset(&m_indexBufferView, 0, sizeof(m_indexBufferView)); + m_indexBufferView.BufferLocation = m_resource->GetGPUVirtualAddress(); + m_indexBufferView.SizeInBytes = UINT(bufferSize); + m_indexBufferView.Format = DXGI_FORMAT_R32_UINT; + return NV_OK; +} + +int VertexBufferD3D12::init(const RenderStateD3D12& state, int stride, ptrdiff_t numElements, const void* sysMem, D3D12_RESOURCE_FLAGS resourceFlags) +{ + if (!sysMem) + { + memset(&m_vertexBufferView, 0, sizeof(m_vertexBufferView)); + return NV_OK; + } + + size_t bufferSize = size_t(numElements * stride); + + { + CD3DX12_HEAP_PROPERTIES defaultHeapProps(D3D12_HEAP_TYPE_DEFAULT); + D3D12_RESOURCE_DESC resourceDesc(CD3DX12_RESOURCE_DESC::Buffer(bufferSize, resourceFlags)); + ComPtr<ID3D12Resource> resource; + + if (sysMem) + { + NV_RETURN_ON_FAIL(state.m_device->CreateCommittedResource(&defaultHeapProps, D3D12_HEAP_FLAG_NONE, &resourceDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, + IID_PPV_ARGS(&resource))); + NV_RETURN_ON_FAIL(state.m_scopeManager->upload(state.m_commandList, sysMem, resource.Get(), D3D12_RESOURCE_STATE_COMMON)); + } + else + { + NV_RETURN_ON_FAIL(state.m_device->CreateCommittedResource(&defaultHeapProps, D3D12_HEAP_FLAG_NONE, &resourceDesc, D3D12_RESOURCE_STATE_COMMON, nullptr, + IID_PPV_ARGS(&resource))); + } + setResource(resource.Get(), D3D12_RESOURCE_STATE_COMMON); + } + + { + memset(&m_vertexBufferView, 0, sizeof(m_vertexBufferView)); + m_vertexBufferView.BufferLocation = m_resource->GetGPUVirtualAddress(); + m_vertexBufferView.SizeInBytes = UINT(bufferSize); + m_vertexBufferView.StrideInBytes = stride; + } + + return NV_OK; +} + +int VertexBufferD3D12::init(const RenderStateD3D12& state, int srcStride, int dstStride, ptrdiff_t numElements, const void* sysMem, D3D12_RESOURCE_FLAGS resourceFlags) +{ + if (srcStride == dstStride || sysMem == nullptr) + { + return init(state, dstStride, numElements, sysMem, resourceFlags); + } + else + { + if (srcStride == 4 * 4 && dstStride == 4 * 3) + { + std::vector<uint32_t> buf(numElements * 3); + uint32_t* dst = &buf.front(); + const uint32_t* src = (const uint32_t*)sysMem; + + for (ptrdiff_t i = 0; i < numElements; i++, dst += 3, src += 4) + { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + } + + return init(state, dstStride, numElements, &buf.front(), resourceFlags); + } + } + + assert(!"Unhandled conversion"); + return NV_FAIL; +} + + +} // namespace FlexSample diff --git a/demo/d3d12/bufferD3D12.h b/demo/d3d12/bufferD3D12.h new file mode 100644 index 0000000..b2bd98a --- /dev/null +++ b/demo/d3d12/bufferD3D12.h @@ -0,0 +1,38 @@ +#ifndef BUFFER_D3D12_H +#define BUFFER_D3D12_H + +#include <NvCoDx12Resource.h> + +#include "renderStateD3D12.h" + +#define NOMINMAX +#include <dxgi.h> +#include <d3d12.h> + +namespace FlexSample { +using namespace nvidia; + +struct IndexBufferD3D12: public NvCo::Dx12Resource +{ + int init(const RenderStateD3D12& state, int stride, ptrdiff_t numIndices, const void* sysMem); + /// Reset + void reset() { setResourceNull(); } + + D3D12_INDEX_BUFFER_VIEW m_indexBufferView; +}; + +struct VertexBufferD3D12: public NvCo::Dx12Resource +{ + /// + int init(const RenderStateD3D12& state, int stride, ptrdiff_t numElements, const void* sysMem, D3D12_RESOURCE_FLAGS resourceFlags = D3D12_RESOURCE_FLAG_NONE); + int init(const RenderStateD3D12& state, int srcStride, int stride, ptrdiff_t numElements, const void* sysMem, D3D12_RESOURCE_FLAGS resourceFlags = D3D12_RESOURCE_FLAG_NONE); + + /// Ctor + VertexBufferD3D12() {} + + D3D12_VERTEX_BUFFER_VIEW m_vertexBufferView; +}; + +} // namespace FlexSample + +#endif // BUFFER_D3D12_H diff --git a/demo/d3d12/demoContextD3D12.cpp b/demo/d3d12/demoContextD3D12.cpp new file mode 100644 index 0000000..8a698f7 --- /dev/null +++ b/demo/d3d12/demoContextD3D12.cpp @@ -0,0 +1,1410 @@ +// to fix min max windows macros +#define NOMINMAX + +#include "meshRendererD3D12.h" + +// Pipelines + +#include "meshRenderPipelineD3D12.h" +#include "pointRenderPipelineD3D12.h" +#include "fluidEllipsoidRenderPipelineD3D12.h" +#include "fluidSmoothRenderPipelineD3D12.h" +#include "fluidCompositeRenderPipelineD3D12.h" +#include "diffusePointRenderPipelineD3D12.h" +#include "lineRenderPipelineD3D12.h" + +#include "meshUtil.h" + +#include <NvCoDx12RenderTarget.h> + +// SDL +#include <SDL_syswm.h> + +#include "d3d/shadersDemoContext.h" + +// Flex +#include "core/maths.h" +#include "core/extrude.h" + +#define NOMINMAX +#include <d3d12.h> +#include <d3dcompiler.h> + +#include "imguiGraphD3D12.h" + +#include "../d3d/loader.h" + +#include "demoContextD3D12.h" + +// include the Direct3D Library file +#pragma comment (lib, "d3d12.lib") +#pragma comment (lib, "DXGI.lib") + +using namespace DirectX; + +static float gSpotMin = 0.5f; +static float gSpotMax = 1.0f; +static float gShadowBias = 0.075f; +static const int kShadowResolution = 2048; + +// Global externally +extern Colour g_colors[]; + +#define NV_PRINT_F_U64 "%I64u" + +DemoContext* CreateDemoContextD3D12() +{ + return new FlexSample::DemoContextD3D12; +} + +namespace FlexSample { + +DemoContextD3D12::DemoContextD3D12() +{ + m_shadowMapLinearSamplerIndex = -1; + m_fluidPointDepthSrvIndex = -1; + m_currentShadowMap = nullptr; + m_targetShadowMap = nullptr; + + m_inLineDraw = false; + memset(&m_meshDrawParams, 0, sizeof(m_meshDrawParams)); + + m_hwnd = nullptr; + m_window = nullptr; + + // Allocate space for all debug vertices + m_debugLineVertices.resize(MAX_DEBUG_LINE_SIZE); +} + +DemoContextD3D12::~DemoContextD3D12() +{ + imguiGraphDestroy(); +} + +bool DemoContextD3D12::initialize(const RenderInitOptions& options) +{ + // must always have at least one sample + m_msaaSamples = Max(1, options.numMsaaSamples); + + { + // Load external modules + loadModules(APP_CONTEXT_D3D12); + } + + m_appGraphCtx = AppGraphCtxCreate(0); + m_renderContext = cast_to_AppGraphCtxD3D12(m_appGraphCtx); + + AppGraphCtxUpdateSize(m_appGraphCtx, options.window, options.fullscreen, m_msaaSamples); + + using namespace NvCo; + // Get the hwnd + m_hwnd = nullptr; + m_window = options.window; + { + // get Windows handle to this SDL window + SDL_SysWMinfo winInfo; + SDL_VERSION(&winInfo.version); + if (SDL_GetWindowWMInfo(options.window, &winInfo)) + { + if (winInfo.subsystem == SDL_SYSWM_WINDOWS) + { + m_hwnd = winInfo.info.win.window; + } + } + } + + { + WCHAR buffer[_MAX_PATH]; + DWORD size = GetModuleFileNameW(nullptr, buffer, _MAX_PATH); + if (size == 0 || size == _MAX_PATH) + { + // Method failed or path was truncated. + return false; + } + std::wstring path; + path += buffer; + const size_t lastSlash = path.find_last_of(L"\\"); + if (lastSlash >= 0) + { + path.resize(lastSlash + 1); + } + + m_executablePath.swap(path); + } + + { + m_shadersPath = m_executablePath; + m_shadersPath += L"../../demo/d3d/shaders/"; + } + + int width, height; + SDL_GetWindowSize(m_window, &width, &height); + + { + ScopeGpuWork scope(getRenderContext()); + NV_RETURN_FALSE_ON_FAIL(_initRenderResources(options)); + + { + // create imgui, connect to app graph context + ImguiGraphDescD3D12 desc; + desc.device = m_renderContext->m_device; + desc.commandList = m_renderContext->m_commandList; + desc.lastFenceCompleted = 0; + desc.nextFenceValue = 1; + desc.winW = m_renderContext->m_winW; + desc.winW = m_renderContext->m_winH; + desc.numMSAASamples = options.numMsaaSamples; + desc.dynamicHeapCbvSrvUav.userdata = this; + desc.dynamicHeapCbvSrvUav.reserveDescriptors = NULL; + + int defaultFontHeight = (options.defaultFontHeight <= 0) ? 13 : options.defaultFontHeight; + + if (!imguiGraphInit("../../data/DroidSans.ttf", float(defaultFontHeight), (ImguiGraphDesc*)&desc)) + { + return false; + } + } + } + + return true; +} + +int DemoContextD3D12::_initRenderResources(const RenderInitOptions& options) +{ + AppGraphCtxD3D12* renderContext = getRenderContext(); + ID3D12Device* device = renderContext->m_device; + + { + // https://msdn.microsoft.com/en-us/library/windows/desktop/dn859253(v=vs.85).aspx + // https://msdn.microsoft.com/en-us/library/windows/desktop/ff476876(v=vs.85).aspx#Overview + D3D12_FEATURE_DATA_D3D12_OPTIONS options; + device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options)); + } + + { + // Make enough space for largest _single_ dynamic buffer allocation + NV_RETURN_ON_FAIL(m_renderStateManager.initialize(renderContext, 16 * 1024 * 1024)); + m_renderState = m_renderStateManager.getState(); + } + + // Create the renderer + { + std::unique_ptr<MeshRendererD3D12> renderer(new MeshRendererD3D12); + NV_RETURN_ON_FAIL(renderer->initialize(m_renderState)); + m_meshRenderer = std::move(renderer); + } + + { + // NOTE! Must be in this order, as compositePS expects s0, s1 = linear, shadow samplers, in that order + m_linearSamplerIndex = m_renderState.m_samplerDescriptorHeap->allocate(); + m_shadowMapLinearSamplerIndex = m_renderState.m_samplerDescriptorHeap->allocate(); + + { + // linear sampler with comparator - used for shadow map sampling + D3D12_SAMPLER_DESC desc = + { + D3D12_FILTER_COMPARISON_MIN_MAG_MIP_POINT, + D3D12_TEXTURE_ADDRESS_MODE_CLAMP, + D3D12_TEXTURE_ADDRESS_MODE_CLAMP, + D3D12_TEXTURE_ADDRESS_MODE_CLAMP, + 0.0f, 0, D3D12_COMPARISON_FUNC_LESS_EQUAL, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, + }; + device->CreateSampler(&desc, m_renderState.m_samplerDescriptorHeap->getCpuHandle(m_shadowMapLinearSamplerIndex)); + } + { + // A regular linear sampler + D3D12_SAMPLER_DESC desc = + { + D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT, + D3D12_TEXTURE_ADDRESS_MODE_CLAMP, + D3D12_TEXTURE_ADDRESS_MODE_CLAMP, + D3D12_TEXTURE_ADDRESS_MODE_CLAMP, + 0.0, 0, D3D12_COMPARISON_FUNC_NEVER, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, + }; + device->CreateSampler(&desc, m_renderState.m_samplerDescriptorHeap->getCpuHandle(m_linearSamplerIndex)); + } + } + + // Allocate the srvs used for fluid render targets + { + m_fluidPointDepthSrvIndex = m_renderState.m_srvCbvUavDescriptorHeap->allocate(); + m_fluidCompositeSrvBaseIndex = m_renderState.m_srvCbvUavDescriptorHeap->allocate(NUM_COMPOSITE_SRVS); + } + + // Create the shadow map + { + m_shadowMap = std::unique_ptr<NvCo::Dx12RenderTarget>(new NvCo::Dx12RenderTarget); + + NvCo::Dx12RenderTarget::Desc desc; + desc.init(kShadowResolution, kShadowResolution); + desc.m_targetFormat = DXGI_FORMAT_UNKNOWN; + desc.m_depthStencilFormat = DXGI_FORMAT_R32_TYPELESS; + + // Make a small shadow map so we can configure pipeline correctly + NV_RETURN_ON_FAIL(m_shadowMap->init(renderContext, desc)); + + m_shadowMap->setDebugName(L"ShadowMap"); + + if (m_shadowMap->allocateSrvView(NvCo::Dx12RenderTarget::BUFFER_DEPTH_STENCIL, device, *m_renderState.m_srvCbvUavDescriptorHeap) < 0) + { + printf("Unable to allocate shadow buffer srv index"); + + return NV_FAIL; + } + } + + // Init fluid resources + NV_RETURN_ON_FAIL(_initFluidRenderTargets()); + + // Create pipelines + { + + // Mesh + { + std::unique_ptr<MeshRenderPipelineD3D12> pipeline(new MeshRenderPipelineD3D12); + NV_RETURN_ON_FAIL(pipeline->initialize(m_renderState, m_shadersPath, FRONT_WINDING_COUNTER_CLOCKWISE, m_shadowMapLinearSamplerIndex, m_shadowMap.get(), options.asyncComputeBenchmark)); + m_meshPipeline = std::move(pipeline); + } + // Point + { + std::unique_ptr<PointRenderPipelineD3D12> pipeline(new PointRenderPipelineD3D12); + NV_RETURN_ON_FAIL(pipeline->initialize(m_renderState, m_shadersPath, m_shadowMapLinearSamplerIndex, m_shadowMap.get())); + m_pointPipeline = std::move(pipeline); + } + // FluidPoint + { + std::unique_ptr<FluidEllipsoidRenderPipelineD3D12> pipeline(new FluidEllipsoidRenderPipelineD3D12); + NV_RETURN_ON_FAIL(pipeline->initialize(m_renderState, m_shadersPath, m_fluidPointRenderTarget.get())); + m_fluidPointPipeline = std::move(pipeline); + } + // FluidSmooth + { + std::unique_ptr<FluidSmoothRenderPipelineD3D12> pipeline(new FluidSmoothRenderPipelineD3D12(m_fluidPointDepthSrvIndex)); + NV_RETURN_ON_FAIL(pipeline->initialize(m_renderState, m_shadersPath, m_fluidSmoothRenderTarget.get())); + m_fluidSmoothPipeline = std::move(pipeline); + } + // FluidComposite + { + std::unique_ptr<FluidCompositeRenderPipelineD3D12> pipeline(new FluidCompositeRenderPipelineD3D12); + NV_RETURN_ON_FAIL(pipeline->initialize(m_renderState, m_shadersPath)); + m_fluidCompositePipeline = std::move(pipeline); + } + // DiffusePoint + { + std::unique_ptr<DiffusePointRenderPipelineD3D12> pipeline(new DiffusePointRenderPipelineD3D12); + NV_RETURN_ON_FAIL(pipeline->initialize(m_renderState, m_shadersPath, m_linearSamplerIndex, m_shadowMap.get())); + m_diffusePointPipeline = std::move(pipeline); + } + // Line + { + std::unique_ptr<LineRenderPipelineD3D12> pipeline(new LineRenderPipelineD3D12); + NV_RETURN_ON_FAIL(pipeline->initialize(m_renderState, m_shadersPath, m_shadowMap.get())); + m_linePipeline = std::move(pipeline); + } + } + + { + // Create a passthru screen quad + uint32_t indices[] = { 0, 1, 2, 0, 2, 3 }; + Vec3 pos[] = { { -1, -1, 0} , {1, -1, 0}, {1, 1, 0}, {-1, 1, 0} }; + Vec2 uvs[] = { { 0, 0}, {1, 0}, {1, 1}, {0, 1} }; + + MeshData mesh; + mesh.init(); + + mesh.indices = indices; + mesh.positions = pos; + mesh.texcoords = uvs; + mesh.numFaces = _countof(indices) / 3; + mesh.numVertices = _countof(pos); + + m_screenQuadMesh = std::unique_ptr<FlexSample::RenderMesh>(m_meshRenderer->createMesh(mesh)); + } + + // create synchronization objects + { + m_graphicsCompleteEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); + if (!m_graphicsCompleteEvent) + { + return E_FAIL; + } + NV_RETURN_ON_FAIL(device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_graphicsCompleteFence))); + m_graphicsCompleteFenceValue = 1; + } + + { + // Query heap and results buffer + + // Create timestamp query heap and results buffer + const int queryCount = 2; + D3D12_QUERY_HEAP_DESC queryHeapDesc = { D3D12_QUERY_HEAP_TYPE_TIMESTAMP, queryCount, 0 /* NodeMask */ }; + NV_RETURN_ON_FAIL(device->CreateQueryHeap(&queryHeapDesc, IID_PPV_ARGS(&m_queryHeap))); + + D3D12_HEAP_PROPERTIES heapProps = + { + D3D12_HEAP_TYPE_READBACK, + D3D12_CPU_PAGE_PROPERTY_UNKNOWN, + D3D12_MEMORY_POOL_UNKNOWN, + 0, + 0 + }; + + D3D12_RESOURCE_DESC queryBufDesc = + { + D3D12_RESOURCE_DIMENSION_BUFFER, + 0u, + queryCount * sizeof(uint64_t), + 1u, + 1u, + 1, + DXGI_FORMAT_UNKNOWN, + { 1u, 0u }, + D3D12_TEXTURE_LAYOUT_ROW_MAJOR, + D3D12_RESOURCE_FLAG_NONE + }; + + NV_RETURN_ON_FAIL(device->CreateCommittedResource( + &heapProps, + D3D12_HEAP_FLAG_NONE, + &queryBufDesc, + D3D12_RESOURCE_STATE_COPY_DEST, + nullptr, + IID_PPV_ARGS(&m_queryResults))); + } + return NV_OK; +} + +int DemoContextD3D12::_initFluidRenderTargets() +{ + AppGraphCtxD3D12* renderContext = getRenderContext(); + ID3D12Device* device = renderContext->m_device; + + // Fluid point render target + { + { + std::unique_ptr<NvCo::Dx12RenderTarget> target(new NvCo::Dx12RenderTarget); + NvCo::Dx12RenderTarget::Desc desc; + desc.init(renderContext->m_winW, renderContext->m_winH, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_TYPELESS); + for(int i=0;i!=4;i++) desc.m_targetClearColor[i] = 0; + + NV_RETURN_ON_FAIL(target->init(renderContext, desc)); + + target->setDebugName(L"Fluid Point"); + m_fluidPointRenderTarget = std::move(target); + } + + } + + // Fluid smooth + { + std::unique_ptr<NvCo::Dx12RenderTarget> target(new NvCo::Dx12RenderTarget); + NvCo::Dx12RenderTarget::Desc desc; + desc.init(renderContext->m_winW, renderContext->m_winH, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_UNKNOWN); + for (int i = 0; i != 4; i++) desc.m_targetClearColor[i] = 0; + + NV_RETURN_ON_FAIL(target->init(renderContext, desc)); + + target->setDebugName(L"Fluid Smooth"); + m_fluidSmoothRenderTarget = std::move(target); + } + + // The resolved target for final compose + { + std::unique_ptr<NvCo::Dx12RenderTarget> target(new NvCo::Dx12RenderTarget); + NvCo::Dx12RenderTarget::Desc desc; + Vec4 clearColor = { 1, 0, 1, 1 }; + desc.m_targetClearColor = clearColor; + desc.init(renderContext->m_winW, renderContext->m_winH, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); + + NV_RETURN_ON_FAIL(target->init(renderContext, desc)); + + target->setDebugName(L"Fluid Resolved Target"); + m_fluidResolvedTarget = std::move(target); + } + + // Init all of the srvs!!!! + + { + NvCo::Dx12DescriptorHeap& heap = *m_renderState.m_srvCbvUavDescriptorHeap; + // Set up the srv for accessing this buffer + { + m_fluidPointRenderTarget->createSrv(device, heap, NvCo::Dx12RenderTarget::BUFFER_TARGET, m_fluidPointDepthSrvIndex); + } + + { + // 0 - is the depth texture m_fluidSmoothRenderTarget (target) + // 1 - is the 'composite' scene texture m_fluidResolvedTarget (target) + // 2 - shadow texture m_shadowMap (depth stencil) + + m_fluidSmoothRenderTarget->createSrv(device, heap, NvCo::Dx12RenderTarget::BUFFER_TARGET, m_fluidCompositeSrvBaseIndex + 0); + m_fluidResolvedTarget->createSrv(device, heap, NvCo::Dx12RenderTarget::BUFFER_TARGET, m_fluidCompositeSrvBaseIndex + 1); + m_shadowMap->createSrv(device, heap, NvCo::Dx12RenderTarget::BUFFER_DEPTH_STENCIL, m_fluidCompositeSrvBaseIndex + 2); + } + } + + return NV_OK; +} + +void DemoContextD3D12::onSizeChanged(int width, int height, bool minimized) +{ + // Free any set render targets + m_fluidPointRenderTarget.reset(); + m_fluidSmoothRenderTarget.reset(); + m_fluidResolvedTarget.reset(); + + // Will need to create the render targets.. + _initFluidRenderTargets(); +} + +void DemoContextD3D12::startFrame(FlexVec4 colorIn) +{ + AppGraphCtxD3D12* renderContext = getRenderContext(); + + // Work out what what can be recovered, as GPU no longer accessing + m_renderStateManager.updateCompleted(); + + AppGraphColor clearColor = { colorIn.x, colorIn.y, colorIn.z, colorIn.w }; + AppGraphCtxFrameStart(cast_from_AppGraphCtxD3D12(renderContext), clearColor); + + { + MeshDrawParamsD3D& params = m_meshDrawParams; + memset(¶ms, 0, sizeof(MeshDrawParamsD3D)); + params.renderStage = MESH_DRAW_LIGHT; + params.renderMode = MESH_RENDER_SOLID; + params.cullMode = MESH_CULL_BACK; + params.projection = XMMatrixIdentity(); + params.view = XMMatrixIdentity(); + params.model = DirectX::XMMatrixMultiply( + DirectX::XMMatrixScaling(1.0f, 1.0f, 1.0f), + DirectX::XMMatrixTranslation(0.0f, 0.0f, 0.0f) + ); + } +} + +void DemoContextD3D12::endFrame() +{ + { + ImguiGraphDescD3D12 desc; + desc.device = m_renderContext->m_device; + desc.commandList = m_renderContext->m_commandList; + desc.winW = m_renderContext->m_winW; + desc.winH = m_renderContext->m_winH; + + imguiGraphUpdate((ImguiGraphDesc*)&desc); + } + + AppGraphCtxD3D12* renderContext = getRenderContext(); + + nvidia::Common::Dx12Resource& backBuffer = renderContext->m_backBuffers[renderContext->m_renderTargetIndex]; + if (renderContext->m_numMsaaSamples > 1) + { + // MSAA resolve + nvidia::Common::Dx12Resource& renderTarget = *renderContext->m_renderTargets[renderContext->m_renderTargetIndex]; + assert(&renderTarget != &backBuffer); + // Barriers to wait for the render target, and the backbuffer to be in correct state + { + nvidia::Common::Dx12BarrierSubmitter submitter(renderContext->m_commandList); + renderTarget.transition(D3D12_RESOURCE_STATE_RESOLVE_SOURCE, submitter); + backBuffer.transition(D3D12_RESOURCE_STATE_RESOLVE_DEST, submitter); + } + // Do the resolve... + renderContext->m_commandList->ResolveSubresource(backBuffer, 0, renderTarget, 0, renderContext->m_targetInfo.m_renderTargetFormats[0]); + } + + { + nvidia::Common::Dx12BarrierSubmitter submitter(renderContext->m_commandList); + backBuffer.transition(D3D12_RESOURCE_STATE_PRESENT, submitter); + } + + renderContext->m_commandList->Close(); + + // submit command list + ID3D12CommandList* cmdLists[] = { renderContext->m_commandList }; + renderContext->m_commandQueue->ExecuteCommandLists(1, cmdLists); + + renderContext->m_commandListOpenCount = 0; + + // Inform the manager that the work has been submitted + m_renderStateManager.onGpuWorkSubmitted(renderContext->m_commandQueue); + + HANDLE completeEvent = m_graphicsCompleteEvent; + + renderContext->m_commandQueue->Signal(m_graphicsCompleteFence.Get(), m_graphicsCompleteFenceValue); +} + +void DemoContextD3D12::getRenderDevice(void** device, void** context) +{ + *device = m_renderContext->m_device; + *context = m_renderContext->m_commandQueue; +} + +void DemoContextD3D12::startGpuWork() +{ + AppGraphCtxBeginGpuWork(m_renderContext); +} + +void DemoContextD3D12::endGpuWork() +{ + AppGraphCtxEndGpuWork(m_renderContext); +} + +void DemoContextD3D12::presentFrame(bool fullsync) +{ + AppGraphCtxFramePresent(cast_from_AppGraphCtxD3D12(m_renderContext), fullsync); +} + +void DemoContextD3D12::getViewRay(int x, int y, FlexVec3& origin, FlexVec3& dir) +{ + //using namespace DirectX; + AppGraphCtxD3D12* renderContext = getRenderContext(); + + int width = renderContext->m_winW; + int height = renderContext->m_winH; + + XMVECTOR nearVector = XMVector3Unproject(XMVectorSet(float(x), float(height - y), 0.0f, 0.0f), 0.0f, 0.0f, (float)width, (float)height, 0.0f, 1.0f, (XMMATRIX)m_proj, XMMatrixIdentity(), (XMMATRIX)m_view); + XMVECTOR farVector = XMVector3Unproject(XMVectorSet(float(x), float(height - y), 1.0f, 0.0f), 0.0f, 0.0f, (float)width, (float)height, 0.0f, 1.0f, (XMMATRIX)m_proj, XMMatrixIdentity(), (XMMATRIX)m_view); + + origin = FlexVec3(XMVectorGetX(nearVector), XMVectorGetY(nearVector), XMVectorGetZ(nearVector)); + XMVECTOR tmp = farVector - nearVector; + dir = Normalize(FlexVec3(XMVectorGetX(tmp), XMVectorGetY(tmp), XMVectorGetZ(tmp))); +} + +void DemoContextD3D12::setView(Matrix44 view, Matrix44 projection) +{ + Matrix44 vp = projection*view; + MeshDrawParamsD3D& params = m_meshDrawParams; + + params.model = XMMatrixIdentity(); + params.view = (XMMATRIX)view; + params.projection = (XMMATRIX)(RenderParamsUtilD3D::convertGLToD3DProjection(projection)); + + m_view = view; + m_proj = RenderParamsUtilD3D::convertGLToD3DProjection(projection); +} + +void DemoContextD3D12::renderEllipsoids(FluidRenderer* renderer, FluidRenderBuffers* buffersIn, int n, int offset, float radius, float screenWidth, float screenAspect, float fov, FlexVec3 lightPos, FlexVec3 lightTarget, Matrix44 lightTransform, ::ShadowMap* shadowMap, FlexVec4 color, float blur, float ior, bool debug) +{ + FluidRenderBuffersD3D12& buffers = *reinterpret_cast<FluidRenderBuffersD3D12*>(buffersIn); + if (n == 0) + return; + + typedef PointRenderAllocationD3D12 Alloc; + + Alloc alloc; + alloc.init(PRIMITIVE_POINT); + + alloc.m_numPrimitives = buffers.m_numParticles; + alloc.m_numPositions = 0; ///? We don't know here yet... + + alloc.m_indexBufferView = buffers.m_indicesView; + alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_DENSITY] = buffers.m_densitiesView; + alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_POSITION] = buffers.m_positionsView; + alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_ANISOTROPY1] = buffers.m_anisotropiesViewArr[0]; + alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_ANISOTROPY2] = buffers.m_anisotropiesViewArr[1]; + alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_ANISOTROPY3] = buffers.m_anisotropiesViewArr[2]; + + AppGraphCtxD3D12* renderContext = getRenderContext(); + + FluidDrawParamsD3D params; + + params.renderMode = FLUID_RENDER_SOLID; + params.cullMode = FLUID_CULL_BACK; + params.model = XMMatrixIdentity(); + params.view = (XMMATRIX&)m_view; + params.projection = (XMMATRIX&)m_proj; + + params.offset = offset; + params.n = n; + params.renderStage = FLUID_DRAW_LIGHT; + + const float viewHeight = tanf(fov / 2.0f); + params.invViewport = Hlsl::float3(1.0f / screenWidth, screenAspect / screenWidth, 1.0f); + params.invProjection = Hlsl::float3(screenAspect * viewHeight, viewHeight, 1.0f); + params.debug = 0; + + params.shadowMap = nullptr; + + { + m_fluidPointRenderTarget->toWritable(renderContext); + m_fluidPointRenderTarget->bindAndClear(renderContext); + + // Draw the ellipsoids + m_meshRenderer->drawTransitory(alloc, sizeof(Alloc), m_fluidPointPipeline.get(), ¶ms); + + m_fluidPointRenderTarget->toReadable(renderContext); + } + + //--------------------------------------------------------------- + // build smooth depth + + { + m_fluidSmoothRenderTarget->toWritable(renderContext); + m_fluidSmoothRenderTarget->bind(renderContext); + + params.blurRadiusWorld = radius * 0.5f; + params.blurScale = screenWidth / screenAspect * (1.0f / (tanf(fov * 0.5f))); + params.invTexScale = Hlsl::float4(1.0f / screenAspect, 1.0f, 0.0f, 0.0f); + params.blurFalloff = blur; + params.debug = debug; + + m_meshRenderer->draw(m_screenQuadMesh.get(), m_fluidSmoothPipeline.get(), ¶ms); + + m_fluidSmoothRenderTarget->toReadable(renderContext); + } + + // First lets resolve the render target + ID3D12GraphicsCommandList* commandList = m_renderContext->m_commandList; + { + // Lets take what's rendered so far and + NvCo::Dx12ResourceBase* targetResource = m_renderContext->m_renderTargets[m_renderContext->m_renderTargetIndex]; + NvCo::Dx12ResourceBase& fluidResolvedTarget = m_fluidResolvedTarget->getResource(NvCo::Dx12RenderTarget::BUFFER_TARGET); + + if (m_renderContext->m_numMsaaSamples > 1) + { + // If enabled can stop/reduce flickering issues on some GPUs related to a problem around ResolveSubresource/ + //m_renderContext->submitGpuWork(); + + { + NvCo::Dx12BarrierSubmitter submitter(commandList); + targetResource->transition(D3D12_RESOURCE_STATE_RESOLVE_SOURCE, submitter); + fluidResolvedTarget.transition(D3D12_RESOURCE_STATE_RESOLVE_DEST, submitter); + } + // Do the resolve + const DXGI_FORMAT format = fluidResolvedTarget.getResource()->GetDesc().Format; + commandList->ResolveSubresource(fluidResolvedTarget, 0, *targetResource, 0, format); + { + NvCo::Dx12BarrierSubmitter submitter(commandList); + targetResource->transition(D3D12_RESOURCE_STATE_RENDER_TARGET, submitter); + fluidResolvedTarget.transition(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, submitter); + } + } + else + { + { + NvCo::Dx12BarrierSubmitter submitter(commandList); + targetResource->transition(D3D12_RESOURCE_STATE_COPY_SOURCE, submitter); + fluidResolvedTarget.transition(D3D12_RESOURCE_STATE_COPY_DEST, submitter); + } + commandList->CopyResource(fluidResolvedTarget, *targetResource); + } + } + + //--------------------------------------------------------------- + // composite + + { + m_shadowMap->toReadable(renderContext); + + AppGraphCtxPrepareRenderTarget(renderContext); + + FlexVec4 aspectWork(1.0f / screenWidth, screenAspect / screenWidth, 0, 0); + params.invTexScale = (Hlsl::float4&)aspectWork; + FlexVec4 clipPosToEyeWork(tanf(fov*0.5f)*screenAspect, tanf(fov*0.5f), 0, 0); + params.clipPosToEye = (Hlsl::float4&)clipPosToEyeWork; + params.color = (Hlsl::float4&)color; + params.ior = ior; + params.spotMin = gSpotMin; + params.spotMax = gSpotMax; + params.debug = debug; + + params.lightPos = (Hlsl::float3&)lightPos; + FlexVec3 lightDirWork = -Normalize(lightTarget - lightPos); + params.lightDir = (Hlsl::float3&)lightDirWork; + Matrix44 lightTransformWork = RenderParamsUtilD3D::convertGLToD3DProjection(lightTransform); + params.lightTransform = (XMMATRIX&)lightTransformWork; + + params.m_srvDescriptorBase = m_fluidCompositeSrvBaseIndex; + params.m_sampleDescriptorBase = m_linearSamplerIndex; + params.shadowMap = (ShadowMapD3D*)m_currentShadowMap; + + m_meshRenderer->draw(m_screenQuadMesh.get(), m_fluidCompositePipeline.get(), ¶ms); + } +} + +void DemoContextD3D12::updateFluidRenderBuffers(FluidRenderBuffers* buffersIn, FlexVec4* particles, float* densities, FlexVec4* anisotropy1, FlexVec4* anisotropy2, FlexVec4* anisotropy3, int numParticles, int* indices, int numIndices) +{ + FluidRenderBuffersD3D12& buffers = *reinterpret_cast<FluidRenderBuffersD3D12*>(buffersIn); + + typedef PointRenderAllocationD3D12 Alloc; + Alloc alloc; + + PointData pointData; + + pointData.positions = (const Vec4*)particles; + pointData.density = densities; + pointData.phase = nullptr; + pointData.indices = (uint32_t*)indices; + pointData.numIndices = numIndices; + pointData.numPoints = numParticles; + pointData.anisotropy[0] = (const Vec4*)anisotropy1; + pointData.anisotropy[1] = (const Vec4*)anisotropy2; + pointData.anisotropy[2] = (const Vec4*)anisotropy3; + + m_meshRenderer->allocateTransitory(pointData, alloc, sizeof(alloc)); + + buffers.m_positionsView = alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_POSITION]; + buffers.m_densitiesView = alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_DENSITY]; + + buffers.m_anisotropiesViewArr[0] = alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_ANISOTROPY1]; + buffers.m_anisotropiesViewArr[1] = alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_ANISOTROPY2]; + buffers.m_anisotropiesViewArr[2] = alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_ANISOTROPY3]; + + buffers.m_indicesView = alloc.m_indexBufferView; + + buffers.m_numParticles = numIndices; +} + +void DemoContextD3D12::shadowBegin(::ShadowMap* map) +{ + assert(map); + assert(m_targetShadowMap == nullptr); + + AppGraphCtxD3D12* renderContext = getRenderContext(); + NvCo::Dx12RenderTarget* shadowMap = reinterpret_cast<NvCo::Dx12RenderTarget*>(map); + + shadowMap->toWritable(renderContext); + shadowMap->bindAndClear(renderContext); + + m_targetShadowMap = shadowMap; + + m_meshDrawParams.renderStage = MESH_DRAW_SHADOW; +} + +void DemoContextD3D12::shadowEnd() +{ + AppGraphCtxD3D12* renderContext = getRenderContext(); + NvCo::Dx12RenderTarget* shadowMap = m_targetShadowMap; + shadowMap->toReadable(renderContext); + m_targetShadowMap = nullptr; + + // Restore to regular render target + AppGraphCtxPrepareRenderTarget(renderContext); + + m_meshDrawParams.renderStage = MESH_DRAW_NULL; +} + +void DemoContextD3D12::drawMesh(const Mesh* m, FlexVec3 color) +{ + MeshDrawParamsD3D& params = m_meshDrawParams; + + if (m) + { + MeshData meshData; + + meshData.positions = (Vec3*)&m->m_positions[0]; + meshData.normals = (Vec3*)&m->m_normals[0]; + meshData.colors = nullptr; + meshData.texcoords = nullptr; + meshData.indices = (uint32_t*)&m->m_indices[0]; + meshData.numFaces = m->GetNumFaces(); + meshData.numVertices = m->GetNumVertices(); + + params.colorArray = 0; + if (m->m_colours.size()) + { + params.colorArray = 1; + meshData.colors = (Vec4*)&m->m_colours[0]; + } + + params.color = Hlsl::float4(color.x, color.y, color.z, 1); + params.secondaryColor = params.color; + params.objectTransform = (Hlsl::float4x4&)Matrix44::kIdentity; + params.shadowMap = (ShadowMapD3D*)m_currentShadowMap; + + m_meshRenderer->drawImmediate(meshData, m_meshPipeline.get(), ¶ms); + + if (m->m_colours.size()) + { + params.colorArray = 0; + } + } +} + +void DemoContextD3D12::drawCloth(const FlexVec4* positions, const FlexVec4* normals, const float* uvs, const int* indices, int numTris, int numPositions, int colorIndex, float expand, bool twosided, bool smooth) +{ + if (!numTris) + return; + + MeshData2 meshData; + + meshData.positions = (const Vec4*)positions; + meshData.normals = (const Vec4*)normals; + meshData.texcoords = nullptr; /* (const Vec2*)uvs; */ + meshData.colors = nullptr; + meshData.numFaces = numTris; + meshData.indices = (const uint32_t*)indices; + meshData.numVertices = numPositions; + + if (twosided) + SetCullMode(false); + + MeshDrawParamsD3D& params = m_meshDrawParams; + + params.bias = 0.0f; + params.expand = expand; + + params.color = (Hlsl::float4&)(g_colors[colorIndex + 1] * 1.5f); + params.secondaryColor = (Hlsl::float4&)(g_colors[colorIndex] * 1.5f); + params.objectTransform = (Hlsl::float4x4&)Matrix44::kIdentity; + params.shadowMap = (ShadowMapD3D*)m_currentShadowMap; + + m_meshRenderer->drawImmediate(meshData, m_meshPipeline.get(), ¶ms); + + if (twosided) + SetCullMode(true); + + params.bias = gShadowBias; + params.expand = 0.0f; +} + +void DemoContextD3D12::drawRope(FlexVec4* positions, int* indices, int numIndices, float radius, int color) +{ + if (numIndices < 2) + return; + + std::vector<FlexVec3> vertices; + std::vector<FlexVec3> normals; + std::vector<int> triangles; + + // flatten curve + std::vector<FlexVec3> curve(numIndices); + for (int i = 0; i < numIndices; ++i) + { + curve[i] = FlexVec3(positions[indices[i]]); + } + + const int resolution = 8; + const int smoothing = 3; + + vertices.reserve(resolution*numIndices*smoothing); + normals.reserve(resolution*numIndices*smoothing); + triangles.reserve(numIndices*resolution * 6 * smoothing); + + Extrude(&curve[0], int(curve.size()), vertices, normals, triangles, radius, resolution, smoothing); + + SetCullMode(false); + + MeshDrawParamsD3D& params = m_meshDrawParams; + + params.color = (Hlsl::float4&)(g_colors[color % 8] * 1.5f); + params.secondaryColor = (Hlsl::float4&)(g_colors[color % 8] * 1.5f); + params.shadowMap = (ShadowMapD3D*)m_currentShadowMap; + + MeshData meshData; + + meshData.positions = (const Vec3*)&vertices[0]; + meshData.normals = (const Vec3*)&normals[0]; + meshData.texcoords = nullptr; + meshData.colors = nullptr; + meshData.indices = (const uint32_t*)&triangles[0]; + meshData.numFaces = int(triangles.size()) / 3; + meshData.numVertices = int(vertices.size()); + + m_meshRenderer->drawImmediate(meshData, m_meshPipeline.get(), ¶ms); + + SetCullMode(true); +} + +void DemoContextD3D12::drawPlane(const FlexVec4& p, bool color) +{ + std::vector<FlexVec3> vertices; + std::vector<FlexVec3> normals; + std::vector<int> indices; + + FlexVec3 u, v; + BasisFromVector(FlexVec3(p.x, p.y, p.z), &u, &v); + + FlexVec3 c = FlexVec3(p.x, p.y, p.z)*-p.w; + + MeshDrawParamsD3D& params = m_meshDrawParams; + + params.shadowMap = (ShadowMapD3D*)m_currentShadowMap; + + if (color) + params.color = (Hlsl::float4&)(p * 0.5f + FlexVec4(0.5f, 0.5f, 0.5f, 0.5f)); + + const float kSize = 200.0f; + const int kGrid = 3; + + // draw a grid of quads, otherwise z precision suffers + for (int x = -kGrid; x <= kGrid; ++x) + { + for (int y = -kGrid; y <= kGrid; ++y) + { + FlexVec3 coff = c + u*float(x)*kSize*2.0f + v*float(y)*kSize*2.0f; + + int indexStart = int(vertices.size()); + + vertices.push_back(FlexVec3(coff + u*kSize + v*kSize)); + vertices.push_back(FlexVec3(coff - u*kSize + v*kSize)); + vertices.push_back(FlexVec3(coff - u*kSize - v*kSize)); + vertices.push_back(FlexVec3(coff + u*kSize - v*kSize)); + + normals.push_back(FlexVec3(p.x, p.y, p.z)); + normals.push_back(FlexVec3(p.x, p.y, p.z)); + normals.push_back(FlexVec3(p.x, p.y, p.z)); + normals.push_back(FlexVec3(p.x, p.y, p.z)); + + + indices.push_back(indexStart + 0); + indices.push_back(indexStart + 1); + indices.push_back(indexStart + 2); + + indices.push_back(indexStart + 2); + indices.push_back(indexStart + 3); + indices.push_back(indexStart + 0); + } + } + + MeshData meshData; + meshData.texcoords = nullptr; + meshData.colors = nullptr; + meshData.positions = (Vec3*)&vertices[0]; + meshData.normals = (Vec3*)&normals[0]; + meshData.indices = (uint32_t*)&indices[0]; + meshData.numFaces = int(indices.size() / 3); + meshData.numVertices = int(vertices.size()); + + m_meshRenderer->drawImmediate(meshData, m_meshPipeline.get(), ¶ms); +} + +void DemoContextD3D12::drawPlanes(FlexVec4* planes, int n, float bias) +{ + MeshDrawParamsD3D& params = m_meshDrawParams; + + params.color = (Hlsl::float4&)FlexVec4(0.9f, 0.9f, 0.9f, 1.0f); + + params.bias = 0.0f; + params.grid = 1; + params.expand = 0; + + for (int i = 0; i < n; ++i) + { + FlexVec4 p = planes[i]; + p.w -= bias; + + drawPlane(p, false); + } + + params.grid = 0; + params.bias = gShadowBias; +} + +void DemoContextD3D12::drawPoints(FluidRenderBuffers* buffersIn, int n, int offset, float radius, float screenWidth, float screenAspect, float fov, FlexVec3 lightPos, FlexVec3 lightTarget, Matrix44 lightTransform, ::ShadowMap* shadowTex, bool showDensity) +{ + FluidRenderBuffersD3D12* buffers = reinterpret_cast<FluidRenderBuffersD3D12*>(buffersIn); + // Okay we can draw the particles here. The update can copy the point positions into the heap, so here we just draw them + + if (n == 0) + return; + + PointRenderAllocationD3D12 pointAlloc; + pointAlloc.init(PRIMITIVE_POINT); + pointAlloc.m_vertexBufferViews[PointRenderAllocationD3D12::VERTEX_VIEW_POSITION] = buffers->m_positionsView; + // It says 'color' as the parameter but actually its the 'density' parameter that is passed in here + pointAlloc.m_vertexBufferViews[PointRenderAllocationD3D12::VERTEX_VIEW_DENSITY] = buffers->m_densitiesView; + pointAlloc.m_indexBufferView = buffers->m_indicesView; + // TODO: JS - I don't know the amount of positions/colors... but the render call doesn't need to know. So just set to 0 for now + pointAlloc.m_numPositions = 0; + pointAlloc.m_numPrimitives = n; + + PointDrawParamsD3D params; + + params.renderMode = POINT_RENDER_SOLID; + params.cullMode = POINT_CULL_BACK; + params.model = XMMatrixIdentity(); + params.view = (XMMATRIX&)m_view; + params.projection = (XMMATRIX&)m_proj; + + params.pointRadius = radius; + params.pointScale = screenWidth / screenAspect * (1.0f / (tanf(fov * 0.5f))); + params.spotMin = gSpotMin; + params.spotMax = gSpotMax; + + int mode = 0; + if (showDensity) + mode = 1; + if (shadowTex == 0) + mode = 2; + params.mode = mode; + + for (int i = 0; i < 8; i++) + params.colors[i] = *((Hlsl::float4*)&g_colors[i].r); + + // set shadow parameters + ShadowParamsD3D shadow; + RenderParamsUtilD3D::calcShadowParams(lightPos, lightTarget, lightTransform, gShadowBias, &shadow); + params.lightTransform = shadow.lightTransform; + params.lightDir = shadow.lightDir; + params.lightPos = shadow.lightPos; + memcpy(params.shadowTaps, shadow.shadowTaps, sizeof(shadow.shadowTaps)); + + if (m_meshDrawParams.renderStage == MESH_DRAW_SHADOW) + { + params.renderStage = POINT_DRAW_SHADOW; + params.mode = 2; + } + else + params.renderStage = POINT_DRAW_LIGHT; + + params.shadowMap = (ShadowMapD3D*)m_currentShadowMap; + + m_meshRenderer->drawTransitory(pointAlloc, sizeof(pointAlloc), m_pointPipeline.get(), ¶ms); +} + +void DemoContextD3D12::graphicsTimerBegin() +{ + ID3D12GraphicsCommandList* commandList = m_renderContext->m_commandList; + + commandList->EndQuery(m_queryHeap.Get(), D3D12_QUERY_TYPE_TIMESTAMP, 0); +} + +void DemoContextD3D12::graphicsTimerEnd() +{ + ID3D12GraphicsCommandList* commandList = m_renderContext->m_commandList; + + commandList->EndQuery(m_queryHeap.Get(), D3D12_QUERY_TYPE_TIMESTAMP, 1); + commandList->ResolveQueryData(m_queryHeap.Get(), D3D12_QUERY_TYPE_TIMESTAMP, 0, 2, m_queryResults.Get(), 0); +} + +float DemoContextD3D12::rendererGetDeviceTimestamps(unsigned long long* begin, unsigned long long* end, unsigned long long* freq) +{ + AppGraphCtxD3D12* renderContext = getRenderContext(); + ID3D12CommandQueue* commandQueue = m_renderContext->m_commandQueue; + + AppGraphCtxWaitForGPU(renderContext); + + // Get timer frequency + static uint64_t frequency = 0; + + if (frequency == 0) + { + commandQueue->GetTimestampFrequency(&frequency); + } + + //Get render timestamps + uint64_t* times; + //m_queryResults->Map(0, nullptr, (void**)×); + D3D12_RANGE readRange = { 0, 1 }; + m_queryResults->Map(0, &readRange, (void**)×); + uint64_t renderBegin = times[0]; + uint64_t renderEnd = times[1]; + D3D12_RANGE writtenRange = { 0, 0 }; // nothing was written + m_queryResults->Unmap(0, &writtenRange); + + double renderTime = double(renderEnd - renderBegin) / double(frequency); + + if (begin) *begin = renderBegin; + if (end) *end = renderEnd; + if (freq) *freq = frequency; + + return float(renderTime); +} + +void DemoContextD3D12::bindSolidShader(FlexVec3 lightPos, FlexVec3 lightTarget, Matrix44 lightTransform, ::ShadowMap* shadowMap, float bias, FlexVec4 fogColor) +{ + MeshDrawParamsD3D& params = m_meshDrawParams; + + params.renderStage = MESH_DRAW_LIGHT; + + params.grid = 0; + params.spotMin = gSpotMin; + params.spotMax = gSpotMax; + params.fogColor = (Hlsl::float4&)fogColor; + + params.objectTransform = (Hlsl::float4x4&)Matrix44::kIdentity; + + ShadowParamsD3D shadow; + RenderParamsUtilD3D::calcShadowParams(lightPos, lightTarget, lightTransform, gShadowBias, &shadow); + params.lightTransform = shadow.lightTransform; + params.lightDir = shadow.lightDir; + params.lightPos = shadow.lightPos; + params.bias = shadow.bias; + memcpy(params.shadowTaps, shadow.shadowTaps, sizeof(shadow.shadowTaps)); + + m_currentShadowMap = (NvCo::Dx12RenderTarget*)shadowMap; +} + +void DemoContextD3D12::drawGpuMesh(GpuMesh* m, const Matrix44& xform, const FlexVec3& color) +{ + if (m) + { + MeshDrawParamsD3D params(m_meshDrawParams); + + params.color = (Hlsl::float4&)color; + params.secondaryColor = (Hlsl::float4&)color; + params.objectTransform = (Hlsl::float4x4&)xform; + params.shadowMap = (ShadowMapD3D*)m_currentShadowMap; + + RenderMesh* renderMesh = (RenderMesh*)m; + + m_meshRenderer->draw(renderMesh, m_meshPipeline.get(), ¶ms); + } +} + +void DemoContextD3D12::drawGpuMeshInstances(GpuMesh* m, const Matrix44* xforms, int n, const FlexVec3& color) +{ + if (m) + { + MeshDrawParamsD3D& contextParams = m_meshDrawParams; + + contextParams.color = (Hlsl::float4&)color; + contextParams.secondaryColor = (Hlsl::float4&)color; + contextParams.shadowMap = (ShadowMapD3D*)m_currentShadowMap; + + // copy params + MeshDrawParamsD3D params(contextParams); + + for (int i = 0; i < n; ++i) + { + params.objectTransform = (Hlsl::float4x4&)xforms[i]; + RenderMesh* renderMesh = (RenderMesh*)m; + m_meshRenderer->draw(renderMesh, m_meshPipeline.get(), ¶ms); + } + } +} + +void DemoContextD3D12::drawDiffuse(FluidRenderer* render, const DiffuseRenderBuffers* buffersIn, int n, float radius, float screenWidth, float screenAspect, float fov, FlexVec4 color, FlexVec3 lightPos, FlexVec3 lightTarget, Matrix44 lightTransform, ShadowMap* shadowMap, float motionBlur, float inscatter, float outscatter, bool shadowEnabled, bool front) +{ + const DiffuseRenderBuffersD3D12& buffers = *reinterpret_cast<const DiffuseRenderBuffersD3D12*>(buffersIn); + if (n == 0) + return; + + typedef PointRenderAllocationD3D12 Alloc; + Alloc alloc; + alloc.init(PRIMITIVE_POINT); + + alloc.m_numPrimitives = buffers.m_numParticles; + alloc.m_numPositions = 0; // ! We don't know + alloc.m_indexBufferView = buffers.m_indicesView; + alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_POSITION] = buffers.m_positionsView; + alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_ANISOTROPY1] = buffers.m_velocitiesView; // Velocity stored in ANISO1 + + DiffuseDrawParamsD3D params; + + params.model = XMMatrixIdentity(); + params.view = (const XMMATRIX&)m_view; + params.projection = (const XMMATRIX&)m_proj; + params.diffuseRadius = screenWidth / screenAspect * (1.0f / (tanf(fov * 0.5f))); + params.diffuseScale = radius; + params.spotMin = gSpotMin; + params.spotMax = gSpotMax; + params.color = Hlsl::float4(1.0f, 1.0f, 1.0f, 1.0f); + params.motionScale = motionBlur; + + // set shadow parameters + ShadowParamsD3D shadow; + RenderParamsUtilD3D::calcShadowParams(lightPos, lightTarget, lightTransform, gShadowBias, &shadow); + params.lightTransform = shadow.lightTransform; + params.lightDir = shadow.lightDir; + params.lightPos = shadow.lightPos; + params.shadowMap = (ShadowMapD3D*)m_currentShadowMap; + + memcpy(params.shadowTaps, shadow.shadowTaps, sizeof(shadow.shadowTaps)); + + m_meshRenderer->drawTransitory(alloc, sizeof(alloc), m_diffusePointPipeline.get(), ¶ms); +} + +void DemoContextD3D12::beginLines() +{ + assert(!m_inLineDraw); + m_inLineDraw = true; + m_debugLineVertices.clear(); +} + +void DemoContextD3D12::drawLine(const Vec3& p, const Vec3& q, const Vec4& color) +{ + assert(m_inLineDraw); + + if (m_debugLineVertices.size() + 2 > MAX_DEBUG_LINE_SIZE) + { + _flushDebugLines(); + } + + LineData::Vertex dst[2]; + dst[0].position = (const Vec3&)p; + dst[0].color = (const Vec4&)color; + dst[1].position = (const Vec3&)q; + dst[1].color = (const Vec4&)color; + + m_debugLineVertices.push_back(dst[0]); + m_debugLineVertices.push_back(dst[1]); +} + +void DemoContextD3D12::_flushDebugLines() +{ + assert(m_inLineDraw); + + if (m_debugLineVertices.size() > 0) + { + LineDrawParams params; + + const Matrix44 modelWorldProjection = ((Matrix44&)(m_meshDrawParams.projection)) * ((Matrix44&)(m_meshDrawParams.view)); + // draw + params.m_modelWorldProjection = (const Hlsl::float4x4&)modelWorldProjection; + params.m_drawStage = (m_targetShadowMap) ? LINE_DRAW_SHADOW : LINE_DRAW_NORMAL; + + LineData lineData; + lineData.init(); + lineData.vertices = &m_debugLineVertices.front(); + lineData.numVertices = m_debugLineVertices.size(); + lineData.numLines = lineData.numVertices / 2; + + m_meshRenderer->drawImmediate(lineData, m_linePipeline.get(), ¶ms); + + m_debugLineVertices.clear(); + } +} + +void DemoContextD3D12::endLines() +{ + _flushDebugLines(); + // No longer in line drawing + m_inLineDraw = false; +} + +void DemoContextD3D12::flushGraphicsAndWait() +{ + AppGraphCtxWaitForGPU(getRenderContext()); +} + +FluidRenderer* DemoContextD3D12::createFluidRenderer(uint32_t width, uint32_t height) +{ + // It's always created.. so just return the context + return (FluidRenderer*)this; +} + +void DemoContextD3D12::destroyFluidRenderer(FluidRenderer* renderer) +{ + /// Don't need to do anything, as will be destroyed with context +} + +FluidRenderBuffers* DemoContextD3D12::createFluidRenderBuffers(int numParticles, bool enableInterop) +{ + return reinterpret_cast<FluidRenderBuffers*>(new FluidRenderBuffersD3D12(numParticles)); +} + +void DemoContextD3D12::updateFluidRenderBuffers(FluidRenderBuffers* buffers, NvFlexSolver* flex, bool anisotropy, bool density) +{ + printf("Not implemented"); + assert(0); +} + +void DemoContextD3D12::destroyFluidRenderBuffers(FluidRenderBuffers* buffers) +{ + delete reinterpret_cast<FluidRenderBuffersD3D12*>(buffers); +} + +ShadowMap* DemoContextD3D12::shadowCreate() +{ + // Currently only allows single shadow map, which is pre created + return (::ShadowMap*)m_shadowMap.get(); +} + +void DemoContextD3D12::shadowDestroy(ShadowMap* map) +{ + assert(map); + assert(m_shadowMap.get() == (NvCo::Dx12RenderTarget*)map); +} + +void DemoContextD3D12::unbindSolidShader() +{ + m_meshDrawParams.renderStage = MESH_DRAW_NULL; + + // !!! Other code appears to assume that this will be set + //context->m_currentShadowMap = nullptr; +} + +GpuMesh* DemoContextD3D12::createGpuMesh(const Mesh* m) +{ + if (m) + { + return (GpuMesh*)MeshUtil::createRenderMesh(m_meshRenderer.get(), *m); + } + return nullptr; +} + +void DemoContextD3D12::destroyGpuMesh(GpuMesh* m) +{ + delete reinterpret_cast<RenderMesh*>(m); +} + + +DiffuseRenderBuffers* DemoContextD3D12::createDiffuseRenderBuffers(int numDiffuseParticles, bool& enableInterop) +{ + return reinterpret_cast<DiffuseRenderBuffers*>(new DiffuseRenderBuffersD3D12(numDiffuseParticles)); +} + +void DemoContextD3D12::destroyDiffuseRenderBuffers(DiffuseRenderBuffers* buffers) +{ + delete reinterpret_cast<DiffuseRenderBuffersD3D12*>(buffers); +} + +int DemoContextD3D12::getNumDiffuseRenderParticles(DiffuseRenderBuffers* buffers) +{ + return reinterpret_cast<DiffuseRenderBuffersD3D12*>(buffers)->m_numParticles; +} + +void DemoContextD3D12::updateDiffuseRenderBuffers(DiffuseRenderBuffers* buffersIn, Vec4* diffusePositions, Vec4* diffuseVelocities, int numDiffuseParticles) +{ + DiffuseRenderBuffersD3D12& buffers = *reinterpret_cast<DiffuseRenderBuffersD3D12*>(buffersIn); + + typedef PointRenderAllocationD3D12 Alloc; + + Alloc alloc; + + PointData pointData; + pointData.init(); + pointData.numIndices = numDiffuseParticles; + pointData.positions = (Vec4*)diffusePositions; + pointData.anisotropy[0] = (Vec4*)diffuseVelocities; // We'll store the velocities in the anisotropy buffer, cos it's the right size + pointData.numPoints = buffers.m_numParticles; + + m_meshRenderer->allocateTransitory(pointData, alloc, sizeof(alloc)); + + buffers.m_indicesView = alloc.m_indexBufferView; + buffers.m_positionsView = alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_POSITION]; + buffers.m_velocitiesView = alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_ANISOTROPY1]; // The velocity + + buffers.m_numParticles = numDiffuseParticles; +} + +void DemoContextD3D12::updateDiffuseRenderBuffers(DiffuseRenderBuffers* buffers, NvFlexSolver* solver) +{ + printf("Not implemented"); + assert(0); +} + +void* DemoContextD3D12::getGraphicsCommandQueue() +{ + return m_renderContext->m_commandQueue; +} + +void DemoContextD3D12::setFillMode(bool wire) +{ + m_meshDrawParams.renderMode = wire ? MESH_RENDER_WIREFRAME : MESH_RENDER_SOLID; +} + +void DemoContextD3D12::setCullMode(bool enabled) +{ + m_meshDrawParams.cullMode = enabled ? MESH_CULL_BACK : MESH_CULL_NONE; +} + +void DemoContextD3D12::drawImguiGraph() +{ + imguiGraphDraw(); + /* + const imguiGfxCmd* cmds = imguiGetRenderQueue(); + int numCmds = imguiGetRenderQueueSize(); + m_imguiGraphContext->draw(cmds, numCmds); */ +} + + +} // namespace FlexSample + + + diff --git a/demo/d3d12/demoContextD3D12.h b/demo/d3d12/demoContextD3D12.h new file mode 100644 index 0000000..5f43c31 --- /dev/null +++ b/demo/d3d12/demoContextD3D12.h @@ -0,0 +1,256 @@ +/* +* Copyright (c) 2008-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. +*/ + +#ifndef DEMO_CONTEXT_D3D12_H +#define DEMO_CONTEXT_D3D12_H + +#include <memory> +#include <NvCoDx12RenderTarget.h> + +#include "meshRenderer.h" +#include "renderStateD3D12.h" +#include "appD3D12Ctx.h" + +// SDL +#include <SDL.h> +#include <SDL_video.h> + +#include "shaders.h" +#include "d3d/demoContext.h" + +#define NOMINMAX +#include <d3d12.h> + +namespace FlexSample { + +struct FlexBuffer +{ + inline FlexBuffer():m_buffer(nullptr) {} + inline operator NvFlexBuffer* () const { return m_buffer; } + ~FlexBuffer() { if (m_buffer) { NvFlexUnregisterD3DBuffer(m_buffer); } } + + NvFlexBuffer* m_buffer; +}; + +struct FluidRenderBuffersD3D12 +{ + FluidRenderBuffersD3D12(int numParticles = 0) + { + m_numParticles = numParticles; + { + const D3D12_VERTEX_BUFFER_VIEW nullView = {}; + m_positionsView = nullView; + m_densitiesView = nullView; + m_fluidView = nullView; + for (int i = 0; i < _countof(m_anisotropiesViewArr); i++) + { + m_anisotropiesViewArr[i] = nullView; + } + } + { + D3D12_INDEX_BUFFER_VIEW nullView = {}; + m_indicesView = nullView; + } + } + + int m_numParticles; + + D3D12_VERTEX_BUFFER_VIEW m_positionsView; + D3D12_VERTEX_BUFFER_VIEW m_densitiesView; + D3D12_VERTEX_BUFFER_VIEW m_anisotropiesViewArr[3]; + D3D12_INDEX_BUFFER_VIEW m_indicesView; + + D3D12_VERTEX_BUFFER_VIEW m_fluidView; // to be removed + + // wrapper buffers that allow Flex to write directly to VBOs + FlexBuffer m_positionsBuf; + FlexBuffer m_densitiesBuf; + FlexBuffer m_anisotropiesBufArr[3]; + FlexBuffer m_indicesBuf; +}; + +// vertex buffers for diffuse particles +struct DiffuseRenderBuffersD3D12 +{ + DiffuseRenderBuffersD3D12(int numParticles = 0) + { + m_numParticles = numParticles; + { + const D3D12_VERTEX_BUFFER_VIEW nullView = {}; + m_positionsView = nullView; + m_velocitiesView = nullView; + } + { + D3D12_INDEX_BUFFER_VIEW nullView = {}; + m_indicesView = nullView; + } + } + + int m_numParticles; + + D3D12_VERTEX_BUFFER_VIEW m_positionsView; + D3D12_VERTEX_BUFFER_VIEW m_velocitiesView; + D3D12_INDEX_BUFFER_VIEW m_indicesView; + + FlexBuffer m_indicesBuf; + FlexBuffer m_positionsBuf; + FlexBuffer m_velocitiesBuf; +}; + +struct DemoContextD3D12: public DemoContext +{ + //NV_CO_DECLARE_POLYMORPHIC_CLASS_BASE(DemoContextD3D12) +public: + enum + { + NUM_COMPOSITE_SRVS = 3, + MAX_DEBUG_LINE_SIZE = 1024 * 4, // Will flush if exceeds this + }; + + // DemoContext Impl + virtual bool initialize(const RenderInitOptions& options) override; + virtual void startFrame(Vec4 colorIn) override; + virtual void endFrame() override; + virtual void presentFrame(bool fullsync) override; + + virtual void getViewRay(int x, int y, Vec3& origin, Vec3& dir) override; + virtual void setView(Matrix44 view, Matrix44 projection) override; + virtual void renderEllipsoids(FluidRenderer* renderer, FluidRenderBuffers* buffers, int n, int offset, float radius, float screenWidth, float screenAspect, float fov, Vec3 lightPos, Vec3 lightTarget, Matrix44 lightTransform, ::ShadowMap* shadowMap, Vec4 color, float blur, float ior, bool debug) override; + + virtual void drawMesh(const Mesh* m, Vec3 color) override; + virtual void drawCloth(const Vec4* positions, const Vec4* normals, const float* uvs, const int* indices, int numTris, int numPositions, int colorIndex, float expand, bool twosided, bool smooth) override; + virtual void drawRope(Vec4* positions, int* indices, int numIndices, float radius, int color) override; + virtual void drawPlane(const Vec4& p, bool color) override; + virtual void drawPlanes(Vec4* planes, int n, float bias) override; + virtual void drawPoints(FluidRenderBuffers* buffers, int n, int offset, float radius, float screenWidth, float screenAspect, float fov, Vec3 lightPos, Vec3 lightTarget, Matrix44 lightTransform, ::ShadowMap* shadowTex, bool showDensity) override; + + virtual void graphicsTimerBegin() override; + virtual void graphicsTimerEnd() override; + + virtual float rendererGetDeviceTimestamps(unsigned long long* begin, unsigned long long* end, unsigned long long* freq) override; + + virtual void bindSolidShader(Vec3 lightPos, Vec3 lightTarget, Matrix44 lightTransform, ::ShadowMap* shadowMap, float bias, Vec4 fogColor) override; + virtual void unbindSolidShader() override; + + virtual ShadowMap* shadowCreate() override; + virtual void shadowDestroy(ShadowMap* map) override; + virtual void shadowBegin(ShadowMap* map) override; + virtual void shadowEnd() override; + + virtual FluidRenderer* createFluidRenderer(uint32_t width, uint32_t height) override; + virtual void destroyFluidRenderer(FluidRenderer* renderer) override; + + virtual FluidRenderBuffers* createFluidRenderBuffers(int numParticles, bool enableInterop) override; + virtual void updateFluidRenderBuffers(FluidRenderBuffers* buffers, NvFlexSolver* flex, bool anisotropy, bool density) override; + virtual void updateFluidRenderBuffers(FluidRenderBuffers* buffers, Vec4* particles, float* densities, Vec4* anisotropy1, Vec4* anisotropy2, Vec4* anisotropy3, int numParticles, int* indices, int numIndices) override; + virtual void destroyFluidRenderBuffers(FluidRenderBuffers* buffers) override; + + virtual GpuMesh* createGpuMesh(const Mesh* m) override; + virtual void destroyGpuMesh(GpuMesh* mesh) override; + virtual void drawGpuMesh(GpuMesh* m, const Matrix44& xform, const Vec3& color) override; + virtual void drawGpuMeshInstances(GpuMesh* m, const Matrix44* xforms, int n, const Vec3& color) override; + + virtual DiffuseRenderBuffers* createDiffuseRenderBuffers(int numDiffuseParticles, bool& enableInterop) override; + virtual void drawDiffuse(FluidRenderer* render, const DiffuseRenderBuffers* buffers, int n, float radius, float screenWidth, float screenAspect, float fov, Vec4 color, Vec3 lightPos, Vec3 lightTarget, Matrix44 lightTransform, ::ShadowMap* shadowMap, float motionBlur, float inscatter, float outscatter, bool shadowEnabled, bool front) override; + virtual void destroyDiffuseRenderBuffers(DiffuseRenderBuffers* buffers) override; + virtual void updateDiffuseRenderBuffers(DiffuseRenderBuffers* buffers, Vec4* diffusePositions, Vec4* diffuseVelocities, int numDiffuseParticles) override; + virtual void updateDiffuseRenderBuffers(DiffuseRenderBuffers* buffers, NvFlexSolver* solver) override; + virtual int getNumDiffuseRenderParticles(DiffuseRenderBuffers* buffers) override; + + virtual void beginLines() override; + virtual void drawLine(const Vec3& p, const Vec3& q, const Vec4& color) override; + virtual void endLines() override; + + virtual void onSizeChanged(int width, int height, bool minimized) override; + + virtual void startGpuWork() override; + virtual void endGpuWork() override; + virtual void flushGraphicsAndWait() override; + + virtual void setFillMode(bool wire) override; + virtual void setCullMode(bool enabled) override; + + virtual void getRenderDevice(void** device, void** context) override; + virtual void drawImguiGraph() override; + virtual void* getGraphicsCommandQueue() override; + + /// Get the render context + inline AppGraphCtxD3D12* getRenderContext() const { return m_renderContext; } + + DemoContextD3D12(); + ~DemoContextD3D12(); + + int _initRenderResources(const RenderInitOptions& options); + int _initFluidRenderTargets(); + + void _flushDebugLines(); + + MeshDrawParamsD3D m_meshDrawParams; + + Matrix44 m_view; + Matrix44 m_proj; + + // NOTE! These are allocated such that they are in order. This is required because on compositePS.hlsl, I need s0, and s1 to be linear, and then shadowMap samplers. + int m_linearSamplerIndex; ///< Index to a linear sample on the m_samplerDescriptorHeap + int m_shadowMapLinearSamplerIndex; ///< Index to shadow map depth comparator sampler descriptor in m_samplerDescriptorHeap + + int m_fluidPointDepthSrvIndex; ///< Index into srv heap that holds srv for the m_flexMeshPipeline + int m_fluidCompositeSrvBaseIndex; ///< We have a set of NUM_COMPOSITE_SRVS for every back buffer there is + + AppGraphCtx* m_appGraphCtx; + AppGraphCtxD3D12* m_renderContext; + + std::unique_ptr<MeshRenderer> m_meshRenderer; + + // Render pipelines + std::unique_ptr<RenderPipeline> m_meshPipeline; + std::unique_ptr<RenderPipeline> m_pointPipeline; + std::unique_ptr<RenderPipeline> m_fluidPointPipeline; + std::unique_ptr<RenderPipeline> m_fluidSmoothPipeline; + std::unique_ptr<RenderPipeline> m_fluidCompositePipeline; + std::unique_ptr<RenderPipeline> m_diffusePointPipeline; + std::unique_ptr<RenderPipeline> m_linePipeline; + + std::unique_ptr<NvCo::Dx12RenderTarget> m_fluidPointRenderTarget; + std::unique_ptr<NvCo::Dx12RenderTarget> m_fluidSmoothRenderTarget; + std::unique_ptr<NvCo::Dx12RenderTarget> m_fluidResolvedTarget; ///< The main render target resolved, such that it can be sampled from + + std::unique_ptr<RenderMesh> m_screenQuadMesh; + + std::unique_ptr<NvCo::Dx12RenderTarget> m_shadowMap; + + NvCo::Dx12RenderTarget* m_currentShadowMap; ///< The current read from shadow buffer + NvCo::Dx12RenderTarget* m_targetShadowMap; ///< The shadow map bound to render to (ie for write with Begin/EndShadow + + std::wstring m_executablePath; + std::wstring m_shadersPath; + + RenderStateManagerD3D12 m_renderStateManager; + RenderStateD3D12 m_renderState; + + SDL_Window* m_window; + HWND m_hwnd; + + int m_msaaSamples; + + // Synchronization and timing for async compute benchmarking + ComPtr<ID3D12Fence> m_graphicsCompleteFence; + HANDLE m_graphicsCompleteEvent; + UINT64 m_graphicsCompleteFenceValue; + ComPtr<ID3D12QueryHeap> m_queryHeap; + ComPtr<ID3D12Resource> m_queryResults; + + bool m_inLineDraw; + std::vector<LineData::Vertex> m_debugLineVertices; +}; + +} // namespace FlexSample + +#endif // DEMO_CONTEXT_D3D12_H
\ No newline at end of file diff --git a/demo/d3d12/diffusePointRenderPipelineD3D12.cpp b/demo/d3d12/diffusePointRenderPipelineD3D12.cpp new file mode 100644 index 0000000..3641a36 --- /dev/null +++ b/demo/d3d12/diffusePointRenderPipelineD3D12.cpp @@ -0,0 +1,223 @@ +#define NOMINMAX + +#include <NvCoDx12HelperUtil.h> + +#include <external/D3D12/include/d3dx12.h> + +#include "pipelineUtilD3D12.h" +#include "bufferD3D12.h" +#include "meshRendererD3D12.h" +#include "../d3d/shaderCommonD3D.h" + +// Shaders +#include "../d3d/shaders/diffuseVS.hlsl.h" +#include "../d3d/shaders/diffuseGS.hlsl.h" +#include "../d3d/shaders/diffusePS.hlsl.h" + +// this +#include "diffusePointRenderPipelineD3D12.h" + +namespace FlexSample { + +static const D3D12_INPUT_ELEMENT_DESC InputElementDescs[] = +{ + { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, + { "VELOCITY", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, +}; + +DiffusePointRenderPipelineD3D12::DiffusePointRenderPipelineD3D12(): + Parent(PRIMITIVE_POINT), + m_shadowMapLinearSamplerIndex(-1) +{ +} + +static D3D12_FILL_MODE _getFillMode(DiffusePointRenderPipelineD3D12::PipelineStateType type) +{ + return D3D12_FILL_MODE_SOLID; +} + +static D3D12_CULL_MODE _getCullMode(DiffusePointRenderPipelineD3D12::PipelineStateType type) +{ + return D3D12_CULL_MODE_NONE; +} + +static void _initRasterizerDesc(DiffusePointRenderPipelineD3D12::PipelineStateType type, D3D12_RASTERIZER_DESC& desc) +{ + PipelineUtilD3D::initRasterizerDesc(FRONT_WINDING_COUNTER_CLOCKWISE, desc); + desc.FillMode = _getFillMode(type); + desc.CullMode = _getCullMode(type); +} + +static void _initPipelineStateDesc(DiffusePointRenderPipelineD3D12::PipelineStateType type, NvCo::Dx12RenderTarget* shadowMap, AppGraphCtxD3D12* renderContext, D3D12_GRAPHICS_PIPELINE_STATE_DESC& psoDesc) +{ + PipelineUtilD3D::initTargetFormat(nullptr, renderContext, psoDesc); + + // Z test, but don't write + { + D3D12_DEPTH_STENCIL_DESC& desc = psoDesc.DepthStencilState; + desc.DepthEnable = TRUE; + desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; + desc.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL; + } + + psoDesc.InputLayout.NumElements = _countof(InputElementDescs); + psoDesc.InputLayout.pInputElementDescs = InputElementDescs; + psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT; +} + +int DiffusePointRenderPipelineD3D12::initialize(const RenderStateD3D12& state, const std::wstring& shadersPath, int shadowMapLinearSamplerIndex, NvCo::Dx12RenderTarget* shadowMap) +{ + using namespace NvCo; + ID3D12Device* device = state.m_device; + + m_shadowMapLinearSamplerIndex = shadowMapLinearSamplerIndex; + + // create the pipeline state object + { + D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; + { + // create blend state + D3D12_BLEND_DESC& desc = psoDesc.BlendState; + desc.AlphaToCoverageEnable = FALSE; + desc.IndependentBlendEnable = FALSE; + { + const D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc = + { + TRUE,FALSE, + D3D12_BLEND_ONE, D3D12_BLEND_INV_SRC_ALPHA, D3D12_BLEND_OP_ADD, + D3D12_BLEND_ONE, D3D12_BLEND_INV_SRC_ALPHA, D3D12_BLEND_OP_ADD, + D3D12_LOGIC_OP_NOOP, + D3D12_COLOR_WRITE_ENABLE_ALL, + }; + for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i) + desc.RenderTarget[i] = defaultRenderTargetBlendDesc; + } + } + + + // create the root signature + ComPtr<ID3D12RootSignature> signiture; + { + CD3DX12_DESCRIPTOR_RANGE ranges[2]; + CD3DX12_ROOT_PARAMETER params[3]; + + UINT rootIndex = 0; + { + D3D12_ROOT_PARAMETER& param = params[rootIndex++]; + param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; + param.Descriptor.ShaderRegister = 0u; + param.Descriptor.RegisterSpace = 0u; + param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + } + + D3D12_ROOT_SIGNATURE_DESC desc; + desc.NumParameters = rootIndex; + desc.pParameters = params; + desc.NumStaticSamplers = 0u; + desc.pStaticSamplers = nullptr; + desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; + + ComPtr<ID3DBlob> sigBlob; + NV_RETURN_ON_FAIL(Dx12HelperUtil::serializeRootSigniture(desc, D3D_ROOT_SIGNATURE_VERSION_1, sigBlob)); + NV_RETURN_ON_FAIL(device->CreateRootSignature(0u, sigBlob->GetBufferPointer(), sigBlob->GetBufferSize(), IID_PPV_ARGS(&signiture))); + } + + { + psoDesc.VS = Dx12Blob(g_diffuseVS); + psoDesc.GS = Dx12Blob(g_diffuseGS); + psoDesc.PS = Dx12Blob(g_diffusePS); + + NV_RETURN_ON_FAIL(_initPipelineState(state, shadowMap, PIPELINE_STATE_LIGHT_SOLID, signiture.Get(), psoDesc)); + } + } + + return NV_OK; +} + +int DiffusePointRenderPipelineD3D12::_initPipelineState(const RenderStateD3D12& state, NvCo::Dx12RenderTarget* shadowMap, PipelineStateType pipeType, ID3D12RootSignature* signiture, D3D12_GRAPHICS_PIPELINE_STATE_DESC& psoDesc) +{ + ID3D12Device* device = state.m_device; + + _initRasterizerDesc(pipeType, psoDesc.RasterizerState); + _initPipelineStateDesc(pipeType, shadowMap, state.m_renderContext, psoDesc); + + psoDesc.pRootSignature = signiture; + + PipelineStateD3D12& pipeState = m_states[pipeType]; + pipeState.m_rootSignature = signiture; + + NV_RETURN_ON_FAIL(device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&pipeState.m_pipelineState))); + return NV_OK; +} + +int DiffusePointRenderPipelineD3D12::bind(const void* paramsIn, const void* platformState) +{ + const RenderStateD3D12& state = *(RenderStateD3D12*)platformState; + const DiffuseDrawParamsD3D& params = *(DiffuseDrawParamsD3D*)paramsIn; + + // Set up constant buffer + NvCo::Dx12CircularResourceHeap::Cursor cursor; + { + Hlsl::DiffuseShaderConst constBuf; + RenderParamsUtilD3D::calcDiffuseConstantBuffer(params, constBuf); + cursor = state.m_constantHeap->newConstantBuffer(constBuf); + if (!cursor.isValid()) + { + return NV_FAIL; + } + } + + const PipelineStateType pipeType = PIPELINE_STATE_LIGHT_SOLID; + PipelineStateD3D12& pipeState = m_states[pipeType]; + if (!pipeState.isValid()) + { + return NV_FAIL; + } + + ID3D12GraphicsCommandList* commandList = state.m_commandList; + commandList->SetGraphicsRootSignature(pipeState.m_rootSignature.Get()); + commandList->SetPipelineState(pipeState.m_pipelineState.Get()); + + D3D12_GPU_VIRTUAL_ADDRESS cbvHandle = state.m_constantHeap->getGpuHandle(cursor); + commandList->SetGraphicsRootConstantBufferView(0, cbvHandle); + + { + ID3D12DescriptorHeap* heaps[] = { state.m_srvCbvUavDescriptorHeap->getHeap() }; + commandList->SetDescriptorHeaps(_countof(heaps), heaps); + } + return NV_OK; +} + +int DiffusePointRenderPipelineD3D12::draw(const RenderAllocation& allocIn, size_t sizeOfAlloc, const void* platformState) +{ + typedef PointRenderAllocationD3D12 Alloc; + const RenderStateD3D12& state = *(RenderStateD3D12*)platformState; + + assert(sizeof(Alloc) == sizeOfAlloc); + const Alloc& alloc = static_cast<const Alloc&>(allocIn); + + assert(alloc.m_numPrimitives >= 0); + + ID3D12GraphicsCommandList* commandList = state.m_commandList; + D3D12_VERTEX_BUFFER_VIEW vertexBufferViews[] = + { + alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_POSITION], + alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_ANISOTROPY1], // Actually holds velocity + }; + + commandList->IASetVertexBuffers(0, _countof(vertexBufferViews), vertexBufferViews); + commandList->IASetIndexBuffer(&alloc.m_indexBufferView); + commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_POINTLIST); + + if (alloc.m_indexBufferView.SizeInBytes) + { + commandList->DrawIndexedInstanced((UINT)allocIn.m_numPrimitives, 1, 0, 0, 0); + } + else + { + commandList->DrawInstanced((UINT)allocIn.m_numPrimitives, 1, 0, 0); + } + return NV_OK; +} + +} // namespace FlexSample
\ No newline at end of file diff --git a/demo/d3d12/diffusePointRenderPipelineD3D12.h b/demo/d3d12/diffusePointRenderPipelineD3D12.h new file mode 100644 index 0000000..39f6292 --- /dev/null +++ b/demo/d3d12/diffusePointRenderPipelineD3D12.h @@ -0,0 +1,54 @@ +/* +* Copyright (c) 2008-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. +*/ + +#ifndef DIFFUSE_POINT_RENDER_PIPELINE_D3D12_H +#define DIFFUSE_POINT_RENDER_PIPELINE_D3D12_H + +#include <DirectXMath.h> +#include "../d3d/renderParamsD3D.h" +#include "renderStateD3D12.h" +#include "meshRenderer.h" + +#include <NvCoDx12RenderTarget.h> + +namespace FlexSample { +using namespace nvidia; + +struct DiffusePointRenderPipelineD3D12: public RenderPipeline +{ + //NV_CO_DECLARE_POLYMORPHIC_CLASS(DiffusePointRenderPipelineD3D12, RenderPipeline); +public: + typedef RenderPipeline Parent; + + enum PipelineStateType + { + PIPELINE_STATE_LIGHT_SOLID, + PIPELINE_STATE_COUNT_OF, + }; + + DiffusePointRenderPipelineD3D12(); + + /// Initialize + int initialize(const RenderStateD3D12& state, const std::wstring& shadersDir, int shadowMapLinearSamplerIndex, NvCo::Dx12RenderTarget* shadowMap); + /// Do the binding + virtual int bind(const void* paramsIn, const void* platformState) override; + virtual int draw(const RenderAllocation& alloc, size_t sizeOfAlloc, const void* platformState) override; + + protected: + + int _initPipelineState(const RenderStateD3D12& state, NvCo::Dx12RenderTarget* shadowMap, PipelineStateType pipeType, ID3D12RootSignature* signiture, D3D12_GRAPHICS_PIPELINE_STATE_DESC& psoDesc); + + int m_shadowMapLinearSamplerIndex; //< The index to the linear sampler in the m_samplerHeap + PipelineStateD3D12 m_states[PIPELINE_STATE_COUNT_OF]; +}; + +} // namespace FlexSample + +#endif // DIFFUSE_POINT_RENDER_PIPELINE_D3D12_H
\ No newline at end of file diff --git a/demo/d3d12/fluidCompositeRenderPipelineD3D12.cpp b/demo/d3d12/fluidCompositeRenderPipelineD3D12.cpp new file mode 100644 index 0000000..87dafd2 --- /dev/null +++ b/demo/d3d12/fluidCompositeRenderPipelineD3D12.cpp @@ -0,0 +1,166 @@ +#define NOMINMAX + +#include <NvCoDx12HelperUtil.h> +#include <external/D3D12/include/d3dx12.h> + +#include "pipelineUtilD3D12.h" +#include "meshRenderer.h" +#include "bufferD3D12.h" +#include "meshRendererD3D12.h" +#include "../d3d/shaderCommonD3D.h" + +// Shaders +#include "../d3d/shaders/passThroughVS.hlsl.h" +#include "../d3d/shaders/compositePS.hlsl.h" + +// this +#include "fluidCompositeRenderPipelineD3D12.h" + +#define NOMINMAX +#include <wrl.h> +using namespace Microsoft::WRL; + +namespace FlexSample { + +FluidCompositeRenderPipelineD3D12::FluidCompositeRenderPipelineD3D12(): + Parent(PRIMITIVE_TRIANGLE) +{ +} + +static void _initPipelineStateDesc(FluidCompositeRenderPipelineD3D12::PipelineStateType type, AppGraphCtxD3D12* renderContext, D3D12_GRAPHICS_PIPELINE_STATE_DESC& psoDesc) +{ + PipelineUtilD3D::initTargetFormat(nullptr, renderContext, psoDesc); + + psoDesc.InputLayout.NumElements = _countof(MeshRendererD3D12::MeshInputElementDescs); + psoDesc.InputLayout.pInputElementDescs = MeshRendererD3D12::MeshInputElementDescs; + psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; +} + +int FluidCompositeRenderPipelineD3D12::initialize(const RenderStateD3D12& state, const std::wstring& shadersPath) +{ + using namespace NvCo; + ID3D12Device* device = state.m_device; + + // create the pipeline state object + { + D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; + PipelineUtilD3D::initSolidBlendDesc(psoDesc.BlendState); + + // create the root signature + ComPtr<ID3D12RootSignature> signiture; + { + CD3DX12_DESCRIPTOR_RANGE ranges[2]; + CD3DX12_ROOT_PARAMETER params[10]; + + int rangeIndex = 0; + UINT rootIndex = 0; + { + D3D12_ROOT_PARAMETER& param = params[rootIndex++]; + param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; + param.Descriptor.ShaderRegister = 0u; + param.Descriptor.RegisterSpace = 0u; + param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + } + + // depthTex, sceneTex, shadowTex + const int numSrvs = 3; + if (numSrvs > 0) + { + ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, numSrvs, 0); + params[rootIndex++].InitAsDescriptorTable(1, &ranges[rangeIndex], D3D12_SHADER_VISIBILITY_PIXEL); + rangeIndex++; + } + + const int numSamplers = 2; + if (numSamplers > 1) + { + ranges[rangeIndex].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, numSamplers, 0); + params[rootIndex++].InitAsDescriptorTable(1, &ranges[rangeIndex], D3D12_SHADER_VISIBILITY_PIXEL); + rangeIndex++; + } + + D3D12_ROOT_SIGNATURE_DESC desc; + desc.NumParameters = rootIndex; + desc.pParameters = params; + desc.NumStaticSamplers = 0u; + desc.pStaticSamplers = nullptr; + desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; + + ComPtr<ID3DBlob> sigBlob; + NV_RETURN_ON_FAIL(Dx12HelperUtil::serializeRootSigniture(desc, D3D_ROOT_SIGNATURE_VERSION_1, sigBlob)); + NV_RETURN_ON_FAIL(device->CreateRootSignature(0u, sigBlob->GetBufferPointer(), sigBlob->GetBufferSize(), IID_PPV_ARGS(&signiture))); + } + + { + psoDesc.VS = Dx12Blob(g_passThroughVS); + psoDesc.PS = Dx12Blob(g_compositePS); + + NV_RETURN_ON_FAIL(_initPipelineState(state, PIPELINE_STATE_NORMAL, signiture.Get(), psoDesc)); + } + } + + return NV_OK; +} + +int FluidCompositeRenderPipelineD3D12::_initPipelineState(const RenderStateD3D12& state, PipelineStateType pipeType, ID3D12RootSignature* signiture, D3D12_GRAPHICS_PIPELINE_STATE_DESC& psoDesc) +{ + ID3D12Device* device = state.m_device; + + PipelineUtilD3D::initRasterizerDesc(FRONT_WINDING_CLOCKWISE, psoDesc.RasterizerState); + _initPipelineStateDesc(pipeType, state.m_renderContext, psoDesc); + + psoDesc.pRootSignature = signiture; + + PipelineStateD3D12& pipeState = m_states[pipeType]; + pipeState.m_rootSignature = signiture; + + NV_RETURN_ON_FAIL(device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&pipeState.m_pipelineState))); + return NV_OK; +} + +int FluidCompositeRenderPipelineD3D12::bind(const void* paramsIn, const void* platformState) +{ + const RenderStateD3D12& state = *(RenderStateD3D12*)platformState; + const FluidDrawParamsD3D& params = *(FluidDrawParamsD3D*)paramsIn; + + PipelineStateD3D12& pipeState = m_states[PIPELINE_STATE_NORMAL]; + if (!pipeState.isValid()) + { + return NV_FAIL; + } + + NvCo::Dx12CircularResourceHeap::Cursor cursor; + { + Hlsl::FluidShaderConst constBuf; + RenderParamsUtilD3D::calcFluidCompositeConstantBuffer(params, constBuf); + cursor = state.m_constantHeap->newConstantBuffer(constBuf); + if (!cursor.isValid()) + { + return NV_FAIL; + } + } + + ID3D12GraphicsCommandList* commandList = state.m_commandList; + + commandList->SetGraphicsRootSignature(pipeState.m_rootSignature.Get()); + commandList->SetPipelineState(pipeState.m_pipelineState.Get()); + + D3D12_GPU_VIRTUAL_ADDRESS cbvHandle = state.m_constantHeap->getGpuHandle(cursor); + commandList->SetGraphicsRootConstantBufferView(0, cbvHandle); + + ID3D12DescriptorHeap* heaps[] = { state.m_srvCbvUavDescriptorHeap->getHeap(), state.m_samplerDescriptorHeap->getHeap() }; + commandList->SetDescriptorHeaps(_countof(heaps), heaps); + + // Bind the srvs + commandList->SetGraphicsRootDescriptorTable(1, state.m_srvCbvUavDescriptorHeap->getGpuHandle(params.m_srvDescriptorBase)); + // Bind the samplers + commandList->SetGraphicsRootDescriptorTable(2, state.m_samplerDescriptorHeap->getGpuHandle(params.m_sampleDescriptorBase)); + return NV_OK; +} + +int FluidCompositeRenderPipelineD3D12::draw(const RenderAllocation& allocIn, size_t sizeOfAlloc, const void* platformState) +{ + return MeshRendererD3D12::defaultDraw(allocIn, sizeOfAlloc, platformState); +} + +} // namespace FlexSample
\ No newline at end of file diff --git a/demo/d3d12/fluidCompositeRenderPipelineD3D12.h b/demo/d3d12/fluidCompositeRenderPipelineD3D12.h new file mode 100644 index 0000000..509acea --- /dev/null +++ b/demo/d3d12/fluidCompositeRenderPipelineD3D12.h @@ -0,0 +1,54 @@ +/* +* Copyright (c) 2008-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. +*/ + +#ifndef FLUID_COMPOSITE_RENDER_PIPELINE_D3D12_H +#define FLUID_COMPOSITE_RENDER_PIPELINE_D3D12_H + +#include <DirectXMath.h> +#include "../d3d/renderParamsD3D.h" +#include "renderStateD3D12.h" +#include "meshRenderer.h" + +#include <NvCoDx12RenderTarget.h> + +#include "fluidEllipsoidRenderPipelineD3D12.h" + +namespace FlexSample { + +struct FluidCompositeRenderPipelineD3D12: public RenderPipeline +{ + //NV_CO_DECLARE_POLYMORPHIC_CLASS(FluidCompositeRenderPipelineD3D12, RenderPipeline); +public: + typedef RenderPipeline Parent; + + enum PipelineStateType + { + PIPELINE_STATE_NORMAL, + PIPELINE_STATE_COUNT_OF, + }; + + FluidCompositeRenderPipelineD3D12(); + + /// Initialize + int initialize(const RenderStateD3D12& state, const std::wstring& shadersPath); + /// Do the binding + virtual int bind(const void* paramsIn, const void* platformState) override; + virtual int draw(const RenderAllocation& alloc, size_t sizeOfAlloc, const void* platformState) override; + + protected: + + int _initPipelineState(const RenderStateD3D12& state, PipelineStateType pipeType, ID3D12RootSignature* signiture, D3D12_GRAPHICS_PIPELINE_STATE_DESC& psoDesc); + + PipelineStateD3D12 m_states[PIPELINE_STATE_COUNT_OF]; +}; + +} // namespace FlexSample + +#endif
\ No newline at end of file diff --git a/demo/d3d12/fluidEllipsoidRenderPipelineD3D12.cpp b/demo/d3d12/fluidEllipsoidRenderPipelineD3D12.cpp new file mode 100644 index 0000000..1c7ff53 --- /dev/null +++ b/demo/d3d12/fluidEllipsoidRenderPipelineD3D12.cpp @@ -0,0 +1,176 @@ +#define NOMINMAX + +#include <NvCoDx12HelperUtil.h> + +#include <external/D3D12/include/d3dx12.h> + +#include "pipelineUtilD3D12.h" +#include "meshRenderer.h" +#include "bufferD3D12.h" +#include "meshRendererD3D12.h" +#include "../d3d/shaderCommonD3D.h" + +#include "../d3d/shaders/ellipsoidDepthVS.hlsl.h" +#include "../d3d/shaders/ellipsoidDepthGS.hlsl.h" +#include "../d3d/shaders/ellipsoidDepthPS.hlsl.h" + +// this +#include "fluidEllipsoidRenderPipelineD3D12.h" + +namespace FlexSample { + +static const D3D12_INPUT_ELEMENT_DESC AnisotropicInputElementDescs[] = +{ + { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, + { "U", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, + { "V", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 2, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, + { "W", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 3, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, +}; + +FluidEllipsoidRenderPipelineD3D12::FluidEllipsoidRenderPipelineD3D12(): + Parent(PRIMITIVE_POINT) +{ +} + +static void _initPipelineStateDesc(FluidEllipsoidRenderPipelineD3D12::PipelineStateType type, NvCo::Dx12RenderTarget* renderTarget, D3D12_GRAPHICS_PIPELINE_STATE_DESC& psoDesc) +{ + PipelineUtilD3D::initTargetFormat(renderTarget, nullptr, psoDesc); + + psoDesc.InputLayout.NumElements = _countof(AnisotropicInputElementDescs); + psoDesc.InputLayout.pInputElementDescs = AnisotropicInputElementDescs; + psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT; +} + +int FluidEllipsoidRenderPipelineD3D12::initialize(const RenderStateD3D12& state, const std::wstring& shadersPath, NvCo::Dx12RenderTarget* renderTarget) +{ + using namespace NvCo; + ID3D12Device* device = state.m_device; + + // create the pipeline state object + { + D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; + PipelineUtilD3D::initSolidBlendDesc(psoDesc.BlendState); + + // create the root signature + ComPtr<ID3D12RootSignature> signiture; + { + CD3DX12_DESCRIPTOR_RANGE ranges[2]; + CD3DX12_ROOT_PARAMETER params[3]; + + UINT rootIndex = 0; + { + D3D12_ROOT_PARAMETER& param = params[rootIndex++]; + param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; + param.Descriptor.ShaderRegister = 0u; + param.Descriptor.RegisterSpace = 0u; + param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + } + + D3D12_ROOT_SIGNATURE_DESC desc; + desc.NumParameters = rootIndex; + desc.pParameters = params; + desc.NumStaticSamplers = 0u; + desc.pStaticSamplers = nullptr; + desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; + + ComPtr<ID3DBlob> sigBlob; + NV_RETURN_ON_FAIL(Dx12HelperUtil::serializeRootSigniture(desc, D3D_ROOT_SIGNATURE_VERSION_1, sigBlob)); + NV_RETURN_ON_FAIL(device->CreateRootSignature(0u, sigBlob->GetBufferPointer(), sigBlob->GetBufferSize(), IID_PPV_ARGS(&signiture))); + } + + { + psoDesc.VS = Dx12Blob(g_ellipsoidDepthVS); + psoDesc.GS = Dx12Blob(g_ellipsoidDepthGS); + psoDesc.PS = Dx12Blob(g_ellipsoidDepthPS); + + NV_RETURN_ON_FAIL(_initPipelineState(state, FRONT_WINDING_COUNTER_CLOCKWISE, renderTarget, PIPELINE_NORMAL, signiture.Get(), psoDesc)); + } + } + + return NV_OK; +} + +int FluidEllipsoidRenderPipelineD3D12::_initPipelineState(const RenderStateD3D12& state, FrontWindingType winding, NvCo::Dx12RenderTarget* renderTarget, PipelineStateType pipeType, ID3D12RootSignature* signiture, D3D12_GRAPHICS_PIPELINE_STATE_DESC& psoDesc) +{ + ID3D12Device* device = state.m_device; + + PipelineUtilD3D::initRasterizerDesc(winding, psoDesc.RasterizerState); + + _initPipelineStateDesc(pipeType, renderTarget, psoDesc); + + psoDesc.pRootSignature = signiture; + + PipelineStateD3D12& pipeState = m_states[pipeType]; + pipeState.m_rootSignature = signiture; + + NV_RETURN_ON_FAIL(device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&pipeState.m_pipelineState))); + return NV_OK; +} + +int FluidEllipsoidRenderPipelineD3D12::bind(const void* paramsIn, const void* platformState) +{ + const RenderStateD3D12& state = *(RenderStateD3D12*)platformState; + const FluidDrawParamsD3D& params = *(FluidDrawParamsD3D*)paramsIn; + + PipelineStateType pipeType = getPipelineStateType(params.renderStage, params.renderMode, params.cullMode); + PipelineStateD3D12& pipeState = m_states[pipeType]; + if (!pipeState.isValid()) + { + return NV_FAIL; + } + + NvCo::Dx12CircularResourceHeap::Cursor cursor; + { + Hlsl::FluidShaderConst constBuf; + RenderParamsUtilD3D::calcFluidConstantBuffer(params, constBuf); + cursor = state.m_constantHeap->newConstantBuffer(constBuf); + if (!cursor.isValid()) + { + return NV_FAIL; + } + } + + ID3D12GraphicsCommandList* commandList = state.m_commandList; + + commandList->SetGraphicsRootSignature(pipeState.m_rootSignature.Get()); + commandList->SetPipelineState(pipeState.m_pipelineState.Get()); + + D3D12_GPU_VIRTUAL_ADDRESS cbvHandle = state.m_constantHeap->getGpuHandle(cursor); + commandList->SetGraphicsRootConstantBufferView(0, cbvHandle); + + ID3D12DescriptorHeap* heaps[] = { nullptr }; + commandList->SetDescriptorHeaps(0, heaps); + + return NV_OK; +} + +int FluidEllipsoidRenderPipelineD3D12::draw(const RenderAllocation& allocIn, size_t sizeOfAlloc, const void* platformState) +{ + typedef PointRenderAllocationD3D12 Alloc; + const RenderStateD3D12& state = *(RenderStateD3D12*)platformState; + + assert(sizeof(Alloc) == sizeOfAlloc); + const Alloc& alloc = static_cast<const Alloc&>(allocIn); + + assert(allocIn.m_numPrimitives >= 0); + + ID3D12GraphicsCommandList* commandList = state.m_commandList; + + D3D12_VERTEX_BUFFER_VIEW vertexBufferViews[4] = + { + alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_POSITION], + alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_ANISOTROPY1], + alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_ANISOTROPY2], + alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_ANISOTROPY3], + }; + + commandList->IASetVertexBuffers(0, _countof(vertexBufferViews), vertexBufferViews); + commandList->IASetIndexBuffer(&alloc.m_indexBufferView); + + commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_POINTLIST); + + commandList->DrawIndexedInstanced((UINT)allocIn.m_numPrimitives, 1, 0, 0, 0); + return NV_OK; +} + +} // namespace FlexSample
\ No newline at end of file diff --git a/demo/d3d12/fluidEllipsoidRenderPipelineD3D12.h b/demo/d3d12/fluidEllipsoidRenderPipelineD3D12.h new file mode 100644 index 0000000..96d326b --- /dev/null +++ b/demo/d3d12/fluidEllipsoidRenderPipelineD3D12.h @@ -0,0 +1,60 @@ +/* +* Copyright (c) 2008-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. +*/ + +#ifndef FLUID_ELLIPSOID_RENDER_PIPELINE_D3D12_H +#define FLUID_ELLIPSOID_RENDER_PIPELINE_D3D12_H + +#include <DirectXMath.h> +#include "RenderStateD3D12.h" +#include "../d3d/renderParamsD3D.h" +#include "meshRenderer.h" + +#include <NvCoDx12RenderTarget.h> + +namespace FlexHlsl { +struct FluidShaderConst; +} // namespace FlexHlsl + +namespace FlexSample { +using namespace nvidia; + +struct FluidEllipsoidRenderPipelineD3D12: public RenderPipeline +{ + //NV_CO_DECLARE_POLYMORPHIC_CLASS(FluidEllipsoidRenderPipelineD3D12, RenderPipeline); +public: + typedef RenderPipeline Parent; + + enum PipelineStateType + { + PIPELINE_NORMAL, + PIPELINE_STATE_COUNT_OF, + }; + + FluidEllipsoidRenderPipelineD3D12(); + + /// Initialize + int initialize(const RenderStateD3D12& state, const std::wstring& shadersDir, NvCo::Dx12RenderTarget* renderTarget); + /// Do the binding + virtual int bind(const void* paramsIn, const void* platformState) override; + virtual int draw(const RenderAllocation& alloc, size_t sizeOfAlloc, const void* platformState) override; + + /// Convert into a single pipeline state type + static PipelineStateType getPipelineStateType(FluidDrawStage stage, FluidRenderMode mode, FluidCullMode cull) { return PIPELINE_NORMAL; } + + protected: + + int _initPipelineState(const RenderStateD3D12& state, FrontWindingType winding, NvCo::Dx12RenderTarget* renderTarget, PipelineStateType pipeType, ID3D12RootSignature* signiture, D3D12_GRAPHICS_PIPELINE_STATE_DESC& psoDesc); + + PipelineStateD3D12 m_states[PIPELINE_STATE_COUNT_OF]; +}; + +} // namespace FlexSample + +#endif
\ No newline at end of file diff --git a/demo/d3d12/fluidSmoothRenderPipelineD3D12.cpp b/demo/d3d12/fluidSmoothRenderPipelineD3D12.cpp new file mode 100644 index 0000000..6d6c489 --- /dev/null +++ b/demo/d3d12/fluidSmoothRenderPipelineD3D12.cpp @@ -0,0 +1,158 @@ +#define NOMINMAX + +#include <NvCoDx12HelperUtil.h> +#include <external/D3D12/include/d3dx12.h> + +#include "meshRenderer.h" +#include "pipelineUtilD3D12.h" +#include "bufferD3D12.h" +#include "meshRendererD3D12.h" +#include "../d3d/shaderCommonD3D.h" + +// this +#include "fluidSmoothRenderPipelineD3D12.h" + +// Shaders +#include "../d3d/shaders/passThroughVS.hlsl.h" +#include "../d3d/shaders/blurDepthPS.hlsl.h" + +namespace FlexSample { + +FluidSmoothRenderPipelineD3D12::FluidSmoothRenderPipelineD3D12(int fluidPointDepthSrvIndex): + Parent(PRIMITIVE_TRIANGLE), + m_fluidPointDepthSrvIndex(fluidPointDepthSrvIndex) +{ +} + +static void _initPipelineStateDesc(FluidSmoothRenderPipelineD3D12::PipelineStateType type, NvCo::Dx12RenderTarget* renderTarget, AppGraphCtxD3D12* renderContext, D3D12_GRAPHICS_PIPELINE_STATE_DESC& psoDesc) +{ + PipelineUtilD3D::initTargetFormat(renderTarget, nullptr, psoDesc); + + psoDesc.InputLayout.NumElements = _countof(MeshRendererD3D12::MeshInputElementDescs); + psoDesc.InputLayout.pInputElementDescs = MeshRendererD3D12::MeshInputElementDescs; + psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; +} + +int FluidSmoothRenderPipelineD3D12::initialize(const RenderStateD3D12& state, const std::wstring& shadersPath, NvCo::Dx12RenderTarget* renderTarget) +{ + using namespace NvCo; + ID3D12Device* device = state.m_device; + + // create the pipeline state object + { + D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; + PipelineUtilD3D::initSolidBlendDesc(psoDesc.BlendState); + + // create the root signature + ComPtr<ID3D12RootSignature> signiture; + { + CD3DX12_DESCRIPTOR_RANGE ranges[2]; + CD3DX12_ROOT_PARAMETER params[3]; + + UINT rootIndex = 0; + { + D3D12_ROOT_PARAMETER& param = params[rootIndex++]; + param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; + param.Descriptor.ShaderRegister = 0u; + param.Descriptor.RegisterSpace = 0u; + param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + } + + const int numSrvs = 1; + if (numSrvs > 0) + { + ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, numSrvs, 0); + params[rootIndex++].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_PIXEL); + } + const int numSamplers = 0; + if (numSamplers > 0) + { + ranges[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, numSamplers, 0); + params[rootIndex++].InitAsDescriptorTable(1, &ranges[1], D3D12_SHADER_VISIBILITY_PIXEL); + } + + D3D12_ROOT_SIGNATURE_DESC desc; + desc.NumParameters = rootIndex; + desc.pParameters = params; + desc.NumStaticSamplers = 0u; + desc.pStaticSamplers = nullptr; + desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; + + ComPtr<ID3DBlob> sigBlob; + NV_RETURN_ON_FAIL(Dx12HelperUtil::serializeRootSigniture(desc, D3D_ROOT_SIGNATURE_VERSION_1, sigBlob)); + NV_RETURN_ON_FAIL(device->CreateRootSignature(0u, sigBlob->GetBufferPointer(), sigBlob->GetBufferSize(), IID_PPV_ARGS(&signiture))); + } + + { + psoDesc.VS = Dx12Blob(g_passThroughVS); + psoDesc.PS = Dx12Blob(g_blurDepthPS); + + NV_RETURN_ON_FAIL(_initPipelineState(state, renderTarget, PIPELINE_STATE_NORMAL, signiture.Get(), psoDesc)); + } + } + + return NV_OK; +} + +int FluidSmoothRenderPipelineD3D12::_initPipelineState(const RenderStateD3D12& state, NvCo::Dx12RenderTarget* renderTarget, PipelineStateType pipeType, ID3D12RootSignature* signiture, D3D12_GRAPHICS_PIPELINE_STATE_DESC& psoDesc) +{ + ID3D12Device* device = state.m_device; + + PipelineUtilD3D::initRasterizerDesc(FRONT_WINDING_CLOCKWISE, psoDesc.RasterizerState); + _initPipelineStateDesc(pipeType, renderTarget, state.m_renderContext, psoDesc); + + psoDesc.pRootSignature = signiture; + + PipelineStateD3D12& pipeState = m_states[pipeType]; + pipeState.m_rootSignature = signiture; + + NV_RETURN_ON_FAIL(device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&pipeState.m_pipelineState))); + return NV_OK; +} + +int FluidSmoothRenderPipelineD3D12::bind(const void* paramsIn, const void* platformState) +{ + const RenderStateD3D12& state = *(RenderStateD3D12*)platformState; + const FluidDrawParamsD3D& params = *(FluidDrawParamsD3D*)paramsIn; + + PipelineStateD3D12& pipeState = m_states[PIPELINE_STATE_NORMAL]; + if (!pipeState.isValid()) + { + return NV_FAIL; + } + + NvCo::Dx12CircularResourceHeap::Cursor cursor; + { + Hlsl::FluidShaderConst constBuf; + RenderParamsUtilD3D::calcFluidConstantBuffer(params, constBuf); + cursor = state.m_constantHeap->newConstantBuffer(constBuf); + if (!cursor.isValid()) + { + return NV_FAIL; + } + } + + ID3D12GraphicsCommandList* commandList = state.m_commandList; + + commandList->SetGraphicsRootSignature(pipeState.m_rootSignature.Get()); + commandList->SetPipelineState(pipeState.m_pipelineState.Get()); + + D3D12_GPU_VIRTUAL_ADDRESS cbvHandle = state.m_constantHeap->getGpuHandle(cursor); + commandList->SetGraphicsRootConstantBufferView(0, cbvHandle); + + NvCo::Dx12RenderTarget* sourceMap = (NvCo::Dx12RenderTarget*)params.shadowMap; + + ID3D12DescriptorHeap* heaps[] = { state.m_srvCbvUavDescriptorHeap->getHeap(), state.m_samplerDescriptorHeap->getHeap() }; + commandList->SetDescriptorHeaps(_countof(heaps), heaps); + + // Bind the srvs + commandList->SetGraphicsRootDescriptorTable(1, state.m_srvCbvUavDescriptorHeap->getGpuHandle(m_fluidPointDepthSrvIndex)); + return NV_OK; +} + +int FluidSmoothRenderPipelineD3D12::draw(const RenderAllocation& allocIn, size_t sizeOfAlloc, const void* platformState) +{ + return MeshRendererD3D12::defaultDraw(allocIn, sizeOfAlloc, platformState); +} + +} // namespace FlexSample
\ No newline at end of file diff --git a/demo/d3d12/fluidSmoothRenderPipelineD3D12.h b/demo/d3d12/fluidSmoothRenderPipelineD3D12.h new file mode 100644 index 0000000..fc08981 --- /dev/null +++ b/demo/d3d12/fluidSmoothRenderPipelineD3D12.h @@ -0,0 +1,55 @@ +/* +* Copyright (c) 2008-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. +*/ + +#ifndef FLUID_SMOOTH_RENDER_PIPELINE_D3D12_H +#define FLUID_SMOOTH_RENDER_PIPELINE_D3D12_H + +#include <DirectXMath.h> +#include "RenderStateD3D12.h" +#include "MeshRenderer.h" + +#include <NvCoDx12RenderTarget.h> + +#include "FluidEllipsoidRenderPipelineD3D12.h" + +namespace FlexSample { + +struct FluidSmoothRenderPipelineD3D12: public RenderPipeline +{ + //NV_CO_DECLARE_POLYMORPHIC_CLASS(FluidSmoothRenderPipelineD3D12, RenderPipeline); +public: + typedef RenderPipeline Parent; + + enum PipelineStateType + { + PIPELINE_STATE_NORMAL, + PIPELINE_STATE_COUNT_OF, + }; + + FluidSmoothRenderPipelineD3D12(int fluidPointDepthSrvIndex); + + /// Initialize + int initialize(const RenderStateD3D12& state, const std::wstring& shadersPath, NvCo::Dx12RenderTarget* renderTarget); + /// Do the binding + virtual int bind(const void* paramsIn, const void* platformState) override; + virtual int draw(const RenderAllocation& alloc, size_t sizeOfAlloc, const void* platformState) override; + + protected: + + int _initPipelineState(const RenderStateD3D12& state, NvCo::Dx12RenderTarget* renderTarget, PipelineStateType pipeType, ID3D12RootSignature* signiture, D3D12_GRAPHICS_PIPELINE_STATE_DESC& psoDesc); + + PipelineStateD3D12 m_states[PIPELINE_STATE_COUNT_OF]; + + int m_fluidPointDepthSrvIndex; +}; + +} // namespace FlexSample + +#endif
\ No newline at end of file diff --git a/demo/d3d12/imguiGraphD3D12.cpp b/demo/d3d12/imguiGraphD3D12.cpp new file mode 100644 index 0000000..64c507d --- /dev/null +++ b/demo/d3d12/imguiGraphD3D12.cpp @@ -0,0 +1,667 @@ +/* + * Copyright (c) 2014-2017, 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. + */ + +//direct3d headers +#define NOMINMAX +#include <d3d12.h> + +#include "imguiGraphD3D12.h" + +#include "../d3d/shaders/imguiVS.hlsl.h" +#include "../d3d/shaders/imguiPS.hlsl.h" + +namespace +{ + template <class T> + void inline COMRelease(T& t) + { + if (t) t->Release(); + t = nullptr; + } +} + +namespace +{ + ImguiGraphDescD3D12 m_desc = {}; + + struct Vertex + { + float x, y; + float u, v; + uint8_t rgba[4]; + }; + + ID3D12RootSignature* m_rootSignature = nullptr; + ID3D12PipelineState* m_pipelineState = nullptr; + ID3D12Resource* m_constantBuffer = nullptr; + UINT8* m_constantBufferData = nullptr; + ID3D12Resource* m_vertexBuffer = nullptr; + Vertex* m_vertexBufferData = nullptr; + D3D12_VERTEX_BUFFER_VIEW m_vertexBufferView = {}; + + struct Scissor + { + int beginIdx; + int stopIdx; + int x; + int y; + int width; + int height; + }; + Scissor m_stateScissor = {}; + + ID3D12Resource* m_textureUploadHeap = nullptr; + ID3D12Resource* m_texture = nullptr; + + ID3D12DescriptorHeap* m_srvUavHeapCPU = nullptr; + ID3D12DescriptorHeap* m_srvUavHeapGPU = nullptr; + + Vertex m_stateVert; + uint32_t m_stateVertIdx = 0u; + + struct Params + { + float projection[16]; + + float padding[64 - 16]; + }; + static const int frameCount = 4; + int frameIndex = 0; +} + +void imguiGraphContextInitD3D12(const ImguiGraphDesc* descIn) +{ + const auto desc = cast_to_imguiGraphDescD3D12(descIn); + + m_desc = *desc; + + // create the root signature + { + D3D12_DESCRIPTOR_RANGE ranges[1]; + ranges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + ranges[0].NumDescriptors = 1u; + ranges[0].BaseShaderRegister = 0u; + ranges[0].RegisterSpace = 0u; + ranges[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; + + D3D12_ROOT_PARAMETER params[2]; + params[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; + params[0].Descriptor.ShaderRegister = 0u; + params[0].Descriptor.RegisterSpace = 0u; + params[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + params[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + params[1].DescriptorTable.NumDescriptorRanges = 1; + params[1].DescriptorTable.pDescriptorRanges = ranges; + params[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; + + D3D12_STATIC_SAMPLER_DESC sampler = {}; + sampler.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT; + sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_BORDER; + sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_BORDER; + sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_BORDER; + sampler.MipLODBias = 0; + sampler.MaxAnisotropy = 0; + sampler.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; + sampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK; + sampler.MinLOD = 0.f; + sampler.MaxLOD = D3D12_FLOAT32_MAX; + sampler.ShaderRegister = 0; + sampler.RegisterSpace = 0; + sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; + + D3D12_ROOT_SIGNATURE_DESC desc; + desc.NumParameters = 2; + desc.pParameters = params; + desc.NumStaticSamplers = 1u; + desc.pStaticSamplers = &sampler; + desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; + + ID3DBlob* signature = nullptr; + ID3DBlob* error = nullptr; + HRESULT hr = S_OK; + if (hr = D3D12SerializeRootSignature(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error)) + { + return; + } + if (hr = m_desc.device->CreateRootSignature(0u, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature))) + { + return; + } + COMRelease(signature); + COMRelease(error); + } + + // create the pipeline state object + { + D3D12_INPUT_ELEMENT_DESC inputElementDescs[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, + }; + + const bool wireFrame = false; + + D3D12_RASTERIZER_DESC rasterDesc; + if (wireFrame) + { + rasterDesc.FillMode = D3D12_FILL_MODE_WIREFRAME; + rasterDesc.CullMode = D3D12_CULL_MODE_NONE; + } + else + { + rasterDesc.FillMode = D3D12_FILL_MODE_SOLID; + rasterDesc.CullMode = D3D12_CULL_MODE_BACK; + } + rasterDesc.FrontCounterClockwise = TRUE; // FALSE; + rasterDesc.DepthBias = D3D12_DEFAULT_DEPTH_BIAS; + rasterDesc.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP; + rasterDesc.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS; + rasterDesc.DepthClipEnable = TRUE; + rasterDesc.MultisampleEnable = FALSE; + rasterDesc.AntialiasedLineEnable = FALSE; + rasterDesc.ForcedSampleCount = 0; + rasterDesc.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF; + + D3D12_BLEND_DESC blendDesc; + blendDesc.AlphaToCoverageEnable = FALSE; + blendDesc.IndependentBlendEnable = FALSE; + { + const D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc = + { + TRUE,FALSE, + D3D12_BLEND_SRC_ALPHA, D3D12_BLEND_INV_SRC_ALPHA, D3D12_BLEND_OP_ADD, + D3D12_BLEND_SRC_ALPHA, D3D12_BLEND_INV_SRC_ALPHA, D3D12_BLEND_OP_ADD, + D3D12_LOGIC_OP_NOOP, + D3D12_COLOR_WRITE_ENABLE_ALL, + }; + for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i) + blendDesc.RenderTarget[i] = defaultRenderTargetBlendDesc; + } + + D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; + psoDesc.InputLayout.NumElements = 3; + psoDesc.InputLayout.pInputElementDescs = inputElementDescs; + psoDesc.pRootSignature = m_rootSignature; + psoDesc.VS.pShaderBytecode = g_imguiVS; + psoDesc.VS.BytecodeLength = sizeof(g_imguiVS); + psoDesc.PS.pShaderBytecode = g_imguiPS; + psoDesc.PS.BytecodeLength = sizeof(g_imguiPS); + psoDesc.RasterizerState = rasterDesc; + psoDesc.BlendState = blendDesc; + psoDesc.DepthStencilState.DepthEnable = FALSE; + psoDesc.DepthStencilState.StencilEnable = FALSE; + psoDesc.SampleMask = UINT_MAX; + psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + psoDesc.NumRenderTargets = 1; + psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; + psoDesc.SampleDesc.Count = desc->numMSAASamples; + HRESULT hr = S_OK; + if (hr = m_desc.device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineState))) + { + return; + } + } + + // create a constant buffer + { + Params params = { + 1.f, 0.f, 0.f, 0.f, + 0.f, 1.f, 0.f, 0.f, + 0.f, 0.f, 1.f, 0.f, + 0.f, 0.f, 0.f, 1.f + }; + + HRESULT hr = S_OK; + + D3D12_HEAP_PROPERTIES heapProps = {}; + heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; + heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + heapProps.CreationNodeMask = 0u; + heapProps.VisibleNodeMask = 0u; + + D3D12_RESOURCE_DESC desc = {}; + desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + desc.Alignment = 0u; + desc.Width = frameCount*sizeof(params); + desc.Height = 1u; + desc.DepthOrArraySize = 1u; + desc.MipLevels = 1; + desc.Format = DXGI_FORMAT_UNKNOWN; + desc.SampleDesc.Count = 1u; + desc.SampleDesc.Quality = 0u; + desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + desc.Flags = D3D12_RESOURCE_FLAG_NONE; + + if (hr = m_desc.device->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, IID_PPV_ARGS(&m_constantBuffer))) + { + return; + } + + UINT8* pdata; + D3D12_RANGE readRange = {}; + if (hr = m_constantBuffer->Map(0, &readRange, (void**)&pdata)) + { + return; + } + else + { + memcpy(pdata, ¶ms, sizeof(params)); + m_constantBufferData = pdata; + //m_constantBuffer->Unmap(0, nullptr); // leave mapped + } + } + + // create a vertex buffer + { + HRESULT hr = S_OK; + + UINT bufferSize = (UINT)(m_desc.maxVertices * frameCount) * sizeof(Vertex); + + D3D12_HEAP_PROPERTIES heapProps = {}; + heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; + heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + heapProps.CreationNodeMask = 0u; + heapProps.VisibleNodeMask = 0u; + + D3D12_RESOURCE_DESC desc = {}; + desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + desc.Alignment = 0u; + desc.Width = bufferSize; + desc.Height = 1u; + desc.DepthOrArraySize = 1u; + desc.MipLevels = 1; + desc.Format = DXGI_FORMAT_UNKNOWN; + desc.SampleDesc.Count = 1u; + desc.SampleDesc.Quality = 0u; + desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + desc.Flags = D3D12_RESOURCE_FLAG_NONE; + + if (hr = m_desc.device->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, IID_PPV_ARGS(&m_vertexBuffer))) + { + return; + } + + UINT8* pdata; + D3D12_RANGE readRange = {}; + if (hr = m_vertexBuffer->Map(0, &readRange, (void**)&pdata)) + { + return; + } + else + { + m_vertexBufferData = (Vertex*)pdata; + //m_vertexBufferUpload->Unmap(0, nullptr); + } + + m_vertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress(); + m_vertexBufferView.StrideInBytes = sizeof(Vertex); + m_vertexBufferView.SizeInBytes = bufferSize; + } +} + +void imguiGraphContextUpdateD3D12(const ImguiGraphDesc* descIn) +{ + const auto desc = cast_to_imguiGraphDescD3D12(descIn); + + m_desc = *desc; +} + +void imguiGraphContextDestroyD3D12() +{ + COMRelease(m_rootSignature); + COMRelease(m_pipelineState); + COMRelease(m_constantBuffer); + COMRelease(m_vertexBuffer); +} + +void imguiGraphRecordBeginD3D12() +{ + frameIndex = (frameIndex + 1) % frameCount; + + Params params = { + 2.f / float(m_desc.winW), 0.f, 0.f, -1.f, + 0.f, 2.f / float(m_desc.winH), 0.f, -1.f, + 0.f, 0.f, 1.f, 0.f, + 0.f, 0.f, 0.f, 1.f + }; + + memcpy(m_constantBufferData + frameIndex*sizeof(Params), ¶ms, sizeof(Params)); + + // clear state + m_stateVert = Vertex{ 0.f, 0.f, -1.f, -1.f, 0,0,0,0 }; + m_stateVertIdx = 0u; + + m_stateScissor = Scissor { 0, 0, 0, 0, m_desc.winW, m_desc.winH }; + + // configure for triangle renderering + ID3D12GraphicsCommandList* commandList = m_desc.commandList; + + D3D12_CPU_DESCRIPTOR_HANDLE srvHandleCPU; + D3D12_GPU_DESCRIPTOR_HANDLE srvHandleGPU; + ID3D12DescriptorHeap* heap = nullptr; + if (m_desc.dynamicHeapCbvSrvUav.reserveDescriptors) + { + auto handle = m_desc.dynamicHeapCbvSrvUav.reserveDescriptors(m_desc.dynamicHeapCbvSrvUav.userdata, + 1u, m_desc.lastFenceCompleted, m_desc.nextFenceValue); + heap = handle.heap; + srvHandleCPU = handle.cpuHandle; + srvHandleGPU = handle.gpuHandle; + } + else + { + if (m_srvUavHeapGPU == nullptr) + { + D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {}; + srvHeapDesc.NumDescriptors = 1; + srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; + srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + m_desc.device->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&m_srvUavHeapGPU)); + } + heap = m_srvUavHeapGPU; + srvHandleCPU = m_srvUavHeapGPU->GetCPUDescriptorHandleForHeapStart(); + srvHandleGPU = m_srvUavHeapGPU->GetGPUDescriptorHandleForHeapStart(); + } + + commandList->SetDescriptorHeaps(1, &heap); + + m_desc.device->CopyDescriptorsSimple(1u, srvHandleCPU, m_srvUavHeapCPU->GetCPUDescriptorHandleForHeapStart(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + + commandList->SetGraphicsRootSignature(m_rootSignature); + commandList->SetPipelineState(m_pipelineState); + + D3D12_GPU_VIRTUAL_ADDRESS cbvHandle = m_constantBuffer->GetGPUVirtualAddress(); + commandList->SetGraphicsRootConstantBufferView(0, cbvHandle + frameIndex * sizeof(Params)); + + commandList->SetGraphicsRootDescriptorTable(1, srvHandleGPU); + + commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + commandList->IASetVertexBuffers(0, 1, &m_vertexBufferView); +} + +static void imguiGraphFlush() +{ + ID3D12GraphicsCommandList* commandList = m_desc.commandList; + + Scissor& p = m_stateScissor; + if (p.beginIdx < p.stopIdx) + { + int winH = m_desc.winH; + D3D12_RECT rect; + rect.left = p.x; + rect.right = p.x + p.width; + rect.top = (winH) - (p.y + p.height); + rect.bottom = (winH) - (p.y); + commandList->RSSetScissorRects(1, &rect); + + UINT vertexCount = (p.stopIdx - p.beginIdx); + UINT startIndex = p.beginIdx + frameIndex * m_desc.maxVertices; + commandList->DrawInstanced(vertexCount, 1, startIndex, 0); + } +} + +void imguiGraphRecordEndD3D12() +{ + ID3D12GraphicsCommandList* commandList = m_desc.commandList; + + // no need to hold onto this + COMRelease(m_textureUploadHeap); + + // restore scissor + Scissor& p = m_stateScissor; + int winH = m_desc.winH; + D3D12_RECT rect; + rect.left = p.x; + rect.right = p.x + p.width; + rect.top = (winH) - (p.y + p.height); + rect.bottom = (winH) - (p.y); + commandList->RSSetScissorRects(1, &rect); +} + +void imguiGraphEnableScissorD3D12(int x, int y, int width, int height) +{ + // mark end of last region + m_stateScissor.stopIdx = m_stateVertIdx; + + imguiGraphFlush(); + + m_stateScissor.beginIdx = m_stateVertIdx; + m_stateScissor.stopIdx = m_stateVertIdx; + m_stateScissor.x = x; + m_stateScissor.y = y; + m_stateScissor.width = width; + m_stateScissor.height = height; +} + +void imguiGraphDisableScissorD3D12() +{ + if (m_stateVertIdx == 0) return; + + // mark end of last region + m_stateScissor.stopIdx = m_stateVertIdx; + + imguiGraphFlush(); + + m_stateScissor.beginIdx = m_stateVertIdx; + m_stateScissor.stopIdx = m_stateVertIdx; + m_stateScissor.x = 0; + m_stateScissor.y = 0; + m_stateScissor.width = m_desc.winW; + m_stateScissor.height = m_desc.winH; +} + +void imguiGraphVertex2fD3D12(float x, float y) +{ + float v[2] = { x,y }; + imguiGraphVertex2fvD3D12(v); +} + +void imguiGraphVertex2fvD3D12(const float* v) +{ + // update state + m_stateVert.x = v[0]; + m_stateVert.y = v[1]; + + Vertex* vdata = &m_vertexBufferData[frameIndex * m_desc.maxVertices]; + + // push vertex + if ((m_stateVertIdx) < m_desc.maxVertices) + { + vdata[m_stateVertIdx++] = m_stateVert; + } +} + +void imguiGraphTexCoord2fD3D12(float u, float v) +{ + m_stateVert.u = u; + m_stateVert.v = v; +} + +void imguiGraphColor4ubD3D12(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) +{ + m_stateVert.rgba[0] = red; + m_stateVert.rgba[1] = green; + m_stateVert.rgba[2] = blue; + m_stateVert.rgba[3] = alpha; +} + +void imguiGraphColor4ubvD3D12(const uint8_t* v) +{ + m_stateVert.rgba[0] = v[0]; + m_stateVert.rgba[1] = v[1]; + m_stateVert.rgba[2] = v[2]; + m_stateVert.rgba[3] = v[3]; +} + +void imguiGraphFontTextureEnableD3D12() +{ + +} + +void imguiGraphFontTextureDisableD3D12() +{ + m_stateVert.u = -1.f; + m_stateVert.v = -1.f; +} + +void imguiGraphFontTextureInitD3D12(unsigned char* data) +{ + ID3D12GraphicsCommandList* commandList = m_desc.commandList; + + // Create the texture + { + UINT width = 512; + UINT height = 512; + + D3D12_HEAP_PROPERTIES heapProps = {}; + heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; + heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + heapProps.CreationNodeMask = 0u; + heapProps.VisibleNodeMask = 0u; + + D3D12_RESOURCE_DESC texDesc = {}; + texDesc.MipLevels = 1u; + texDesc.Format = DXGI_FORMAT_R8_UNORM; + texDesc.Width = width; + texDesc.Height = height; + texDesc.Flags = D3D12_RESOURCE_FLAG_NONE; + texDesc.DepthOrArraySize = 1u; + texDesc.SampleDesc.Count = 1u; + texDesc.SampleDesc.Quality = 0u; + texDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; + + if (m_desc.device->CreateCommittedResource( + &heapProps, + D3D12_HEAP_FLAG_NONE, + &texDesc, + D3D12_RESOURCE_STATE_COPY_DEST, + nullptr, + IID_PPV_ARGS(&m_texture) + )) + { + return; + } + + // get footprint information + D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprint = {}; + UINT64 uploadHeapSize = 0u; + m_desc.device->GetCopyableFootprints(&texDesc, 0u, 1u, 0u, &footprint, nullptr, nullptr, &uploadHeapSize); + + heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; + D3D12_RESOURCE_DESC bufferDesc = texDesc; + bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + bufferDesc.Alignment = 0u; + bufferDesc.Width = uploadHeapSize; + bufferDesc.Height = 1u; + bufferDesc.DepthOrArraySize = 1u; + bufferDesc.MipLevels = 1; + bufferDesc.Format = DXGI_FORMAT_UNKNOWN; + bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + bufferDesc.Flags = D3D12_RESOURCE_FLAG_NONE; + + if (m_desc.device->CreateCommittedResource( + &heapProps, + D3D12_HEAP_FLAG_NONE, + &bufferDesc, + D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, + IID_PPV_ARGS(&m_textureUploadHeap) + )) + { + return; + } + + // map upload heap, and convert rgb bitmap to rgba + UINT8* pdata; + D3D12_RANGE readRange = {}; + if (m_textureUploadHeap->Map(0, &readRange, (void**)&pdata)) + { + return; + } + else + { + UINT8* dst = pdata; + UINT elements = width*height; + UINT8* src = data; + for (UINT j = 0; j < height; j++) + { + for (UINT i = 0; i < width; i++) + { + UINT idx = j * (footprint.Footprint.RowPitch) + i; + + UINT8 a = src[j * width + i]; + dst[idx] = a; + } + } + + m_textureUploadHeap->Unmap(0, nullptr); + } + + // add copy from upload heap to default heap to command list + D3D12_TEXTURE_COPY_LOCATION dstCopy = {}; + D3D12_TEXTURE_COPY_LOCATION srcCopy = {}; + dstCopy.pResource = m_texture; + dstCopy.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + dstCopy.SubresourceIndex = 0u; + srcCopy.pResource = m_textureUploadHeap; + srcCopy.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + srcCopy.PlacedFootprint = footprint; + commandList->CopyTextureRegion(&dstCopy, 0, 0, 0, &srcCopy, nullptr); + + D3D12_RESOURCE_BARRIER barrier[1] = {}; + auto textureBarrier = [&barrier](UINT idx, ID3D12Resource* texture) + { + barrier[idx].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier[idx].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + barrier[idx].Transition.pResource = texture; + barrier[idx].Transition.Subresource = 0u; + barrier[idx].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; + barrier[idx].Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; + }; + textureBarrier(0, m_texture); + commandList->ResourceBarrier(1, barrier); + + // create an SRV heap and descriptor for the texture + D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {}; + srvHeapDesc.NumDescriptors = 1; + srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; + srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; + if (m_desc.device->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&m_srvUavHeapCPU))) + { + return; + } + + D3D12_CPU_DESCRIPTOR_HANDLE srvUavHandle = m_srvUavHeapCPU->GetCPUDescriptorHandleForHeapStart(); + + D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; + srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + srvDesc.Format = texDesc.Format; + srvDesc.Texture2D.MipLevels = 1; + srvDesc.Texture2D.MostDetailedMip = 0; + srvDesc.Texture2D.ResourceMinLODClamp = 0.f; + + m_desc.device->CreateShaderResourceView(m_texture, &srvDesc, srvUavHandle); + } + +} + +void imguiGraphFontTextureReleaseD3D12() +{ + COMRelease(m_texture); + COMRelease(m_textureUploadHeap); + COMRelease(m_srvUavHeapCPU); + COMRelease(m_srvUavHeapGPU); +}
\ No newline at end of file diff --git a/demo/d3d12/imguiGraphD3D12.h b/demo/d3d12/imguiGraphD3D12.h new file mode 100644 index 0000000..fc2e67e --- /dev/null +++ b/demo/d3d12/imguiGraphD3D12.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2014-2017, 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. + */ + +#ifndef IMGUI_GRAPH_D3D12_H +#define IMGUI_GRAPH_D3D12_H + +#include <stdint.h> + +#include "../d3d/imguiGraph.h" + +struct ImguiDescriptorReserveHandleD3D12 +{ + ID3D12DescriptorHeap* heap; + UINT descriptorSize; + D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle; + D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle; +}; + +struct ImguiDynamicDescriptorHeapD3D12 +{ + void* userdata; + ImguiDescriptorReserveHandleD3D12(*reserveDescriptors)(void* userdata, UINT numDescriptors, UINT64 lastFenceCompleted, UINT64 nextFenceValue); +}; + +struct ImguiGraphDescD3D12 +{ + ID3D12Device* device = nullptr; + ID3D12GraphicsCommandList* commandList = nullptr; + UINT64 lastFenceCompleted; + UINT64 nextFenceValue; + int winW; + int winH; + int numMSAASamples = 1; + + uint32_t maxVertices = 64 * 4096u; + + ImguiDynamicDescriptorHeapD3D12 dynamicHeapCbvSrvUav = {}; + + ImguiGraphDescD3D12() {} +}; + +inline const ImguiGraphDescD3D12* cast_to_imguiGraphDescD3D12(const ImguiGraphDesc* desc) +{ + return (const ImguiGraphDescD3D12*)(desc); +} + +inline ImguiGraphDesc* cast_from_imguiGraphDescD3D12(ImguiGraphDescD3D12* desc) +{ + return (ImguiGraphDesc*)(desc); +} + +IMGUI_GRAPH_API void imguiGraphContextInitD3D12(const ImguiGraphDesc* desc); + +IMGUI_GRAPH_API void imguiGraphContextUpdateD3D12(const ImguiGraphDesc* desc); + +IMGUI_GRAPH_API void imguiGraphContextDestroyD3D12(); + +IMGUI_GRAPH_API void imguiGraphRecordBeginD3D12(); + +IMGUI_GRAPH_API void imguiGraphRecordEndD3D12(); + +IMGUI_GRAPH_API void imguiGraphVertex2fD3D12(float x, float y); + +IMGUI_GRAPH_API void imguiGraphVertex2fvD3D12(const float* v); + +IMGUI_GRAPH_API void imguiGraphTexCoord2fD3D12(float u, float v); + +IMGUI_GRAPH_API void imguiGraphColor4ubD3D12(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha); + +IMGUI_GRAPH_API void imguiGraphColor4ubvD3D12(const uint8_t* v); + +IMGUI_GRAPH_API void imguiGraphFontTextureEnableD3D12(); + +IMGUI_GRAPH_API void imguiGraphFontTextureDisableD3D12(); + +IMGUI_GRAPH_API void imguiGraphEnableScissorD3D12(int x, int y, int width, int height); + +IMGUI_GRAPH_API void imguiGraphDisableScissorD3D12(); + +IMGUI_GRAPH_API void imguiGraphFontTextureInitD3D12(unsigned char* data); + +IMGUI_GRAPH_API void imguiGraphFontTextureReleaseD3D12(); + +#endif
\ No newline at end of file diff --git a/demo/d3d12/imguiInteropD3D12.cpp b/demo/d3d12/imguiInteropD3D12.cpp new file mode 100644 index 0000000..23d7422 --- /dev/null +++ b/demo/d3d12/imguiInteropD3D12.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2014-2017, 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. + */ + + //direct3d headers +#define NOMINMAX +#include <d3d12.h> + +// include the Direct3D Library file +#pragma comment (lib, "d3d12.lib") + +#include "imguiGraphD3D12.h" + +#include "appD3D12Ctx.h" + +struct AppGraphCtx; + +namespace NvCo = nvidia::Common; + +inline void imguiInteropUpdateDesc(ImguiGraphDescD3D12& desc, AppGraphCtx* appctxIn) +{ + auto context = cast_to_AppGraphCtxD3D12(appctxIn); + + desc.device = context->m_device; + desc.commandList = context->m_commandList; + + desc.lastFenceCompleted = 0; + desc.nextFenceValue = 1; + + desc.winW = context->m_winW; + desc.winH = context->m_winH; + desc.numMSAASamples = context->m_numMsaaSamples; + desc.dynamicHeapCbvSrvUav.userdata = context; + desc.dynamicHeapCbvSrvUav.reserveDescriptors = nullptr; +} + +IMGUI_GRAPH_API bool imguiInteropGraphInitD3D12(imguiGraphInit_t func, const char* fontpath, AppGraphCtx* appctx); + +IMGUI_GRAPH_API void imguiInteropGraphUpdateD3D12(imguiGraphUpdate_t func, AppGraphCtx* appctx); + +bool imguiInteropGraphInitD3D12(imguiGraphInit_t func, const char* fontpath, AppGraphCtx* appctx) +{ + ImguiGraphDescD3D12 desc; + imguiInteropUpdateDesc(desc, appctx); + + return func(fontpath, cast_from_imguiGraphDescD3D12(&desc)); +} + +void imguiInteropGraphUpdateD3D12(imguiGraphUpdate_t func, AppGraphCtx* appctx) +{ + ImguiGraphDescD3D12 desc; + imguiInteropUpdateDesc(desc, appctx); + + return func(cast_from_imguiGraphDescD3D12(&desc)); +}
\ No newline at end of file diff --git a/demo/d3d12/lineRenderPipelineD3D12.cpp b/demo/d3d12/lineRenderPipelineD3D12.cpp new file mode 100644 index 0000000..e6d75a1 --- /dev/null +++ b/demo/d3d12/lineRenderPipelineD3D12.cpp @@ -0,0 +1,140 @@ +#define NOMINMAX + +#include <NvCoDx12HelperUtil.h> +#include <external/D3D12/include/d3dx12.h> + +#include "pipelineUtilD3D12.h" +#include "bufferD3D12.h" +#include "meshRendererD3D12.h" +#include "../d3d/shaderCommonD3D.h" + +// this +#include "lineRenderPipelineD3D12.h" + +// Shaders +#include "../d3d/shaders/debugLineVS.hlsl.h" +#include "../d3d/shaders/debugLinePS.hlsl.h" + +namespace FlexSample { + +static const D3D12_INPUT_ELEMENT_DESC InputElementDescs[] = +{ + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, sizeof(Vec3), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, +}; + +LineRenderPipelineD3D12::LineRenderPipelineD3D12(): + Parent(PRIMITIVE_LINE) +{ +} + +int LineRenderPipelineD3D12::initialize(const RenderStateD3D12& state, const std::wstring& shadersPath, NvCo::Dx12RenderTarget* shadowMap) +{ + using namespace NvCo; + ID3D12Device* device = state.m_device; + + // create the pipeline state object + { + D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; + PipelineUtilD3D::initSolidBlendDesc(psoDesc.BlendState); + PipelineUtilD3D::initRasterizerDesc(FRONT_WINDING_CLOCKWISE, psoDesc.RasterizerState); + + { + PipelineUtilD3D::initTargetFormat(nullptr, state.m_renderContext, psoDesc); + + psoDesc.InputLayout.NumElements = _countof(InputElementDescs); + psoDesc.InputLayout.pInputElementDescs = InputElementDescs; + psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; + } + + //psoDesc.RasterizerState.MultisampleEnable = TRUE; + psoDesc.RasterizerState.FrontCounterClockwise = TRUE; + + // create the root signature + ComPtr<ID3D12RootSignature> signiture; + { + CD3DX12_DESCRIPTOR_RANGE ranges[2]; + CD3DX12_ROOT_PARAMETER params[3]; + + UINT rootIndex = 0; + { + D3D12_ROOT_PARAMETER& param = params[rootIndex++]; + param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; + param.Descriptor.ShaderRegister = 0u; + param.Descriptor.RegisterSpace = 0u; + param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + } + + D3D12_ROOT_SIGNATURE_DESC desc; + desc.NumParameters = rootIndex; + desc.pParameters = params; + desc.NumStaticSamplers = 0u; + desc.pStaticSamplers = nullptr; + desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; + + ComPtr<ID3DBlob> sigBlob; + NV_RETURN_ON_FAIL(Dx12HelperUtil::serializeRootSigniture(desc, D3D_ROOT_SIGNATURE_VERSION_1, sigBlob)); + NV_RETURN_ON_FAIL(device->CreateRootSignature(0u, sigBlob->GetBufferPointer(), sigBlob->GetBufferSize(), IID_PPV_ARGS(&signiture))); + } + + psoDesc.VS = Dx12Blob(g_debugLineVS); + psoDesc.PS = Dx12Blob(g_debugLinePS); + psoDesc.pRootSignature = signiture.Get(); + + { + PipelineStateD3D12& pipeState = m_states[PIPELINE_STATE_NORMAL]; + pipeState.m_rootSignature = signiture.Get(); + NV_RETURN_ON_FAIL(device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&pipeState.m_pipelineState))); + } + { + // Setup for shadow + PipelineUtilD3D::initTargetFormat(shadowMap, nullptr, psoDesc); + + PipelineStateD3D12& pipeState = m_states[PIPELINE_STATE_SHADOW]; + pipeState.m_rootSignature = signiture.Get(); + NV_RETURN_ON_FAIL(device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&pipeState.m_pipelineState))); + } + } + + return NV_OK; +} + +int LineRenderPipelineD3D12::bind(const void* paramsIn, const void* platformState) +{ + const RenderStateD3D12& state = *(RenderStateD3D12*)platformState; + LineDrawParams& params = *(LineDrawParams*)paramsIn; + + // Set up constant buffer + NvCo::Dx12CircularResourceHeap::Cursor cursor = state.m_constantHeap->newConstantBuffer(params); + if (!cursor.isValid()) + { + return NV_FAIL; + } + + PipelineStateD3D12& pipeState = (params.m_drawStage == LINE_DRAW_NORMAL) ? m_states[PIPELINE_STATE_NORMAL] : m_states[PIPELINE_STATE_SHADOW]; + if (!pipeState.isValid()) + { + return NV_FAIL; + } + + ID3D12GraphicsCommandList* commandList = state.m_commandList; + commandList->SetGraphicsRootSignature(pipeState.m_rootSignature.Get()); + commandList->SetPipelineState(pipeState.m_pipelineState.Get()); + + D3D12_GPU_VIRTUAL_ADDRESS cbvHandle = state.m_constantHeap->getGpuHandle(cursor); + commandList->SetGraphicsRootConstantBufferView(0, cbvHandle); + + { + ID3D12DescriptorHeap* heaps[] = { state.m_srvCbvUavDescriptorHeap->getHeap() }; + commandList->SetDescriptorHeaps(_countof(heaps), heaps); + } + + return NV_OK; +} + +int LineRenderPipelineD3D12::draw(const RenderAllocation& allocIn, size_t sizeOfAlloc, const void* platformState) +{ + return MeshRendererD3D12::defaultDraw(allocIn, sizeOfAlloc, platformState); +} + +} // namespace FlexSample
\ No newline at end of file diff --git a/demo/d3d12/lineRenderPipelineD3D12.h b/demo/d3d12/lineRenderPipelineD3D12.h new file mode 100644 index 0000000..ce3db58 --- /dev/null +++ b/demo/d3d12/lineRenderPipelineD3D12.h @@ -0,0 +1,65 @@ +/* +* Copyright (c) 2008-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. +*/ + +#ifndef LINE_RENDER_PIPELINE_D3D12_H +#define LINE_RENDER_PIPELINE_D3D12_H + +#include <DirectXMath.h> +#include "renderStateD3D12.h" +#include "meshRenderer.h" + +#include <NvCoDx12RenderTarget.h> + +#include <string> + +namespace FlexSample { +using namespace nvidia; + +enum LineDrawStage +{ + LINE_DRAW_NORMAL, + LINE_DRAW_SHADOW, +}; + +struct LineDrawParams +{ + Hlsl::float4x4 m_modelWorldProjection; /// Transforms point from world-space to clip space + LineDrawStage m_drawStage; +}; + +struct LineRenderPipelineD3D12: public RenderPipeline +{ + //NV_CO_DECLARE_POLYMORPHIC_CLASS(LineRenderPipelineD3D12, RenderPipeline); +public: + typedef RenderPipeline Parent; + + enum PipelineStateType + { + PIPELINE_STATE_NORMAL, + PIPELINE_STATE_SHADOW, + PIPELINE_STATE_COUNT_OF, + }; + + LineRenderPipelineD3D12(); + + /// Initialize + int initialize(const RenderStateD3D12& state, const std::wstring& shadersDir, NvCo::Dx12RenderTarget* shadowMap); + /// Do the binding + virtual int bind(const void* paramsIn, const void* platformState) override; + virtual int draw(const RenderAllocation& alloc, size_t sizeOfAlloc, const void* platformState) override; + + protected: + + PipelineStateD3D12 m_states[PIPELINE_STATE_COUNT_OF]; +}; + +} // namespace FlexSample + +#endif
\ No newline at end of file diff --git a/demo/d3d12/meshRenderPipelineD3D12.cpp b/demo/d3d12/meshRenderPipelineD3D12.cpp new file mode 100644 index 0000000..167a032 --- /dev/null +++ b/demo/d3d12/meshRenderPipelineD3D12.cpp @@ -0,0 +1,284 @@ +#define NOMINMAX + +#include <NvCoDx12HelperUtil.h> +#include <external/D3D12/include/d3dx12.h> + +#include "pipelineUtilD3D12.h" +#include "meshRenderer.h" +#include "bufferD3D12.h" +#include "meshRendererD3D12.h" +#include "../d3d/shaderCommonD3D.h" + +// this +#include "meshRenderPipelineD3D12.h" + +// Shaders +#include "../d3d/shaders/meshVS.hlsl.h" +#include "../d3d/shaders/meshPS.hlsl.h" +#include "../d3d/shaders/meshShadowPS.hlsl.h" + +namespace FlexSample { + +// Make async compute benchmark shader have a unique name +namespace AsyncComputeBench +{ +#include "../d3d/shaders/meshAsyncComputeBenchPS.hlsl.h" +} + +MeshRenderPipelineD3D12::MeshRenderPipelineD3D12(): + Parent(PRIMITIVE_TRIANGLE), + m_shadowMapLinearSamplerIndex(-1) +{ +} + +/* static */MeshRenderPipelineD3D12::PipelineStateType MeshRenderPipelineD3D12::getPipelineStateType(MeshDrawStage stage, MeshRenderMode mode, MeshCullMode cull) +{ + switch (stage) + { + case MESH_DRAW_NULL: + case MESH_DRAW_REFLECTION: + case MESH_DRAW_LIGHT: + { + if (mode == MESH_RENDER_WIREFRAME) + { + return PIPELINE_STATE_LIGHT_WIREFRAME; + } + + switch (cull) + { + case MESH_CULL_BACK: return PIPELINE_STATE_LIGHT_SOLID_CULL_BACK; + case MESH_CULL_FRONT: return PIPELINE_STATE_LIGHT_SOLID_CULL_FRONT; + default: + case MESH_CULL_NONE: return PIPELINE_STATE_LIGHT_SOLID_CULL_NONE; + } + } + case MESH_DRAW_SHADOW: + { + switch (cull) + { + case MESH_CULL_BACK: return PIPELINE_STATE_SHADOW_CULL_BACK; + default: + case MESH_CULL_NONE: return PIPELINE_STATE_SHADOW_CULL_NONE; + } + } + } + + printf("Unhandled option!"); + return PIPELINE_STATE_LIGHT_SOLID_CULL_BACK; +} + +static D3D12_FILL_MODE _getFillMode(MeshRenderPipelineD3D12::PipelineStateType type) +{ + switch (type) + { + default: return D3D12_FILL_MODE_SOLID; + case MeshRenderPipelineD3D12::PIPELINE_STATE_LIGHT_WIREFRAME: return D3D12_FILL_MODE_WIREFRAME; + } +} + +static D3D12_CULL_MODE _getCullMode(MeshRenderPipelineD3D12::PipelineStateType type) +{ + switch (type) + { + case MeshRenderPipelineD3D12::PIPELINE_STATE_COUNT_OF: break; + + case MeshRenderPipelineD3D12::PIPELINE_STATE_SHADOW_CULL_BACK: return D3D12_CULL_MODE_BACK; + + case MeshRenderPipelineD3D12::PIPELINE_STATE_LIGHT_SOLID_CULL_FRONT: return D3D12_CULL_MODE_FRONT; + case MeshRenderPipelineD3D12::PIPELINE_STATE_LIGHT_SOLID_CULL_BACK: return D3D12_CULL_MODE_BACK; + + case MeshRenderPipelineD3D12::PIPELINE_STATE_SHADOW_CULL_NONE: + case MeshRenderPipelineD3D12::PIPELINE_STATE_LIGHT_WIREFRAME: + case MeshRenderPipelineD3D12::PIPELINE_STATE_LIGHT_SOLID_CULL_NONE: return D3D12_CULL_MODE_NONE; + } + + printf("Unhandled option!"); + return D3D12_CULL_MODE_NONE; +} + +static void _initRasterizerDesc(MeshRenderPipelineD3D12::PipelineStateType type, FrontWindingType winding, D3D12_RASTERIZER_DESC& desc) +{ + PipelineUtilD3D::initRasterizerDesc(winding, desc); + + desc.FillMode = _getFillMode(type); + desc.CullMode = _getCullMode(type); +} + +static void _initPipelineStateDesc(MeshRenderPipelineD3D12::PipelineStateType type, NvCo::Dx12RenderTarget* shadowMap, AppGraphCtxD3D12* renderContext, D3D12_GRAPHICS_PIPELINE_STATE_DESC& psoDesc) +{ + PipelineUtilD3D::initTargetFormat((shadowMap && MeshRenderPipelineD3D12::isShadow(type)) ? shadowMap : nullptr, renderContext, psoDesc); + + psoDesc.InputLayout.NumElements = _countof(MeshRendererD3D12::MeshInputElementDescs); + psoDesc.InputLayout.pInputElementDescs = MeshRendererD3D12::MeshInputElementDescs; + psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; +} + +int MeshRenderPipelineD3D12::initialize(const RenderStateD3D12& state, const std::wstring& shadersPath, FrontWindingType winding, int shadowMapLinearSamplerIndex, NvCo::Dx12RenderTarget* shadowMap, bool asyncComputeBenchmark) +{ + using namespace NvCo; + ID3D12Device* device = state.m_device; + + m_shadowMapLinearSamplerIndex = shadowMapLinearSamplerIndex; + + // create the pipeline state object + { + D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; + PipelineUtilD3D::initSolidBlendDesc(psoDesc.BlendState); + + // create the root signature + ComPtr<ID3D12RootSignature> signiture; + { + CD3DX12_DESCRIPTOR_RANGE ranges[2]; + CD3DX12_ROOT_PARAMETER params[3]; + + UINT rootIndex = 0; + { + D3D12_ROOT_PARAMETER& param = params[rootIndex++]; + param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; + param.Descriptor.ShaderRegister = 0u; + param.Descriptor.RegisterSpace = 0u; + param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + } + + const int numSrvs = 1; + if (numSrvs > 0) + { + ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, numSrvs, 0); + params[rootIndex++].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_PIXEL); + } + const int numSamplers = 1; + if (numSamplers > 0) + { + ranges[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, numSamplers, 0); + params[rootIndex++].InitAsDescriptorTable(1, &ranges[1], D3D12_SHADER_VISIBILITY_PIXEL); + } + + D3D12_ROOT_SIGNATURE_DESC desc; + desc.NumParameters = rootIndex; + desc.pParameters = params; + desc.NumStaticSamplers = 0; + desc.pStaticSamplers = nullptr; + desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; + + ComPtr<ID3DBlob> sigBlob; + NV_RETURN_ON_FAIL(Dx12HelperUtil::serializeRootSigniture(desc, D3D_ROOT_SIGNATURE_VERSION_1, sigBlob)); + NV_RETURN_ON_FAIL(device->CreateRootSignature(0u, sigBlob->GetBufferPointer(), sigBlob->GetBufferSize(), IID_PPV_ARGS(&signiture))); + } + + { + psoDesc.VS = Dx12Blob(g_meshVS); + psoDesc.PS = asyncComputeBenchmark ? Dx12Blob(AsyncComputeBench::g_meshPS) : Dx12Blob(g_meshPS);; + + NV_RETURN_ON_FAIL(_initPipelineState(state, winding, shadowMap, PIPELINE_STATE_LIGHT_SOLID_CULL_FRONT, signiture.Get(), psoDesc)); + NV_RETURN_ON_FAIL(_initPipelineState(state, winding, shadowMap, PIPELINE_STATE_LIGHT_SOLID_CULL_BACK, signiture.Get(), psoDesc)); + NV_RETURN_ON_FAIL(_initPipelineState(state, winding, shadowMap, PIPELINE_STATE_LIGHT_SOLID_CULL_NONE, signiture.Get(), psoDesc)); + NV_RETURN_ON_FAIL(_initPipelineState(state, winding, shadowMap, PIPELINE_STATE_LIGHT_WIREFRAME, signiture.Get(), psoDesc)); + } + + // Shadow rendering + + { + D3D12_ROOT_PARAMETER params[1]; + params[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; + params[0].Descriptor.ShaderRegister = 0u; + params[0].Descriptor.RegisterSpace = 0u; + params[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + + D3D12_ROOT_SIGNATURE_DESC desc; + desc.NumParameters = 1; + desc.pParameters = params; + desc.NumStaticSamplers = 0; + desc.pStaticSamplers = nullptr; + desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; + + ComPtr<ID3DBlob> sigBlob; + NV_RETURN_ON_FAIL(Dx12HelperUtil::serializeRootSigniture(desc, D3D_ROOT_SIGNATURE_VERSION_1, sigBlob)); + NV_RETURN_ON_FAIL(device->CreateRootSignature(0u, sigBlob->GetBufferPointer(), sigBlob->GetBufferSize(), IID_PPV_ARGS(&signiture))); + } + + { + psoDesc.VS = Dx12Blob(g_meshVS); + psoDesc.PS = Dx12Blob(g_meshPS_Shadow); + + NV_RETURN_ON_FAIL(_initPipelineState(state, winding, shadowMap, PIPELINE_STATE_SHADOW_CULL_BACK, signiture.Get(), psoDesc)); + NV_RETURN_ON_FAIL(_initPipelineState(state, winding, shadowMap, PIPELINE_STATE_SHADOW_CULL_NONE, signiture.Get(), psoDesc)); + } + } + + return NV_OK; +} + +int MeshRenderPipelineD3D12::_initPipelineState(const RenderStateD3D12& state, FrontWindingType winding, NvCo::Dx12RenderTarget* shadowMap, PipelineStateType pipeType, ID3D12RootSignature* signiture, D3D12_GRAPHICS_PIPELINE_STATE_DESC& psoDesc) +{ + ID3D12Device* device = state.m_device; + + _initRasterizerDesc(pipeType, winding, psoDesc.RasterizerState); + _initPipelineStateDesc(pipeType, shadowMap, state.m_renderContext, psoDesc); + + psoDesc.pRootSignature = signiture; + + PipelineStateD3D12& pipeState = m_states[pipeType]; + pipeState.m_rootSignature = signiture; + + NV_RETURN_ON_FAIL(device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&pipeState.m_pipelineState))); + return NV_OK; +} + +int MeshRenderPipelineD3D12::bind(const void* paramsIn, const void* platformState) +{ + const RenderStateD3D12& state = *(RenderStateD3D12*)platformState; + const MeshDrawParamsD3D& params = *(MeshDrawParamsD3D*)paramsIn; + + NvCo::Dx12CircularResourceHeap::Cursor cursor; + { + Hlsl::MeshShaderConst constBuf; + RenderParamsUtilD3D::calcMeshConstantBuffer(params, constBuf); + cursor = state.m_constantHeap->newConstantBuffer(constBuf); + if (!cursor.isValid()) + { + return NV_FAIL; + } + } + + const PipelineStateType pipeType = getPipelineStateType(params.renderStage, params.renderMode, params.cullMode); + PipelineStateD3D12& pipeState = m_states[pipeType]; + if (!pipeState.isValid()) + { + return NV_FAIL; + } + + ID3D12GraphicsCommandList* commandList = state.m_commandList; + + commandList->SetGraphicsRootSignature(pipeState.m_rootSignature.Get()); + commandList->SetPipelineState(pipeState.m_pipelineState.Get()); + + D3D12_GPU_VIRTUAL_ADDRESS cbvHandle = state.m_constantHeap->getGpuHandle(cursor); + commandList->SetGraphicsRootConstantBufferView(0, cbvHandle); + + if (isShadow(pipeType)) + { + ID3D12DescriptorHeap* heaps[] = { nullptr }; + commandList->SetDescriptorHeaps(0, heaps); + } + else + { + NvCo::Dx12RenderTarget* shadowMap = (NvCo::Dx12RenderTarget*)params.shadowMap; + + ID3D12DescriptorHeap* heaps[] = { state.m_srvCbvUavDescriptorHeap->getHeap(), state.m_samplerDescriptorHeap->getHeap() }; + commandList->SetDescriptorHeaps(_countof(heaps), heaps); + + // Bind the srvs + commandList->SetGraphicsRootDescriptorTable(1, state.m_srvCbvUavDescriptorHeap->getGpuHandle(shadowMap->getSrvHeapIndex(shadowMap->getPrimaryBufferType()))); + // Bind the samplers + commandList->SetGraphicsRootDescriptorTable(2, state.m_samplerDescriptorHeap->getGpuHandle(m_shadowMapLinearSamplerIndex)); + } + + return NV_OK; +} + +int MeshRenderPipelineD3D12::draw(const RenderAllocation& allocIn, size_t sizeOfAlloc, const void* platformState) +{ + return MeshRendererD3D12::defaultDraw(allocIn, sizeOfAlloc, platformState); +} + +} // namespace FlexSample
\ No newline at end of file diff --git a/demo/d3d12/meshRenderPipelineD3D12.h b/demo/d3d12/meshRenderPipelineD3D12.h new file mode 100644 index 0000000..be2511f --- /dev/null +++ b/demo/d3d12/meshRenderPipelineD3D12.h @@ -0,0 +1,66 @@ +/* +* Copyright (c) 2008-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. +*/ + +#ifndef MESH_RENDER_PIPELINE_D3D12_H +#define MESH_RENDER_PIPELINE_D3D12_H + +#include <DirectXMath.h> +#include "renderStateD3D12.h" +#include "../d3d/shaderCommonD3D.h" +#include "meshRenderer.h" +#include "../d3d/renderParamsD3D.h" + +#include <NvCoDx12RenderTarget.h> + +namespace FlexSample { +using namespace nvidia; + +struct MeshRenderPipelineD3D12: public RenderPipeline +{ + //NV_CO_DECLARE_POLYMORPHIC_CLASS(MeshRenderPipelineD3D12, RenderPipeline); +public: + typedef RenderPipeline Parent; + + enum PipelineStateType + { + PIPELINE_STATE_SHADOW_CULL_BACK, // Is cull back + PIPELINE_STATE_SHADOW_CULL_NONE, + PIPELINE_STATE_LIGHT_WIREFRAME, // No culling + PIPELINE_STATE_LIGHT_SOLID_CULL_FRONT, + PIPELINE_STATE_LIGHT_SOLID_CULL_BACK, + PIPELINE_STATE_LIGHT_SOLID_CULL_NONE, + PIPELINE_STATE_COUNT_OF, + }; + + MeshRenderPipelineD3D12(); + + /// Initialize + int initialize(const RenderStateD3D12& state, const std::wstring& shadersDir, FrontWindingType winding, int shadowMapLinearSamplerIndex, NvCo::Dx12RenderTarget* shadowMap, bool asyncComputeBenchmark); + /// Do the binding + virtual int bind(const void* paramsIn, const void* platformState) override; + virtual int draw(const RenderAllocation& alloc, size_t sizeOfAlloc, const void* platformState) override; + + /// Convert into a single pipeline state type + static PipelineStateType getPipelineStateType(MeshDrawStage stage, MeshRenderMode mode, MeshCullMode cull); + /// true if it's a shadowing type + static bool isShadow(PipelineStateType type) { return type == PIPELINE_STATE_SHADOW_CULL_BACK || type == PIPELINE_STATE_SHADOW_CULL_NONE; } + + protected: + + int _initPipelineState(const RenderStateD3D12& state, FrontWindingType winding, NvCo::Dx12RenderTarget* shadowMap, PipelineStateType pipeType, ID3D12RootSignature* signiture, D3D12_GRAPHICS_PIPELINE_STATE_DESC& psoDesc); + + int m_shadowMapLinearSamplerIndex; //< The index to the linear sampler in the m_samplerHeap + + PipelineStateD3D12 m_states[PIPELINE_STATE_COUNT_OF]; +}; + +} // namespace FlexSample + +#endif
\ No newline at end of file diff --git a/demo/d3d12/meshRenderer.cpp b/demo/d3d12/meshRenderer.cpp new file mode 100644 index 0000000..5b8a41e --- /dev/null +++ b/demo/d3d12/meshRenderer.cpp @@ -0,0 +1,15 @@ +/* +* Copyright (c) 2008-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 "meshRenderer.h" + +namespace FlexSample { + +} // namespace FlexSample
\ No newline at end of file diff --git a/demo/d3d12/meshRenderer.h b/demo/d3d12/meshRenderer.h new file mode 100644 index 0000000..5acc701 --- /dev/null +++ b/demo/d3d12/meshRenderer.h @@ -0,0 +1,194 @@ + +#ifndef MESH_RENDERER_H +#define MESH_RENDERER_H + +#include "core/maths.h" + +namespace FlexSample { + +enum FrontWindingType +{ + FRONT_WINDING_CLOCKWISE, + FRONT_WINDING_COUNTER_CLOCKWISE, +}; + +struct RenderAllocation; + +enum PrimitiveType +{ + PRIMITIVE_UNKNOWN, + PRIMITIVE_POINT, + PRIMITIVE_LINE, + PRIMITIVE_TRIANGLE, +}; + +/* Abstraction for how something is rendered. A pipeline indicates what kind of rendering it can be used with via the usage type */ +struct RenderPipeline +{ + //NV_CO_DECLARE_POLYMORPHIC_CLASS_BASE(RenderPipeline); +public: + /// Bind with platform specific state + virtual int bind(const void* paramsIn, const void* platformState) = 0; + virtual int draw(const RenderAllocation& pointAlloc, size_t sizeOfAlloc, const void* platformState) = 0; + + /// Get the usage type + inline PrimitiveType getPrimitiveType() const { return m_primitiveType; } + + /// Ctor + RenderPipeline(PrimitiveType primitiveType): m_primitiveType(primitiveType) {} + + virtual ~RenderPipeline() {} + private: + PrimitiveType m_primitiveType; +}; + +struct MeshData +{ + void init() + { + positions = nullptr; + normals = nullptr; + texcoords = nullptr; + colors = nullptr; + indices = nullptr; + numFaces = 0; + numVertices = 0; + } + + const Vec3* positions; + const Vec3* normals; + const Vec2* texcoords; + const Vec4* colors; + const uint32_t* indices; + int numVertices; + int numFaces; +}; + +struct MeshData2 +{ + void init() + { + positions = nullptr; + normals = nullptr; + texcoords = nullptr; + colors = nullptr; + indices = nullptr; + numFaces = 0; + numVertices = 0; + } + + const Vec4* positions; + const Vec4* normals; + const Vec2* texcoords; + const Vec4* colors; + const uint32_t* indices; + ptrdiff_t numVertices; + ptrdiff_t numFaces; +}; + + +struct LineData +{ + struct Vertex + { + Vec3 position; + Vec4 color; + }; + void init() + { + vertices = nullptr; + indices = nullptr; + numLines = 0; + numVertices = 0; + } + const Vertex* vertices; ///< Must be set, and holds numPositions. If indices is nullptr, must hold at least numLines * 2 + const uint32_t* indices; ///< If not nullptr holds 2 * numLines + ptrdiff_t numVertices; ///< The total amount of positions + ptrdiff_t numLines; ///< The total number of lines +}; + +struct PointData +{ + void init() + { + positions = nullptr; + density = nullptr; + phase = nullptr; + numPoints = 0; + for (int i = 0; i < 3; i++) + { + anisotropy[i] = nullptr; + } + indices = nullptr; + numIndices = 0; + } + + const Vec4* positions; + const float* density; + const int* phase; + ptrdiff_t numPoints; //< The number of values in position, density and phase. It must be +1 the maximum particle indexed + + const Vec4* anisotropy[3]; // Holds anisotropy or can be nullptr if not used + + const uint32_t* indices; //< The indices to used particles + ptrdiff_t numIndices; +}; + +struct RenderMesh +{ + //NV_CO_DECLARE_POLYMORPHIC_CLASS_BASE(RenderMesh); +public: + virtual ~RenderMesh() {}; +}; + +struct RenderAllocation +{ + void init(PrimitiveType primType) + { + m_numPositions = -1; + m_numPrimitives = -1; + m_primitiveType = primType; + } + + PrimitiveType m_primitiveType; ///< The primitive type to draw + ptrdiff_t m_numPositions; ///< The total number of positions + ptrdiff_t m_numPrimitives; ///< The total number of primitives +}; + +struct MeshRenderer +{ + //NV_CO_DECLARE_POLYMORPHIC_CLASS_BASE(MeshRenderer); +public: + /// Draw a pre-created mesh + virtual int draw(RenderMesh* mesh, RenderPipeline* pipeline, const void* params) = 0; + + /// Do an immediate mode draw + virtual int drawImmediate(const MeshData& meshData, RenderPipeline* pipeline, const void* params) = 0; + /// Do an immediate mode draw + virtual int drawImmediate(const MeshData2& meshData, RenderPipeline* pipeline, const void* params) = 0; + /// Draw particles immediately + virtual int drawImmediate(const PointData& pointData, RenderPipeline* pipeline, const void* params) = 0; + /// Draw lines immediately + virtual int drawImmediate(const LineData& lineData, RenderPipeline* pipeline, const void* params) = 0; + + /// Render immediately using a previously transitory allocation + virtual int drawTransitory(RenderAllocation& allocation, size_t sizeOfAlloc, RenderPipeline* pipeline, const void* params) = 0; + + /// Allocate rendering data temporarily in gpu accessible memory. Render with drawTransitory. + /// A transitory allocations lifetime is dependent on rendering API, but typically stays in scope for a frame, so multiple + /// draw Transitory allocation can be done for a single allocation - but only in drawing a single frame. + /// NOTE! The PointAllocation/MeshAllocation structures must be the derived type for the API being used (say Dx12PointAllocation) + /// this is verified by the sizeOfAlloc being that size. + virtual int allocateTransitory(const PointData& pointData, RenderAllocation& allocation, size_t sizeOfAlloc) = 0; + virtual int allocateTransitory(const MeshData& meshData, RenderAllocation& allocation, size_t sizeOfAlloc) = 0; + virtual int allocateTransitory(const MeshData2& meshData, RenderAllocation& allocation, size_t sizeOfAlloc) = 0; + virtual int allocateTransitory(const LineData& lineData, RenderAllocation& allocation, size_t sizeOfAlloc) = 0; + + /// Create a render mesh from mesh data + virtual RenderMesh* createMesh(const MeshData& meshData) = 0; + virtual RenderMesh* createMesh(const MeshData2& meshData) = 0; +}; + +} // namespace FlexSample + +#endif
\ No newline at end of file diff --git a/demo/d3d12/meshRendererD3D12.cpp b/demo/d3d12/meshRendererD3D12.cpp new file mode 100644 index 0000000..3ea4012 --- /dev/null +++ b/demo/d3d12/meshRendererD3D12.cpp @@ -0,0 +1,419 @@ + +// this +#include "meshRendererD3D12.h" + +namespace FlexSample { + +/* static */ const D3D12_INPUT_ELEMENT_DESC MeshRendererD3D12::MeshInputElementDescs[4] = +{ + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, + { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 1, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 2, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 3, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 } +}; + +/* static */ const D3D12_INPUT_ELEMENT_DESC MeshRendererD3D12::PointInputElementDescs[3] = +{ + { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, + { "DENSITY", 0, DXGI_FORMAT_R32_FLOAT, 1, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, + { "PHASE", 0, DXGI_FORMAT_R32_SINT, 2, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, +}; + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Dx12RenderMesh !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ + +RenderMeshD3D12::RenderMeshD3D12() +{ + m_numVertices = 0; + m_numFaces = 0; +} + +int RenderMeshD3D12::initialize(const RenderStateD3D12& state, const MeshData& meshData) +{ + NV_RETURN_ON_FAIL(m_positionBuffer.init(state, sizeof(Vec3), meshData.numVertices, meshData.positions)); + NV_RETURN_ON_FAIL(m_normalBuffer.init(state, sizeof(Vec3), meshData.numVertices, meshData.normals)); + NV_RETURN_ON_FAIL(m_texcoordBuffer.init(state, sizeof(Vec2), meshData.numVertices, meshData.texcoords)); + NV_RETURN_ON_FAIL(m_colorBuffer.init(state, sizeof(Vec4), meshData.numVertices, meshData.colors)); + NV_RETURN_ON_FAIL(m_indexBuffer.init(state, sizeof(uint32_t), meshData.numFaces * 3, meshData.indices)); + + m_numVertices = meshData.numVertices; + m_numFaces = meshData.numFaces; + + _setBufferNames(); + return NV_OK; +} + +int RenderMeshD3D12::initialize(const RenderStateD3D12& state, const MeshData2& meshData) +{ + NV_RETURN_ON_FAIL(m_positionBuffer.init(state, sizeof(Vec4), sizeof(Vec3), meshData.numVertices, meshData.positions)); + NV_RETURN_ON_FAIL(m_normalBuffer.init(state, sizeof(Vec4), sizeof(Vec3), meshData.numVertices, meshData.normals)); + NV_RETURN_ON_FAIL(m_texcoordBuffer.init(state, sizeof(Vec2), meshData.numVertices, meshData.texcoords)); + NV_RETURN_ON_FAIL(m_colorBuffer.init(state, sizeof(Vec4), meshData.numVertices, meshData.colors)); + NV_RETURN_ON_FAIL(m_indexBuffer.init(state, sizeof(uint32_t), meshData.numFaces * 3, meshData.indices)); + + m_numVertices = meshData.numVertices; + m_numFaces = meshData.numFaces; + + _setBufferNames(); + return NV_OK; +} + +void RenderMeshD3D12::_setBufferNames() +{ + m_positionBuffer.setDebugName(L"positions"); + m_normalBuffer.setDebugName(L"normals"); + m_texcoordBuffer.setDebugName(L"texcoords"); + m_colorBuffer.setDebugName(L"colors"); + m_indexBuffer.setDebugName(L"indices"); +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Dx12MeshRenderer !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ + + +MeshRendererD3D12::MeshRendererD3D12() +{ +} + +int MeshRendererD3D12::initialize(const RenderStateD3D12& state) +{ + m_renderState = state; + return NV_OK; +} + +D3D12_VERTEX_BUFFER_VIEW MeshRendererD3D12::_newImmediateVertexBuffer(const void* data, int stride, ptrdiff_t numVertices) +{ + D3D12_VERTEX_BUFFER_VIEW view = {}; + if (data) + { + const size_t bufferSize = stride * numVertices; + NvCo::Dx12CircularResourceHeap::Cursor cursor = m_renderState.m_constantHeap->allocateVertexBuffer(bufferSize); + + memcpy(cursor.m_position, data, bufferSize); + + view.BufferLocation = m_renderState.m_constantHeap->getGpuHandle(cursor); + view.SizeInBytes = UINT(bufferSize); + view.StrideInBytes = stride; + } + return view; +} + +D3D12_VERTEX_BUFFER_VIEW MeshRendererD3D12::_newStridedImmediateVertexBuffer(const void* data, int srcStride, int dstStride, ptrdiff_t numElements) +{ + if (srcStride == dstStride) + { + return _newImmediateVertexBuffer(data, srcStride, numElements); + } + + D3D12_VERTEX_BUFFER_VIEW view = {}; + if (srcStride == 4 * 4 && dstStride == 4 * 3) + { + const size_t bufferSize = dstStride * numElements; + NvCo::Dx12CircularResourceHeap::Cursor cursor = m_renderState.m_constantHeap->allocateVertexBuffer(bufferSize); + + uint32_t* dst = (uint32_t*)cursor.m_position; + const uint32_t* src = (const uint32_t*)data; + + // Copy taking into account stride difference + for (ptrdiff_t i = 0; i < numElements; i++, dst += 3, src += 4) + { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + } + + view.BufferLocation = m_renderState.m_constantHeap->getGpuHandle(cursor); + view.SizeInBytes = UINT(bufferSize); + view.StrideInBytes = dstStride; + + return view; + } + + printf("Unhandled conversion"); + return view; +} + +D3D12_INDEX_BUFFER_VIEW MeshRendererD3D12::_newImmediateIndexBuffer(const void* data, int stride, ptrdiff_t numIndices) +{ + assert(stride == sizeof(uint32_t)); + D3D12_INDEX_BUFFER_VIEW view = {}; + + if (data) + { + const size_t bufferSize = stride * numIndices; + NvCo::Dx12CircularResourceHeap::Cursor cursor = m_renderState.m_constantHeap->allocateVertexBuffer(bufferSize); + + memcpy(cursor.m_position, data, bufferSize); + + view.BufferLocation = m_renderState.m_constantHeap->getGpuHandle(cursor); + view.SizeInBytes = UINT(bufferSize); + view.Format = DXGI_FORMAT_R32_UINT; + } + + return view; +} + +int MeshRendererD3D12::draw(RenderMesh* meshIn, RenderPipeline* pipeline, const void* params) +{ + RenderMeshD3D12* mesh = static_cast<RenderMeshD3D12*>(meshIn); + + // Set up the allocation block + MeshRenderAllocationD3D12 alloc; + alloc.init(PRIMITIVE_TRIANGLE); + + alloc.m_vertexBufferViews[0] = mesh->m_positionBuffer.m_vertexBufferView; + alloc.m_vertexBufferViews[1] = mesh->m_normalBuffer.m_vertexBufferView; + alloc.m_vertexBufferViews[2] = mesh->m_texcoordBuffer.m_vertexBufferView; + alloc.m_vertexBufferViews[3] = mesh->m_colorBuffer.m_vertexBufferView; + + alloc.m_indexBufferView = mesh->m_indexBuffer.m_indexBufferView; + alloc.m_numPrimitives = mesh->m_numFaces; + alloc.m_numPositions = mesh->m_numVertices; + + return drawTransitory(alloc, sizeof(MeshRenderAllocationD3D12), pipeline, params); +} + +int MeshRendererD3D12::drawImmediate(const MeshData& mesh, RenderPipeline* pipeline, const void* params) +{ + MeshRenderAllocationD3D12 alloc; + allocateTransitory(mesh, alloc, sizeof(alloc)); + return drawTransitory(alloc, sizeof(alloc), pipeline, params); +} + +int MeshRendererD3D12::drawImmediate(const MeshData2& mesh, RenderPipeline* pipeline, const void* params) +{ + MeshRenderAllocationD3D12 alloc; + allocateTransitory(mesh, alloc, sizeof(alloc)); + return drawTransitory(alloc, sizeof(alloc), pipeline, params); +} + +int MeshRendererD3D12::drawImmediate(const LineData& lineData, RenderPipeline* pipeline, const void* params) +{ + LineRenderAllocationD3D12 alloc; + allocateTransitory(lineData, alloc, sizeof(alloc)); + return drawTransitory(alloc, sizeof(alloc), pipeline, params); +} + +int MeshRendererD3D12::drawImmediate(const PointData& pointData, RenderPipeline* pipeline, const void* params) +{ + PointRenderAllocationD3D12 alloc; + allocateTransitory(pointData, alloc, sizeof(alloc)); + return drawTransitory(alloc, sizeof(alloc), pipeline, params); +} + +int MeshRendererD3D12::allocateTransitory(const PointData& pointData, RenderAllocation& allocIn, size_t sizeOfAlloc) +{ + typedef PointRenderAllocationD3D12 Alloc; + + assert(sizeof(Alloc) == sizeOfAlloc); + + Alloc& alloc = static_cast<Alloc&>(allocIn); + alloc.init(PRIMITIVE_POINT); + + alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_POSITION] = _newImmediateVertexBuffer(pointData.positions, sizeof(Vec4), pointData.numPoints); + alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_DENSITY] = _newImmediateVertexBuffer(pointData.density, sizeof(float), pointData.numPoints); + alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_PHASE] = _newImmediateVertexBuffer(pointData.phase, sizeof(int), pointData.numPoints); + + if (pointData.anisotropy[0]) + { + for (int i = 0; i < 3; i++) + { + alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_ANISOTROPY1 + i] = _newImmediateVertexBuffer(pointData.anisotropy[i], sizeof(Vec4), pointData.numPoints); + } + } + + alloc.m_indexBufferView = _newImmediateIndexBuffer(pointData.indices, sizeof(uint32_t), pointData.numIndices); + + alloc.m_numPrimitives = pointData.numIndices; + alloc.m_numPositions = pointData.numPoints; + return NV_OK; +} + +int MeshRendererD3D12::allocateTransitory(const MeshData2& mesh, RenderAllocation& allocIn, size_t sizeOfAlloc) +{ + typedef MeshRenderAllocationD3D12 Alloc; + assert(sizeof(Alloc) == sizeOfAlloc); + + Alloc& alloc = static_cast<Alloc&>(allocIn); + alloc.init(PRIMITIVE_TRIANGLE); + + const int numIndices = int(mesh.numFaces * 3); + alloc.m_indexBufferView = _newImmediateIndexBuffer(mesh.indices, sizeof(uint32_t), numIndices); + + alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_POSITION] = _newStridedImmediateVertexBuffer(mesh.positions, sizeof(Vec4), sizeof(Vec3), mesh.numVertices); + alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_NORMAL] = _newStridedImmediateVertexBuffer(mesh.normals, sizeof(Vec4), sizeof(Vec3), mesh.numVertices); + alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_TEX_COORDS] = _newImmediateVertexBuffer(mesh.texcoords, sizeof(Vec2), mesh.numVertices); + alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_COLOR] = _newImmediateVertexBuffer(mesh.colors, sizeof(Vec4), mesh.numVertices); + + alloc.m_numPrimitives = mesh.numFaces; + alloc.m_numPositions = mesh.numVertices; + return NV_OK; +} + +int MeshRendererD3D12::allocateTransitory(const LineData& lineData, RenderAllocation& allocIn, size_t sizeOfAlloc) +{ + typedef LineRenderAllocationD3D12 Alloc; + assert(sizeof(Alloc) == sizeOfAlloc); + + Alloc& alloc = static_cast<Alloc&>(allocIn); + alloc.init(PRIMITIVE_LINE); + + alloc.m_vertexBufferView = _newImmediateVertexBuffer(lineData.vertices, sizeof(LineData::Vertex), lineData.numVertices); + alloc.m_indexBufferView = _newImmediateIndexBuffer(lineData.indices, sizeof(uint32_t), lineData.numLines * 2); + + alloc.m_numPrimitives = lineData.numLines; + alloc.m_numPositions = lineData.numVertices; + return NV_OK; +} + +int MeshRendererD3D12::allocateTransitory(const MeshData& mesh, RenderAllocation& allocIn, size_t sizeOfAlloc) +{ + typedef MeshRenderAllocationD3D12 Alloc; + assert(sizeof(Alloc) == sizeOfAlloc); + + Alloc& alloc = static_cast<Alloc&>(allocIn); + + alloc.init(PRIMITIVE_TRIANGLE); + + const int numIndices = int(mesh.numFaces * 3); + alloc.m_indexBufferView = _newImmediateIndexBuffer(mesh.indices, sizeof(uint32_t), numIndices); + + alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_POSITION] = _newImmediateVertexBuffer(mesh.positions, sizeof(Vec3), mesh.numVertices); + alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_NORMAL] = _newImmediateVertexBuffer(mesh.normals, sizeof(Vec3), mesh.numVertices); + alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_TEX_COORDS] = _newImmediateVertexBuffer(mesh.texcoords, sizeof(Vec2), mesh.numVertices); + alloc.m_vertexBufferViews[Alloc::VERTEX_VIEW_COLOR] = _newImmediateVertexBuffer(mesh.colors, sizeof(Vec4), mesh.numVertices); + + alloc.m_numPrimitives = mesh.numFaces; + alloc.m_numPositions = mesh.numVertices; + + return NV_OK; +} + +int MeshRendererD3D12::drawTransitory(RenderAllocation& allocIn, size_t sizeOfAlloc, RenderPipeline* pipeline, const void* params) +{ + if (allocIn.m_primitiveType == PRIMITIVE_UNKNOWN) + { + return NV_OK; + } + if (allocIn.m_primitiveType != pipeline->getPrimitiveType()) + { + printf("Wrong pipeline primitive type"); + return NV_FAIL; + } + + NV_RETURN_ON_FAIL(pipeline->bind(params, &m_renderState)); + NV_RETURN_ON_FAIL(pipeline->draw(allocIn, sizeOfAlloc, &m_renderState)); + return NV_OK; +} + +RenderMesh* MeshRendererD3D12::createMesh(const MeshData& meshData) +{ + RenderMeshD3D12* mesh = new RenderMeshD3D12; + if (NV_FAILED(mesh->initialize(m_renderState, meshData))) + { + delete mesh; + return nullptr; + } + return mesh; +} + +RenderMesh* MeshRendererD3D12::createMesh(const MeshData2& meshData) +{ + RenderMeshD3D12* mesh = new RenderMeshD3D12; + if (NV_FAILED(mesh->initialize(m_renderState, meshData))) + { + delete mesh; + return nullptr; + } + return mesh; +} + + +/* static */int MeshRendererD3D12::defaultDraw(const RenderAllocation& allocIn, size_t sizeOfAlloc, const void* platformState) +{ + const RenderStateD3D12& state = *(RenderStateD3D12*)platformState; + ID3D12GraphicsCommandList* commandList = state.m_commandList; + + switch (allocIn.m_primitiveType) + { + case PRIMITIVE_POINT: + { + typedef PointRenderAllocationD3D12 Alloc; + const RenderStateD3D12& state = *(RenderStateD3D12*)platformState; + + assert(sizeof(Alloc) == sizeOfAlloc); + const Alloc& alloc = static_cast<const Alloc&>(allocIn); + + assert(allocIn.m_numPrimitives >= 0); + + ID3D12GraphicsCommandList* commandList = state.m_commandList; + + commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_POINTLIST); + commandList->IASetVertexBuffers(0, Alloc::NUM_DEFAULT_VERTEX_VIEWS, alloc.m_vertexBufferViews); + commandList->IASetIndexBuffer(&alloc.m_indexBufferView); + + if (alloc.m_indexBufferView.SizeInBytes) + { + commandList->DrawIndexedInstanced((UINT)allocIn.m_numPrimitives, 1, 0, 0, 0); + } + else + { + commandList->DrawInstanced((UINT)allocIn.m_numPrimitives, 1, 0, 0); + } + break; + } + case PRIMITIVE_LINE: + { + typedef LineRenderAllocationD3D12 Alloc; + assert(sizeof(Alloc) == sizeOfAlloc); + const Alloc& alloc = static_cast<const Alloc&>(allocIn); + + assert(alloc.m_numPrimitives >= 0); + + const int numIndices = int(alloc.m_numPrimitives * 2); + + commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_LINELIST); + commandList->IASetVertexBuffers(0, 1, &alloc.m_vertexBufferView); + + if (alloc.m_indexBufferView.SizeInBytes) + { + commandList->IASetIndexBuffer(nullptr); + commandList->DrawIndexedInstanced((UINT)numIndices, 1, 0, 0, 0); + } + else + { + commandList->IASetIndexBuffer(&alloc.m_indexBufferView); + commandList->DrawInstanced((UINT)numIndices, 1, 0, 0); + } + break; + } + case PRIMITIVE_TRIANGLE: + { + typedef MeshRenderAllocationD3D12 Alloc; + assert(sizeof(Alloc) == sizeOfAlloc); + const Alloc& alloc = static_cast<const Alloc&>(allocIn); + + const int numIndices = int(alloc.m_numPrimitives * 3); + + commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + commandList->IASetVertexBuffers(0, _countof(alloc.m_vertexBufferViews), alloc.m_vertexBufferViews); + commandList->IASetIndexBuffer(&alloc.m_indexBufferView); + + if (alloc.m_indexBufferView.SizeInBytes) + { + commandList->DrawIndexedInstanced((UINT)numIndices, 1, 0, 0, 0); + } + else + { + commandList->DrawInstanced((UINT)numIndices, 1, 0, 0); + } + break; + } + default: + { + printf("Unhandled primitive type"); + } + } + + return NV_OK; +} + +} // namespace FlexSample
\ No newline at end of file diff --git a/demo/d3d12/meshRendererD3D12.h b/demo/d3d12/meshRendererD3D12.h new file mode 100644 index 0000000..1afb6b3 --- /dev/null +++ b/demo/d3d12/meshRendererD3D12.h @@ -0,0 +1,175 @@ +#ifndef MESH_RENDERER_D3D12_H +#define MESH_RENDERER_D3D12_H + +#include "bufferD3D12.h" + +#include "renderStateD3D12.h" +#include "meshRenderer.h" + +// Predeclare so all use the same +struct ShadowMap; + +namespace FlexSample { +using namespace nvidia; + +struct MeshRendererD3D12; +struct RenderMeshD3D12: public RenderMesh +{ + //NV_CO_DECLARE_POLYMORPHIC_CLASS(RenderMeshD3D12, RenderMesh); +public: + typedef RenderMesh Parent; + + friend struct MeshRendererD3D12; + + RenderMeshD3D12(); + int initialize(const RenderStateD3D12& state, const MeshData& meshData); + int initialize(const RenderStateD3D12& state, const MeshData2& meshData); + + protected: + void _setBufferNames(); + + VertexBufferD3D12 m_positionBuffer; + VertexBufferD3D12 m_normalBuffer; + VertexBufferD3D12 m_texcoordBuffer; + VertexBufferD3D12 m_colorBuffer; + IndexBufferD3D12 m_indexBuffer; + + ptrdiff_t m_numVertices; + ptrdiff_t m_numFaces; +}; + +struct PointRenderAllocationD3D12: public RenderAllocation +{ + typedef RenderAllocation Parent; + enum VertexViewType + { + // NOTE! Do not change order without fixing pipelines that use it! + VERTEX_VIEW_POSITION, + VERTEX_VIEW_DENSITY, + VERTEX_VIEW_PHASE, + + VERTEX_VIEW_ANISOTROPY1, + VERTEX_VIEW_ANISOTROPY2, + VERTEX_VIEW_ANISOTROPY3, + + VERTEX_VIEW_COUNT_OF, + }; + enum + { + // For typical point rendering we don't need anisotropy, so typically just bind the first 3 + NUM_DEFAULT_VERTEX_VIEWS = VERTEX_VIEW_PHASE + 1 + }; + + /// Initialize state + void init(PrimitiveType primitiveType) + { + Parent::init(primitiveType); + D3D12_VERTEX_BUFFER_VIEW nullView = {}; + for (int i = 0; i < _countof(m_vertexBufferViews); i++) + { + m_vertexBufferViews[i] = nullView; + } + D3D12_INDEX_BUFFER_VIEW nullIndexView = {}; + m_indexBufferView = nullIndexView; + } + + D3D12_VERTEX_BUFFER_VIEW m_vertexBufferViews[VERTEX_VIEW_COUNT_OF]; + D3D12_INDEX_BUFFER_VIEW m_indexBufferView; +}; + +struct MeshRenderAllocationD3D12:public RenderAllocation +{ + typedef RenderAllocation Parent; + + // Vertex buffer viewer are in the order to be set + enum VertexViewType + { + // NOTE! Do not change order without fixing pipelines that use it! + VERTEX_VIEW_POSITION, + VERTEX_VIEW_NORMAL, + VERTEX_VIEW_TEX_COORDS, + VERTEX_VIEW_COLOR, + + VERTEX_VIEW_COUNT_OF, + }; + + void init(PrimitiveType primType) + { + Parent::init(primType); + D3D12_VERTEX_BUFFER_VIEW nullView = {}; + for (int i = 0; i < _countof(m_vertexBufferViews); i++) + { + m_vertexBufferViews[i] = nullView; + } + D3D12_INDEX_BUFFER_VIEW nullIndexView = {}; + m_indexBufferView = nullIndexView; + } + + D3D12_VERTEX_BUFFER_VIEW m_vertexBufferViews[VERTEX_VIEW_COUNT_OF]; + D3D12_INDEX_BUFFER_VIEW m_indexBufferView; +}; + +struct LineRenderAllocationD3D12 :public RenderAllocation +{ + typedef RenderAllocation Parent; + + void init(PrimitiveType primType) + { + Parent::init(primType); + const D3D12_VERTEX_BUFFER_VIEW nullView = {}; + m_vertexBufferView = nullView; + const D3D12_INDEX_BUFFER_VIEW nullIndexView = {}; + m_indexBufferView = nullIndexView; + } + + D3D12_VERTEX_BUFFER_VIEW m_vertexBufferView; + D3D12_INDEX_BUFFER_VIEW m_indexBufferView; +}; + +struct MeshRendererD3D12: public MeshRenderer +{ + //NV_CO_DECLARE_POLYMORPHIC_CLASS(MeshRendererD3D12, MeshRenderer); +public: + typedef MeshRenderer Parent; + + /// MeshRenderer + virtual int draw(RenderMesh* mesh, RenderPipeline* pipeline, const void* params) override; + virtual int drawImmediate(const MeshData& mesh, RenderPipeline* pipeline, const void* params) override; + virtual int drawImmediate(const MeshData2& meshData, RenderPipeline* pipeline, const void* params) override; + virtual int drawImmediate(const PointData& pointData, RenderPipeline* pipeline, const void* params) override; + virtual int drawImmediate(const LineData& lineData, RenderPipeline* pipeline, const void* params) override; + + virtual RenderMesh* createMesh(const MeshData& meshData) override; + virtual RenderMesh* createMesh(const MeshData2& meshData) override; + + virtual int allocateTransitory(const PointData& pointData, RenderAllocation& allocation, size_t sizeOfAlloc) override; + virtual int allocateTransitory(const MeshData& meshData, RenderAllocation& allocIn, size_t sizeofAlloc) override; + virtual int allocateTransitory(const MeshData2& meshData, RenderAllocation& allocation, size_t sizeofAlloc) override; + virtual int allocateTransitory(const LineData& lineData, RenderAllocation& allocation, size_t sizeOfAlloc) override; + + virtual int drawTransitory(RenderAllocation& allocation, size_t sizeOfAlloc, RenderPipeline* pipeline, const void* params) override; + + int initialize(const RenderStateD3D12& state); + + MeshRendererD3D12(); + + /// Default drawing impls, can be used in pipelines + static int defaultDraw(const RenderAllocation& allocIn, size_t sizeOfAlloc, const void* platformState); + + /// The input desc layout used + static const D3D12_INPUT_ELEMENT_DESC MeshInputElementDescs[4]; + /// Layout for points + static const D3D12_INPUT_ELEMENT_DESC PointInputElementDescs[3]; + + protected: + + D3D12_VERTEX_BUFFER_VIEW _newImmediateVertexBuffer(const void* data, int stride, ptrdiff_t numVertices); + D3D12_VERTEX_BUFFER_VIEW _newStridedImmediateVertexBuffer(const void* data, int srcStride, int dstStride, ptrdiff_t numElements); + D3D12_INDEX_BUFFER_VIEW _newImmediateIndexBuffer(const void* data, int stride, ptrdiff_t numIndices); + + RenderStateD3D12 m_renderState; +}; + +} // namespace FlexSample + +#endif
\ No newline at end of file diff --git a/demo/d3d12/meshUtil.cpp b/demo/d3d12/meshUtil.cpp new file mode 100644 index 0000000..b83a3f4 --- /dev/null +++ b/demo/d3d12/meshUtil.cpp @@ -0,0 +1,33 @@ +/* +* Copyright (c) 2008-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 "meshUtil.h" + +namespace FlexSample { + +/* static */RenderMesh* MeshUtil::createRenderMesh(MeshRenderer* renderer, const Mesh& mesh) +{ + int numFaces = mesh.GetNumFaces(); + int numVertices = mesh.GetNumVertices(); + + MeshData data; + data.colors = (mesh.m_colours.size() > 0) ? (const Vec4*)&mesh.m_colours[0] : nullptr; + data.positions = (mesh.m_positions.size() > 0) ? (const Vec3*)&mesh.m_positions[0] : nullptr; + data.normals = (mesh.m_normals.size() > 0) ? (const Vec3*)&mesh.m_normals[0] : nullptr; + data.indices = (mesh.m_indices.size() > 0) ? (const uint32_t*)&mesh.m_indices[0] : nullptr; + data.texcoords = (mesh.m_texcoords[0].size() > 0) ? (const Vec2*)&mesh.m_texcoords[0] : nullptr; + + data.numFaces = numFaces; + data.numVertices = numVertices; + + return renderer->createMesh(data); +} + +} // namespace FlexSample
\ No newline at end of file diff --git a/demo/d3d12/meshUtil.h b/demo/d3d12/meshUtil.h new file mode 100644 index 0000000..a9070b7 --- /dev/null +++ b/demo/d3d12/meshUtil.h @@ -0,0 +1,26 @@ +#ifndef MESH_UTIL_H +#define MESH_UTIL_H + +// Needed for mesh.h +#pragma warning( disable : 4458 ) + +#include "meshRenderer.h" + +#include <core/mesh.h> + +typedef ::Vec4 FlexVec4; +typedef ::Vec3 FlexVec3; +typedef ::Vec2 FlexVec2; + +namespace FlexSample { +//using namespace nvidia; + +/* Tools/types to implify use of the flex 'Mesh' types */ +struct MeshUtil +{ + static RenderMesh* createRenderMesh(MeshRenderer* renderer, const Mesh& mesh); +}; + +} // namespace FlexSample + +#endif
\ No newline at end of file diff --git a/demo/d3d12/pipelineUtilD3D12.cpp b/demo/d3d12/pipelineUtilD3D12.cpp new file mode 100644 index 0000000..81e2581 --- /dev/null +++ b/demo/d3d12/pipelineUtilD3D12.cpp @@ -0,0 +1,78 @@ + +// this +#include "pipelineUtilD3D12.h" + +namespace NvCo = nvidia::Common; + +namespace FlexSample { + +/* static */void PipelineUtilD3D::initRasterizerDesc(FrontWindingType winding, D3D12_RASTERIZER_DESC& desc) +{ + desc.FillMode = D3D12_FILL_MODE_SOLID; + desc.CullMode = D3D12_CULL_MODE_NONE; + + desc.FrontCounterClockwise = (winding == FRONT_WINDING_COUNTER_CLOCKWISE); + + desc.DepthBias = D3D12_DEFAULT_DEPTH_BIAS; + desc.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP; + desc.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS; + desc.DepthClipEnable = TRUE; + desc.MultisampleEnable = FALSE; + desc.AntialiasedLineEnable = FALSE; + desc.ForcedSampleCount = 0; + desc.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF; +} + +/* static */void PipelineUtilD3D::initSolidBlendDesc(D3D12_BLEND_DESC& desc) +{ + desc.AlphaToCoverageEnable = FALSE; + desc.IndependentBlendEnable = FALSE; + { + const D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc = + { + FALSE,FALSE, + D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, + D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, + D3D12_LOGIC_OP_NOOP, + D3D12_COLOR_WRITE_ENABLE_ALL, + }; + for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i) + desc.RenderTarget[i] = defaultRenderTargetBlendDesc; + } +} + +/* static */void PipelineUtilD3D::initTargetFormat(NvCo::Dx12RenderTarget* renderTarget, AppGraphCtxD3D12* renderContext, D3D12_GRAPHICS_PIPELINE_STATE_DESC& psoDesc) +{ + psoDesc.DepthStencilState.DepthEnable = TRUE; + psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; + psoDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL; + psoDesc.DepthStencilState.StencilEnable = FALSE; + psoDesc.SampleMask = UINT_MAX; + + // Normally single render target + psoDesc.NumRenderTargets = 1; + + if (renderTarget) + { + psoDesc.RTVFormats[0] = renderTarget->getTargetFormat(NvCo::Dx12RenderTarget::BUFFER_TARGET); + psoDesc.DSVFormat = renderTarget->getTargetFormat(NvCo::Dx12RenderTarget::BUFFER_DEPTH_STENCIL); + psoDesc.NumRenderTargets = renderTarget->getNumRenderTargets(); + psoDesc.SampleDesc.Count = 1; + } + else + { + const NvCo::Dx12TargetInfo& targetInfo = renderContext->m_targetInfo; + + psoDesc.RTVFormats[0] = targetInfo.m_renderTargetFormats[0]; + psoDesc.DSVFormat = targetInfo.m_depthStencilFormat; + psoDesc.SampleDesc.Count = targetInfo.m_numSamples; + } + + // If no depth buffer, disable + if (psoDesc.DSVFormat == DXGI_FORMAT_UNKNOWN) + { + psoDesc.DepthStencilState.DepthEnable = FALSE; + } +} + +} // namespace FlexSample
\ No newline at end of file diff --git a/demo/d3d12/pipelineUtilD3D12.h b/demo/d3d12/pipelineUtilD3D12.h new file mode 100644 index 0000000..2949bd3 --- /dev/null +++ b/demo/d3d12/pipelineUtilD3D12.h @@ -0,0 +1,37 @@ +/* +* Copyright (c) 2008-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. +*/ + +#ifndef PIPELINE_UTIL_D3D12_H +#define PIPELINE_UTIL_D3D12_H + +#define NOMINMAX +#include <dxgi.h> +#include <d3d12.h> + +#include "meshRenderer.h" +#include <NvCoDx12RenderTarget.h> + +namespace FlexSample { +using namespace nvidia; + +struct PipelineUtilD3D +{ + /// Default initializes rasterizer + static void initRasterizerDesc(FrontWindingType winding, D3D12_RASTERIZER_DESC& desc); + /// Initialize default blend desc for solid rendering + static void initSolidBlendDesc(D3D12_BLEND_DESC& desc); + /// Set on psoDesc the format/samples and set up other default state. + /// If renderTarget is NV_NULL then the format that's set on the Dx12RenderInterface/RenderContext is used + static void initTargetFormat(Common::Dx12RenderTarget* renderTarget, AppGraphCtxD3D12* renderContext, D3D12_GRAPHICS_PIPELINE_STATE_DESC& psoDesc); +}; + +} // namespace FlexSample + +#endif
\ No newline at end of file diff --git a/demo/d3d12/pointRenderPipelineD3D12.cpp b/demo/d3d12/pointRenderPipelineD3D12.cpp new file mode 100644 index 0000000..7650c49 --- /dev/null +++ b/demo/d3d12/pointRenderPipelineD3D12.cpp @@ -0,0 +1,227 @@ +#define NOMINMAX + +#include <NvCoDx12HelperUtil.h> +#include <external/D3D12/include/d3dx12.h> + +#include "pipelineUtilD3D12.h" +#include "bufferD3D12.h" +#include "meshRendererD3D12.h" +#include "../d3d/shaderCommonD3D.h" + +// this +#include "pointRenderPipelineD3D12.h" + +// Shaders +#include "../d3d/shaders/pointVS.hlsl.h" +#include "../d3d/shaders/pointGS.hlsl.h" +#include "../d3d/shaders/pointPS.hlsl.h" +#include "../d3d/shaders/pointShadowPS.hlsl.h" + +namespace FlexSample { + +PointRenderPipelineD3D12::PointRenderPipelineD3D12(): + Parent(PRIMITIVE_POINT), + m_shadowMapLinearSamplerIndex(-1) +{ +} + +/* static */PointRenderPipelineD3D12::PipelineStateType PointRenderPipelineD3D12::getPipelineStateType(PointDrawStage stage, PointRenderMode mode, PointCullMode cull) +{ + switch (stage) + { + case POINT_DRAW_SHADOW: return PIPELINE_STATE_SHADOW; + default: return PIPELINE_STATE_LIGHT_SOLID; + } +} + +static D3D12_FILL_MODE _getFillMode(PointRenderPipelineD3D12::PipelineStateType type) +{ + return D3D12_FILL_MODE_SOLID; +} + +static D3D12_CULL_MODE _getCullMode(PointRenderPipelineD3D12::PipelineStateType type) +{ + return D3D12_CULL_MODE_NONE; +} + +static void _initRasterizerDesc(PointRenderPipelineD3D12::PipelineStateType type, D3D12_RASTERIZER_DESC& desc) +{ + PipelineUtilD3D::initRasterizerDesc(FRONT_WINDING_COUNTER_CLOCKWISE, desc); + desc.FillMode = _getFillMode(type); + desc.CullMode = _getCullMode(type); +} + +static void _initPipelineStateDesc(PointRenderPipelineD3D12::PipelineStateType type, NvCo::Dx12RenderTarget* shadowMap, AppGraphCtxD3D12* renderContext, D3D12_GRAPHICS_PIPELINE_STATE_DESC& psoDesc) +{ + PipelineUtilD3D::initTargetFormat((shadowMap && type == PointRenderPipelineD3D12::PIPELINE_STATE_SHADOW) ? shadowMap : nullptr, renderContext, psoDesc); + + psoDesc.InputLayout.NumElements = _countof(MeshRendererD3D12::PointInputElementDescs); + psoDesc.InputLayout.pInputElementDescs = MeshRendererD3D12::PointInputElementDescs; + psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT; +} + +int PointRenderPipelineD3D12::initialize(const RenderStateD3D12& state, const std::wstring& shadersPath, int shadowMapLinearSamplerIndex, NvCo::Dx12RenderTarget* shadowMap) +{ + using namespace NvCo; + ID3D12Device* device = state.m_device; + + m_shadowMapLinearSamplerIndex = shadowMapLinearSamplerIndex; + + // create the pipeline state object + { + D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; + PipelineUtilD3D::initSolidBlendDesc(psoDesc.BlendState); + + // create the root signature + ComPtr<ID3D12RootSignature> signiture; + { + CD3DX12_DESCRIPTOR_RANGE ranges[2]; + CD3DX12_ROOT_PARAMETER params[3]; + + UINT rootIndex = 0; + { + D3D12_ROOT_PARAMETER& param = params[rootIndex++]; + param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; + param.Descriptor.ShaderRegister = 0u; + param.Descriptor.RegisterSpace = 0u; + param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + } + + const int numSrvs = 1; + if (numSrvs > 0) + { + ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, numSrvs, 0); + params[rootIndex++].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_PIXEL); + } + const int numSamplers = 1; + if (numSamplers > 0) + { + ranges[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, numSamplers, 0); + params[rootIndex++].InitAsDescriptorTable(1, &ranges[1], D3D12_SHADER_VISIBILITY_PIXEL); + } + + D3D12_ROOT_SIGNATURE_DESC desc; + desc.NumParameters = rootIndex; + desc.pParameters = params; + desc.NumStaticSamplers = 0; + desc.pStaticSamplers = nullptr; + desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; + + ComPtr<ID3DBlob> sigBlob; + NV_RETURN_ON_FAIL(Dx12HelperUtil::serializeRootSigniture(desc, D3D_ROOT_SIGNATURE_VERSION_1, sigBlob)); + NV_RETURN_ON_FAIL(device->CreateRootSignature(0u, sigBlob->GetBufferPointer(), sigBlob->GetBufferSize(), IID_PPV_ARGS(&signiture))); + } + + { + psoDesc.VS = Dx12Blob(g_pointVS); + psoDesc.GS = Dx12Blob(g_pointGS); + psoDesc.PS = Dx12Blob(g_pointPS); + + NV_RETURN_ON_FAIL(_initPipelineState(state, shadowMap, PIPELINE_STATE_LIGHT_SOLID, signiture.Get(), psoDesc)); + } + + // Shadow rendering + { + D3D12_ROOT_PARAMETER params[1]; + params[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; + params[0].Descriptor.ShaderRegister = 0u; + params[0].Descriptor.RegisterSpace = 0u; + params[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + + D3D12_ROOT_SIGNATURE_DESC desc; + desc.NumParameters = 1; + desc.pParameters = params; + desc.NumStaticSamplers = 0u; + desc.pStaticSamplers = nullptr; + desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; + + ComPtr<ID3DBlob> sigBlob; + NV_RETURN_ON_FAIL(Dx12HelperUtil::serializeRootSigniture(desc, D3D_ROOT_SIGNATURE_VERSION_1, sigBlob)); + NV_RETURN_ON_FAIL(device->CreateRootSignature(0u, sigBlob->GetBufferPointer(), sigBlob->GetBufferSize(), IID_PPV_ARGS(&signiture))); + } + + { + psoDesc.VS = Dx12Blob(g_pointVS); + psoDesc.GS = Dx12Blob(g_pointGS); + psoDesc.PS = Dx12Blob(g_pointShadowPS); + + NV_RETURN_ON_FAIL(_initPipelineState(state, shadowMap, PIPELINE_STATE_SHADOW, signiture.Get(), psoDesc)); + } + } + + return NV_OK; +} + +int PointRenderPipelineD3D12::_initPipelineState(const RenderStateD3D12& state, NvCo::Dx12RenderTarget* shadowMap, PipelineStateType pipeType, ID3D12RootSignature* signiture, D3D12_GRAPHICS_PIPELINE_STATE_DESC& psoDesc) +{ + ID3D12Device* device = state.m_device; + + _initRasterizerDesc(pipeType, psoDesc.RasterizerState); + _initPipelineStateDesc(pipeType, shadowMap, state.m_renderContext, psoDesc); + + psoDesc.pRootSignature = signiture; + + PipelineStateD3D12& pipeState = m_states[pipeType]; + pipeState.m_rootSignature = signiture; + + NV_RETURN_ON_FAIL(device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&pipeState.m_pipelineState))); + return NV_OK; +} + +int PointRenderPipelineD3D12::bind(const void* paramsIn, const void* platformState) +{ + const RenderStateD3D12& state = *(RenderStateD3D12*)platformState; + const PointDrawParamsD3D& params = *(PointDrawParamsD3D*)paramsIn; + + // Set up constant buffer + NvCo::Dx12CircularResourceHeap::Cursor cursor; + { + Hlsl::PointShaderConst constBuf; + RenderParamsUtilD3D::calcPointConstantBuffer(params, constBuf); + cursor = state.m_constantHeap->newConstantBuffer(constBuf); + if (!cursor.isValid()) + { + return NV_FAIL; + } + } + + const PipelineStateType pipeType = getPipelineStateType(params.renderStage, params.renderMode, params.cullMode); + PipelineStateD3D12& pipeState = m_states[pipeType]; + if (!pipeState.isValid()) + { + return NV_FAIL; + } + + ID3D12GraphicsCommandList* commandList = state.m_commandList; + commandList->SetGraphicsRootSignature(pipeState.m_rootSignature.Get()); + commandList->SetPipelineState(pipeState.m_pipelineState.Get()); + + D3D12_GPU_VIRTUAL_ADDRESS cbvHandle = state.m_constantHeap->getGpuHandle(cursor); + commandList->SetGraphicsRootConstantBufferView(0, cbvHandle); + + if (pipeType == PIPELINE_STATE_SHADOW) + { + ID3D12DescriptorHeap* heaps[] = { nullptr }; + commandList->SetDescriptorHeaps(0, heaps); + } + else + { + NvCo::Dx12RenderTarget* shadowMap = (NvCo::Dx12RenderTarget*)params.shadowMap; + + ID3D12DescriptorHeap* heaps[] = { state.m_srvCbvUavDescriptorHeap->getHeap(), state.m_samplerDescriptorHeap->getHeap() }; + commandList->SetDescriptorHeaps(_countof(heaps), heaps); + // Bind the srvs + commandList->SetGraphicsRootDescriptorTable(1, state.m_srvCbvUavDescriptorHeap->getGpuHandle(shadowMap->getSrvHeapIndex(shadowMap->getPrimaryBufferType()))); + // Bind the samplers + commandList->SetGraphicsRootDescriptorTable(2, state.m_samplerDescriptorHeap->getGpuHandle(m_shadowMapLinearSamplerIndex)); + } + + return NV_OK; +} + +int PointRenderPipelineD3D12::draw(const RenderAllocation& allocIn, size_t sizeOfAlloc, const void* platformState) +{ + return MeshRendererD3D12::defaultDraw(allocIn, sizeOfAlloc, platformState); +} + +} // namespace FlexSample
\ No newline at end of file diff --git a/demo/d3d12/pointRenderPipelineD3D12.h b/demo/d3d12/pointRenderPipelineD3D12.h new file mode 100644 index 0000000..cdd03bc --- /dev/null +++ b/demo/d3d12/pointRenderPipelineD3D12.h @@ -0,0 +1,60 @@ +/* +* Copyright (c) 2008-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. +*/ + +#ifndef POINT_RENDER_PIPELINE_D3D12_H +#define POINT_RENDER_PIPELINE_D3D12_H + +#include <DirectXMath.h> +#include "renderStateD3D12.h" +#include "meshRenderer.h" + +#include <NvCoDx12RenderTarget.h> + +#include "../d3d/renderParamsD3D.h" + +namespace FlexSample { +using namespace nvidia; + +struct PointRenderPipelineD3D12: public RenderPipeline +{ + //NV_CO_DECLARE_POLYMORPHIC_CLASS(PointRenderPipelineD3D12, RenderPipeline); +public: + typedef RenderPipeline Parent; + + enum PipelineStateType + { + PIPELINE_STATE_SHADOW, + PIPELINE_STATE_LIGHT_SOLID, + PIPELINE_STATE_COUNT_OF, + }; + + PointRenderPipelineD3D12(); + + /// Initialize + int initialize(const RenderStateD3D12& state, const std::wstring& shadersDir, int shadowMapLinearSamplerIndex, NvCo::Dx12RenderTarget* shadowMap); + /// Do the binding + virtual int bind(const void* paramsIn, const void* platformState) override; + virtual int draw(const RenderAllocation& alloc, size_t sizeOfAlloc, const void* platformState) override; + + /// Convert into a single pipeline state type + static PipelineStateType getPipelineStateType(PointDrawStage stage, PointRenderMode mode, PointCullMode cull); + + protected: + + int _initPipelineState(const RenderStateD3D12& state, NvCo::Dx12RenderTarget* shadowMap, PipelineStateType pipeType, ID3D12RootSignature* signiture, D3D12_GRAPHICS_PIPELINE_STATE_DESC& psoDesc); + + int m_shadowMapLinearSamplerIndex; //< The index to the linear sampler in the m_samplerHeap + + PipelineStateD3D12 m_states[PIPELINE_STATE_COUNT_OF]; +}; + +} // namespace FlexSample + +#endif
\ No newline at end of file diff --git a/demo/d3d12/renderStateD3D12.cpp b/demo/d3d12/renderStateD3D12.cpp new file mode 100644 index 0000000..28a69f4 --- /dev/null +++ b/demo/d3d12/renderStateD3D12.cpp @@ -0,0 +1,67 @@ + +#include "renderStateD3D12.h" + +namespace FlexSample { + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Dx12RenderStateManager !!!!!!!!!!!!!!!!!!!!!!!!!! */ + +int RenderStateManagerD3D12::initialize(AppGraphCtxD3D12* renderContext, size_t maxHeapAlloc) +{ + m_renderContext = renderContext; + m_device = renderContext->m_device; + + m_fence.init(m_device); + m_scopeManager.init(m_device, &m_fence); + m_srvCbvUavDescriptorHeap.init(m_device, 256, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE); + m_samplerDescriptorHeap.init(m_device, 64, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE); + + { + NvCo::Dx12CircularResourceHeap::Desc desc; + desc.init(); + desc.m_blockSize = maxHeapAlloc; + m_constantHeap.init(m_device, desc, &m_fence); + } + + return NV_OK; +} + +void RenderStateManagerD3D12::updateCompleted() +{ + m_scopeManager.updateCompleted(); + m_constantHeap.updateCompleted(); +} + +void RenderStateManagerD3D12::onGpuWorkSubmitted(ID3D12CommandQueue* commandQueue) +{ + assert(commandQueue); + if (!commandQueue) + { + printf("Must pass a ID3D12CommandQueue to onGpuWorkSubmitted"); + return; + } + + const uint64_t signalValue = m_fence.nextSignal(commandQueue); + + m_scopeManager.addSync(signalValue); + m_constantHeap.addSync(signalValue); +} + +RenderStateD3D12 RenderStateManagerD3D12::getState() +{ + RenderStateD3D12 state; + + state.m_renderContext = m_renderContext; + state.m_commandList = m_renderContext->m_commandList; + state.m_device = m_device; + + state.m_constantHeap = &m_constantHeap; + state.m_srvCbvUavDescriptorHeap = &m_srvCbvUavDescriptorHeap; + state.m_fence = &m_fence; + state.m_scopeManager = &m_scopeManager; + state.m_samplerDescriptorHeap = &m_samplerDescriptorHeap; + + return state; +} + + +} // namespace FlexSample
\ No newline at end of file diff --git a/demo/d3d12/renderStateD3D12.h b/demo/d3d12/renderStateD3D12.h new file mode 100644 index 0000000..1fb1f7d --- /dev/null +++ b/demo/d3d12/renderStateD3D12.h @@ -0,0 +1,74 @@ +/* +* Copyright (c) 2008-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. +*/ + +#ifndef RENDER_STATE_D3D12_H +#define RENDER_STATE_D3D12_H + +#include <NvCoDx12ResourceScopeManager.h> +#include <NvCoDx12CircularResourceHeap.h> +#include <NvCoDx12DescriptorHeap.h> +#include "appD3D12Ctx.h" + +namespace NvCo = nvidia::Common; + +namespace FlexSample { +using namespace nvidia; + +struct PipelineStateD3D12 +{ + /// True if contents is all set and therefore 'valid' + inline bool isValid() const { return m_rootSignature && m_pipelineState; } + + ComPtr<ID3D12RootSignature> m_rootSignature; + ComPtr<ID3D12PipelineState> m_pipelineState; +}; + +struct RenderStateD3D12 +{ + AppGraphCtxD3D12* m_renderContext; + + ID3D12Device* m_device; + ID3D12GraphicsCommandList* m_commandList; + + NvCo::Dx12ResourceScopeManager* m_scopeManager; ///< Holds resources in scope + NvCo::Dx12DescriptorHeap* m_srvCbvUavDescriptorHeap; ///< Can hold cbv, srv, uavs + NvCo::Dx12DescriptorHeap* m_samplerDescriptorHeap; ///< Descriptor heap + NvCo::Dx12CircularResourceHeap* m_constantHeap; ///< Can hold transitory constant buffers, and vertex buffers + NvCo::Dx12CounterFence* m_fence; ///< Main fence to track lifetimes +}; + +struct RenderStateManagerD3D12 +{ + RenderStateManagerD3D12(): + m_renderContext(nullptr), + m_device(nullptr) + {} + + int initialize(AppGraphCtxD3D12* renderContext, size_t maxHeapAlloc); + + void onGpuWorkSubmitted(ID3D12CommandQueue* handle); + void updateCompleted(); + + /// Get the render state + RenderStateD3D12 getState(); + + AppGraphCtxD3D12* m_renderContext; + ID3D12Device* m_device; + + NvCo::Dx12ResourceScopeManager m_scopeManager; ///< Holds resources in scope + NvCo::Dx12DescriptorHeap m_srvCbvUavDescriptorHeap; ///< Can hold cbv, srv, uavs + NvCo::Dx12DescriptorHeap m_samplerDescriptorHeap; ///< Holds sampler descriptions + NvCo::Dx12CircularResourceHeap m_constantHeap; ///< Can hold transitory constant buffers, and vertex buffers + NvCo::Dx12CounterFence m_fence; ///< Main fence to track lifetimes +}; + +} // namespace FlexSample + +#endif
\ No newline at end of file |