Blob Blame Raw


#include "trenderer.h"
#include "trasterfx.h"

#include <algorithm>

#include "tpredictivecachemanager.h"

//************************************************************************************************
//    Preliminaries
//************************************************************************************************

class TPredictiveCacheManagerGenerator : public TRenderResourceManagerGenerator
{
public:
	TPredictiveCacheManagerGenerator() : TRenderResourceManagerGenerator(true) {}

	TRenderResourceManager *operator()(void)
	{
		return new TPredictiveCacheManager;
	}
};

MANAGER_FILESCOPE_DECLARATION_DEP(
	TPredictiveCacheManager,
	TPredictiveCacheManagerGenerator,
	TFxCacheManager::deps())

//-------------------------------------------------------------------------

TPredictiveCacheManager *TPredictiveCacheManager::instance()
{
	return static_cast<TPredictiveCacheManager *>(
		//TPredictiveCacheManager::gen()->getManager(TRenderer::instance())
		TPredictiveCacheManager::gen()->getManager(TRenderer::renderId()));
}

//************************************************************************************************
//    TPredictiveCacheManager::Imp definition
//************************************************************************************************

//=======================
//    PredictionData
//-----------------------

struct PredictionData {
	const ResourceDeclaration *m_decl;
	int m_usageCount;

	PredictionData(const ResourceDeclaration *declaration)
		: m_decl(declaration), m_usageCount(1) {}
};

//============================================================================================

//=====================================
//    TPredictiveCacheManager::Imp
//-------------------------------------

class TPredictiveCacheManager::Imp
{
public:
	int m_renderStatus;
	bool m_enabled;

	std::map<TCacheResourceP, PredictionData> m_resources;
	QMutex m_mutex;

public:
	//Active getResource(..) callback
	typedef void (TPredictiveCacheManager::Imp::*GetResourceFuncPtr)(TCacheResourceP &resource, const string &alias,
																	 const TFxP &fx, double frame, const TRenderSettings &rs,
																	 ResourceDeclaration *resData);

	GetResourceFuncPtr m_getResFuncPtr;

public:
	Imp()
		: m_renderStatus(TRenderer::IDLE), m_getResFuncPtr(&Imp::getResourceComputing), m_enabled(TRenderer::instance().isPrecomputingEnabled()) {}

	void getResourceTestRun(
		TCacheResourceP &resource, const string &alias,
		const TFxP &fx, double frame, const TRenderSettings &rs,
		ResourceDeclaration *resData);

	void getResourceComputing(
		TCacheResourceP &resource, const string &alias,
		const TFxP &fx, double frame, const TRenderSettings &rs,
		ResourceDeclaration *resData);
};

//************************************************************************************************
//    TPredictiveCacheManager methods
//************************************************************************************************

TPredictiveCacheManager::TPredictiveCacheManager()
	: m_imp(new TPredictiveCacheManager::Imp())
{
}

//---------------------------------------------------------------------------

TPredictiveCacheManager::~TPredictiveCacheManager()
{
	delete m_imp;
}

//---------------------------------------------------------------------------

void TPredictiveCacheManager::setMaxTileSize(int maxTileSize)
{
}

//---------------------------------------------------------------------------

void TPredictiveCacheManager::setBPP(int bpp)
{
}

//---------------------------------------------------------------------------

void TPredictiveCacheManager::getResource(
	TCacheResourceP &resource, const string &alias,
	const TFxP &fx, double frame, const TRenderSettings &rs,
	ResourceDeclaration *resData)
{
	if (!m_imp->m_enabled)
		return;

	(m_imp->*(m_imp->m_getResFuncPtr))(resource, alias, fx, frame, rs, resData);
}

//************************************************************************************************
//    Notification-related functions
//************************************************************************************************

void TPredictiveCacheManager::Imp::getResourceTestRun(
	TCacheResourceP &resource, const string &alias,
	const TFxP &fx, double frame, const TRenderSettings &rs,
	ResourceDeclaration *resData)
{
	assert(resData && resData->m_rawData);
	if (!(resData && resData->m_rawData))
		//This is a very rare case. I've seen it happen once in a 'pathologic' case
		//which involved affines truncation while building aliases.
		//The rendering system didn't expect the truncated part 'resurface' in a
		//downstream fx with a slightly different affine alias.

		//TODO: Affines should be coded completely in the aliases... in a compact way though.
		return;

	if (!resource)
		resource = TCacheResourceP(alias, true);

	//Lock against concurrent threads
	//QMutexLocker locker(&m_mutex);    //preComputing is currently single-threaded

	std::map<TCacheResourceP, PredictionData>::iterator it =
		m_resources.find(resource);

	if (it != m_resources.end())
		it->second.m_usageCount++;
	else {
		//Already initializes usageCount at 1
		m_resources.insert(std::make_pair(resource, PredictionData(resData))).first;
	}
}

//---------------------------------------------------------------------------

void TPredictiveCacheManager::Imp::getResourceComputing(
	TCacheResourceP &resource, const string &alias,
	const TFxP &fx, double frame, const TRenderSettings &rs,
	ResourceDeclaration *resData)
{
	//If there is no declaration data, either the request can be resolved in one
	//computation code (therefore it is uninteresting for us), or it was never declared.
	//Anyway, return.
	if (!resData)
		return;

	//NO! The refCount is dynamically depleted - could become 0 from n...
	//assert(!(resData->m_tiles.size() == 1 && resData->m_tiles[0].m_refCount == 1));

	if (!resource)
		resource = TCacheResourceP(alias);

	if (!resource)
		return;

	//Lock against concurrent threads
	QMutexLocker locker(&m_mutex);

	std::map<TCacheResourceP, PredictionData>::iterator it =
		m_resources.find(resource);

	if (it == m_resources.end())
		return;

	if (--it->second.m_usageCount <= 0)
		m_resources.erase(it);
}

//---------------------------------------------------------------------------

void TPredictiveCacheManager::onRenderStatusStart(int renderStatus)
{
	m_imp->m_renderStatus = renderStatus;
	switch (renderStatus) {
	case TRenderer::TESTRUN:
		m_imp->m_getResFuncPtr = &TPredictiveCacheManager::Imp::getResourceTestRun;
		CASE TRenderer::COMPUTING : m_imp->m_getResFuncPtr = &TPredictiveCacheManager::Imp::getResourceComputing;
	}
}

//---------------------------------------------------------------------------

void TPredictiveCacheManager::onRenderStatusEnd(int renderStatus)
{
	switch (renderStatus) {
	case TRenderer::TESTRUN:

		//All resources which have just 1 computation tile, which is also referenced
		//only once, are released.

		std::map<TCacheResourceP, PredictionData>::iterator it;
		for (it = m_imp->m_resources.begin(); it != m_imp->m_resources.end();) {
			const ResourceDeclaration *decl = it->second.m_decl;

			if (decl->m_tiles.size() == 1 && decl->m_tiles[0].m_refCount == 1) {
				std::map<TCacheResourceP, PredictionData>::iterator jt = it++;
				m_imp->m_resources.erase(jt);
			} else
				it++;
		}
	}
}