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  */
54 add_placement(TexturePlacement *placement) {
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 }
This represents a texture filename as it has been resized and copied to the map directory (e....
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
int get_x_size() const
Returns the size of the image file in pixels in the X direction.
Definition: imageFile.cxx:82
const TextureProperties & get_properties() const
Returns the grouping properties of the image.
Definition: imageFile.cxx:119
int get_y_size() const
Returns the size of the image file in pixels in the Y direction.
Definition: imageFile.cxx:92
This is a single palette image, one of several within a PalettePage, which is in turn one of several ...
Definition: paletteImage.h:32
double count_utilization() const
Returns the fraction of the PaletteImage that is actually used by any textures.
double count_coverage() const
Returns the a weighted average of the fraction of coverage represented by all of the textures placed ...
This represents a single source texture that is referenced by one or more egg files.
Definition: textureImage.h:46
void add_placement(TexturePlacement *placement)
Adds the indicated TexturePlacement to the counter.
void report(std::ostream &out, int indent_level)
Reports the measured texture memory usage.
void reset()
Resets the count to zero.
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.
DestTextureImage * get_dest() const
Returns the DestTextureImage that corresponds to this texture as it was copied to the install directo...
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...
PaletteImage * get_image() const
Returns the particular PaletteImage on which the texture has been placed.
TextureImage * get_texture() const
Returns the texture that this placement represents.
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.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.