source: golgotha/src/render/dx5/r1_dx5_texture.cc

Last change on this file was 80, checked in by Sam Hocevar, 13 years ago
  • Adding the Golgotha source code. Not sure what's going to be interesting in there, but since it's all public domain, there's certainly stuff to pick up.
File size: 18.7 KB
Line 
1/********************************************************************** <BR>
2  This file is part of Crack dot Com's free source code release of
3  Golgotha. <a href="http://www.crack.com/golgotha_release"> <BR> for
4  information about compiling & licensing issues visit this URL</a>
5  <PRE> If that doesn't help, contact Jonathan Clark at
6  golgotha_source@usa.net (Subject should have "GOLG" in it)
7***********************************************************************/
8
9#include "dx5/r1_dx5_texture.hh"
10
11#include "video/win32/dx5.hh"
12#include "video/win32/dx5_error.hh"
13#include "time/profile.hh"
14#include "r1_res.hh"
15
16i4_profile_class pf_dx5_install_vram("dx5 install vram texture");
17i4_profile_class pf_dx5_free_vram("dx5 free vram texture");
18i4_profile_class pf_dx5_select_texture("dx5 select_texture");
19i4_profile_class pf_dx5_texture_load("dx5 texture Load()");
20
21DDPIXELFORMAT dd_fmt_565;
22DDPIXELFORMAT dd_fmt_1555;
23DDPIXELFORMAT dd_fmt_4444;
24
25r1_dx5_texture_class *r1_dx5_texture_class_instance=0;
26
27LPDDSURFACEDESC first_tex_format=0;
28
29HRESULT WINAPI texture_enum(LPDDSURFACEDESC lpddsd, LPVOID _regular_format)
30{
31  if ((lpddsd->ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS)==0 &&
32       lpddsd->ddpfPixelFormat.dwRGBBitCount==16)
33  {
34    //find the best non-alpha surface format
35    i4_pixel_format *regular_format = (i4_pixel_format *)_regular_format;
36
37    sw32 total_new_bits = lpddsd->ddpfPixelFormat.dwRBitMask +
38                          lpddsd->ddpfPixelFormat.dwGBitMask +
39                          lpddsd->ddpfPixelFormat.dwBBitMask;
40
41    sw32 total_reg_bits = regular_format->red_mask   +
42                          regular_format->green_mask +
43                          regular_format->blue_mask;
44
45    if (total_new_bits > total_reg_bits)
46    {
47      regular_format->red_mask   = lpddsd->ddpfPixelFormat.dwRBitMask;
48      regular_format->green_mask = lpddsd->ddpfPixelFormat.dwGBitMask;
49      regular_format->blue_mask  = lpddsd->ddpfPixelFormat.dwBBitMask;
50      regular_format->alpha_mask = 0;
51      regular_format->lookup     = 0;
52      regular_format->calc_shift();
53      regular_format->pixel_depth = I4_16BIT;
54    }
55  }
56
57  if (first_tex_format)
58  {
59    if (lpddsd==first_tex_format)
60      return D3DENUMRET_CANCEL;
61  }
62  else
63    first_tex_format = lpddsd;
64
65  return D3DENUMRET_OK;
66}
67
68r1_dx5_texture_class::r1_dx5_texture_class(const i4_pal *pal)
69: r1_texture_manager_class(pal),finished_array(16,16)
70{
71  r1_dx5_texture_class_instance = this;
72 
73  tex_no_heap = 0;
74
75  //find out how much texture memory we have and show it to anyone debugging
76  DDSCAPS tcaps;
77  tcaps.dwCaps = DDSCAPS_TEXTURE; 
78  w32 total_free, texture_free;
79  dx5_common.ddraw->GetAvailableVidMem(&tcaps, &total_free, &texture_free); 
80  i4_warning("Total Display Memory Free: %d",total_free);
81  i4_warning("Total Display Texture Memory Free: %d",texture_free);
82   
83  memset(&regular_format,0,sizeof(i4_pixel_format));
84
85  if (r1_dx5_class_instance.d3d_device->EnumTextureFormats(texture_enum,(LPVOID)&regular_format) != D3D_OK)
86    i4_error("Couldn't determine Direct3D Texture Formats");
87 
88  chroma_format.red_mask   = 31 << 10;
89  chroma_format.green_mask = 31 << 5;
90  chroma_format.blue_mask  = 31;
91  chroma_format.alpha_mask = 1 << 15;
92  chroma_format.lookup     = 0; 
93  chroma_format.calc_shift();
94  chroma_format.pixel_depth = I4_16BIT;
95 
96  alpha_format.red_mask   = 15 << 8;
97  alpha_format.green_mask = 15 << 4;
98  alpha_format.blue_mask  = 15;
99  alpha_format.alpha_mask = 15 << 12;
100  alpha_format.lookup     = 0; 
101  alpha_format.calc_shift();
102  alpha_format.pixel_depth = I4_16BIT;
103
104  memset(&dd_fmt_565,0,sizeof(DDPIXELFORMAT));
105  dd_fmt_565.dwSize = sizeof(DDPIXELFORMAT);
106  dd_fmt_565.dwFlags = DDPF_RGB;
107  dd_fmt_565.dwRGBBitCount = 16;
108  dd_fmt_565.dwRBitMask = regular_format.red_mask;
109  dd_fmt_565.dwGBitMask = regular_format.green_mask;
110  dd_fmt_565.dwBBitMask = regular_format.blue_mask;
111
112  memset(&dd_fmt_1555,0,sizeof(DDPIXELFORMAT));
113  dd_fmt_1555.dwSize = sizeof(DDPIXELFORMAT);
114  dd_fmt_1555.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
115  dd_fmt_1555.dwRGBBitCount     = 16;   
116  dd_fmt_1555.dwRBitMask        = 31 << 10;
117  dd_fmt_1555.dwGBitMask        = 31 << 5;
118  dd_fmt_1555.dwBBitMask        = 31;
119  dd_fmt_1555.dwRGBAlphaBitMask = 1 << 15;
120
121  memset(&dd_fmt_4444,0,sizeof(DDPIXELFORMAT));
122  dd_fmt_4444.dwSize = sizeof(DDPIXELFORMAT);
123  dd_fmt_4444.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
124  dd_fmt_4444.dwRGBBitCount     = 16;   
125  dd_fmt_4444.dwRBitMask        = 15 << 8;
126  dd_fmt_4444.dwGBitMask        = 15 << 4;
127  dd_fmt_4444.dwBBitMask        = 15;
128  dd_fmt_4444.dwRGBAlphaBitMask = 15 << 12;
129
130  min_texture_dimention = 0;
131
132  max_texture_dimention = r1_max_texture_size;
133
134  if (max_texture_dimention>256)
135    max_texture_dimention=256;     // don't allow d3d to go above 256
136
137  square_textures = r1_dx5_class_instance.needs_square_textures;
138
139  init();
140}
141
142void r1_dx5_texture_class::init()
143
144  r1_texture_manager_class::init();
145 
146  tex_no_heap  = new r1_texture_no_heap_class(this,sizeof(used_node),(w32 *)&frame_count);
147 
148  array_lock.lock();
149  array_lock.unlock();
150
151  bytes_loaded = 0;
152  textures_loaded = 0;
153}
154
155void r1_dx5_texture_class::uninit()
156
157  if (tex_no_heap)
158  {
159    delete tex_no_heap;
160    tex_no_heap = 0;
161  }
162
163  r1_texture_manager_class::uninit();
164}
165
166
167#define R1_DX5_SURFACE_HOLY         1
168#define R1_DX5_SURFACE_ALPHATEXTURE 2
169#define R1_DX5_SURFACE_VRAM         4
170
171
172IDirectDrawSurface3 *dx5_make_surface(sw32 w, sw32 h, w8 flags)
173{
174  DDSURFACEDESC ddsd;
175  memset(&ddsd,0,sizeof(DDSURFACEDESC));
176  ddsd.dwSize = sizeof(DDSURFACEDESC); 
177  ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
178  ddsd.dwWidth  = w;
179  ddsd.dwHeight = h;
180
181  if (flags & R1_DX5_SURFACE_VRAM)
182  {
183    ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_ALLOCONLOAD;
184 
185    if (r1_dx5_class_instance.hardware_tmapping)
186      ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
187    else
188      ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
189  }
190  else
191    ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY;
192
193  if (flags & R1_DX5_SURFACE_HOLY)
194    ddsd.ddpfPixelFormat = dd_fmt_1555;
195  else
196  if (flags & R1_DX5_SURFACE_ALPHATEXTURE)
197    ddsd.ddpfPixelFormat = dd_fmt_4444;
198  else
199    ddsd.ddpfPixelFormat = dd_fmt_565;
200 
201  IDirectDrawSurface  *return_surface  = 0;
202  IDirectDrawSurface3 *return_surface3 = 0;
203 
204  HRESULT res = dx5_common.ddraw->CreateSurface(&ddsd,&return_surface,0);
205
206  if (!i4_dx5_check(res))
207  {
208#ifdef DEBUG
209    i4_warning("r1_dx5_texture::dx5_make_surface failed.");
210#endif
211    return_surface = 0;
212  }
213  else
214  {   
215    res = return_surface->QueryInterface(IID_IDirectDrawSurface3,(void **)&return_surface3);   
216
217    if (!i4_dx5_check(res))
218    {
219#ifdef DEBUG
220      i4_warning("r1_dx5_texture::dx5_make_surface failed.");
221#endif
222      return_surface3 = 0;
223    }
224   
225    return_surface->Release();
226  }
227
228  return return_surface3;
229}
230
231r1_dx5_texture_class::used_node *r1_dx5_texture_class::make_surfaces_for_load(
232                                                     IDirectDrawSurface3 *&vram_surface3,
233                                                     IDirectDrawSurface3 *&system_surface3,
234                                                     r1_mip_load_info *&load_info,
235                                                     sw32 actual_w, sw32 actual_h,
236                                                     w8 node_alloc_flags)
237{
238  r1_miplevel_t *mip = load_info->dest_mip;
239
240  sw32 need_size = actual_w*actual_h*2;
241
242  w8 create_flags = 0;
243 
244  if (mip->entry->is_transparent())
245    create_flags = R1_DX5_SURFACE_HOLY;
246  else
247  if (mip->entry->is_alphatexture())
248    create_flags = R1_DX5_SURFACE_ALPHATEXTURE;
249 
250  system_surface3 = dx5_make_surface(actual_w, actual_h, create_flags);
251   
252  if (!system_surface3)
253  {   
254    load_info->error = R1_MIP_LOAD_NO_ROOM;   
255    return 0;
256  }
257
258  create_flags |= R1_DX5_SURFACE_VRAM;
259
260  vram_surface3 = dx5_make_surface(actual_w, actual_h, create_flags);
261
262  used_node *new_used = 0;
263
264  if (vram_surface3)
265  {
266    new_used = (used_node *)tex_no_heap->alloc(node_alloc_flags);
267  }
268  else 
269  {
270    used_node *u = (used_node *)tex_no_heap->alloc_from_used(mip->width*mip->height*2,node_alloc_flags);
271   
272    if (!u)
273    {
274      system_surface3->Release();
275      system_surface3 = 0;
276
277      load_info->error = R1_MIP_LOAD_NO_ROOM;     
278      return 0;
279    }
280       
281    vram_surface3 = dx5_make_surface(actual_w, actual_h, create_flags);
282   
283    if (!vram_surface3)
284    {
285      system_surface3->Release();
286      system_surface3 = 0;
287     
288      tex_no_heap->missed_one(mip->width*mip->height*2);
289     
290      load_info->error = R1_MIP_LOAD_NO_ROOM;     
291      return 0;
292    }
293
294    new_used = u;
295  }
296 
297  if (!new_used)
298  {
299    i4_warning("couldn't alloc used_node");
300    if (system_surface3)
301      system_surface3->Release();
302    if (vram_surface3)
303      vram_surface3->Release();
304   
305    system_surface3 = 0;
306    vram_surface3   = 0;
307
308    load_info->error = R1_MIP_LOAD_NO_ROOM;   
309    return 0;
310  } 
311
312  return new_used;
313}
314
315
316i4_bool r1_dx5_texture_class::immediate_mip_load(r1_mip_load_info *load_info)
317
318  if (textures_loaded > 0)
319  {
320    if (load_info->dest_mip->last_frame_used!=-1)
321    {
322      load_info->error = R1_MIP_LOAD_BUSY;
323      return i4_F;
324    }
325  }
326
327  pf_dx5_install_vram.start();
328
329  IDirectDrawSurface3 *vram_surface   = 0;
330  IDirectDrawSurface3 *system_surface = 0;
331
332  sw32 i,j,actual_w,actual_h;
333   
334  r1_miplevel_t *mip = load_info->dest_mip;
335
336  for (actual_w = 1; actual_w < mip->width;  actual_w*=2); // these need to be power of 2
337  for (actual_h = 1; actual_h < mip->height; actual_h*=2);
338   
339  used_node *new_used = make_surfaces_for_load(vram_surface,system_surface,load_info,actual_w,actual_h);
340 
341  if (!new_used)
342  {
343    pf_dx5_install_vram.stop();
344    return i4_F;
345  }
346
347  DDSURFACEDESC ddsd;
348  memset(&ddsd,0,sizeof(DDSURFACEDESC));
349  ddsd.dwSize = sizeof(DDSURFACEDESC);
350
351  // Lock the surface so we can get the memory address where it is
352  system_surface->Lock(0, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY | DDLOCK_NOSYSLOCK, 0); 
353
354  w8   *texture_ptr = (w8 *)ddsd.lpSurface;
355  sw32  bpl         = mip->width*2;
356
357  i4_bool segmented_load = i4_F;
358   
359  if (load_info->src_file)
360  {
361    if (!segmented_load)
362      load_info->src_file->read(texture_ptr,mip->width*mip->height*2);
363    else
364    {
365      for (i=0; i<mip->height; i++)
366      {
367        load_info->src_file->read(texture_ptr,bpl);
368        texture_ptr += ddsd.lPitch;
369      }
370    }
371  }
372  else
373  {
374    i4_str *fn = r1_texture_id_to_filename(mip->entry->id,r1_get_decompressed_dir());   
375   
376    i4_file_class *fp = i4_open(*fn,I4_READ | I4_NO_BUFFER);
377
378    delete fn;
379   
380    fp->seek(mip->entry->file_offsets[mip->level]+8);
381   
382    if (!segmented_load)
383      fp->read(texture_ptr,mip->width*mip->height*2);
384    else
385    {
386      for (i=0; i<mip->height; i++)
387      {
388        fp->read(texture_ptr,bpl);
389        texture_ptr += ddsd.lPitch;
390      }
391    }
392
393    delete fp;
394  }   
395
396  system_surface->Unlock(0);
397
398  mip->vram_handle = new_used;
399
400  if (mip->last_frame_used != -1)
401    mip->last_frame_used = frame_count; 
402
403  new_used->vram_surface   = vram_surface;
404  new_used->system_surface = 0;
405  new_used->mip            = mip;
406  new_used->async_fp       = 0;
407  new_used->data           = 0;
408
409  IDirect3DTexture2 *system_texture, *vram_texture;
410 
411  system_surface->QueryInterface(IID_IDirect3DTexture2,(void **)&system_texture);
412  vram_surface->QueryInterface(IID_IDirect3DTexture2,(void **)&vram_texture);
413
414  pf_dx5_texture_load.start();
415  if (vram_texture->Load(system_texture) != D3D_OK)
416    i4_warning("r1_dx5_texture:: Load() failed");
417  pf_dx5_texture_load.stop();
418 
419  vram_texture->GetHandle(r1_dx5_class_instance.d3d_device, &new_used->texture_handle);
420   
421  vram_texture->Release();
422  system_texture->Release();
423
424  system_surface->Release();
425 
426  bytes_loaded += mip->width*mip->height*2;
427  textures_loaded++;
428
429  pf_dx5_install_vram.stop();
430  return i4_T;
431}
432
433void dx5_async_callback(w32 count, void *context)
434{
435  r1_dx5_texture_class::used_node *u = (r1_dx5_texture_class::used_node *)context;
436
437  if (u->async_fp)
438  {
439    delete u->async_fp;
440    u->async_fp = 0;
441  }
442
443  r1_dx5_texture_class_instance->async_load_finished(u);
444}
445
446void r1_dx5_texture_class::async_load_finished(used_node *u)
447{
448  array_lock.lock();
449 
450  finished_array.add(u);
451 
452  array_lock.unlock();
453}
454
455i4_bool r1_dx5_texture_class::async_mip_load(r1_mip_load_info *load_info)
456
457  if (bytes_loaded > 32768 || textures_loaded > 16)
458  {
459    if (load_info->dest_mip->last_frame_used!=-1)
460    {
461      load_info->error = R1_MIP_LOAD_BUSY;
462      return i4_F;
463    }
464  }
465
466  pf_dx5_install_vram.start(); 
467
468  IDirectDrawSurface3 *vram_surface   = 0;
469  IDirectDrawSurface3 *system_surface = 0;
470
471  sw32 i,j,actual_w,actual_h;
472   
473  r1_miplevel_t *mip = load_info->dest_mip;
474
475  //for (actual_w = 1; actual_w < mip->width;  actual_w*=2); // these need to be power of 2
476  //for (actual_h = 1; actual_h < mip->height; actual_h*=2);
477 
478  //all textures are power of 2 now
479  actual_w = mip->width;
480  actual_h = mip->height;
481   
482  used_node *new_used = make_surfaces_for_load(vram_surface,system_surface,load_info,actual_w,actual_h,R1_TEX_NO_HEAP_DONT_LIST);
483 
484  if (!new_used)
485  {
486    pf_dx5_install_vram.stop();
487    return i4_F;
488  }
489
490  new_used->mip      = mip;
491  new_used->data     = (w8 *)i4_malloc(mip->width*mip->height*2,"dx5 async load alloc");
492  new_used->async_fp = 0; 
493 
494  new_used->vram_surface   = vram_surface;
495  new_used->system_surface = system_surface;   
496  new_used->texture_handle = 0;
497
498  mip->vram_handle  = 0;
499  mip->flags       |= R1_MIPLEVEL_IS_LOADING;
500
501  i4_bool async_worked = i4_F;
502 
503  if (load_info->src_file)
504  {
505    async_worked = load_info->src_file->async_read(new_used->data,
506                                                   mip->width*mip->height*2,
507                                                   dx5_async_callback,
508                                                   new_used);
509  }
510  else
511  {
512    i4_str *fn = r1_texture_id_to_filename(mip->entry->id,r1_get_decompressed_dir());   
513   
514    i4_file_class *fp = i4_open(*fn,I4_READ | I4_NO_BUFFER);
515
516    delete fn;
517   
518    new_used->async_fp = fp;
519
520    fp->seek(mip->entry->file_offsets[mip->level]+8);
521   
522    async_worked = fp->async_read(new_used->data,
523                                  mip->width*mip->height*2,
524                                  dx5_async_callback,
525                                  new_used);
526  }
527 
528  if (!async_worked)
529  {
530    mip->flags &= (~R1_MIPLEVEL_IS_LOADING);
531    free_mip(new_used);   
532   
533    load_info->error = R1_MIP_LOAD_BUSY;   
534    pf_dx5_install_vram.stop();
535    return i4_F;
536  } 
537 
538  bytes_loaded += mip->width*mip->height*2;
539  textures_loaded++;
540
541  pf_dx5_install_vram.stop();
542  return i4_T;
543}
544
545void r1_dx5_texture_class::free_mip(void *vram_handle)
546{
547  pf_dx5_free_vram.start();
548  used_node *u = (used_node *)vram_handle;
549
550  if (u->system_surface)
551  {
552    u->system_surface->Release();
553    u->system_surface = 0;
554  }
555   
556  if (u->vram_surface)
557  {
558    u->vram_surface->Release();
559    u->vram_surface = 0;
560  }
561   
562  if (u->async_fp)
563  {
564    delete u->async_fp;
565    u->async_fp = 0;
566  }
567 
568  if (u->data)
569  {
570    i4_free(u->data);
571    u->data = 0;
572  }   
573
574  tex_no_heap->free((r1_tex_no_heap_used_node *)u);
575 
576  pf_dx5_free_vram.stop();
577}
578
579void r1_dx5_texture_class::select_texture(r1_local_texture_handle_type handle,
580                                          float &smul, float &tmul)
581{
582  pf_dx5_select_texture.start();
583
584  used_node *u = (used_node *)handle;
585 
586  if (r1_dx5_class_instance.d3d_device->SetRenderState(D3DRENDERSTATE_TEXTUREHANDLE,
587                                                   u->texture_handle) != D3D_OK)
588  {
589    i4_warning("select_texture failed");
590  }
591
592  smul = 1.0;//n->smul;
593  tmul = 1.0;//n->tmul;
594
595  pf_dx5_select_texture.stop();
596}
597
598r1_miplevel_t *r1_dx5_texture_class::get_texture(r1_texture_handle handle,
599                                                 w32 frame_counter,
600                                                 sw32 desired_width,
601                                                 sw32 &w, sw32 &h)
602{
603  r1_miplevel_t *mip = r1_texture_manager_class::get_texture(handle,frame_counter,desired_width,w,h);
604 
605  used_node *u = (used_node *)mip->vram_handle; 
606
607  tex_no_heap->update_usage((r1_tex_no_heap_used_node *)u);
608 
609  return mip;
610}
611
612void r1_dx5_texture_class::next_frame()
613{
614  r1_texture_manager_class::next_frame();
615 
616  sw32 i,j;
617  array_lock.lock();
618
619  for (i=0; i<finished_array.size(); i++)
620  {
621    used_node *u = finished_array[i];   
622   
623    //this officially puts it in vram
624    u->mip->vram_handle  = u;
625    u->mip->flags       &= (~R1_MIPLEVEL_IS_LOADING);
626   
627    if (u->mip->last_frame_used != -1)
628      u->mip->last_frame_used  = frame_count;
629   
630    //this adds it into the list of used nodes
631    tex_no_heap->update_usage((r1_tex_no_heap_used_node *)u);
632                                   
633    DDSURFACEDESC ddsd;
634    memset(&ddsd,0,sizeof(DDSURFACEDESC));
635    ddsd.dwSize = sizeof(DDSURFACEDESC);
636
637    u->system_surface->Lock(0, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY | DDLOCK_NOSYSLOCK, 0);   
638   
639    sw32 bpl = u->mip->width*2;
640
641    w8 *texture_ptr = (w8 *)ddsd.lpSurface;
642
643    if (0)//ddsd.lPitch > bpl)
644    {     
645      for (j=0; j<u->mip->height; j++)
646      {
647        memcpy(texture_ptr,u->data,bpl);
648        texture_ptr += ddsd.lPitch;
649      }
650    }
651    else
652      memcpy(texture_ptr,u->data,u->mip->width*u->mip->height*2);   
653
654    u->system_surface->Unlock(0);
655
656    i4_free(u->data);
657    u->data = 0;   
658
659    IDirect3DTexture2  *system_texture, *vram_texture;       
660
661    u->system_surface->QueryInterface(IID_IDirect3DTexture2,(void **)&system_texture);
662    u->vram_surface->QueryInterface(IID_IDirect3DTexture2,(void **)&vram_texture);
663
664    pf_dx5_texture_load.start();
665    if (vram_texture->Load(system_texture) != D3D_OK)
666      i4_warning("d3d:load texture failed");
667    pf_dx5_texture_load.stop();
668
669    vram_texture->GetHandle(r1_dx5_class_instance.d3d_device, &u->texture_handle);
670
671    vram_texture->Release();
672    system_texture->Release();   
673   
674    u->system_surface->Release();
675    u->system_surface = 0;   
676  }
677  finished_array.clear();
678
679  array_lock.unlock();
680 
681  if (tex_no_heap->needs_cleanup)
682  {
683    tex_no_heap->free_really_old();
684  }
685
686  bytes_loaded = 0;
687  textures_loaded = 0;
688}
689
690
691
692
Note: See TracBrowser for help on using the repository browser.