Panda3D
textureMemoryCounter.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file textureMemoryCounter.cxx
10  * @author drose
11  * @date 2000-12-19
12  */
13 
14 #include "textureMemoryCounter.h"
15 #include "paletteImage.h"
16 #include "textureImage.h"
17 #include "destTextureImage.h"
18 #include "omitReason.h"
19 #include "texturePlacement.h"
20 
21 #include "indent.h"
22 #include <math.h>
23 
24 /**
25  *
26  */
27 TextureMemoryCounter::
28 TextureMemoryCounter() {
29  reset();
30 }
31 
32 /**
33  * Resets the count to zero.
34  */
36 reset() {
37  _num_textures = 0;
38  _num_unplaced = 0;
39  _num_placed = 0;
40  _num_palettes = 0;
41 
42  _bytes = 0;
43  _unused_bytes = 0;
44  _duplicate_bytes = 0;
45  _coverage_bytes = 0;
46  _textures.clear();
47  _palettes.clear();
48 }
49 
50 /**
51  * Adds the indicated TexturePlacement to the counter.
52  */
55  TextureImage *texture = placement->get_texture();
56  nassertv(texture != nullptr);
57 
58  if (placement->get_omit_reason() == OR_none) {
59  PaletteImage *image = placement->get_image();
60  nassertv(image != nullptr);
61  add_palette(image);
62 
63  int bytes = count_bytes(image, placement->get_placed_x_size(),
64  placement->get_placed_y_size());
65  add_texture(texture, bytes);
66  _num_placed++;
67 
68  } else {
69  DestTextureImage *dest = placement->get_dest();
70  if (dest != nullptr) {
71  int bytes = count_bytes(dest);
72  add_texture(texture, bytes);
73 
74  _bytes += bytes;
75  _num_unplaced++;
76  }
77  }
78 }
79 
80 /**
81  * Reports the measured texture memory usage.
82  */
84 report(std::ostream &out, int indent_level) {
85  indent(out, indent_level)
86  << _num_placed << " of " << _num_textures << " textures appear on "
87  << _num_palettes << " palette images with " << _num_unplaced
88  << " unplaced.\n";
89 
90  indent(out, indent_level)
91  << (_bytes + 512) / 1024 << "k estimated texture memory required.\n";
92 
93  if (_bytes != 0) {
94  if (_unused_bytes != 0) {
95  indent(out, indent_level + 2);
96  format_memory_fraction(out, _unused_bytes, _bytes)
97  << " is wasted because of unused palette space.\n";
98  }
99 
100  if (_coverage_bytes > 0) {
101  indent(out, indent_level + 2);
102  format_memory_fraction(out, _coverage_bytes, _bytes)
103  << " is wasted for repeating textures and margins.\n";
104 
105  } else if (_coverage_bytes < 0) {
106  indent(out, indent_level + 2);
107  format_memory_fraction(out, -_coverage_bytes, _bytes)
108  << " is *saved* for palettizing partial textures.\n";
109  }
110 
111  if (_duplicate_bytes != 0) {
112  indent(out, indent_level + 2);
113  format_memory_fraction(out, _duplicate_bytes, _bytes)
114  << " is wasted because of a texture appearing in multiple groups.\n";
115  }
116  }
117 }
118 
119 /**
120  * Writes to the indicated ostream an indication of the fraction of the total
121  * memory usage that is represented by fraction_bytes.
122  */
123 std::ostream &TextureMemoryCounter::
124 format_memory_fraction(std::ostream &out, int fraction_bytes, int palette_bytes) {
125  out << floor(1000.0 * (double)fraction_bytes / (double)palette_bytes + 0.5) / 10.0
126  << "% (" << (fraction_bytes + 512) / 1024 << "k)";
127  return out;
128 }
129 
130 /**
131  * Adds the indicated PaletteImage to the count. If this is called twice for
132  * a given PaletteImage it does nothing.
133  */
134 void TextureMemoryCounter::
135 add_palette(PaletteImage *image) {
136  bool inserted = _palettes.insert(image).second;
137  if (!inserted) {
138  // We've already added this palette image.
139  return;
140  }
141 
142  int bytes = count_bytes(image);
143  double unused = 1.0 - image->count_utilization();
144  double coverage = image->count_coverage();
145 
146  _bytes += bytes;
147  _unused_bytes += (int)(unused * bytes);
148  _coverage_bytes += (int)(coverage * bytes);
149 
150  _num_palettes++;
151 }
152 
153 /**
154  * Adds the given TextureImage to the counter. If the texture image has
155  * already been added, this counts the smaller of the two as duplicate bytes.
156  */
157 void TextureMemoryCounter::
158 add_texture(TextureImage *texture, int bytes) {
159  std::pair<Textures::iterator, bool> result;
160  result = _textures.insert(Textures::value_type(texture, bytes));
161  if (result.second) {
162  // If it was inserted, no problem--no duplicates.
163  _num_textures++;
164  return;
165  }
166 
167  // If it was not inserted, we have a duplicate.
168  Textures::iterator ti = result.first;
169 
170  _duplicate_bytes += std::min(bytes, (*ti).second);
171  (*ti).second = std::max(bytes, (*ti).second);
172 }
173 
174 /**
175  * Attempts to estimate the number of bytes the given image file will use in
176  * texture memory.
177  */
178 int TextureMemoryCounter::
179 count_bytes(ImageFile *image) {
180  return count_bytes(image, image->get_x_size(), image->get_y_size());
181 }
182 
183 /**
184  * Attempts to estimate the number of bytes the given image file will use in
185  * texture memory.
186  */
187 int TextureMemoryCounter::
188 count_bytes(ImageFile *image, int x_size, int y_size) {
189  int pixels = x_size * y_size;
190 
191  // Try to guess the number of bytes per pixel this texture will consume in
192  // texture memory, based on its requested format. This is only a loose
193  // guess, because this depends of course on the pecularities of the
194  // particular rendering engine.
195  int bpp = 0;
196  switch (image->get_properties()._format) {
197  case EggTexture::F_rgba12:
198  bpp = 6;
199  break;
200 
201  case EggTexture::F_rgba:
202  case EggTexture::F_rgbm:
203  case EggTexture::F_rgba8:
204  bpp = 4;
205  break;
206 
207  case EggTexture::F_rgb:
208  case EggTexture::F_rgb12:
209  bpp = 3;
210  break;
211 
212  case EggTexture::F_rgba4:
213  case EggTexture::F_rgba5:
214  case EggTexture::F_rgb8:
215  case EggTexture::F_rgb5:
216  case EggTexture::F_luminance_alpha:
217  case EggTexture::F_luminance_alphamask:
218  bpp = 2;
219  break;
220 
221  case EggTexture::F_rgb332:
222  case EggTexture::F_red:
223  case EggTexture::F_green:
224  case EggTexture::F_blue:
225  case EggTexture::F_alpha:
226  case EggTexture::F_luminance:
227  bpp = 1;
228  break;
229 
230  default:
231  bpp = image->get_num_channels();
232  }
233 
234  int bytes = pixels * bpp;
235 
236  // If we're mipmapping, it's worth 13 more bytes.
237  switch (image->get_properties()._minfilter) {
238  case EggTexture::FT_nearest_mipmap_nearest:
239  case EggTexture::FT_linear_mipmap_nearest:
240  case EggTexture::FT_nearest_mipmap_linear:
241  case EggTexture::FT_linear_mipmap_linear:
242  bytes = (bytes * 4) / 3;
243  break;
244 
245  default:
246  break;
247  }
248 
249  return bytes;
250 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void reset()
Resets the count to zero.
This represents a texture filename as it has been resized and copied to the map directory (e....
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
double count_utilization() const
Returns the fraction of the PaletteImage that is actually used by any textures.
int get_placed_x_size() const
Returns the size in the X dimension, in pixels, of the texture image as it has been placed within the...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
double count_coverage() const
Returns the a weighted average of the fraction of coverage represented by all of the textures placed ...
int get_y_size() const
Returns the size of the image file in pixels in the Y direction.
Definition: imageFile.cxx:92
PaletteImage * get_image() const
Returns the particular PaletteImage on which the texture has been placed.
void report(std::ostream &out, int indent_level)
Reports the measured texture memory usage.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
const TextureProperties & get_properties() const
Returns the grouping properties of the image.
Definition: imageFile.cxx:119
int get_x_size() const
Returns the size of the image file in pixels in the X direction.
Definition: imageFile.cxx:82
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
This is the base class of both TextureImage and PaletteImage.
Definition: imageFile.h:33
int get_num_channels() const
Returns the number of channels of the image.
Definition: imageFile.cxx:111
void add_placement(TexturePlacement *placement)
Adds the indicated TexturePlacement to the counter.
This corresponds to a particular assignment of a TextureImage with a PaletteGroup,...
OmitReason get_omit_reason() const
Returns the reason the texture has been omitted from a palette image, or OR_none if it has not.
TextureImage * get_texture() const
Returns the texture that this placement represents.
DestTextureImage * get_dest() const
Returns the DestTextureImage that corresponds to this texture as it was copied to the install directo...
This is a single palette image, one of several within a PalettePage, which is in turn one of several ...
Definition: paletteImage.h:32
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This represents a single source texture that is referenced by one or more egg files.
Definition: textureImage.h:46
int get_placed_y_size() const
Returns the size in the Y dimension, in pixels, of the texture image as it has been placed within the...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.