d_surf.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  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. size = (int)&((surfcache_t *)0)->data[size];
  106. size = (size + 3) & ~3;
  107. if (size > sc_size)
  108. Sys_Error ("D_SCAlloc: %i > cache size",size);
  109. // if there is not size bytes after the rover, reset to the start
  110. wrapped_this_time = false;
  111. if ( !sc_rover || (byte *)sc_rover - (byte *)sc_base > sc_size - size)
  112. {
  113. if (sc_rover)
  114. {
  115. wrapped_this_time = true;
  116. }
  117. sc_rover = sc_base;
  118. }
  119. // colect and free surfcache_t blocks until the rover block is large enough
  120. new = sc_rover;
  121. if (sc_rover->owner)
  122. *sc_rover->owner = NULL;
  123. while (new->size < size)
  124. {
  125. // free another
  126. sc_rover = sc_rover->next;
  127. if (!sc_rover)
  128. Sys_Error ("D_SCAlloc: hit the end of memory");
  129. if (sc_rover->owner)
  130. *sc_rover->owner = NULL;
  131. new->size += sc_rover->size;
  132. new->next = sc_rover->next;
  133. }
  134. // create a fragment out of any leftovers
  135. if (new->size - size > 256)
  136. {
  137. sc_rover = (surfcache_t *)( (byte *)new + size);
  138. sc_rover->size = new->size - size;
  139. sc_rover->next = new->next;
  140. sc_rover->width = 0;
  141. sc_rover->owner = NULL;
  142. new->next = sc_rover;
  143. new->size = size;
  144. }
  145. else
  146. sc_rover = new->next;
  147. new->width = width;
  148. // DEBUG
  149. if (width > 0)
  150. new->height = (size - sizeof(*new) + sizeof(new->data)) / width;
  151. new->owner = NULL; // should be set properly after return
  152. if (d_roverwrapped)
  153. {
  154. if (wrapped_this_time || (sc_rover >= d_initial_rover))
  155. r_cache_thrash = true;
  156. }
  157. else if (wrapped_this_time)
  158. {
  159. d_roverwrapped = true;
  160. }
  161. D_CheckCacheGuard (); // DEBUG
  162. return new;
  163. }
  164. /*
  165. =================
  166. D_SCDump
  167. =================
  168. */
  169. void D_SCDump (void)
  170. {
  171. surfcache_t *test;
  172. for (test = sc_base ; test ; test = test->next)
  173. {
  174. if (test == sc_rover)
  175. Sys_Printf ("ROVER:\n");
  176. printf ("%p : %i bytes %i width\n",test, test->size, test->width);
  177. }
  178. }
  179. //=============================================================================
  180. // if the num is not a power of 2, assume it will not repeat
  181. int MaskForNum (int num)
  182. {
  183. if (num==128)
  184. return 127;
  185. if (num==64)
  186. return 63;
  187. if (num==32)
  188. return 31;
  189. if (num==16)
  190. return 15;
  191. return 255;
  192. }
  193. int D_log2 (int num)
  194. {
  195. int c;
  196. c = 0;
  197. while (num>>=1)
  198. c++;
  199. return c;
  200. }
  201. //=============================================================================
  202. /*
  203. ================
  204. D_CacheSurface
  205. ================
  206. */
  207. surfcache_t *D_CacheSurface (msurface_t *surface, int miplevel)
  208. {
  209. surfcache_t *cache;
  210. //
  211. // if the surface is animating or flashing, flush the cache
  212. //
  213. r_drawsurf.texture = R_TextureAnimation (surface->texinfo->texture);
  214. r_drawsurf.lightadj[0] = d_lightstylevalue[surface->styles[0]];
  215. r_drawsurf.lightadj[1] = d_lightstylevalue[surface->styles[1]];
  216. r_drawsurf.lightadj[2] = d_lightstylevalue[surface->styles[2]];
  217. r_drawsurf.lightadj[3] = d_lightstylevalue[surface->styles[3]];
  218. //
  219. // see if the cache holds apropriate data
  220. //
  221. cache = surface->cachespots[miplevel];
  222. if (cache && !cache->dlight && surface->dlightframe != r_framecount
  223. && cache->texture == r_drawsurf.texture
  224. && cache->lightadj[0] == r_drawsurf.lightadj[0]
  225. && cache->lightadj[1] == r_drawsurf.lightadj[1]
  226. && cache->lightadj[2] == r_drawsurf.lightadj[2]
  227. && cache->lightadj[3] == r_drawsurf.lightadj[3] )
  228. return cache;
  229. //
  230. // determine shape of surface
  231. //
  232. surfscale = 1.0 / (1<<miplevel);
  233. r_drawsurf.surfmip = miplevel;
  234. r_drawsurf.surfwidth = surface->extents[0] >> miplevel;
  235. r_drawsurf.rowbytes = r_drawsurf.surfwidth;
  236. r_drawsurf.surfheight = surface->extents[1] >> miplevel;
  237. //
  238. // allocate memory if needed
  239. //
  240. if (!cache) // if a texture just animated, don't reallocate it
  241. {
  242. cache = D_SCAlloc (r_drawsurf.surfwidth,
  243. r_drawsurf.surfwidth * r_drawsurf.surfheight);
  244. surface->cachespots[miplevel] = cache;
  245. cache->owner = &surface->cachespots[miplevel];
  246. cache->mipscale = surfscale;
  247. }
  248. if (surface->dlightframe == r_framecount)
  249. cache->dlight = 1;
  250. else
  251. cache->dlight = 0;
  252. r_drawsurf.surfdat = (pixel_t *)cache->data;
  253. cache->texture = r_drawsurf.texture;
  254. cache->lightadj[0] = r_drawsurf.lightadj[0];
  255. cache->lightadj[1] = r_drawsurf.lightadj[1];
  256. cache->lightadj[2] = r_drawsurf.lightadj[2];
  257. cache->lightadj[3] = r_drawsurf.lightadj[3];
  258. //
  259. // draw and light the surface texture
  260. //
  261. r_drawsurf.surf = surface;
  262. c_surf++;
  263. R_DrawSurface ();
  264. return surface->cachespots[miplevel];
  265. }