d_surf.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. // d_surf.c: rasterization driver surface heap manager
  16. #include "quakedef.h"
  17. #include "d_local.h"
  18. #include "r_local.h"
  19. float surfscale;
  20. qboolean r_cache_thrash; // set if surface cache is thrashing
  21. int sc_size;
  22. surfcache_t *sc_rover, *sc_base;
  23. #define GUARDSIZE 4
  24. int D_SurfaceCacheForRes (int width, int height)
  25. {
  26. int size, pix;
  27. if (COM_CheckParm ("-surfcachesize"))
  28. {
  29. size = Q_atoi(com_argv[COM_CheckParm("-surfcachesize")+1]) * 1024;
  30. return size;
  31. }
  32. size = SURFCACHE_SIZE_AT_320X200;
  33. pix = width*height;
  34. if (pix > 64000)
  35. size += (pix-64000)*3;
  36. return size;
  37. }
  38. void D_CheckCacheGuard (void)
  39. {
  40. byte *s;
  41. int i;
  42. s = (byte *)sc_base + sc_size;
  43. for (i=0 ; i<GUARDSIZE ; i++)
  44. if (s[i] != (byte)i)
  45. Sys_Error ("D_CheckCacheGuard: failed");
  46. }
  47. void D_ClearCacheGuard (void)
  48. {
  49. byte *s;
  50. int i;
  51. s = (byte *)sc_base + sc_size;
  52. for (i=0 ; i<GUARDSIZE ; i++)
  53. s[i] = (byte)i;
  54. }
  55. /*
  56. ================
  57. D_InitCaches
  58. ================
  59. */
  60. void D_InitCaches (void *buffer, int size)
  61. {
  62. // if (!msg_suppress_1)
  63. // Con_Printf ("%ik surface cache\n", size/1024);
  64. sc_size = size - GUARDSIZE;
  65. sc_base = (surfcache_t *)buffer;
  66. sc_rover = sc_base;
  67. sc_base->next = NULL;
  68. sc_base->owner = NULL;
  69. sc_base->size = sc_size;
  70. D_ClearCacheGuard ();
  71. }
  72. /*
  73. ==================
  74. D_FlushCaches
  75. ==================
  76. */
  77. void D_FlushCaches (void)
  78. {
  79. surfcache_t *c;
  80. if (!sc_base)
  81. return;
  82. for (c = sc_base ; c ; c = c->next)
  83. {
  84. if (c->owner)
  85. *c->owner = NULL;
  86. }
  87. sc_rover = sc_base;
  88. sc_base->next = NULL;
  89. sc_base->owner = NULL;
  90. sc_base->size = sc_size;
  91. }
  92. /*
  93. =================
  94. D_SCAlloc
  95. =================
  96. */
  97. surfcache_t *D_SCAlloc (int width, int size)
  98. {
  99. surfcache_t *new;
  100. qboolean wrapped_this_time;
  101. if ((width < 0) || (width > 256))
  102. Sys_Error ("D_SCAlloc: bad cache width %d\n", width);
  103. if ((size <= 0) || (size > 0x10000))
  104. Sys_Error ("D_SCAlloc: bad cache size %d\n", size);
  105. #ifdef __alpha__
  106. size = (int)((long)&((surfcache_t *)0)->data[size]);
  107. #else
  108. size = (int)&((surfcache_t *)0)->data[size];
  109. #endif
  110. size = (size + 3) & ~3;
  111. if (size > sc_size)
  112. Sys_Error ("D_SCAlloc: %i > cache size",size);
  113. // if there is not size bytes after the rover, reset to the start
  114. wrapped_this_time = false;
  115. if ( !sc_rover || (byte *)sc_rover - (byte *)sc_base > sc_size - size)
  116. {
  117. if (sc_rover)
  118. {
  119. wrapped_this_time = true;
  120. }
  121. sc_rover = sc_base;
  122. }
  123. // colect and free surfcache_t blocks until the rover block is large enough
  124. new = sc_rover;
  125. if (sc_rover->owner)
  126. *sc_rover->owner = NULL;
  127. while (new->size < size)
  128. {
  129. // free another
  130. sc_rover = sc_rover->next;
  131. if (!sc_rover)
  132. Sys_Error ("D_SCAlloc: hit the end of memory");
  133. if (sc_rover->owner)
  134. *sc_rover->owner = NULL;
  135. new->size += sc_rover->size;
  136. new->next = sc_rover->next;
  137. }
  138. // create a fragment out of any leftovers
  139. if (new->size - size > 256)
  140. {
  141. sc_rover = (surfcache_t *)( (byte *)new + size);
  142. sc_rover->size = new->size - size;
  143. sc_rover->next = new->next;
  144. sc_rover->width = 0;
  145. sc_rover->owner = NULL;
  146. new->next = sc_rover;
  147. new->size = size;
  148. }
  149. else
  150. sc_rover = new->next;
  151. new->width = width;
  152. // DEBUG
  153. if (width > 0)
  154. new->height = (size - sizeof(*new) + sizeof(new->data)) / width;
  155. new->owner = NULL; // should be set properly after return
  156. if (d_roverwrapped)
  157. {
  158. if (wrapped_this_time || (sc_rover >= d_initial_rover))
  159. r_cache_thrash = true;
  160. }
  161. else if (wrapped_this_time)
  162. {
  163. d_roverwrapped = true;
  164. }
  165. D_CheckCacheGuard (); // DEBUG
  166. return new;
  167. }
  168. /*
  169. =================
  170. D_SCDump
  171. =================
  172. */
  173. void D_SCDump (void)
  174. {
  175. surfcache_t *test;
  176. for (test = sc_base ; test ; test = test->next)
  177. {
  178. if (test == sc_rover)
  179. Sys_Printf ("ROVER:\n");
  180. printf ("%p : %i bytes %i width\n",test, test->size, test->width);
  181. }
  182. }
  183. //=============================================================================
  184. // if the num is not a power of 2, assume it will not repeat
  185. int MaskForNum (int num)
  186. {
  187. if (num==128)
  188. return 127;
  189. if (num==64)
  190. return 63;
  191. if (num==32)
  192. return 31;
  193. if (num==16)
  194. return 15;
  195. return 255;
  196. }
  197. int D_log2 (int num)
  198. {
  199. int c;
  200. c = 0;
  201. while (num>>=1)
  202. c++;
  203. return c;
  204. }
  205. //=============================================================================
  206. /*
  207. ================
  208. D_CacheSurface
  209. ================
  210. */
  211. surfcache_t *D_CacheSurface (msurface_t *surface, int miplevel)
  212. {
  213. surfcache_t *cache;
  214. //
  215. // if the surface is animating or flashing, flush the cache
  216. //
  217. r_drawsurf.texture = R_TextureAnimation (surface->texinfo->texture);
  218. r_drawsurf.lightadj[0] = d_lightstylevalue[surface->styles[0]];
  219. r_drawsurf.lightadj[1] = d_lightstylevalue[surface->styles[1]];
  220. r_drawsurf.lightadj[2] = d_lightstylevalue[surface->styles[2]];
  221. r_drawsurf.lightadj[3] = d_lightstylevalue[surface->styles[3]];
  222. //
  223. // see if the cache holds apropriate data
  224. //
  225. cache = surface->cachespots[miplevel];
  226. if (cache && !cache->dlight && surface->dlightframe != r_framecount
  227. && cache->texture == r_drawsurf.texture
  228. && cache->lightadj[0] == r_drawsurf.lightadj[0]
  229. && cache->lightadj[1] == r_drawsurf.lightadj[1]
  230. && cache->lightadj[2] == r_drawsurf.lightadj[2]
  231. && cache->lightadj[3] == r_drawsurf.lightadj[3] )
  232. return cache;
  233. //
  234. // determine shape of surface
  235. //
  236. surfscale = 1.0 / (1<<miplevel);
  237. r_drawsurf.surfmip = miplevel;
  238. r_drawsurf.surfwidth = surface->extents[0] >> miplevel;
  239. r_drawsurf.rowbytes = r_drawsurf.surfwidth;
  240. r_drawsurf.surfheight = surface->extents[1] >> miplevel;
  241. //
  242. // allocate memory if needed
  243. //
  244. if (!cache) // if a texture just animated, don't reallocate it
  245. {
  246. cache = D_SCAlloc (r_drawsurf.surfwidth,
  247. r_drawsurf.surfwidth * r_drawsurf.surfheight);
  248. surface->cachespots[miplevel] = cache;
  249. cache->owner = &surface->cachespots[miplevel];
  250. cache->mipscale = surfscale;
  251. }
  252. if (surface->dlightframe == r_framecount)
  253. cache->dlight = 1;
  254. else
  255. cache->dlight = 0;
  256. r_drawsurf.surfdat = (pixel_t *)cache->data;
  257. cache->texture = r_drawsurf.texture;
  258. cache->lightadj[0] = r_drawsurf.lightadj[0];
  259. cache->lightadj[1] = r_drawsurf.lightadj[1];
  260. cache->lightadj[2] = r_drawsurf.lightadj[2];
  261. cache->lightadj[3] = r_drawsurf.lightadj[3];
  262. //
  263. // draw and light the surface texture
  264. //
  265. r_drawsurf.surf = surface;
  266. c_surf++;
  267. R_DrawSurface ();
  268. return surface->cachespots[miplevel];
  269. }