*** empty log message ***

This commit is contained in:
David Rose 2000-12-20 04:00:40 +00:00
parent 417ed7154a
commit 8735480f77
11 changed files with 576 additions and 15 deletions

View File

@ -22,6 +22,7 @@
palettizer.cxx palettizer.h \
sourceTextureImage.cxx sourceTextureImage.h \
textureImage.cxx textureImage.h \
textureMemoryCounter.cxx textureMemoryCounter.h \
texturePlacement.cxx texturePlacement.h \
texturePosition.cxx texturePosition.h \
textureProperties.cxx textureProperties.h textureReference.cxx \

View File

@ -69,7 +69,7 @@ EggPalettize() : EggMultiFilter(true) {
("s", "", 0,
"Do not process anything, but report statistics on palette "
"and texture utilization.",
&EggPalettize::dispatch_none, &_statistics_only);
&EggPalettize::dispatch_none, &_report_statistics);
// We redefine -d using add_option() instead of redescribe_option()
// so it gets listed along with these other options that relate.
@ -515,6 +515,11 @@ run() {
exit(0);
}
if (_report_statistics) {
pal->report_statistics();
exit(0);
}
bool okflag = true;
pal->read_txa_file(_txa_filename);

View File

@ -44,7 +44,7 @@ private:
// The following values control behavior specific to this session.
// They're not saved for future sessions.
bool _report_pi;
bool _statistics_only;
bool _report_statistics;
bool _all_textures;
bool _optimal;
bool _redo_all;

View File

