00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "textureMemoryCounter.h"
00020 #include "paletteImage.h"
00021 #include "textureImage.h"
00022 #include "destTextureImage.h"
00023 #include "omitReason.h"
00024 #include "texturePlacement.h"
00025
00026 #include <indent.h>
00027 #include <math.h>
00028
00029
00030
00031
00032
00033
00034 TextureMemoryCounter::
00035 TextureMemoryCounter() {
00036 reset();
00037 }
00038
00039
00040
00041
00042
00043
00044 void TextureMemoryCounter::
00045 reset() {
00046 _num_textures = 0;
00047 _num_unplaced = 0;
00048 _num_placed = 0;
00049 _num_palettes = 0;
00050
00051 _bytes = 0;
00052 _unused_bytes = 0;
00053 _duplicate_bytes = 0;
00054 _coverage_bytes = 0;
00055 _textures.clear();
00056 _palettes.clear();
00057 }
00058
00059
00060
00061
00062
00063
00064 void TextureMemoryCounter::
00065 add_placement(TexturePlacement *placement) {
00066 TextureImage *texture = placement->get_texture();
00067 nassertv(texture != (TextureImage *)NULL);
00068
00069 if (placement->get_omit_reason() == OR_none) {
00070 PaletteImage *image = placement->get_image();
00071 nassertv(image != (PaletteImage *)NULL);
00072 add_palette(image);
00073
00074 int bytes = count_bytes(image, placement->get_placed_x_size(),
00075 placement->get_placed_y_size());
00076 add_texture(texture, bytes);
00077 _num_placed++;
00078
00079 } else {
00080 DestTextureImage *dest = placement->get_dest();
00081 nassertv(dest != (DestTextureImage *)NULL);
00082
00083 int bytes = count_bytes(dest);
00084 add_texture(texture, bytes);
00085
00086 _bytes += bytes;
00087 _num_unplaced++;
00088 }
00089 }
00090
00091
00092
00093
00094
00095
00096 void TextureMemoryCounter::
00097 report(ostream &out, int indent_level) {
00098 indent(out, indent_level)
00099 << _num_placed << " of " << _num_textures << " textures appear on "
00100 << _num_palettes << " palette images with " << _num_unplaced
00101 << " unplaced.\n";
00102
00103 indent(out, indent_level)
00104 << (_bytes + 512) / 1024 << "k estimated texture memory required.\n";
00105
00106 if (_bytes != 0) {
00107 if (_unused_bytes != 0) {
00108 indent(out, indent_level + 2);
00109 format_memory_fraction(out, _unused_bytes, _bytes)
00110 << " is wasted because of unused palette space.\n";
00111 }
00112
00113 if (_coverage_bytes > 0) {
00114 indent(out, indent_level + 2);
00115 format_memory_fraction(out, _coverage_bytes, _bytes)
00116 << " is wasted for repeating textures and margins.\n";
00117
00118 } else if (_coverage_bytes < 0) {
00119 indent(out, indent_level + 2);
00120 format_memory_fraction(out, -_coverage_bytes, _bytes)
00121 << " is *saved* for palettizing partial textures.\n";
00122 }
00123
00124 if (_duplicate_bytes != 0) {
00125 indent(out, indent_level + 2);
00126 format_memory_fraction(out, _duplicate_bytes, _bytes)
00127 << " is wasted because of a texture appearing in multiple groups.\n";
00128 }
00129 }
00130 }
00131
00132
00133
00134
00135
00136
00137
00138
00139 ostream &TextureMemoryCounter::
00140 format_memory_fraction(ostream &out, int fraction_bytes, int palette_bytes) {
00141 out << floor(1000.0 * (double)fraction_bytes / (double)palette_bytes + 0.5) / 10.0
00142 << "% (" << (fraction_bytes + 512) / 1024 << "k)";
00143 return out;
00144 }
00145
00146
00147
00148
00149
00150
00151
00152
00153 void TextureMemoryCounter::
00154 add_palette(PaletteImage *image) {
00155 bool inserted = _palettes.insert(image).second;
00156 if (!inserted) {
00157
00158 return;
00159 }
00160
00161 int bytes = count_bytes(image);
00162 double unused = 1.0 - image->count_utilization();
00163 double coverage = image->count_coverage();
00164
00165 _bytes += bytes;
00166 _unused_bytes += (int)(unused * bytes);
00167 _coverage_bytes += (int)(coverage * bytes);
00168
00169 _num_palettes++;
00170 }
00171
00172
00173
00174
00175
00176
00177
00178
00179 void TextureMemoryCounter::
00180 add_texture(TextureImage *texture, int bytes) {
00181 pair<Textures::iterator, bool> result;
00182 result = _textures.insert(Textures::value_type(texture, bytes));
00183 if (result.second) {
00184
00185 _num_textures++;
00186 return;
00187 }
00188
00189
00190 Textures::iterator ti = result.first;
00191
00192 _duplicate_bytes += min(bytes, (*ti).second);
00193 (*ti).second = max(bytes, (*ti).second);
00194 }
00195
00196
00197
00198
00199
00200
00201
00202 int TextureMemoryCounter::
00203 count_bytes(ImageFile *image) {
00204 return count_bytes(image, image->get_x_size(), image->get_y_size());
00205 }
00206
00207
00208
00209
00210
00211
00212
00213 int TextureMemoryCounter::
00214 count_bytes(ImageFile *image, int x_size, int y_size) {
00215 int pixels = x_size * y_size;
00216
00217
00218
00219
00220
00221 int bpp = 0;
00222 switch (image->get_properties()._format) {
00223 case EggTexture::F_rgba12:
00224 bpp = 6;
00225 break;
00226
00227 case EggTexture::F_rgba:
00228 case EggTexture::F_rgbm:
00229 case EggTexture::F_rgba8:
00230 bpp = 4;
00231 break;
00232
00233 case EggTexture::F_rgb:
00234 case EggTexture::F_rgb12:
00235 bpp = 3;
00236 break;
00237
00238 case EggTexture::F_rgba4:
00239 case EggTexture::F_rgba5:
00240 case EggTexture::F_rgb8:
00241 case EggTexture::F_rgb5:
00242 case EggTexture::F_luminance_alpha:
00243 case EggTexture::F_luminance_alphamask:
00244 bpp = 2;
00245 break;
00246
00247 case EggTexture::F_rgb332:
00248 case EggTexture::F_red:
00249 case EggTexture::F_green:
00250 case EggTexture::F_blue:
00251 case EggTexture::F_alpha:
00252 case EggTexture::F_luminance:
00253 bpp = 1;
00254 break;
00255
00256 default:
00257 bpp = image->get_num_channels();
00258 }
00259
00260 int bytes = pixels * bpp;
00261
00262
00263 switch (image->get_properties()._minfilter) {
00264 case EggTexture::FT_nearest_mipmap_nearest:
00265 case EggTexture::FT_linear_mipmap_nearest:
00266 case EggTexture::FT_nearest_mipmap_linear:
00267 case EggTexture::FT_linear_mipmap_linear:
00268 bytes = (bytes * 4) / 3;
00269 break;
00270
00271 default:
00272 break;
00273 }
00274
00275 return bytes;
00276 }