Panda3D
|
00001 // Filename: textureMemoryCounter.cxx 00002 // Created by: drose (19Dec00) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "textureMemoryCounter.h" 00016 #include "paletteImage.h" 00017 #include "textureImage.h" 00018 #include "destTextureImage.h" 00019 #include "omitReason.h" 00020 #include "texturePlacement.h" 00021 00022 #include "indent.h" 00023 #include <math.h> 00024 00025 //////////////////////////////////////////////////////////////////// 00026 // Function: TextureMemoryCounter::Constructor 00027 // Access: Public 00028 // Description: 00029 //////////////////////////////////////////////////////////////////// 00030 TextureMemoryCounter:: 00031 TextureMemoryCounter() { 00032 reset(); 00033 } 00034 00035 //////////////////////////////////////////////////////////////////// 00036 // Function: TextureMemoryCounter::reset 00037 // Access: Public 00038 // Description: Resets the count to zero. 00039 //////////////////////////////////////////////////////////////////// 00040 void TextureMemoryCounter:: 00041 reset() { 00042 _num_textures = 0; 00043 _num_unplaced = 0; 00044 _num_placed = 0; 00045 _num_palettes = 0; 00046 00047 _bytes = 0; 00048 _unused_bytes = 0; 00049 _duplicate_bytes = 0; 00050 _coverage_bytes = 0; 00051 _textures.clear(); 00052 _palettes.clear(); 00053 } 00054 00055 //////////////////////////////////////////////////////////////////// 00056 // Function: TextureMemoryCounter::add_placement 00057 // Access: Public 00058 // Description: Adds the indicated TexturePlacement to the counter. 00059 //////////////////////////////////////////////////////////////////// 00060 void TextureMemoryCounter:: 00061 add_placement(TexturePlacement *placement) { 00062 TextureImage *texture = placement->get_texture(); 00063 nassertv(texture != (TextureImage *)NULL); 00064 00065 if (placement->get_omit_reason() == OR_none) { 00066 PaletteImage *image = placement->get_image(); 00067 nassertv(image != (PaletteImage *)NULL); 00068 add_palette(image); 00069 00070 int bytes = count_bytes(image, placement->get_placed_x_size(), 00071 placement->get_placed_y_size()); 00072 add_texture(texture, bytes); 00073 _num_placed++; 00074 00075 } else { 00076 DestTextureImage *dest = placement->get_dest(); 00077 if (dest != (DestTextureImage *)NULL) { 00078 int bytes = count_bytes(dest); 00079 add_texture(texture, bytes); 00080 00081 _bytes += bytes; 00082 _num_unplaced++; 00083 } 00084 } 00085 } 00086 00087 //////////////////////////////////////////////////////////////////// 00088 // Function: TextureMemoryCounter::report 00089 // Access: Public 00090 // Description: Reports the measured texture memory usage. 00091 //////////////////////////////////////////////////////////////////// 00092 void TextureMemoryCounter:: 00093 report(ostream &out, int indent_level) { 00094 indent(out, indent_level) 00095 << _num_placed << " of " << _num_textures << " textures appear on " 00096 << _num_palettes << " palette images with " << _num_unplaced 00097 << " unplaced.\n"; 00098 00099 indent(out, indent_level) 00100 << (_bytes + 512) / 1024 << "k estimated texture memory required.\n"; 00101 00102 if (_bytes != 0) { 00103 if (_unused_bytes != 0) { 00104 indent(out, indent_level + 2); 00105 format_memory_fraction(out, _unused_bytes, _bytes) 00106 << " is wasted because of unused palette space.\n"; 00107 } 00108 00109 if (_coverage_bytes > 0) { 00110 indent(out, indent_level + 2); 00111 format_memory_fraction(out, _coverage_bytes, _bytes) 00112 << " is wasted for repeating textures and margins.\n"; 00113 00114 } else if (_coverage_bytes < 0) { 00115 indent(out, indent_level + 2); 00116 format_memory_fraction(out, -_coverage_bytes, _bytes) 00117 << " is *saved* for palettizing partial textures.\n"; 00118 } 00119 00120 if (_duplicate_bytes != 0) { 00121 indent(out, indent_level + 2); 00122 format_memory_fraction(out, _duplicate_bytes, _bytes) 00123 << " is wasted because of a texture appearing in multiple groups.\n"; 00124 } 00125 } 00126 } 00127 00128 //////////////////////////////////////////////////////////////////// 00129 // Function: TextureMemoryCounter::format_memory_fraction 00130 // Access: Private, Static 00131 // Description: Writes to the indicated ostream an indication of the 00132 // fraction of the total memory usage that is 00133 // represented by fraction_bytes. 00134 //////////////////////////////////////////////////////////////////// 00135 ostream &TextureMemoryCounter:: 00136 format_memory_fraction(ostream &out, int fraction_bytes, int palette_bytes) { 00137 out << floor(1000.0 * (double)fraction_bytes / (double)palette_bytes + 0.5) / 10.0 00138 << "% (" << (fraction_bytes + 512) / 1024 << "k)"; 00139 return out; 00140 } 00141 00142 //////////////////////////////////////////////////////////////////// 00143 // Function: TextureMemoryCounter::add_palette 00144 // Access: Private 00145 // Description: Adds the indicated PaletteImage to the count. If 00146 // this is called twice for a given PaletteImage it does 00147 // nothing. 00148 //////////////////////////////////////////////////////////////////// 00149 void TextureMemoryCounter:: 00150 add_palette(PaletteImage *image) { 00151 bool inserted = _palettes.insert(image).second; 00152 if (!inserted) { 00153 // We've already added this palette image. 00154 return; 00155 } 00156 00157 int bytes = count_bytes(image); 00158 double unused = 1.0 - image->count_utilization(); 00159 double coverage = image->count_coverage(); 00160 00161 _bytes += bytes; 00162 _unused_bytes += (int)(unused * bytes); 00163 _coverage_bytes += (int)(coverage * bytes); 00164 00165 _num_palettes++; 00166 } 00167 00168 //////////////////////////////////////////////////////////////////// 00169 // Function: TextureMemoryCounter::add_texture 00170 // Access: Private 00171 // Description: Adds the given TextureImage to the counter. If the 00172 // texture image has already been added, this counts the 00173 // smaller of the two as duplicate bytes. 00174 //////////////////////////////////////////////////////////////////// 00175 void TextureMemoryCounter:: 00176 add_texture(TextureImage *texture, int bytes) { 00177 pair<Textures::iterator, bool> result; 00178 result = _textures.insert(Textures::value_type(texture, bytes)); 00179 if (result.second) { 00180 // If it was inserted, no problem--no duplicates. 00181 _num_textures++; 00182 return; 00183 } 00184 00185 // If it was not inserted, we have a duplicate. 00186 Textures::iterator ti = result.first; 00187 00188 _duplicate_bytes += min(bytes, (*ti).second); 00189 (*ti).second = max(bytes, (*ti).second); 00190 } 00191 00192 //////////////////////////////////////////////////////////////////// 00193 // Function: TextureMemoryCounter::count_bytes 00194 // Access: Private 00195 // Description: Attempts to estimate the number of bytes the given 00196 // image file will use in texture memory. 00197 //////////////////////////////////////////////////////////////////// 00198 int TextureMemoryCounter:: 00199 count_bytes(ImageFile *image) { 00200 return count_bytes(image, image->get_x_size(), image->get_y_size()); 00201 } 00202 00203 //////////////////////////////////////////////////////////////////// 00204 // Function: TextureMemoryCounter::count_bytes 00205 // Access: Private 00206 // Description: Attempts to estimate the number of bytes the given 00207 // image file will use in texture memory. 00208 //////////////////////////////////////////////////////////////////// 00209 int TextureMemoryCounter:: 00210 count_bytes(ImageFile *image, int x_size, int y_size) { 00211 int pixels = x_size * y_size; 00212 00213 // Try to guess the number of bytes per pixel this texture will 00214 // consume in texture memory, based on its requested format. This 00215 // is only a loose guess, because this depends of course on the 00216 // pecularities of the particular rendering engine. 00217 int bpp = 0; 00218 switch (image->get_properties()._format) { 00219 case EggTexture::F_rgba12: 00220 bpp = 6; 00221 break; 00222 00223 case EggTexture::F_rgba: 00224 case EggTexture::F_rgbm: 00225 case EggTexture::F_rgba8: 00226 bpp = 4; 00227 break; 00228 00229 case EggTexture::F_rgb: 00230 case EggTexture::F_rgb12: 00231 bpp = 3; 00232 break; 00233 00234 case EggTexture::F_rgba4: 00235 case EggTexture::F_rgba5: 00236 case EggTexture::F_rgb8: 00237 case EggTexture::F_rgb5: 00238 case EggTexture::F_luminance_alpha: 00239 case EggTexture::F_luminance_alphamask: 00240 bpp = 2; 00241 break; 00242 00243 case EggTexture::F_rgb332: 00244 case EggTexture::F_red: 00245 case EggTexture::F_green: 00246 case EggTexture::F_blue: 00247 case EggTexture::F_alpha: 00248 case EggTexture::F_luminance: 00249 bpp = 1; 00250 break; 00251 00252 default: 00253 bpp = image->get_num_channels(); 00254 } 00255 00256 int bytes = pixels * bpp; 00257 00258 // If we're mipmapping, it's worth 1/3 more bytes. 00259 switch (image->get_properties()._minfilter) { 00260 case EggTexture::FT_nearest_mipmap_nearest: 00261 case EggTexture::FT_linear_mipmap_nearest: 00262 case EggTexture::FT_nearest_mipmap_linear: 00263 case EggTexture::FT_linear_mipmap_linear: 00264 bytes = (bytes * 4) / 3; 00265 break; 00266 00267 default: 00268 break; 00269 } 00270 00271 return bytes; 00272 }