PageRenderTime 29ms CodeModel.GetById 8ms app.highlight 18ms RepoModel.GetById 1ms app.codeStats 0ms

/opengles/src/arm/FunctionCache.cpp

http://ftk.googlecode.com/
C++ | 274 lines | 169 code | 62 blank | 43 comment | 26 complexity | 74d38cac7b222dc0785c259ce914ae69 MD5 | raw file
  1// ==========================================================================
  2//
  3// FunctionCache.cpp	Cache of compiled functions for 3D Rendering Library
  4//
  5// --------------------------------------------------------------------------
  6//
  7// 03-08-2003		Hans-Martin Will	initial version
  8//
  9// --------------------------------------------------------------------------
 10//
 11// Copyright (c) 2004, Hans-Martin Will. All rights reserved.
 12// 
 13// Redistribution and use in source and binary forms, with or without 
 14// modification, are permitted provided that the following conditions are 
 15// met:
 16// 
 17//	 *  Redistributions of source code must retain the above copyright
 18// 		notice, this list of conditions and the following disclaimer. 
 19//   *	Redistributions in binary form must reproduce the above copyright
 20// 		notice, this list of conditions and the following disclaimer in the 
 21// 		documentation and/or other materials provided with the distribution. 
 22// 
 23// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 24// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 25// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 26// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
 27// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 
 28// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
 29// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 30// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 31// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 32// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
 33// THE POSSIBILITY OF SUCH DAMAGE.
 34//
 35// ==========================================================================
 36
 37
 38#include "stdafx.h"
 39#include "FunctionCache.h"
 40#include "CodeGenerator.h"
 41
 42#ifdef EGL_ON_LINUX
 43#include <sys/mman.h>
 44#endif
 45
 46using namespace EGL;
 47
 48// ----------------------------------------------------------------------
 49// Info-Block to manage a single compiled function
 50// ----------------------------------------------------------------------
 51
 52namespace EGL {
 53	struct FunctionInfo {
 54		FunctionInfo	* m_Prev;		// previous item in LRU chain
 55		FunctionInfo	* m_Next;		// next item in LRU chain
 56		RasterizerState	m_State;		// the state that was compiled into this function
 57		size_t			m_Offset;		// offset of function in code segment
 58		size_t			m_Size;			// size of function in code segment
 59		U32				m_Flags;		// flags for garbage collection
 60
 61		FunctionCache::FunctionType m_Type;	// what kind of function is this?
 62	};
 63}
 64
 65FunctionCache :: FunctionCache(size_t totalSize, float percentageKeep) {
 66	m_Total = totalSize;
 67	m_Used = 0;
 68	m_PercentageKeep = percentageKeep;
 69
 70	m_UsedFunctions = 0;
 71	m_MaxFunctions = totalSize / 256;		 
 72
 73	m_MostRecentlyUsed = 0;
 74	m_LeastRecentlyUsed = 0;
 75
 76	m_Functions = (FunctionInfo *) malloc(sizeof(FunctionInfo)  * m_MaxFunctions);
 77	memset(m_Functions, 0, sizeof(FunctionInfo)  * m_MaxFunctions);
 78
 79#if defined(EGL_ON_WINCE)
 80	m_Code = reinterpret_cast<U8 *>(VirtualAlloc(0, totalSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE));
 81#elif defined(EGL_ON_SYMBIAN)
 82    m_Code = reinterpret_cast<U8*>(User::Alloc(totalSize));
 83#elif defined(EGL_ON_LINUX)
 84    m_Code = new U8[totalSize];
 85    mprotect((void *) m_Code, totalSize, PROT_READ | PROT_WRITE | PROT_EXEC);
 86#endif
 87}
 88
 89
 90FunctionCache :: ~FunctionCache() {
 91	free(m_Functions);
 92
 93#if defined(EGL_ON_WINCE)
 94	VirtualFree(m_Code, m_Total, MEM_DECOMMIT);
 95#elif defined(EGL_ON_SYMBIAN)
 96    User::Free(m_Code);
 97#elif defined(EGL_ON_LINUX)
 98    delete[] m_Code;
 99#endif
100}
101
102
103void * FunctionCache :: GetFunction(FunctionType type, const RasterizerState & state) {
104
105	RasterizerState::CompareFunction comparison = 0;
106
107	switch (type) {
108	case FunctionTypePoint:
109		comparison = &RasterizerState::ComparePoint;
110		break;
111
112	case FunctionTypeLine:
113		comparison = &RasterizerState::CompareLine;
114		break;
115
116	case FunctionTypeScanline:
117	case FunctionTypeTriangle:
118		comparison = &RasterizerState::ComparePolygon;
119		break;
120
121	}
122
123	for (FunctionInfo * function = m_MostRecentlyUsed; function; function = function->m_Next) {
124		if (function->m_Type == type && (state.*comparison)(function->m_State)) {
125			// move to front
126			if (function->m_Prev) {
127				function->m_Prev->m_Next = function->m_Next;
128
129				if (function->m_Next) {
130					function->m_Next->m_Prev = function->m_Prev;
131				} else {
132					m_LeastRecentlyUsed = function->m_Prev;
133				}
134
135				function->m_Next = m_MostRecentlyUsed;
136				function->m_Prev = 0;
137				m_MostRecentlyUsed->m_Prev = function;
138				m_MostRecentlyUsed = function;
139			}
140
141			return reinterpret_cast<void *>(m_Code + function->m_Offset);
142		}
143	}
144
145	// not found in cache, need to compile
146
147	CodeGenerator generator;
148	generator.SetState(&state);
149
150	switch (type) {
151	case FunctionTypeScanline:
152		generator.Compile(this, FunctionTypeScanline, &CodeGenerator::GenerateRasterScanLine);
153		break;
154
155	case FunctionTypePoint:
156		generator.Compile(this, FunctionTypePoint, &CodeGenerator::GenerateRasterPoint);
157		break;
158
159	case FunctionTypeLine:
160		generator.Compile(this, FunctionTypeLine, &CodeGenerator::GenerateRasterLine);
161		break;
162
163	case FunctionTypeTriangle:
164		generator.Compile(this, FunctionTypeTriangle, &CodeGenerator::GenerateRasterTriangle);
165
166	default:
167		;
168	}
169
170	return reinterpret_cast<void *>(m_Code + m_MostRecentlyUsed->m_Offset); 
171}
172
173
174void * FunctionCache :: AddFunction(FunctionType type, const RasterizerState & state, size_t size) {
175
176	if (size + m_Used >= m_Total || m_UsedFunctions >= m_MaxFunctions) {
177		CompactCode();
178	}
179
180	assert(m_UsedFunctions < m_MaxFunctions);
181	assert(size + m_Used < m_Total);
182
183	FunctionInfo * function = m_Functions + m_UsedFunctions++;
184
185	function->m_Next = m_MostRecentlyUsed;
186	function->m_Prev = 0;
187
188	if (m_MostRecentlyUsed) {
189		m_MostRecentlyUsed->m_Prev = function;
190	} else {
191		m_LeastRecentlyUsed = function;
192	}
193
194	m_MostRecentlyUsed = function;
195
196	function->m_Flags = 0;
197	function->m_Offset = m_Used;
198	function->m_Size = size;
199	m_Used += size;
200	function->m_State = state;
201	function->m_Type = type;
202
203	return reinterpret_cast<void *>(m_Code + m_MostRecentlyUsed->m_Offset); 
204}
205
206
207void FunctionCache :: CompactCode() {
208
209	size_t limit = (size_t) (m_Total * m_PercentageKeep);
210	size_t limitFunctions = (size_t) (m_MaxFunctions * m_PercentageKeep);
211
212	size_t countFunctions = 0;
213	size_t countMemory = 0;
214
215	// mark those functions that need to be retained
216	FunctionInfo * function = m_MostRecentlyUsed;
217
218	for (; function; function = function->m_Next) {
219		if (function->m_Size + countMemory > limit ||
220			countFunctions >= limitFunctions)
221			break;
222
223		function->m_Flags = 1;
224		++countFunctions;
225		countMemory += function->m_Size;
226	}
227
228	for (; function; function = function->m_Next) {
229		function->m_Flags = 0;
230	}
231
232	// now compact the list of functions
233
234	m_Used = 0;
235	countFunctions = 0;
236
237	FunctionInfo * target = m_Functions;
238	
239	for (function = m_Functions; function < m_Functions + m_UsedFunctions; ++function) {
240		if (function->m_Flags) {
241			memmove(m_Code + m_Used, m_Code + function->m_Offset, function->m_Size);
242			function->m_Offset = m_Used;
243			m_Used += function->m_Size;
244
245			target->m_State = function->m_State;
246			target->m_Offset = function->m_Offset;
247			target->m_Size = function->m_Size;
248
249			++target;
250		}
251	}
252
253	m_UsedFunctions = countFunctions;
254
255	// re-link LRU chain
256
257	if (m_UsedFunctions == 0) {
258		m_MostRecentlyUsed = m_LeastRecentlyUsed = 0;
259	} else if (m_UsedFunctions == 1) {
260		m_MostRecentlyUsed = m_LeastRecentlyUsed = m_Functions;
261		m_Functions->m_Prev = m_Functions->m_Next = 0;
262	} else if (m_UsedFunctions > 1) {
263		m_MostRecentlyUsed = m_Functions;
264		m_LeastRecentlyUsed = m_Functions + m_UsedFunctions - 1;
265		m_Functions[0].m_Prev = m_Functions[m_UsedFunctions - 1].m_Next = 0;
266		m_Functions[0].m_Next = m_Functions + 1;
267		m_Functions[m_UsedFunctions - 1].m_Prev = m_Functions + m_UsedFunctions - 2;
268
269		for (size_t index = 1; index < m_UsedFunctions - 1; ++index) {
270			m_Functions[index].m_Prev = m_Functions + index - 1;
271			m_Functions[index].m_Next = m_Functions + index + 1;
272		}
273	}
274}