@ -7,6 +7,7 @@
#include "palettePage.h"
#include "texturePlacement.h"
#include "textureImage.h"
#include "palettizer.h"
#include <indent.h>
#include <datagram.h>
@ -25,6 +26,7 @@ PaletteGroup::
PaletteGroup() {
_egg_count = 0;
_dependency_level = 0;
_dependency_order = 0;
}
////////////////////////////////////////////////////////////////////
@ -73,6 +75,7 @@ void PaletteGroup::
clear_depends() {
_dependent.clear();
_dependency_level = 0;
_dependency_order = 0;
}
////////////////////////////////////////////////////////////////////
@ -102,6 +105,59 @@ get_groups() const {
return _dependent;
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::get_placements
// Access: Public
// Description: Adds the set of TexturePlacements associated with
// this group to the indicated vector. The vector is
// not cleared before this operation; if the user wants
// to retrieve the set of placements particular to this
// group only, it is the user's responsibility to clear
// the vector first.
////////////////////////////////////////////////////////////////////
void PaletteGroup::
get_placements(vector<TexturePlacement *> &placements) const {
Placements::iterator pi;
for (pi = _placements.begin(); pi != _placements.end(); ++pi) {
placements.push_back(*pi);
}
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::get_complete_placements
// Access: Public
// Description: Adds the set of TexturePlacements associated with
// this group and all dependent groups to the indicated
// vector. See get_placements().
////////////////////////////////////////////////////////////////////
void PaletteGroup::
get_complete_placements(vector<TexturePlacement *> &placements) const {
PaletteGroups complete;
complete.make_complete(_dependent);
PaletteGroups::iterator gi;
for (gi = complete.begin(); gi != complete.end(); ++gi) {
PaletteGroup *group = (*gi);
group->get_placements(placements);
}
get_placements(placements);
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::reset_dependency_level
// Access: Public
// Description: Unconditionally sets the dependency level and order
// of this group to zero, in preparation for a later
// call to set_dependency_level(). See
// set_dependency_level().
////////////////////////////////////////////////////////////////////
void PaletteGroup::
reset_dependency_level() {
_dependency_level = 0;
_dependency_order = 0;
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::set_dependency_level
// Access: Public
@ -120,11 +176,44 @@ set_dependency_level(int level) {
_dependency_level = level;
PaletteGroups::iterator gi;
for (gi = _dependent.begin(); gi != _dependent.end(); ++gi) {
(*gi)->set_dependency_level(level + 1);
PaletteGroup *group = (*gi);
group->set_dependency_level(level + 1);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::set_dependency_order
// Access: Public
// Description: Updates the dependency order of this group. This
// number is the inverse of the dependency level, and
// can be used to rank the groups in order so that all
// the groups that a given group depends on will appear
// first in the list. See get_dependency_order().
//
// This function returns true if anything was changed,
// false otherwise.
////////////////////////////////////////////////////////////////////
bool PaletteGroup::
set_dependency_order() {
bool any_changed = false;
PaletteGroups::iterator gi;
for (gi = _dependent.begin(); gi != _dependent.end(); ++gi) {
PaletteGroup *group = (*gi);
if (group->set_dependency_order()) {
any_changed = true;
}
if (_dependency_order <= group->get_dependency_order()) {
_dependency_order = group->get_dependency_order() + 1;
any_changed = true;
}
}
return any_changed;
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::get_dependency_level
// Access: Public
@ -151,6 +240,26 @@ get_dependency_level() const {
return _dependency_level;
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::get_dependency_order
// Access: Public
// Description: Returns the dependency order of this group. This is
// similar in principle to the dependency level, but it
// represents the inverse concept: if group a depends on
// group b, then a->get_dependency_order() >
// b->get_dependency_order().
//
// This is not exactly the same thing as n -
// get_dependency_level(). In particular, this can be
// used to sort the groups into an ordering such that
// all the groups that group a depends on appear before
// group a in the list.
////////////////////////////////////////////////////////////////////
int PaletteGroup::
get_dependency_order() const {
return _dependency_order;
}
////////////////////////////////////////////////////////////////////
// Function: PaletteGroup::increment_egg_count
// Access: Public
@ -392,8 +501,8 @@ write_datagram(BamWriter *writer, Datagram &datagram) {
datagram.add_string(_dirname);
_dependent.write_datagram(writer, datagram);
// We don't write out _dependency_level. It's best to recompute
// that each time.
datagram.add_int32(_dependency_level);
datagram.add_int32(_dependency_order);
datagram.add_uint32(_placements.size());
Placements::const_iterator pli;
@ -504,6 +613,11 @@ fillin(DatagramIterator &scan, BamReader *manager) {
_dirname = scan.get_string();
_dependent.fillin(scan, manager);
if (Palettizer::_read_pi_version >= 3) {
_dependency_level = scan.get_int32();
_dependency_order = scan.get_int32();
}
_num_placements = scan.get_uint32();
manager->read_pointers(scan, this, _num_placements);

View File

@ -15,6 +15,7 @@
#include <typedWriteable.h>
#include <set>
#include <vector>
class EggFile;
class TexturePlacement;
@ -44,8 +45,14 @@ public:
void group_with(PaletteGroup *other);
const PaletteGroups &get_groups() const;
void get_placements(vector<TexturePlacement *> &placements) const;
void get_complete_placements(vector<TexturePlacement *> &placements) const;
void reset_dependency_level();
void set_dependency_level(int level);
bool set_dependency_order();
int get_dependency_level() const;
int get_dependency_order() const;
void increment_egg_count();
int get_egg_count() const;
@ -69,6 +76,7 @@ private:
int _egg_count;
PaletteGroups _dependent;
int _dependency_level;
int _dependency_order;
typedef set<TexturePlacement *> Placements;
Placements _placements;

View File

@ -207,6 +207,31 @@ is_empty() const {
}
}
////////////////////////////////////////////////////////////////////
// Function: PaletteImage::count_utilization
// Access: Public
// Description: Returns the fraction of the PaletteImage that is
// actually used by any textures. This is 1.0 if every
// pixel in the PaletteImage is used, or 0.0 if none
// are. Normally it will be somewhere in between.
////////////////////////////////////////////////////////////////////
double PaletteImage::
count_utilization() const {
int used_pixels = 0;
Placements::const_iterator pi;
for (pi = _placements.begin(); pi != _placements.end(); ++pi) {
TexturePlacement *placement = (*pi);
int texture_pixels = placement->get_x_size() * placement->get_y_size();
used_pixels += texture_pixels;
}
int total_pixels = get_x_size() * get_y_size();
return (double)used_pixels / (double)total_pixels;
}
////////////////////////////////////////////////////////////////////
// Function: PaletteImage::place
// Access: Public

View File

@ -34,6 +34,7 @@ public:
PalettePage *get_page() const;
bool is_empty() const;
double count_utilization() const;
bool place(TexturePlacement *placement);
void unplace(TexturePlacement *placement);

View File

@ -9,6 +9,7 @@
#include "pal_string_utils.h"
#include "paletteGroup.h"
#include "filenameUnifier.h"
#include "textureMemoryCounter.h"
#include <pnmImage.h>
#include <pnmFileTypeRegistry.h>
@ -18,6 +19,7 @@
#include <datagramIterator.h>
#include <bamReader.h>
#include <bamWriter.h>
#include <indent.h>
Palettizer *pal = (Palettizer *)NULL;
@ -26,9 +28,10 @@ Palettizer *pal = (Palettizer *)NULL;
// allows us to easily update egg-palettize to write out additional
// information to its pi file, without having it increment the bam
// version number for all bam and boo files anywhere in the world.
int Palettizer::_pi_version = 2;
int Palettizer::_pi_version = 3;
// Updated to version 1 on 12/11/00 to add _remap_char_uv.
// Updated to version 2 on 12/19/00 to add TexturePlacement::_dest.
// Updated to version 3 on 12/19/00 to add PaletteGroup::_dependency_order.
int Palettizer::_read_pi_version = 0;
@ -52,6 +55,18 @@ ostream &operator << (ostream &out, Palettizer::RemapUV remap) {
return out << "**invalid**(" << (int)remap << ")";
}
// This STL function object is used in report_statistics(), below.
class SortGroupsByDependencyOrder {
public:
bool operator ()(PaletteGroup *a, PaletteGroup *b) {
if (a->get_dependency_order() != b->get_dependency_order()) {
return a->get_dependency_order() < b->get_dependency_order();
}
return a->get_name() < b->get_name();
}
};
////////////////////////////////////////////////////////////////////
// Function: Palettizer::Constructor
// Access: Public
@ -178,6 +193,63 @@ report_pi() const {
cout << "\n";
}
////////////////////////////////////////////////////////////////////
// Function: Palettizer::report_statistics
// Access: Public
// Description: Output a report of the palettization effectiveness,
// texture memory utilization, and so on.
////////////////////////////////////////////////////////////////////
void Palettizer::
report_statistics() const {
// Sort the groups into order by dependency order, for the user's
// convenience.
vector<PaletteGroup *> sorted_groups;
Groups::const_iterator gi;
for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
sorted_groups.push_back((*gi).second);
}
sort(sorted_groups.begin(), sorted_groups.end(),
SortGroupsByDependencyOrder());
Placements overall_placements;
vector<PaletteGroup *>::const_iterator sgi;
for (sgi = sorted_groups.begin();
sgi != sorted_groups.end();
++sgi) {
PaletteGroup *group = (*sgi);
Placements placements;
group->get_placements(placements);
if (!placements.empty()) {
group->get_placements(overall_placements);
cout << "\n" << group->get_name() << ", by itself:\n";
compute_statistics(cout, 2, placements);
PaletteGroups complete;
complete.make_complete(group->get_groups());
if (complete.size() > 1) {
Placements complete_placements;
group->get_complete_placements(complete_placements);
if (complete_placements.size() != placements.size()) {
cout << "\n" << group->get_name()
<< ", with dependents (" << complete << "):\n";
compute_statistics(cout, 2, complete_placements);
}
}
}
}
cout << "\nOverall:\n";
compute_statistics(cout, 2, overall_placements);
cout << "\n";
}
////////////////////////////////////////////////////////////////////
// Function: Palettizer::read_txa_file
@ -209,12 +281,28 @@ read_txa_file(const Filename &txa_filename) {
exit(1);
}
// Compute the correct dependency level for each group. This will
// help us when we assign the textures to their groups.
// Compute the correct dependency level and order for each group.
// This will help us when we assign the textures to their groups.
for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
PaletteGroup *group = (*gi).second;
group->reset_dependency_level();
}
for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
PaletteGroup *group = (*gi).second;
group->set_dependency_level(1);
}
bool any_changed;
do {
any_changed = false;
for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
PaletteGroup *group = (*gi).second;
if (group->set_dependency_order()) {
any_changed = true;
}
}
} while (any_changed);
}
////////////////////////////////////////////////////////////////////
@ -617,6 +705,17 @@ get_texture(const string &name) {
return image;
}
////////////////////////////////////////////////////////////////////
// Function: Palettizer::yesno
// Access: Private, Static
// Description: A silly function to return "yes" or "no" based on a
// bool flag for nicely formatted output.
////////////////////////////////////////////////////////////////////
const char *Palettizer::
yesno(bool flag) {
return flag ? "yes" : "no";
}
////////////////////////////////////////////////////////////////////
// Function: Palettizer::string_remap
// Access: Public, Static
@ -641,14 +740,24 @@ string_remap(const string &str) {
}
////////////////////////////////////////////////////////////////////
// Function: Palettizer::yesno
// Access: Private, Static
// Description: A silly function to return "yes" or "no" based on a
// bool flag for nicely formatted output.
// Function: Palettizer::compute_statistics
// Access: Private
// Description: Determines how much memory, etc. is required by the
// indicated set of texture placements, and reports this
// to the indicated output stream.
////////////////////////////////////////////////////////////////////
const char *Palettizer::
yesno(bool flag) {
return flag ? "yes" : "no";
void Palettizer::
compute_statistics(ostream &out, int indent_level,
const Palettizer::Placements &placements) const {
TextureMemoryCounter counter;
Placements::const_iterator pi;
for (pi = placements.begin(); pi != placements.end(); ++pi) {
TexturePlacement *placement = (*pi);
counter.add_placement(placement);
}
counter.report(out, indent_level);
}
////////////////////////////////////////////////////////////////////

View File

@ -20,6 +20,7 @@ class PNMFileType;
class EggFile;
class PaletteGroup;
class TextureImage;
class TexturePlacement;
////////////////////////////////////////////////////////////////////
// Class : Palettizer
@ -34,6 +35,8 @@ public:
Palettizer();
void report_pi() const;
void report_statistics() const;
void read_txa_file(const Filename &txa_filename);
void all_params_set();
void process_command_line_eggs(bool force_texture_read);
@ -94,6 +97,10 @@ public:
PNMFileType *_shadow_alpha_type;
private:
typedef vector<TexturePlacement *> Placements;
void compute_statistics(ostream &out, int indent_level,
const Placements &placements) const;
typedef map<string, EggFile *> EggFiles;
EggFiles _egg_files;

View File

@ -0,0 +1,233 @@
// Filename: textureMemoryCounter.cxx
// Created by: drose (19Dec00)
//
////////////////////////////////////////////////////////////////////
#include "textureMemoryCounter.h"
#include "paletteImage.h"
#include "textureImage.h"
#include "destTextureImage.h"
#include "omitReason.h"
#include "texturePlacement.h"
#include <indent.h>
#include <math.h>
////////////////////////////////////////////////////////////////////
// Function: TextureMemoryCounter::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
TextureMemoryCounter::
TextureMemoryCounter() {
reset();
}
////////////////////////////////////////////////////////////////////
// Function: TextureMemoryCounter::reset
// Access: Public
// Description: 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;
_textures.clear();
_palettes.clear();
}
////////////////////////////////////////////////////////////////////
// Function: TextureMemoryCounter::add_placement
// Access: Public
// Description: Adds the indicated TexturePlacement to the counter.
////////////////////////////////////////////////////////////////////
void TextureMemoryCounter::
add_placement(TexturePlacement *placement) {
TextureImage *texture = placement->get_texture();
nassertv(texture != (TextureImage *)NULL);
if (placement->get_omit_reason() == OR_none) {
PaletteImage *image = placement->get_image();
nassertv(image != (PaletteImage *)NULL);
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();
nassertv(dest != (DestTextureImage *)NULL);
int bytes = count_bytes(dest);
add_texture(texture, bytes);
_bytes += bytes;
_num_unplaced++;
}
}
////////////////////////////////////////////////////////////////////
// Function: TextureMemoryCounter::report
// Access: Public
// Description: Reports the measured texture memory usage.
////////////////////////////////////////////////////////////////////
void TextureMemoryCounter::
report(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) {
indent(out, indent_level + 2)
<< "Of this, "
<< floor(1000.0 * (double)_unused_bytes / (double)_bytes + 0.5) / 10.0
<< "% is wasted because of unused palette space.\n";
if (_duplicate_bytes != 0) {
indent(out, indent_level + 2)
<< "And " << 100.0 * (double)_duplicate_bytes / (double)_bytes
<< "% is wasted because of a texture appearing in multiple places.\n";
}
}
}
////////////////////////////////////////////////////////////////////
// Function: TextureMemoryCounter::add_palette
// Access: Private
// Description: 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 wasted = 1.0 - image->count_utilization();
_bytes += bytes;
_unused_bytes += (int)(wasted * bytes);
_num_palettes++;
}
////////////////////////////////////////////////////////////////////
// Function: TextureMemoryCounter::add_texture
// Access: Private
// Description: 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) {
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 += min(bytes, (*ti).second);
(*ti).second = max(bytes, (*ti).second);
}
////////////////////////////////////////////////////////////////////
// Function: TextureMemoryCounter::count_bytes
// Access: Private
// Description: 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());
}
////////////////////////////////////////////////////////////////////
// Function: TextureMemoryCounter::count_bytes
// Access: Private
// Description: 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 1/3 more bytes.
switch (image->get_properties()._magfilter) {
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;
}

