Added support for textures_auto_power_2 and shader_auto_utilization

This commit is contained in:
Josh Yelon 2007-12-15 07:08:14 +00:00
parent 21436b4f4d
commit 2288645d39
17 changed files with 349 additions and 12 deletions

View File

@ -19,6 +19,7 @@
#include "graphicsEngine.h"
#include "graphicsPipe.h"
#include "parasiteBuffer.h"
#include "config_gobj.h"
#include "config_display.h"
#include "pipeline.h"
#include "drawCullHandler.h"
@ -1761,7 +1762,8 @@ do_add_window(GraphicsOutput *window,
// Access: Private
// Description: An internal function called by make_output to add
// the newly-created gsg object to the engine's
// list of gsg's.
// list of gsg's. It also adjusts various config
// variables based on the gsg's capabilities.
////////////////////////////////////////////////////////////////////
void GraphicsEngine::
do_add_gsg(GraphicsStateGuardian *gsg, GraphicsPipe *pipe,
@ -1772,6 +1774,8 @@ do_add_gsg(GraphicsStateGuardian *gsg, GraphicsPipe *pipe,
gsg->_pipe = pipe;
gsg->_engine = this;
auto_adjust_capabilities(gsg);
WindowRenderer *draw =
get_window_renderer(threading_model.get_draw_name(),
threading_model.get_draw_stage());
@ -1835,6 +1839,155 @@ do_resort_windows() {
_windows.sort();
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsEngine::auto_adjust_capabilities
// Access: Private
// Description: Video card capability flags are stored on a
// per-gsg basis. However, there are a few cases
// where panda needs to know not the capabilities
// of an individual GSG, but rather, the
// collective capabilities of all the GSGs.
//
// Non-power-of-two (NPOT) texture support is the
// classic example. Panda makes a single global
// decision to either create NPOT textures, or not.
// Therefore, it doesn't need to know whether one GSG
// supports NPOT textures. It needs to know whether ALL
// the GSGs support NPOT textures.
//
// The purpose of this routine is to maintain global
// capability flags that summarize the collective
// capabilities of the computer as a whole.
//
// These global capability flags are initialized from
// config variables. Then, they can be auto-reconfigured
// using built-in heuristic mechanisms if the user so
// desires. Whether auto-reconfiguration is enabled or
// not, the configured values are checked against
// the actual capabilities of the machine and error
// messages will be printed if there is a mismatch.
//
////////////////////////////////////////////////////////////////////
void GraphicsEngine::
auto_adjust_capabilities(GraphicsStateGuardian *gsg) {
// The rule we use when auto-reconfiguring is as follows. The
// global capabilities must initially be set to conservative
// values. When the first GSG comes into existence, its
// capabilities will be checked, and the global capabilities
// may be elevated to more aggressive values.
//
// At first glance, this might seem backward, and it might seem
// better to do it the other way: start with all global capabilities
// aggressively set, and then disable capabilities when you discover
// a gsg that doesn't support them.
//
// However, that approach doesn't work, because once a global
// capability is enabled, there is no going back. If
// textures_power_2 has ever been set to 'none', there may be NPOT
// textures already floating about the system. Ie, it's too late:
// you can't turn these global capability flags off, once they've
// been turned on.
//
// That's why we have to start with conservative settings, and then
// elevate those settings to more aggressive values later when
// we're fairly sure it's OK to do so.
//
// For each global capability, we must:
// 1. Make sure the initial setting is conservative.
// 2. Possibly elevate to a more aggressive value.
// 3. Check that we haven't over-elevated.
//
if (textures_auto_power_2 && (textures_power_2 == ATS_none)) {
display_cat.error()
<< "Invalid panda config file: if you set the config-variable\n"
<< "textures_auto_power_2 to true, you must set the config-variable"
<< "textures_power_2 to 'up' or 'down'.\n";
textures_power_2 = ATS_down; // Not a fix. Just suppresses further error messages.
}
if (textures_auto_power_2 && !Texture::have_textures_power_2()) {
if (gsg->get_supports_tex_non_pow2()) {
Texture::set_textures_power_2(ATS_none);
} else {
Texture::set_textures_power_2(textures_power_2);
}
}
if ((Texture::get_textures_power_2() == ATS_none) &&
(!gsg->get_supports_tex_non_pow2())) {
// Overaggressive configuration detected
display_cat.error()
<< "The 'textures_power_2' configuration is set to 'none', meaning \n"
<< "that non-power-of-two texture support is required, but the video \n"
<< "driver I'm trying to use does not support non-power-of-two textures.\n";
if (textures_power_2 != ATS_none) {
display_cat.error()
<< "The 'none' did not come from the config file. In other words,\n"
<< "the variable 'textures_power_2' was altered procedurally.\n";
if (textures_auto_power_2) {
display_cat.error()
<< "It is possible that it was set by panda's automatic mechanisms,\n"
<< "which are currently enabled, because 'textures_auto_power_2' is\n"
<< "true. Panda's automatic mechanisms assume that if one\n"
<< "window supports non-power-of-two textures, then they all will.\n"
<< "This assumption works for most games, but not all.\n"
<< "In particular, it can fail if the game creates multiple windows\n"
<< "on multiple displays with different video cards.\n";
}
}
}
if (shader_auto_utilization && (shader_utilization != SUT_none)) {
display_cat.error()
<< "Invalid panda config file: if you set the config-variable\n"
<< "shader_auto_utilization to true, you must set the config-variable"
<< "shader_utilization to 'none'.\n";
shader_utilization = SUT_none; // Not a fix. Just suppresses further error messages.
}
if (shader_auto_utilization && !Shader::have_shader_utilization()) {
if (gsg->get_supports_basic_shaders()) {
Shader::set_shader_utilization(SUT_basic);
} else {
Shader::set_shader_utilization(SUT_none);
}
}
if ((Shader::get_shader_utilization() != SUT_none) &&
(!gsg->get_supports_basic_shaders())) {
// Overaggressive configuration detected
display_cat.error()
<< "The 'shader_utilization' config variable is set, meaning\n"
<< "that panda may try to generate shaders. However, the video \n"
<< "driver I'm trying to use does not support shaders.\n";
if (shader_utilization == SUT_none) {
display_cat.error()
<< "The 'shader_utilization' setting did not come from the config\n"
<< "file. In other words, it was altered procedurally.\n";
if (shader_auto_utilization) {
display_cat.error()
<< "It is possible that it was set by panda's automatic mechanisms,\n"
<< "which are currently enabled, because 'shader_auto_utilization' is\n"
<< "true. Panda's automatic mechanisms assume that if one\n"
<< "window supports shaders, then they all will.\n"
<< "This assumption works for most games, but not all.\n"
<< "In particular, it can fail if the game creates multiple windows\n"
<< "on multiple displays with different video cards.\n";
}
}
}
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsEngine::terminate_threads
// Access: Private

View File

@ -124,6 +124,7 @@ public:
bool remove_callback(const string &thread_name, CallbackTime callback_time,
CallbackFunction *func, void *data);
private:
class Callback {
public:
@ -172,6 +173,7 @@ private:
void do_remove_window(GraphicsOutput *window, Thread *current_thread);
void do_resort_windows();
void terminate_threads(Thread *current_thread);
void auto_adjust_capabilities(GraphicsStateGuardian *gsg);
#ifdef DO_PSTATS
typedef map<TypeHandle, PStatCollector> CyclerTypeCounters;

View File

@ -268,6 +268,7 @@ clear_render_textures() {
void GraphicsOutput::
add_render_texture(Texture *tex, RenderTextureMode mode,
RenderTexturePlane plane) {
if (mode == RTM_none) {
return;
}
@ -315,7 +316,7 @@ add_render_texture(Texture *tex, RenderTextureMode mode,
// Go ahead and tell the texture our anticipated size, even if it
// might be inaccurate (particularly if this is a GraphicsWindow,
// which has system-imposed restrictions on size).
if (textures_power_2 != ATS_none) {
if (Texture::get_textures_power_2() != ATS_none) {
tex->set_x_size(Texture::up_to_power_2(get_x_size()));
tex->set_y_size(Texture::up_to_power_2(get_y_size()));
} else {
@ -590,7 +591,7 @@ create_texture_card_vdata(int x, int y)
float xhi = 1.0;
float yhi = 1.0;
if (textures_power_2 != ATS_none) {
if (Texture::get_textures_power_2() != ATS_none) {
int xru = Texture::up_to_power_2(x);
int yru = Texture::up_to_power_2(y);
xhi = (x * 1.0f) / xru;

View File

@ -405,11 +405,11 @@ protected:
bool _supports_stencil_wrap;
bool _supports_two_sided_stencil;
int _supported_geom_rendering;
int _supported_geom_rendering;
bool _color_scale_via_lighting;
bool _alpha_scale_via_texture;
int _stereo_buffer_mask;
int _stereo_buffer_mask;
StencilRenderStates *_stencil_render_states;

View File

@ -178,7 +178,7 @@ rebuild_bitplanes() {
}
int bitplane_x = _x_size;
int bitplane_y = _y_size;
if (textures_power_2 != ATS_none) {
if (Texture::get_textures_power_2() != ATS_none) {
bitplane_x = Texture::up_to_power_2(bitplane_x);
bitplane_y = Texture::up_to_power_2(bitplane_y);
}

View File

@ -228,6 +228,32 @@ ConfigVariableEnum<AutoTextureScale> textures_square
"a square aspect ratio when they are loaded from disk. Set this "
"to 'none', 'down', or 'up'. See textures-power-2."));
ConfigVariableBool textures_auto_power_2
("textures-auto-power-2", false,
PRC_DESC("If this is true, then panda will wait until you open a window, "
"and then ask the window if it supports non-power-of-two textures. "
"If so, then the config variable textures_power_2 will "
"automatically be adjusted. The pitfall of doing this is that if "
"you then open a second window that doesn't support the same "
"capabilities, it will have no choice but to print an error message."));
ConfigVariableEnum<ShaderUtilization> shader_utilization
("shader-utilization", SUT_none,
PRC_DESC("At times, panda may generate shaders. This variable controls what "
"kinds of shaders can be generated. If you set it to SUT_none, "
"shader generation will be be disabled. If you set it to SUT_basic, "
"then DX9 shaders may be generated, if you set it to SUT_advanced, "
"then DX10 shaders may be generated."));
ConfigVariableBool shader_auto_utilization
("shader-auto-utilization", false,
PRC_DESC("If this is true, then panda will wait until you open a window, "
"and then ask the window if it supports basic or advanced shaders. "
"If so, then the config variable shader-utilization will "
"automatically be adusted. The pitfall of doing this is that if "
"you then open a second window that doesn't support the same "
"capabilities, it will have no choice but to print an error message."));
extern EXPCL_PANDA_GOBJ ConfigVariableBool textures_header_only;
ConfigVariableBool textures_header_only
("textures-header-only", false,
@ -445,3 +471,47 @@ operator >> (istream &in, AutoTextureScale &ats) {
return in;
}
ostream &
operator << (ostream &out, ShaderUtilization sgc) {
switch (sgc) {
case SUT_none:
return out << "none";
case SUT_basic:
return out << "basic";
case SUT_advanced:
return out << "advanced";
}
return out << "**invalid ShaderUtilization (" << (int)sgc << ")**";
}
istream &
operator >> (istream &in, ShaderUtilization &sgc) {
string word;
in >> word;
if (cmp_nocase(word, "none") == 0 ||
cmp_nocase(word, "0") == 0 ||
cmp_nocase(word, "#f") == 0 ||
tolower(word[0] == 'f')) {
sgc = SUT_none;
} else if (cmp_nocase(word, "basic") == 0 ||
cmp_nocase(word, "1") == 0 ||
cmp_nocase(word, "#t") == 0 ||
tolower(word[0] == 't')) {
sgc = SUT_basic;
} else if (cmp_nocase(word, "advanced") == 0) {
sgc = SUT_advanced;
} else {
gobj_cat->error() << "Invalid ShaderUtilization value: " << word << "\n";
sgc = SUT_none;
}
return in;
}

View File

@ -33,10 +33,20 @@ NotifyCategoryDecl(gobj, EXPCL_PANDA_GOBJ, EXPTP_PANDA_GOBJ);
enum AutoTextureScale {
ATS_none,
ATS_down,
ATS_up
ATS_up,
ATS_UNSPECIFIED,
};
enum ShaderUtilization {
SUT_none,
SUT_basic,
SUT_advanced,
SUT_UNSPECIFIED,
};
EXPCL_PANDA_GOBJ ostream &operator << (ostream &out, AutoTextureScale ats);
EXPCL_PANDA_GOBJ istream &operator >> (istream &in, AutoTextureScale &ats);
EXPCL_PANDA_GOBJ ostream &operator << (ostream &out, ShaderUtilization sut);
EXPCL_PANDA_GOBJ istream &operator >> (istream &in, ShaderUtilization &sut);
// Configure variables for gobj package.
extern EXPCL_PANDA_GOBJ ConfigVariableInt max_texture_dimension;
@ -59,8 +69,12 @@ extern EXPCL_PANDA_GOBJ ConfigVariableBool preserve_triangle_strips;
extern EXPCL_PANDA_GOBJ ConfigVariableEnum<AutoTextureScale> textures_power_2;
extern EXPCL_PANDA_GOBJ ConfigVariableEnum<AutoTextureScale> textures_square;
extern EXPCL_PANDA_GOBJ ConfigVariableBool textures_auto_power_2;
extern EXPCL_PANDA_GOBJ ConfigVariableBool textures_header_only;
extern EXPCL_PANDA_GOBJ ConfigVariableEnum<ShaderUtilization> shader_utilization;
extern EXPCL_PANDA_GOBJ ConfigVariableBool shader_auto_utilization;
extern EXPCL_PANDA_GOBJ ConfigVariableInt geom_cache_size;
extern EXPCL_PANDA_GOBJ ConfigVariableInt geom_cache_min_frames;
extern EXPCL_PANDA_GOBJ ConfigVariableInt released_vbuffer_cache_size;

View File

@ -58,6 +58,49 @@ get_error_flag() const {
return _error_flag;
}
////////////////////////////////////////////////////////////////////
// Function: Shader::set_shader_utilization
// Access: Published, Static
// Description: Set this flag to SUT_none, SUT_basic, or
// SUT_advanced to limit panda's automatic shader
// generation facilities.
////////////////////////////////////////////////////////////////////
INLINE void Shader::
set_shader_utilization(ShaderUtilization sut) {
_shader_utilization = sut;
}
////////////////////////////////////////////////////////////////////
// Function: Shader::get_shader_utilization
// Access: Published, Static
// Description: This flag returns SUT_none, SUT_basic, or
// SUT_advanced and controls the automatic generation
// of shaders. It is initialized from the config
// variable of the same name, but it can be
// subsequently adjusted.
////////////////////////////////////////////////////////////////////
INLINE ShaderUtilization Shader::
get_shader_utilization() {
if (_shader_utilization == SUT_UNSPECIFIED) {
return shader_utilization;
} else {
return _shader_utilization;
}
}
////////////////////////////////////////////////////////////////////
// Function: Shader::have_shader_utilization
// Access: Published, Static
// Description: If true, then get_shader_utilization has been
// set using set_shader_utilization.
// If false, then get_shader_utilization simply
// returns the config variable of the same name.
////////////////////////////////////////////////////////////////////
INLINE bool Shader::
have_shader_utilization() {
return (_shader_utilization != SUT_UNSPECIFIED);
}
////////////////////////////////////////////////////////////////////
// Function: Shader::ShaderCapabilities Constructor
// Access: Public

View File

@ -29,6 +29,7 @@ TypeHandle Shader::_type_handle;
Shader::LoadTable Shader::_load_table;
Shader::MakeTable Shader::_make_table;
Shader::ShaderCaps Shader::_default_caps;
ShaderUtilization Shader::_shader_utilization = SUT_UNSPECIFIED;
////////////////////////////////////////////////////////////////////
// Function: Shader::cp_report_error

View File

@ -51,6 +51,10 @@ PUBLISHED:
INLINE const string &get_header() const;
INLINE bool get_error_flag() const;
INLINE static ShaderUtilization get_shader_utilization();
INLINE static void set_shader_utilization(ShaderUtilization utl);
INLINE static bool have_shader_utilization();
void prepare(PreparedGraphicsObjects *prepared_objects);
bool is_prepared(PreparedGraphicsObjects *prepared_objects) const;
bool release(PreparedGraphicsObjects *prepared_objects);
@ -268,6 +272,7 @@ public:
bool _loaded;
static ShaderCaps _default_caps;
static ShaderUtilization _shader_utilization;
typedef pmap < Filename , Shader * > LoadTable;
typedef pmap < string , Shader * > MakeTable;

View File

@ -1381,3 +1381,45 @@ is_txo_filename(const Filename &fullpath) {
#endif // HAVE_ZLIB
return (extension == "txo");
}
////////////////////////////////////////////////////////////////////
// Function: Texture::set_textures_power_2
// Access: Published, Static
// Description: Set this flag to ATS_none, ATS_up, or ATS_down
// to control the scaling of textures.
////////////////////////////////////////////////////////////////////
INLINE void Texture::
set_textures_power_2(AutoTextureScale scale) {
_textures_power_2 = scale;
}
////////////////////////////////////////////////////////////////////
// Function: Texture::get_textures_power_2
// Access: Published, Static
// Description: This flag returns ATS_none, ATS_up, or ATS_down
// and controls the scaling of textures. It is
// initialized from the config variable of the same
// name, but it can be subsequently adjusted.
////////////////////////////////////////////////////////////////////
INLINE AutoTextureScale Texture::
get_textures_power_2() {
if (_textures_power_2 == ATS_UNSPECIFIED) {
return textures_power_2;
} else {
return _textures_power_2;
}
}
////////////////////////////////////////////////////////////////////
// Function: Texture::have_textures_power_2
// Access: Published, Static
// Description: If true, then get_textures_power_2 has been
// set using set_textures_power_2.
// If false, then get_textures_power_2 simply
// returns the config variable of the same name.
////////////////////////////////////////////////////////////////////
INLINE bool Texture::
have_textures_power_2() {
return (_textures_power_2 != ATS_UNSPECIFIED);
}

View File

@ -44,6 +44,7 @@
PStatCollector Texture::_texture_read_pcollector("*:Texture:Read");
TypeHandle Texture::_type_handle;
AutoTextureScale Texture::_textures_power_2 = ATS_UNSPECIFIED;
////////////////////////////////////////////////////////////////////
// Function: Texture::Constructor
@ -2909,7 +2910,7 @@ consider_rescale(PNMImage &pnmimage, const string &name) {
new_y_size = (int)cfloor(new_y_size * texture_scale + 0.5);
}
switch (textures_power_2.get_value()) {
switch (get_textures_power_2()) {
case ATS_down:
new_x_size = down_to_power_2(new_x_size);
new_y_size = down_to_power_2(new_y_size);

View File

@ -323,6 +323,10 @@ PUBLISHED:
void clear_aux_data(const string &key);
TypedReferenceCount *get_aux_data(const string &key) const;
INLINE static void set_textures_power_2(AutoTextureScale scale);
INLINE static AutoTextureScale get_textures_power_2();
INLINE static bool have_textures_power_2();
PUBLISHED:
// These are published, but in general, you shouldn't be mucking
// with these values; they are set automatically when a texture is
@ -547,6 +551,7 @@ private:
typedef pmap<string, PT(TypedReferenceCount) > AuxData;
AuxData _aux_data;
static AutoTextureScale _textures_power_2;
static PStatCollector _texture_read_pcollector;
// Datagram stuff

View File

@ -138,7 +138,7 @@ reconsider_video_properties(const FFMpegTexture::VideoStream &stream,
int x_size = width;
int y_size = height;
if (textures_power_2 != ATS_none) {
if (Texture::get_textures_power_2() != ATS_none) {
x_size = up_to_power_2(width);
y_size = up_to_power_2(height);
}

View File

@ -236,7 +236,7 @@ recalculate_image_properties(CDWriter &cdata) {
int x_size = x_max;
int y_size = y_max;
if (textures_power_2 != ATS_none) {
if (Texture::get_textures_power_2() != ATS_none) {
x_max = up_to_power_2(x_max);
y_max = up_to_power_2(y_max);
}

View File

@ -156,7 +156,7 @@ reconsider_video_properties(const OpenCVTexture::VideoStream &stream,
int x_size = width;
int y_size = height;
if (textures_power_2 != ATS_none) {
if (Texture::get_textures_power_2() != ATS_none) {
x_size = up_to_power_2(width);
y_size = up_to_power_2(height);
}

View File

@ -86,7 +86,7 @@ void MovieVideoCursor::
setup_texture(Texture *tex) const {
int fullx = size_x();
int fully = size_y();
if (textures_power_2) {
if (Texture::get_textures_power_2()) {
fullx = Texture::up_to_power_2(fullx);
fully = Texture::up_to_power_2(fully);
}