/opengles/src/arm/FunctionCache.cpp
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}