瀏覽代碼

Added support for textures_auto_power_2 and shader_auto_utilization

Josh Yelon 18 年之前
父節點
當前提交
2288645d39

+ 154 - 1
panda/src/display/graphicsEngine.cxx

@@ -19,6 +19,7 @@
 #include "graphicsEngine.h"
 #include "graphicsEngine.h"
 #include "graphicsPipe.h"
 #include "graphicsPipe.h"
 #include "parasiteBuffer.h"
 #include "parasiteBuffer.h"
+#include "config_gobj.h"
 #include "config_display.h"
 #include "config_display.h"
 #include "pipeline.h"
 #include "pipeline.h"
 #include "drawCullHandler.h"
 #include "drawCullHandler.h"
@@ -1761,7 +1762,8 @@ do_add_window(GraphicsOutput *window,
 //       Access: Private
 //       Access: Private
 //  Description: An internal function called by make_output to add
 //  Description: An internal function called by make_output to add
 //               the newly-created gsg object to the engine's
 //               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::
 void GraphicsEngine::
 do_add_gsg(GraphicsStateGuardian *gsg, GraphicsPipe *pipe,
 do_add_gsg(GraphicsStateGuardian *gsg, GraphicsPipe *pipe,
@@ -1772,6 +1774,8 @@ do_add_gsg(GraphicsStateGuardian *gsg, GraphicsPipe *pipe,
   gsg->_pipe = pipe;
   gsg->_pipe = pipe;
   gsg->_engine = this;
   gsg->_engine = this;
 
 
+  auto_adjust_capabilities(gsg);
+  
   WindowRenderer *draw = 
   WindowRenderer *draw = 
     get_window_renderer(threading_model.get_draw_name(),
     get_window_renderer(threading_model.get_draw_name(),
                         threading_model.get_draw_stage());
                         threading_model.get_draw_stage());
@@ -1835,6 +1839,155 @@ do_resort_windows() {
   _windows.sort();
   _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
 //     Function: GraphicsEngine::terminate_threads
 //       Access: Private
 //       Access: Private

+ 2 - 0
panda/src/display/graphicsEngine.h

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

+ 3 - 2
panda/src/display/graphicsOutput.cxx

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

+ 2 - 2
panda/src/display/graphicsStateGuardian.h

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

+ 1 - 1
panda/src/glstuff/glGraphicsBuffer_src.cxx

@@ -178,7 +178,7 @@ rebuild_bitplanes() {
   }
   }
   int bitplane_x = _x_size;
   int bitplane_x = _x_size;
   int bitplane_y = _y_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_x = Texture::up_to_power_2(bitplane_x);
     bitplane_y = Texture::up_to_power_2(bitplane_y);
     bitplane_y = Texture::up_to_power_2(bitplane_y);
   }
   }

+ 70 - 0
panda/src/gobj/config_gobj.cxx

@@ -228,6 +228,32 @@ ConfigVariableEnum<AutoTextureScale> textures_square
           "a square aspect ratio when they are loaded from disk.  Set this "
           "a square aspect ratio when they are loaded from disk.  Set this "
           "to 'none', 'down', or 'up'.  See textures-power-2."));
           "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;
 extern EXPCL_PANDA_GOBJ ConfigVariableBool textures_header_only;
 ConfigVariableBool textures_header_only
 ConfigVariableBool textures_header_only
 ("textures-header-only", false,
 ("textures-header-only", false,
@@ -445,3 +471,47 @@ operator >> (istream &in, AutoTextureScale &ats) {
 
 
   return in;
   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;
+}

+ 15 - 1
panda/src/gobj/config_gobj.h

@@ -33,10 +33,20 @@ NotifyCategoryDecl(gobj, EXPCL_PANDA_GOBJ, EXPTP_PANDA_GOBJ);
 enum AutoTextureScale {
 enum AutoTextureScale {
   ATS_none,
   ATS_none,
   ATS_down,
   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 ostream &operator << (ostream &out, AutoTextureScale ats);
 EXPCL_PANDA_GOBJ istream &operator >> (istream &in, 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.
 // Configure variables for gobj package.
 extern EXPCL_PANDA_GOBJ ConfigVariableInt max_texture_dimension;
 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_power_2;
 extern EXPCL_PANDA_GOBJ ConfigVariableEnum<AutoTextureScale> textures_square;
 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 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_size;
 extern EXPCL_PANDA_GOBJ ConfigVariableInt geom_cache_min_frames;
 extern EXPCL_PANDA_GOBJ ConfigVariableInt geom_cache_min_frames;
 extern EXPCL_PANDA_GOBJ ConfigVariableInt released_vbuffer_cache_size;
 extern EXPCL_PANDA_GOBJ ConfigVariableInt released_vbuffer_cache_size;

+ 43 - 0
panda/src/gobj/shader.I

@@ -58,6 +58,49 @@ get_error_flag() const {
   return _error_flag;
   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
 //  Function: Shader::ShaderCapabilities Constructor
 //  Access: Public
 //  Access: Public

+ 1 - 0
panda/src/gobj/shader.cxx

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

+ 5 - 0
panda/src/gobj/shader.h

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

+ 42 - 0
panda/src/gobj/texture.I

@@ -1381,3 +1381,45 @@ is_txo_filename(const Filename &fullpath) {
 #endif  // HAVE_ZLIB
 #endif  // HAVE_ZLIB
   return (extension == "txo");
   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);
+}
+

+ 2 - 1
panda/src/gobj/texture.cxx

@@ -44,6 +44,7 @@
 
 
 PStatCollector Texture::_texture_read_pcollector("*:Texture:Read");
 PStatCollector Texture::_texture_read_pcollector("*:Texture:Read");
 TypeHandle Texture::_type_handle;
 TypeHandle Texture::_type_handle;
+AutoTextureScale Texture::_textures_power_2 = ATS_UNSPECIFIED;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::Constructor
 //     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);
     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:
   case ATS_down:
     new_x_size = down_to_power_2(new_x_size);
     new_x_size = down_to_power_2(new_x_size);
     new_y_size = down_to_power_2(new_y_size);
     new_y_size = down_to_power_2(new_y_size);

+ 5 - 0
panda/src/gobj/texture.h

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

+ 1 - 1
panda/src/grutil/ffmpegTexture.cxx

@@ -138,7 +138,7 @@ reconsider_video_properties(const FFMpegTexture::VideoStream &stream,
   int x_size = width;
   int x_size = width;
   int y_size = height;
   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);
     x_size = up_to_power_2(width);
     y_size = up_to_power_2(height);
     y_size = up_to_power_2(height);
   }
   }

+ 1 - 1
panda/src/grutil/movieTexture.cxx

@@ -236,7 +236,7 @@ recalculate_image_properties(CDWriter &cdata) {
 
 
   int x_size = x_max;
   int x_size = x_max;
   int y_size = y_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);
     x_max = up_to_power_2(x_max);
     y_max = up_to_power_2(y_max);
     y_max = up_to_power_2(y_max);
   }
   }

+ 1 - 1
panda/src/grutil/openCVTexture.cxx

@@ -156,7 +156,7 @@ reconsider_video_properties(const OpenCVTexture::VideoStream &stream,
   int x_size = width;
   int x_size = width;
   int y_size = height;
   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);
     x_size = up_to_power_2(width);
     y_size = up_to_power_2(height);
     y_size = up_to_power_2(height);
   }
   }

+ 1 - 1
panda/src/movies/movieVideoCursor.cxx

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