Bläddra i källkod

pipeline GraphicsOutput::set_active() to better support offscreen rendering in threaded mode

David Rose 14 år sedan
förälder
incheckning
bee4cb326a
32 ändrade filer med 374 tillägg och 233 borttagningar
  1. 9 11
      panda/src/display/displayRegion.cxx
  2. 3 1
      panda/src/display/graphicsEngine.cxx
  3. 21 34
      panda/src/display/graphicsOutput.I
  4. 159 60
      panda/src/display/graphicsOutput.cxx
  5. 44 15
      panda/src/display/graphicsOutput.h
  6. 1 1
      panda/src/display/graphicsWindow.cxx
  7. 2 6
      panda/src/display/parasiteBuffer.cxx
  8. 0 5
      panda/src/dxgsg8/wdxGraphicsBuffer8.cxx
  9. 0 1
      panda/src/dxgsg8/wdxGraphicsWindow8.cxx
  10. 0 1
      panda/src/dxgsg9/dxVertexBufferContext9.cxx
  11. 37 16
      panda/src/dxgsg9/wdxGraphicsBuffer9.cxx
  12. 0 1
      panda/src/dxgsg9/wdxGraphicsWindow9.cxx
  13. 8 4
      panda/src/egldisplay/eglGraphicsBuffer.cxx
  14. 8 4
      panda/src/egldisplay/eglGraphicsPixmap.cxx
  15. 0 1
      panda/src/egldisplay/eglGraphicsWindow.cxx
  16. 30 25
      panda/src/glstuff/glGraphicsBuffer_src.cxx
  17. 1 1
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  18. 0 1
      panda/src/glstuff/glShaderContext_src.cxx
  19. 8 4
      panda/src/glxdisplay/glxGraphicsBuffer.cxx
  20. 8 4
      panda/src/glxdisplay/glxGraphicsPixmap.cxx
  21. 0 1
      panda/src/glxdisplay/glxGraphicsWindow.cxx
  22. 2 5
      panda/src/gobj/config_gobj.cxx
  23. 8 4
      panda/src/osxdisplay/osxGraphicsBuffer.cxx
  24. 1 2
      panda/src/osxdisplay/osxGraphicsWindow.mm
  25. 0 1
      panda/src/tinydisplay/tinyGraphicsBuffer.cxx
  26. 5 7
      panda/src/tinydisplay/tinyOsxGraphicsWindow.mm
  27. 0 1
      panda/src/tinydisplay/tinyWinGraphicsWindow.cxx
  28. 0 1
      panda/src/tinydisplay/tinyXGraphicsWindow.cxx
  29. 19 10
      panda/src/wgldisplay/wglGraphicsBuffer.cxx
  30. 0 3
      panda/src/wgldisplay/wglGraphicsPipe.cxx
  31. 0 1
      panda/src/wgldisplay/wglGraphicsWindow.cxx
  32. 0 1
      panda/src/x11display/x11GraphicsWindow.cxx

+ 9 - 11
panda/src/display/displayRegion.cxx

