[80]  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 
