1 // $Header: x:/prj/tech/libsrc/lgd3d/RCS/tmgr.c 1.33 1998/06/30 18:36:56 buzzard Exp $
13 #define mono_printf(x) \
19 #define mono_printf(x)
28 uchar *p_mono = (uchar *)0xb0082; \
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
)
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
;
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
87 ulong cookie
; // cookie from tmgr. Can reload when these match!
90 typedef struct 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
;
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
;
116 static uchar
*tmgr_set_clut(uchar
*clut
)
118 uchar
*retval
= texture_clut
;
123 // return amount of texture memory loaded this frame
124 static uint
tmgr_bytes_loaded(void)
129 static BOOL
tmgr_get_utilization(float *utilization
)
131 if (overloaded
) { // we're really overutilized
137 // we're not loaded to capacity yet; stats wouldn't be valid
140 *utilization
= ((float )texmem_used
)/texmem_loaded
;
144 const char *bad_bm_string
= "Bitmap data out of synch.";
146 #define is_valid(bm) \
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))
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
)
166 tmgr_texture_info
*info
;
173 bm
->flags
&= ~BMF_LOADED
;
174 bm
->bits
= info
->bits
;
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
;
191 if (info
->bits
!=NULL
) {
192 g_driver
->release_texture(i
);
194 texmem_loaded
-= info
->size
;
198 static void set_flags(tdrv_texture_info
*info
)
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
;
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
);
231 if (g_driver
->load_texture(info
) == TDRV_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
;
247 static void init_bitmap_list(void)
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;
257 tmgr_info
->clut
= NULL
;
262 static void do_set_texture(r3s_texture bm
)
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
);
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)
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
)
295 tmap_chain
**size_table
;
297 grs_bitmap
*bm
= info
->bm
;
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
;
308 size_table
= norm16_size_table
;
311 for (i
=0, w
=1; i
<MAX_SIZE
; i
++, w
+=w
)
313 for (j
=0, h
=1; j
<MAX_SIZE
; j
++, h
+=h
)
316 if ((i
>=MAX_SIZE
)||(j
>=MAX_SIZE
)) {
317 mono_printf(("Unsupported texture size: w=%i h=%i\n", bm
->w
, bm
->h
));
321 else while ((chain
= size_table
[i
*MAX_SIZE
+j
])==NULL
)
324 i
++, info
->scale_w
++;
326 j
++, info
->scale_h
++;
330 mono_printf(("Unsupported texture size: w=%i h=%i\n", bm
->w
, bm
->h
));
336 info
->size
= chain
->size
;
338 info
->w
= bm
->w
<< info
->scale_w
;
339 info
->h
= bm
->h
<< info
->scale_h
;
344 static void init_size_table(tmap_chain
**size_table
, int type
)
348 tdrv_texture_info info
;
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
);
355 info
.scale_w
= info
.scale_h
= 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
;
364 size_table
[i
+ j
] = (tmap_chain
*)info
.size
;
365 g_driver
->release_texture(info
.id
);
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
)
378 for (i
=0; i
<MAX_SIZE
*MAX_SIZE
; i
++) {
379 if (size_table
[i
]==TMGR_INVALID_TEXTURE_SIZE
)
382 for (j
=0; j
<num_sizes
; j
++) {
383 if (size_list
[j
]==size_table
[i
])
387 size_list
[num_sizes
++] = size_table
[i
];
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
)
396 for (i
=0; i
<MAX_SIZE
*MAX_SIZE
; i
++) {
397 if (size_table
[i
]==TMGR_INVALID_TEXTURE_SIZE
) {
398 size_table
[i
] = NULL
;
401 for (j
=0; j
<num_sizes
; j
++) {
402 if (chain_list
[j
].size
==(int )size_table
[i
])
406 chain_list
[num_sizes
].head
= -1;
407 chain_list
[num_sizes
].size
= (int )size_table
[i
];
410 size_table
[i
] = &chain_list
[j
];
416 static void munge_size_tables(void)
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
);
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
);
448 static void dump_all_textures(void)
451 BOOL end_and_start
= in_frame
;
456 g_driver
->end_frame();
458 g_driver
->synchronize();
460 for (i
=0; i
<max_textures
; i
++)
464 g_driver
->start_frame(cur_frame
);
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
;
477 int min_frame
=cur_frame
-1;
480 for (i
= chain
->head
; i
>=0; i
=tmgr_info
->next
) {
483 tmgr_info
= &texinfo
[i
];
485 AssertMsg(info
->size
== texinfo
[i
].size
, "wrong size!");
487 frame
= tmgr_info
->frame
;
489 if (frame
>= cur_frame
-1)
492 if (reload
&& (info
->cookie
!= tmgr_info
->cookie
))
495 if ((!reload
) && (info
->cookie
== tmgr_info
->cookie
))
497 else if (frame
>= min_frame
)
502 if (reload
&& (min_frame
==TMGR_UNLOADED
))
503 // can't do better than this!
507 // if we're not in swapout mode, we only want to reload unloaded textures
508 if ((!swapout
) && ((!reload
) || (min_frame
!= TMGR_UNLOADED
))) {
513 if (n
==-1) { // can't find suitable swapout; dump everything!
514 mono_printf(("Can't find suitable swapout candidate; dumping all textures!\n"));
521 else if (texinfo
[n
].bitmap
!= NULL
)
522 do_unload(texinfo
[n
].bitmap
);
529 static void tmgr_unload_texture(r3s_texture bm
)
532 if ((bm
->flags
&BMF_LOADED
)==0) {
538 // synch now in case we want to swap out this texture later this frame...
539 g_driver
->synchronize();
542 Warning(("bad bitmap pointer for unload!\n"));
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"));
558 info
.id
= (int )bm
->bits
;
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
;
576 if (bm
->flags
& BMF_LOADED
)
577 { // must have meant _re_load ;)
578 tmgr_reload_texture(bm
);
584 chain
= calc_size(&info
);
586 if (bm
->flags
& BMF_HACK
)
589 g_driver
->cook_info(&info
);
591 swapout_bitmap(&info
, chain
);
595 if (do_load(&info
)!=TDRV_FAILURE
)
600 mono_printf(("swapout _really_ failed; dumping all textures!"));
605 mono_printf(("Out of texture memory; entring swapout mode.\n"));
607 swapout_bitmap(&info
, chain
);
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"));
626 static void tmgr_set_texture(r3s_texture bm
)
630 g_driver
->set_texture_id(TDRV_ID_SOLID
);
634 if (bm
->flags
& BMF_LOADED
) {
636 if (texture_clut
== texinfo
[(int )bm
->bits
].clut
) {
641 mono_printf(("unloading to resynch with new texture clut!\n"));
642 tmgr_unload_texture(bm
);
646 g_driver
->set_texture_id(TDRV_ID_CALLBACK
);
650 static void tmgr_set_texture_callback(void)
653 AssertMsg(callback_bm
!=NULL
, "can't load NULL bitmap!\n");
654 tmgr_load_texture(callback_bm
);
656 do_set_texture(callback_bm
);
660 static void tmgr_start_frame(int frame
)
664 if (frame
!= cur_frame
) {
667 abl
= (abl
*7 + bytes_loaded
)/8;
668 if ((frame
& 0xf) == 0)
669 mono_printf(("avg bytes downloaded per frame: %i \n", abl
));
677 static void tmgr_end_frame(void)
682 static int tmgr_init(r3s_texture bm
, int num_textures
, int flags
)
688 spew
= ((flags
& TMGRF_SPEW
) != 0);
694 max_textures
= num_textures
;
695 texinfo
= (tmgr_texture_info
*)Malloc(num_textures
* sizeof(*texinfo
));
708 static void tmgr_shutdown(void)
719 if (chain_list
!= NULL
) {
732 static void tmgr_stats(void)
734 int i
, current_total
=0, global_total
=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;
748 AssertMsg(size
== texinfo
[index
].size
, "wrong size!");
749 if (texinfo
[index
].bits
!= NULL
) {
751 if (texinfo
[index
].frame
== cur_frame
)
754 index
= texinfo
[index
].next
;
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!");
769 static void tmgr_stats(void) {}