1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, 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
26 float surfscale;
27 qboolean r_cache_thrash; // set if surface cache is thrashing
28
29 int sc_size;
30 surfcache_t *sc_rover, *sc_base;
31
32 #define GUARDSIZE 4
33
34
D_SurfaceCacheForRes(int width,int height)35 int 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
D_CheckCacheGuard(void)55 void 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
D_ClearCacheGuard(void)66 void 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 ================
79 D_InitCaches
80
81 ================
82 */
D_InitCaches(void * buffer,int size)83 void 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 ==================
102 D_FlushCaches
103 ==================
104 */
D_FlushCaches(void)105 void 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 =================
126 D_SCAlloc
127 =================
128 */
D_SCAlloc(int width,int size)129 surfcache_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
210 D_CheckCacheGuard (); // DEBUG
211 return new;
212 }
213
214
215 /*
216 =================
217 D_SCDump
218 =================
219 */
D_SCDump(void)220 void 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
MaskForNum(int num)236 int 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
D_log2(int num)249 int 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 ================
264 D_CacheSurface
265 ================
266 */
D_CacheSurface(msurface_t * surface,int miplevel)267 surfcache_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