summaryrefslogtreecommitdiff
path: root/Runtime/GfxDevice/opengles30/DataBuffersGLES30.h
blob: 524dc53f39dcc6ae6cf61f066c95f70a80cee7a7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#pragma once

#include "Configuration/UnityConfigure.h"
#include "Runtime/GfxDevice/GfxDeviceConfigure.h"

#if GFX_SUPPORTS_OPENGLES30

#include "Runtime/GfxDevice/GfxDeviceObjects.h"
#include "Runtime/GfxDevice/GfxDeviceTypes.h"

class BufferManagerGLES30;

enum
{
	kBufferUpdateMinAgeGLES30		= 2 //!< This many frames must be elapsed since last render before next buffer update. \todo [2013-05-31 pyry] From GfxDevice caps
};

class DataBufferGLES30
{
public:
							DataBufferGLES30		(BufferManagerGLES30& bufferManager);
							~DataBufferGLES30		(void);

	void					Release					(void); //!< Release to BufferManager.

	UInt32					GetBuffer				(void) const { return m_buffer; }
	int						GetSize					(void) const { return m_size;	}
	UInt32					GetUsage				(void) const { return m_usage;	}

	void					RecreateStorage			(int size, UInt32 usage);
	void					RecreateWithData		(int size, UInt32 usage, const void* data);

	void					Upload					(int offset, int size, const void* data);

	void*					Map						(int offset, int size, UInt32 mapBits);
	void					FlushMappedRange		(int offset, int size);
	void					Unmap					(void);

	void					RecordRecreate			(int size, UInt32 usage);	//!< Updates storage parameters and recreate time.
	void					RecordUpdate			(void);						//!< Updates last update time if buffer was updated manually.
	void					RecordRender			(void);						//!< Updates last render time.

	UInt32					GetRecreateAge			(void) const;
	UInt32					GetUpdateAge			(void) const;
	UInt32					GetRenderAge			(void) const;

	//! Disown and remove buffer handle. Used if destructor should not try to delete buffer..
	void					Disown					(void);

private:
							DataBufferGLES30		(const DataBufferGLES30& other);
	DataBufferGLES30&		operator=				(const DataBufferGLES30& other);

	BufferManagerGLES30&	m_manager;
	UInt32					m_buffer;
	int						m_size;
	UInt32					m_usage;

	// \note Always used to compute relative age and overflow is handled
	//		 in computation. Thus frame index can safely overflow.
	UInt32					m_lastRecreated;		//!< Last recreated.
	UInt32					m_lastUpdated;			//!< Frame index when last updated.
	UInt32					m_lastRendered;			//!< Frame index when last rendered.
};

// BufferManager
//
// BufferManager is responsible for allocating and maintaining list of free buffer objects that
// could be recycled later on. Buffers are either allocated or recycled based on their properties.
// Most important property for proper use of buffers is to make sure they are not recycled
// too soon after using them for rendering.
//
// BufferManager is only responsible for managing currently free buffers. So user must either
// release or destroy buffer objects manually. User is also responsible of implementing sane
// usage patterns for buffers that it owns (for example not updating data right after buffer
// has been submitted for rendering).
//
// Buffers are associated to the BufferManager that was used to create them. Thus user must either
// destroy buffer, or release it back to same BufferManager.
//
// The best usage pattern for leveraging BufferManager is to always release buffers when there
// is no longer need to preserve the data in buffer object. That way BufferManager takes care
// of recycling buffer when it is appropriate.

class BufferManagerGLES30
{
public:
							BufferManagerGLES30		(void);
							~BufferManagerGLES30	(void);

	//! Acquire a new or recycled buffer. Returns either buffer object that can fit data, or empty buffer (GetSize() == 0).
	DataBufferGLES30*		AcquireBuffer			(int size, UInt32 usage);
	void					ReleaseBuffer			(DataBufferGLES30* buffer);

	void					AdvanceFrame			(void); //!< Advance frame index. Must be called at the end of frame.
	UInt32					GetFrameIndex			(void) const { return m_frameIndex; }

	//!< Invalidate all owned buffers. Used on context loss.
	void					InvalidateAll			(void);

private:
							BufferManagerGLES30		(const BufferManagerGLES30& other);
	BufferManagerGLES30&	operator=				(const BufferManagerGLES30& other);

	void					Clear					(void);

	void					PruneFreeBuffers		(void);
	UInt32					GetTotalFreeSize		(void);

	static inline int		GetSizeClassLimit		(int classNdx) { return classNdx+1 < kSizeClassCount ? (1<<(classNdx*kSizeClassStepLog2 + kSizeClassBaseLog2)) : INT_MAX; }

	void					UpdateLiveSetFromPending(void);
	void					InsertIntoLive			(DataBufferGLES30* buffer);
	static int				GetSizeClass			(int bufSize);

	UInt32					m_frameIndex;	//!< Frame index for computing buffer ages.

	enum
	{
		kSizeClassBaseLog2	= 10,
		kSizeClassStepLog2	= 1,
		kSizeClassCount		= 7
	};

	// Buffers that can not be selected are in pendingBuffers. Live buffers contain
	// buffers organized by size into kSizeClassCount classes.
	std::vector<DataBufferGLES30*>	m_pendingBuffers;
	std::vector<DataBufferGLES30*>	m_liveBuffers[kSizeClassCount];
};

// \todo [2013-05-10 pyry] Do not use singletons...
BufferManagerGLES30*	GetBufferManagerGLES30				(void);

//! Determine if buffer update will likely cause GPU stall.
bool					BufferUpdateCausesStallGLES30		(const DataBufferGLES30* buffer);

#endif // GFX_SUPPORTS_OPENGLES30