/*
	ZRendererResource.hpp
	Author: James Russell <jcrussell@762studios.com>
	Created: 7/8/2012

	Purpose: 

	A renderer resource is anything that is created by the renderer and is used as part of
	the rendering process.  Generally, renderer resources are objects that act as an interface
	to graphics device state, such as buffers, textures, etc.   

	It should be noted that resources are not safe to be used across multiple threads, even though
	the renderer is multi thread capable.  A resource should only be used within the context of a 
	single thread, and draw calls using that resource should also remain within the same thread 
	(this is done to avoid costly concurrent operations).  
	
	Different resources are free to be used across different threads.

	Usage:

	A renderer resource can be 'available', 'locked', or 'contended'.  When a resource is available, 
	all calls to methods that modify the underlying data (or make the underlying data available for 
	modification) succeed and this will be indicated by the return value.  If the resource is locked
	or contended, the return value of the method will indicate failure to modify the resource.

	If a resource is 'locked', then the resource is currently in the midst of modification.  This
	means that some modification methods will be unavailable.  As an example, 'MapBuffer' cannot 
	be called while the buffer is already mapped, and 'FillBuffer' will fail if a buffer has
	been mapped.  A locked resource can be unlocked and returned to 'available' state before 
	rendering.

	If a resource is contended, this means that the renderer is relying on the data that is currently
	present in graphics memory, as a draw call has been placed using the data at the time of contention.  
	This means that any calls that would allow the user to modify the underlying data will fail.  A
	contended buffer becomes available when the renderer has finished reading the data needed from
	the resource, which will occur at frame end.

	Note that this means that the following set of actions (using an example of ZDataBuffer):

		buffer = dataBuffer->MapBuffer(true);
		...										//Update Buffer
		dataBuffer->UnmapBuffer();

		renderer->SubmitDrawData(...);			//Draw using this buffer

		buffer = dataBuffer->MapBuffer(true);
		...										//Update Buffer
		dataBuffer->UnmapBuffer();

		renderer->SubmitDrawData(...);			//Draw using the updated buffer

		renderer->RenderFrame(...);				//Render this frame

	Will not work.  The second call to 'MapBuffer' will fail because the buffer became contended 
	as soon as the buffer was used as an argument to 'SubmitDrawData'.  The renderer's 'WaitFameEnd' 
	method will enable you to wait until the resource is no longer contended.

	License:

	TODO

*/

#pragma once

#ifndef _ZRENDERERRESOURCE_HPP
#define _ZRENDERERRESOURCE_HPP

#include <ZRenderer/ZRendererBuild.hpp>

class ZRendererResource
{
private:
	DISABLE_COPY_AND_ASSIGN(ZRendererResource);

protected:
	//Counter of 'owners' claiming contention
	int ContentionCount;

	//Flag indicating that this resource has been 'locked'
	bool bIsLocked;

public:
	//Default Constructor
	ZRendererResource();

	//Virtual Destructor
	virtual ~ZRendererResource() { }

	/*
	public ZRendererResource::Available
	
	Returns whether or not this resource is currently available (able to be modified).  
	If a resource is locked or contended, then it is not available for modification.
	
	@return (bool) - true if available, false otherwise
	@context (all)
	*/
	bool IsAvailable();

	/*
	public ZRendererResource::Lock
	
	Locks this resource, making it unavailable for modification.
	
	@return (void)
	@context (all)
	*/
	void Lock();

	/*
	public ZRendererResource::MarkContended
	
	Marks this resource as contended.  Resources should, from this point out,
	understand that modification of the underlying resource should not happen
	until after the frame is drawn that would release this resource from
	contention.  From this point out, the caller 'owns' the resource.

	Resources can be marked as contended by multiple sources, and the resource
	will not be available until all owners who have marked contended have 
	released their claim.

	Generally, this should only be called by the renderer.
	
	@return (void)
	@context (renderer)
	*/
	void MarkContended();

	/*
	public ZRendererResource::ReleaseContended
	
	Removes a previous claim of contention.  If all previous owners have 
	released their contention, then the resource is available.

	@return (void)
	@context (all)
	*/
	void ReleaseContention();

	/*
	public ZRendererResource::Unlock
	
	Unlocks a resource, making it available for modification.
	
	@return (void)
	@context (all)
	*/
	void Unlock();
};

#endif
 
