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