/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. #include "stdafx.h"
  37. #include "FunctionCache.h"
  38. #include "CodeGenerator.h"
  39. #ifdef EGL_ON_LINUX
  40. #include <sys/mman.h>
  41. #endif
  42. using namespace EGL;
  43. // ----------------------------------------------------------------------
  44. // Info-Block to manage a single compiled function
  45. // ----------------------------------------------------------------------
  46. namespace EGL {
  47. struct FunctionInfo {
  48. FunctionInfo * m_Prev; // previous item in LRU chain
  49. FunctionInfo * m_Next; // next item in LRU chain
  50. RasterizerState m_State; // the state that was compiled into this function
  51. size_t m_Offset; // offset of function in code segment
  52. size_t m_Size; // size of function in code segment
  53. U32 m_Flags; // flags for garbage collection
  54. FunctionCache::FunctionType m_Type; // what kind of function is this?
  55. };
  56. }
  57. FunctionCache :: FunctionCache(size_t totalSize, float percentageKeep) {
  58. m_Total = totalSize;
  59. m_Used = 0;
  60. m_PercentageKeep = percentageKeep;
  61. m_UsedFunctions = 0;
  62. m_MaxFunctions = totalSize / 256;
  63. m_MostRecentlyUsed = 0;
  64. m_LeastRecentlyUsed = 0;
  65. m_Functions = (FunctionInfo *) malloc(sizeof(FunctionInfo) * m_MaxFunctions);
  66. memset(m_Functions, 0, sizeof(FunctionInfo) * m_MaxFunctions);
  67. #if defined(EGL_ON_WINCE)
  68. m_Code = reinterpret_cast<U8 *>(VirtualAlloc(0, totalSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE));
  69. #elif defined(EGL_ON_SYMBIAN)
  70. m_Code = reinterpret_cast<U8*>(User::Alloc(totalSize));
  71. #elif defined(EGL_ON_LINUX)
  72. m_Code = new U8[totalSize];
  73. mprotect((void *) m_Code, totalSize, PROT_READ | PROT_WRITE | PROT_EXEC);
  74. #endif
  75. }
  76. FunctionCache :: ~FunctionCache() {
  77. free(m_Functions);
  78. #if defined(EGL_ON_WINCE)
  79. VirtualFree(m_Code, m_Total, MEM_DECOMMIT);
  80. #elif defined(EGL_ON_SYMBIAN)
  81. User::Free(m_Code);
  82. #elif defined(EGL_ON_LINUX)
  83. delete[] m_Code;
  84. #endif
  85. }
  86. void * FunctionCache :: GetFunction(FunctionType type, const RasterizerState & state) {
  87. RasterizerState::CompareFunction comparison = 0;
  88. switch (type) {
  89. case FunctionTypePoint:
  90. comparison = &RasterizerState::ComparePoint;
  91. break;
  92. case FunctionTypeLine:
  93. comparison = &RasterizerState::CompareLine;
  94. break;
  95. case FunctionTypeScanline:
  96. case FunctionTypeTriangle:
  97. comparison = &RasterizerState::ComparePolygon;
  98. break;
  99. }
  100. for (FunctionInfo * function = m_MostRecentlyUsed; function; function = function->m_Next) {
  101. if (function->m_Type == type && (state.*comparison)(function->m_State)) {
  102. // move to front
  103. if (function->m_Prev) {
  104. function->m_Prev->m_Next = function->m_Next;
  105. if (function->m_Next) {
  106. function->m_Next->m_Prev = function->m_Prev;
  107. } else {
  108. m_LeastRecentlyUsed = function->m_Prev;
  109. }
  110. function->m_Next = m_MostRecentlyUsed;
  111. function->m_Prev = 0;
  112. m_MostRecentlyUsed->m_Prev = function;
  113. m_MostRecentlyUsed = function;
  114. }
  115. return reinterpret_cast<void *>(m_Code + function->m_Offset);
  116. }
  117. }
  118. // not found in cache, need to compile
  119. CodeGenerator generator;
  120. generator.SetState(&state);
  121. switch (type) {
  122. case FunctionTypeScanline:
  123. generator.Compile(this, FunctionTypeScanline, &CodeGenerator::GenerateRasterScanLine);
  124. break;
  125. case FunctionTypePoint:
  126. generator.Compile(this, FunctionTypePoint, &CodeGenerator::GenerateRasterPoint);
  127. break;
  128. case FunctionTypeLine:
  129. generator.Compile(this, FunctionTypeLine, &CodeGenerator::GenerateRasterLine);
  130. break;
  131. case FunctionTypeTriangle:
  132. generator.Compile(this, FunctionTypeTriangle, &CodeGenerator::GenerateRasterTriangle);
  133. default:
  134. ;
  135. }
  136. return reinterpret_cast<void *>(m_Code + m_MostRecentlyUsed->m_Offset);
  137. }
  138. void * FunctionCache :: AddFunction(FunctionType type, const RasterizerState & state, size_t size) {
  139. if (size + m_Used >= m_Total || m_UsedFunctions >= m_MaxFunctions) {
  140. CompactCode();
  141. }
  142. assert(m_UsedFunctions < m_MaxFunctions);
  143. assert(size + m_Used < m_Total);
  144. FunctionInfo * function = m_Functions + m_UsedFunctions++;
  145. function->m_Next = m_MostRecentlyUsed;
  146. function->m_Prev = 0;
  147. if (m_MostRecentlyUsed) {
  148. m_MostRecentlyUsed->m_Prev = function;
  149. } else {
  150. m_LeastRecentlyUsed = function;
  151. }
  152. m_MostRecentlyUsed = function;
  153. function->m_Flags = 0;
  154. function->m_Offset = m_Used;
  155. function->m_Size = size;
  156. m_Used += size;
  157. function->m_State = state;
  158. function->m_Type = type;
  159. return reinterpret_cast<void *>(m_Code + m_MostRecentlyUsed->m_Offset);
  160. }
  161. void FunctionCache :: CompactCode() {
  162. size_t limit = (size_t) (m_Total * m_PercentageKeep);
  163. size_t limitFunctions = (size_t) (m_MaxFunctions * m_PercentageKeep);
  164. size_t countFunctions = 0;
  165. size_t countMemory = 0;
  166. // mark those functions that need to be retained
  167. FunctionInfo * function = m_MostRecentlyUsed;
  168. for (; function; function = function->m_Next) {
  169. if (function->m_Size + countMemory > limit ||
  170. countFunctions >= limitFunctions)
  171. break;
  172. function->m_Flags = 1;
  173. ++countFunctions;
  174. countMemory += function->m_Size;
  175. }
  176. for (; function; function = function->m_Next) {
  177. function->m_Flags = 0;
  178. }
  179. // now compact the list of functions
  180. m_Used = 0;
  181. countFunctions = 0;
  182. FunctionInfo * target = m_Functions;
  183. for (function = m_Functions; function < m_Functions + m_UsedFunctions; ++function) {
  184. if (function->m_Flags) {
  185. memmove(m_Code + m_Used, m_Code + function->m_Offset, function->m_Size);
  186. function->m_Offset = m_Used;
  187. m_Used += function->m_Size;
  188. target->m_State = function->m_State;
  189. target->m_Offset = function->m_Offset;
  190. target->m_Size = function->m_Size;
  191. ++target;
  192. }
  193. }
  194. m_UsedFunctions = countFunctions;
  195. // re-link LRU chain
  196. if (m_UsedFunctions == 0) {
  197. m_MostRecentlyUsed = m_LeastRecentlyUsed = 0;
  198. } else if (m_UsedFunctions == 1) {
  199. m_MostRecentlyUsed = m_LeastRecentlyUsed = m_Functions;
  200. m_Functions->m_Prev = m_Functions->m_Next = 0;
  201. } else if (m_UsedFunctions > 1) {
  202. m_MostRecentlyUsed = m_Functions;
  203. m_LeastRecentlyUsed = m_Functions + m_UsedFunctions - 1;
  204. m_Functions[0].m_Prev = m_Functions[m_UsedFunctions - 1].m_Next = 0;
  205. m_Functions[0].m_Next = m_Functions + 1;
  206. m_Functions[m_UsedFunctions - 1].m_Prev = m_Functions + m_UsedFunctions - 2;
  207. for (size_t index = 1; index < m_UsedFunctions - 1; ++index) {
  208. m_Functions[index].m_Prev = m_Functions + index - 1;
  209. m_Functions[index].m_Next = m_Functions + index + 1;
  210. }
  211. }
  212. }