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