text: //*********************************************************
  //
  // Copyright (c) Microsoft. All rights reserved.
  // This code is licensed under the MIT License (MIT).
  // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
  // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
  // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
  // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
  //
  //*********************************************************
  
  #include "stdafx.h"
  #include "D3D12Bundles.h"
  #include "occcity.h"
  
  D3D12Bundles::D3D12Bundles(UINT width, UINT height, std::wstring name) :
  	DXSample(width, height, name),
  	m_frameIndex(0),
  	m_viewport(),
  	m_scissorRect(),
  	m_frameCounter(0),
  	m_fenceValue(0),
  	m_rtvDescriptorSize(0),
  	m_currentFrameResourceIndex(0),
  	m_pCurrentFrameResource(nullptr)
  {
  	m_viewport.Width = static_cast<float>(width);
  	m_viewport.Height = static_cast<float>(height);
  	m_viewport.MaxDepth = 1.0f;
  
  	m_scissorRect.right = static_cast<LONG>(width);
  	m_scissorRect.bottom = static_cast<LONG>(height);
  }
  
  void D3D12Bundles::OnInit()
  {
  	m_camera.Init({ 8, 8, 30 });
  
  	LoadPipeline();
  	LoadAssets();
  }
  
  // Load the rendering pipeline dependencies.
  void D3D12Bundles::LoadPipeline()
  {
  #if defined(_DEBUG)
  	// Enable the D3D12 debug layer.
  	{
  		ComPtr<ID3D12Debug> debugController;
  		if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController))))
  		{
  			debugController->EnableDebugLayer();
  		}
  	}
  #endif
  
  	ComPtr<IDXGIFactory4> factory;
  	ThrowIfFailed(CreateDXGIFactory1(IID_PPV_ARGS(&factory)));
  
  	if (m_useWarpDevice)
  	{
  		ComPtr<IDXGIAdapter> warpAdapter;
  		ThrowIfFailed(factory->EnumWarpAdapter(IID_PPV_ARGS(&warpAdapter)));
  
  		ThrowIfFailed(D3D12CreateDevice(
  			warpAdapter.Get(),
  			D3D_FEATURE_LEVEL_11_0,
  			IID_PPV_ARGS(&m_device)
  			));
  	}
  	else
  	{
  		ComPtr<IDXGIAdapter1> hardwareAdapter;
  		GetHardwareAdapter(factory.Get(), &hardwareAdapter);
  
  		ThrowIfFailed(D3D12CreateDevice(
  			hardwareAdapter.Get(),
  			D3D_FEATURE_LEVEL_11_0,
  			IID_PPV_ARGS(&m_device)
  			));
  	}
  
  	// Describe and create the command queue.
  	D3D12_COMMAND_QUEUE_DESC queueDesc = {};
  	queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
  	queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
  
  	ThrowIfFailed(m_device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&m_commandQueue)));
  	NAME_D3D12_OBJECT(m_commandQueue);
  
  	// Describe and create the swap chain.
  	DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
  	swapChainDesc.BufferCount = FrameCount;
  	swapChainDesc.Width = m_width;
  	swapChainDesc.Height = m_height;
  	swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
  	swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
  	swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
  	swapChainDesc.SampleDesc.Count = 1;
  
  	ComPtr<IDXGISwapChain1> swapChain;
  	ThrowIfFailed(factory->CreateSwapChainForCoreWindow(
  		m_commandQueue.Get(),		// Swap chain needs the queue so that it can force a flush on it.
  		reinterpret_cast<IUnknown*>(Windows::UI::Core::CoreWindow::GetForCurrentThread()),
  		&swapChainDesc,
  		nullptr,
  		&swapChain
  		));
  
  	ThrowIfFailed(swapChain.As(&m_swapChain));
  	m_frameIndex = m_swapChain->GetCurrentBackBufferIndex();
  
  	// Create descriptor heaps.
  	{
  		// Describe and create a render target view (RTV) descriptor heap.
  		D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {};
  		rtvHeapDesc.NumDescriptors = FrameCount;
  		rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
  		rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
  		ThrowIfFailed(m_device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&m_rtvHeap)));
  
  		// Describe and create a depth stencil view (DSV) descriptor heap.
  		D3D12_DESCRIPTOR_HEAP_DESC dsvHeapDesc = {};
  		dsvHeapDesc.NumDescriptors = 1;
  		dsvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
  		dsvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
  		ThrowIfFailed(m_device->CreateDescriptorHeap(&dsvHeapDesc, IID_PPV_ARGS(&m_dsvHeap)));
  
  		// Describe and create a shader resource view (SRV) and constant 
  		// buffer view (CBV) descriptor heap.
  		D3D12_DESCRIPTOR_HEAP_DESC cbvSrvHeapDesc = {};
  		cbvSrvHeapDesc.NumDescriptors =
  			FrameCount * CityRowCount * CityColumnCount		// FrameCount frames * CityRowCount * CityColumnCount.
  			+ 1;											// + 1 for the SRV.
  		cbvSrvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
  		cbvSrvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
  		ThrowIfFailed(m_device->CreateDescriptorHeap(&cbvSrvHeapDesc, IID_PPV_ARGS(&m_cbvSrvHeap)));
  		NAME_D3D12_OBJECT(m_cbvSrvHeap);
  
  		// Describe and create a sampler descriptor heap.
  		D3D12_DESCRIPTOR_HEAP_DESC samplerHeapDesc = {};
  		samplerHeapDesc.NumDescriptors = 1;
  		samplerHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER;
  		samplerHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
  		ThrowIfFailed(m_device->CreateDescriptorHeap(&samplerHeapDesc, IID_PPV_ARGS(&m_samplerHeap)));
  
  		m_rtvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
  		m_cbvSrvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
  	}
  
  	ThrowIfFailed(m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_commandAllocator)));
  }
  
  // Load the sample assets.
  void D3D12Bundles::LoadAssets()
  {
  	// Note: ComPtr's are CPU objects but these resources need to stay in scope until
  	// the command list that references them has finished executing on the GPU.
  	// We will flush the GPU at the end of this method to ensure the resources are not
  	// prematurely destroyed.
  	ComPtr<ID3D12Resource> vertexBufferUploadHeap;
  	ComPtr<ID3D12Resource> indexBufferUploadHeap;
  	ComPtr<ID3D12Resource> textureUploadHeap;
  
  	// Create the root signature.
  	{
  		CD3DX12_DESCRIPTOR_RANGE ranges[3];
  		ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);
  		ranges[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1, 0);
  		ranges[2].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0);
  
  		CD3DX12_ROOT_PARAMETER rootParameters[3];
  		rootParameters[0].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_PIXEL);
  		rootParameters[1].InitAsDescriptorTable(1, &ranges[1], D3D12_SHADER_VISIBILITY_PIXEL);
  		rootParameters[2].InitAsDescriptorTable(1, &ranges[2], D3D12_SHADER_VISIBILITY_ALL);
  
  		CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc;
  		rootSignatureDesc.Init(_countof(rootParameters), rootParameters, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
  
  		ComPtr<ID3DBlob> signature;
  		ComPtr<ID3DBlob> error;
  		ThrowIfFailed(D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error));
  		ThrowIfFailed(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature)));
  		NAME_D3D12_OBJECT(m_rootSignature);
  	}
  
  	// Create the pipeline state, which includes loading shaders.
  	{
  		UINT8* pVertexShaderData;
  		UINT8* pPixelShaderData1;
  		UINT8* pPixelShaderData2;
  		UINT vertexShaderDataLength;
  		UINT pixelShaderDataLength1;
  		UINT pixelShaderDataLength2;
  
  		// Load pre-compiled shaders.
  		ThrowIfFailed(ReadDataFromFile(GetAssetFullPath(L"shader_mesh_simple_vert.cso").c_str(), &pVertexShaderData, &vertexShaderDataLength));
  		ThrowIfFailed(ReadDataFromFile(GetAssetFullPath(L"shader_mesh_simple_pixel.cso").c_str(), &pPixelShaderData1, &pixelShaderDataLength1));
  		ThrowIfFailed(ReadDataFromFile(GetAssetFullPath(L"shader_mesh_alt_pixel.cso").c_str(), &pPixelShaderData2, &pixelShaderDataLength2));
  
  		CD3DX12_RASTERIZER_DESC rasterizerStateDesc(D3D12_DEFAULT);
  		rasterizerStateDesc.CullMode = D3D12_CULL_MODE_NONE;
  
  		// Describe and create the graphics pipeline state objects (PSO).
  		D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
  		psoDesc.InputLayout = { SampleAssets::StandardVertexDescription, SampleAssets::StandardVertexDescriptionNumElements };
  		psoDesc.pRootSignature = m_rootSignature.Get();
  		psoDesc.VS = CD3DX12_SHADER_BYTECODE(pVertexShaderData, vertexShaderDataLength);
  		psoDesc.PS = CD3DX12_SHADER_BYTECODE(pPixelShaderData1, pixelShaderDataLength1);
  		psoDesc.RasterizerState = rasterizerStateDesc;
  		psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
  		psoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
  		psoDesc.SampleMask = UINT_MAX;
  		psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
  		psoDesc.NumRenderTargets = 1;
  		psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
  		psoDesc.DSVFormat = DXGI_FORMAT_D32_FLOAT;
  		psoDesc.SampleDesc.Count = 1;
  
  		ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineState1)));
  		NAME_D3D12_OBJECT(m_pipelineState1);
  
  		// Modify the description to use an alternate pixel shader and create
  		// a second PSO.
  		psoDesc.PS = CD3DX12_SHADER_BYTECODE(pPixelShaderData2, pixelShaderDataLength2);
  
  		ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineState2)));
  		NAME_D3D12_OBJECT(m_pipelineState2);
  
  		delete pVertexShaderData;
  		delete pPixelShaderData1;
  		delete pPixelShaderData2;
  	}
  
  	ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocator.Get(), nullptr, IID_PPV_ARGS(&m_commandList)));
  	NAME_D3D12_OBJECT(m_commandList);
  
  	// Create render target views (RTVs).
  	CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart());
  	for (UINT i = 0; i < FrameCount; i++)
  	{
  		ThrowIfFailed(m_swapChain->GetBuffer(i, IID_PPV_ARGS(&m_renderTargets[i])));
  		m_device->CreateRenderTargetView(m_renderTargets[i].Get(), nullptr, rtvHandle);
  		rtvHandle.Offset(1, m_rtvDescriptorSize);
  
  		NAME_D3D12_OBJECT_INDEXED(m_renderTargets, i);
  	}
  
  	// Read in mesh data for vertex/index buffers.
  	UINT8* pMeshData;
  	UINT meshDataLength;
  	ThrowIfFailed(ReadDataFromFile(GetAssetFullPath(SampleAssets::DataFileName).c_str(), &pMeshData, &meshDataLength));
  
  	// Create the vertex buffer.
  	{
  		ThrowIfFailed(m_device->CreateCommittedResource(
  			&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
  			D3D12_HEAP_FLAG_NONE,
  			&CD3DX12_RESOURCE_DESC::Buffer(SampleAssets::VertexDataSize),
  			D3D12_RESOURCE_STATE_COPY_DEST,
  			nullptr,
  			IID_PPV_ARGS(&m_vertexBuffer)));
  
  		ThrowIfFailed(m_device->CreateCommittedResource(
  			&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
  			D3D12_HEAP_FLAG_NONE,
  			&CD3DX12_RESOURCE_DESC::Buffer(SampleAssets::VertexDataSize),
  			D3D12_RESOURCE_STATE_GENERIC_READ,
  			nullptr,
  			IID_PPV_ARGS(&vertexBufferUploadHeap)));
  
  		NAME_D3D12_OBJECT(m_vertexBuffer);
  
  		// Copy data to the intermediate upload heap and then schedule a copy 
  		// from the upload heap to the vertex buffer.
  		D3D12_SUBRESOURCE_DATA vertexData = {};
  		vertexData.pData = pMeshData + SampleAssets::VertexDataOffset;
  		vertexData.RowPitch = SampleAssets::VertexDataSize;
  		vertexData.SlicePitch = vertexData.RowPitch;
  
  		UpdateSubresources<1>(m_commandList.Get(), m_vertexBuffer.Get(), vertexBufferUploadHeap.Get(), 0, 0, 1, &vertexData);
  		m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_vertexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER));
  
  		// Initialize the vertex buffer view.
  		m_vertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress();
  		m_vertexBufferView.StrideInBytes = SampleAssets::StandardVertexStride;
  		m_vertexBufferView.SizeInBytes = SampleAssets::VertexDataSize;
  	}
  
  	// Create the index buffer.
  	{
  		ThrowIfFailed(m_device->CreateCommittedResource(
  			&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
  			D3D12_HEAP_FLAG_NONE,
  			&CD3DX12_RESOURCE_DESC::Buffer(SampleAssets::IndexDataSize),
  			D3D12_RESOURCE_STATE_COPY_DEST,
  			nullptr,
  			IID_PPV_ARGS(&m_indexBuffer)));
  
  		ThrowIfFailed(m_device->CreateCommittedResource(
  			&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
  			D3D12_HEAP_FLAG_NONE,
  			&CD3DX12_RESOURCE_DESC::Buffer(SampleAssets::IndexDataSize),
  			D3D12_RESOURCE_STATE_GENERIC_READ,
  			nullptr,
  			IID_PPV_ARGS(&indexBufferUploadHeap)));
  
  		NAME_D3D12_OBJECT(m_indexBuffer);
  
  		// Copy data to the intermediate upload heap and then schedule a copy 
  		// from the upload heap to the index buffer.
  		D3D12_SUBRESOURCE_DATA indexData = {};
  		indexData.pData = pMeshData + SampleAssets::IndexDataOffset;
  		indexData.RowPitch = SampleAssets::IndexDataSize;
  		indexData.SlicePitch = indexData.RowPitch;
  
  		UpdateSubresources<1>(m_commandList.Get(), m_indexBuffer.Get(), indexBufferUploadHeap.Get(), 0, 0, 1, &indexData);
  		m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_indexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_INDEX_BUFFER));
  
  		// Describe the index buffer view.
  		m_indexBufferView.BufferLocation = m_indexBuffer->GetGPUVirtualAddress();
  		m_indexBufferView.Format = SampleAssets::StandardIndexFormat;
  		m_indexBufferView.SizeInBytes = SampleAssets::IndexDataSize;
  
  		m_numIndices = SampleAssets::IndexDataSize / 4;	// R32_UINT (SampleAssets::StandardIndexFormat) = 4 bytes each.
  	}
  
  	// Create the texture and sampler.
  	{
  		// Describe and create a Texture2D.
  		D3D12_RESOURCE_DESC textureDesc = {};
  		textureDesc.MipLevels = SampleAssets::Textures[0].MipLevels;
  		textureDesc.Format = SampleAssets::Textures[0].Format;
  		textureDesc.Width = SampleAssets::Textures[0].Width;
  		textureDesc.Height = SampleAssets::Textures[0].Height;
  		textureDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
  		textureDesc.DepthOrArraySize = 1;
  		textureDesc.SampleDesc.Count = 1;
  		textureDesc.SampleDesc.Quality = 0;
  		textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
  
  		ThrowIfFailed(m_device->CreateCommittedResource(
  			&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
  			D3D12_HEAP_FLAG_NONE,
  			&textureDesc,
  			D3D12_RESOURCE_STATE_COPY_DEST,
  			nullptr,
  			IID_PPV_ARGS(&m_texture)));
  
  		NAME_D3D12_OBJECT(m_texture);
  
  		const UINT subresourceCount = textureDesc.DepthOrArraySize * textureDesc.MipLevels;
  		const UINT64 uploadBufferSize = GetRequiredIntermediateSize(m_texture.Get(), 0, subresourceCount);
  
  		ThrowIfFailed(m_device->CreateCommittedResource(
  			&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
  			D3D12_HEAP_FLAG_NONE,
  			&CD3DX12_RESOURCE_DESC::Buffer(uploadBufferSize),
  			D3D12_RESOURCE_STATE_GENERIC_READ,
  			nullptr,
  			IID_PPV_ARGS(&textureUploadHeap)));
  
  		// Copy data to the intermediate upload heap and then schedule a copy 
  		// from the upload heap to the Texture2D.
  		D3D12_SUBRESOURCE_DATA textureData = {};
  		textureData.pData = pMeshData + SampleAssets::Textures[0].Data[0].Offset;
  		textureData.RowPitch = SampleAssets::Textures[0].Data[0].Pitch;
  		textureData.SlicePitch = SampleAssets::Textures[0].Data[0].Size;
  
  		UpdateSubresources(m_commandList.Get(), m_texture.Get(), textureUploadHeap.Get(), 0, 0, subresourceCount, &textureData);
  		m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_texture.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE));
  
  		// Describe and create a sampler.
  		D3D12_SAMPLER_DESC samplerDesc = {};
  		samplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
  		samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
  		samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
  		samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
  		samplerDesc.MinLOD = 0;
  		samplerDesc.MaxLOD = D3D12_FLOAT32_MAX;
  		samplerDesc.MipLODBias = 0.0f;
  		samplerDesc.MaxAnisotropy = 1;
  		samplerDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS;
  		m_device->CreateSampler(&samplerDesc, m_samplerHeap->GetCPUDescriptorHandleForHeapStart());
  
  		// Describe and create a SRV for the texture.
  		D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
  		srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
  		srvDesc.Format = SampleAssets::Textures->Format;
  		srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
  		srvDesc.Texture2D.MipLevels = 1;
  		m_device->CreateShaderResourceView(m_texture.Get(), &srvDesc, m_cbvSrvHeap->GetCPUDescriptorHandleForHeapStart());
  	}
  
  	delete pMeshData;
  
  	// Create the depth stencil view.
  	{
  		D3D12_DEPTH_STENCIL_VIEW_DESC depthStencilDesc = {};
  		depthStencilDesc.Format = DXGI_FORMAT_D32_FLOAT;
  		depthStencilDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
  		depthStencilDesc.Flags = D3D12_DSV_FLAG_NONE;
  
  		D3D12_CLEAR_VALUE depthOptimizedClearValue = {};
  		depthOptimizedClearValue.Format = DXGI_FORMAT_D32_FLOAT;
  		depthOptimizedClearValue.DepthStencil.Depth = 1.0f;
  		depthOptimizedClearValue.DepthStencil.Stencil = 0;
  
  		ThrowIfFailed(m_device->CreateCommittedResource(
  			&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
  			D3D12_HEAP_FLAG_NONE,
  			&CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_D32_FLOAT, m_width, m_height, 1, 0, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL),
  			D3D12_RESOURCE_STATE_DEPTH_WRITE,
  			&depthOptimizedClearValue,
  			IID_PPV_ARGS(&m_depthStencil)
  			));
  
  		NAME_D3D12_OBJECT(m_depthStencil);
  
  		m_device->CreateDepthStencilView(m_depthStencil.Get(), &depthStencilDesc, m_dsvHeap->GetCPUDescriptorHandleForHeapStart());
  	}
  
  	// Close the command list and execute it to begin the initial GPU setup.
  	ThrowIfFailed(m_commandList->Close());
  	ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() };
  	m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);
  
  	CreateFrameResources();
  
  	// Create synchronization objects and wait until assets have been uploaded to the GPU.
  	{
  		ThrowIfFailed(m_device->CreateFence(m_fenceValue, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence)));
  		m_fenceValue++;
  
  		// Create an event handle to use for frame synchronization.
  		m_fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
  		if (m_fenceEvent == nullptr)
  		{
  			ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError()));
  		}
  
  		// Wait for the command list to execute; we are reusing the same command 
  		// list in our main loop but for now, we just want to wait for setup to 
  		// complete before continuing.
  
  		// Signal and increment the fence value.
  		const UINT64 fenceToWaitFor = m_fenceValue;
  		ThrowIfFailed(m_commandQueue->Signal(m_fence.Get(), fenceToWaitFor));
  		m_fenceValue++;
  
  		// Wait until the fence is completed.
  		ThrowIfFailed(m_fence->SetEventOnCompletion(fenceToWaitFor, m_fenceEvent));
  		WaitForSingleObject(m_fenceEvent, INFINITE);
  	}
  }
  
  // Update frame-based values.
  void D3D12Bundles::OnUpdate()
  {
  	m_timer.Tick(NULL);
  
  	if (m_frameCounter == 500)
  	{
  		// Update window text with FPS value.
  		wchar_t fps[64];
  		swprintf_s(fps, L"%ufps", m_timer.GetFramesPerSecond());
  		SetCustomWindowText(fps);
  		m_frameCounter = 0;
  	}
  
  	m_frameCounter++;
  
  	// Get current GPU progress against submitted workload. Resources still scheduled 
  	// for GPU execution cannot be modified or else undefined behavior will result.
  	const UINT64 lastCompletedFence = m_fence->GetCompletedValue();
  
  	// Move to the next frame resource.
  	m_currentFrameResourceIndex = (m_currentFrameResourceIndex + 1) % FrameCount;
  	m_pCurrentFrameResource = m_frameResources[m_currentFrameResourceIndex];
  
  	// Make sure that this frame resource isn't still in use by the GPU.
  	// If it is, wait for it to complete.
  	if (m_pCurrentFrameResource->m_fenceValue != 0 && m_pCurrentFrameResource->m_fenceValue > lastCompletedFence)
  	{
  		ThrowIfFailed(m_fence->SetEventOnCompletion(m_pCurrentFrameResource->m_fenceValue, m_fenceEvent));
  		WaitForSingleObject(m_fenceEvent, INFINITE);
  	}
  
  	m_camera.Update(static_cast<float>(m_timer.GetElapsedSeconds()));
  	m_pCurrentFrameResource->UpdateConstantBuffers(m_camera.GetViewMatrix(), m_camera.GetProjectionMatrix(0.8f, m_aspectRatio));
  }
  
  // Render the scene.
  void D3D12Bundles::OnRender()
  {
  	PIXBeginEvent(m_commandQueue.Get(), 0, L"Render");
  
  	// Record all the commands we need to render the scene into the command list.
  	PopulateCommandList(m_pCurrentFrameResource);
  
  	// Execute the command list.
  	ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() };
  	m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);
  
  	PIXEndEvent(m_commandQueue.Get());
  
  	// Present and update the frame index for the next frame.
  	ThrowIfFailed(m_swapChain->Present(1, 0));
  	m_frameIndex = m_swapChain->GetCurrentBackBufferIndex();
  
  	// Signal and increment the fence value.
  	m_pCurrentFrameResource->m_fenceValue = m_fenceValue;
  	ThrowIfFailed(m_commandQueue->Signal(m_fence.Get(), m_fenceValue));
  	m_fenceValue++;
  }
  
  void D3D12Bundles::OnDestroy()
  {
  	// Ensure that the GPU is no longer referencing resources that are about to be
  	// cleaned up by the destructor.
  	{
  		const UINT64 fence = m_fenceValue;
  		const UINT64 lastCompletedFence = m_fence->GetCompletedValue();
  
  		// Signal and increment the fence value.
  		ThrowIfFailed(m_commandQueue->Signal(m_fence.Get(), m_fenceValue));
  		m_fenceValue++;
  
  		// Wait until the previous frame is finished.
  		if (lastCompletedFence < fence)
  		{
  			ThrowIfFailed(m_fence->SetEventOnCompletion(fence, m_fenceEvent));
  			WaitForSingleObject(m_fenceEvent, INFINITE);
  		}
  	}
  
  	for (UINT i = 0; i < m_frameResources.size(); i++)
  	{
  		delete m_frameResources.at(i);
  	}
  }
  
  void D3D12Bundles::OnKeyDown(UINT8 key)
  {
  	m_camera.OnKeyDown(key);
  }
  
  void D3D12Bundles::OnKeyUp(UINT8 key)
  {
  	m_camera.OnKeyUp(key);
  }
  
  // Create the resources that will be used every frame.
  void D3D12Bundles::CreateFrameResources()
  {
  	ThrowIfFailed(m_commandList->Reset(m_commandAllocator.Get(), m_pipelineState1.Get()));
  
  	// Initialize each frame resource.
  	CD3DX12_CPU_DESCRIPTOR_HANDLE cbvSrvHandle(m_cbvSrvHeap->GetCPUDescriptorHandleForHeapStart(), 1, m_cbvSrvDescriptorSize);	// Move past the SRV in slot 1.
  	for (UINT i = 0; i < FrameCount; i++)
  	{
  		FrameResource* pFrameResource = new FrameResource(m_device.Get(), CityRowCount, CityColumnCount);
  
  		UINT64 cbOffset = 0;
  		for (UINT j = 0; j < CityRowCount; j++)
  		{
  			for (UINT k = 0; k < CityColumnCount; k++)
  			{
  				// Describe and create a constant buffer view (CBV).
  				D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};
  				cbvDesc.BufferLocation = pFrameResource->m_cbvUploadHeap->GetGPUVirtualAddress() + cbOffset;
  				cbvDesc.SizeInBytes = sizeof(FrameResource::ConstantBuffer);
  				cbOffset += cbvDesc.SizeInBytes;
  				m_device->CreateConstantBufferView(&cbvDesc, cbvSrvHandle);
  				cbvSrvHandle.Offset(m_cbvSrvDescriptorSize);
  			}
  		}
  
  		pFrameResource->InitBundle(m_device.Get(), m_pipelineState1.Get(), m_pipelineState2.Get(), i, m_numIndices, &m_indexBufferView,
  			&m_vertexBufferView, m_cbvSrvHeap.Get(), m_cbvSrvDescriptorSize, m_samplerHeap.Get(), m_rootSignature.Get());
  
  		m_frameResources.push_back(pFrameResource);
  	}
  
  	// Close the command list and use it to execute the initial setup.
  	// This places the CBVs in the heap.
  	ThrowIfFailed(m_commandList->Close());
  	ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() };
  	m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);
  }
  
  void D3D12Bundles::PopulateCommandList(FrameResource* pFrameResource)
  {
  	// Command list allocators can only be reset when the associated
  	// command lists have finished execution on the GPU; apps should use
  	// fences to determine GPU execution progress.
  	ThrowIfFailed(m_pCurrentFrameResource->m_commandAllocator->Reset());
  
  	// However, when ExecuteCommandList() is called on a particular command
  	// list, that command list can then be reset at any time and must be before
  	// re-recording.
  	ThrowIfFailed(m_commandList->Reset(m_pCurrentFrameResource->m_commandAllocator.Get(), m_pipelineState1.Get()));
  
  	// Set necessary state.
  	m_commandList->SetGraphicsRootSignature(m_rootSignature.Get());
  
  	ID3D12DescriptorHeap* ppHeaps[] = { m_cbvSrvHeap.Get(), m_samplerHeap.Get() };
  	m_commandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps);
  
  	m_commandList->RSSetViewports(1, &m_viewport);
  	m_commandList->RSSetScissorRects(1, &m_scissorRect);
  
  	// Indicate that the back buffer will be used as a render target.
  	m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));
  
  	CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart(), m_frameIndex, m_rtvDescriptorSize);
  	CD3DX12_CPU_DESCRIPTOR_HANDLE dsvHandle(m_dsvHeap->GetCPUDescriptorHandleForHeapStart());
  	m_commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, &dsvHandle);
  
  	// Record commands.
  	const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
  	m_commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);
  	m_commandList->ClearDepthStencilView(m_dsvHeap->GetCPUDescriptorHandleForHeapStart(), D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr);
  
  	if (UseBundles)
  	{
  		// Execute the prebuilt bundle.
  		m_commandList->ExecuteBundle(pFrameResource->m_bundle.Get());
  	}
  	else
  	{
  		// Populate a new command list.
  		pFrameResource->PopulateCommandList(m_commandList.Get(), m_pipelineState1.Get(), m_pipelineState2.Get(), m_currentFrameResourceIndex, m_numIndices, &m_indexBufferView,
  			&m_vertexBufferView, m_cbvSrvHeap.Get(), m_cbvSrvDescriptorSize, m_samplerHeap.Get(), m_rootSignature.Get());
  	}
  
  	// Indicate that the back buffer will now be used to present.
  	m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
  
  	ThrowIfFailed(m_commandList->Close());
  }
  