Panda3D
 All Classes Functions Variables Enumerations
textureMemoryCounter.cxx
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 }
 All Classes Functions Variables Enumerations