open_toontown_panda3d/pandatool/src/palettizer/textureMemoryCounter.cxx

251 lines
6.3 KiB
C++

/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file textureMemoryCounter.cxx
* @author drose
* @date 2000-12-19
*/
#include "textureMemoryCounter.h"
#include "paletteImage.h"
#include "textureImage.h"
#include "destTextureImage.h"
#include "omitReason.h"
#include "texturePlacement.h"
#include "indent.h"
#include <math.h>
/**
*
*/
TextureMemoryCounter::
TextureMemoryCounter() {
reset();
}
/**
* Resets the count to zero.
*/
void TextureMemoryCounter::
reset() {
_num_textures = 0;
_num_unplaced = 0;
_num_placed = 0;
_num_palettes = 0;
_bytes = 0;
_unused_bytes = 0;
_duplicate_bytes = 0;
_coverage_bytes = 0;
_textures.clear();
_palettes.clear();
}
/**
* Adds the indicated TexturePlacement to the counter.
*/
void TextureMemoryCounter::
add_placement(TexturePlacement *placement) {
TextureImage *texture = placement->get_texture();
nassertv(texture != nullptr);
if (placement->get_omit_reason() == OR_none) {
PaletteImage *image = placement->get_image();
nassertv(image != nullptr);
add_palette(image);
int bytes = count_bytes(image, placement->get_placed_x_size(),
placement->get_placed_y_size());
add_texture(texture, bytes);
_num_placed++;
} else {
DestTextureImage *dest = placement->get_dest();
if (dest != nullptr) {
int bytes = count_bytes(dest);
add_texture(texture, bytes);
_bytes += bytes;
_num_unplaced++;
}
}
}
/**
* Reports the measured texture memory usage.
*/
void TextureMemoryCounter::
report(std::ostream &out, int indent_level) {
indent(out, indent_level)
<< _num_placed << " of " << _num_textures << " textures appear on "
<< _num_palettes << " palette images with " << _num_unplaced
<< " unplaced.\n";
indent(out, indent_level)
<< (_bytes + 512) / 1024 << "k estimated texture memory required.\n";
if (_bytes != 0) {
if (_unused_bytes != 0) {
indent(out, indent_level + 2);
format_memory_fraction(out, _unused_bytes, _bytes)
<< " is wasted because of unused palette space.\n";
}
if (_coverage_bytes > 0) {
indent(out, indent_level + 2);
format_memory_fraction(out, _coverage_bytes, _bytes)
<< " is wasted for repeating textures and margins.\n";
} else if (_coverage_bytes < 0) {
indent(out, indent_level + 2);
format_memory_fraction(out, -_coverage_bytes, _bytes)
<< " is *saved* for palettizing partial textures.\n";
}
if (_duplicate_bytes != 0) {
indent(out, indent_level + 2);
format_memory_fraction(out, _duplicate_bytes, _bytes)
<< " is wasted because of a texture appearing in multiple groups.\n";
}
}
}
/**
* Writes to the indicated ostream an indication of the fraction of the total
* memory usage that is represented by fraction_bytes.
*/
std::ostream &TextureMemoryCounter::
format_memory_fraction(std::ostream &out, int fraction_bytes, int palette_bytes) {
out << floor(1000.0 * (double)fraction_bytes / (double)palette_bytes + 0.5) / 10.0
<< "% (" << (fraction_bytes + 512) / 1024 << "k)";
return out;
}
/**
* Adds the indicated PaletteImage to the count. If this is called twice for
* a given PaletteImage it does nothing.
*/
void TextureMemoryCounter::
add_palette(PaletteImage *image) {
bool inserted = _palettes.insert(image).second;
if (!inserted) {
// We've already added this palette image.
return;
}
int bytes = count_bytes(image);
double unused = 1.0 - image->count_utilization();
double coverage = image->count_coverage();
_bytes += bytes;
_unused_bytes += (int)(unused * bytes);
_coverage_bytes += (int)(coverage * bytes);
_num_palettes++;
}
/**
* Adds the given TextureImage to the counter. If the texture image has
* already been added, this counts the smaller of the two as duplicate bytes.
*/
void TextureMemoryCounter::
add_texture(TextureImage *texture, int bytes) {
std::pair<Textures::iterator, bool> result;
result = _textures.insert(Textures::value_type(texture, bytes));
if (result.second) {
// If it was inserted, no problem--no duplicates.
_num_textures++;
return;
}
// If it was not inserted, we have a duplicate.
Textures::iterator ti = result.first;
_duplicate_bytes += std::min(bytes, (*ti).second);
(*ti).second = std::max(bytes, (*ti).second);
}
/**
* Attempts to estimate the number of bytes the given image file will use in
* texture memory.
*/
int TextureMemoryCounter::
count_bytes(ImageFile *image) {
return count_bytes(image, image->get_x_size(), image->get_y_size());
}
/**
* Attempts to estimate the number of bytes the given image file will use in
* texture memory.
*/
int TextureMemoryCounter::
count_bytes(ImageFile *image, int x_size, int y_size) {
int pixels = x_size * y_size;
// Try to guess the number of bytes per pixel this texture will consume in
// texture memory, based on its requested format. This is only a loose
// guess, because this depends of course on the pecularities of the
// particular rendering engine.
int bpp = 0;
switch (image->get_properties()._format) {
case EggTexture::F_rgba12:
bpp = 6;
break;
case EggTexture::F_rgba:
case EggTexture::F_rgbm:
case EggTexture::F_rgba8:
bpp = 4;
break;
case EggTexture::F_rgb:
case EggTexture::F_rgb12:
bpp = 3;
break;
case EggTexture::F_rgba4:
case EggTexture::F_rgba5:
case EggTexture::F_rgb8:
case EggTexture::F_rgb5:
case EggTexture::F_luminance_alpha:
case EggTexture::F_luminance_alphamask:
bpp = 2;
break;
case EggTexture::F_rgb332:
case EggTexture::F_red:
case EggTexture::F_green:
case EggTexture::F_blue:
case EggTexture::F_alpha:
case EggTexture::F_luminance:
bpp = 1;
break;
default:
bpp = image->get_num_channels();
}
int bytes = pixels * bpp;
// If we're mipmapping, it's worth 13 more bytes.
switch (image->get_properties()._minfilter) {
case EggTexture::FT_nearest_mipmap_nearest:
case EggTexture::FT_linear_mipmap_nearest:
case EggTexture::FT_nearest_mipmap_linear:
case EggTexture::FT_linear_mipmap_linear:
bytes = (bytes * 4) / 3;
break;
default:
break;
}
return bytes;
}