summaryrefslogtreecommitdiff
path: root/Runtime/Graphics/RenderBufferManager.cpp
blob: 2b0f25ab4bcead4ee5030de9c735f18a761ad782 (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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
#include "UnityPrefix.h"
#include "RenderBufferManager.h"
#include "Runtime/Camera/Camera.h"
#include "Runtime/Camera/CameraUtil.h"
#include "Runtime/Camera/RenderManager.h"
#include "Runtime/GfxDevice/GfxDevice.h"
#include "RenderTexture.h"
#include "Runtime/Utilities/BitUtility.h"
#include "Runtime/Profiler/Profiler.h"
#if UNITY_XENON
	#include "PlatformDependent/Xbox360/Source/GfxDevice/TexturesXenon.h"
#elif UNITY_WII
	#include "Runtime/Graphics/ScreenManager.h"	
#endif

#ifndef DEBUG_RB_MANAGER
#define DEBUG_RB_MANAGER 0
#endif

using namespace std;

static RenderBufferManager* gRenderBufferManager = NULL;

void RenderBufferManager::InitRenderBufferManager ()
{
	Assert(gRenderBufferManager == NULL);
	gRenderBufferManager = new RenderBufferManager();
}

void RenderBufferManager::CleanupRenderBufferManager ()
{
	Assert(gRenderBufferManager != NULL);
	delete gRenderBufferManager;
	gRenderBufferManager = NULL;
}

RenderBufferManager& GetRenderBufferManager ()
{
	Assert(gRenderBufferManager != NULL);
	return *gRenderBufferManager;
}

RenderBufferManager* GetRenderBufferManagerPtr ()
{
	return gRenderBufferManager;
}


static int CalcSize( int size, int parentSize )
{
	switch (size) {
	case RenderBufferManager::kFullSize:
		return parentSize;
	default:
		#if DEBUGMODE
		if( size <= 0 ) {
			AssertString ("Invalid Temp Buffer size");
			return 128;
		}
		#endif
		return size;
	}
}


RenderTexture *RenderBufferManager::GetTempBuffer (int width, int height, DepthBufferFormat depthFormat, RenderTextureFormat colorFormat, UInt32 flags, RenderTextureReadWrite colorSpace, int antiAliasing)
{
	if( colorFormat == kRTFormatDefault )
		colorFormat = GetGfxDevice().GetDefaultRTFormat();

	if( colorFormat == kRTFormatDefaultHDR )
		colorFormat = GetGfxDevice().GetDefaultHDRRTFormat();

	bool sRGB = colorSpace == kRTReadWriteSRGB;
	const bool createdFromScript = flags & kRBCreatedFromScript;
	const bool sampleOnlyDepth = flags & kRBSampleOnlyDepth;
	const TextureDimension dim = (flags & kRBCubemap) ? kTexDimCUBE : kTexDim2D;

	if (colorSpace == kRTReadWriteDefault)
		sRGB = GetActiveColorSpace() == kLinearColorSpace;

	// only SRGB where it makes sense
	sRGB = sRGB && (colorFormat != GetGfxDevice().GetDefaultHDRRTFormat());

	if( width <= 0 || height <= 0 )
	{
		if (dim != kTexDim2D) {
			AssertString( "Trying to get a relatively sized RenderBuffer cubemap" );
			return NULL;
		}
		Camera *cam = GetCurrentCameraPtr();
		if (cam == NULL) {
			AssertString ("Trying to get a relatively sized RenderBuffer without an active camera.");
			return NULL;
		}
		Rectf r = cam->GetScreenViewportRect();
#if UNITY_WII
		GetScreenManager().ScaleViewportToFrameBuffer(r);
#endif
		// Figure out pixel size. Get screen extents as ints so we do the rounding correctly.
		int viewport[4];
		RectfToViewport(r, viewport);
		width = viewport[2];
		height = viewport[3];
	}
	
	if (dim == kTexDimCUBE && (!IsPowerOfTwo(width) || width != height))
	{
		AssertString( "Trying to get a non square or non power of two RenderBuffer cubemap" );
		return NULL;
	}

	if (antiAliasing < 1 || antiAliasing > 8 || !IsPowerOfTwo(antiAliasing))
	{
		AssertString( "Trying to get RenderBuffer with invalid antiAliasing (must be 1, 2, 4 or 8)" );
		return NULL;
	}
	
	// TODO: actually set & check depth

	// Go over free textures & find the one that matches in parameters.
	// The main point is: If we used a texture of same dims last frame we'll get that.
	FreeTextures::iterator found = m_FreeTextures.end();
	for( FreeTextures::iterator i = m_FreeTextures.begin(); i != m_FreeTextures.end(); ++i )
	{
		RenderTexture* rt = i->second;
		if( !rt 
		   || rt->GetDepthFormat() != depthFormat 
		   || rt->GetColorFormat() != colorFormat 
		   || rt->GetDimension() != dim
		   //@TODO: Only matters on OSX as DX can just set sampler state...
		   || rt->GetSRGBReadWrite() != sRGB
		   || rt->GetAntiAliasing() != antiAliasing
		   || rt->GetSampleOnlyDepth() != sampleOnlyDepth )
			continue;
		int tw = rt->GetWidth();
		int th = rt->GetHeight();
		
		if (tw == width && th == height) { 	// If the texture is same size
			found = i;
			break;
		}
	}
	
	// We didn't find any.
	if (found == m_FreeTextures.end() || !found->second)
	{
		m_TempBuffers++;
		RenderTexture *tex = NEW_OBJECT (RenderTexture);
		tex->Reset();

		tex->SetHideFlags(Object::kDontSave);
		tex->SetName (Format ("TempBuffer %d", m_TempBuffers).c_str());
		tex->SetWidth(width);
		tex->SetHeight(height);
		tex->SetColorFormat( colorFormat );
		tex->SetDepthFormat( depthFormat );
		tex->SetDimension (dim);
		tex->SetSRGBReadWrite (sRGB);
		tex->SetAntiAliasing (antiAliasing);
		tex->SetSampleOnlyDepth (sampleOnlyDepth);
		tex->AwakeFromLoad(kInstantiateOrCreateFromCodeAwakeFromLoad);
		m_TakenTextures.insert (tex);
		#if DEBUG_RB_MANAGER
		printf_console ("RBM: new texture %ix%i fmt=%i\n", width, height, colorFormat);
		#endif
		return tex;
	}

	// We found one. Move it from free to taken
	RenderTexture *tex = found->second;
	Assert (tex->GetWidth() == width && tex->GetHeight() == height);
	m_TakenTextures.insert (tex);
	m_FreeTextures.erase (found);

	// Set it's parameters (filtering etc.) as if it was newly created
	tex->GetSettings().Reset();
	tex->GetSettings().m_WrapMode = kTexWrapClamp;
	tex->ApplySettings();

	tex->SetCreatedFromScript (createdFromScript);

	// Automatically DiscardContents when createdFromScript - user can't expect any valid content.
	if (createdFromScript)
		tex->DiscardContents();

	return tex;
}

PROFILER_INFORMATION(gRenderBufferCollect, "RenderTexture.GarbageCollectTemporary", kProfilerRender)

void RenderBufferManager::GarbageCollect (int framesDelay)
{
	++m_CurrentRBMFrame;
	
	for (FreeTextures::iterator i = m_FreeTextures.begin(); i != m_FreeTextures.end();)
	{
		// Should only ever compare the difference since frame wraps around
		int frameDiff = m_CurrentRBMFrame - i->first;
		if( frameDiff > framesDelay || frameDiff < 0 )
		{
			PROFILER_AUTO(gRenderBufferCollect, NULL);
			#if DEBUG_RB_MANAGER
			printf_console ("RBM: kill unused texture (currframe=%i usedframe=%i)\n", m_CurrentRBMFrame, i->first);
			#endif

			FreeTextures::iterator j = i;
			i++;
			DestroySingleObject(j->second);
			m_FreeTextures.erase (j);
		}
		else
		{
			i++;
		}
	}
}


void RenderBufferManager::Cleanup ()
{
	for (TakenTextures::iterator i=m_TakenTextures.begin();i != m_TakenTextures.end();i++)
	{
		DestroySingleObject(*i);
	}
	m_TakenTextures.clear();

	for (FreeTextures::iterator i=m_FreeTextures.begin();i != m_FreeTextures.end();i++)
	{
		DestroySingleObject(i->second);
	}
	m_FreeTextures.clear();
	#if DEBUG_RB_MANAGER
	printf_console( "RBM: destroy all textures\n" );
	#endif
}
	
void RenderBufferManager::ReleaseTempBuffer (RenderTexture *rTex)
{
	if (!rTex)
		return;
	
	if (!m_TakenTextures.count (PPtr<RenderTexture> (rTex)))
	{
		ErrorStringObject ("Attempting to release RenderTexture that were not gotten as a temp buffer", rTex);
		return;
	}

	m_TakenTextures.erase (PPtr<RenderTexture> (rTex));
	m_FreeTextures.push_back (make_pair (m_CurrentRBMFrame, PPtr<RenderTexture> (rTex)));
}