void D3D12PipelineStateCache::OnKeyUp(WPARAM key)
{
	switch (key)
	{
	case 'C':
		WaitForGpu();
		m_psoLibrary.ClearPSOCache();
		break;

	case 'U':
		m_psoLibrary.ToggleUberShader();
		break;

	case 'L':
		m_psoLibrary.ToggleDiskLibrary();
		break;

	case '1':
		ToggleEffect(PostBlit);
		break;

	case '2':
		ToggleEffect(PostInvert);
		break;

	case '3':
		ToggleEffect(PostGrayScale);
		break;

	case '4':
		ToggleEffect(PostEdgeDetect);
		break;

	case '5':
		ToggleEffect(PostBlur);
		break;

	case '6':
		ToggleEffect(PostWarp);
		break;

	case '7':
		ToggleEffect(PostPixelate);
		break;

	case '8':
		ToggleEffect(PostDistort);
		break;

	case '9':
		ToggleEffect(PostWave);
		break;

	default:
		break;
	}

	UpdateWindowTextPso();
}
void D3D12PipelineStateCache::OnInit()
{
	UpdateWindowTextPso();
	m_camera.Init({ 0.0f, 0.0f, 5.0f });
	m_camera.SetMoveSpeed(1.0f);

	m_projectionMatrix = m_camera.GetProjectionMatrix(0.8f, m_aspectRatio);

	LoadPipeline();
	LoadAssets();
}
void D3D12PipelineStateCache::OnKeyUp(UINT8 key)
{
	m_camera.OnKeyUp(key);
	
	switch (key)
	{
	case 'C':
		WaitForGpu();
		m_psoLibrary.ClearPSOCache();
		m_psoLibrary.Build(m_device.Get(), m_rootSignature.Get());
		break;

	case 'U':
		m_psoLibrary.ToggleUberShader();
		break;

	case 'L':
		m_psoLibrary.ToggleDiskLibrary();
		break;

	case 'M':
		m_psoLibrary.SwitchPSOCachingMechanism();
		break;

	case '1':
		ToggleEffect(PostBlit);
		break;

	case '2':
		ToggleEffect(PostInvert);
		break;

	case '3':
		ToggleEffect(PostGrayScale);
		break;

	case '4':
		ToggleEffect(PostEdgeDetect);
		break;

	case '5':
		ToggleEffect(PostBlur);
		break;

	case '6':
		ToggleEffect(PostWarp);
		break;

	case '7':
		ToggleEffect(PostPixelate);
		break;

	case '8':
		ToggleEffect(PostDistort);
		break;

	case '9':
		ToggleEffect(PostWave);
		break;

	default:
		break;
	}

	UpdateWindowTextPso();
}
void D3D12PipelineStateCache::LoadAssets()
{
	// Create the root signature.
	{
		D3D12_FEATURE_DATA_ROOT_SIGNATURE featureData = {};

		// This is the highest version the sample supports. If CheckFeatureSupport succeeds, the HighestVersion returned will not be greater than this.
		featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_1;

		if (FAILED(m_device->CheckFeatureSupport(D3D12_FEATURE_ROOT_SIGNATURE, &featureData, sizeof(featureData))))
		{
			featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_0;
		}

		CD3DX12_DESCRIPTOR_RANGE1 ranges[RootParametersCount];
		ranges[RootParameterSRV].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC);

		CD3DX12_ROOT_PARAMETER1 rootParameters[RootParametersCount];
		rootParameters[RootParameterUberShaderCB].InitAsConstantBufferView(0, 0, D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC, D3D12_SHADER_VISIBILITY_ALL);
		rootParameters[RootParameterCB].InitAsConstantBufferView(1, 0, D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC, D3D12_SHADER_VISIBILITY_ALL);
		rootParameters[RootParameterSRV].InitAsDescriptorTable(1, &ranges[RootParameterSRV]);

		D3D12_STATIC_SAMPLER_DESC sampler = {};
		sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
		sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
		sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
		sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
		sampler.MipLODBias = 0;
		sampler.MaxAnisotropy = 0;
		sampler.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
		sampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;
		sampler.MinLOD = 0.0f;
		sampler.MaxLOD = 9999.0f;
		sampler.ShaderRegister = 0;
		sampler.RegisterSpace = 0;
		sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;

		CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc;
		rootSignatureDesc.Init_1_1(_countof(rootParameters), rootParameters, 1, &sampler, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);

		ComPtr<ID3DBlob> signature;
		ComPtr<ID3DBlob> error;
		ThrowIfFailed(D3DX12SerializeVersionedRootSignature(&rootSignatureDesc, featureData.HighestVersion, &signature, &error));
		ThrowIfFailed(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature)));
		NAME_D3D12_OBJECT(m_rootSignature);
	}

	// Create the command list.
	ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocators[m_frameIndex].Get(), nullptr, IID_PPV_ARGS(&m_commandList)));
	NAME_D3D12_OBJECT(m_commandList);

	// Note: ComPtr's are CPU objects but this resource needs to stay in scope until
	// the command list that references it has finished executing on the GPU.
	// We will flush the GPU at the end of this method to ensure the resource is not
	// prematurely destroyed.
	ComPtr<ID3D12Resource> vertexIndexBufferUpload;

	// Vertex and Index Buffer.
	{
		const VertexPositionColor cubeVertices[] = {
			{ { -1.0f, 1.0f, -1.0f, 1.0f }, { GetRandomColor(),GetRandomColor(), GetRandomColor() } },	// Back Top Left
			{ { 1.0f, 1.0f, -1.0f, 1.0f }, { GetRandomColor(), GetRandomColor(), GetRandomColor() } },	// Back Top Right
			{ { 1.0f, 1.0f, 1.0f, 1.0f }, { GetRandomColor(), GetRandomColor(), GetRandomColor() } },	// Front Top Right
			{ { -1.0f, 1.0f, 1.0f, 1.0f }, { GetRandomColor(), GetRandomColor(), GetRandomColor() } },	// Front Top Left

			{ { -1.0f, -1.0f, -1.0f, 1.0f }, { GetRandomColor(),GetRandomColor(), GetRandomColor() } },	// Back Bottom Left
			{ { 1.0f, -1.0f, -1.0f, 1.0f }, { GetRandomColor(),GetRandomColor(), GetRandomColor() } },	// Back Bottom Right
			{ { 1.0f, -1.0f, 1.0f, 1.0f }, { GetRandomColor(),GetRandomColor(), GetRandomColor() } },	// Front Bottom Right
			{ { -1.0f, -1.0f, 1.0f, 1.0f }, { GetRandomColor(),GetRandomColor(), GetRandomColor() } },	// Front Bottom Left
		};

		const UINT cubeIndices[] =
		{
			0, 1, 3,
			1, 2, 3,

			3, 2, 7,
			6, 7, 2,

			2, 1, 6,
			5, 6, 1,

			1, 0, 5,
			4, 5, 0,

			0, 3, 4,
			7, 4, 3,

			7, 6, 4,
			5, 4, 6,
		};

		static const VertexPositionUV quadVertices[] =
		{
			{ { -1.0f, -1.0f, 0.0f, 1.0f }, { 0.0f, 1.0f } },	// Bottom Left
			{ { -1.0f, 1.0f, 0.0f, 1.0f }, { 0.0f, 0.0f } },	// Top Left
			{ { 1.0f, -1.0f, 0.0f, 1.0f }, { 1.0f, 1.0f } },	// Bottom Right
			{ { 1.0f, 1.0f, 0.0f, 1.0f }, { 1.0f, 0.0f } },		// Top Right
		};

		const UINT vertexIndexBufferSize = sizeof(cubeIndices) + sizeof(cubeVertices) + sizeof(quadVertices);

		ThrowIfFailed(m_device->CreateCommittedResource(
			&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
			D3D12_HEAP_FLAG_NONE,
			&CD3DX12_RESOURCE_DESC::Buffer(vertexIndexBufferSize),
			D3D12_RESOURCE_STATE_COPY_DEST,
			nullptr,
			IID_PPV_ARGS(&m_vertexIndexBuffer)));

		ThrowIfFailed(m_device->CreateCommittedResource(
			&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
			D3D12_HEAP_FLAG_NONE,
			&CD3DX12_RESOURCE_DESC::Buffer(vertexIndexBufferSize),
			D3D12_RESOURCE_STATE_GENERIC_READ,
			nullptr,
			IID_PPV_ARGS(&vertexIndexBufferUpload)));

		NAME_D3D12_OBJECT(m_vertexIndexBuffer);

		UINT8* mappedUploadHeap = nullptr;
		CD3DX12_RANGE readRange(0, 0);		// We do not intend to read from this resource on the CPU.
		ThrowIfFailed(vertexIndexBufferUpload->Map(0, &readRange, reinterpret_cast<void**>(&mappedUploadHeap)));

		// Fill in part of the upload heap with our index and vertex data.
		UINT8* heapLocation = static_cast<UINT8*>(mappedUploadHeap);
		memcpy(heapLocation, cubeVertices, sizeof(cubeVertices));
		heapLocation += sizeof(cubeVertices);
		memcpy(heapLocation, cubeIndices, sizeof(cubeIndices));
		heapLocation += sizeof(cubeIndices);
		memcpy(heapLocation, quadVertices, sizeof(quadVertices));

		// Pack the vertices and indices into their destination by copying from the upload heap.
		m_commandList->CopyBufferRegion(m_vertexIndexBuffer.Get(), 0, vertexIndexBufferUpload.Get(), 0, vertexIndexBufferSize);
		m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_vertexIndexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER | D3D12_RESOURCE_STATE_INDEX_BUFFER));

		// Create the index and vertex buffer views.
		m_cubeVbv.BufferLocation = m_vertexIndexBuffer.Get()->GetGPUVirtualAddress();
		m_cubeVbv.SizeInBytes = sizeof(cubeVertices);
		m_cubeVbv.StrideInBytes = sizeof(VertexPositionColor);

		m_cubeIbv.BufferLocation = m_cubeVbv.BufferLocation + sizeof(cubeVertices);
		m_cubeIbv.SizeInBytes = sizeof(cubeIndices);
		m_cubeIbv.Format = DXGI_FORMAT_R32_UINT;

		m_quadVbv.BufferLocation = m_cubeIbv.BufferLocation + sizeof(cubeIndices);
		m_quadVbv.SizeInBytes = sizeof(quadVertices);
		m_quadVbv.StrideInBytes = sizeof(VertexPositionUV);
	}

	// Create the constant buffer.
	m_dynamicCB.Init(m_device.Get());

	// Close the command list and execute it to begin the vertex/index buffer copy
	// into the default heap.
	ThrowIfFailed(m_commandList->Close());
	ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() };
	m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);

	// Create synchronization objects and wait until assets have been uploaded to the GPU.
	{
		ThrowIfFailed(m_device->CreateFence(m_fenceValues[m_frameIndex], D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence)));
		m_fenceValues[m_frameIndex]++;

		// 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.
		WaitForGpu();
	}

	m_psoLibrary.Build(m_device.Get(), m_rootSignature.Get());
	UpdateWindowTextPso();
}