View File

@ -0,0 +1,58 @@
// Filename: textureMemoryCounter.h
// Created by: drose (19Dec00)
//
////////////////////////////////////////////////////////////////////
#ifndef TEXTUREMEMORYCOUNTER_H
#define TEXTUREMEMORYCOUNTER_H
#include <pandatoolbase.h>
class ImageFile;
class PaletteImage;
class TextureImage;
class DestTextureImage;
class TexturePlacement;
#include <map>
#include <set>
////////////////////////////////////////////////////////////////////
// Class : TextureMemoryCounter
// Description : This class is used to gather statistics on texture
// memory usage, etc. It adds up the total texture
// memory required by a number of image files, and
// reports it at the end.
////////////////////////////////////////////////////////////////////
class TextureMemoryCounter {
public:
TextureMemoryCounter();
void reset();
void add_placement(TexturePlacement *placement);
void report(ostream &out, int indent_level);
private:
void add_palette(PaletteImage *image);
void add_texture(TextureImage *texture, int bytes);
int count_bytes(ImageFile *image);
int count_bytes(ImageFile *image, int x_size, int y_size);
int _num_textures;
int _num_placed;
int _num_unplaced;
int _num_palettes;
int _bytes;
int _unused_bytes;
int _duplicate_bytes;
typedef map<TextureImage *, int> Textures;
Textures _textures;
typedef set<PaletteImage *> Palettes;
Palettes _palettes;
};
#endif