// Update frame-based values.
void D3D12DynamicIndexing::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));
}
void D3D12PipelineStateCache::UpdateWindowTextPso()
{
	std::wstringstream stringStream;
	stringStream << L"  [Use Uber Shader: ";
	stringStream << (m_psoLibrary.UberShadersEnabled() ? L"true]" : L"false]");
	stringStream << L"   [Use DiskCache: ";

	if (m_psoLibrary.DiskCacheEnabled())
	{
		stringStream << L"true, ";
		switch (m_psoLibrary.GetPSOCachingMechanism())
		{
		case PSOCachingMechanism::CachedBlobs:
				stringStream << L"CachedBlobs]";
				break;
		case PSOCachingMechanism::PipelineLibraries:
			stringStream << L"PipelineLibraries]";
			break;
		}
	}
	else
	{
		stringStream <<  L"false]";
	}

	SetCustomWindowText(stringStream.str().c_str());
}
void D3D12Fullscreen::UpdateTitle() 
{
	// Update resolutions shown in app title.
	wchar_t updatedTitle[256];
	swprintf_s(updatedTitle, L"( %u x %u ) scaled to ( %u x %u )", m_resolutionOptions[m_resolutionIndex].Width, m_resolutionOptions[m_resolutionIndex].Height, m_width, m_height);
	SetCustomWindowText(updatedTitle);
}
// Render the scene.
void D3D12SmallResources::OnRender()
{
	PIXBeginEvent(m_commandQueue.Get(), 0, L"Render");

	// 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);

	PIXEndEvent(m_commandQueue.Get());

	DXGI_QUERY_VIDEO_MEMORY_INFO memoryInfo;
	m_adapter->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &memoryInfo);

	WCHAR text[100];
	WCHAR usageString[20];
	swprintf_s(text, L"[ResourceType: %s] - Memory Used: %s", m_usePlacedResources ? L"Placed" : L"Committed", FormatMemoryUsage(memoryInfo.CurrentUsage, usageString));
	SetCustomWindowText(text);

	// Present the frame.
	ThrowIfFailed(m_swapChain->Present(1, 0));

	MoveToNextFrame();
}
void D3D12HeterogeneousMultiadapter::UpdateWindowTitle()
{
	std::wstringstream stringStream;

	stringStream << L"[" << m_triangleCount << L" triangles]";
	stringStream << L" [Render, " << m_adapterDescs[Primary].Description << ": " << m_drawTimeMovingAverage << L"us" << L" (PS loop count : " << m_psLoopCount<< ")]";
	stringStream << L" [Blur, " << m_adapterDescs[Secondary].Description << ": " << m_blurTimeMovingAverage << L"us" << L" (PS loop count : " << m_blurPSLoopCount << ")]";

	SetCustomWindowText(stringStream.str().c_str());
}
void D3D12PipelineStateCache::UpdateWindowTextPso()
{
	std::wstringstream stringStream;
	stringStream << L"  [Use Uber Shader: ";
	stringStream << (m_psoLibrary.UberShadersEnabled() ? L"true]" : L"false]");
	stringStream << L"   [Use DiskCache: ";
	stringStream << (m_psoLibrary.DiskCacheEnabled() ? L"true]" : L"false]");

	SetCustomWindowText(stringStream.str().c_str());
}
// Render the scene.
void D3D12Multithreading::OnRender()
{
	BeginFrame();

#if SINGLETHREADED
	for (int i = 0; i < NumContexts; i++)
	{
		WorkerThread(reinterpret_cast<LPVOID>(i));
	}
	MidFrame();
	EndFrame();
	m_commandQueue->ExecuteCommandLists(_countof(m_pCurrentFrameResource->m_batchSubmit), m_pCurrentFrameResource->m_batchSubmit);
#else
	for (int i = 0; i < NumContexts; i++)
	{
		SetEvent(m_workerBeginRenderFrame[i]); // Tell each worker to start drawing.
	}

	MidFrame();
	EndFrame();

	WaitForMultipleObjects(NumContexts, m_workerFinishShadowPass, TRUE, INFINITE);

	// You can execute command lists on any thread. Depending on the work 
	// load, apps can choose between using ExecuteCommandLists on one thread 
	// vs ExecuteCommandList from multiple threads.
	m_commandQueue->ExecuteCommandLists(NumContexts + 2, m_pCurrentFrameResource->m_batchSubmit); // Submit PRE, MID and shadows.

	WaitForMultipleObjects(NumContexts, m_workerFinishedRenderFrame, TRUE, INFINITE);

	// Submit remaining command lists.
	m_commandQueue->ExecuteCommandLists(_countof(m_pCurrentFrameResource->m_batchSubmit) - NumContexts - 2, m_pCurrentFrameResource->m_batchSubmit + NumContexts + 2);
#endif

	m_cpuTimer.Tick(NULL);
	if (m_titleCount == TitleThrottle)
	{
		WCHAR cpu[64];
		swprintf_s(cpu, L"%.4f CPU", m_cpuTime / m_titleCount);
		SetCustomWindowText(cpu);

		m_titleCount = 0;
		m_cpuTime = 0;
	}
	else
	{
		m_titleCount++;
		m_cpuTime += m_cpuTimer.GetElapsedSeconds() * 1000;
		m_cpuTimer.ResetElapsedTime();
	}

	// Present and update the frame index for the next frame.
	PIXBeginEvent(m_commandQueue.Get(), 0, L"Presenting to screen");
	ThrowIfFailed(m_swapChain->Present(0, 0));
	PIXEndEvent(m_commandQueue.Get());
	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++;
}