2 * $Logfile: /Freespace2/code/Graphics/GrD3DTexture.cpp $
7 * Code to manage loading textures into VRAM for Direct3D
10 * Revision 1.2 2002/05/07 03:16:45 theoddone33
11 * The Great Newline Fix
13 * Revision 1.1.1.1 2002/05/03 03:28:09 root
17 * 22 9/09/99 8:53p Dave
18 * Fixed multiplayer degenerate orientation case problem. Make sure warp
19 * effect never goes lower than LOD 1.
21 * 21 9/05/99 11:19p Dave
22 * Made d3d texture cache much more safe. Fixed training scoring bug where
23 * it would backout scores without ever having applied them in the first
26 * 20 8/16/99 4:04p Dave
27 * Big honking checkin.
29 * 19 7/29/99 10:47p Dave
30 * Standardized D3D fogging using vertex fog. Shook out Savage 4 bugs.
32 * 18 7/16/99 1:49p Dave
33 * 8 bit aabitmaps. yay.
35 * 17 7/13/99 1:15p Dave
36 * 32 bit support. Whee!
38 * 16 7/09/99 9:51a Dave
39 * Added thick polyline code.
41 * 15 6/29/99 10:35a Dave
42 * Interface polygon bitmaps! Whee!
44 * 14 6/16/99 4:06p Dave
45 * New pilot info popup. Added new draw-bitmap-as-poly function.
47 * 13 5/05/99 9:02p Dave
48 * Fixed D3D aabitmap rendering. Spiffed up nebula effect a bit (added
49 * rotations, tweaked values, made bitmap selection more random). Fixed
50 * D3D beam weapon clipping problem. Added D3d frame dumping.
52 * 12 2/11/99 3:08p Dave
53 * PXO refresh button. Very preliminary squad war support.
55 * 11 2/05/99 12:52p Dave
56 * Fixed Glide nondarkening textures.
58 * 10 2/03/99 11:44a Dave
59 * Fixed d3d transparent textures.
61 * 9 1/30/99 5:08p Dave
62 * More new hi-res stuff.Support for nice D3D textures.
64 * 8 1/15/99 11:29a Neilk
65 * Fixed D3D screen/texture pixel formatting problem.
67 * 7 1/12/99 12:53a Dave
68 * More work on beam weapons - made collision detection very efficient -
69 * collide against all object types properly - made 3 movement types
70 * smooth. Put in test code to check for possible non-darkening pixels on
73 * 6 12/01/98 6:12p Johnson
74 * Make sure to page in weapon impact animations as xparent textures.
76 * 5 12/01/98 10:32a Johnson
77 * Fixed direct3d font problems. Fixed sun bitmap problem. Fixed direct3d
80 * 4 11/30/98 1:07p Dave
81 * 16 bit conversion, first run.
83 * 3 10/09/98 2:57p Dave
84 * Starting splitting up OS stuff.
86 * 2 10/07/98 10:52a Dave
89 * 1 10/07/98 10:49a Dave
91 * 37 6/13/98 3:18p Hoffoss
92 * NOX()ed out a bunch of strings that shouldn't be translated.
94 * 36 5/23/98 6:12p John
95 * added code to use registry to force preloading of textures or not.
97 * 35 5/23/98 5:17p John
98 * added reg key to set texture divider
100 * 34 5/23/98 5:01p John
101 * made agp preloading happen if >= 6 MB of VRAM.
103 * 33 5/23/98 4:14p John
104 * Added code to preload textures to video card for AGP. Added in code
105 * to page in some bitmaps that weren't getting paged in at level start.
107 * 32 5/22/98 10:29p John
108 * made direct3d textures scale as little as glide.
110 * 31 5/22/98 12:54p John
111 * forced all cards to use a max of 256 pixel wide textures, but added a
112 * registry setting to disable it.
114 * 30 5/21/98 9:56p John
115 * Made Direct3D work with classic alpha-blending only devices, like the
116 * Virge. Added a texture type XPARENT that fills the alpha in in the
117 * bitmap for Virge. Added support for Permedia by making making
118 * additive alphablending be one/one instead of alpha/one, which didn't
119 * work, and there is no way to tell this from caps.
121 * 29 5/20/98 10:23a John
122 * put in code to fix an optimized build problem.
124 * 28 5/18/98 8:26p John
125 * Made cards with only 1bpp alpha fonts work.
127 * 27 5/12/98 7:53p John
128 * Fixed some 3dfx d3d bugs on allenders, jasen and johnson's computers
129 * caused by 8:3:3:2 format being used, but not liked by the card.
131 * 26 5/12/98 8:18a John
132 * Put in code to use a different texture format for alpha textures and
133 * normal textures. Turned off filtering for aabitmaps. Took out
134 * destblend=invsrccolor alpha mode that doesn't work on riva128.
136 * 25 5/11/98 10:58a John
137 * Fixed pilot name cursor bug. Started adding in code for alphachannel
140 * 24 5/09/98 12:37p John
141 * More texture caching
143 * 23 5/09/98 12:16p John
144 * Even better texture caching.
146 * 22 5/09/98 11:07a John
147 * Better Direct3D texture caching
149 * 21 5/08/98 5:41p John
151 * 20 5/08/98 5:36p John
152 * MAde texturing blink white but not crash
154 * 19 5/07/98 3:02p John
155 * Mpre texture cleanup. You can now reinit d3d without a crash.
157 * 18 5/07/98 11:31a John
158 * Removed DEMO defines
160 * 17 5/07/98 10:28a John
161 * Made texture format use 4444. Made fonts use alpha to render.
163 * 16 5/07/98 9:40a John
164 * Fixed some bitmap transparency issues with Direct3D.
166 * 15 5/06/98 11:21p John
167 * Fixed a bitmap bug with Direct3D. Started adding new caching code into
170 * 14 5/06/98 8:41p John
171 * Fixed some font clipping bugs. Moved texture handle set code for d3d
172 * into the texture module.
174 * 13 5/03/98 10:52a John
175 * Made D3D sort of work on 3dfx.
177 * 12 5/03/98 10:43a John
178 * Working on Direct3D.
180 * 11 4/09/98 11:05a John
181 * Removed all traces of Direct3D out of the demo version of Freespace and
184 * 10 3/12/98 5:36p John
185 * Took out any unused shaders. Made shader code take rgbc instead of
186 * matrix and vector since noone used it like a matrix and it would have
187 * been impossible to do in hardware. Made Glide implement a basic
188 * shader for online help.
190 * 9 3/08/98 10:25a John
191 * Made textures in VRAM reload if they changed
193 * 8 3/07/98 8:29p John
194 * Put in some Direct3D features. Transparency on bitmaps. Made fonts &
195 * aabitmaps render nice.
197 * 7 3/06/98 5:39p John
198 * Started adding in aabitmaps
200 * 6 3/02/98 6:00p John
201 * Moved MAX_BITMAPS into BmpMan.h so the stuff in the graphics code that
202 * is dependent on it won't break if it changes. Made ModelCache slots
203 * be equal to MAX_OBJECTS which is what it is.
205 * 5 2/17/98 7:46p John
206 * Took out debug code
208 * 4 2/17/98 7:28p John
209 * Got fonts and texturing working in Direct3D
211 * 3 2/06/98 4:56p John
212 * Turned off texturing
214 * 2 2/05/98 9:21p John
215 * Some new Direct3D code. Added code to monitor a ton of stuff in the
218 * 1 2/03/98 9:24p John
224 #include "grd3dinternal.h"
229 #include "systemvars.h"
230 #include "osregistry.h"
232 #include "multi_log.h"
234 typedef struct tcache_slot_d3d {
235 LPDIRECTDRAWSURFACE vram_texture_surface;
236 LPDIRECT3DTEXTURE2 vram_texture;
237 D3DTEXTUREHANDLE texture_handle;
238 float u_scale, v_scale;
241 char used_this_frame;
246 tcache_slot_d3d *data_sections[MAX_BMAP_SECTIONS_X][MAX_BMAP_SECTIONS_Y];
247 tcache_slot_d3d *parent;
250 static void *Texture_sections = NULL;
251 tcache_slot_d3d *Textures = NULL;
254 int D3D_texture_sections = 0;
255 int D3D_texture_ram = 0;
256 int D3D_frame_count = 0;
257 int D3D_min_texture_width = 0;
258 int D3D_max_texture_width = 0;
259 int D3D_min_texture_height = 0;
260 int D3D_max_texture_height = 0;
261 int D3D_square_textures = 0;
262 int D3D_pow2_textures = 0;
263 int D3D_textures_in = 0;
264 int D3D_textures_in_frame = 0;
265 int D3D_last_bitmap_id = -1;
266 int D3D_last_detail = -1;
267 int D3D_last_bitmap_type = -1;
268 int D3D_last_section_x = -1;
269 int D3D_last_section_y = -1;
274 int d3d_free_texture( tcache_slot_d3d *t )
279 if ( t->bitmap_id > -1 ) {
280 // if I, or any of my children have been used this frame, bail
281 if(t->used_this_frame){
284 for(idx=0; idx<MAX_BMAP_SECTIONS_X; idx++){
285 for(s_idx=0; s_idx<MAX_BMAP_SECTIONS_Y; s_idx++){
286 if((t->data_sections[idx][s_idx] != NULL) && (t->data_sections[idx][s_idx]->used_this_frame)){
292 // ok, now we know its legal to free everything safely
293 if ( t->vram_texture ) {
294 t->vram_texture->Release();
295 t->vram_texture = NULL;
298 if ( t->vram_texture_surface ) {
299 t->vram_texture_surface->Release();
300 t->vram_texture_surface = NULL;
303 t->texture_handle = NULL;
305 if ( D3D_last_bitmap_id == t->bitmap_id ) {
306 D3D_last_bitmap_id = -1;
309 // if this guy has children, free them too, since the children
310 // actually make up his size
311 for(idx=0; idx<MAX_BMAP_SECTIONS_X; idx++){
312 for(s_idx=0; s_idx<MAX_BMAP_SECTIONS_Y; s_idx++){
313 if(t->data_sections[idx][s_idx] != NULL){
314 d3d_free_texture(t->data_sections[idx][s_idx]);
320 t->used_this_frame = 0;
321 D3D_textures_in -= t->size;
327 // we must make sure we never free my parent or any of my siblings!!!!!
328 int d3d_older_test(tcache_slot_d3d *new_slot, tcache_slot_d3d *test, tcache_slot_d3d *oldest)
330 if ( (test != new_slot) && (test != new_slot->parent) && (test->bitmap_id > -1) && (!test->used_this_frame)) {
331 if ( (oldest == NULL) || (test->time_created < oldest->time_created)) {
340 int d3d_free_some_texture_ram(tcache_slot_d3d *t, int size)
342 tcache_slot_d3d *oldest = NULL;
344 // Go through all the textures... find the oldest one
345 // that was not used this frame yet.
348 int goal_size = D3D_textures_in - size*2;
349 if ( goal_size < 0 ) {
351 } else if ( goal_size > D3D_texture_ram*3/4 ) {
352 goal_size = D3D_texture_ram*3/4;
355 while( D3D_textures_in > goal_size ) {
357 for( i=0; i<MAX_BITMAPS; i++ ) {
358 // maybe pick this one
359 if(d3d_older_test(t, &Textures[i], oldest)){
360 oldest = &Textures[i];
364 if ( oldest == NULL ) {
365 mprintf(( "Couldn't free enough VRAM this frame... you might see some ugliness!\n" ));
369 d3d_free_texture(oldest);
372 mprintf(( "Freed 1/4 of the VRAM\n" ));
377 int Show_uploads = 0;
378 DCF_BOOL( show_uploads, Show_uploads )
381 // is the given existing texture handle the same dimensions as the passed in bitmap?
382 int d3d_tcache_same_dimension(int bitmap_id, int bitmap_type, tcache_slot_d3d *t)
385 int w, h, nframes, fps;
387 bitmap_section_info *s = NULL;
390 bm_get_info(bitmap_id, &w, &h, &flags, &nframes, &fps, &s);
398 if(bitmap_type == TCACHE_TYPE_BITMAP_SECTION){
399 for(idx=0; idx<s->num_x; idx++){
400 for(s_idx=0; s_idx<s->num_y; s_idx++){
402 if(t->data_sections[idx][s_idx] == NULL){
406 // given a bitmap and a section, return the size (w, h)
407 bm_get_section_size(bitmap_id, idx, s_idx, &w, &h);
410 if((t->data_sections[idx][s_idx]->w != w) || (t->data_sections[idx][s_idx]->h != h)){
416 // non-sectioned bitmap
418 if((t->w != w) || (t->h != h)){
427 // get the final texture size (the one which will get allocated as a surface)
428 void d3d_tcache_get_adjusted_texture_size(int w_in, int h_in, int *w_out, int *h_out)
433 if((w_out == NULL) || (h_out == NULL)){
441 if ( D3D_pow2_textures ) {
443 for (i=0; i<16; i++ ) {
444 if ( (tex_w > (1<<i)) && (tex_w <= (1<<(i+1))) ) {
450 for (i=0; i<16; i++ ) {
451 if ( (tex_h > (1<<i)) && (tex_h <= (1<<(i+1))) ) {
458 if ( tex_w < D3D_min_texture_width ) {
459 tex_w = D3D_min_texture_width;
460 } else if ( tex_w > D3D_max_texture_width ) {
461 tex_w = D3D_max_texture_width;
464 if ( tex_h < D3D_min_texture_height ) {
465 tex_h = D3D_min_texture_height;
466 } else if ( tex_h > D3D_max_texture_height ) {
467 tex_h = D3D_max_texture_height;
470 if ( D3D_square_textures ) {
472 // Make the both be equal to larger of the two
473 new_size = max(tex_w, tex_h);
478 // store the outgoing size
483 // data == start of bitmap data
484 // sx == x offset into bitmap
485 // sy == y offset into bitmap
486 // src_w == absolute width of section on source bitmap
487 // src_h == absolute height of section on source bitmap
488 // bmap_w == width of source bitmap
489 // bmap_h == height of source bitmap
490 // tex_w == width of final texture
491 // tex_h == height of final texture
492 int d3d_create_texture_sub(int bitmap_type, int texture_handle, ushort *data, int sx, int sy, int src_w, int src_h, int bmap_w, int bmap_h, int tex_w, int tex_h, tcache_slot_d3d *t, int reload, int fail_on_full)
494 LPDIRECTDRAWSURFACE sys_texture_surface = NULL;
495 LPDIRECT3DTEXTURE2 sys_texture = NULL;
499 if ( Show_uploads ) {
501 mprintf(( "Reloading '%s'\n", bm_get_filename(texture_handle) ));
503 mprintf(( "Uploading '%s'\n", bm_get_filename(texture_handle) ));
513 if ( t->used_this_frame ) {
514 mprintf(( "ARGHH!!! Texture already used this frame! Cannot free it!\n" ));
519 if(!d3d_free_texture(t)){
526 DWORD dwHeight, dwWidth;
530 DDPIXELFORMAT *surface_desc;
532 switch( bitmap_type ) {
533 case TCACHE_TYPE_AABITMAP:
534 surface_desc = &AlphaTextureFormat;
537 case TCACHE_TYPE_XPARENT:
541 surface_desc = &NonAlphaTextureFormat;
544 // get final texture size
545 d3d_tcache_get_adjusted_texture_size(tex_w, tex_h, &tex_w, &tex_h);
547 if ( (tex_w < 1) || (tex_h < 1) ) {
548 mprintf(("Bitmap is to small at %dx%d.\n", tex_w, tex_h ));
552 if ( bitmap_type == TCACHE_TYPE_AABITMAP ) {
553 t->u_scale = (float)bmap_w / (float)tex_w;
554 t->v_scale = (float)bmap_h / (float)tex_h;
555 } else if(bitmap_type == TCACHE_TYPE_BITMAP_SECTION){
556 t->u_scale = (float)src_w / (float)tex_w;
557 t->v_scale = (float)src_h / (float)tex_h;
565 bmp_data = (ushort *)data;
566 ubyte *bmp_data_byte = (ubyte*)data;
568 // Create a surface in system memory and load texture into it.
570 // Create a surface of the given format using the dimensions of the bitmap
571 memset(&ddsd, 0, sizeof(DDSURFACEDESC));
573 ddsd.dwSize = sizeof(DDSURFACEDESC);
574 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
575 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY;
576 ddsd.dwHeight = dwHeight;
577 ddsd.dwWidth = dwWidth;
578 ddsd.ddpfPixelFormat = *surface_desc;
580 sys_texture_surface = NULL;
581 ddrval = lpDD->CreateSurface(&ddsd, &sys_texture_surface, NULL);
582 if ( (ddrval != DD_OK) || (sys_texture_surface == NULL) ) {
583 mprintf(("CreateSurface for texture failed (loadtex), w=%d, h=%d, %s\n", tex_w, tex_h, d3d_error_string(ddrval) ));
584 mprintf(( "Texture RAM = %d KB\n", D3D_textures_in / 1024 ));
585 // bm_unlock(bitmap_handle);
589 // Lock the surface so it can be filled with the bitmap data
590 memset(&ddsd, 0, sizeof(DDSURFACEDESC));
591 ddsd.dwSize = sizeof(DDSURFACEDESC);
592 ddrval = sys_texture_surface->Lock(NULL, &ddsd, 0, NULL);
593 if (ddrval != DD_OK) {
594 sys_texture_surface->Release();
595 mprintf(("Lock failed while loading surface (loadtex).\n" ));
599 Assert( surface_desc->dwRGBBitCount == 16 );
601 // Each RGB bit count requires different pointers
606 switch( bitmap_type ) {
607 case TCACHE_TYPE_AABITMAP:
608 // setup convenient translation table
609 for (i=0; i<16; i++ ) {
613 a = Gr_gamma_lookup[(i*255)/15];
614 r /= Gr_ta_red.scale;
615 g /= Gr_ta_green.scale;
616 b /= Gr_ta_blue.scale;
617 a /= Gr_ta_alpha.scale;
618 xlat[i] = unsigned short(((a<<Gr_ta_alpha.shift) | (r << Gr_ta_red.shift) | (g << Gr_ta_green.shift) | (b << Gr_ta_blue.shift)));
622 for ( ; i<256; i++ ) {
626 for (j = 0; j < tex_h; j++) {
627 lpSP = (unsigned short*)(((char*)ddsd.lpSurface) + ddsd.lPitch * j);
629 for (i = 0; i < tex_w; i++) {
630 if ( (i < bmap_w) && (j<bmap_h) ) {
631 *lpSP++ = xlat[(ubyte)bmp_data_byte[j*bmap_w+i]];
639 case TCACHE_TYPE_BITMAP_SECTION:
640 for (j = 0; j < src_h; j++) {
641 // the proper line in the temp ram
642 lpSP = (unsigned short*)(((char*)ddsd.lpSurface) + ddsd.lPitch * j);
645 for (i = 0; i < src_w; i++) {
646 // stuff the texture into vram
647 *lpSP++ = bmp_data[((j+sy) * bmap_w) + sx + i];
652 default: { // normal:
653 fix u, utmp, v, du, dv;
657 du = ( (bmap_w-1)*F1_0 ) / tex_w;
658 dv = ( (bmap_h-1)*F1_0 ) / tex_h;
660 for (j = 0; j < tex_h; j++) {
661 lpSP = (unsigned short*)(((char*)ddsd.lpSurface) + ddsd.lPitch * j);
665 for (i = 0; i < tex_w; i++) {
666 *lpSP++ = bmp_data[f2i(v)*bmap_w+f2i(utmp)];
675 // bm_unlock(bitmap_handle);
677 // Unlock the texture
678 sys_texture_surface->Unlock(NULL);
681 ddrval = sys_texture_surface->QueryInterface(IID_IDirect3DTexture2, (LPVOID *)&sys_texture);
682 if ( (ddrval != DD_OK) || (sys_texture == NULL) ) {
683 mprintf(( "Getting sys surface's texture failed!\n" ));
688 goto FreeSurfacesAndExit;
694 // Create a surface of the given format using the dimensions of the bitmap
695 memset(&ddsd, 0, sizeof(DDSURFACEDESC));
697 ddsd.dwSize = sizeof(DDSURFACEDESC);
698 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
699 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_ALLOCONLOAD | DDSCAPS_VIDEOMEMORY;
700 //| DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM | DDSCAPS_ALLOCONLOAD;
701 ddsd.dwHeight = dwHeight;
702 ddsd.dwWidth = dwWidth;
703 ddsd.ddpfPixelFormat = *surface_desc;
705 t->vram_texture_surface = NULL;
706 ddrval = lpDD->CreateSurface(&ddsd, &t->vram_texture_surface, NULL);
707 if ( (ddrval != DD_OK) || (t->vram_texture_surface == NULL) ) {
708 t->vram_texture = NULL;
709 t->vram_texture_surface = NULL;
710 t->texture_handle = NULL;
712 if ( ddrval==DDERR_OUTOFVIDEOMEMORY ) {
713 mprintf(("Out of VRAM (w=%d, h=%d, used=%d KB)\n", tex_w, tex_h, D3D_textures_in / 1024 ));
714 if ( fail_on_full ) {
718 goto FreeSurfacesAndExit;
720 if ( d3d_free_some_texture_ram(t,dwHeight*dwWidth*2)) {
724 mprintf(("CreateSurface for VRAM texture failed, w=%d, h=%d\n%s\n", tex_w, tex_h, d3d_error_string(ddrval) ));
725 mprintf(( "Texture RAM = %d KB\n", D3D_textures_in / 1024 ));
732 goto FreeSurfacesAndExit;
736 t->vram_texture = NULL;
737 ddrval = t->vram_texture_surface->QueryInterface(IID_IDirect3DTexture2, (LPVOID *)&t->vram_texture);
738 if ( (ddrval != DD_OK) || (t->vram_texture == NULL) ) {
739 mprintf(( "GR_D3D_INIT: TextureSurface->QueryInterface failed.\n" ));
745 goto FreeSurfacesAndExit;
748 // char *name = bm_get_filename(bitmap_handle);
749 // mprintf(( "Uploading '%s'\n", name ));
750 t->texture_handle = NULL;
751 ddrval = t->vram_texture->GetHandle(lpD3DDevice, &t->texture_handle );
752 if ( (ddrval != DD_OK) || (t->texture_handle == NULL) ) {
753 mprintf(( "GR_D3D_INIT: Texture->GetHandle failed.\n" ));
754 t->texture_handle = NULL;
760 goto FreeSurfacesAndExit;
764 // argh. this texture appears to be bogus. lets free it
765 if(t->vram_texture == NULL){
771 goto FreeSurfacesAndExit;
774 ddrval = t->vram_texture->Load( sys_texture );
775 if ( ddrval != DD_OK ) {
776 mprintf(("VRAM Load failed, w=%d, h=%d, %s\n", tex_w, tex_h, d3d_error_string(ddrval) ));
777 mprintf(( "Texture RAM = %d KB\n", D3D_textures_in / 1024 ));
783 goto FreeSurfacesAndExit;
786 t->bitmap_id = texture_handle;
787 t->time_created = D3D_frame_count;
788 t->used_this_frame = 0;
789 t->size = tex_w * tex_h * 2;
790 t->w = (ushort)tex_w;
791 t->h = (ushort)tex_h;
792 D3D_textures_in_frame += t->size;
794 D3D_textures_in += t->size;
799 sys_texture->Release();
803 if ( sys_texture_surface ) {
804 sys_texture_surface->Release();
805 sys_texture_surface = NULL;
808 // hopefully this is 1 :)
812 int d3d_create_texture(int bitmap_handle, int bitmap_type, tcache_slot_d3d *tslot, int fail_on_full)
816 int final_w, final_h;
820 // setup texture/bitmap flags
823 case TCACHE_TYPE_AABITMAP:
824 flags |= BMP_AABITMAP;
827 case TCACHE_TYPE_NORMAL:
828 flags |= BMP_TEX_OTHER;
829 case TCACHE_TYPE_XPARENT:
830 flags |= BMP_TEX_XPARENT;
832 case TCACHE_TYPE_NONDARKENING:
834 flags |= BMP_TEX_NONDARK;
838 // lock the bitmap into the proper format
839 bmp = bm_lock(bitmap_handle, bpp, flags);
841 mprintf(("Couldn't lock bitmap %d.\n", bitmap_handle ));
848 if ( bitmap_type != TCACHE_TYPE_AABITMAP ) {
849 max_w /= D3D_texture_divider;
850 max_h /= D3D_texture_divider;
852 // Detail.debris_culling goes from 0 to 4.
853 max_w /= 16 >> Detail.hardware_textures;
854 max_h /= 16 >> Detail.hardware_textures;
857 // get final texture size as it will be allocated as a DD surface
858 d3d_tcache_get_adjusted_texture_size(max_w, max_h, &final_w, &final_h);
860 // if this tcache slot has no bitmap
861 if ( tslot->bitmap_id < 0) {
864 // different bitmap altogether - determine if the new one can use the old one's slot
865 else if (tslot->bitmap_id != bitmap_handle) {
866 if((final_w == tslot->w) && (final_h == tslot->h)){
869 ml_printf("Reloading texture %d\n", bitmap_handle);
876 int ret_val = d3d_create_texture_sub(bitmap_type, bitmap_handle, (ushort*)bmp->data, 0, 0, bmp->w, bmp->h, bmp->w, bmp->h, max_w, max_h, tslot, reload, fail_on_full);
879 bm_unlock(bitmap_handle);
884 int d3d_create_texture_sectioned(int bitmap_handle, int bitmap_type, tcache_slot_d3d *tslot, int sx, int sy, int fail_on_full)
888 int final_w, final_h;
889 int section_x, section_y;
892 // setup texture/bitmap flags
893 Assert(bitmap_type == TCACHE_TYPE_BITMAP_SECTION);
894 if(bitmap_type != TCACHE_TYPE_BITMAP_SECTION){
895 bitmap_type = TCACHE_TYPE_BITMAP_SECTION;
897 flags = BMP_TEX_XPARENT;
899 // lock the bitmap in the proper format
900 bmp = bm_lock(bitmap_handle, 16, flags);
902 mprintf(("Couldn't lock bitmap %d.\n", bitmap_handle ));
906 // determine the width and height of this section
907 bm_get_section_size(bitmap_handle, sx, sy, §ion_x, §ion_y);
909 // get final texture size as it will be allocated as a DD surface
910 d3d_tcache_get_adjusted_texture_size(section_x, section_y, &final_w, &final_h);
912 // if this tcache slot has no bitmap
913 if ( tslot->bitmap_id < 0) {
916 // different bitmap altogether - determine if the new one can use the old one's slot
917 else if (tslot->bitmap_id != bitmap_handle) {
918 if((final_w == tslot->w) && (final_h == tslot->h)){
926 int ret_val = d3d_create_texture_sub(bitmap_type, bitmap_handle, (ushort*)bmp->data, bmp->sections.sx[sx], bmp->sections.sy[sy], section_x, section_y, bmp->w, bmp->h, section_x, section_y, tslot, reload, fail_on_full);
929 bm_unlock(bitmap_handle);
934 extern int bm_get_cache_slot( int bitmap_id, int separate_ani_frames );
935 int d3d_tcache_set(int bitmap_id, int bitmap_type, float *u_scale, float *v_scale, int fail_on_full, int sx, int sy, int force )
941 if ( bitmap_id < 0 ) {
942 D3D_last_bitmap_id = -1;
946 if ( D3D_last_detail != Detail.hardware_textures ) {
947 D3D_last_detail = Detail.hardware_textures;
951 //mprintf(( "Setting texture %d\n", bitmap_handle ));
956 int n = bm_get_cache_slot( bitmap_id, 1 );
957 tcache_slot_d3d * t = &Textures[n];
959 if ( (D3D_last_bitmap_id == bitmap_id) && (D3D_last_bitmap_type==bitmap_type) && (t->bitmap_id == bitmap_id) && (D3D_last_section_x == sx) && (D3D_last_section_y == sy)) {
960 t->used_this_frame++;
962 // mark all children as used
963 if(D3D_texture_sections){
964 for(idx=0; idx<MAX_BMAP_SECTIONS_X; idx++){
965 for(s_idx=0; s_idx<MAX_BMAP_SECTIONS_Y; s_idx++){
966 if(t->data_sections[idx][s_idx] != NULL){
967 t->data_sections[idx][s_idx]->used_this_frame++;
973 *u_scale = t->u_scale;
974 *v_scale = t->v_scale;
978 // if this is a sectioned bitmap
979 if(bitmap_type == TCACHE_TYPE_BITMAP_SECTION){
980 Assert((sx >= 0) && (sy >= 0) && (sx < MAX_BMAP_SECTIONS_X) && (sy < MAX_BMAP_SECTIONS_Y));
981 if(!((sx >= 0) && (sy >= 0) && (sx < MAX_BMAP_SECTIONS_X) && (sy < MAX_BMAP_SECTIONS_Y))){
987 // if the texture sections haven't been created yet
988 if((t->bitmap_id < 0) || (t->bitmap_id != bitmap_id)){
989 // lock the bitmap in the proper format
990 bmp = bm_lock(bitmap_id, 16, BMP_TEX_XPARENT);
991 bm_unlock(bitmap_id);
993 // now lets do something for each texture
994 for(idx=0; idx<bmp->sections.num_x; idx++){
995 for(s_idx=0; s_idx<bmp->sections.num_y; s_idx++){
996 // hmm. i'd rather we didn't have to do it this way...
997 if(!d3d_create_texture_sectioned(bitmap_id, bitmap_type, t->data_sections[idx][s_idx], idx, s_idx, fail_on_full)){
1001 // not used this frame
1002 t->data_sections[idx][s_idx]->used_this_frame = 0;
1006 // zero out pretty much everything in the parent struct since he's just the root
1007 t->bitmap_id = bitmap_id;
1008 t->texture_handle = NULL;
1009 t->time_created = t->data_sections[sx][sy]->time_created;
1010 t->used_this_frame = 0;
1011 t->vram_texture = NULL;
1012 t->vram_texture_surface = NULL;
1015 // argh. we failed to upload. free anything we can
1017 d3d_free_texture(t);
1019 // swap in the texture we want
1021 t = t->data_sections[sx][sy];
1024 // all other "normal" textures
1025 else if((bitmap_id < 0) || (bitmap_id != t->bitmap_id)){
1026 ret_val = d3d_create_texture( bitmap_id, bitmap_type, t, fail_on_full );
1029 // everything went ok
1030 if(ret_val && (t->texture_handle != NULL) && !vram_full){
1031 *u_scale = t->u_scale;
1032 *v_scale = t->v_scale;
1034 d3d_SetRenderState(D3DRENDERSTATE_TEXTUREHANDLE, t->texture_handle );
1036 D3D_last_bitmap_id = t->bitmap_id;
1037 D3D_last_bitmap_type = bitmap_type;
1038 D3D_last_section_x = sx;
1039 D3D_last_section_y = sy;
1041 t->used_this_frame++;
1051 int D3D_should_preload = 0;
1053 void d3d_tcache_init(int use_sections)
1057 D3D_should_preload = 0;
1061 DWORD dwFree, dwTotal;
1063 memset(&ddsCaps,0,sizeof(ddsCaps) );
1064 ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1065 HRESULT ddrval = lpDD->GetAvailableVidMem(&ddsCaps, &dwTotal, &dwFree);
1066 if ( ddrval != DD_OK ) {
1067 mprintf(( "GR_D3D_INIT: GetAvailableVidMem failed.\n" ));
1072 D3D_texture_ram = dwFree;
1074 uint tmp_pl = os_config_read_uint( NULL, NOX("D3DPreloadTextures"), 255 );
1076 if ( tmp_pl == 0 ) {
1077 D3D_should_preload = 0;
1078 } else if ( tmp_pl == 1 ) {
1079 D3D_should_preload = 1;
1081 if ( D3D_texture_ram >= 6*1024*1024 ) {
1082 D3D_should_preload = 1;
1084 D3D_should_preload = 0;
1089 int megs = dwFree / (1024*1024);
1090 uint tmp_val = os_config_read_uint( NULL, NOX("D3DTextureDivider"), 255 );
1092 if ( tmp_val == 0 ) {
1095 D3D_texture_divider = 4;
1096 } else if ( megs <=8 ) {
1097 D3D_texture_divider = 3;
1098 } else if ( megs <=16 ) {
1099 D3D_texture_divider = 2;
1101 D3D_texture_divider = 1;
1103 } else if ( tmp_val < 5 ) {
1104 D3D_texture_divider = tmp_val;
1107 D3D_texture_divider = 4;
1111 // setup texture divider
1112 uint tmp_val = os_config_read_uint( NULL, NOX("D3DFast"), 1 );
1113 D3D_texture_divider = 1;
1115 D3D_texture_divider = 4;
1119 int megs = dwFree / (1024*1024);
1120 mprintf(( "TEXTURE RAM: %d bytes (%d MB) available, size divisor = %d\n", dwFree, megs, D3D_texture_divider ));
1125 D3D_min_texture_width = (int)lpDevDesc->dwMinTextureWidth;
1126 D3D_max_texture_width = (int)lpDevDesc->dwMaxTextureWidth;
1127 D3D_min_texture_height = (int)lpDevDesc->dwMinTextureHeight;
1128 D3D_max_texture_height = (int)lpDevDesc->dwMaxTextureHeight;
1130 // The following checks are needed because the PowerVR reports
1131 // it's texture caps as 0,0 up to 0,0.
1132 if ( D3D_min_texture_width < 16 ) {
1133 D3D_min_texture_width = 16;
1135 if ( D3D_min_texture_height < 16 ) {
1136 D3D_min_texture_height = 16;
1138 if ( D3D_max_texture_width < 16 ) {
1139 mprintf(( "Driver claims to have a max texture width of %d. Bashing to 256.\n(Is this a PowerVR?)\n", D3D_max_texture_width ));
1140 D3D_max_texture_width = 256; // Can we assume 256?
1143 if ( D3D_max_texture_height < 16 ) {
1144 mprintf(( "Driver claims to have a max texture height of %d. Bashing to 256.\n(Is this a PowerVR?)\n", D3D_max_texture_height ));
1145 D3D_max_texture_height = 256; // Can we assume 256?
1148 if (lpDevDesc->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_SQUAREONLY) {
1149 mprintf(( "Darn. Driver needs square textures.\n" ));
1150 D3D_square_textures = 1;
1152 mprintf(( "Woohoo! Driver doesn't need square textures!\n" ));
1153 D3D_square_textures = 0;
1156 if ( lpDevDesc->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2 ) {
1157 mprintf(( "Textures must be power of 2.\n" ));
1158 D3D_pow2_textures = 1;
1160 mprintf(( "Textures can be any size.\n" ));
1161 D3D_pow2_textures = 0;
1165 if ( !(DD_driver_caps.dwCaps2 & DDCAPS2_WIDESURFACES) ) {
1166 if ( D3D_max_texture_width > gr_screen.max_w ) {
1167 D3D_max_texture_width = gr_screen.max_w;
1169 if ( D3D_pow2_textures ) {
1170 for (i=0; i<16; i++ ) {
1171 if ( (D3D_max_texture_width>= (1<<i)) && (D3D_max_texture_width < (1<<(i+1))) ) {
1172 D3D_max_texture_width = 1 << i;
1178 if ( D3D_max_texture_height > D3D_max_texture_width ) {
1179 D3D_max_texture_height = D3D_max_texture_width;
1182 mprintf(( "Doesn't support wide surfaces. Bashing max down to %d\n", D3D_max_texture_width ));
1186 if ( !os_config_read_uint( NULL, NOX("D3DUseLargeTextures"), 0 )) {
1187 mprintf(( "No large texture flag specified, so using max of 256\n" ));
1188 if ( D3D_max_texture_width > 256 ) {
1189 D3D_max_texture_width = 256;
1192 if ( D3D_max_texture_height > 256 ) {
1193 D3D_max_texture_height = 256;
1196 mprintf(( "Large textures enabled!\n" ));
1199 Textures = (tcache_slot_d3d *)malloc(MAX_BITMAPS*sizeof(tcache_slot_d3d));
1205 Texture_sections = (tcache_slot_d3d*)malloc(MAX_BITMAPS * MAX_BMAP_SECTIONS_X * MAX_BMAP_SECTIONS_Y * sizeof(tcache_slot_d3d));
1206 if(!Texture_sections){
1209 memset(Texture_sections, 0, MAX_BITMAPS * MAX_BMAP_SECTIONS_X * MAX_BMAP_SECTIONS_Y * sizeof(tcache_slot_d3d));
1212 // Init the texture structures
1213 int section_count = 0;
1214 for( i=0; i<MAX_BITMAPS; i++ ) {
1215 Textures[i].vram_texture = NULL;
1216 Textures[i].vram_texture_surface = NULL;
1217 Textures[i].texture_handle = NULL;
1219 Textures[i].bitmap_id = -1;
1220 Textures[i].size = 0;
1221 Textures[i].used_this_frame = 0;
1223 Textures[i].parent = NULL;
1225 // allocate sections
1227 for(idx=0; idx<MAX_BMAP_SECTIONS_X; idx++){
1228 for(s_idx=0; s_idx<MAX_BMAP_SECTIONS_Y; s_idx++){
1229 Textures[i].data_sections[idx][s_idx] = &((tcache_slot_d3d*)Texture_sections)[section_count++];
1230 Textures[i].data_sections[idx][s_idx]->parent = &Textures[i];
1232 Textures[i].data_sections[idx][s_idx]->vram_texture = NULL;
1233 Textures[i].data_sections[idx][s_idx]->vram_texture_surface = NULL;
1234 Textures[i].data_sections[idx][s_idx]->texture_handle = NULL;
1236 Textures[i].data_sections[idx][s_idx]->bitmap_id = -1;
1237 Textures[i].data_sections[idx][s_idx]->size = 0;
1238 Textures[i].data_sections[idx][s_idx]->used_this_frame = 0;
1242 for(idx=0; idx<MAX_BMAP_SECTIONS_X; idx++){
1243 for(s_idx=0; s_idx<MAX_BMAP_SECTIONS_Y; s_idx++){
1244 Textures[i].data_sections[idx][s_idx] = NULL;
1250 D3D_texture_sections = use_sections;
1252 D3D_last_detail = Detail.hardware_textures;
1253 D3D_last_bitmap_id = -1;
1254 D3D_last_bitmap_type = -1;
1256 D3D_last_section_x = -1;
1257 D3D_last_section_y = -1;
1259 D3D_textures_in = 0;
1260 D3D_textures_in_frame = 0;
1264 void d3d_tcache_flush()
1269 for( i=0; i<MAX_BITMAPS; i++ ) {
1270 d3d_free_texture( &Textures[i] );
1272 if ( D3D_textures_in != 0 ) {
1273 mprintf(( "WARNING: VRAM is at %d instead of zero after flushing!\n", D3D_textures_in ));
1274 D3D_textures_in = 0;
1277 D3D_last_bitmap_id = -1;
1278 D3D_last_section_x = -1;
1279 D3D_last_section_y = -1;
1282 void d3d_tcache_cleanup()
1286 D3D_textures_in = 0;
1287 D3D_textures_in_frame = 0;
1294 if(Texture_sections != NULL){
1295 free(Texture_sections);
1296 Texture_sections = NULL;
1300 void d3d_tcache_frame()
1304 D3D_last_bitmap_id = -1;
1305 D3D_textures_in_frame = 0;
1310 for( i=0; i<MAX_BITMAPS; i++ ) {
1311 Textures[i].used_this_frame = 0;
1314 if(Textures[i].data_sections[0][0] != NULL){
1315 Assert(D3D_texture_sections);
1316 if(D3D_texture_sections){
1317 for(idx=0; idx<MAX_BMAP_SECTIONS_X; idx++){
1318 for(s_idx=0; s_idx<MAX_BMAP_SECTIONS_Y; s_idx++){
1319 if(Textures[i].data_sections[idx][s_idx] != NULL){
1320 Textures[i].data_sections[idx][s_idx]->used_this_frame = 0;
1335 void gr_d3d_preload_init()
1337 if ( gr_screen.mode != GR_DIRECT3D ) {
1343 int gr_d3d_preload(int bitmap_num, int is_aabitmap)
1345 if ( gr_screen.mode != GR_DIRECT3D ) {
1349 if ( !D3D_should_preload ) {
1353 float u_scale, v_scale;
1357 if ( is_aabitmap ) {
1358 retval = gr_tcache_set(bitmap_num, TCACHE_TYPE_AABITMAP, &u_scale, &v_scale, 1 );
1360 retval = gr_tcache_set(bitmap_num, TCACHE_TYPE_NORMAL, &u_scale, &v_scale, 1 );
1364 mprintf(("Texture upload failed!\n" ));
1370 // call this to safely fill in the texture shift and scale values for the specified texture type (Gr_t_*)
1371 void gr_d3d_get_tex_format(int alpha)
1374 DDPIXELFORMAT *surface_desc;
1379 // get the proper texture format
1381 surface_desc = &AlphaTextureFormat;
1383 surface_desc = &NonAlphaTextureFormat;
1386 // Determine the red, green and blue masks' shift and scale.
1387 for (s = 0, m = surface_desc->dwRBitMask; !(m & 1); s++, m >>= 1);
1389 Gr_t_red_scale = 255 / (surface_desc->dwRBitMask >> s);
1390 for (s = 0, m = surface_desc->dwGBitMask; !(m & 1); s++, m >>= 1);
1391 Gr_t_green_shift = s;
1392 Gr_t_green_scale = 255 / (surface_desc->dwGBitMask >> s);
1393 for (s = 0, m = surface_desc->dwBBitMask; !(m & 1); s++, m >>= 1);
1394 Gr_t_blue_shift = s;
1395 Gr_t_blue_scale = 255 / (surface_desc->dwBBitMask >> s);
1397 if ( surface_desc->dwFlags & DDPF_ALPHAPIXELS ) {
1398 for (s = 0, m = surface_desc->dwRGBAlphaBitMask; !(m & 1); s++, m >>= 1);
1399 Gr_t_alpha_shift = s;
1400 Gr_t_alpha_scale = 255 / (surface_desc->dwRGBAlphaBitMask >> s);
1402 Gr_t_alpha_shift = 0;
1403 Gr_t_alpha_scale = 256;