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 "D3D12HelloConstBuffers.h"
  
  D3D12HelloConstBuffers::D3D12HelloConstBuffers(UINT width, UINT height, std::wstring name) :
  	DXSample(width, height, name),
  	m_frameIndex(0),
  	m_pCbvDataBegin(nullptr),
  	m_viewport(),
  	m_scissorRect(),
  	m_rtvDescriptorSize(0)
  {
  	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 D3D12HelloConstBuffers::OnInit()
  {
  	LoadPipeline();
  	LoadAssets();
  }
  
  // Load the rendering pipeline dependencies.
  void D3D12HelloConstBuffers::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)));
  
  	// 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->CreateSwapChainForHwnd(
  		m_commandQueue.Get(),		// Swap chain needs the queue so that it can force a flush on it.
  		Win32Application::GetHwnd(),
  		&swapChainDesc,
  		nullptr,
  		nullptr,
  		&swapChain
  		));
  
  	// This sample does not support fullscreen transitions.
  	ThrowIfFailed(factory->MakeWindowAssociation(Win32Application::GetHwnd(), DXGI_MWA_NO_ALT_ENTER));
  
  	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)));
  
  		m_rtvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
  
  		// Describe and create a constant buffer view (CBV) descriptor heap.
  		// Flags indicate that this descriptor heap can be bound to the pipeline 
  		// and that descriptors contained in it can be referenced by a root table.
  		D3D12_DESCRIPTOR_HEAP_DESC cbvHeapDesc = {};
  		cbvHeapDesc.NumDescriptors = 1;
  		cbvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
  		cbvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
  		ThrowIfFailed(m_device->CreateDescriptorHeap(&cbvHeapDesc, IID_PPV_ARGS(&m_cbvHeap)));
  	}
  
  	// Create frame resources.
  	{
  		CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart());
  
  		// Create a RTV for each frame.
  		for (UINT n = 0; n < FrameCount; n++)
  		{
  			ThrowIfFailed(m_swapChain->GetBuffer(n, IID_PPV_ARGS(&m_renderTargets[n])));
  			m_device->CreateRenderTargetView(m_renderTargets[n].Get(), nullptr, rtvHandle);
  			rtvHandle.Offset(1, m_rtvDescriptorSize);
  		}
  	}
  
  	ThrowIfFailed(m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_commandAllocator)));
  }
  
  // Load the sample assets.
  void D3D12HelloConstBuffers::LoadAssets()
  {
  	// Create a root signature consisting of a descriptor table with a single CBV.
  	{
  		CD3DX12_DESCRIPTOR_RANGE ranges[1];
  		CD3DX12_ROOT_PARAMETER rootParameters[1];
  
  		ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0);
  		rootParameters[0].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_VERTEX);
  
  		// Allow input layout and deny uneccessary access to certain pipeline stages.
  		D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags =
  			D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |
  			D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS |
  			D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
  			D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS |
  			D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS;
  
  		CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc;
  		rootSignatureDesc.Init(_countof(rootParameters), rootParameters, 0, nullptr, rootSignatureFlags);
  
  		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)));
  	}
  
  	// Create the pipeline state, which includes compiling and loading shaders.
  	{
  		ComPtr<ID3DBlob> vertexShader;
  		ComPtr<ID3DBlob> pixelShader;
  
  #if defined(_DEBUG)
  		// Enable better shader debugging with the graphics debugging tools.
  		UINT compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
  #else
  		UINT compileFlags = 0;
  #endif
  
  		ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "VSMain", "vs_5_0", compileFlags, 0, &vertexShader, nullptr));
  		ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "PSMain", "ps_5_0", compileFlags, 0, &pixelShader, nullptr));
  
  		// Define the vertex input layout.
  		D3D12_INPUT_ELEMENT_DESC inputElementDescs[] =
  		{
  			{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  			{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }
  		};
  
  		// Describe and create the graphics pipeline state object (PSO).
  		D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
  		psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) };
  		psoDesc.pRootSignature = m_rootSignature.Get();
  		psoDesc.VS = CD3DX12_SHADER_BYTECODE(vertexShader.Get());
  		psoDesc.PS = CD3DX12_SHADER_BYTECODE(pixelShader.Get());
  		psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
  		psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
  		psoDesc.DepthStencilState.DepthEnable = FALSE;
  		psoDesc.DepthStencilState.StencilEnable = FALSE;
  		psoDesc.SampleMask = UINT_MAX;
  		psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
  		psoDesc.NumRenderTargets = 1;
  		psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
  		psoDesc.SampleDesc.Count = 1;
  
  		ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineState)));
  	}
  
  	// Create the command list.
  	ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocator.Get(), m_pipelineState.Get(), IID_PPV_ARGS(&m_commandList)));
  
  	// Command lists are created in the recording state, but there is nothing
  	// to record yet. The main loop expects it to be closed, so close it now.
  	ThrowIfFailed(m_commandList->Close());
  
  	// Create the vertex buffer.
  	{
  		// Define the geometry for a triangle.
  		Vertex triangleVertices[] =
  		{
  			{ { 0.0f, 0.25f * m_aspectRatio, 0.0f }, { 1.0f, 0.0f, 0.0f, 1.0f } },
  			{ { 0.25f, -0.25f * m_aspectRatio, 0.0f }, { 0.0f, 1.0f, 0.0f, 1.0f } },
  			{ { -0.25f, -0.25f * m_aspectRatio, 0.0f }, { 0.0f, 0.0f, 1.0f, 1.0f } }
  		};
  
  		const UINT vertexBufferSize = sizeof(triangleVertices);
  
  		// Note: using upload heaps to transfer static data like vert buffers is not 
  		// recommended. Every time the GPU needs it, the upload heap will be marshalled 
  		// over. Please read up on Default Heap usage. An upload heap is used here for 
  		// code simplicity and because there are very few verts to actually transfer.
  		ThrowIfFailed(m_device->CreateCommittedResource(
  			&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
  			D3D12_HEAP_FLAG_NONE,
  			&CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize),
  			D3D12_RESOURCE_STATE_GENERIC_READ,
  			nullptr,
  			IID_PPV_ARGS(&m_vertexBuffer)));
  
  		// Copy the triangle data to the vertex buffer.
  		UINT8* pVertexDataBegin;
  		CD3DX12_RANGE readRange(0, 0);		// We do not intend to read from this resource on the CPU.
  		ThrowIfFailed(m_vertexBuffer->Map(0, &readRange, reinterpret_cast<void**>(&pVertexDataBegin)));
  		memcpy(pVertexDataBegin, triangleVertices, sizeof(triangleVertices));
  		m_vertexBuffer->Unmap(0, nullptr);
  
  		// Initialize the vertex buffer view.
  		m_vertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress();
  		m_vertexBufferView.StrideInBytes = sizeof(Vertex);
  		m_vertexBufferView.SizeInBytes = vertexBufferSize;
  	}
  
  	// Create the constant buffer.
  	{
  		ThrowIfFailed(m_device->CreateCommittedResource(
  			&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
  			D3D12_HEAP_FLAG_NONE,
  			&CD3DX12_RESOURCE_DESC::Buffer(1024 * 64),
  			D3D12_RESOURCE_STATE_GENERIC_READ,
  			nullptr,
  			IID_PPV_ARGS(&m_constantBuffer)));
  
  		// Describe and create a constant buffer view.
  		D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};
  		cbvDesc.BufferLocation = m_constantBuffer->GetGPUVirtualAddress();
  		cbvDesc.SizeInBytes = (sizeof(ConstantBuffer) + 255) & ~255;	// CB size is required to be 256-byte aligned.
  		m_device->CreateConstantBufferView(&cbvDesc, m_cbvHeap->GetCPUDescriptorHandleForHeapStart());
  
  		// Initialize and map the constant buffers. We don't unmap this until the
  		// app closes. Keeping things mapped for the lifetime of the resource is okay.
  		ZeroMemory(&m_constantBufferData, sizeof(m_constantBufferData));
  
  		CD3DX12_RANGE readRange(0, 0);		// We do not intend to read from this resource on the CPU.
  		ThrowIfFailed(m_constantBuffer->Map(0, &readRange, reinterpret_cast<void**>(&m_pCbvDataBegin)));
  		memcpy(m_pCbvDataBegin, &m_constantBufferData, sizeof(m_constantBufferData));
  	}
  
  	// Create synchronization objects and wait until assets have been uploaded to the GPU.
  	{
  		ThrowIfFailed(m_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence)));
  		m_fenceValue = 1;
  
  		// 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.
  		WaitForPreviousFrame();
  	}
  }
  
  // Update frame-based values.
  void D3D12HelloConstBuffers::OnUpdate()
  {
  	const float translationSpeed = 0.005f;
  	const float offsetBounds = 1.25f;
  
  	m_constantBufferData.offset.x += translationSpeed;
  	if (m_constantBufferData.offset.x > offsetBounds)
  	{
  		m_constantBufferData.offset.x = -offsetBounds;
  	}
  	memcpy(m_pCbvDataBegin, &m_constantBufferData, sizeof(m_constantBufferData));
  }
  
  // Render the scene.
  void D3D12HelloConstBuffers::OnRender()
  {
  	// Record all the commands we need to render the scene into the command list.
  	PopulateCommandList();
  
  	// Execute the command list.
  	ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() };
  	m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);
  
  	// Present the frame.
  	ThrowIfFailed(m_swapChain->Present(1, 0));
  
  	WaitForPreviousFrame();
  }
  
  void D3D12HelloConstBuffers::OnDestroy()
  {
  	// Ensure that the GPU is no longer referencing resources that are about to be
  	// cleaned up by the destructor.
  	WaitForPreviousFrame();
  
  	CloseHandle(m_fenceEvent);
  }
  
  // Fill the command list with all the render commands and dependent state.
  void D3D12HelloConstBuffers::PopulateCommandList()
  {
  	// 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_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_commandAllocator.Get(), m_pipelineState.Get()));
  
  	// Set necessary state.
  	m_commandList->SetGraphicsRootSignature(m_rootSignature.Get());
  
  	ID3D12DescriptorHeap* ppHeaps[] = { m_cbvHeap.Get() };
  	m_commandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps);
  
  	m_commandList->SetGraphicsRootDescriptorTable(0, m_cbvHeap->GetGPUDescriptorHandleForHeapStart());
  	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);
  	m_commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr);
  
  	// Record commands.
  	const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
  	m_commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);
  	m_commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
  	m_commandList->IASetVertexBuffers(0, 1, &m_vertexBufferView);
  	m_commandList->DrawInstanced(3, 1, 0, 0);
  
  	// 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());
  }
  
  void D3D12HelloConstBuffers::WaitForPreviousFrame()
  {
  	// WAITING FOR THE FRAME TO COMPLETE BEFORE CONTINUING IS NOT BEST PRACTICE.
  	// This is code implemented as such for simplicity. The D3D12HelloFrameBuffering
  	// sample illustrates how to use fences for efficient resource usage and to
  	// maximize GPU utilization.
  
  	// Signal and increment the fence value.
  	const UINT64 fence = m_fenceValue;
  	ThrowIfFailed(m_commandQueue->Signal(m_fence.Get(), fence));
  	m_fenceValue++;
  
  	// Wait until the previous frame is finished.
  	if (m_fence->GetCompletedValue() < fence)
  	{
  		ThrowIfFailed(m_fence->SetEventOnCompletion(fence, m_fenceEvent));
  		WaitForSingleObject(m_fenceEvent, INFINITE);
  	}
  
  	m_frameIndex = m_swapChain->GetCurrentBackBufferIndex();
  }
  