• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (c) 2019-2020 Advanced Micro Devices, Inc. All rights reserved.
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21 //
22 
23 #include "D3D12MemAlloc.h"
24 #include "Common.h"
25 #include "Tests.h"
26 #include <atomic>
27 
28 namespace VS
29 {
30     #include "Shaders\VS_Compiled.h"
31 }
32 namespace PS
33 {
34     #include "Shaders\PS_Compiled.h"
35 }
36 
37 static const wchar_t * const CLASS_NAME = L"D3D12MemAllocSample";
38 static const wchar_t * const WINDOW_TITLE = L"D3D12 Memory Allocator Sample";
39 static const int SIZE_X = 1024;
40 static const int SIZE_Y = 576;
41 static const bool FULLSCREEN = false;
42 static const UINT PRESENT_SYNC_INTERVAL = 1;
43 static const DXGI_FORMAT RENDER_TARGET_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM;
44 static const DXGI_FORMAT DEPTH_STENCIL_FORMAT = DXGI_FORMAT_D32_FLOAT;
45 static const size_t FRAME_BUFFER_COUNT = 3; // number of buffers we want, 2 for double buffering, 3 for tripple buffering
46 static const D3D_FEATURE_LEVEL MY_D3D_FEATURE_LEVEL = D3D_FEATURE_LEVEL_12_0;
47 
48 static const bool ENABLE_DEBUG_LAYER = true;
49 static const bool ENABLE_CPU_ALLOCATION_CALLBACKS = true;
50 static const bool ENABLE_CPU_ALLOCATION_CALLBACKS_PRINT = false;
51 static constexpr D3D12MA::ALLOCATOR_FLAGS g_AllocatorFlags = D3D12MA::ALLOCATOR_FLAG_NONE;
52 static D3D12MA::ALLOCATION_CALLBACKS g_AllocationCallbacks = {}; // Used only when ENABLE_CPU_ALLOCATION_CALLBACKS
53 
54 static HINSTANCE g_Instance;
55 static HWND g_Wnd;
56 
57 static UINT64 g_TimeOffset; // In ms.
58 static UINT64 g_TimeValue; // Time since g_TimeOffset, in ms.
59 static float g_Time; // g_TimeValue converted to float, in seconds.
60 static float g_TimeDelta;
61 
62 static CComPtr<ID3D12Device> g_Device;
63 static D3D12MA::Allocator* g_Allocator;
64 
65 static CComPtr<IDXGISwapChain3> g_SwapChain; // swapchain used to switch between render targets
66 static CComPtr<ID3D12CommandQueue> g_CommandQueue; // container for command lists
67 static CComPtr<ID3D12DescriptorHeap> g_RtvDescriptorHeap; // a descriptor heap to hold resources like the render targets
68 static CComPtr<ID3D12Resource> g_RenderTargets[FRAME_BUFFER_COUNT]; // number of render targets equal to buffer count
69 static CComPtr<ID3D12CommandAllocator> g_CommandAllocators[FRAME_BUFFER_COUNT]; // we want enough allocators for each buffer * number of threads (we only have one thread)
70 static CComPtr<ID3D12GraphicsCommandList> g_CommandList; // a command list we can record commands into, then execute them to render the frame
71 static CComPtr<ID3D12Fence> g_Fences[FRAME_BUFFER_COUNT];    // an object that is locked while our command list is being executed by the gpu. We need as many
72                                                       //as we have allocators (more if we want to know when the gpu is finished with an asset)
73 static HANDLE g_FenceEvent; // a handle to an event when our g_Fences is unlocked by the gpu
74 static UINT64 g_FenceValues[FRAME_BUFFER_COUNT]; // this value is incremented each frame. each g_Fences will have its own value
75 static UINT g_FrameIndex; // current rtv we are on
76 static UINT g_RtvDescriptorSize; // size of the rtv descriptor on the g_Device (all front and back buffers will be the same size)
77 
78 static CComPtr<ID3D12PipelineState> g_PipelineStateObject;
79 static CComPtr<ID3D12RootSignature> g_RootSignature;
80 static CComPtr<ID3D12Resource> g_VertexBuffer;
81 static D3D12MA::Allocation* g_VertexBufferAllocation;
82 static CComPtr<ID3D12Resource> g_IndexBuffer;
83 static D3D12MA::Allocation* g_IndexBufferAllocation;
84 static D3D12_VERTEX_BUFFER_VIEW g_VertexBufferView;
85 static D3D12_INDEX_BUFFER_VIEW g_IndexBufferView;
86 static CComPtr<ID3D12Resource> g_DepthStencilBuffer;
87 static D3D12MA::Allocation* g_DepthStencilAllocation;
88 static CComPtr<ID3D12DescriptorHeap> g_DepthStencilDescriptorHeap;
89 
90 struct Vertex {
91     vec3 pos;
92     vec2 texCoord;
93 
VertexVertex94     Vertex() { }
VertexVertex95     Vertex(float x, float y, float z, float tx, float ty) :
96         pos(x, y, z),
97         texCoord(tx, ty)
98     {
99     }
100 };
101 
102 struct ConstantBuffer0_PS
103 {
104     vec4 Color;
105 };
106 struct ConstantBuffer1_VS
107 {
108     mat4 WorldViewProj;
109 };
110 
111 static const size_t ConstantBufferPerObjectAlignedSize = AlignUp<size_t>(sizeof(ConstantBuffer1_VS), 256);
112 static D3D12MA::Allocation* g_CbPerObjectUploadHeapAllocations[FRAME_BUFFER_COUNT];
113 static CComPtr<ID3D12Resource> g_CbPerObjectUploadHeaps[FRAME_BUFFER_COUNT];
114 static void* g_CbPerObjectAddress[FRAME_BUFFER_COUNT];
115 static uint32_t g_CubeIndexCount;
116 
117 static CComPtr<ID3D12DescriptorHeap> g_MainDescriptorHeap[FRAME_BUFFER_COUNT];
118 static CComPtr<ID3D12Resource> g_ConstantBufferUploadHeap[FRAME_BUFFER_COUNT];
119 static D3D12MA::Allocation* g_ConstantBufferUploadAllocation[FRAME_BUFFER_COUNT];
120 static void* g_ConstantBufferAddress[FRAME_BUFFER_COUNT];
121 
122 static CComPtr<ID3D12Resource> g_Texture;
123 static D3D12MA::Allocation* g_TextureAllocation;
124 
125 static void* const CUSTOM_ALLOCATION_USER_DATA = (void*)(uintptr_t)0xDEADC0DE;
126 
127 static std::atomic<size_t> g_CpuAllocationCount{0};
128 
CustomAllocate(size_t Size,size_t Alignment,void * pUserData)129 static void* CustomAllocate(size_t Size, size_t Alignment, void* pUserData)
130 {
131     assert(pUserData == CUSTOM_ALLOCATION_USER_DATA);
132     void* memory = _aligned_malloc(Size, Alignment);
133     if(ENABLE_CPU_ALLOCATION_CALLBACKS_PRINT)
134     {
135         wprintf(L"Allocate Size=%llu Alignment=%llu -> %p\n", Size, Alignment, memory);
136     }
137     ++g_CpuAllocationCount;
138     return memory;
139 }
140 
CustomFree(void * pMemory,void * pUserData)141 static void CustomFree(void* pMemory, void* pUserData)
142 {
143     assert(pUserData == CUSTOM_ALLOCATION_USER_DATA);
144     if(pMemory)
145     {
146         --g_CpuAllocationCount;
147         if(ENABLE_CPU_ALLOCATION_CALLBACKS_PRINT)
148         {
149             wprintf(L"Free %p\n", pMemory);
150         }
151         _aligned_free(pMemory);
152     }
153 }
154 
SetDefaultRasterizerDesc(D3D12_RASTERIZER_DESC & outDesc)155 static void SetDefaultRasterizerDesc(D3D12_RASTERIZER_DESC& outDesc)
156 {
157     outDesc.FillMode = D3D12_FILL_MODE_SOLID;
158     outDesc.CullMode = D3D12_CULL_MODE_BACK;
159     outDesc.FrontCounterClockwise = FALSE;
160     outDesc.DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
161     outDesc.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
162     outDesc.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
163     outDesc.DepthClipEnable = TRUE;
164     outDesc.MultisampleEnable = FALSE;
165     outDesc.AntialiasedLineEnable = FALSE;
166     outDesc.ForcedSampleCount = 0;
167     outDesc.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
168 }
169 
SetDefaultBlendDesc(D3D12_BLEND_DESC & outDesc)170 static void SetDefaultBlendDesc(D3D12_BLEND_DESC& outDesc)
171 {
172     outDesc.AlphaToCoverageEnable = FALSE;
173     outDesc.IndependentBlendEnable = FALSE;
174     const D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc = {
175         FALSE,FALSE,
176         D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD,
177         D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD,
178         D3D12_LOGIC_OP_NOOP,
179         D3D12_COLOR_WRITE_ENABLE_ALL };
180     for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i)
181         outDesc.RenderTarget[i] = defaultRenderTargetBlendDesc;
182 }
183 
SetDefaultDepthStencilDesc(D3D12_DEPTH_STENCIL_DESC & outDesc)184 static void SetDefaultDepthStencilDesc(D3D12_DEPTH_STENCIL_DESC& outDesc)
185 {
186     outDesc.DepthEnable = TRUE;
187     outDesc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
188     outDesc.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
189     outDesc.StencilEnable = FALSE;
190     outDesc.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK;
191     outDesc.StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK;
192     const D3D12_DEPTH_STENCILOP_DESC defaultStencilOp = {
193         D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_COMPARISON_FUNC_ALWAYS };
194     outDesc.FrontFace = defaultStencilOp;
195     outDesc.BackFace = defaultStencilOp;
196 }
197 
WaitForFrame(size_t frameIndex)198 void WaitForFrame(size_t frameIndex) // wait until gpu is finished with command list
199 {
200     // if the current g_Fences value is still less than "g_FenceValues", then we know the GPU has not finished executing
201     // the command queue since it has not reached the "g_CommandQueue->Signal(g_Fences, g_FenceValues)" command
202     if (g_Fences[frameIndex]->GetCompletedValue() < g_FenceValues[frameIndex])
203     {
204         // we have the g_Fences create an event which is signaled once the g_Fences's current value is "g_FenceValues"
205         CHECK_HR( g_Fences[frameIndex]->SetEventOnCompletion(g_FenceValues[frameIndex], g_FenceEvent) );
206 
207         // We will wait until the g_Fences has triggered the event that it's current value has reached "g_FenceValues". once it's value
208         // has reached "g_FenceValues", we know the command queue has finished executing
209         WaitForSingleObject(g_FenceEvent, INFINITE);
210     }
211 }
212 
WaitGPUIdle(size_t frameIndex)213 void WaitGPUIdle(size_t frameIndex)
214 {
215     g_FenceValues[frameIndex]++;
216     CHECK_HR( g_CommandQueue->Signal(g_Fences[frameIndex], g_FenceValues[frameIndex]) );
217     WaitForFrame(frameIndex);
218 }
219 
220 //*********************************************************
221 //
222 // Copyright (c) Microsoft. All rights reserved.
223 // This code is licensed under the MIT License (MIT).
224 // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
225 // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
226 // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
227 // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
228 //
229 //*********************************************************
230 // Row-by-row memcpy
MemcpySubresource(_In_ const D3D12_MEMCPY_DEST * pDest,_In_ const D3D12_SUBRESOURCE_DATA * pSrc,SIZE_T RowSizeInBytes,UINT NumRows,UINT NumSlices)231 inline void MemcpySubresource(
232     _In_ const D3D12_MEMCPY_DEST* pDest,
233     _In_ const D3D12_SUBRESOURCE_DATA* pSrc,
234     SIZE_T RowSizeInBytes,
235     UINT NumRows,
236     UINT NumSlices)
237 {
238     for (UINT z = 0; z < NumSlices; ++z)
239     {
240         BYTE* pDestSlice = reinterpret_cast<BYTE*>(pDest->pData) + pDest->SlicePitch * z;
241         const BYTE* pSrcSlice = reinterpret_cast<const BYTE*>(pSrc->pData) + pSrc->SlicePitch * z;
242         for (UINT y = 0; y < NumRows; ++y)
243         {
244             memcpy(pDestSlice + pDest->RowPitch * y,
245                 pSrcSlice + pSrc->RowPitch * y,
246                 RowSizeInBytes);
247         }
248     }
249 }
250 
251 //*********************************************************
252 //
253 // Copyright (c) Microsoft. All rights reserved.
254 // This code is licensed under the MIT License (MIT).
255 // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
256 // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
257 // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
258 // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
259 //
260 //*********************************************************
261 inline UINT64 UpdateSubresources(
262     _In_ ID3D12GraphicsCommandList* pCmdList,
263     _In_ ID3D12Resource* pDestinationResource,
264     _In_ ID3D12Resource* pIntermediate,
265     _In_range_(0,D3D12_REQ_SUBRESOURCES) UINT FirstSubresource,
266     _In_range_(0,D3D12_REQ_SUBRESOURCES-FirstSubresource) UINT NumSubresources,
267     UINT64 RequiredSize,
268     _In_reads_(NumSubresources) const D3D12_PLACED_SUBRESOURCE_FOOTPRINT* pLayouts,
269     _In_reads_(NumSubresources) const UINT* pNumRows,
270     _In_reads_(NumSubresources) const UINT64* pRowSizesInBytes,
271     _In_reads_(NumSubresources) const D3D12_SUBRESOURCE_DATA* pSrcData)
272 {
273     // Minor validation
274     D3D12_RESOURCE_DESC IntermediateDesc = pIntermediate->GetDesc();
275     D3D12_RESOURCE_DESC DestinationDesc = pDestinationResource->GetDesc();
276     if (IntermediateDesc.Dimension != D3D12_RESOURCE_DIMENSION_BUFFER ||
277         IntermediateDesc.Width < RequiredSize + pLayouts[0].Offset ||
278         RequiredSize > (SIZE_T)-1 ||
279         (DestinationDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER &&
280         (FirstSubresource != 0 || NumSubresources != 1)))
281     {
282         return 0;
283     }
284 
285     BYTE* pData;
286     HRESULT hr = pIntermediate->Map(0, &EMPTY_RANGE, reinterpret_cast<void**>(&pData));
287     if (FAILED(hr))
288     {
289         return 0;
290     }
291 
292     for (UINT i = 0; i < NumSubresources; ++i)
293     {
294         if (pRowSizesInBytes[i] > (SIZE_T)-1) return 0;
295         D3D12_MEMCPY_DEST DestData = { pData + pLayouts[i].Offset, pLayouts[i].Footprint.RowPitch, pLayouts[i].Footprint.RowPitch * pNumRows[i] };
296         MemcpySubresource(&DestData, &pSrcData[i], (SIZE_T)pRowSizesInBytes[i], pNumRows[i], pLayouts[i].Footprint.Depth);
297     }
298     pIntermediate->Unmap(0, NULL);
299 
300     if (DestinationDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
301     {
302         D3D12_BOX SrcBox = {
303             UINT( pLayouts[0].Offset ), 0, 0,
304             UINT( pLayouts[0].Offset + pLayouts[0].Footprint.Width ), 0, 0 };
305         pCmdList->CopyBufferRegion(
306             pDestinationResource, 0, pIntermediate, pLayouts[0].Offset, pLayouts[0].Footprint.Width);
307     }
308     else
309     {
310         for (UINT i = 0; i < NumSubresources; ++i)
311         {
312             D3D12_TEXTURE_COPY_LOCATION Dst = {};
313             Dst.pResource = pDestinationResource;
314             Dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
315             Dst.SubresourceIndex = i + FirstSubresource;
316             D3D12_TEXTURE_COPY_LOCATION Src = {};
317             Src.pResource = pIntermediate;
318             Src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
319             Src.PlacedFootprint = pLayouts[i];
320             pCmdList->CopyTextureRegion(&Dst, 0, 0, 0, &Src, nullptr);
321         }
322     }
323     return RequiredSize;
324 }
325 
326 //*********************************************************
327 //
328 // Copyright (c) Microsoft. All rights reserved.
329 // This code is licensed under the MIT License (MIT).
330 // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
331 // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
332 // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
333 // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
334 //
335 //*********************************************************
336 inline UINT64 UpdateSubresources(
337     _In_ ID3D12GraphicsCommandList* pCmdList,
338     _In_ ID3D12Resource* pDestinationResource,
339     _In_ ID3D12Resource* pIntermediate,
340     UINT64 IntermediateOffset,
341     _In_range_(0,D3D12_REQ_SUBRESOURCES) UINT FirstSubresource,
342     _In_range_(0,D3D12_REQ_SUBRESOURCES-FirstSubresource) UINT NumSubresources,
343     _In_reads_(NumSubresources) D3D12_SUBRESOURCE_DATA* pSrcData)
344 {
345     UINT64 RequiredSize = 0;
346     UINT64 MemToAlloc = static_cast<UINT64>(sizeof(D3D12_PLACED_SUBRESOURCE_FOOTPRINT) + sizeof(UINT) + sizeof(UINT64)) * NumSubresources;
347     if (MemToAlloc > SIZE_MAX)
348     {
349         return 0;
350     }
351     void* pMem = HeapAlloc(GetProcessHeap(), 0, static_cast<SIZE_T>(MemToAlloc));
352     if (pMem == NULL)
353     {
354         return 0;
355     }
356     D3D12_PLACED_SUBRESOURCE_FOOTPRINT* pLayouts = reinterpret_cast<D3D12_PLACED_SUBRESOURCE_FOOTPRINT*>(pMem);
357     UINT64* pRowSizesInBytes = reinterpret_cast<UINT64*>(pLayouts + NumSubresources);
358     UINT* pNumRows = reinterpret_cast<UINT*>(pRowSizesInBytes + NumSubresources);
359 
360     D3D12_RESOURCE_DESC Desc = pDestinationResource->GetDesc();
361     ID3D12Device* pDevice;
362     pDestinationResource->GetDevice(__uuidof(*pDevice), reinterpret_cast<void**>(&pDevice));
363     pDevice->GetCopyableFootprints(&Desc, FirstSubresource, NumSubresources, IntermediateOffset, pLayouts, pNumRows, pRowSizesInBytes, &RequiredSize);
364     pDevice->Release();
365 
366     UINT64 Result = UpdateSubresources(pCmdList, pDestinationResource, pIntermediate, FirstSubresource, NumSubresources, RequiredSize, pLayouts, pNumRows, pRowSizesInBytes, pSrcData);
367     HeapFree(GetProcessHeap(), 0, pMem);
368     return Result;
369 }
370 
InitD3D()371 void InitD3D() // initializes direct3d 12
372 {
373     IDXGIFactory4* dxgiFactory;
374     CHECK_HR( CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory)) );
375 
376     IDXGIAdapter1* adapter = nullptr; // adapters are the graphics card (this includes the embedded graphics on the motherboard)
377 
378     int adapterIndex = 0; // we'll start looking for directx 12  compatible graphics devices starting at index 0
379 
380     bool adapterFound = false; // set this to true when a good one was found
381 
382                                // find first hardware gpu that supports d3d 12
383     while (dxgiFactory->EnumAdapters1(adapterIndex, &adapter) != DXGI_ERROR_NOT_FOUND)
384     {
385         DXGI_ADAPTER_DESC1 desc;
386         adapter->GetDesc1(&desc);
387 
388         if ((desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) == 0)
389         {
390             HRESULT hr = D3D12CreateDevice(adapter, MY_D3D_FEATURE_LEVEL, _uuidof(ID3D12Device), nullptr);
391             if (SUCCEEDED(hr))
392             {
393                 adapterFound = true;
394                 break;
395             }
396         }
397         adapter->Release();
398         adapterIndex++;
399     }
400     assert(adapterFound);
401 
402     // Must be done before D3D12 device is created.
403     if(ENABLE_DEBUG_LAYER)
404     {
405         CComPtr<ID3D12Debug> debug;
406         if(SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debug))))
407             debug->EnableDebugLayer();
408     }
409 
410     // Create the g_Device
411     ID3D12Device* device = nullptr;
412     CHECK_HR( D3D12CreateDevice(
413         adapter,
414         MY_D3D_FEATURE_LEVEL,
415         IID_PPV_ARGS(&device)) );
416     g_Device.Attach(device);
417 
418     // Create allocator
419 
420     {
421         D3D12MA::ALLOCATOR_DESC desc = {};
422         desc.Flags = g_AllocatorFlags;
423         desc.pDevice = device;
424         desc.pAdapter = adapter;
425 
426         if(ENABLE_CPU_ALLOCATION_CALLBACKS)
427         {
428             g_AllocationCallbacks.pAllocate = &CustomAllocate;
429             g_AllocationCallbacks.pFree = &CustomFree;
430             g_AllocationCallbacks.pUserData = CUSTOM_ALLOCATION_USER_DATA;
431             desc.pAllocationCallbacks = &g_AllocationCallbacks;
432         }
433 
434         CHECK_HR( D3D12MA::CreateAllocator(&desc, &g_Allocator) );
435 
436         switch(g_Allocator->GetD3D12Options().ResourceHeapTier)
437         {
438         case D3D12_RESOURCE_HEAP_TIER_1:
439             wprintf(L"ResourceHeapTier = D3D12_RESOURCE_HEAP_TIER_1\n");
440             break;
441         case D3D12_RESOURCE_HEAP_TIER_2:
442             wprintf(L"ResourceHeapTier = D3D12_RESOURCE_HEAP_TIER_2\n");
443             break;
444         default:
445             assert(0);
446         }
447     }
448 
449     // -- Create the Command Queue -- //
450 
451     D3D12_COMMAND_QUEUE_DESC cqDesc = {}; // we will be using all the default values
452 
453     ID3D12CommandQueue* commandQueue = nullptr;
454     CHECK_HR( g_Device->CreateCommandQueue(&cqDesc, IID_PPV_ARGS(&commandQueue)) ); // create the command queue
455     g_CommandQueue.Attach(commandQueue);
456 
457     // -- Create the Swap Chain (double/tripple buffering) -- //
458 
459     DXGI_MODE_DESC backBufferDesc = {}; // this is to describe our display mode
460     backBufferDesc.Width = SIZE_X; // buffer width
461     backBufferDesc.Height = SIZE_Y; // buffer height
462     backBufferDesc.Format = RENDER_TARGET_FORMAT; // format of the buffer (rgba 32 bits, 8 bits for each chanel)
463 
464                                                   // describe our multi-sampling. We are not multi-sampling, so we set the count to 1 (we need at least one sample of course)
465     DXGI_SAMPLE_DESC sampleDesc = {};
466     sampleDesc.Count = 1; // multisample count (no multisampling, so we just put 1, since we still need 1 sample)
467 
468                           // Describe and create the swap chain.
469     DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
470     swapChainDesc.BufferCount = FRAME_BUFFER_COUNT; // number of buffers we have
471     swapChainDesc.BufferDesc = backBufferDesc; // our back buffer description
472     swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // this says the pipeline will render to this swap chain
473     swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; // dxgi will discard the buffer (data) after we call present
474     swapChainDesc.OutputWindow = g_Wnd; // handle to our window
475     swapChainDesc.SampleDesc = sampleDesc; // our multi-sampling description
476     swapChainDesc.Windowed = !FULLSCREEN; // set to true, then if in fullscreen must call SetFullScreenState with true for full screen to get uncapped fps
477 
478     IDXGISwapChain* tempSwapChain;
479 
480     CHECK_HR( dxgiFactory->CreateSwapChain(
481         g_CommandQueue, // the queue will be flushed once the swap chain is created
482         &swapChainDesc, // give it the swap chain description we created above
483         &tempSwapChain // store the created swap chain in a temp IDXGISwapChain interface
484     ) );
485 
486     g_SwapChain.Attach(static_cast<IDXGISwapChain3*>(tempSwapChain));
487 
488     g_FrameIndex = g_SwapChain->GetCurrentBackBufferIndex();
489 
490     // -- Create the Back Buffers (render target views) Descriptor Heap -- //
491 
492     // describe an rtv descriptor heap and create
493     D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {};
494     rtvHeapDesc.NumDescriptors = FRAME_BUFFER_COUNT; // number of descriptors for this heap.
495     rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; // this heap is a render target view heap
496 
497                                                        // This heap will not be directly referenced by the shaders (not shader visible), as this will store the output from the pipeline
498                                                        // otherwise we would set the heap's flag to D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE
499     rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
500     ID3D12DescriptorHeap* rtvDescriptorHeap = nullptr;
501     CHECK_HR( g_Device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&rtvDescriptorHeap)) );
502     g_RtvDescriptorHeap.Attach(rtvDescriptorHeap);
503 
504     // get the size of a descriptor in this heap (this is a rtv heap, so only rtv descriptors should be stored in it.
505     // descriptor sizes may vary from g_Device to g_Device, which is why there is no set size and we must ask the
506     // g_Device to give us the size. we will use this size to increment a descriptor handle offset
507     g_RtvDescriptorSize = g_Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
508 
509     // get a handle to the first descriptor in the descriptor heap. a handle is basically a pointer,
510     // but we cannot literally use it like a c++ pointer.
511     D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle { g_RtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart() };
512 
513     // Create a RTV for each buffer (double buffering is two buffers, tripple buffering is 3).
514     for (int i = 0; i < FRAME_BUFFER_COUNT; i++)
515     {
516         // first we get the n'th buffer in the swap chain and store it in the n'th
517         // position of our ID3D12Resource array
518         ID3D12Resource* res = nullptr;
519         CHECK_HR( g_SwapChain->GetBuffer(i, IID_PPV_ARGS(&res)) );
520         g_RenderTargets[i].Attach(res);
521 
522         // the we "create" a render target view which binds the swap chain buffer (ID3D12Resource[n]) to the rtv handle
523         g_Device->CreateRenderTargetView(g_RenderTargets[i], nullptr, rtvHandle);
524 
525         // we increment the rtv handle by the rtv descriptor size we got above
526         rtvHandle.ptr += g_RtvDescriptorSize;
527     }
528 
529     // -- Create the Command Allocators -- //
530 
531     for (int i = 0; i < FRAME_BUFFER_COUNT; i++)
532     {
533         ID3D12CommandAllocator* commandAllocator = nullptr;
534         CHECK_HR( g_Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&commandAllocator)) );
535         g_CommandAllocators[i].Attach(commandAllocator);
536     }
537 
538     // create the command list with the first allocator
539     CHECK_HR( g_Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, g_CommandAllocators[0], NULL, IID_PPV_ARGS(&g_CommandList)) );
540 
541     // command lists are created in the recording state. our main loop will set it up for recording again so close it now
542     g_CommandList->Close();
543 
544     // create a depth stencil descriptor heap so we can get a pointer to the depth stencil buffer
545     D3D12_DESCRIPTOR_HEAP_DESC dsvHeapDesc = {};
546     dsvHeapDesc.NumDescriptors = 1;
547     dsvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
548     dsvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
549     CHECK_HR( g_Device->CreateDescriptorHeap(&dsvHeapDesc, IID_PPV_ARGS(&g_DepthStencilDescriptorHeap)) );
550 
551     D3D12_CLEAR_VALUE depthOptimizedClearValue = {};
552     depthOptimizedClearValue.Format = DEPTH_STENCIL_FORMAT;
553     depthOptimizedClearValue.DepthStencil.Depth = 1.0f;
554     depthOptimizedClearValue.DepthStencil.Stencil = 0;
555 
556     D3D12MA::ALLOCATION_DESC depthStencilAllocDesc = {};
557     depthStencilAllocDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT;
558     D3D12_RESOURCE_DESC depthStencilResourceDesc = {};
559     depthStencilResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
560     depthStencilResourceDesc.Alignment = 0;
561     depthStencilResourceDesc.Width = SIZE_X;
562     depthStencilResourceDesc.Height = SIZE_Y;
563     depthStencilResourceDesc.DepthOrArraySize = 1;
564     depthStencilResourceDesc.MipLevels = 1;
565     depthStencilResourceDesc.Format = DEPTH_STENCIL_FORMAT;
566     depthStencilResourceDesc.SampleDesc.Count = 1;
567     depthStencilResourceDesc.SampleDesc.Quality = 0;
568     depthStencilResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
569     depthStencilResourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
570     CHECK_HR( g_Allocator->CreateResource(
571         &depthStencilAllocDesc,
572         &depthStencilResourceDesc,
573         D3D12_RESOURCE_STATE_DEPTH_WRITE,
574         &depthOptimizedClearValue,
575         &g_DepthStencilAllocation,
576         IID_PPV_ARGS(&g_DepthStencilBuffer)
577     ) );
578     CHECK_HR( g_DepthStencilBuffer->SetName(L"Depth/Stencil Resource Heap") );
579 
580     D3D12_DEPTH_STENCIL_VIEW_DESC depthStencilDesc = {};
581     depthStencilDesc.Format = DEPTH_STENCIL_FORMAT;
582     depthStencilDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
583     depthStencilDesc.Flags = D3D12_DSV_FLAG_NONE;
584     g_Device->CreateDepthStencilView(g_DepthStencilBuffer, &depthStencilDesc, g_DepthStencilDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
585 
586     // -- Create a Fence & Fence Event -- //
587 
588     // create the fences
589     for (int i = 0; i < FRAME_BUFFER_COUNT; i++)
590     {
591         ID3D12Fence* fence = nullptr;
592         CHECK_HR( g_Device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence)) );
593         g_Fences[i].Attach(fence);
594         g_FenceValues[i] = 0; // set the initial g_Fences value to 0
595     }
596 
597     // create a handle to a g_Fences event
598     g_FenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
599     assert(g_FenceEvent);
600 
601     D3D12_DESCRIPTOR_RANGE cbDescriptorRange;
602     cbDescriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV;
603     cbDescriptorRange.NumDescriptors = 1;
604     cbDescriptorRange.BaseShaderRegister = 0;
605     cbDescriptorRange.RegisterSpace = 0;
606     cbDescriptorRange.OffsetInDescriptorsFromTableStart = 0;
607 
608     D3D12_DESCRIPTOR_RANGE textureDescRange;
609     textureDescRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
610     textureDescRange.NumDescriptors = 1;
611     textureDescRange.BaseShaderRegister = 0;
612     textureDescRange.RegisterSpace = 0;
613     textureDescRange.OffsetInDescriptorsFromTableStart = 1;
614 
615     D3D12_ROOT_PARAMETER  rootParameters[3];
616 
617     rootParameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
618     rootParameters[0].DescriptorTable = {1, &cbDescriptorRange};
619     rootParameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
620 
621     rootParameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
622     rootParameters[1].Descriptor = {1, 0};
623     rootParameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX;
624 
625     rootParameters[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
626     rootParameters[2].DescriptorTable = {1, &textureDescRange};
627     rootParameters[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
628 
629     // create root signature
630 
631     // create a static sampler
632     D3D12_STATIC_SAMPLER_DESC sampler = {};
633     sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
634     sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
635     sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
636     sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
637     sampler.MipLODBias = 0;
638     sampler.MaxAnisotropy = 0;
639     sampler.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
640     sampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;
641     sampler.MinLOD = 0.0f;
642     sampler.MaxLOD = D3D12_FLOAT32_MAX;
643     sampler.ShaderRegister = 0;
644     sampler.RegisterSpace = 0;
645     sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
646 
647     D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc = {};
648     rootSignatureDesc.NumParameters = _countof(rootParameters);
649     rootSignatureDesc.pParameters = rootParameters;
650     rootSignatureDesc.NumStaticSamplers = 1;
651     rootSignatureDesc.pStaticSamplers = &sampler;
652     rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |
653         D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS |
654         D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
655         D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;
656 
657     CComPtr<ID3DBlob> signatureBlob;
658     ID3DBlob* signatureBlobPtr;
659     CHECK_HR( D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signatureBlobPtr, nullptr) );
660     signatureBlob.Attach(signatureBlobPtr);
661 
662     ID3D12RootSignature* rootSignature = nullptr;
663     CHECK_HR( device->CreateRootSignature(0, signatureBlob->GetBufferPointer(), signatureBlob->GetBufferSize(), IID_PPV_ARGS(&rootSignature)) );
664     g_RootSignature.Attach(rootSignature);
665 
666     for (int i = 0; i < FRAME_BUFFER_COUNT; ++i)
667     {
668         D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
669         heapDesc.NumDescriptors = 2;
670         heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
671         heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
672         CHECK_HR( g_Device->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&g_MainDescriptorHeap[i])) );
673     }
674 
675     // # CONSTANT BUFFER
676 
677     for (int i = 0; i < FRAME_BUFFER_COUNT; ++i)
678     {
679         D3D12MA::ALLOCATION_DESC constantBufferUploadAllocDesc = {};
680         constantBufferUploadAllocDesc.HeapType = D3D12_HEAP_TYPE_UPLOAD;
681         D3D12_RESOURCE_DESC constantBufferResourceDesc = {};
682         constantBufferResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
683         constantBufferResourceDesc.Alignment = 0;
684         constantBufferResourceDesc.Width = 1024 * 64;
685         constantBufferResourceDesc.Height = 1;
686         constantBufferResourceDesc.DepthOrArraySize = 1;
687         constantBufferResourceDesc.MipLevels = 1;
688         constantBufferResourceDesc.Format = DXGI_FORMAT_UNKNOWN;
689         constantBufferResourceDesc.SampleDesc.Count = 1;
690         constantBufferResourceDesc.SampleDesc.Quality = 0;
691         constantBufferResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
692         constantBufferResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
693         CHECK_HR( g_Allocator->CreateResource(
694             &constantBufferUploadAllocDesc,
695             &constantBufferResourceDesc,
696             D3D12_RESOURCE_STATE_GENERIC_READ,
697             nullptr,
698             &g_ConstantBufferUploadAllocation[i],
699             IID_PPV_ARGS(&g_ConstantBufferUploadHeap[i])) );
700         g_ConstantBufferUploadHeap[i]->SetName(L"Constant Buffer Upload Resource Heap");
701 
702         D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};
703         cbvDesc.BufferLocation = g_ConstantBufferUploadHeap[i]->GetGPUVirtualAddress();
704         cbvDesc.SizeInBytes = AlignUp<UINT>(sizeof(ConstantBuffer0_PS), 256);
705         g_Device->CreateConstantBufferView(&cbvDesc, g_MainDescriptorHeap[i]->GetCPUDescriptorHandleForHeapStart());
706 
707         CHECK_HR( g_ConstantBufferUploadHeap[i]->Map(0, &EMPTY_RANGE, &g_ConstantBufferAddress[i]) );
708     }
709 
710     // create input layout
711 
712     // The input layout is used by the Input Assembler so that it knows
713     // how to read the vertex data bound to it.
714 
715     const D3D12_INPUT_ELEMENT_DESC inputLayout[] =
716     {
717         { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT,    0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
718         { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,       0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
719     };
720 
721     // create a pipeline state object (PSO)
722 
723     // In a real application, you will have many pso's. for each different shader
724     // or different combinations of shaders, different blend states or different rasterizer states,
725     // different topology types (point, line, triangle, patch), or a different number
726     // of render targets you will need a pso
727 
728     // VS is the only required shader for a pso. You might be wondering when a case would be where
729     // you only set the VS. It's possible that you have a pso that only outputs data with the stream
730     // output, and not on a render target, which means you would not need anything after the stream
731     // output.
732 
733     D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; // a structure to define a pso
734     psoDesc.InputLayout.NumElements = _countof(inputLayout);
735     psoDesc.InputLayout.pInputElementDescs = inputLayout;
736     psoDesc.pRootSignature = g_RootSignature; // the root signature that describes the input data this pso needs
737     psoDesc.VS.BytecodeLength = sizeof(VS::g_main);
738     psoDesc.VS.pShaderBytecode = VS::g_main;
739     psoDesc.PS.BytecodeLength = sizeof(PS::g_main);
740     psoDesc.PS.pShaderBytecode = PS::g_main;
741     psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; // type of topology we are drawing
742     psoDesc.RTVFormats[0] = RENDER_TARGET_FORMAT; // format of the render target
743     psoDesc.DSVFormat = DEPTH_STENCIL_FORMAT;
744     psoDesc.SampleDesc = sampleDesc; // must be the same sample description as the swapchain and depth/stencil buffer
745     psoDesc.SampleMask = 0xffffffff; // sample mask has to do with multi-sampling. 0xffffffff means point sampling is done
746     SetDefaultRasterizerDesc(psoDesc.RasterizerState);
747     SetDefaultBlendDesc(psoDesc.BlendState);
748     psoDesc.NumRenderTargets = 1; // we are only binding one render target
749     SetDefaultDepthStencilDesc(psoDesc.DepthStencilState);
750 
751     // create the pso
752     ID3D12PipelineState* pipelineStateObject;
753     CHECK_HR( device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&pipelineStateObject)) );
754     g_PipelineStateObject.Attach(pipelineStateObject);
755 
756     // Create vertex buffer
757 
758     // a triangle
759     Vertex vList[] = {
760         // front face
761         { -0.5f,  0.5f, -0.5f, 0.f, 0.f },
762         {  0.5f, -0.5f, -0.5f, 1.f, 1.f },
763         { -0.5f, -0.5f, -0.5f, 0.f, 1.f },
764         {  0.5f,  0.5f, -0.5f, 1.f, 0.f },
765 
766         // right side face
767         {  0.5f, -0.5f, -0.5f, 0.f, 1.f },
768         {  0.5f,  0.5f,  0.5f, 1.f, 0.f },
769         {  0.5f, -0.5f,  0.5f, 1.f, 1.f },
770         {  0.5f,  0.5f, -0.5f, 0.f, 0.f },
771 
772         // left side face
773         { -0.5f,  0.5f,  0.5f, 0.f, 0.f },
774         { -0.5f, -0.5f, -0.5f, 1.f, 1.f },
775         { -0.5f, -0.5f,  0.5f, 0.f, 1.f },
776         { -0.5f,  0.5f, -0.5f, 1.f, 0.f },
777 
778         // back face
779         {  0.5f,  0.5f,  0.5f, 0.f, 0.f },
780         { -0.5f, -0.5f,  0.5f, 1.f, 1.f },
781         {  0.5f, -0.5f,  0.5f, 0.f, 1.f },
782         { -0.5f,  0.5f,  0.5f, 1.f, 0.f },
783 
784         // top face
785         { -0.5f,  0.5f, -0.5f, 0.f, 0.f },
786         {  0.5f,  0.5f,  0.5f, 1.f, 1.f },
787         {  0.5f,  0.5f, -0.5f, 0.f, 1.f },
788         { -0.5f,  0.5f,  0.5f, 1.f, 0.f },
789 
790         // bottom face
791         {  0.5f, -0.5f,  0.5f, 0.f, 0.f },
792         { -0.5f, -0.5f, -0.5f, 1.f, 1.f },
793         {  0.5f, -0.5f, -0.5f, 0.f, 1.f },
794         { -0.5f, -0.5f,  0.5f, 1.f, 0.f },
795     };
796     const uint32_t vBufferSize = sizeof(vList);
797 
798     // create default heap
799     // default heap is memory on the GPU. Only the GPU has access to this memory
800     // To get data into this heap, we will have to upload the data using
801     // an upload heap
802     D3D12MA::ALLOCATION_DESC vertexBufferAllocDesc = {};
803     vertexBufferAllocDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT;
804     D3D12_RESOURCE_DESC vertexBufferResourceDesc = {};
805     vertexBufferResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
806     vertexBufferResourceDesc.Alignment = 0;
807     vertexBufferResourceDesc.Width = vBufferSize;
808     vertexBufferResourceDesc.Height = 1;
809     vertexBufferResourceDesc.DepthOrArraySize = 1;
810     vertexBufferResourceDesc.MipLevels = 1;
811     vertexBufferResourceDesc.Format = DXGI_FORMAT_UNKNOWN;
812     vertexBufferResourceDesc.SampleDesc.Count = 1;
813     vertexBufferResourceDesc.SampleDesc.Quality = 0;
814     vertexBufferResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
815     vertexBufferResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
816     ID3D12Resource* vertexBufferPtr;
817     CHECK_HR( g_Allocator->CreateResource(
818         &vertexBufferAllocDesc,
819         &vertexBufferResourceDesc, // resource description for a buffer
820         D3D12_RESOURCE_STATE_COPY_DEST, // we will start this heap in the copy destination state since we will copy data
821                                         // from the upload heap to this heap
822         nullptr, // optimized clear value must be null for this type of resource. used for render targets and depth/stencil buffers
823         &g_VertexBufferAllocation,
824         IID_PPV_ARGS(&vertexBufferPtr)) );
825     g_VertexBuffer.Attach(vertexBufferPtr);
826 
827     // we can give resource heaps a name so when we debug with the graphics debugger we know what resource we are looking at
828     g_VertexBuffer->SetName(L"Vertex Buffer Resource Heap");
829 
830     // create upload heap
831     // upload heaps are used to upload data to the GPU. CPU can write to it, GPU can read from it
832     // We will upload the vertex buffer using this heap to the default heap
833     D3D12MA::ALLOCATION_DESC vBufferUploadAllocDesc = {};
834     vBufferUploadAllocDesc.HeapType = D3D12_HEAP_TYPE_UPLOAD;
835     D3D12_RESOURCE_DESC vertexBufferUploadResourceDesc = {};
836     vertexBufferUploadResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
837     vertexBufferUploadResourceDesc.Alignment = 0;
838     vertexBufferUploadResourceDesc.Width = vBufferSize;
839     vertexBufferUploadResourceDesc.Height = 1;
840     vertexBufferUploadResourceDesc.DepthOrArraySize = 1;
841     vertexBufferUploadResourceDesc.MipLevels = 1;
842     vertexBufferUploadResourceDesc.Format = DXGI_FORMAT_UNKNOWN;
843     vertexBufferUploadResourceDesc.SampleDesc.Count = 1;
844     vertexBufferUploadResourceDesc.SampleDesc.Quality = 0;
845     vertexBufferUploadResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
846     vertexBufferUploadResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
847     CComPtr<ID3D12Resource> vBufferUploadHeap;
848     D3D12MA::Allocation* vBufferUploadHeapAllocation = nullptr;
849     CHECK_HR( g_Allocator->CreateResource(
850         &vBufferUploadAllocDesc,
851         &vertexBufferUploadResourceDesc, // resource description for a buffer
852         D3D12_RESOURCE_STATE_GENERIC_READ, // GPU will read from this buffer and copy its contents to the default heap
853         nullptr,
854         &vBufferUploadHeapAllocation,
855         IID_PPV_ARGS(&vBufferUploadHeap)) );
856     vBufferUploadHeap->SetName(L"Vertex Buffer Upload Resource Heap");
857 
858     // store vertex buffer in upload heap
859     D3D12_SUBRESOURCE_DATA vertexData = {};
860     vertexData.pData = reinterpret_cast<BYTE*>(vList); // pointer to our vertex array
861     vertexData.RowPitch = vBufferSize; // size of all our triangle vertex data
862     vertexData.SlicePitch = vBufferSize; // also the size of our triangle vertex data
863 
864     CHECK_HR( g_CommandList->Reset(g_CommandAllocators[g_FrameIndex], NULL) );
865 
866     // we are now creating a command with the command list to copy the data from
867     // the upload heap to the default heap
868     UINT64 r = UpdateSubresources(g_CommandList, g_VertexBuffer, vBufferUploadHeap, 0, 0, 1, &vertexData);
869     assert(r);
870 
871     // transition the vertex buffer data from copy destination state to vertex buffer state
872     D3D12_RESOURCE_BARRIER vbBarrier = {};
873     vbBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
874     vbBarrier.Transition.pResource = g_VertexBuffer;
875     vbBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
876     vbBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
877     vbBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
878     g_CommandList->ResourceBarrier(1, &vbBarrier);
879 
880     // Create index buffer
881 
882     // a quad (2 triangles)
883     uint16_t iList[] = {
884         // ffront face
885         0, 1, 2, // first triangle
886         0, 3, 1, // second triangle
887 
888         // left face
889         4, 5, 6, // first triangle
890         4, 7, 5, // second triangle
891 
892         // right face
893         8, 9, 10, // first triangle
894         8, 11, 9, // second triangle
895 
896         // back face
897         12, 13, 14, // first triangle
898         12, 15, 13, // second triangle
899 
900         // top face
901         16, 17, 18, // first triangle
902         16, 19, 17, // second triangle
903 
904         // bottom face
905         20, 21, 22, // first triangle
906         20, 23, 21, // second triangle
907     };
908 
909     g_CubeIndexCount = (uint32_t)_countof(iList);
910 
911     size_t iBufferSize = sizeof(iList);
912 
913     // create default heap to hold index buffer
914     D3D12MA::ALLOCATION_DESC indexBufferAllocDesc = {};
915     indexBufferAllocDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT;
916     D3D12_RESOURCE_DESC indexBufferResourceDesc = {};
917     indexBufferResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
918     indexBufferResourceDesc.Alignment = 0;
919     indexBufferResourceDesc.Width = iBufferSize;
920     indexBufferResourceDesc.Height = 1;
921     indexBufferResourceDesc.DepthOrArraySize = 1;
922     indexBufferResourceDesc.MipLevels = 1;
923     indexBufferResourceDesc.Format = DXGI_FORMAT_UNKNOWN;
924     indexBufferResourceDesc.SampleDesc.Count = 1;
925     indexBufferResourceDesc.SampleDesc.Quality = 0;
926     indexBufferResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
927     indexBufferResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
928     CHECK_HR( g_Allocator->CreateResource(
929         &indexBufferAllocDesc,
930         &indexBufferResourceDesc, // resource description for a buffer
931         D3D12_RESOURCE_STATE_COPY_DEST, // start in the copy destination state
932         nullptr, // optimized clear value must be null for this type of resource
933         &g_IndexBufferAllocation,
934         IID_PPV_ARGS(&g_IndexBuffer)) );
935 
936     // we can give resource heaps a name so when we debug with the graphics debugger we know what resource we are looking at
937     g_IndexBuffer->SetName(L"Index Buffer Resource Heap");
938 
939     // create upload heap to upload index buffer
940     D3D12MA::ALLOCATION_DESC iBufferUploadAllocDesc = {};
941     iBufferUploadAllocDesc.HeapType = D3D12_HEAP_TYPE_UPLOAD;
942     D3D12_RESOURCE_DESC indexBufferUploadResourceDesc = {};
943     indexBufferUploadResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
944     indexBufferUploadResourceDesc.Alignment = 0;
945     indexBufferUploadResourceDesc.Width = iBufferSize;
946     indexBufferUploadResourceDesc.Height = 1;
947     indexBufferUploadResourceDesc.DepthOrArraySize = 1;
948     indexBufferUploadResourceDesc.MipLevels = 1;
949     indexBufferUploadResourceDesc.Format = DXGI_FORMAT_UNKNOWN;
950     indexBufferUploadResourceDesc.SampleDesc.Count = 1;
951     indexBufferUploadResourceDesc.SampleDesc.Quality = 0;
952     indexBufferUploadResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
953     indexBufferUploadResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
954     CComPtr<ID3D12Resource> iBufferUploadHeap;
955     D3D12MA::Allocation* iBufferUploadHeapAllocation = nullptr;
956     CHECK_HR( g_Allocator->CreateResource(
957         &iBufferUploadAllocDesc,
958         &indexBufferUploadResourceDesc, // resource description for a buffer
959         D3D12_RESOURCE_STATE_GENERIC_READ, // GPU will read from this buffer and copy its contents to the default heap
960         nullptr,
961         &iBufferUploadHeapAllocation,
962         IID_PPV_ARGS(&iBufferUploadHeap)) );
963     CHECK_HR( iBufferUploadHeap->SetName(L"Index Buffer Upload Resource Heap") );
964 
965     // store vertex buffer in upload heap
966     D3D12_SUBRESOURCE_DATA indexData = {};
967     indexData.pData = iList; // pointer to our index array
968     indexData.RowPitch = iBufferSize; // size of all our index buffer
969     indexData.SlicePitch = iBufferSize; // also the size of our index buffer
970 
971                                         // we are now creating a command with the command list to copy the data from
972                                         // the upload heap to the default heap
973     r = UpdateSubresources(g_CommandList, g_IndexBuffer, iBufferUploadHeap, 0, 0, 1, &indexData);
974     assert(r);
975 
976     // transition the index buffer data from copy destination state to vertex buffer state
977     D3D12_RESOURCE_BARRIER ibBarrier = {};
978     ibBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
979     ibBarrier.Transition.pResource = g_IndexBuffer;
980     ibBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
981     ibBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_INDEX_BUFFER;
982     ibBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
983     g_CommandList->ResourceBarrier(1, &ibBarrier);
984 
985     // create a vertex buffer view for the triangle. We get the GPU memory address to the vertex pointer using the GetGPUVirtualAddress() method
986     g_VertexBufferView.BufferLocation = g_VertexBuffer->GetGPUVirtualAddress();
987     g_VertexBufferView.StrideInBytes = sizeof(Vertex);
988     g_VertexBufferView.SizeInBytes = vBufferSize;
989 
990     // create a index buffer view for the triangle. We get the GPU memory address to the vertex pointer using the GetGPUVirtualAddress() method
991     g_IndexBufferView.BufferLocation = g_IndexBuffer->GetGPUVirtualAddress();
992     g_IndexBufferView.Format = DXGI_FORMAT_R16_UINT;
993     g_IndexBufferView.SizeInBytes = (UINT)iBufferSize;
994 
995     D3D12MA::ALLOCATION_DESC cbPerObjectUploadAllocDesc = {};
996     cbPerObjectUploadAllocDesc.HeapType = D3D12_HEAP_TYPE_UPLOAD;
997     D3D12_RESOURCE_DESC cbPerObjectUploadResourceDesc = {};
998     cbPerObjectUploadResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
999     cbPerObjectUploadResourceDesc.Alignment = 0;
1000     cbPerObjectUploadResourceDesc.Width = 1024 * 64;
1001     cbPerObjectUploadResourceDesc.Height = 1;
1002     cbPerObjectUploadResourceDesc.DepthOrArraySize = 1;
1003     cbPerObjectUploadResourceDesc.MipLevels = 1;
1004     cbPerObjectUploadResourceDesc.Format = DXGI_FORMAT_UNKNOWN;
1005     cbPerObjectUploadResourceDesc.SampleDesc.Count = 1;
1006     cbPerObjectUploadResourceDesc.SampleDesc.Quality = 0;
1007     cbPerObjectUploadResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
1008     cbPerObjectUploadResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
1009     for (size_t i = 0; i < FRAME_BUFFER_COUNT; ++i)
1010     {
1011         // create resource for cube 1
1012         CHECK_HR( g_Allocator->CreateResource(
1013             &cbPerObjectUploadAllocDesc,
1014             &cbPerObjectUploadResourceDesc, // size of the resource heap. Must be a multiple of 64KB for single-textures and constant buffers
1015             D3D12_RESOURCE_STATE_GENERIC_READ, // will be data that is read from so we keep it in the generic read state
1016             nullptr, // we do not have use an optimized clear value for constant buffers
1017             &g_CbPerObjectUploadHeapAllocations[i],
1018             IID_PPV_ARGS(&g_CbPerObjectUploadHeaps[i])) );
1019         g_CbPerObjectUploadHeaps[i]->SetName(L"Constant Buffer Upload Resource Heap");
1020 
1021         CHECK_HR( g_CbPerObjectUploadHeaps[i]->Map(0, &EMPTY_RANGE, &g_CbPerObjectAddress[i]) );
1022     }
1023 
1024     // # TEXTURE
1025 
1026     D3D12_RESOURCE_DESC textureDesc;
1027     size_t imageBytesPerRow;
1028     size_t imageSize = SIZE_MAX;
1029     std::vector<char> imageData;
1030     {
1031         const UINT sizeX = 256;
1032         const UINT sizeY = 256;
1033         const DXGI_FORMAT format = DXGI_FORMAT_R8G8B8A8_UNORM;
1034         const UINT bytesPerPixel = 4;
1035 
1036         imageBytesPerRow = sizeX * bytesPerPixel;
1037         imageSize = sizeY * imageBytesPerRow;
1038 
1039         imageData.resize(imageSize);
1040         char* rowPtr = (char*)imageData.data();
1041         for(UINT y = 0; y < sizeY; ++y)
1042         {
1043             char* pixelPtr = rowPtr;
1044             for(UINT x = 0; x < sizeX; ++x)
1045             {
1046                 *(UINT8*)(pixelPtr    ) = (UINT8)x; // R
1047                 *(UINT8*)(pixelPtr + 1) = (UINT8)y; // G
1048                 *(UINT8*)(pixelPtr + 2) = 0x00; // B
1049                 *(UINT8*)(pixelPtr + 3) = 0xFF; // A
1050 
1051                 *(UINT8*)(pixelPtr    ) = x > 128 ? 0xFF : 00;
1052                 *(UINT8*)(pixelPtr + 1) = y > 128 ? 0xFF : 00;
1053                 pixelPtr += bytesPerPixel;
1054             }
1055             rowPtr += imageBytesPerRow;
1056         }
1057 
1058         textureDesc = {};
1059         textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
1060         textureDesc.Alignment = 0;
1061         textureDesc.Width = sizeX;
1062         textureDesc.Height = sizeY;
1063         textureDesc.DepthOrArraySize = 1;
1064         textureDesc.MipLevels = 1;
1065         textureDesc.Format = format;
1066         textureDesc.SampleDesc.Count = 1;
1067         textureDesc.SampleDesc.Quality = 0;
1068         textureDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
1069         textureDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
1070     }
1071 
1072     D3D12MA::ALLOCATION_DESC textureAllocDesc = {};
1073     textureAllocDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT;
1074     CHECK_HR( g_Allocator->CreateResource(
1075         &textureAllocDesc,
1076         &textureDesc,
1077         D3D12_RESOURCE_STATE_COPY_DEST,
1078         nullptr, // pOptimizedClearValue
1079         &g_TextureAllocation,
1080         IID_PPV_ARGS(&g_Texture)) );
1081     g_Texture->SetName(L"g_Texture");
1082 
1083     UINT64 textureUploadBufferSize;
1084     device->GetCopyableFootprints(
1085         &textureDesc,
1086         0, // FirstSubresource
1087         1, // NumSubresources
1088         0, // BaseOffset
1089         nullptr, // pLayouts
1090         nullptr, // pNumRows
1091         nullptr, // pRowSizeInBytes
1092         &textureUploadBufferSize); // pTotalBytes
1093 
1094     D3D12MA::ALLOCATION_DESC textureUploadAllocDesc = {};
1095     textureUploadAllocDesc.HeapType = D3D12_HEAP_TYPE_UPLOAD;
1096     D3D12_RESOURCE_DESC textureUploadResourceDesc = {};
1097     textureUploadResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
1098     textureUploadResourceDesc.Alignment = 0;
1099     textureUploadResourceDesc.Width = textureUploadBufferSize;
1100     textureUploadResourceDesc.Height = 1;
1101     textureUploadResourceDesc.DepthOrArraySize = 1;
1102     textureUploadResourceDesc.MipLevels = 1;
1103     textureUploadResourceDesc.Format = DXGI_FORMAT_UNKNOWN;
1104     textureUploadResourceDesc.SampleDesc.Count = 1;
1105     textureUploadResourceDesc.SampleDesc.Quality = 0;
1106     textureUploadResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
1107     textureUploadResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
1108     CComPtr<ID3D12Resource> textureUpload;
1109     D3D12MA::Allocation* textureUploadAllocation;
1110     CHECK_HR( g_Allocator->CreateResource(
1111         &textureUploadAllocDesc,
1112         &textureUploadResourceDesc,
1113         D3D12_RESOURCE_STATE_GENERIC_READ,
1114         nullptr, // pOptimizedClearValue
1115         &textureUploadAllocation,
1116         IID_PPV_ARGS(&textureUpload)) );
1117     textureUpload->SetName(L"textureUpload");
1118 
1119     D3D12_SUBRESOURCE_DATA textureSubresourceData = {};
1120     textureSubresourceData.pData = imageData.data();
1121     textureSubresourceData.RowPitch = imageBytesPerRow;
1122     textureSubresourceData.SlicePitch = imageBytesPerRow * textureDesc.Height;
1123 
1124     UpdateSubresources(g_CommandList, g_Texture, textureUpload, 0, 0, 1, &textureSubresourceData);
1125 
1126     D3D12_RESOURCE_BARRIER textureBarrier = {};
1127     textureBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
1128     textureBarrier.Transition.pResource = g_Texture;
1129     textureBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
1130     textureBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
1131     textureBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
1132     g_CommandList->ResourceBarrier(1, &textureBarrier);
1133 
1134     D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
1135     srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
1136     srvDesc.Format = textureDesc.Format;
1137     srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
1138     srvDesc.Texture2D.MipLevels = 1;
1139     for (size_t i = 0; i < FRAME_BUFFER_COUNT; ++i)
1140     {
1141         D3D12_CPU_DESCRIPTOR_HANDLE descHandle = {
1142             g_MainDescriptorHeap[i]->GetCPUDescriptorHandleForHeapStart().ptr +
1143             g_Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)};
1144         g_Device->CreateShaderResourceView(g_Texture, &srvDesc, descHandle);
1145     }
1146 
1147     // # END OF INITIAL COMMAND LIST
1148 
1149     // Now we execute the command list to upload the initial assets (triangle data)
1150     g_CommandList->Close();
1151     ID3D12CommandList* ppCommandLists[] = { g_CommandList };
1152     commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);
1153 
1154     // increment the fence value now, otherwise the buffer might not be uploaded by the time we start drawing
1155     WaitGPUIdle(g_FrameIndex);
1156 
1157     textureUploadAllocation->Release();
1158     iBufferUploadHeapAllocation->Release();
1159     vBufferUploadHeapAllocation->Release();
1160 }
1161 
Update()1162 void Update()
1163 {
1164     {
1165         const float f = sin(g_Time * (PI * 2.f)) * 0.5f + 0.5f;
1166         ConstantBuffer0_PS cb;
1167         cb.Color = vec4(f, f, f, 1.f);
1168         memcpy(g_ConstantBufferAddress[g_FrameIndex], &cb, sizeof(cb));
1169     }
1170 
1171     {
1172         const mat4 projection = mat4::Perspective(
1173             45.f * (PI / 180.f), // fovY
1174             (float)SIZE_X / (float)SIZE_Y, // aspectRatio
1175             0.1f, // zNear
1176             1000.0f); // zFar
1177         const mat4 view = mat4::LookAt(
1178             vec3(0.f, 0.f, 0.f), // at
1179             vec3(-.4f, 1.7f, -3.5f), // eye
1180             vec3(0.f, 1.f, 0.f)); // up
1181         const mat4 viewProjection = view * projection;
1182 
1183         mat4 cube1World = mat4::RotationZ(g_Time);
1184 
1185         ConstantBuffer1_VS cb;
1186         mat4 worldViewProjection = cube1World * viewProjection;
1187         cb.WorldViewProj = worldViewProjection.Transposed();
1188         memcpy(g_CbPerObjectAddress[g_FrameIndex], &cb, sizeof(cb));
1189 
1190         mat4 cube2World = mat4::Scaling(0.5f) *
1191             mat4::RotationX(g_Time * 2.0f) *
1192             mat4::Translation(vec3(-1.2f, 0.f, 0.f)) *
1193             cube1World;
1194 
1195         worldViewProjection = cube2World * viewProjection;
1196         cb.WorldViewProj = worldViewProjection.Transposed();
1197         memcpy((char*)g_CbPerObjectAddress[g_FrameIndex] + ConstantBufferPerObjectAlignedSize, &cb, sizeof(cb));
1198     }
1199 }
1200 
Render()1201 void Render() // execute the command list
1202 {
1203     // # Here was UpdatePipeline function.
1204 
1205     // swap the current rtv buffer index so we draw on the correct buffer
1206     g_FrameIndex = g_SwapChain->GetCurrentBackBufferIndex();
1207     // We have to wait for the gpu to finish with the command allocator before we reset it
1208     WaitForFrame(g_FrameIndex);
1209     // increment g_FenceValues for next frame
1210     g_FenceValues[g_FrameIndex]++;
1211 
1212     // we can only reset an allocator once the gpu is done with it
1213     // resetting an allocator frees the memory that the command list was stored in
1214     CHECK_HR( g_CommandAllocators[g_FrameIndex]->Reset() );
1215 
1216     // reset the command list. by resetting the command list we are putting it into
1217     // a recording state so we can start recording commands into the command allocator.
1218     // the command allocator that we reference here may have multiple command lists
1219     // associated with it, but only one can be recording at any time. Make sure
1220     // that any other command lists associated to this command allocator are in
1221     // the closed state (not recording).
1222     // Here you will pass an initial pipeline state object as the second parameter,
1223     // but in this tutorial we are only clearing the rtv, and do not actually need
1224     // anything but an initial default pipeline, which is what we get by setting
1225     // the second parameter to NULL
1226     CHECK_HR( g_CommandList->Reset(g_CommandAllocators[g_FrameIndex], NULL) );
1227 
1228     // here we start recording commands into the g_CommandList (which all the commands will be stored in the g_CommandAllocators)
1229 
1230     // transition the "g_FrameIndex" render target from the present state to the render target state so the command list draws to it starting from here
1231     D3D12_RESOURCE_BARRIER presentToRenderTargetBarrier = {};
1232     presentToRenderTargetBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
1233     presentToRenderTargetBarrier.Transition.pResource = g_RenderTargets[g_FrameIndex];
1234     presentToRenderTargetBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
1235     presentToRenderTargetBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
1236     presentToRenderTargetBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
1237     g_CommandList->ResourceBarrier(1, &presentToRenderTargetBarrier);
1238 
1239     // here we again get the handle to our current render target view so we can set it as the render target in the output merger stage of the pipeline
1240     D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = {
1241         g_RtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart().ptr + g_FrameIndex * g_RtvDescriptorSize};
1242     D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle =
1243         g_DepthStencilDescriptorHeap->GetCPUDescriptorHandleForHeapStart();
1244 
1245     // set the render target for the output merger stage (the output of the pipeline)
1246     g_CommandList->OMSetRenderTargets(1, &rtvHandle, FALSE, &dsvHandle);
1247 
1248     g_CommandList->ClearDepthStencilView(g_DepthStencilDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr);
1249 
1250     // Clear the render target by using the ClearRenderTargetView command
1251     const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
1252     g_CommandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);
1253 
1254     g_CommandList->SetPipelineState(g_PipelineStateObject);
1255 
1256     g_CommandList->SetGraphicsRootSignature(g_RootSignature);
1257 
1258     ID3D12DescriptorHeap* descriptorHeaps[] = { g_MainDescriptorHeap[g_FrameIndex] };
1259     g_CommandList->SetDescriptorHeaps(_countof(descriptorHeaps), descriptorHeaps);
1260 
1261     g_CommandList->SetGraphicsRootDescriptorTable(0, g_MainDescriptorHeap[g_FrameIndex]->GetGPUDescriptorHandleForHeapStart());
1262     g_CommandList->SetGraphicsRootDescriptorTable(2, g_MainDescriptorHeap[g_FrameIndex]->GetGPUDescriptorHandleForHeapStart());
1263 
1264     D3D12_VIEWPORT viewport{0.f, 0.f, (float)SIZE_X, (float)SIZE_Y, 0.f, 1.f};
1265     g_CommandList->RSSetViewports(1, &viewport); // set the viewports
1266 
1267     D3D12_RECT scissorRect{0, 0, SIZE_X, SIZE_Y};
1268     g_CommandList->RSSetScissorRects(1, &scissorRect); // set the scissor rects
1269 
1270     g_CommandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); // set the primitive topology
1271     g_CommandList->IASetVertexBuffers(0, 1, &g_VertexBufferView); // set the vertex buffer (using the vertex buffer view)
1272     g_CommandList->IASetIndexBuffer(&g_IndexBufferView);
1273 
1274     g_CommandList->SetGraphicsRootConstantBufferView(1,
1275         g_CbPerObjectUploadHeaps[g_FrameIndex]->GetGPUVirtualAddress());
1276     g_CommandList->DrawIndexedInstanced(g_CubeIndexCount, 1, 0, 0, 0);
1277 
1278     g_CommandList->SetGraphicsRootConstantBufferView(1,
1279         g_CbPerObjectUploadHeaps[g_FrameIndex]->GetGPUVirtualAddress() + ConstantBufferPerObjectAlignedSize);
1280     g_CommandList->DrawIndexedInstanced(g_CubeIndexCount, 1, 0, 0, 0);
1281 
1282     // transition the "g_FrameIndex" render target from the render target state to the present state. If the debug layer is enabled, you will receive a
1283     // warning if present is called on the render target when it's not in the present state
1284     D3D12_RESOURCE_BARRIER renderTargetToPresentBarrier = {};
1285     renderTargetToPresentBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
1286     renderTargetToPresentBarrier.Transition.pResource = g_RenderTargets[g_FrameIndex];
1287     renderTargetToPresentBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
1288     renderTargetToPresentBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
1289     renderTargetToPresentBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
1290     g_CommandList->ResourceBarrier(1, &renderTargetToPresentBarrier);
1291 
1292     CHECK_HR( g_CommandList->Close() );
1293 
1294     // ================
1295 
1296     // create an array of command lists (only one command list here)
1297     ID3D12CommandList* ppCommandLists[] = { g_CommandList };
1298 
1299     // execute the array of command lists
1300     g_CommandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);
1301 
1302     // this command goes in at the end of our command queue. we will know when our command queue
1303     // has finished because the g_Fences value will be set to "g_FenceValues" from the GPU since the command
1304     // queue is being executed on the GPU
1305     CHECK_HR( g_CommandQueue->Signal(g_Fences[g_FrameIndex], g_FenceValues[g_FrameIndex]) );
1306 
1307     // present the current backbuffer
1308     CHECK_HR( g_SwapChain->Present(PRESENT_SYNC_INTERVAL, 0) );
1309 }
1310 
Cleanup()1311 void Cleanup() // release com ojects and clean up memory
1312 {
1313     // wait for the gpu to finish all frames
1314     for (size_t i = 0; i < FRAME_BUFFER_COUNT; ++i)
1315     {
1316         WaitForFrame(i);
1317         CHECK_HR( g_CommandQueue->Wait(g_Fences[i], g_FenceValues[i]) );
1318     }
1319 
1320     // get swapchain out of full screen before exiting
1321     BOOL fs = false;
1322     CHECK_HR( g_SwapChain->GetFullscreenState(&fs, NULL) );
1323     if (fs)
1324         g_SwapChain->SetFullscreenState(false, NULL);
1325 
1326     WaitGPUIdle(0);
1327 
1328     g_Texture.Release();
1329     g_TextureAllocation->Release(); g_TextureAllocation = nullptr;
1330     g_IndexBuffer.Release();
1331     g_IndexBufferAllocation->Release(); g_IndexBufferAllocation = nullptr;
1332     g_VertexBuffer.Release();
1333     g_VertexBufferAllocation->Release(); g_VertexBufferAllocation = nullptr;
1334     g_PipelineStateObject.Release();
1335     g_RootSignature.Release();
1336 
1337     CloseHandle(g_FenceEvent);
1338     g_CommandList.Release();
1339     g_CommandQueue.Release();
1340 
1341     for (size_t i = FRAME_BUFFER_COUNT; i--; )
1342     {
1343         g_CbPerObjectUploadHeaps[i].Release();
1344         g_CbPerObjectUploadHeapAllocations[i]->Release(); g_CbPerObjectUploadHeapAllocations[i] = nullptr;
1345         g_MainDescriptorHeap[i].Release();
1346         g_ConstantBufferUploadHeap[i].Release();
1347         g_ConstantBufferUploadAllocation[i]->Release(); g_ConstantBufferUploadAllocation[i] = nullptr;
1348     }
1349 
1350     g_DepthStencilDescriptorHeap.Release();
1351     g_DepthStencilBuffer.Release();
1352     g_DepthStencilAllocation->Release(); g_DepthStencilAllocation = nullptr;
1353     g_RtvDescriptorHeap.Release();
1354     for (size_t i = FRAME_BUFFER_COUNT; i--; )
1355     {
1356         g_RenderTargets[i].Release();
1357         g_CommandAllocators[i].Release();
1358         g_Fences[i].Release();
1359     }
1360 
1361     g_Allocator->Release(); g_Allocator = nullptr;
1362     if(ENABLE_CPU_ALLOCATION_CALLBACKS)
1363     {
1364         assert(g_CpuAllocationCount.load() == 0);
1365     }
1366 
1367     g_Device.Release();
1368     g_SwapChain.Release();
1369 }
1370 
ExecuteTests()1371 static void ExecuteTests()
1372 {
1373     try
1374     {
1375         TestContext ctx = {};
1376         ctx.allocationCallbacks = &g_AllocationCallbacks;
1377         ctx.device = g_Device;
1378         ctx.allocator = g_Allocator;
1379         ctx.allocatorFlags = g_AllocatorFlags;
1380         Test(ctx);
1381     }
1382     catch(const std::exception& ex)
1383     {
1384         wprintf(L"ERROR: %hs\n", ex.what());
1385     }
1386 }
1387 
OnKeyDown(WPARAM key)1388 static void OnKeyDown(WPARAM key)
1389 {
1390     switch (key)
1391     {
1392     case 'T':
1393         ExecuteTests();
1394         break;
1395 
1396     case 'J':
1397         {
1398             WCHAR* statsString = NULL;
1399             g_Allocator->BuildStatsString(&statsString, TRUE);
1400             wprintf(L"%s\n", statsString);
1401             g_Allocator->FreeStatsString(statsString);
1402         }
1403         break;
1404 
1405     case VK_ESCAPE:
1406         PostMessage(g_Wnd, WM_CLOSE, 0, 0);
1407         break;
1408     }
1409 }
1410 
WndProc(HWND wnd,UINT msg,WPARAM wParam,LPARAM lParam)1411 static LRESULT WINAPI WndProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
1412 {
1413     switch(msg)
1414     {
1415     case WM_CREATE:
1416         g_Wnd = wnd;
1417         InitD3D();
1418         g_TimeOffset = GetTickCount64();
1419         return 0;
1420 
1421     case WM_DESTROY:
1422         Cleanup();
1423         PostQuitMessage(0);
1424         return 0;
1425 
1426     case WM_KEYDOWN:
1427         OnKeyDown(wParam);
1428         return 0;
1429     }
1430 
1431     return DefWindowProc(wnd, msg, wParam, lParam);
1432 }
1433 
BeginCommandList()1434 ID3D12GraphicsCommandList* BeginCommandList()
1435 {
1436     CHECK_HR( g_CommandList->Reset(g_CommandAllocators[g_FrameIndex], NULL) );
1437 
1438     return g_CommandList;
1439 }
1440 
EndCommandList(ID3D12GraphicsCommandList * cmdList)1441 void EndCommandList(ID3D12GraphicsCommandList* cmdList)
1442 {
1443     cmdList->Close();
1444 
1445     ID3D12CommandList* genericCmdList = cmdList;
1446     g_CommandQueue->ExecuteCommandLists(1, &genericCmdList);
1447 
1448     WaitGPUIdle(g_FrameIndex);
1449 }
1450 
main()1451 int main()
1452 {
1453     g_Instance = (HINSTANCE)GetModuleHandle(NULL);
1454 
1455     CoInitialize(NULL);
1456 
1457     WNDCLASSEX wndClass;
1458     ZeroMemory(&wndClass, sizeof(wndClass));
1459     wndClass.cbSize = sizeof(wndClass);
1460     wndClass.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
1461     wndClass.hbrBackground = NULL;
1462     wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
1463     wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
1464     wndClass.hInstance = g_Instance;
1465     wndClass.lpfnWndProc = &WndProc;
1466     wndClass.lpszClassName = CLASS_NAME;
1467 
1468     ATOM classR = RegisterClassEx(&wndClass);
1469     assert(classR);
1470 
1471     DWORD style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE;
1472     DWORD exStyle = 0;
1473 
1474     RECT rect = { 0, 0, SIZE_X, SIZE_Y };
1475     AdjustWindowRectEx(&rect, style, FALSE, exStyle);
1476     g_Wnd = CreateWindowEx(
1477         exStyle,
1478         CLASS_NAME,
1479         WINDOW_TITLE,
1480         style,
1481         CW_USEDEFAULT, CW_USEDEFAULT,
1482         rect.right - rect.left, rect.bottom - rect.top,
1483         NULL,
1484         NULL,
1485         g_Instance,
1486         0);
1487     assert(g_Wnd);
1488 
1489     MSG msg;
1490     for (;;)
1491     {
1492         if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
1493         {
1494             if (msg.message == WM_QUIT)
1495                 break;
1496             TranslateMessage(&msg);
1497             DispatchMessage(&msg);
1498         }
1499         else
1500         {
1501             const UINT64 newTimeValue = GetTickCount64() - g_TimeOffset;
1502             g_TimeDelta = (float)(newTimeValue - g_TimeValue) * 0.001f;
1503             g_TimeValue = newTimeValue;
1504             g_Time = (float)newTimeValue * 0.001f;
1505 
1506             Update();
1507             Render();
1508         }
1509     }
1510     return (int)msg.wParam;
1511 }
1512