convert line ends
[canaan.git] / prj / tech / libsrc / lgd3d / tmgr.c
blob036a90fd1882659f5ede47a7f3ae00b474135688
1 // $Header: x:/prj/tech/libsrc/lgd3d/RCS/tmgr.c 1.33 1998/06/30 18:36:56 buzzard Exp $
2 #include <string.h>
4 #include <dbg.h>
5 #include <dev2d.h>
6 #include <lgassert.h>
7 #include <memall.h>
8 #include <r3ds.h>
10 #ifndef SHIP
11 #include <mprintf.h>
12 static BOOL spew;
13 #define mono_printf(x) \
14 do { \
15 if (spew) \
16 mprintf x ; \
17 } while (0)
18 #else
19 #define mono_printf(x)
20 #endif
22 #include <tmgr.h>
23 #include <tdrv.h>
25 #ifdef MONO_SPEW
26 #define put_mono(c) \
27 do { \
28 uchar *p_mono = (uchar *)0xb0082; \
29 *p_mono = c; \
30 } while (0)
31 #else
32 #define put_mono(c)
33 #endif
35 static int tmgr_init(r3s_texture bm, int num_entries, int flags);
36 static void tmgr_shutdown(void);
37 static void tmgr_start_frame(int f);
38 static void tmgr_end_frame(void);
39 static void tmgr_load_texture(r3s_texture bm);
40 static void tmgr_unload_texture(r3s_texture bm);
41 static void tmgr_reload_texture(r3s_texture bm);
42 static void tmgr_set_texture(r3s_texture bm);
43 static void tmgr_set_texture_callback(void);
44 static void tmgr_stats(void);
45 static uint tmgr_bytes_loaded(void);
46 static BOOL tmgr_get_utilization(float *utilization);
47 static uchar *tmgr_set_clut(uchar *);
48 static void tmgr_restore_bits(grs_bitmap *bm);
50 static texture_driver *g_driver;
51 static texture_manager tmgr;
53 // Look! it's our one and only export!
54 texture_manager *get_dopey_texture_manager(texture_driver *driver)
56 g_driver = driver;
57 tmgr.init = tmgr_init;
58 tmgr.shutdown = tmgr_shutdown;
59 tmgr.start_frame = tmgr_start_frame;
60 tmgr.end_frame = tmgr_end_frame;
61 tmgr.load_texture = tmgr_load_texture;
62 tmgr.unload_texture = tmgr_unload_texture;
63 tmgr.set_texture = tmgr_set_texture;
64 tmgr.set_texture_callback = tmgr_set_texture_callback;
65 tmgr.stats = tmgr_stats;
66 tmgr.bytes_loaded = tmgr_bytes_loaded;
67 tmgr.get_utilization = tmgr_get_utilization;
68 tmgr.set_clut = tmgr_set_clut;
69 tmgr.restore_bits = tmgr_restore_bits;
70 tmgr.reload_texture = tmgr_reload_texture;
71 return &tmgr;
75 #define BMF_HACK 0x80
76 #define TMGR_UNLOADED (-1)
78 typedef struct tmgr_texture_info tmgr_texture_info;
80 struct tmgr_texture_info {
81 grs_bitmap *bitmap; // back ptr to bitmap
82 uchar *bits; // bits ptr from bitmap
83 int frame; // frame last used
84 uchar *clut; // ptr to clut used when loaded
85 int next; // index of next texture of this size
86 int size;
87 ulong cookie; // cookie from tmgr. Can reload when these match!
90 typedef struct tmap_chain {
91 int size;
92 int head;
93 } tmap_chain;
95 static tmgr_texture_info *texinfo = NULL;
96 static tmap_chain *chain_list = NULL;
97 static int num_texture_sizes = 0;
99 static uchar *texture_clut;
100 static r3s_texture default_bm;
101 static r3s_texture callback_bm;
103 static int cur_frame;
104 static int max_textures;
105 static int next_id;
106 static uint bytes_loaded; // bytes loaded this frame
107 static uint texmem_used;
108 static uint texmem_loaded;
110 static BOOL swapout = FALSE;
111 static BOOL overloaded = FALSE;
112 static BOOL in_frame = FALSE;
115 // returns old clut
116 static uchar *tmgr_set_clut(uchar *clut)
118 uchar *retval = texture_clut;
119 texture_clut = clut;
120 return retval;
123 // return amount of texture memory loaded this frame
124 static uint tmgr_bytes_loaded(void)
126 return bytes_loaded;
129 static BOOL tmgr_get_utilization(float *utilization)
131 if (overloaded) { // we're really overutilized
132 *utilization = 1.0;
133 return TRUE;
136 if (!swapout)
137 // we're not loaded to capacity yet; stats wouldn't be valid
138 return FALSE;
140 *utilization = ((float )texmem_used)/texmem_loaded;
141 return TRUE;
144 const char *bad_bm_string = "Bitmap data out of synch.";
146 #define is_valid(bm) \
147 ((bm != NULL) && \
148 ((uint )bm->bits < (uint )max_textures) && \
149 (bm == texinfo[(uint )bm->bits].bitmap))
151 #define validate_bm(bm) AssertMsg(is_valid(bm), bad_bm_string)
153 static void tmgr_restore_bits(grs_bitmap *bm)
155 if ((bm == NULL)||((bm->flags&BMF_LOADED)==0))
156 return;
157 validate_bm(bm);
158 bm->bits = texinfo[(uint )bm->bits].bits;
161 // eliminate bitmap pointer from list, mark
162 // vidmem as ready to be released.
163 static void do_unload(grs_bitmap *bm)
165 int i;
166 tmgr_texture_info *info;
168 validate_bm(bm);
170 i = (int )bm->bits;
171 info = &texinfo[i];
173 bm->flags &= ~BMF_LOADED;
174 bm->bits = info->bits;
175 info->bitmap = NULL;
176 info->frame = TMGR_UNLOADED;
178 // tell driver to disconnect bitmap from texture
179 g_driver->unload_texture(i);
183 // really for sure get rid of this texture
184 static void release_texture(int i)
186 tmgr_texture_info *info = &texinfo[i];
187 grs_bitmap *bm = info->bitmap;
188 if (bm!=NULL)
189 do_unload(bm);
190 info->frame = 0;
191 if (info->bits!=NULL) {
192 g_driver->release_texture(i);
193 info->bits = NULL;
194 texmem_loaded -= info->size;
198 static void set_flags(tdrv_texture_info *info)
200 info->flags = 0;
201 if (gr_get_fill_type() == FILL_BLEND) {
202 info->flags |= TF_ALPHA;
205 if ((!(info->flags&TF_ALPHA)) && (info->bm->flags&BMF_TRANS)) {
206 info->flags |= TF_TRANS;
209 if (info->bm->flags & BMF_LOADED)
210 info->bits = texinfo[info->id].bits;
211 else
212 info->bits = info->bm->bits;
216 #define TMGR_SUCCESS 0
217 static int do_load(tdrv_texture_info *info)
219 grs_bitmap *bm = info->bm;
220 tmgr_texture_info *tmgr_info = &texinfo[info->id];
222 AssertMsg((!swapout)||(tmgr_info->size == info->size), "do_load(): size mismatch.");
224 if (tmgr_info->bits != NULL) {
226 AssertMsg(info->cookie == tmgr_info->cookie,
227 "do_load(): cookie doesn't match original.");
229 g_driver->reload_texture(info);
230 } else {
231 if (g_driver->load_texture(info) == TDRV_FAILURE)
232 return TMGR_FAILURE;
233 texmem_loaded += info->size;
235 bytes_loaded += info->size;
236 tmgr_info->clut = texture_clut;
237 tmgr_info->bits = bm->bits;
238 tmgr_info->bitmap = bm;
239 tmgr_info->cookie = info->cookie;
240 tmgr_info->size = info->size;
241 bm->bits = (uchar *)info->id;
242 bm->flags |= BMF_LOADED;
244 return TMGR_SUCCESS;
247 static void init_bitmap_list(void)
249 int i;
250 tmgr_texture_info *tmgr_info = texinfo;
252 for (i=0; i<max_textures; i++) {
253 tmgr_info->bitmap = NULL;
254 tmgr_info->bits = NULL;
255 tmgr_info->frame = 0;
256 tmgr_info->size = 0;
257 tmgr_info->clut = NULL;
258 tmgr_info++;
262 static void do_set_texture(r3s_texture bm)
264 int i;
265 tmgr_texture_info *info;
267 if (bm->flags & BMF_HACK) {
268 if (!(default_bm->flags&BMF_LOADED))
269 tmgr_load_texture(default_bm);
270 do_set_texture(default_bm);
271 return;
274 validate_bm(bm);
276 i = (int )bm->bits;
277 info = &texinfo[i];
279 if (info->frame != cur_frame) {
280 texmem_used += info->size;
281 info->frame = cur_frame;
283 g_driver->set_texture_id(i);
286 #define TMGR_INVALID_TEXTURE_SIZE ((tmap_chain *)-1)
287 #define MAX_SIZE 9
288 static tmap_chain *alpha_size_table[MAX_SIZE*MAX_SIZE];
289 static tmap_chain *norm8_size_table[MAX_SIZE*MAX_SIZE];
290 static tmap_chain *norm16_size_table[MAX_SIZE*MAX_SIZE];
292 static tmap_chain *calc_size(tdrv_texture_info *info)
294 int i,j,w,h;
295 tmap_chain **size_table;
296 tmap_chain *chain;
297 grs_bitmap *bm = info->bm;
299 set_flags(info);
300 info->scale_w = info->scale_h = 0;
303 if (info->flags & TF_ALPHA)
304 size_table = alpha_size_table;
305 else if (bm->type == BMT_FLAT8)
306 size_table = norm8_size_table;
307 else
308 size_table = norm16_size_table;
311 for (i=0, w=1; i<MAX_SIZE; i++, w+=w)
312 if (w==bm->w) break;
313 for (j=0, h=1; j<MAX_SIZE; j++, h+=h)
314 if (h==bm->h) break;
316 if ((i>=MAX_SIZE)||(j>=MAX_SIZE)) {
317 mono_printf(("Unsupported texture size: w=%i h=%i\n", bm->w, bm->h));
318 bm->flags|=BMF_HACK;
321 else while ((chain = size_table[i*MAX_SIZE+j])==NULL)
323 if (i<j) {
324 i++, info->scale_w++;
325 } else {
326 j++, info->scale_h++;
327 if (j<MAX_SIZE)
328 continue;
330 mono_printf(("Unsupported texture size: w=%i h=%i\n", bm->w, bm->h));
331 bm->flags|=BMF_HACK;
332 break;
335 if (chain!=NULL)
336 info->size = chain->size;
338 info->w = bm->w << info->scale_w;
339 info->h = bm->h << info->scale_h;
340 return chain;
344 static void init_size_table(tmap_chain **size_table, int type)
346 int i, j;
347 int w, h;
348 tdrv_texture_info info;
349 info.id = 0;
351 for (i=0,w=1; i<MAX_SIZE * MAX_SIZE; w+=w, i+=MAX_SIZE) {
352 for (j=0,h=1; j<MAX_SIZE; h+=h, j++) {
353 info.bm = gr_alloc_bitmap(type, 0, w, h);
354 set_flags(&info);
355 info.scale_w = info.scale_h = 0;
356 info.w = info.bm->w;
357 info.h = info.bm->h;
358 info.size = 0;
359 g_driver->cook_info(&info);
360 if (g_driver->load_texture(&info) == TDRV_FAILURE)
361 { // can't load this size texture
362 size_table[i + j] = TMGR_INVALID_TEXTURE_SIZE;
363 } else {
364 size_table[i + j] = (tmap_chain *)info.size;
365 g_driver->release_texture(info.id);
367 gr_free(info.bm);
372 #define MAX_TMAP_SIZES 3*MAX_SIZE*MAX_SIZE
374 // here we're just trying to figure out how many distinct texture sizes there are...
375 static int get_num_sizes(tmap_chain **size_list, int num_sizes, tmap_chain **size_table)
377 int i,j;
378 for (i=0; i<MAX_SIZE*MAX_SIZE; i++) {
379 if (size_table[i]==TMGR_INVALID_TEXTURE_SIZE)
380 continue;
382 for (j=0; j<num_sizes; j++) {
383 if (size_list[j]==size_table[i])
384 break;
386 if (j==num_sizes)
387 size_list[num_sizes++] = size_table[i];
389 return num_sizes;
392 // here we actually munge the size table to have real (tmap_chain *)'s
393 static int munge_table(int num_sizes, tmap_chain **size_table)
395 int i,j;
396 for (i=0; i<MAX_SIZE*MAX_SIZE; i++) {
397 if (size_table[i]==TMGR_INVALID_TEXTURE_SIZE) {
398 size_table[i] = NULL;
399 continue;
401 for (j=0; j<num_sizes; j++) {
402 if (chain_list[j].size==(int )size_table[i])
403 break;
405 if (j==num_sizes) {
406 chain_list[num_sizes].head = -1;
407 chain_list[num_sizes].size = (int )size_table[i];
408 num_sizes++;
410 size_table[i] = &chain_list[j];
412 return num_sizes;
416 static void munge_size_tables(void)
418 int num_sizes;
419 tmap_chain **size_list;
421 size_list = (tmap_chain **)Malloc(MAX_TMAP_SIZES*sizeof(tmap_chain *));
422 num_sizes = get_num_sizes(size_list, 0, alpha_size_table);
423 num_sizes = get_num_sizes(size_list, num_sizes, norm8_size_table);
424 num_sizes = get_num_sizes(size_list, num_sizes, norm16_size_table);
425 Free(size_list);
426 chain_list = (tmap_chain *)Malloc(num_sizes * sizeof(tmap_chain));
427 num_texture_sizes = munge_table(0, alpha_size_table);
428 num_texture_sizes = munge_table(num_texture_sizes, norm8_size_table);
429 num_texture_sizes = munge_table(num_texture_sizes, norm16_size_table);
430 AssertMsg(num_texture_sizes==num_sizes,
431 "munge_size_tables(): detected bug in get_num_sizes() or munge_table()");
435 static int init_size_tables(void)
437 gr_set_fill_type(FILL_BLEND);
438 init_size_table(alpha_size_table, BMT_FLAT8);
439 gr_set_fill_type(FILL_NORM);
441 init_size_table(norm8_size_table, BMT_FLAT8);
442 init_size_table(norm16_size_table, BMT_FLAT16);
444 munge_size_tables();
445 return TMGR_SUCCESS;
448 static void dump_all_textures(void)
450 int i;
451 BOOL end_and_start = in_frame;
453 swapout = FALSE;
454 next_id = 0;
455 if (end_and_start)
456 g_driver->end_frame();
458 g_driver->synchronize();
460 for (i=0; i<max_textures; i++)
461 release_texture(i);
463 if (end_and_start)
464 g_driver->start_frame(cur_frame);
466 overloaded = TRUE;
468 // reset all the size chains
469 for (i=0; i<num_texture_sizes; i++)
470 chain_list[i].head=-1;
473 void swapout_bitmap(tdrv_texture_info *info, tmap_chain *chain)
475 tmgr_texture_info *tmgr_info;
476 int i,n=-1;
477 int min_frame=cur_frame-1;
478 BOOL reload = FALSE;
480 for (i = chain->head; i>=0; i=tmgr_info->next) {
481 int frame;
483 tmgr_info = &texinfo[i];
485 AssertMsg(info->size == texinfo[i].size, "wrong size!");
486 // old enough?
487 frame = tmgr_info->frame;
489 if (frame >= cur_frame-1)
490 continue;
492 if (reload && (info->cookie != tmgr_info->cookie))
493 continue;
495 if ((!reload) && (info->cookie == tmgr_info->cookie))
496 reload = TRUE;
497 else if (frame >= min_frame)
498 continue;
500 min_frame = frame;
501 n = i;
502 if (reload && (min_frame==TMGR_UNLOADED))
503 // can't do better than this!
504 break;
507 // if we're not in swapout mode, we only want to reload unloaded textures
508 if ((!swapout) && ((!reload) || (min_frame != TMGR_UNLOADED))) {
509 info->id = next_id;
510 return;
513 if (n==-1) { // can't find suitable swapout; dump everything!
514 mono_printf(("Can't find suitable swapout candidate; dumping all textures!\n"));
516 dump_all_textures();
517 info->id = next_id;
518 } else {
519 if (!reload)
520 release_texture(n);
521 else if (texinfo[n].bitmap != NULL)
522 do_unload(texinfo[n].bitmap);
524 info->id = n;
529 static void tmgr_unload_texture(r3s_texture bm)
531 put_mono('e');
532 if ((bm->flags&BMF_LOADED)==0) {
533 put_mono('.');
534 return;
537 if (is_valid(bm)) {
538 // synch now in case we want to swap out this texture later this frame...
539 g_driver->synchronize();
540 do_unload(bm);
541 } else
542 Warning(("bad bitmap pointer for unload!\n"));
544 put_mono('.');
547 static void tmgr_reload_texture(grs_bitmap *bm)
549 tdrv_texture_info info;
551 if ((bm == NULL)||((bm->flags&BMF_LOADED)==0)) {
552 Warning(("tmgr_reload_texture(): NULL bitmap or bitmap not loaded.\n"));
553 return;
556 validate_bm(bm);
557 info.bm = bm;
558 info.id = (int )bm->bits;
560 calc_size(&info);
561 g_driver->cook_info(&info);
563 AssertMsg(info.cookie == texinfo[info.id].cookie,
564 "tmgr_reload_texture(): cookie doesn't match original.");
566 g_driver->reload_texture(&info);
569 static void tmgr_load_texture(r3s_texture bm)
571 tdrv_texture_info info;
572 tmap_chain *chain;
574 put_mono('d');
576 if (bm->flags & BMF_LOADED)
577 { // must have meant _re_load ;)
578 tmgr_reload_texture(bm);
579 return;
582 info.bm = bm;
584 chain = calc_size(&info);
586 if (bm->flags & BMF_HACK)
587 return;
589 g_driver->cook_info(&info);
591 swapout_bitmap(&info, chain);
593 do {
594 put_mono('1');
595 if (do_load(&info)!=TDRV_FAILURE)
596 break;
598 if (swapout) {
599 put_mono('2');
600 mono_printf(("swapout _really_ failed; dumping all textures!"));
601 dump_all_textures();
602 info.id = next_id;
603 } else {
604 put_mono('3');
605 mono_printf(("Out of texture memory; entring swapout mode.\n"));
606 swapout = TRUE;
607 swapout_bitmap(&info, chain);
609 } while (TRUE);
611 put_mono('4');
612 if ((!swapout)&&(info.id==next_id)) {
613 // add new texture to head of chain...
614 texinfo[next_id].next = chain->head;
615 chain->head = next_id;
616 AssertMsg(texinfo[next_id].size == chain->size, "wrong size!");
618 if (++next_id == max_textures) {
619 mono_printf(("Out of texture handles; entering swapout mode.\n"));
620 swapout = TRUE;
623 put_mono('.');
626 static void tmgr_set_texture(r3s_texture bm)
628 put_mono('f');
629 if (bm==NULL) {
630 g_driver->set_texture_id(TDRV_ID_SOLID);
631 put_mono('.');
632 return;
634 if (bm->flags & BMF_LOADED) {
635 validate_bm(bm);
636 if (texture_clut == texinfo[(int )bm->bits].clut) {
637 do_set_texture(bm);
638 put_mono('.');
639 return;
641 mono_printf(("unloading to resynch with new texture clut!\n"));
642 tmgr_unload_texture(bm);
643 put_mono('f');
645 callback_bm = bm;
646 g_driver->set_texture_id(TDRV_ID_CALLBACK);
647 put_mono('.');
650 static void tmgr_set_texture_callback(void)
652 put_mono('g');
653 AssertMsg(callback_bm!=NULL, "can't load NULL bitmap!\n");
654 tmgr_load_texture(callback_bm);
655 put_mono('g');
656 do_set_texture(callback_bm);
657 put_mono('.');
660 static void tmgr_start_frame(int frame)
662 static uint abl = 0;
663 put_mono('c');
664 if (frame != cur_frame) {
665 cur_frame = frame;
666 overloaded = FALSE;
667 abl = (abl*7 + bytes_loaded)/8;
668 if ((frame & 0xf) == 0)
669 mono_printf(("avg bytes downloaded per frame: %i \n", abl));
670 bytes_loaded = 0;
671 texmem_used = 0;
673 in_frame = TRUE;
674 put_mono('.');
677 static void tmgr_end_frame(void)
679 in_frame = FALSE;
682 static int tmgr_init(r3s_texture bm, int num_textures, int flags)
684 if (texinfo!=NULL)
685 tmgr_shutdown();
687 #ifndef SHIP
688 spew = ((flags & TMGRF_SPEW) != 0);
689 #endif
691 put_mono('a');
692 bytes_loaded = 0;
693 texmem_loaded = 0;
694 max_textures = num_textures;
695 texinfo = (tmgr_texture_info *)Malloc(num_textures * sizeof(*texinfo));
696 init_bitmap_list();
697 init_size_tables();
698 default_bm = bm;
699 swapout = FALSE;
700 overloaded = FALSE;
701 in_frame = FALSE;
702 texture_clut = NULL;
703 next_id = 0;
704 put_mono('.');
705 return TMGR_SUCCESS;
708 static void tmgr_shutdown(void)
710 if (texinfo == NULL)
711 return;
713 put_mono('b');
714 dump_all_textures();
716 Free(texinfo);
717 texinfo = NULL;
719 if (chain_list != NULL) {
720 Free(chain_list);
721 chain_list = NULL;
724 put_mono('.');
730 #ifndef SHIP
732 static void tmgr_stats(void)
734 int i, current_total=0, global_total=0;
736 mono_setxy(0,0);
737 mprint("Texture Manager Stats: \n");
738 mprintf("texmem_loaded: %i texmem_used: %i swapout: %i \n",
739 texmem_loaded, texmem_used, swapout);
740 for (i = 0; i<num_texture_sizes; i++)
742 int size = chain_list[i].size;
743 int index = chain_list[i].head;
744 int current=0, total=0;
746 while (index >= 0)
748 AssertMsg(size == texinfo[index].size, "wrong size!");
749 if (texinfo[index].bits != NULL) {
750 total++;
751 if (texinfo[index].frame == cur_frame)
752 current++;
754 index = texinfo[index].next;
756 if (total > 0) {
757 mprintf("size %i: this frame: %i total: %i \n",
758 size, current, total);
759 current_total += current*size;
760 global_total += total*size;
763 mprintf("checksum: \n");
764 mprintf("texmem_loaded: %i texmem_used: %i \n",
765 global_total, current_total);
766 AssertMsg(global_total==texmem_loaded, "stats incorrect!");
768 #else
769 static void tmgr_stats(void) {}
770 #endif