aboutsummaryrefslogtreecommitdiff
path: root/demo/d3d12
diff options
context:
space:
mode:
authorMiles Macklin <[email protected]>2017-06-09 13:41:15 +1200
committerMiles Macklin <[email protected]>2017-06-09 13:41:15 +1200
commit688b5f42e9bfe498d7af7075d4d8f4429867f3a3 (patch)
tree7e0d0e7c95298f0418723abd92f61ac6e16b055e /demo/d3d12
parentUpdate README.md (diff)
downloadflex-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')
-rw-r--r--demo/d3d12/NvCoDx12CircularResourceHeap.cpp204
-rw-r--r--demo/d3d12/NvCoDx12CircularResourceHeap.h234
-rw-r--r--demo/d3d12/NvCoDx12CounterFence.cpp71
-rw-r--r--demo/d3d12/NvCoDx12CounterFence.h82
-rw-r--r--demo/d3d12/NvCoDx12DescriptorHeap.cpp54
-rw-r--r--demo/d3d12/NvCoDx12DescriptorHeap.h116
-rw-r--r--demo/d3d12/NvCoDx12Handle.h162
-rw-r--r--demo/d3d12/NvCoDx12HelperUtil.cpp89
-rw-r--r--demo/d3d12/NvCoDx12HelperUtil.h52
-rw-r--r--demo/d3d12/NvCoDx12RenderTarget.cpp324
-rw-r--r--demo/d3d12/NvCoDx12RenderTarget.h122
-rw-r--r--demo/d3d12/NvCoDx12Resource.cpp167
-rw-r--r--demo/d3d12/NvCoDx12Resource.h140
-rw-r--r--demo/d3d12/NvCoDx12ResourceScopeManager.cpp179
-rw-r--r--demo/d3d12/NvCoDx12ResourceScopeManager.h100
-rw-r--r--demo/d3d12/NvCoDxDebugUtil.cpp32
-rw-r--r--demo/d3d12/NvCoDxDebugUtil.h37
-rw-r--r--demo/d3d12/NvCoDxFormatUtil.cpp173
-rw-r--r--demo/d3d12/NvCoDxFormatUtil.h41
-rw-r--r--demo/d3d12/NvCoFreeList.cpp232
-rw-r--r--demo/d3d12/NvCoFreeList.h154
-rw-r--r--demo/d3d12/NvResult.h137
-rw-r--r--demo/d3d12/appD3D12Ctx.cpp1210
-rw-r--r--demo/d3d12/appD3D12Ctx.h181
-rw-r--r--demo/d3d12/bufferD3D12.cpp118
-rw-r--r--demo/d3d12/bufferD3D12.h38
-rw-r--r--demo/d3d12/demoContextD3D12.cpp1410
-rw-r--r--demo/d3d12/demoContextD3D12.h256
-rw-r--r--demo/d3d12/diffusePointRenderPipelineD3D12.cpp223
-rw-r--r--demo/d3d12/diffusePointRenderPipelineD3D12.h54
-rw-r--r--demo/d3d12/fluidCompositeRenderPipelineD3D12.cpp166
-rw-r--r--demo/d3d12/fluidCompositeRenderPipelineD3D12.h54
-rw-r--r--demo/d3d12/fluidEllipsoidRenderPipelineD3D12.cpp176
-rw-r--r--demo/d3d12/fluidEllipsoidRenderPipelineD3D12.h60
-rw-r--r--demo/d3d12/fluidSmoothRenderPipelineD3D12.cpp158
-rw-r--r--demo/d3d12/fluidSmoothRenderPipelineD3D12.h55
-rw-r--r--demo/d3d12/imguiGraphD3D12.cpp667
-rw-r--r--demo/d3d12/imguiGraphD3D12.h91
-rw-r--r--demo/d3d12/imguiInteropD3D12.cpp61
-rw-r--r--demo/d3d12/lineRenderPipelineD3D12.cpp140
-rw-r--r--demo/d3d12/lineRenderPipelineD3D12.h65
-rw-r--r--demo/d3d12/meshRenderPipelineD3D12.cpp284
-rw-r--r--demo/d3d12/meshRenderPipelineD3D12.h66
-rw-r--r--demo/d3d12/meshRenderer.cpp15
-rw-r--r--demo/d3d12/meshRenderer.h194
-rw-r--r--demo/d3d12/meshRendererD3D12.cpp419
-rw-r--r--demo/d3d12/meshRendererD3D12.h175
-rw-r--r--demo/d3d12/meshUtil.cpp33
-rw-r--r--demo/d3d12/meshUtil.h26
-rw-r--r--demo/d3d12/pipelineUtilD3D12.cpp78
-rw-r--r--demo/d3d12/pipelineUtilD3D12.h37
-rw-r--r--demo/d3d12/pointRenderPipelineD3D12.cpp227
-rw-r--r--demo/d3d12/pointRenderPipelineD3D12.h60
-rw-r--r--demo/d3d12/renderStateD3D12.cpp67
-rw-r--r--demo/d3d12/renderStateD3D12.h74
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(&params, 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(), &params);
+
+ 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(), &params);
+
+ 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(), &params);
+ }
+}
+
+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(), &params);
+
+ 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(), &params);
+
+ 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(), &params);
+
+ 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(), &params);
+}
+
+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(), &params);
+}
+
+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**)&times);
+ D3D12_RANGE readRange = { 0, 1 };
+ m_queryResults->Map(0, &readRange, (void**)&times);
+ 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(), &params);
+ }
+}
+
+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(), &params);
+ }
+ }
+}
+
+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(), &params);
+}
+
+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(), &params);
+
+ 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, &params, 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), &params, 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