2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
10 * $Logfile: /Freespace2/code/Graphics/GrD3DTexture.cpp $
15 * Code to manage loading textures into VRAM for Direct3D
18 * Revision 1.3 2002/06/09 04:41:17 relnev
19 * added copyright header
21 * Revision 1.2 2002/05/07 03:16:45 theoddone33
22 * The Great Newline Fix
24 * Revision 1.1.1.1 2002/05/03 03:28:09 root
28 * 22 9/09/99 8:53p Dave
29 * Fixed multiplayer degenerate orientation case problem. Make sure warp
30 * effect never goes lower than LOD 1.
32 * 21 9/05/99 11:19p Dave
33 * Made d3d texture cache much more safe. Fixed training scoring bug where
34 * it would backout scores without ever having applied them in the first
37 * 20 8/16/99 4:04p Dave
38 * Big honking checkin.
40 * 19 7/29/99 10:47p Dave
41 * Standardized D3D fogging using vertex fog. Shook out Savage 4 bugs.
43 * 18 7/16/99 1:49p Dave
44 * 8 bit aabitmaps. yay.
46 * 17 7/13/99 1:15p Dave
47 * 32 bit support. Whee!
49 * 16 7/09/99 9:51a Dave
50 * Added thick polyline code.
52 * 15 6/29/99 10:35a Dave
53 * Interface polygon bitmaps! Whee!
55 * 14 6/16/99 4:06p Dave
56 * New pilot info popup. Added new draw-bitmap-as-poly function.
58 * 13 5/05/99 9:02p Dave
59 * Fixed D3D aabitmap rendering. Spiffed up nebula effect a bit (added
60 * rotations, tweaked values, made bitmap selection more random). Fixed
61 * D3D beam weapon clipping problem. Added D3d frame dumping.
63 * 12 2/11/99 3:08p Dave
64 * PXO refresh button. Very preliminary squad war support.
66 * 11 2/05/99 12:52p Dave
67 * Fixed Glide nondarkening textures.
69 * 10 2/03/99 11:44a Dave
70 * Fixed d3d transparent textures.
72 * 9 1/30/99 5:08p Dave
73 * More new hi-res stuff.Support for nice D3D textures.
75 * 8 1/15/99 11:29a Neilk
76 * Fixed D3D screen/texture pixel formatting problem.
78 * 7 1/12/99 12:53a Dave
79 * More work on beam weapons - made collision detection very efficient -
80 * collide against all object types properly - made 3 movement types
81 * smooth. Put in test code to check for possible non-darkening pixels on
84 * 6 12/01/98 6:12p Johnson
85 * Make sure to page in weapon impact animations as xparent textures.
87 * 5 12/01/98 10:32a Johnson
88 * Fixed direct3d font problems. Fixed sun bitmap problem. Fixed direct3d
91 * 4 11/30/98 1:07p Dave
92 * 16 bit conversion, first run.
94 * 3 10/09/98 2:57p Dave
95 * Starting splitting up OS stuff.
97 * 2 10/07/98 10:52a Dave
100 * 1 10/07/98 10:49a Dave
102 * 37 6/13/98 3:18p Hoffoss
103 * NOX()ed out a bunch of strings that shouldn't be translated.
105 * 36 5/23/98 6:12p John
106 * added code to use registry to force preloading of textures or not.
108 * 35 5/23/98 5:17p John
109 * added reg key to set texture divider
111 * 34 5/23/98 5:01p John
112 * made agp preloading happen if >= 6 MB of VRAM.
114 * 33 5/23/98 4:14p John
115 * Added code to preload textures to video card for AGP. Added in code
116 * to page in some bitmaps that weren't getting paged in at level start.
118 * 32 5/22/98 10:29p John
119 * made direct3d textures scale as little as glide.
121 * 31 5/22/98 12:54p John
122 * forced all cards to use a max of 256 pixel wide textures, but added a
123 * registry setting to disable it.
125 * 30 5/21/98 9:56p John
126 * Made Direct3D work with classic alpha-blending only devices, like the
127 * Virge. Added a texture type XPARENT that fills the alpha in in the
128 * bitmap for Virge. Added support for Permedia by making making
129 * additive alphablending be one/one instead of alpha/one, which didn't
130 * work, and there is no way to tell this from caps.
132 * 29 5/20/98 10:23a John
133 * put in code to fix an optimized build problem.
135 * 28 5/18/98 8:26p John
136 * Made cards with only 1bpp alpha fonts work.
138 * 27 5/12/98 7:53p John
139 * Fixed some 3dfx d3d bugs on allenders, jasen and johnson's computers
140 * caused by 8:3:3:2 format being used, but not liked by the card.
142 * 26 5/12/98 8:18a John
143 * Put in code to use a different texture format for alpha textures and
144 * normal textures. Turned off filtering for aabitmaps. Took out
145 * destblend=invsrccolor alpha mode that doesn't work on riva128.
147 * 25 5/11/98 10:58a John
148 * Fixed pilot name cursor bug. Started adding in code for alphachannel
151 * 24 5/09/98 12:37p John
152 * More texture caching
154 * 23 5/09/98 12:16p John
155 * Even better texture caching.
157 * 22 5/09/98 11:07a John
158 * Better Direct3D texture caching
160 * 21 5/08/98 5:41p John
162 * 20 5/08/98 5:36p John
163 * MAde texturing blink white but not crash
165 * 19 5/07/98 3:02p John
166 * Mpre texture cleanup. You can now reinit d3d without a crash.
168 * 18 5/07/98 11:31a John
169 * Removed DEMO defines
171 * 17 5/07/98 10:28a John
172 * Made texture format use 4444. Made fonts use alpha to render.
174 * 16 5/07/98 9:40a John
175 * Fixed some bitmap transparency issues with Direct3D.
177 * 15 5/06/98 11:21p John
178 * Fixed a bitmap bug with Direct3D. Started adding new caching code into
181 * 14 5/06/98 8:41p John
182 * Fixed some font clipping bugs. Moved texture handle set code for d3d
183 * into the texture module.
185 * 13 5/03/98 10:52a John
186 * Made D3D sort of work on 3dfx.
188 * 12 5/03/98 10:43a John
189 * Working on Direct3D.
191 * 11 4/09/98 11:05a John
192 * Removed all traces of Direct3D out of the demo version of Freespace and
195 * 10 3/12/98 5:36p John
196 * Took out any unused shaders. Made shader code take rgbc instead of
197 * matrix and vector since noone used it like a matrix and it would have
198 * been impossible to do in hardware. Made Glide implement a basic
199 * shader for online help.
201 * 9 3/08/98 10:25a John
202 * Made textures in VRAM reload if they changed
204 * 8 3/07/98 8:29p John
205 * Put in some Direct3D features. Transparency on bitmaps. Made fonts &
206 * aabitmaps render nice.
208 * 7 3/06/98 5:39p John
209 * Started adding in aabitmaps
211 * 6 3/02/98 6:00p John
212 * Moved MAX_BITMAPS into BmpMan.h so the stuff in the graphics code that
213 * is dependent on it won't break if it changes. Made ModelCache slots
214 * be equal to MAX_OBJECTS which is what it is.
216 * 5 2/17/98 7:46p John
217 * Took out debug code
219 * 4 2/17/98 7:28p John
220 * Got fonts and texturing working in Direct3D
222 * 3 2/06/98 4:56p John
223 * Turned off texturing
225 * 2 2/05/98 9:21p John
226 * Some new Direct3D code. Added code to monitor a ton of stuff in the
229 * 1 2/03/98 9:24p John
235 #include "grd3dinternal.h"
240 #include "systemvars.h"
241 #include "osregistry.h"
243 #include "multi_log.h"
245 typedef struct tcache_slot_d3d {
246 LPDIRECTDRAWSURFACE vram_texture_surface;
247 LPDIRECT3DTEXTURE2 vram_texture;
248 D3DTEXTUREHANDLE texture_handle;
249 float u_scale, v_scale;
252 char used_this_frame;
257 tcache_slot_d3d *data_sections[MAX_BMAP_SECTIONS_X][MAX_BMAP_SECTIONS_Y];
258 tcache_slot_d3d *parent;
261 static void *Texture_sections = NULL;
262 tcache_slot_d3d *Textures = NULL;
265 int D3D_texture_sections = 0;
266 int D3D_texture_ram = 0;
267 int D3D_frame_count = 0;
268 int D3D_min_texture_width = 0;
269 int D3D_max_texture_width = 0;
270 int D3D_min_texture_height = 0;
271 int D3D_max_texture_height = 0;
272 int D3D_square_textures = 0;
273 int D3D_pow2_textures = 0;
274 int D3D_textures_in = 0;
275 int D3D_textures_in_frame = 0;
276 int D3D_last_bitmap_id = -1;
277 int D3D_last_detail = -1;
278 int D3D_last_bitmap_type = -1;
279 int D3D_last_section_x = -1;
280 int D3D_last_section_y = -1;
285 int d3d_free_texture( tcache_slot_d3d *t )
290 if ( t->bitmap_id > -1 ) {
291 // if I, or any of my children have been used this frame, bail
292 if(t->used_this_frame){
295 for(idx=0; idx<MAX_BMAP_SECTIONS_X; idx++){
296 for(s_idx=0; s_idx<MAX_BMAP_SECTIONS_Y; s_idx++){
297 if((t->data_sections[idx][s_idx] != NULL) && (t->data_sections[idx][s_idx]->used_this_frame)){
303 // ok, now we know its legal to free everything safely
304 if ( t->vram_texture ) {
305 t->vram_texture->Release();
306 t->vram_texture = NULL;
309 if ( t->vram_texture_surface ) {
310 t->vram_texture_surface->Release();
311 t->vram_texture_surface = NULL;
314 t->texture_handle = NULL;
316 if ( D3D_last_bitmap_id == t->bitmap_id ) {
317 D3D_last_bitmap_id = -1;
320 // if this guy has children, free them too, since the children
321 // actually make up his size
322 for(idx=0; idx<MAX_BMAP_SECTIONS_X; idx++){
323 for(s_idx=0; s_idx<MAX_BMAP_SECTIONS_Y; s_idx++){
324 if(t->data_sections[idx][s_idx] != NULL){
325 d3d_free_texture(t->data_sections[idx][s_idx]);
331 t->used_this_frame = 0;
332 D3D_textures_in -= t->size;
338 // we must make sure we never free my parent or any of my siblings!!!!!
339 int d3d_older_test(tcache_slot_d3d *new_slot, tcache_slot_d3d *test, tcache_slot_d3d *oldest)
341 if ( (test != new_slot) && (test != new_slot->parent) && (test->bitmap_id > -1) && (!test->used_this_frame)) {
342 if ( (oldest == NULL) || (test->time_created < oldest->time_created)) {
351 int d3d_free_some_texture_ram(tcache_slot_d3d *t, int size)
353 tcache_slot_d3d *oldest = NULL;
355 // Go through all the textures... find the oldest one
356 // that was not used this frame yet.
359 int goal_size = D3D_textures_in - size*2;
360 if ( goal_size < 0 ) {
362 } else if ( goal_size > D3D_texture_ram*3/4 ) {
363 goal_size = D3D_texture_ram*3/4;
366 while( D3D_textures_in > goal_size ) {
368 for( i=0; i<MAX_BITMAPS; i++ ) {
369 // maybe pick this one
370 if(d3d_older_test(t, &Textures[i], oldest)){
371 oldest = &Textures[i];
375 if ( oldest == NULL ) {
376 mprintf(( "Couldn't free enough VRAM this frame... you might see some ugliness!\n" ));
380 d3d_free_texture(oldest);
383 mprintf(( "Freed 1/4 of the VRAM\n" ));
388 int Show_uploads = 0;
389 DCF_BOOL( show_uploads, Show_uploads )
392 // is the given existing texture handle the same dimensions as the passed in bitmap?
393 int d3d_tcache_same_dimension(int bitmap_id, int bitmap_type, tcache_slot_d3d *t)
396 int w, h, nframes, fps;
398 bitmap_section_info *s = NULL;
401 bm_get_info(bitmap_id, &w, &h, &flags, &nframes, &fps, &s);
409 if(bitmap_type == TCACHE_TYPE_BITMAP_SECTION){
410 for(idx=0; idx<s->num_x; idx++){
411 for(s_idx=0; s_idx<s->num_y; s_idx++){
413 if(t->data_sections[idx][s_idx] == NULL){
417 // given a bitmap and a section, return the size (w, h)
418 bm_get_section_size(bitmap_id, idx, s_idx, &w, &h);
421 if((t->data_sections[idx][s_idx]->w != w) || (t->data_sections[idx][s_idx]->h != h)){
427 // non-sectioned bitmap
429 if((t->w != w) || (t->h != h)){
438 // get the final texture size (the one which will get allocated as a surface)
439 void d3d_tcache_get_adjusted_texture_size(int w_in, int h_in, int *w_out, int *h_out)
444 if((w_out == NULL) || (h_out == NULL)){
452 if ( D3D_pow2_textures ) {
454 for (i=0; i<16; i++ ) {
455 if ( (tex_w > (1<<i)) && (tex_w <= (1<<(i+1))) ) {
461 for (i=0; i<16; i++ ) {
462 if ( (tex_h > (1<<i)) && (tex_h <= (1<<(i+1))) ) {
469 if ( tex_w < D3D_min_texture_width ) {
470 tex_w = D3D_min_texture_width;
471 } else if ( tex_w > D3D_max_texture_width ) {
472 tex_w = D3D_max_texture_width;
475 if ( tex_h < D3D_min_texture_height ) {
476 tex_h = D3D_min_texture_height;
477 } else if ( tex_h > D3D_max_texture_height ) {
478 tex_h = D3D_max_texture_height;
481 if ( D3D_square_textures ) {
483 // Make the both be equal to larger of the two
484 new_size = max(tex_w, tex_h);
489 // store the outgoing size
494 // data == start of bitmap data
495 // sx == x offset into bitmap
496 // sy == y offset into bitmap
497 // src_w == absolute width of section on source bitmap
498 // src_h == absolute height of section on source bitmap
499 // bmap_w == width of source bitmap
500 // bmap_h == height of source bitmap
501 // tex_w == width of final texture
502 // tex_h == height of final texture
503 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)
505 LPDIRECTDRAWSURFACE sys_texture_surface = NULL;
506 LPDIRECT3DTEXTURE2 sys_texture = NULL;
510 if ( Show_uploads ) {
512 mprintf(( "Reloading '%s'\n", bm_get_filename(texture_handle) ));
514 mprintf(( "Uploading '%s'\n", bm_get_filename(texture_handle) ));
524 if ( t->used_this_frame ) {
525 mprintf(( "ARGHH!!! Texture already used this frame! Cannot free it!\n" ));
530 if(!d3d_free_texture(t)){
537 DWORD dwHeight, dwWidth;
541 DDPIXELFORMAT *surface_desc;
543 switch( bitmap_type ) {
544 case TCACHE_TYPE_AABITMAP:
545 surface_desc = &AlphaTextureFormat;
548 case TCACHE_TYPE_XPARENT:
552 surface_desc = &NonAlphaTextureFormat;
555 // get final texture size
556 d3d_tcache_get_adjusted_texture_size(tex_w, tex_h, &tex_w, &tex_h);
558 if ( (tex_w < 1) || (tex_h < 1) ) {
559 mprintf(("Bitmap is to small at %dx%d.\n", tex_w, tex_h ));
563 if ( bitmap_type == TCACHE_TYPE_AABITMAP ) {
564 t->u_scale = (float)bmap_w / (float)tex_w;
565 t->v_scale = (float)bmap_h / (float)tex_h;
566 } else if(bitmap_type == TCACHE_TYPE_BITMAP_SECTION){
567 t->u_scale = (float)src_w / (float)tex_w;
568 t->v_scale = (float)src_h / (float)tex_h;
576 bmp_data = (ushort *)data;
577 ubyte *bmp_data_byte = (ubyte*)data;
579 // Create a surface in system memory and load texture into it.
581 // Create a surface of the given format using the dimensions of the bitmap
582 memset(&ddsd, 0, sizeof(DDSURFACEDESC));
584 ddsd.dwSize = sizeof(DDSURFACEDESC);
585 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
586 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY;
587 ddsd.dwHeight = dwHeight;
588 ddsd.dwWidth = dwWidth;
589 ddsd.ddpfPixelFormat = *surface_desc;
591 sys_texture_surface = NULL;
592 ddrval = lpDD->CreateSurface(&ddsd, &sys_texture_surface, NULL);
593 if ( (ddrval != DD_OK) || (sys_texture_surface == NULL) ) {
594 mprintf(("CreateSurface for texture failed (loadtex), w=%d, h=%d, %s\n", tex_w, tex_h, d3d_error_string(ddrval) ));
595 mprintf(( "Texture RAM = %d KB\n", D3D_textures_in / 1024 ));
596 // bm_unlock(bitmap_handle);
600 // Lock the surface so it can be filled with the bitmap data
601 memset(&ddsd, 0, sizeof(DDSURFACEDESC));
602 ddsd.dwSize = sizeof(DDSURFACEDESC);
603 ddrval = sys_texture_surface->Lock(NULL, &ddsd, 0, NULL);
604 if (ddrval != DD_OK) {
605 sys_texture_surface->Release();
606 mprintf(("Lock failed while loading surface (loadtex).\n" ));
610 Assert( surface_desc->dwRGBBitCount == 16 );
612 // Each RGB bit count requires different pointers
617 switch( bitmap_type ) {
618 case TCACHE_TYPE_AABITMAP:
619 // setup convenient translation table
620 for (i=0; i<16; i++ ) {
624 a = Gr_gamma_lookup[(i*255)/15];
625 r /= Gr_ta_red.scale;
626 g /= Gr_ta_green.scale;
627 b /= Gr_ta_blue.scale;
628 a /= Gr_ta_alpha.scale;
629 xlat[i] = unsigned short(((a<<Gr_ta_alpha.shift) | (r << Gr_ta_red.shift) | (g << Gr_ta_green.shift) | (b << Gr_ta_blue.shift)));
633 for ( ; i<256; i++ ) {
637 for (j = 0; j < tex_h; j++) {
638 lpSP = (unsigned short*)(((char*)ddsd.lpSurface) + ddsd.lPitch * j);
640 for (i = 0; i < tex_w; i++) {
641 if ( (i < bmap_w) && (j<bmap_h) ) {
642 *lpSP++ = xlat[(ubyte)bmp_data_byte[j*bmap_w+i]];
650 case TCACHE_TYPE_BITMAP_SECTION:
651 for (j = 0; j < src_h; j++) {
652 // the proper line in the temp ram
653 lpSP = (unsigned short*)(((char*)ddsd.lpSurface) + ddsd.lPitch * j);
656 for (i = 0; i < src_w; i++) {
657 // stuff the texture into vram
658 *lpSP++ = bmp_data[((j+sy) * bmap_w) + sx + i];
663 default: { // normal:
664 fix u, utmp, v, du, dv;
668 du = ( (bmap_w-1)*F1_0 ) / tex_w;
669 dv = ( (bmap_h-1)*F1_0 ) / tex_h;
671 for (j = 0; j < tex_h; j++) {
672 lpSP = (unsigned short*)(((char*)ddsd.lpSurface) + ddsd.lPitch * j);
676 for (i = 0; i < tex_w; i++) {
677 *lpSP++ = bmp_data[f2i(v)*bmap_w+f2i(utmp)];
686 // bm_unlock(bitmap_handle);
688 // Unlock the texture
689 sys_texture_surface->Unlock(NULL);
692 ddrval = sys_texture_surface->QueryInterface(IID_IDirect3DTexture2, (LPVOID *)&sys_texture);
693 if ( (ddrval != DD_OK) || (sys_texture == NULL) ) {
694 mprintf(( "Getting sys surface's texture failed!\n" ));
699 goto FreeSurfacesAndExit;
705 // Create a surface of the given format using the dimensions of the bitmap
706 memset(&ddsd, 0, sizeof(DDSURFACEDESC));
708 ddsd.dwSize = sizeof(DDSURFACEDESC);
709 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
710 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_ALLOCONLOAD | DDSCAPS_VIDEOMEMORY;
711 //| DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM | DDSCAPS_ALLOCONLOAD;
712 ddsd.dwHeight = dwHeight;
713 ddsd.dwWidth = dwWidth;
714 ddsd.ddpfPixelFormat = *surface_desc;
716 t->vram_texture_surface = NULL;
717 ddrval = lpDD->CreateSurface(&ddsd, &t->vram_texture_surface, NULL);
718 if ( (ddrval != DD_OK) || (t->vram_texture_surface == NULL) ) {
719 t->vram_texture = NULL;
720 t->vram_texture_surface = NULL;
721 t->texture_handle = NULL;
723 if ( ddrval==DDERR_OUTOFVIDEOMEMORY ) {
724 mprintf(("Out of VRAM (w=%d, h=%d, used=%d KB)\n", tex_w, tex_h, D3D_textures_in / 1024 ));
725 if ( fail_on_full ) {
729 goto FreeSurfacesAndExit;
731 if ( d3d_free_some_texture_ram(t,dwHeight*dwWidth*2)) {
735 mprintf(("CreateSurface for VRAM texture failed, w=%d, h=%d\n%s\n", tex_w, tex_h, d3d_error_string(ddrval) ));
736 mprintf(( "Texture RAM = %d KB\n", D3D_textures_in / 1024 ));
743 goto FreeSurfacesAndExit;
747 t->vram_texture = NULL;
748 ddrval = t->vram_texture_surface->QueryInterface(IID_IDirect3DTexture2, (LPVOID *)&t->vram_texture);
749 if ( (ddrval != DD_OK) || (t->vram_texture == NULL) ) {
750 mprintf(( "GR_D3D_INIT: TextureSurface->QueryInterface failed.\n" ));
756 goto FreeSurfacesAndExit;
759 // char *name = bm_get_filename(bitmap_handle);
760 // mprintf(( "Uploading '%s'\n", name ));
761 t->texture_handle = NULL;
762 ddrval = t->vram_texture->GetHandle(lpD3DDevice, &t->texture_handle );
763 if ( (ddrval != DD_OK) || (t->texture_handle == NULL) ) {
764 mprintf(( "GR_D3D_INIT: Texture->GetHandle failed.\n" ));
765 t->texture_handle = NULL;
771 goto FreeSurfacesAndExit;
775 // argh. this texture appears to be bogus. lets free it
776 if(t->vram_texture == NULL){
782 goto FreeSurfacesAndExit;
785 ddrval = t->vram_texture->Load( sys_texture );
786 if ( ddrval != DD_OK ) {
787 mprintf(("VRAM Load failed, w=%d, h=%d, %s\n", tex_w, tex_h, d3d_error_string(ddrval) ));
788 mprintf(( "Texture RAM = %d KB\n", D3D_textures_in / 1024 ));
794 goto FreeSurfacesAndExit;
797 t->bitmap_id = texture_handle;
798 t->time_created = D3D_frame_count;
799 t->used_this_frame = 0;
800 t->size = tex_w * tex_h * 2;
801 t->w = (ushort)tex_w;
802 t->h = (ushort)tex_h;
803 D3D_textures_in_frame += t->size;
805 D3D_textures_in += t->size;
810 sys_texture->Release();
814 if ( sys_texture_surface ) {
815 sys_texture_surface->Release();
816 sys_texture_surface = NULL;
819 // hopefully this is 1 :)
823 int d3d_create_texture(int bitmap_handle, int bitmap_type, tcache_slot_d3d *tslot, int fail_on_full)
827 int final_w, final_h;
831 // setup texture/bitmap flags
834 case TCACHE_TYPE_AABITMAP:
835 flags |= BMP_AABITMAP;
838 case TCACHE_TYPE_NORMAL:
839 flags |= BMP_TEX_OTHER;
840 case TCACHE_TYPE_XPARENT:
841 flags |= BMP_TEX_XPARENT;
843 case TCACHE_TYPE_NONDARKENING:
845 flags |= BMP_TEX_NONDARK;
849 // lock the bitmap into the proper format
850 bmp = bm_lock(bitmap_handle, bpp, flags);
852 mprintf(("Couldn't lock bitmap %d.\n", bitmap_handle ));
859 if ( bitmap_type != TCACHE_TYPE_AABITMAP ) {
860 max_w /= D3D_texture_divider;
861 max_h /= D3D_texture_divider;
863 // Detail.debris_culling goes from 0 to 4.
864 max_w /= 16 >> Detail.hardware_textures;
865 max_h /= 16 >> Detail.hardware_textures;
868 // get final texture size as it will be allocated as a DD surface
869 d3d_tcache_get_adjusted_texture_size(max_w, max_h, &final_w, &final_h);
871 // if this tcache slot has no bitmap
872 if ( tslot->bitmap_id < 0) {
875 // different bitmap altogether - determine if the new one can use the old one's slot
876 else if (tslot->bitmap_id != bitmap_handle) {
877 if((final_w == tslot->w) && (final_h == tslot->h)){
880 ml_printf("Reloading texture %d\n", bitmap_handle);
887 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);
890 bm_unlock(bitmap_handle);
895 int d3d_create_texture_sectioned(int bitmap_handle, int bitmap_type, tcache_slot_d3d *tslot, int sx, int sy, int fail_on_full)
899 int final_w, final_h;
900 int section_x, section_y;
903 // setup texture/bitmap flags
904 Assert(bitmap_type == TCACHE_TYPE_BITMAP_SECTION);
905 if(bitmap_type != TCACHE_TYPE_BITMAP_SECTION){
906 bitmap_type = TCACHE_TYPE_BITMAP_SECTION;
908 flags = BMP_TEX_XPARENT;
910 // lock the bitmap in the proper format
911 bmp = bm_lock(bitmap_handle, 16, flags);
913 mprintf(("Couldn't lock bitmap %d.\n", bitmap_handle ));
917 // determine the width and height of this section
918 bm_get_section_size(bitmap_handle, sx, sy, §ion_x, §ion_y);
920 // get final texture size as it will be allocated as a DD surface
921 d3d_tcache_get_adjusted_texture_size(section_x, section_y, &final_w, &final_h);
923 // if this tcache slot has no bitmap
924 if ( tslot->bitmap_id < 0) {
927 // different bitmap altogether - determine if the new one can use the old one's slot
928 else if (tslot->bitmap_id != bitmap_handle) {
929 if((final_w == tslot->w) && (final_h == tslot->h)){
937 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);
940 bm_unlock(bitmap_handle);
945 extern int bm_get_cache_slot( int bitmap_id, int separate_ani_frames );
946 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 )
952 if ( bitmap_id < 0 ) {
953 D3D_last_bitmap_id = -1;
957 if ( D3D_last_detail != Detail.hardware_textures ) {
958 D3D_last_detail = Detail.hardware_textures;
962 //mprintf(( "Setting texture %d\n", bitmap_handle ));
967 int n = bm_get_cache_slot( bitmap_id, 1 );
968 tcache_slot_d3d * t = &Textures[n];
970 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)) {
971 t->used_this_frame++;
973 // mark all children as used
974 if(D3D_texture_sections){
975 for(idx=0; idx<MAX_BMAP_SECTIONS_X; idx++){
976 for(s_idx=0; s_idx<MAX_BMAP_SECTIONS_Y; s_idx++){
977 if(t->data_sections[idx][s_idx] != NULL){
978 t->data_sections[idx][s_idx]->used_this_frame++;
984 *u_scale = t->u_scale;
985 *v_scale = t->v_scale;
989 // if this is a sectioned bitmap
990 if(bitmap_type == TCACHE_TYPE_BITMAP_SECTION){
991 Assert((sx >= 0) && (sy >= 0) && (sx < MAX_BMAP_SECTIONS_X) && (sy < MAX_BMAP_SECTIONS_Y));
992 if(!((sx >= 0) && (sy >= 0) && (sx < MAX_BMAP_SECTIONS_X) && (sy < MAX_BMAP_SECTIONS_Y))){
998 // if the texture sections haven't been created yet
999 if((t->bitmap_id < 0) || (t->bitmap_id != bitmap_id)){
1000 // lock the bitmap in the proper format
1001 bmp = bm_lock(bitmap_id, 16, BMP_TEX_XPARENT);
1002 bm_unlock(bitmap_id);
1004 // now lets do something for each texture
1005 for(idx=0; idx<bmp->sections.num_x; idx++){
1006 for(s_idx=0; s_idx<bmp->sections.num_y; s_idx++){
1007 // hmm. i'd rather we didn't have to do it this way...
1008 if(!d3d_create_texture_sectioned(bitmap_id, bitmap_type, t->data_sections[idx][s_idx], idx, s_idx, fail_on_full)){
1012 // not used this frame
1013 t->data_sections[idx][s_idx]->used_this_frame = 0;
1017 // zero out pretty much everything in the parent struct since he's just the root
1018 t->bitmap_id = bitmap_id;
1019 t->texture_handle = NULL;
1020 t->time_created = t->data_sections[sx][sy]->time_created;
1021 t->used_this_frame = 0;
1022 t->vram_texture = NULL;
1023 t->vram_texture_surface = NULL;
1026 // argh. we failed to upload. free anything we can
1028 d3d_free_texture(t);
1030 // swap in the texture we want
1032 t = t->data_sections[sx][sy];
1035 // all other "normal" textures
1036 else if((bitmap_id < 0) || (bitmap_id != t->bitmap_id)){
1037 ret_val = d3d_create_texture( bitmap_id, bitmap_type, t, fail_on_full );
1040 // everything went ok
1041 if(ret_val && (t->texture_handle != NULL) && !vram_full){
1042 *u_scale = t->u_scale;
1043 *v_scale = t->v_scale;
1045 d3d_SetRenderState(D3DRENDERSTATE_TEXTUREHANDLE, t->texture_handle );
1047 D3D_last_bitmap_id = t->bitmap_id;
1048 D3D_last_bitmap_type = bitmap_type;
1049 D3D_last_section_x = sx;
1050 D3D_last_section_y = sy;
1052 t->used_this_frame++;
1062 int D3D_should_preload = 0;
1064 void d3d_tcache_init(int use_sections)
1068 D3D_should_preload = 0;
1072 DWORD dwFree, dwTotal;
1074 memset(&ddsCaps,0,sizeof(ddsCaps) );
1075 ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1076 HRESULT ddrval = lpDD->GetAvailableVidMem(&ddsCaps, &dwTotal, &dwFree);
1077 if ( ddrval != DD_OK ) {
1078 mprintf(( "GR_D3D_INIT: GetAvailableVidMem failed.\n" ));
1083 D3D_texture_ram = dwFree;
1085 uint tmp_pl = os_config_read_uint( NULL, NOX("D3DPreloadTextures"), 255 );
1087 if ( tmp_pl == 0 ) {
1088 D3D_should_preload = 0;
1089 } else if ( tmp_pl == 1 ) {
1090 D3D_should_preload = 1;
1092 if ( D3D_texture_ram >= 6*1024*1024 ) {
1093 D3D_should_preload = 1;
1095 D3D_should_preload = 0;
1100 int megs = dwFree / (1024*1024);
1101 uint tmp_val = os_config_read_uint( NULL, NOX("D3DTextureDivider"), 255 );
1103 if ( tmp_val == 0 ) {
1106 D3D_texture_divider = 4;
1107 } else if ( megs <=8 ) {
1108 D3D_texture_divider = 3;
1109 } else if ( megs <=16 ) {
1110 D3D_texture_divider = 2;
1112 D3D_texture_divider = 1;
1114 } else if ( tmp_val < 5 ) {
1115 D3D_texture_divider = tmp_val;
1118 D3D_texture_divider = 4;
1122 // setup texture divider
1123 uint tmp_val = os_config_read_uint( NULL, NOX("D3DFast"), 1 );
1124 D3D_texture_divider = 1;
1126 D3D_texture_divider = 4;
1130 int megs = dwFree / (1024*1024);
1131 mprintf(( "TEXTURE RAM: %d bytes (%d MB) available, size divisor = %d\n", dwFree, megs, D3D_texture_divider ));
1136 D3D_min_texture_width = (int)lpDevDesc->dwMinTextureWidth;
1137 D3D_max_texture_width = (int)lpDevDesc->dwMaxTextureWidth;
1138 D3D_min_texture_height = (int)lpDevDesc->dwMinTextureHeight;
1139 D3D_max_texture_height = (int)lpDevDesc->dwMaxTextureHeight;
1141 // The following checks are needed because the PowerVR reports
1142 // it's texture caps as 0,0 up to 0,0.
1143 if ( D3D_min_texture_width < 16 ) {
1144 D3D_min_texture_width = 16;
1146 if ( D3D_min_texture_height < 16 ) {
1147 D3D_min_texture_height = 16;
1149 if ( D3D_max_texture_width < 16 ) {
1150 mprintf(( "Driver claims to have a max texture width of %d. Bashing to 256.\n(Is this a PowerVR?)\n", D3D_max_texture_width ));
1151 D3D_max_texture_width = 256; // Can we assume 256?
1154 if ( D3D_max_texture_height < 16 ) {
1155 mprintf(( "Driver claims to have a max texture height of %d. Bashing to 256.\n(Is this a PowerVR?)\n", D3D_max_texture_height ));
1156 D3D_max_texture_height = 256; // Can we assume 256?
1159 if (lpDevDesc->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_SQUAREONLY) {
1160 mprintf(( "Darn. Driver needs square textures.\n" ));
1161 D3D_square_textures = 1;
1163 mprintf(( "Woohoo! Driver doesn't need square textures!\n" ));
1164 D3D_square_textures = 0;
1167 if ( lpDevDesc->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2 ) {
1168 mprintf(( "Textures must be power of 2.\n" ));
1169 D3D_pow2_textures = 1;
1171 mprintf(( "Textures can be any size.\n" ));
1172 D3D_pow2_textures = 0;
1176 if ( !(DD_driver_caps.dwCaps2 & DDCAPS2_WIDESURFACES) ) {
1177 if ( D3D_max_texture_width > gr_screen.max_w ) {
1178 D3D_max_texture_width = gr_screen.max_w;
1180 if ( D3D_pow2_textures ) {
1181 for (i=0; i<16; i++ ) {
1182 if ( (D3D_max_texture_width>= (1<<i)) && (D3D_max_texture_width < (1<<(i+1))) ) {
1183 D3D_max_texture_width = 1 << i;
1189 if ( D3D_max_texture_height > D3D_max_texture_width ) {
1190 D3D_max_texture_height = D3D_max_texture_width;
1193 mprintf(( "Doesn't support wide surfaces. Bashing max down to %d\n", D3D_max_texture_width ));
1197 if ( !os_config_read_uint( NULL, NOX("D3DUseLargeTextures"), 0 )) {
1198 mprintf(( "No large texture flag specified, so using max of 256\n" ));
1199 if ( D3D_max_texture_width > 256 ) {
1200 D3D_max_texture_width = 256;
1203 if ( D3D_max_texture_height > 256 ) {
1204 D3D_max_texture_height = 256;
1207 mprintf(( "Large textures enabled!\n" ));
1210 Textures = (tcache_slot_d3d *)malloc(MAX_BITMAPS*sizeof(tcache_slot_d3d));
1216 Texture_sections = (tcache_slot_d3d*)malloc(MAX_BITMAPS * MAX_BMAP_SECTIONS_X * MAX_BMAP_SECTIONS_Y * sizeof(tcache_slot_d3d));
1217 if(!Texture_sections){
1220 memset(Texture_sections, 0, MAX_BITMAPS * MAX_BMAP_SECTIONS_X * MAX_BMAP_SECTIONS_Y * sizeof(tcache_slot_d3d));
1223 // Init the texture structures
1224 int section_count = 0;
1225 for( i=0; i<MAX_BITMAPS; i++ ) {
1226 Textures[i].vram_texture = NULL;
1227 Textures[i].vram_texture_surface = NULL;
1228 Textures[i].texture_handle = NULL;
1230 Textures[i].bitmap_id = -1;
1231 Textures[i].size = 0;
1232 Textures[i].used_this_frame = 0;
1234 Textures[i].parent = NULL;
1236 // allocate sections
1238 for(idx=0; idx<MAX_BMAP_SECTIONS_X; idx++){
1239 for(s_idx=0; s_idx<MAX_BMAP_SECTIONS_Y; s_idx++){
1240 Textures[i].data_sections[idx][s_idx] = &((tcache_slot_d3d*)Texture_sections)[section_count++];
1241 Textures[i].data_sections[idx][s_idx]->parent = &Textures[i];
1243 Textures[i].data_sections[idx][s_idx]->vram_texture = NULL;
1244 Textures[i].data_sections[idx][s_idx]->vram_texture_surface = NULL;
1245 Textures[i].data_sections[idx][s_idx]->texture_handle = NULL;
1247 Textures[i].data_sections[idx][s_idx]->bitmap_id = -1;
1248 Textures[i].data_sections[idx][s_idx]->size = 0;
1249 Textures[i].data_sections[idx][s_idx]->used_this_frame = 0;
1253 for(idx=0; idx<MAX_BMAP_SECTIONS_X; idx++){
1254 for(s_idx=0; s_idx<MAX_BMAP_SECTIONS_Y; s_idx++){
1255 Textures[i].data_sections[idx][s_idx] = NULL;
1261 D3D_texture_sections = use_sections;
1263 D3D_last_detail = Detail.hardware_textures;
1264 D3D_last_bitmap_id = -1;
1265 D3D_last_bitmap_type = -1;
1267 D3D_last_section_x = -1;
1268 D3D_last_section_y = -1;
1270 D3D_textures_in = 0;
1271 D3D_textures_in_frame = 0;
1275 void d3d_tcache_flush()
1280 for( i=0; i<MAX_BITMAPS; i++ ) {
1281 d3d_free_texture( &Textures[i] );
1283 if ( D3D_textures_in != 0 ) {
1284 mprintf(( "WARNING: VRAM is at %d instead of zero after flushing!\n", D3D_textures_in ));
1285 D3D_textures_in = 0;
1288 D3D_last_bitmap_id = -1;
1289 D3D_last_section_x = -1;
1290 D3D_last_section_y = -1;
1293 void d3d_tcache_cleanup()
1297 D3D_textures_in = 0;
1298 D3D_textures_in_frame = 0;
1305 if(Texture_sections != NULL){
1306 free(Texture_sections);
1307 Texture_sections = NULL;
1311 void d3d_tcache_frame()
1315 D3D_last_bitmap_id = -1;
1316 D3D_textures_in_frame = 0;
1321 for( i=0; i<MAX_BITMAPS; i++ ) {
1322 Textures[i].used_this_frame = 0;
1325 if(Textures[i].data_sections[0][0] != NULL){
1326 Assert(D3D_texture_sections);
1327 if(D3D_texture_sections){
1328 for(idx=0; idx<MAX_BMAP_SECTIONS_X; idx++){
1329 for(s_idx=0; s_idx<MAX_BMAP_SECTIONS_Y; s_idx++){
1330 if(Textures[i].data_sections[idx][s_idx] != NULL){
1331 Textures[i].data_sections[idx][s_idx]->used_this_frame = 0;
1346 void gr_d3d_preload_init()
1348 if ( gr_screen.mode != GR_DIRECT3D ) {
1354 int gr_d3d_preload(int bitmap_num, int is_aabitmap)
1356 if ( gr_screen.mode != GR_DIRECT3D ) {
1360 if ( !D3D_should_preload ) {
1364 float u_scale, v_scale;
1368 if ( is_aabitmap ) {
1369 retval = gr_tcache_set(bitmap_num, TCACHE_TYPE_AABITMAP, &u_scale, &v_scale, 1 );
1371 retval = gr_tcache_set(bitmap_num, TCACHE_TYPE_NORMAL, &u_scale, &v_scale, 1 );
1375 mprintf(("Texture upload failed!\n" ));
1381 // call this to safely fill in the texture shift and scale values for the specified texture type (Gr_t_*)
1382 void gr_d3d_get_tex_format(int alpha)
1385 DDPIXELFORMAT *surface_desc;
1390 // get the proper texture format
1392 surface_desc = &AlphaTextureFormat;
1394 surface_desc = &NonAlphaTextureFormat;
1397 // Determine the red, green and blue masks' shift and scale.
1398 for (s = 0, m = surface_desc->dwRBitMask; !(m & 1); s++, m >>= 1);
1400 Gr_t_red_scale = 255 / (surface_desc->dwRBitMask >> s);
1401 for (s = 0, m = surface_desc->dwGBitMask; !(m & 1); s++, m >>= 1);
1402 Gr_t_green_shift = s;
1403 Gr_t_green_scale = 255 / (surface_desc->dwGBitMask >> s);
1404 for (s = 0, m = surface_desc->dwBBitMask; !(m & 1); s++, m >>= 1);
1405 Gr_t_blue_shift = s;
1406 Gr_t_blue_scale = 255 / (surface_desc->dwBBitMask >> s);
1408 if ( surface_desc->dwFlags & DDPF_ALPHAPIXELS ) {
1409 for (s = 0, m = surface_desc->dwRGBAlphaBitMask; !(m & 1); s++, m >>= 1);
1410 Gr_t_alpha_shift = s;
1411 Gr_t_alpha_scale = 255 / (surface_desc->dwRGBAlphaBitMask >> s);
1413 Gr_t_alpha_shift = 0;
1414 Gr_t_alpha_scale = 256;