@@ -174,8 +174,11 @@ is_stereo() const {
 void DisplayRegion::
 set_camera(const NodePath &camera) {
   int pipeline_stage = Thread::get_current_pipeline_stage();
-  nassertv(pipeline_stage == 0);
-  CDWriter cdata(_cycler);
+
+  // We allow set_camera(NodePath()) to happen in cleanup(), which can
+  // be called from any pipeline stage.
+  nassertv(pipeline_stage == 0 || camera.is_empty());
+  CDStageWriter cdata(_cycler, 0);
 
   Camera *camera_node = (Camera *)NULL;
   if (!camera.is_empty()) {
@@ -561,10 +564,10 @@ get_screenshot() {
   Thread *current_thread = Thread::get_current_thread();
 
   GraphicsOutput *window = get_window();
-  nassertr(window != (GraphicsOutput *)NULL, false);
+  nassertr(window != (GraphicsOutput *)NULL, NULL);
   
   GraphicsStateGuardian *gsg = window->get_gsg();
-  nassertr(gsg != (GraphicsStateGuardian *)NULL, false);
+  nassertr(gsg != (GraphicsStateGuardian *)NULL, NULL);
   
   if (!window->begin_frame(GraphicsOutput::FM_refresh, current_thread)) {
     return NULL;
@@ -622,11 +625,8 @@ make_cull_result_graph() {
 ////////////////////////////////////////////////////////////////////
 void DisplayRegion::
 compute_pixels() {
-  int pipeline_stage = Thread::get_current_pipeline_stage();
-  nassertv(pipeline_stage == 0);
-
   if (_window != (GraphicsOutput *)NULL) {
-    CDWriter cdata(_cycler);
+    CDWriter cdata(_cycler, false);
     do_compute_pixels(_window->get_fb_x_size(), _window->get_fb_y_size(), 
                       cdata);
   }
@@ -663,9 +663,7 @@ compute_pixels_all_stages() {
 ////////////////////////////////////////////////////////////////////
 void DisplayRegion::
 compute_pixels(int x_size, int y_size) {
-  int pipeline_stage = Thread::get_current_pipeline_stage();
-  nassertv(pipeline_stage == 0);
-  CDWriter cdata(_cycler);
+  CDWriter cdata(_cycler, false);
   do_compute_pixels(x_size, y_size, cdata);
 }
 

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

@@ -1407,7 +1407,9 @@ cull_to_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
 void GraphicsEngine::
 cull_to_bins(GraphicsOutput *win, DisplayRegion *dr, Thread *current_thread) {
   GraphicsStateGuardian *gsg = win->get_gsg();
-  nassertv(gsg != (GraphicsStateGuardian *)NULL);
+  if (gsg == (GraphicsStateGuardian *)NULL) {
+    return;
+  }
 
   PT(CullResult) cull_result;
   PT(SceneSetup) scene_setup;

+ 21 - 34
panda/src/display/graphicsOutput.I

@@ -80,7 +80,8 @@ get_name() const {
 ////////////////////////////////////////////////////////////////////
 INLINE int GraphicsOutput::
 count_textures() const {
-  return _textures.size();
+  CDReader cdata(_cycler);
+  return cdata->_textures.size();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -91,7 +92,8 @@ count_textures() const {
 ////////////////////////////////////////////////////////////////////
 INLINE bool GraphicsOutput::
 has_texture() const {
-  return (_textures.size() > 0);
+  CDReader cdata(_cycler);
+  return (cdata->_textures.size() > 0);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -109,10 +111,11 @@ has_texture() const {
 ////////////////////////////////////////////////////////////////////
 INLINE Texture *GraphicsOutput::
 get_texture(int i) const {
-  if ((i < 0) || (i >= ((int)_textures.size()))) {
+  CDReader cdata(_cycler);
+  if ((i < 0) || (i >= ((int)cdata->_textures.size()))) {
     return (Texture *)NULL;
   }
-  return _textures[i]._texture;
+  return cdata->_textures[i]._texture;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -124,10 +127,11 @@ get_texture(int i) const {
 ////////////////////////////////////////////////////////////////////
 INLINE GraphicsOutput::RenderTexturePlane GraphicsOutput::
 get_texture_plane(int i) const {
-  if ((i < 0) || (i >= ((int)_textures.size()))) {
+  CDReader cdata(_cycler);
+  if ((i < 0) || (i >= ((int)cdata->_textures.size()))) {
     return (RenderTexturePlane)0;
   }
-  return _textures[i]._plane;
+  return cdata->_textures[i]._plane;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -139,10 +143,11 @@ get_texture_plane(int i) const {
 ////////////////////////////////////////////////////////////////////
 INLINE GraphicsOutput::RenderTextureMode GraphicsOutput::
 get_rtm_mode(int i) const {
-  if ((i < 0) || (i >= ((int)_textures.size()))) {
+  CDReader cdata(_cycler);
+  if ((i < 0) || (i >= ((int)cdata->_textures.size()))) {
     return RTM_none;
   }
-  return _textures[i]._rtm_mode;
+  return cdata->_textures[i]._rtm_mode;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -325,9 +330,8 @@ set_one_shot(bool one_shot) {
 //       Access: Published
 //  Description: Returns the current setting of the one-shot flag.
 //               When this is true, the GraphicsOutput will
-//               automatically detach its texture (if it has one) and
-//               remove itself from the GraphicsEngine after it
-//               renders the next frame.
+//               automatically set itself inactive after the next
+//               frame.
 ////////////////////////////////////////////////////////////////////
 INLINE bool GraphicsOutput::
 get_one_shot() const {
@@ -487,26 +491,6 @@ clear_delete_flag() {
   _delete_flag = false;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsOutput::get_delete_flag
-//       Access: Published
-//  Description: Returns the current setting of the delete flag.  When
-//               this is true, the GraphicsOutput will automatically
-//               be removed before the beginning of the next frame by
-//               the GraphicsEngine.
-////////////////////////////////////////////////////////////////////
-INLINE bool GraphicsOutput::
-get_delete_flag() const {
-  // We only delete the window or buffer automatically when it is
-  // no longer associated with a texture.
-  for (int i=0; i<(int)_hold_textures.size(); i++) {
-    if (_hold_textures[i].is_valid_pointer()) {
-      return false;
-    }
-  }
-  return _delete_flag;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsOutput::get_sort
 //       Access: Published
@@ -816,8 +800,10 @@ INLINE void GraphicsOutput::
 determine_display_regions() const {
   // This function isn't strictly speaking const, but we pretend it is
   // because it only updates a transparent cache value.
-  if (_display_regions_stale) {
-    ((GraphicsOutput *)this)->do_determine_display_regions();
+  CDLockedReader cdata(_cycler);
+  if (cdata->_active_display_regions_stale) {
+    CDWriter cdataw(((GraphicsOutput *)this)->_cycler, cdata, false);
+    ((GraphicsOutput *)this)->do_determine_display_regions(cdataw);
   }
 }
 
@@ -830,7 +816,8 @@ determine_display_regions() const {
 ////////////////////////////////////////////////////////////////////
 INLINE void GraphicsOutput::
 win_display_regions_changed() {
-  _display_regions_stale = true;
+  CDWriter cdata(_cycler, true);
+  cdata->_active_display_regions_stale = true;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 159 - 60
panda/src/display/graphicsOutput.cxx

@@ -104,7 +104,6 @@ GraphicsOutput(GraphicsEngine *engine, GraphicsPipe *pipe,
   _child_sort = 0;
   _got_child_sort = false;
   _internal_sort_index = 0;
-  _active = true;
   _one_shot = false;
   _inverted = window_inverted;
   _red_blue_stereo = false;
@@ -146,7 +145,11 @@ GraphicsOutput(GraphicsEngine *engine, GraphicsPipe *pipe,
   _overlay_display_region = make_mono_display_region(0.0f, 1.0f, 0.0f, 1.0f);
   _overlay_display_region->set_active(false);
 
-  _display_regions_stale = false;
+  // Make sure the "active" flag is set true for pipeline stage 0.
+  {
+    CDWriter cdata(_cycler, true);
+    cdata->_active = true;
+  }
 
   // By default, each new GraphicsOutput is set up to clear color and
   // depth.
@@ -226,7 +229,6 @@ GraphicsOutput::
   }
 
   _total_display_regions.clear();
-  _active_display_regions.clear();
   _overlay_display_region = NULL;
 }
 
@@ -239,9 +241,9 @@ GraphicsOutput::
 ////////////////////////////////////////////////////////////////////
 void GraphicsOutput::
 clear_render_textures() {
-  LightMutexHolder holder(_lock);
+  CDWriter cdata(_cycler, true);
+  cdata->_textures.clear();
   throw_event("render-texture-targets-changed");
-  _textures.clear();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -294,8 +296,6 @@ add_render_texture(Texture *tex, RenderTextureMode mode,
   }
   LightMutexHolder holder(_lock);
 
-  throw_event("render-texture-targets-changed");
-
   // Create texture if necessary.
   if (tex == (Texture *)NULL) {
     tex = new Texture(get_name());
@@ -385,11 +385,14 @@ add_render_texture(Texture *tex, RenderTextureMode mode,
     tex->set_render_to_texture(true);
   }
 
+  CDWriter cdata(_cycler, true);
   RenderTexture result;
   result._texture = tex;
   result._plane = plane;
   result._rtm_mode = mode;
-  _textures.push_back(result);
+  cdata->_textures.push_back(result);
+
+  throw_event("render-texture-targets-changed");
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -424,7 +427,11 @@ setup_render_texture(Texture *tex, bool allow_bind, bool to_ram) {
 ////////////////////////////////////////////////////////////////////
 void GraphicsOutput::
 set_active(bool active) {
-  _active = active;
+  CDLockedReader cdata(_cycler);
+  if (cdata->_active != active) {
+    CDWriter cdataw(((GraphicsOutput *)this)->_cycler, cdata, true);
+    cdataw->_active = active;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -435,7 +442,12 @@ set_active(bool active) {
 ////////////////////////////////////////////////////////////////////
 bool GraphicsOutput::
 is_active() const {
-  return _active && is_valid();
+  if (!is_valid()) {
+    return false;
+  }
+
+  CDReader cdata(_cycler);
+  return cdata->_active;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -530,6 +542,27 @@ set_side_by_side_stereo(bool side_by_side_stereo,
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::get_delete_flag
+//       Access: Published
+//  Description: Returns the current setting of the delete flag.  When
+//               this is true, the GraphicsOutput will automatically
+//               be removed before the beginning of the next frame by
+//               the GraphicsEngine.
+////////////////////////////////////////////////////////////////////
+bool GraphicsOutput::
+get_delete_flag() const {
+  // We only delete the window or buffer automatically when it is
+  // no longer associated with a texture.
+  for (int i = 0; i < (int)_hold_textures.size(); i++) {
+    if (_hold_textures[i].is_valid_pointer()) {
+      return false;
+    }
+  }
+
+  return _delete_flag;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsOutput::set_sort
 //       Access: Published, Virtual
@@ -683,6 +716,9 @@ void GraphicsOutput::
 remove_all_display_regions() {
   LightMutexHolder holder(_lock);
 
+  CDWriter cdata(_cycler, true);
+  cdata->_active_display_regions_stale = true;
+
   TotalDisplayRegions::iterator dri;
   for (dri = _total_display_regions.begin();
        dri != _total_display_regions.end();
@@ -696,7 +732,6 @@ remove_all_display_regions() {
   }
   _total_display_regions.clear();
   _total_display_regions.push_back(_overlay_display_region);
-  _display_regions_stale = true;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -774,12 +809,8 @@ get_display_region(int n) const {
 int GraphicsOutput::
 get_num_active_display_regions() const {
   determine_display_regions();
-  int result;
-  {
-    LightMutexHolder holder(_lock);
-    result = _active_display_regions.size();
-  }
-  return result;
+  CDReader cdata(_cycler);
+  return cdata->_active_display_regions.size();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -794,16 +825,12 @@ get_num_active_display_regions() const {
 PT(DisplayRegion) GraphicsOutput::
 get_active_display_region(int n) const {
   determine_display_regions();
-  PT(DisplayRegion) result;
-  {
-    LightMutexHolder holder(_lock);
-    if (n >= 0 && n < (int)_active_display_regions.size()) {
-      result = _active_display_regions[n];
-    } else {
-      result = NULL;
-    }
+
+  CDReader cdata(_cycler);
+  if (n >= 0 && n < (int)cdata->_active_display_regions.size()) {
+    return cdata->_active_display_regions[n];
   }
-  return result;
+  return NULL;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -837,9 +864,7 @@ get_active_display_region(int n) const {
 //               created for some reason.
 //
 //               When you are done using the buffer, you should remove
-//               it with a call to GraphicsEngine::remove_window() (or
-//               set the one_shot flag so it removes itself after one
-//               frame).
+//               it with a call to GraphicsEngine::remove_window().
 ////////////////////////////////////////////////////////////////////
 GraphicsOutput *GraphicsOutput::
 make_texture_buffer(const string &name, int x_size, int y_size,
@@ -997,8 +1022,10 @@ get_texture_card() {
   // render-to-texture output texture.  Depth and stencil
   // textures are ignored.  The user can freely alter the
   // card's texture attrib.
-  for (int i=0; i<count_textures(); i++) {
-    Texture *texture = get_texture(i);
+  CDReader cdata(_cycler);
+  RenderTextures::const_iterator ri;
+  for (ri = cdata->_textures.begin(); ri != cdata->_textures.end(); ++ri) {
+    Texture *texture = (*ri)._texture;
     if ((texture->get_format() != Texture::F_depth_stencil)) {
       path.set_texture(texture, 0);
       break;
@@ -1204,9 +1231,11 @@ change_scenes(DisplayRegionPipelineReader *new_dr) {
     _cube_map_index = new_cube_map_index;
     _cube_map_dr = new_dr->get_object();
 
-    for (int i=0; i<count_textures(); i++) {
-      Texture *texture = get_texture(i);
-      RenderTextureMode rtm_mode = get_rtm_mode(i);
+    CDReader cdata(_cycler);
+    RenderTextures::const_iterator ri;
+    for (ri = cdata->_textures.begin(); ri != cdata->_textures.end(); ++ri) {
+      RenderTextureMode rtm_mode = (*ri)._rtm_mode;
+      Texture *texture = (*ri)._texture;
       if (rtm_mode != RTM_none) {
         if (rtm_mode == RTM_bind_or_copy) {
           // In render-to-texture mode, switch the rendering backend to
@@ -1334,7 +1363,19 @@ pixel_factor_changed() {
 ////////////////////////////////////////////////////////////////////
 void GraphicsOutput::
 prepare_for_deletion() {
-  _active = false;
+  CDWriter cdata(_cycler, true);
+  cdata->_active = false;
+
+  // If we were rendering directly to texture, we can't delete the
+  // buffer until all the textures are gone too.
+  RenderTextures::iterator ri;
+  for (ri = cdata->_textures.begin(); ri != cdata->_textures.end(); ++ri) {
+    if ((*ri)._rtm_mode == RTM_bind_or_copy) {
+      _hold_textures.push_back((*ri)._texture);
+    }
+  }
+  cdata->_textures.clear();
+
   _delete_flag = true;
 
   // We have to be sure to remove all of the display regions
@@ -1342,18 +1383,35 @@ prepare_for_deletion() {
   // up (each display region keeps a pointer to a CullResult,
   // which can hold all sorts of pointers).
   remove_all_display_regions();
+}
 
-  // If we were rendering directly to texture, we can't delete the
-  // buffer until the texture is gone too.
-  for (int i=0; i<count_textures(); i++) {
-    if (get_rtm_mode(i) == RTM_bind_or_copy) {
-      _hold_textures.push_back(get_texture(i));
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::promote_to_copy_texture
+//       Access: Protected
+//  Description: If any textures are marked RTM_bind_or_copy, change
+//               them to RTM_copy_texture.
+////////////////////////////////////////////////////////////////////
+void GraphicsOutput::
+promote_to_copy_texture() {
+  CDLockedReader cdata(_cycler);
+  RenderTextures::const_iterator ri;
+
+  bool any_bind = false;
+  for (ri = cdata->_textures.begin(); ri != cdata->_textures.end(); ++ri) {
+    if ((*ri)._rtm_mode == RTM_bind_or_copy) {
+      any_bind = true;
+      break;
+    }
+  }
+  if (any_bind) {
+    CDWriter cdataw(((GraphicsOutput *)this)->_cycler, cdata, true);
+    RenderTextures::iterator ri;
+    for (ri = cdataw->_textures.begin(); ri != cdataw->_textures.end(); ++ri) {
+      if ((*ri)._rtm_mode == RTM_bind_or_copy) {
+        (*ri)._rtm_mode = RTM_copy_texture;
+      }
     }
   }
-
-  // We have to be sure to clear the _textures pointers, though, or
-  // we'll end up holding a reference to the textures forever.
-  clear_render_textures();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1369,15 +1427,17 @@ prepare_for_deletion() {
 bool GraphicsOutput::
 copy_to_textures() {
   bool okflag = true;
-  for (int i = 0; i < count_textures(); ++i) {
-    RenderTextureMode rtm_mode = get_rtm_mode(i);
+
+  CDReader cdata(_cycler);
+  RenderTextures::const_iterator ri;
+  for (ri = cdata->_textures.begin(); ri != cdata->_textures.end(); ++ri) {
+    RenderTextureMode rtm_mode = (*ri)._rtm_mode;
     if ((rtm_mode == RTM_none) || (rtm_mode == RTM_bind_or_copy)) {
       continue;
     }
 
-    Texture *texture = get_texture(i);
+    Texture *texture = (*ri)._texture;
     PStatTimer timer(_copy_texture_pcollector);
-    nassertr(has_texture(), false);
 
     if ((rtm_mode == RTM_copy_texture)||
         (rtm_mode == RTM_copy_ram)||
@@ -1389,7 +1449,7 @@ copy_to_textures() {
         display_cat.debug()
           << "cube_map_index = " << _cube_map_index << "\n";
       }
-      int plane = get_texture_plane(i);
+      RenderTexturePlane plane = (*ri)._plane;
       RenderBuffer buffer(_gsg, DrawableRegion::get_renderbuffer_type(plane));
       if (plane == RTP_color) {
         buffer = _gsg->get_render_buffer(get_draw_buffer_type(),
@@ -1481,8 +1541,10 @@ create_texture_card_vdata(int x, int y) {
 DisplayRegion *GraphicsOutput::
 add_display_region(DisplayRegion *display_region) {
   LightMutexHolder holder(_lock);
+  CDWriter cdata(_cycler, true);
+  cdata->_active_display_regions_stale = true;
+  
   _total_display_regions.push_back(display_region);
-  _display_regions_stale = true;
 
   return display_region;
 }
@@ -1502,12 +1564,12 @@ do_remove_display_region(DisplayRegion *display_region) {
     find(_total_display_regions.begin(), _total_display_regions.end(), drp);
   if (dri != _total_display_regions.end()) {
     // Let's aggressively clean up the display region too.
+    CDWriter cdata(_cycler, true);
     display_region->cleanup();
     display_region->_window = NULL;
     _total_display_regions.erase(dri);
-    if (display_region->is_active()) {
-      _display_regions_stale = true;
-    }
+
+    cdata->_active_display_regions_stale = true;
 
     return true;
   }
@@ -1522,12 +1584,11 @@ do_remove_display_region(DisplayRegion *display_region) {
 //               the window.
 ////////////////////////////////////////////////////////////////////
 void GraphicsOutput::
-do_determine_display_regions() {
-  LightMutexHolder holder(_lock);
-  _display_regions_stale = false;
+do_determine_display_regions(GraphicsOutput::CData *cdata) {
+  cdata->_active_display_regions_stale = false;
 
-  _active_display_regions.clear();
-  _active_display_regions.reserve(_total_display_regions.size());
+  cdata->_active_display_regions.clear();
+  cdata->_active_display_regions.reserve(_total_display_regions.size());
 
   int index = 0;
   TotalDisplayRegions::const_iterator dri;
@@ -1536,7 +1597,7 @@ do_determine_display_regions() {
        ++dri) {
     DisplayRegion *display_region = (*dri);
     if (display_region->is_active()) {
-      _active_display_regions.push_back(display_region);
+      cdata->_active_display_regions.push_back(display_region);
       display_region->set_active_index(index);
       ++index;
     } else {
@@ -1544,7 +1605,7 @@ do_determine_display_regions() {
     }
   }
 
-  stable_sort(_active_display_regions.begin(), _active_display_regions.end(), IndirectLess<DisplayRegion>());
+  stable_sort(cdata->_active_display_regions.begin(), cdata->_active_display_regions.end(), IndirectLess<DisplayRegion>());
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1597,6 +1658,44 @@ parse_color_mask(const string &word) {
   return result;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::CData::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+GraphicsOutput::CData::
+CData() {
+  // The default is *not* active, so the entire pipeline stage is
+  // initially populated with inactive outputs.  Pipeline stage 0 is
+  // set to active in the constructor.
+  _active = false;
+  _active_display_regions_stale = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::CData::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+GraphicsOutput::CData::
+CData(const GraphicsOutput::CData &copy) :
+  _textures(copy._textures),
+  _active(copy._active),
+  _active_display_regions(copy._active_display_regions),
+  _active_display_regions_stale(copy._active_display_regions_stale)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::CData::make_copy
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+CycleData *GraphicsOutput::CData::
+make_copy() const {
+  return new CData(*this);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsOutput::FrameMode output operator
 //  Description:

+ 44 - 15
panda/src/display/graphicsOutput.h

@@ -35,6 +35,11 @@
 #include "pvector.h"
 #include "weakPointerTo.h"
 #include "nodePath.h"
+#include "cycleData.h"
+#include "cycleDataLockedReader.h"
+#include "cycleDataReader.h"
+#include "cycleDataWriter.h"
+#include "pipelineCycler.h"
 
 class PNMImage;
 class GraphicsEngine;
@@ -147,7 +152,7 @@ PUBLISHED:
   INLINE bool is_stereo() const;
 
   INLINE void clear_delete_flag();
-  INLINE bool get_delete_flag() const;
+  bool get_delete_flag() const;
 
   virtual void set_sort(int sort);
   INLINE int get_sort() const;
@@ -246,6 +251,7 @@ public:
 protected:
   virtual void pixel_factor_changed();
   void prepare_for_deletion();
+  void promote_to_copy_texture();
   bool copy_to_textures();
   
   INLINE void begin_frame_spam(FrameMode mode);
@@ -253,6 +259,8 @@ protected:
   INLINE void clear_cube_map_selection();
   INLINE void trigger_flip();
 
+  class CData;
+
 private:
   PT(GeomVertexData) create_texture_card_vdata(int x, int y);
   
@@ -262,17 +270,11 @@ private:
   INLINE void win_display_regions_changed();
 
   INLINE void determine_display_regions() const;
-  void do_determine_display_regions();
+  void do_determine_display_regions(CData *cdata);
 
   static unsigned int parse_color_mask(const string &word);
 
 protected:
-  class RenderTexture {
-  public:
-    PT(Texture) _texture;
-    RenderTexturePlane _plane;
-    RenderTextureMode _rtm_mode;
-  };
   PT(GraphicsStateGuardian) _gsg;
   GraphicsEngine *_engine;
   PT(GraphicsPipe) _pipe;
@@ -280,12 +282,19 @@ protected:
   FrameBufferProperties _fb_properties;
   bool _stereo;
   string _name;
-  pvector<RenderTexture> _textures;
   bool _flip_ready;
   int _cube_map_index;
   DisplayRegion *_cube_map_dr;
   PT(Geom) _texture_card;
   bool _trigger_copy;
+
+  class RenderTexture {
+  public:
+    PT(Texture) _texture;
+    RenderTexturePlane _plane;
+    RenderTextureMode _rtm_mode;
+  };
+  typedef pvector<RenderTexture> RenderTextures;
   
 private:
   int _sort;
@@ -294,7 +303,6 @@ private:
   unsigned int _internal_sort_index;
 
 protected:
-  bool _active;
   bool _one_shot;
   bool _inverted;
   bool _red_blue_stereo;
@@ -306,9 +314,9 @@ protected:
   bool _delete_flag;
 
   // These weak pointers are used to keep track of whether the
-  // buffer's bound Texture has been deleted or not.  Until they have,
-  // we don't auto-close the buffer (since that would deallocate the
-  // memory associated with the texture).
+  // buffer's bound Textures have been deleted or not.  Until they
+  // have, we don't auto-close the buffer (since that would deallocate
+  // the memory associated with the texture).
   pvector<WPT(Texture)> _hold_textures;
   
 protected:
@@ -318,8 +326,29 @@ protected:
   typedef pvector< PT(DisplayRegion) > TotalDisplayRegions;
   TotalDisplayRegions _total_display_regions;
   typedef pvector<DisplayRegion *> ActiveDisplayRegions;
-  ActiveDisplayRegions _active_display_regions;
-  bool _display_regions_stale;
+
+  // This is the data that is associated with the GraphicsOutput that
+  // needs to be cycled every frame.  Mostly we don't cycle this data,
+  // but we do cycle the textures list, and the active flag.
+  class EXPCL_PANDA_DISPLAY CData : public CycleData {
+  public:
+    CData();
+    CData(const CData &copy);
+
+    virtual CycleData *make_copy() const;
+    virtual TypeHandle get_parent_type() const {
+      return GraphicsOutput::get_class_type();
+    }
+
+    RenderTextures _textures;
+    bool _active;
+    ActiveDisplayRegions _active_display_regions;
+    bool _active_display_regions_stale;
+  };
+  PipelineCycler<CData> _cycler;
+  typedef CycleDataLockedReader<CData> CDLockedReader;
+  typedef CycleDataReader<CData> CDReader;
+  typedef CycleDataWriter<CData> CDWriter;
 
 protected:
   int _creation_flags;

+ 1 - 1
panda/src/display/graphicsWindow.cxx

@@ -184,7 +184,7 @@ request_properties(const WindowProperties &requested_properties) {
 bool GraphicsWindow::
 is_active() const {
   // Make this smarter?
-  return _active && _properties.get_open() && !_properties.get_minimized();
+  return GraphicsOutput::is_active() && _properties.get_open() && !_properties.get_minimized();
 }
 
 ////////////////////////////////////////////////////////////////////

+ 2 - 6
panda/src/display/parasiteBuffer.cxx

@@ -114,7 +114,7 @@ set_size_and_recalc(int x, int y) {
 ////////////////////////////////////////////////////////////////////
 bool ParasiteBuffer::
 is_active() const {
-  return _active && _host->is_active();
+  return GraphicsOutput::is_active() && _host->is_active();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -186,11 +186,7 @@ end_frame(FrameMode mode, Thread *current_thread) {
   }
   
   if (mode == FM_render) {
-    for (int i=0; i<count_textures(); i++) {
-      if (get_rtm_mode(i) == RTM_bind_or_copy) {
-        _textures[i]._rtm_mode = RTM_copy_texture;
-      }
-    }
+    promote_to_copy_texture();
     copy_to_textures();
     if (_one_shot) {
       prepare_for_deletion();

+ 0 - 5
panda/src/dxgsg8/wdxGraphicsBuffer8.cxx

@@ -259,8 +259,6 @@ rebuild_bitplanes() {
           (get_texture(i)->get_format() != Texture::F_depth_component)&&
           (color_tex_index < 0)) {
         color_tex_index = i;
-      } else {
-        _textures[i]._rtm_mode = RTM_copy_texture;
       }
     }
   }
@@ -424,8 +422,6 @@ select_cube_map(int cube_map_index) {
           (get_texture(i)->get_format() != Texture::F_depth_component)&&
           (color_tex_index < 0)) {
         color_tex_index = i;
-      } else {
-        _textures[i]._rtm_mode = RTM_copy_texture;
       }
     }
   }
@@ -506,7 +502,6 @@ close_buffer() {
     _depth_backing_store = NULL;
   }
 
-  _active = false;
   _cube_map_index = -1;
   _is_valid = false;
 }

+ 0 - 1
panda/src/dxgsg8/wdxGraphicsWindow8.cxx

@@ -253,7 +253,6 @@ close_window() {
 
   if (_gsg != (GraphicsStateGuardian*)NULL) {
     _gsg.clear();
-    _active = false;
   }
 
   _dxgsg->release_swap_chain(&_wcontext);

+ 0 - 1
panda/src/dxgsg9/dxVertexBufferContext9.cxx

@@ -41,7 +41,6 @@ CLP(VertexBufferContext)(CLP(GraphicsStateGuardian) *dxgsg,
 
   // We have to start with the vertex data, and work up from there in
   // order, since that's the way the FVF is defined.
-  int index;
   int n = 0;
   int num_columns = array_format->get_num_columns();
 

+ 37 - 16
panda/src/dxgsg9/wdxGraphicsBuffer9.cxx

@@ -306,14 +306,19 @@ rebuild_bitplanes() {
 
   int color_tex_index = -1;
   int depth_tex_index = -1;
-  for (int i=0; i<count_textures(); i++) {
-    if (get_rtm_mode(i) == RTM_bind_or_copy) {
-      RenderTexturePlane plane = get_texture_plane(i);
-
-      switch (plane) {
+  {
+    CDLockedReader cdata(_cycler);
+    for (size_t i = 0; i != cdata->_textures.size(); ++i) {
+      const RenderTexture &rt = cdata->_textures[i];
+      RenderTextureMode rtm_mode = rt._rtm_mode;
+      if (rtm_mode == RTM_bind_or_copy) {
+        RenderTexturePlane plane = rt._plane;
+
+        switch (plane) {
         case RTP_color:
           color_tex_index = i;
           break;
+
         case RTP_aux_rgba_0:
         case RTP_aux_rgba_1:
         case RTP_aux_rgba_2:
@@ -326,11 +331,20 @@ rebuild_bitplanes() {
         case RTP_aux_float_1:
         case RTP_aux_float_2:
         case RTP_aux_float_3:
-          _textures[i]._rtm_mode = RTM_none;
+          {
+            CDWriter cdataw(_cycler, cdata, false);
+            nassertr(cdata->_textures.size() == cdataw->_textures.size(), false);
+            cdataw->_textures[i]._rtm_mode = RTM_none;
+          }
           break;
         default:
-          _textures[i]._rtm_mode = RTM_copy_texture;
+          {
+            CDWriter cdataw(_cycler, cdata, false);
+            nassertr(cdata->_textures.size() == cdataw->_textures.size(), false);
+            cdataw->_textures[i]._rtm_mode = RTM_copy_texture;
+          }
           break;
+        }
       }                
     }
   }
@@ -591,14 +605,22 @@ select_cube_map(int cube_map_index) {
   IDirect3DSurface9 *color_surf = 0;
   int color_tex_index = -1;
 
-  for (int i=0; i<count_textures(); i++) {
-    if (get_rtm_mode(i) == RTM_bind_or_copy) {
-      if ((get_texture(i)->get_format() != Texture::F_depth_stencil)&&
-          (get_texture(i)->get_format() != Texture::F_depth_component)&&
-          (color_tex_index < 0)) {
-        color_tex_index = i;
-      } else {
-        _textures[i]._rtm_mode = RTM_copy_texture;
+  {
+    CDLockedReader cdata(_cycler);
+    for (size_t i = 0; i != cdata->_textures.size(); ++i) {
+      const RenderTexture &rt = cdata->_textures[i];
+      RenderTextureMode rtm_mode = rt._rtm_mode;
+      if (rtm_mode == RTM_bind_or_copy) {
+        Texture *tex = rt._texture;
+        if ((tex->get_format() != Texture::F_depth_stencil)&&
+            (tex->get_format() != Texture::F_depth_component)&&
+            (color_tex_index < 0)) {
+          color_tex_index = i;
+        } else {
+          CDWriter cdataw(_cycler, cdata, false);
+          nassertv(cdata->_textures.size() == cdataw->_textures.size());
+          cdataw->_textures[i]._rtm_mode = RTM_copy_texture;
+        }
       }
     }
   }
@@ -728,7 +750,6 @@ close_buffer() {
     _depth_backing_store = NULL;
   }
 
-  _active = false;
   _cube_map_index = -1;
   _is_valid = false;
 }

+ 0 - 1
panda/src/dxgsg9/wdxGraphicsWindow9.cxx

@@ -254,7 +254,6 @@ close_window() {
 
   if (_gsg != (GraphicsStateGuardian *)NULL) {
     _gsg.clear();
-    _active = false;
   }
 
   DXGraphicsStateGuardian9::set_cg_device(NULL);

+ 8 - 4
panda/src/egldisplay/eglGraphicsBuffer.cxx

@@ -88,9 +88,14 @@ begin_frame(FrameMode mode, Thread *current_thread) {
   eglgsg->reset_if_new();
 
   if (mode == FM_render) {
-    for (int i=0; i<count_textures(); i++) {
-      if (get_rtm_mode(i) == RTM_bind_or_copy) {
-        _textures[i]._rtm_mode = RTM_copy_texture;
+    CDLockedReader cdata(_cycler);
+    for (size_t i = 0; i != cdata->_textures.size(); ++i) {
+      const RenderTexture &rt = cdata->_textures[i];
+      RenderTextureMode rtm_mode = rt._rtm_mode;
+      if (rtm_mode == RTM_bind_or_copy) {
+        CDWriter cdataw(_cycler, cdata, false);
+        nassertr(cdata->_textures.size() == cdataw->_textures.size(), false);
+        cdataw->_textures[i]._rtm_mode = RTM_copy_texture;
       }
     }
     clear_cube_map_selection();
@@ -143,7 +148,6 @@ close_buffer() {
         << get_egl_error_string(eglGetError()) << "\n";
     }
     _gsg.clear();
-    _active = false;
     
     if (_pbuffer != EGL_NO_SURFACE) {
       if (!eglDestroySurface(_egl_display, _pbuffer)) {

+ 8 - 4
panda/src/egldisplay/eglGraphicsPixmap.cxx

@@ -93,9 +93,14 @@ begin_frame(FrameMode mode, Thread *current_thread) {
   eglgsg->reset_if_new();
 
   if (mode == FM_render) {
-    for (int i=0; i<count_textures(); i++) {
-      if (get_rtm_mode(i) == RTM_bind_or_copy) {
-        _textures[i]._rtm_mode = RTM_copy_texture;
+    CDLockedReader cdata(_cycler);
+    for (size_t i = 0; i != cdata->_textures.size(); ++i) {
+      const RenderTexture &rt = cdata->_textures[i];
+      RenderTextureMode rtm_mode = rt._rtm_mode;
+      if (rtm_mode == RTM_bind_or_copy) {
+        CDWriter cdataw(_cycler, cdata, false);
+        nassertr(cdata->_textures.size() == cdataw->_textures.size(), false);
+        cdataw->_textures[i]._rtm_mode = RTM_copy_texture;
       }
     }
     clear_cube_map_selection();
@@ -146,7 +151,6 @@ close_buffer() {
         << get_egl_error_string(eglGetError()) << "\n";
     }
     _gsg.clear();
-    _active = false;
   }
 
   if (_egl_surface != EGL_NO_SURFACE) {

+ 0 - 1
panda/src/egldisplay/eglGraphicsWindow.cxx

@@ -591,7 +591,6 @@ close_window() {
         << get_egl_error_string(eglGetError()) << "\n";
     }
     _gsg.clear();
-    _active = false;
   }
 
   if (_ic != (XIC)NULL) {

+ 30 - 25
panda/src/glstuff/glGraphicsBuffer_src.cxx

@@ -84,7 +84,6 @@ CLP(GraphicsBuffer)(GraphicsEngine *engine, GraphicsPipe *pipe,
   }
 
   _shared_depth_buffer = 0;
-  report_my_gl_errors();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -287,29 +286,37 @@ rebuild_bitplanes() {
 
     // Sort the textures list into appropriate slots.
 
-    for (int i=0; i<count_textures(); i++) {
-      if (get_rtm_mode(i) != RTM_bind_or_copy) {
-        continue;
-      }
-      Texture *tex = get_texture(i);
-      RenderTexturePlane plane = get_texture_plane(i);
-
-      // If it's a not a 2D texture or a cube map, punt it.
-      if ((tex->get_texture_type() != Texture::TT_2d_texture)&&
-          (tex->get_texture_type() != Texture::TT_cube_map)) {
-        _textures[i]._rtm_mode = RTM_copy_texture;
-        continue;
-      }
-      // If I can't find an appropriate slot, or if there's
-      // already a texture bound to this slot, then punt
-      // this texture.
-
-      if (attach[plane]) {
-        _textures[i]._rtm_mode = RTM_copy_texture;
-        continue;
+    {
+      CDLockedReader cdata(_cycler);
+      for (size_t i = 0; i != cdata->_textures.size(); ++i) {
+        const RenderTexture &rt = cdata->_textures[i];
+        RenderTextureMode rtm_mode = rt._rtm_mode;
+        if (rtm_mode != RTM_bind_or_copy) {
+          continue;
+        }
+        Texture *tex = rt._texture;
+        RenderTexturePlane plane = rt._plane;
+
+        // If it's a not a 2D texture or a cube map, punt it.
+        if ((tex->get_texture_type() != Texture::TT_2d_texture)&&
+            (tex->get_texture_type() != Texture::TT_cube_map)) {
+          CDWriter cdataw(_cycler, cdata, false);
+          nassertv(cdata->_textures.size() == cdataw->_textures.size());
+          cdataw->_textures[i]._rtm_mode = RTM_copy_texture;
+          continue;
+        }
+        // If I can't find an appropriate slot, or if there's
+        // already a texture bound to this slot, then punt
+        // this texture.
+        if (attach[plane]) {
+          CDWriter cdataw(_cycler, cdata, false);
+          nassertv(cdata->_textures.size() == cdataw->_textures.size());
+          cdataw->_textures[i]._rtm_mode = RTM_copy_texture;
+          continue;
+        }
+        // Assign the texture to this slot.
+        attach[plane] = tex;
       }
-      // Assign the texture to this slot.
-      attach[plane] = tex;
     }
 
     // Having both a depth texture and a depth_stencil texture is invalid: depth_stencil implies
@@ -1019,7 +1026,6 @@ close_buffer() {
   check_host_valid();
   report_my_gl_errors();
 
-  _active = false;
   if (_gsg == 0) {
     return;
   }
@@ -1200,7 +1206,6 @@ void CLP(GraphicsBuffer)::
 check_host_valid() {
   if ((_host == 0)||(!_host->is_valid())) {
     _is_valid = false;
-    _active = false;
     _gsg.clear();
     _host.clear();
   }

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

@@ -9778,7 +9778,7 @@ get_supports_cg_profile(const string &name) const {
     GLCAT.error() << name <<", unknown Cg-profile\n";
     return false;
   }
-  return cgGLIsProfileSupported(profile);
+  return (cgGLIsProfileSupported(profile) != 0);
 #endif
 }
 

+ 0 - 1
panda/src/glstuff/glShaderContext_src.cxx

@@ -288,7 +288,6 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
       }
       delete[] param_name;
       
-      int attrib_idx = 0;
       // Now we've processed the uniforms, we'll process the attribs.
       gsg->_glGetProgramiv(_glsl_program, GL_ACTIVE_ATTRIBUTES, &param_count);
       gsg->_glGetProgramiv(_glsl_program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &param_maxlength);

+ 8 - 4
panda/src/glxdisplay/glxGraphicsBuffer.cxx

@@ -88,9 +88,14 @@ begin_frame(FrameMode mode, Thread *current_thread) {
   glxgsg->reset_if_new();
 
   if (mode == FM_render) {
-    for (int i=0; i<count_textures(); i++) {
-      if (get_rtm_mode(i) == RTM_bind_or_copy) {
-        _textures[i]._rtm_mode = RTM_copy_texture;
+    CDLockedReader cdata(_cycler);
+    for (size_t i = 0; i != cdata->_textures.size(); ++i) {
+      const RenderTexture &rt = cdata->_textures[i];
+      RenderTextureMode rtm_mode = rt._rtm_mode;
+      if (rtm_mode == RTM_bind_or_copy) {
+        CDWriter cdataw(_cycler, cdata, false);
+        nassertr(cdata->_textures.size() == cdataw->_textures.size(), false);
+        cdataw->_textures[i]._rtm_mode = RTM_copy_texture;
       }
     }
     clear_cube_map_selection();
@@ -146,7 +151,6 @@ close_buffer() {
     }
     
     _gsg.clear();
-    _active = false;
   }
 
   _pbuffer = None;

+ 8 - 4
panda/src/glxdisplay/glxGraphicsPixmap.cxx

@@ -91,9 +91,14 @@ begin_frame(FrameMode mode, Thread *current_thread) {
   glxgsg->reset_if_new();
 
   if (mode == FM_render) {
-    for (int i=0; i<count_textures(); i++) {
-      if (get_rtm_mode(i) == RTM_bind_or_copy) {
-        _textures[i]._rtm_mode = RTM_copy_texture;
+    CDLockedReader cdata(_cycler);
+    for (size_t i = 0; i != cdata->_textures.size(); ++i) {
+      const RenderTexture &rt = cdata->_textures[i];
+      RenderTextureMode rtm_mode = rt._rtm_mode;
+      if (rtm_mode == RTM_bind_or_copy) {
+        CDWriter cdataw(_cycler, cdata, false);
+        nassertr(cdata->_textures.size() == cdataw->_textures.size(), false);
+        cdataw->_textures[i]._rtm_mode = RTM_copy_texture;
       }
     }
     clear_cube_map_selection();
@@ -141,7 +146,6 @@ close_buffer() {
   if (_gsg != (GraphicsStateGuardian *)NULL) {
     glXMakeCurrent(_display, None, NULL);
     _gsg.clear();
-    _active = false;
   }
 
   if (_glx_pixmap != None) {

+ 0 - 1
panda/src/glxdisplay/glxGraphicsWindow.cxx

@@ -143,7 +143,6 @@ close_window() {
   if (_gsg != (GraphicsStateGuardian *)NULL) {
     glXMakeCurrent(_display, None, NULL);
     _gsg.clear();
-    _active = false;
   }
   
   x11GraphicsWindow::close_window();

+ 2 - 5
panda/src/gobj/config_gobj.cxx

@@ -128,13 +128,10 @@ ConfigVariableBool driver_compress_textures
           "of this setting."));
 
 ConfigVariableBool driver_generate_mipmaps
-("driver-generate-mipmaps", false,
+("driver-generate-mipmaps", true,
  PRC_DESC("Set this true to use the hardware to generate mipmaps "
           "automatically in all cases, if supported.  Set it false "
-          "to generate mipmaps in software when possible.  This is "
-          "false by default because some drivers (Intel) seem to do a "
-          "poor job of generating mipmaps when needed; also, generating "
-          "mipmaps in software may allow smoother texture loads."));
+          "to generate mipmaps in software when possible."));
 
 ConfigVariableBool vertex_buffers
 ("vertex-buffers", true,

+ 8 - 4
panda/src/osxdisplay/osxGraphicsBuffer.cxx

@@ -89,9 +89,14 @@ begin_frame(FrameMode mode, Thread *current_thread) {
   osxgsg->reset_if_new();
 
   if (mode == FM_render) {
-    for (int i=0; i<count_textures(); i++) {
-      if (get_rtm_mode(i) == RTM_bind_or_copy) {
-        _textures[i]._rtm_mode = RTM_copy_texture;
+    CDLockedReader cdata(_cycler);
+    for (size_t i = 0; i != cdata->_textures.size(); ++i) {
+      const RenderTexture &rt = cdata->_textures[i];
+      RenderTextureMode rtm_mode = rt._rtm_mode;
+      if (rtm_mode == RTM_bind_or_copy) {
+        CDWriter cdataw(_cycler, cdata, false);
+        nassertr(cdata->_textures.size() == cdataw->_textures.size(), false);
+        cdataw->_textures[i]._rtm_mode = RTM_copy_texture;
       }
     }
     clear_cube_map_selection();
@@ -138,7 +143,6 @@ close_buffer() {
   if (_gsg != (GraphicsStateGuardian *)NULL) {
     //    aglSetPBuffer(osxgsg->get_context(), _pbuffer, 0, 0, 0);
     _gsg.clear();
-    _active = false;
   }
   if (_pbuffer != NULL) {
     aglDestroyPBuffer(_pbuffer);

+ 1 - 2
panda/src/osxdisplay/osxGraphicsWindow.mm

@@ -995,8 +995,7 @@ close_window() {
 
   release_system_resources(false);
   _gsg.clear();
-  _active = false;
-  GraphicsWindow::close_window();
+ GraphicsWindow::close_window();
 }
 
 //////////////////////////////////////////////////////////

+ 0 - 1
panda/src/tinydisplay/tinyGraphicsBuffer.cxx

@@ -115,7 +115,6 @@ close_buffer() {
     DCAST_INTO_V(tinygsg, _gsg);
     tinygsg->_current_frame_buffer = NULL;
     _gsg.clear();
-    _active = false;
   }
 
   _is_valid = false;

+ 5 - 7
panda/src/tinydisplay/tinyOsxGraphicsWindow.mm

@@ -490,9 +490,9 @@ TinyOsxGraphicsWindow::TinyOsxGraphicsWindow(GraphicsEngine *engine, GraphicsPip
   _is_fullscreen(false),
   _pending_icon(NULL),
   _current_icon(NULL),
-  _originalMode(NULL),
-  _ID(id_seed++) {
-  GraphicsWindowInputDevice device =
+  _ID(id_seed++),
+  _originalMode(NULL) {
+ GraphicsWindowInputDevice device =
     GraphicsWindowInputDevice::pointer_and_keyboard(this, "keyboard/mouse");
   _input_devices.push_back(device);
   _input_devices[0].set_pointer_in_window(0, 0);
@@ -753,8 +753,7 @@ void TinyOsxGraphicsWindow::close_window() {
 
   ReleaseSystemResources();
   _gsg.clear();
-  _active = false;
-  GraphicsWindow::close_window();
+ GraphicsWindow::close_window();
 }
 
 //////////////////////////////////////////////////////////
@@ -1248,8 +1247,7 @@ void TinyOsxGraphicsWindow::SystemPointToLocalPoint(Point &qdGlobalPoint) {
   WindowRef            window = NULL;
   OSStatus            result = eventNotHandledErr;
   UInt32                 kind = GetEventKind (event);
-  EventMouseButton    button = 0;
-  Point qdGlobalPoint = {0, 0};
+ Point qdGlobalPoint = {0, 0};
   UInt32                modifiers = 0;
   Rect                 rectPort;
   SInt32 this_wheel_delta;

+ 0 - 1
panda/src/tinydisplay/tinyWinGraphicsWindow.cxx

@@ -184,7 +184,6 @@ close_window() {
     DCAST_INTO_V(tinygsg, _gsg);
     tinygsg->_current_frame_buffer = NULL;
     _gsg.clear();
-    _active = false;
   }
 
   ReleaseDC(_hWnd, _hdc);

+ 0 - 1
panda/src/tinydisplay/tinyXGraphicsWindow.cxx

@@ -413,7 +413,6 @@ close_window() {
     DCAST_INTO_V(tinygsg, _gsg);
     tinygsg->_current_frame_buffer = NULL;
     _gsg.clear();
-    _active = false;
   }
   
   x11GraphicsWindow::close_window();

+ 19 - 10
panda/src/wgldisplay/wglGraphicsBuffer.cxx

@@ -91,11 +91,15 @@ begin_frame(FrameMode mode, Thread *current_thread) {
                                     &_make_current_pcollector);
   
   if (mode == FM_render) {
-    for (int i=0; i<count_textures(); i++) {
-      if (get_texture_plane(i) != RTP_color) {
-        if (get_rtm_mode(i) == RTM_bind_or_copy) {
-          _textures[i]._rtm_mode = RTM_copy_texture;
-        }
+    CDLockedReader cdata(_cycler);
+    for (size_t i = 0; i != cdata->_textures.size(); ++i) {
+      const RenderTexture &rt = cdata->_textures[i];
+      RenderTextureMode rtm_mode = rt._rtm_mode;
+      RenderTexturePlane plane = rt._plane;
+      if (rtm_mode == RTM_bind_or_copy && plane != RTP_color) {
+        CDWriter cdataw(_cycler, cdata, false);
+        nassertr(cdata->_textures.size() == cdataw->_textures.size(), false);
+        cdataw->_textures[i]._rtm_mode = RTM_copy_texture;
       }
     }
     clear_cube_map_selection();
@@ -148,15 +152,19 @@ bind_texture_to_pbuffer() {
   // the framebuffer.  All others must be marked RTM_copy_to_texture.
 
   int tex_index = -1;
-  for (int i=0; i<count_textures(); i++) {
-    if (get_texture_plane(i) == RTP_color) {
+  CDLockedReader cdata(_cycler);
+  for (size_t i = 0; i != cdata->_textures.size(); ++i) {
+    const RenderTexture &rt = cdata->_textures[i];
+    RenderTexturePlane plane = rt._plane;
+    if (plane == RTP_color) {
       tex_index = i;
       break;
     }
   }
 
   if (tex_index >= 0) {
-    Texture *tex = get_texture(tex_index);
+    const RenderTexture &rt = cdata->_textures[tex_index];
+    Texture *tex = rt._texture;
     if ((_pbuffer_bound != 0)&&(_pbuffer_bound != tex)) {
       _pbuffer_bound->release(wglgsg->get_prepared_objects());
       _pbuffer_bound = 0;
@@ -174,7 +182,9 @@ bind_texture_to_pbuffer() {
     CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
     GLenum target = wglgsg->get_texture_target(tex->get_texture_type());
     if (target == GL_NONE) {
-      _textures[tex_index]._rtm_mode = RTM_copy_texture;
+      CDWriter cdataw(_cycler, cdata, false);
+      nassertv(cdata->_textures.size() == cdataw->_textures.size());
+      cdataw->_textures[tex_index]._rtm_mode = RTM_copy_texture;
       return;
     }
     GLP(BindTexture)(target, gtc->_index);
@@ -259,7 +269,6 @@ close_buffer() {
     DCAST_INTO_V(wglgsg, _gsg);
 
     _gsg.clear();
-    _active = false;
   }
   
   release_pbuffer();

+ 0 - 3
panda/src/wgldisplay/wglGraphicsPipe.cxx

@@ -213,7 +213,6 @@ make_output(const string &name,
       if ((fb_prop.get_aux_rgba() > 0)||
           (fb_prop.get_aux_rgba() > 0)||
           (fb_prop.get_aux_float() > 0)) {
-        cerr << "b\n";
         return NULL;
       }
     }
@@ -225,10 +224,8 @@ make_output(const string &name,
         (wglgsg->pfnum_supports_pbuffer()) &&
         (wglgsg->get_fb_properties().subsumes(fb_prop))&&
         (wglgsg->get_fb_properties().is_single_buffered())) {
-      cerr << "c\n";
       precertify = true;
     }
-    cerr << "d\n";
     return new wglGraphicsBuffer(engine, this, name, fb_prop, win_prop,
                                  flags, gsg, host);
   }

+ 0 - 1
panda/src/wgldisplay/wglGraphicsWindow.cxx

@@ -186,7 +186,6 @@ close_window() {
   if (_gsg != (GraphicsStateGuardian *)NULL) {
     wglGraphicsPipe::wgl_make_current(_hdc, NULL, &_make_current_pcollector);
     _gsg.clear();
-    _active = false;
   }
   ReleaseDC(_hWnd, _hdc);
   _hdc = (HDC)0;

+ 0 - 1
panda/src/x11display/x11GraphicsWindow.cxx

@@ -759,7 +759,6 @@ void x11GraphicsWindow::
 close_window() {
   if (_gsg != (GraphicsStateGuardian *)NULL) {
     _gsg.clear();
-    _active = false;
   }
   
   if (_ic != (XIC)NULL) {