• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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