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