#include "RenderThread.h"

#include "../frames/InputFrameMailbox.h"
#include "InputFrameTexture.h"
#include "readback/Bgra8ReadbackPipeline.h"

RenderThread::Metrics RenderThread::GetMetrics() const
{
	Metrics metrics;
	metrics.renderedFrames = mRenderedFrames.load(std::memory_order_relaxed);
	metrics.completedReadbacks = mCompletedReadbacks.load(std::memory_order_relaxed);
	metrics.acquireMisses = mAcquireMisses.load(std::memory_order_relaxed);
	metrics.pboQueueMisses = mPboQueueMisses.load(std::memory_order_relaxed);
	metrics.clockOverruns = mClockOverruns.load(std::memory_order_relaxed);
	metrics.skippedFrames = mSkippedFrames.load(std::memory_order_relaxed);
	metrics.shaderBuildsCommitted = mShaderBuildsCommitted.load(std::memory_order_relaxed);
	metrics.shaderBuildFailures = mShaderBuildFailures.load(std::memory_order_relaxed);
	metrics.renderFrameMilliseconds = mRenderFrameMilliseconds.load(std::memory_order_relaxed);
	metrics.renderFrameBudgetUsedPercent = mRenderFrameBudgetUsedPercent.load(std::memory_order_relaxed);
	metrics.renderFrameMaxMilliseconds = mRenderFrameMaxMilliseconds.load(std::memory_order_relaxed);
	metrics.readbackQueueMilliseconds = mReadbackQueueMilliseconds.load(std::memory_order_relaxed);
	metrics.completedReadbackCopyMilliseconds = mCompletedReadbackCopyMilliseconds.load(std::memory_order_relaxed);
	metrics.inputFramesReceived = mInputFramesReceived.load(std::memory_order_relaxed);
	metrics.inputFramesDropped = mInputFramesDropped.load(std::memory_order_relaxed);
	metrics.inputConsumeMisses = mInputConsumeMisses.load(std::memory_order_relaxed);
	metrics.inputUploadMisses = mInputUploadMisses.load(std::memory_order_relaxed);
	metrics.inputReadyFrames = mInputReadyFrames.load(std::memory_order_relaxed);
	metrics.inputReadingFrames = mInputReadingFrames.load(std::memory_order_relaxed);
	metrics.inputLatestAgeMilliseconds = mInputLatestAgeMilliseconds.load(std::memory_order_relaxed);
	metrics.inputUploadMilliseconds = mInputUploadMilliseconds.load(std::memory_order_relaxed);
	metrics.inputFormatSupported = mInputFormatSupported.load(std::memory_order_relaxed);
	metrics.inputSignalPresent = mInputSignalPresent.load(std::memory_order_relaxed);
	return metrics;
}

void RenderThread::CountRendered()
{
	mRenderedFrames.fetch_add(1, std::memory_order_relaxed);
}

void RenderThread::CountCompleted()
{
	mCompletedReadbacks.fetch_add(1, std::memory_order_relaxed);
}

void RenderThread::CountAcquireMiss()
{
	mAcquireMisses.fetch_add(1, std::memory_order_relaxed);
}

void RenderThread::PublishReadbackMetrics(const Bgra8ReadbackPipeline& readback)
{
	const double renderMilliseconds = readback.LastRenderFrameMilliseconds();
	mRenderFrameMilliseconds.store(renderMilliseconds, std::memory_order_relaxed);
	if (mConfig.frameDurationMilliseconds > 0.0)
	{
		mRenderFrameBudgetUsedPercent.store(
			(renderMilliseconds / mConfig.frameDurationMilliseconds) * 100.0,
			std::memory_order_relaxed);
	}
	else
	{
		mRenderFrameBudgetUsedPercent.store(0.0, std::memory_order_relaxed);
	}

	const double previousMax = mRenderFrameMaxMilliseconds.load(std::memory_order_relaxed);
	if (renderMilliseconds > previousMax)
		mRenderFrameMaxMilliseconds.store(renderMilliseconds, std::memory_order_relaxed);

	mReadbackQueueMilliseconds.store(readback.LastReadbackQueueMilliseconds(), std::memory_order_relaxed);
	mCompletedReadbackCopyMilliseconds.store(readback.LastCompletedReadbackCopyMilliseconds(), std::memory_order_relaxed);
}

void RenderThread::PublishInputMetrics(const InputFrameTexture& inputTexture)
{
	if (mInputMailbox != nullptr)
	{
		const InputFrameMailboxMetrics mailboxMetrics = mInputMailbox->Metrics();
		mInputFramesReceived.store(mailboxMetrics.submittedFrames, std::memory_order_relaxed);
		mInputFramesDropped.store(mailboxMetrics.droppedReadyFrames + mailboxMetrics.submitMisses, std::memory_order_relaxed);
		mInputConsumeMisses.store(mailboxMetrics.consumeMisses, std::memory_order_relaxed);
		mInputReadyFrames.store(mailboxMetrics.readyCount, std::memory_order_relaxed);
		mInputReadingFrames.store(mailboxMetrics.readingCount, std::memory_order_relaxed);
		mInputLatestAgeMilliseconds.store(mailboxMetrics.latestFrameAgeMilliseconds, std::memory_order_relaxed);
		mInputSignalPresent.store(mailboxMetrics.hasSubmittedFrame, std::memory_order_relaxed);
	}
	else
	{
		mInputFramesReceived.store(0, std::memory_order_relaxed);
		mInputFramesDropped.store(0, std::memory_order_relaxed);
		mInputConsumeMisses.store(0, std::memory_order_relaxed);
		mInputReadyFrames.store(0, std::memory_order_relaxed);
		mInputReadingFrames.store(0, std::memory_order_relaxed);
		mInputLatestAgeMilliseconds.store(0.0, std::memory_order_relaxed);
		mInputSignalPresent.store(false, std::memory_order_relaxed);
	}

	mInputUploadMisses.store(inputTexture.UploadMisses(), std::memory_order_relaxed);
	mInputUploadMilliseconds.store(inputTexture.LastUploadMilliseconds(), std::memory_order_relaxed);
	mInputFormatSupported.store(inputTexture.LastFrameFormatSupported(), std::memory_order_relaxed);
}
