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  #ifndef _TEX_NO_HEAP_HH_


10  #define _TEX_NO_HEAP_HH_


11 


12  #include "time/profile.hh"


13 


14  extern i4_profile_class pf_tex_no_heap_alloc;


15  extern i4_profile_class pf_tex_no_heap_free;


16  extern i4_profile_class pf_tex_no_heap_cleanup;


17 


18  #define R1_TEX_NO_HEAP_USED_NODE_DATA r1_miplevel_t *mip; r1_tex_no_heap_used_node *next; r1_tex_no_heap_used_node *last;


19 


20  #define R1_TEX_NO_HEAP_DONT_LIST 1


21 


22  class r1_tex_no_heap_used_node


23  {


24  public:


25  R1_TEX_NO_HEAP_USED_NODE_DATA


26  };


27 


28  class r1_texture_no_heap_class


29  {


30  public:


31  r1_tex_no_heap_used_node *first_used;


32  r1_tex_no_heap_used_node *oldest_used;


33 


34  i4_linear_allocator *used_node_alloc;


35 


36  r1_texture_no_heap_class(r1_texture_manager_class *tman, w32 used_node_size, w32 *frame_count)


37  {


38  tmanager = tman;


39 


40  num_ram_misses = 0;


41  needs_cleanup = i4_F;


42 


43  used_node_alloc = 0;


44 


45  frame_count_ptr = frame_count;


46 


47  if (!used_node_alloc)


48  {


49  used_node_alloc = new i4_linear_allocator(used_node_size, 2048, 1024, "texture nonheap used nodes");


50  first_used = 0;


51  oldest_used = 0;


52  }


53  }


54 


55  ~r1_texture_no_heap_class()


56  {


57  //kill the used list


58  r1_tex_no_heap_used_node *u,*next_used;


59 


60  u = first_used;


61  while (u)


62  {


63  next_used = u>next;


64 


65  tmanager>free_mip(u);


66 


67  u = next_used;


68  }


69 


70  first_used = 0;


71  oldest_used = 0;


72 


73  delete used_node_alloc;


74  used_node_alloc=0;


75  }


76 


77  r1_texture_manager_class *tmanager;


78  w32 *frame_count_ptr;


79  w32 num_ram_misses;


80  sw32 max_fail_size;


81 


82  i4_bool needs_cleanup;


83 


84  void free_really_old()


85  {


86  pf_tex_no_heap_cleanup.start();


87 


88  w32 total_freed = 0;


89 


90  r1_tex_no_heap_used_node *u = oldest_used;


91  r1_tex_no_heap_used_node *last;


92 


93  while (u && total_freed < max_fail_size)


94  {


95  sw32 lfu = u>mip>last_frame_used;


96  sw32 age = *frame_count_ptr  lfu;


97 


98  last = u>last;


99 


100  if ((lfu != 1) && (age > 10))


101  {


102  total_freed += (u>mip>width*u>mip>height*2);


103 


104  tmanager>free_mip(u);


105  }


106 


107  u = last;


108  }


109 


110  #ifdef DEBUG


111  if (total_freed < max_fail_size)


112  i4_warning("Texture cleanup: freed %d bytes (not enough)",total_freed);


113  else


114  i4_warning("Texture cleanup: freed %d bytes (successful)",total_freed);


115  #endif


116 


117  max_fail_size = 0;


118  needs_cleanup = i4_F;


119 


120  pf_tex_no_heap_cleanup.stop();


121  }


122 


123  r1_tex_no_heap_used_node *alloc(w8 flags=0)


124  {


125  r1_tex_no_heap_used_node *u = (r1_tex_no_heap_used_node *)used_node_alloc>alloc();


126 


127  if (flags & R1_TEX_NO_HEAP_DONT_LIST)


128  {


129  u>next = 0;


130  u>last = 0;


131  }


132  else


133  {


134  u>next = first_used;


135  u>last = 0;


136 


137  if (first_used)


138  first_used>last = u;


139 


140  first_used = u;


141  }


142 


143  return u;


144  }


145 


146  r1_tex_no_heap_used_node *alloc_from_used(w32 need_size, w8 flags=0)


147  {


148  pf_tex_no_heap_alloc.start();


149 


150  //we know how much memory we need, now try to find an old texture of the same or greater size


151 


152  //no memory large enough. dig through and see if there is a used chunk that we can free


153  r1_tex_no_heap_used_node *u = oldest_used;


154 


155  while (u)


156  {


157  if (u>mip>width*u>mip>height*2 >= need_size)


158  {


159  r1_miplevel_t *m = u>mip;


160  if (m>last_frame_used < (*frame_count_ptr  2))


161  {


162  if (m>flags & R1_MIPLEVEL_IS_LOADING)


163  {


164  i4_warning("loading miplevel is in used list. bad.");


165  }


166  break;


167  }


168  }


169  u = u>last;


170  }


171 


172  //couldnt find a used one that we could free


173  if (!u)


174  {


175  num_ram_misses++;


176 


177  if (need_size > max_fail_size)


178  max_fail_size = need_size;


179 


180  if ((num_ram_misses & 15) == 0)


181  {


182  //cleanup old textures every 16 misses


183  needs_cleanup = i4_T;


184  }


185 


186  pf_tex_no_heap_alloc.stop();


187  return 0;


188  }


189 


190  //kill the old mip's reference to it


191  u>mip>vram_handle = 0;


192 


193  //free it


194  tmanager>free_mip(u);


195 


196  u = alloc(flags);


197 


198  pf_tex_no_heap_alloc.stop();


199  return u;


200  }


201 


202  void missed_one(sw32 miss_size)


203  {


204  if (miss_size > max_fail_size)


205  max_fail_size = miss_size;


206  }


207 


208  void update_usage(r1_tex_no_heap_used_node *u)


209  {


210  if ((u>mip>last_frame_used) != 1)


211  {


212  u>mip>last_frame_used = *frame_count_ptr;


213 


214  if (u != first_used)


215  {


216  //put this node at the front of the used list


217  //has the effect of sorting all used nodes according to


218  //their age (most recently used are at the


219  //front of the list)


220 


221  if (u==oldest_used)


222  oldest_used = u>last;


223 


224  if (u>next) u>next>last = u>last;


225  if (u>last) u>last>next = u>next;


226 


227  u>last = 0;


228  u>next = first_used;


229 


230  if (first_used)


231  first_used>last = u;


232 


233  first_used = u;


234  }


235  }


236 


237  //update the oldest used pointer


238  if (!oldest_used)


239  oldest_used = u;


240  else


241  {


242  if (oldest_used>mip>last_frame_used==1)


243  oldest_used = u;


244  else


245  {


246  if ((u>mip>last_frame_used != 1) &&


247  (u>mip>last_frame_used < oldest_used>mip>last_frame_used))


248  {


249  oldest_used = u;


250  }


251  }


252  }


253  }


254 


255  void free(r1_tex_no_heap_used_node *u)


256  {


257  if (!u)


258  {


259  i4_warning("tex_no_heap_class free : handle is 0");


260  return;


261  }


262 


263  if (u>mip>flags & R1_MIPLEVEL_IS_LOADING)


264  {


265  i4_warning("free called on a mip that was still loading");


266  }


267 


268  pf_tex_no_heap_free.start();


269 


270  //give its r1_miplevel_t an invalid vram handle


271  u>mip>vram_handle = 0;


272 


273  //process these cases 1st


274  if (u==first_used)


275  first_used = u>next;


276  if (u==oldest_used)


277  oldest_used = u>last;


278 


279  //pull it from the used_list


280  if (u>next) u>next>last = u>last;


281  if (u>last) u>last>next = u>next;


282 


283  used_node_alloc>free(u);


284 


285  pf_tex_no_heap_free.stop();


286  }


287 


288  };


289 


290  #endif 
