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