Ver código fonte

Overhaul stereo FBOs in Panda making it more reliable, fix MRT bugs, disable auto-GLSL profile choosing on AMD, add max_color_targets (not yet implemented)

rdb 11 anos atrás
pai
commit
d792c93026
34 arquivos alterados com 325 adições e 256 exclusões
  1. 11 0
      panda/src/display/config_display.cxx
  2. 1 0
      panda/src/display/config_display.h
  3. 1 28
      panda/src/display/displayRegion.I
  4. 4 7
      panda/src/display/displayRegion.cxx
  5. 1 4
      panda/src/display/displayRegion.h
  6. 1 2
      panda/src/display/graphicsOutput.I
  7. 63 35
      panda/src/display/graphicsOutput.cxx
  8. 1 1
      panda/src/display/graphicsOutput.h
  9. 26 3
      panda/src/display/graphicsStateGuardian.I
  10. 7 6
      panda/src/display/graphicsStateGuardian.cxx
  11. 4 3
      panda/src/display/graphicsStateGuardian.h
  12. 16 8
      panda/src/display/stereoDisplayRegion.cxx
  13. 1 1
      panda/src/display/stereoDisplayRegion.h
  14. 14 12
      panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx
  15. 8 4
      panda/src/dxgsg8/dxGraphicsStateGuardian8.h
  16. 5 1
      panda/src/dxgsg8/dxTextureContext8.cxx
  17. 1 1
      panda/src/dxgsg8/dxTextureContext8.h
  18. 1 1
      panda/src/dxgsg8/wdxGraphicsBuffer8.cxx
  19. 2 2
      panda/src/dxgsg8/wdxGraphicsBuffer8.h
  20. 12 11
      panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx
  21. 8 4
      panda/src/dxgsg9/dxGraphicsStateGuardian9.h
  22. 5 1
      panda/src/dxgsg9/dxTextureContext9.cxx
  23. 1 1
      panda/src/dxgsg9/dxTextureContext9.h
  24. 1 1
      panda/src/dxgsg9/wdxGraphicsBuffer9.cxx
  25. 2 2
      panda/src/dxgsg9/wdxGraphicsBuffer9.h
  26. 56 48
      panda/src/glstuff/glGraphicsBuffer_src.cxx
  27. 2 3
      panda/src/glstuff/glGraphicsBuffer_src.h
  28. 55 45
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  29. 2 3
      panda/src/glstuff/glGraphicsStateGuardian_src.h
  30. 3 3
      panda/src/gsgbase/graphicsStateGuardianBase.h
  31. 6 11
      panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx
  32. 2 2
      panda/src/tinydisplay/tinyGraphicsStateGuardian.h
  33. 1 1
      panda/src/wgldisplay/wglGraphicsBuffer.cxx
  34. 1 1
      panda/src/wgldisplay/wglGraphicsBuffer.h

+ 11 - 0
panda/src/display/config_display.cxx

@@ -172,6 +172,17 @@ ConfigVariableInt max_texture_stages
           "this number of texture stages simultaneously, regardless of "
           "what the GSG says it can do."));
 
+ConfigVariableInt max_color_targets
+("max-color-targets", -1,
+ PRC_DESC("Set this to a positive integer to limit the number of "
+          "color targets reported by the GSG.  This can be used to limit "
+          "the amount of render targets Panda will attempt to use.  "
+          "If this is zero or less, the GSG will report its honest number "
+          "of color targets, allowing Panda the full use of the graphics "
+          "card; if it is 1 or more, then Panda will never allow more than "
+          "this number of color targets simultaneously, regardless of "
+          "what the GSG says it can do."));
+
 ConfigVariableBool support_render_texture
 ("support-render-texture", true,
  PRC_DESC("Set this true allow use of the render-to-a-texture feature, if it "

+ 1 - 0
panda/src/display/config_display.h

@@ -52,6 +52,7 @@ extern EXPCL_PANDA_DISPLAY ConfigVariableBool force_parasite_buffer;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool prefer_single_buffer;
 
 extern EXPCL_PANDA_DISPLAY ConfigVariableInt max_texture_stages;
+extern EXPCL_PANDA_DISPLAY ConfigVariableInt max_color_targets;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool support_render_texture;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool support_rescale_normal;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool support_stencil;

+ 1 - 28
panda/src/display/displayRegion.I

@@ -245,7 +245,7 @@ get_texture_reload_priority() const {
 ////////////////////////////////////////////////////////////////////
 INLINE void DisplayRegion::
 set_cube_map_index(int cube_map_index) {
-  set_target_tex_page(cube_map_index, 0);
+  set_target_tex_page(cube_map_index);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -262,20 +262,6 @@ get_target_tex_page() const {
   return cdata->_target_tex_page;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: DisplayRegion::get_target_tex_view
-//       Access: Published
-//  Description: Returns the target view number associated with this
-//               particular DisplayRegion, or -1 if it is not
-//               associated with a view.  See
-//               set_target_tex_page().
-////////////////////////////////////////////////////////////////////
-INLINE int DisplayRegion::
-get_target_tex_view() const {
-  CDReader cdata(_cycler);
-  return cdata->_target_tex_view;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: DisplayRegion::set_cull_callback
 //       Access: Published
@@ -812,19 +798,6 @@ get_target_tex_page() const {
   return _cdata->_target_tex_page;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: DisplayRegionPipelineReader::get_target_tex_view
-//       Access: Published
-//  Description: Returns the target view number associated with this
-//               particular DisplayRegion, or -1 if it is not
-//               associated with a view.  See
-//               set_target_tex_page().
-////////////////////////////////////////////////////////////////////
-INLINE int DisplayRegionPipelineReader::
-get_target_tex_view() const {
-  return _cdata->_target_tex_view;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: DisplayRegionPipelineReader::get_draw_callback
 //       Access: Published

+ 4 - 7
panda/src/display/displayRegion.cxx

@@ -404,12 +404,11 @@ get_cull_traverser() {
 //               and/or stereo textures.
 ////////////////////////////////////////////////////////////////////
 void DisplayRegion::
-set_target_tex_page(int page, int view) {
+set_target_tex_page(int page) {
   int pipeline_stage = Thread::get_current_pipeline_stage();
   nassertv(pipeline_stage == 0);
   CDWriter cdata(_cycler);
   cdata->_target_tex_page = page;
-  cdata->_target_tex_view = view;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -587,7 +586,7 @@ get_screenshot() {
   
   RenderBuffer buffer = gsg->get_render_buffer(get_screenshot_buffer_type(),
                                                _window->get_fb_properties());
-  if (!gsg->framebuffer_copy_to_ram(tex, -1, this, buffer)) {
+  if (!gsg->framebuffer_copy_to_ram(tex, 0, -1, this, buffer)) {
     return NULL;
   }
   
@@ -823,8 +822,7 @@ CData() :
   _sort(0),
   _stereo_channel(Lens::SC_mono),
   _tex_view_offset(0),
-  _target_tex_page(-1),
-  _target_tex_view(-1)
+  _target_tex_page(-1)
 {
 }
 
@@ -849,8 +847,7 @@ CData(const DisplayRegion::CData &copy) :
   _sort(copy._sort),
   _stereo_channel(copy._stereo_channel),
   _tex_view_offset(copy._tex_view_offset),
-  _target_tex_page(copy._target_tex_page),
-  _target_tex_view(copy._target_tex_view)
+  _target_tex_page(copy._target_tex_page)
 {
 }
 

+ 1 - 4
panda/src/display/displayRegion.h

@@ -112,9 +112,8 @@ PUBLISHED:
   CullTraverser *get_cull_traverser();
 
   INLINE void set_cube_map_index(int cube_map_index);
-  virtual void set_target_tex_page(int page, int view);
+  virtual void set_target_tex_page(int page);
   INLINE int get_target_tex_page() const;
-  INLINE int get_target_tex_view() const;
 
   INLINE void set_cull_callback(CallbackObject *object);
   INLINE void clear_cull_callback();
@@ -213,7 +212,6 @@ private:
     Lens::StereoChannel _stereo_channel;
     int _tex_view_offset;
     int _target_tex_page;
-    int _target_tex_view;
 
     PT(CallbackObject) _cull_callback;
     PT(CallbackObject) _draw_callback;
@@ -312,7 +310,6 @@ public:
   INLINE int get_tex_view_offset();
   INLINE bool get_clear_depth_between_eyes() const;
   INLINE int get_target_tex_page() const;
-  INLINE int get_target_tex_view() const;
   INLINE CallbackObject *get_draw_callback() const;
 
   INLINE void get_pixels(int &pl, int &pr, int &pb, int &pt) const;

+ 1 - 2
panda/src/display/graphicsOutput.I

@@ -863,12 +863,11 @@ end_frame_spam(FrameMode mode) {
 //     Function: GraphicsOutput::clear_cube_map_selection
 //       Access: Public
 //  Description: Clear the variables that select a cube-map face (or
-//               other multipage or multiview texture face).
+//               other multipage texture face).
 ////////////////////////////////////////////////////////////////////
 INLINE void GraphicsOutput::
 clear_cube_map_selection() {
   _target_tex_page = -1;
-  _target_tex_view = -1;
   _prev_page_dr = NULL;
 }
 

+ 63 - 35
panda/src/display/graphicsOutput.cxx

@@ -107,7 +107,6 @@ GraphicsOutput(GraphicsEngine *engine, GraphicsPipe *pipe,
   _is_valid = false;
   _flip_ready = false;
   _target_tex_page = -1;
-  _target_tex_view = -1;
   _prev_page_dr = NULL;
   _sort = 0;
   _child_sort = 0;
@@ -373,6 +372,12 @@ add_render_texture(Texture *tex, RenderTextureMode mode,
   // which has system-imposed restrictions on size).
   tex->set_size_padded(get_x_size(), get_y_size(), tex->get_z_size());
 
+  if (_fb_properties.is_stereo() && plane == RTP_color) {
+    if (tex->get_num_views() < 2) {
+      tex->set_num_views(2);
+    }
+  }
+
   if (!support_render_texture || !get_supports_render_texture()) {
     // Binding is not supported or it is disabled, so just fall back
     // to copy instead.
@@ -1069,7 +1074,7 @@ make_cube_map(const string &name, int size, NodePath &camera_rig,
     DisplayRegion *dr;
     dr = buffer->make_display_region();
 
-    dr->set_target_tex_page(i, 0);
+    dr->set_target_tex_page(i);
     dr->copy_clear_settings(*this);
     dr->set_camera(camera_np);
   }
@@ -1342,38 +1347,34 @@ end_frame(FrameMode mode, Thread *current_thread) {
 void GraphicsOutput::
 change_scenes(DisplayRegionPipelineReader *new_dr) {
   int new_target_tex_page = new_dr->get_target_tex_page();
-  int new_target_tex_view = new_dr->get_target_tex_view();
-  if ((new_target_tex_page != -1 && new_target_tex_page != _target_tex_page) ||
-      new_target_tex_view != _target_tex_view) {
+
+  if (new_target_tex_page != -1 && new_target_tex_page != _target_tex_page) {
+
+    if (new_target_tex_page == -1) {
+      new_target_tex_page = 0;
+    }
     int old_target_tex_page = _target_tex_page;
-    int old_target_tex_view = _target_tex_view;
     DisplayRegion *old_page_dr = _prev_page_dr;
     _target_tex_page = new_target_tex_page;
-    _target_tex_view = new_target_tex_view;
     _prev_page_dr = new_dr->get_object();
 
     CDReader cdata(_cycler);
     RenderTextures::const_iterator ri;
     for (ri = cdata->_textures.begin(); ri != cdata->_textures.end(); ++ri) {
       RenderTextureMode rtm_mode = (*ri)._rtm_mode;
+      RenderTexturePlane plane = (*ri)._plane;
       Texture *texture = (*ri)._texture;
       if (rtm_mode != RTM_none) {
         if (rtm_mode == RTM_bind_or_copy || rtm_mode == RTM_bind_layered) {
           // In render-to-texture mode, switch the rendering backend
           // to the new page, so that the subsequent frame will be
           // rendered to the correct page.
-          select_target_tex_page(_target_tex_page, _target_tex_view);
+          select_target_tex_page(_target_tex_page);
 
         } else if (old_target_tex_page != -1) {
           // In copy-to-texture mode, copy the just-rendered framebuffer
           // to the old texture page.
 
-          // TODO: we should probably pass the view parameter into
-          // framebuffer_copy_to_xxx(), as we do the page parameter.
-          // Instead these methods draw the view parameter from
-          // dr->get_target_tex_view(), which is not altogether wrong
-          // but is a strange approach.
-
           nassertv(old_page_dr != (DisplayRegion *)NULL);
           if (display_cat.is_debug()) {
             display_cat.debug()
@@ -1383,12 +1384,31 @@ change_scenes(DisplayRegionPipelineReader *new_dr) {
           }
           RenderBuffer buffer = _gsg->get_render_buffer(get_draw_buffer_type(),
                                                         get_fb_properties());
-          if (rtm_mode == RTM_copy_ram) {
-            _gsg->framebuffer_copy_to_ram(texture, old_target_tex_page,
-                                          old_page_dr, buffer);
+
+          if (plane == RTP_color && _fb_properties.is_stereo()) {
+            // We've got two texture views to copy.
+            RenderBuffer left(_gsg, buffer._buffer_type & ~RenderBuffer::T_right);
+            RenderBuffer right(_gsg, buffer._buffer_type & ~RenderBuffer::T_left);
+
+            if (rtm_mode == RTM_copy_ram) {
+              _gsg->framebuffer_copy_to_ram(texture, 0, old_target_tex_page,
+                                            old_page_dr, left);
+              _gsg->framebuffer_copy_to_ram(texture, 1, old_target_tex_page,
+                                            old_page_dr, right);
+            } else {
+              _gsg->framebuffer_copy_to_texture(texture, 0, old_target_tex_page,
+                                                old_page_dr, left);
+              _gsg->framebuffer_copy_to_texture(texture, 1, old_target_tex_page,
+                                                old_page_dr, right);
+            }
           } else {
-            _gsg->framebuffer_copy_to_texture(texture, old_target_tex_page,
-                                              old_page_dr, buffer);
+            if (rtm_mode == RTM_copy_ram) {
+              _gsg->framebuffer_copy_to_ram(texture, 0, old_target_tex_page,
+                                            old_page_dr, buffer);
+            } else {
+              _gsg->framebuffer_copy_to_texture(texture, 0, old_target_tex_page,
+                                                old_page_dr, buffer);
+            }
           }
         }
       }
@@ -1402,12 +1422,11 @@ change_scenes(DisplayRegionPipelineReader *new_dr) {
 //  Description: Called internally when the window is in
 //               render-to-a-texture mode and we are in the process of
 //               rendering the six faces of a cube map, or any other
-//               multi-page and/or multi-view texture.  This should do
-//               whatever needs to be done to switch the buffer to the
-//               indicated page and view.
+//               multi-page texture.  This should do whatever needs
+//               to be done to switch the buffer to the indicated page.
 ////////////////////////////////////////////////////////////////////
 void GraphicsOutput::
-select_target_tex_page(int, int) {
+select_target_tex_page(int) {
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1588,25 +1607,34 @@ copy_to_textures() {
       }
 
       bool copied = false;
+      DisplayRegion *dr = _overlay_display_region;
       if (_prev_page_dr != (DisplayRegion *)NULL) {
+        dr = _prev_page_dr;
+      }
+
+      if (plane == RTP_color && _fb_properties.is_stereo()) {
+        // We've got two texture views to copy.
+        RenderBuffer left(_gsg, buffer._buffer_type & ~RenderBuffer::T_right);
+        RenderBuffer right(_gsg, buffer._buffer_type & ~RenderBuffer::T_left);
+
         if ((rtm_mode == RTM_copy_ram)||(rtm_mode == RTM_triggered_copy_ram)) {
-          copied =
-            _gsg->framebuffer_copy_to_ram(texture, _target_tex_page,
-                                          _prev_page_dr, buffer);
+          copied = _gsg->framebuffer_copy_to_ram(texture, 0, _target_tex_page,
+                                                 dr, left);
+          copied = _gsg->framebuffer_copy_to_ram(texture, 1, _target_tex_page,
+                                                 dr, right) && copied;
         } else {
-          copied =
-            _gsg->framebuffer_copy_to_texture(texture, _target_tex_page,
-                                              _prev_page_dr, buffer);
+          copied = _gsg->framebuffer_copy_to_texture(texture, 0, _target_tex_page,
+                                                     dr, left);
+          copied = _gsg->framebuffer_copy_to_texture(texture, 1, _target_tex_page,
+                                                     dr, right) && copied;
         }
       } else {
         if ((rtm_mode == RTM_copy_ram)||(rtm_mode == RTM_triggered_copy_ram)) {
-          copied =
-            _gsg->framebuffer_copy_to_ram(texture, _target_tex_page,
-                                          _overlay_display_region, buffer);
+          copied = _gsg->framebuffer_copy_to_ram(texture, 0, _target_tex_page,
+                                                 dr, buffer);
         } else {
-          copied =
-            _gsg->framebuffer_copy_to_texture(texture, _target_tex_page,
-                                              _overlay_display_region, buffer);
+          copied = _gsg->framebuffer_copy_to_texture(texture, 0, _target_tex_page,
+                                                     dr, buffer);
         }
       }
       if (!copied) {

+ 1 - 1
panda/src/display/graphicsOutput.h

@@ -260,7 +260,7 @@ public:
   virtual void end_frame(FrameMode mode, Thread *current_thread);
 
   void change_scenes(DisplayRegionPipelineReader *new_dr);
-  virtual void select_target_tex_page(int page, int view);
+  virtual void select_target_tex_page(int page);
 
   // These methods will be called within the app (main) thread.
   virtual void begin_flip();

+ 26 - 3
panda/src/display/graphicsStateGuardian.I

@@ -702,15 +702,38 @@ get_supports_geometry_instancing() const {
   return _supports_geometry_instancing;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::get_max_color_targets
+//       Access: Published
+//  Description: Returns the maximum number of simultaneous color
+//               textures that may be attached for render-to-texture,
+//               as supported by this particular GSG.  If you exceed
+//               this number, the lowest-priority render targets will
+//               not be applied.  Use RenderTarget::set_priority() to
+//               adjust the relative importance of the different
+//               render targets.
+//
+//               The value returned may not be meaningful until after
+//               the graphics context has been fully created (e.g. the
+//               window has been opened).
+////////////////////////////////////////////////////////////////////
+INLINE int GraphicsStateGuardian::
+get_max_color_targets() const {
+  if (max_color_targets > 0) {
+    return min(_max_color_targets, (int)max_color_targets);
+  }
+  return _max_color_targets;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::get_maximum_simultaneous_render_targets
 //       Access: Published
-//  Description: Returns the maximum simultaneous render targets 
-//               supported.
+//  Description: Deprecated.  Use get_max_color_targets() instead,
+//               which returns the exact same value.
 ////////////////////////////////////////////////////////////////////
 INLINE int GraphicsStateGuardian::
 get_maximum_simultaneous_render_targets() const {
-  return _maximum_simultaneous_render_targets;
+  return get_max_color_targets();
 }
 
 ////////////////////////////////////////////////////////////////////

+ 7 - 6
panda/src/display/graphicsStateGuardian.cxx

@@ -218,7 +218,8 @@ GraphicsStateGuardian(CoordinateSystem internal_coordinate_system,
   _supports_two_sided_stencil = false;
   _supports_geometry_instancing = false;
 
-  _maximum_simultaneous_render_targets = 1;
+  // Assume a maximum of 1 render target in absence of MRT.
+  _max_color_targets = 1;
 
   _supported_geom_rendering = 0;
 
@@ -1317,14 +1318,14 @@ prepare_display_region(DisplayRegionPipelineReader *dr) {
   case Lens::SC_left:
     _color_write_mask = dr->get_window()->get_left_eye_color_mask();
     if (_current_properties->is_stereo()) {
-      _stereo_buffer_mask = ~(RenderBuffer::T_front_right | RenderBuffer::T_back_right);
+      _stereo_buffer_mask = ~RenderBuffer::T_right;
     }
     break;
 
   case Lens::SC_right:
     _color_write_mask = dr->get_window()->get_right_eye_color_mask();
     if (_current_properties->is_stereo()) {
-      _stereo_buffer_mask = ~(RenderBuffer::T_front_left | RenderBuffer::T_back_left);
+      _stereo_buffer_mask = ~RenderBuffer::T_left;
     }
     break;
 
@@ -2150,7 +2151,7 @@ do_issue_light() {
 //               copy.
 ////////////////////////////////////////////////////////////////////
 bool GraphicsStateGuardian::
-framebuffer_copy_to_texture(Texture *, int, const DisplayRegion *,
+framebuffer_copy_to_texture(Texture *, int, int, const DisplayRegion *,
                             const RenderBuffer &) {
   return false;
 }
@@ -2167,7 +2168,7 @@ framebuffer_copy_to_texture(Texture *, int, const DisplayRegion *,
 //               indicated texture.
 ////////////////////////////////////////////////////////////////////
 bool GraphicsStateGuardian::
-framebuffer_copy_to_ram(Texture *, int, const DisplayRegion *,
+framebuffer_copy_to_ram(Texture *, int, int, const DisplayRegion *,
                         const RenderBuffer &) {
   return false;
 }
@@ -2722,7 +2723,7 @@ make_shadow_buffer(const NodePath &light_np, GraphicsOutputBase *host) {
     for (int i = 0; i < 6; ++i) {
       PT(DisplayRegion) dr = sbuffer->make_mono_display_region(0, 1, 0, 1);
       dr->set_lens_index(i);
-      dr->set_target_tex_page(i, 0);
+      dr->set_target_tex_page(i);
       dr->set_camera(light_np);
       dr->set_clear_depth_active(true);
     }

+ 4 - 3
panda/src/display/graphicsStateGuardian.h

@@ -150,6 +150,7 @@ PUBLISHED:
   INLINE bool get_supports_two_sided_stencil() const;
   INLINE bool get_supports_geometry_instancing() const;
 
+  INLINE int get_max_color_targets() const;
   INLINE int get_maximum_simultaneous_render_targets() const;
 
   INLINE int get_shader_model() const;
@@ -308,9 +309,9 @@ public:
   virtual void do_issue_light();
 
   virtual bool framebuffer_copy_to_texture
-  (Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb);
+  (Texture *tex, int view, int z, const DisplayRegion *dr, const RenderBuffer &rb);
   virtual bool framebuffer_copy_to_ram
-  (Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb);
+  (Texture *tex, int view, int z, const DisplayRegion *dr, const RenderBuffer &rb);
 
   virtual void bind_light(PointLight *light_obj, const NodePath &light,
                           int light_id);
@@ -495,7 +496,7 @@ protected:
   bool _supports_two_sided_stencil;
   bool _supports_geometry_instancing;
 
-  int _maximum_simultaneous_render_targets;
+  int _max_color_targets;
 
   int  _supported_geom_rendering;
   bool _color_scale_via_lighting;

+ 16 - 8
panda/src/display/stereoDisplayRegion.cxx

@@ -52,9 +52,17 @@ StereoDisplayRegion::
 ////////////////////////////////////////////////////////////////////
 void StereoDisplayRegion::
 set_clear_active(int n, bool clear_active) {
-  //DisplayRegion::set_clear_active(n, clear_active);
-  _left_eye->set_clear_active(n, clear_active);
-  _right_eye->set_clear_active(n, clear_active);
+  // The clear_active flag gets set only on the parent, stereo display
+  // region.
+  DisplayRegion::set_clear_active(n, clear_active);
+
+  // Except for non-color buffers.  These also get set on the
+  // right display region by default, on the assumption that we want
+  // to clear these buffers between drawing the eyes, and that the
+  // right eye is the second of the pair.
+  if (n != RTP_color) {
+    _right_eye->set_clear_active(n, clear_active);
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -64,7 +72,7 @@ set_clear_active(int n, bool clear_active) {
 ////////////////////////////////////////////////////////////////////
 void StereoDisplayRegion::
 set_clear_value(int n, const LColor &clear_value) {
-  //DisplayRegion::set_clear_value(n, clear_value);
+  DisplayRegion::set_clear_value(n, clear_value);
   _left_eye->set_clear_value(n, clear_value);
   _right_eye->set_clear_value(n, clear_value);
 }
@@ -290,10 +298,10 @@ set_cull_traverser(CullTraverser *trav) {
 //               right DisplayRegions to the indicated value.
 ////////////////////////////////////////////////////////////////////
 void StereoDisplayRegion::
-set_target_tex_page(int page, int view) {
-  DisplayRegion::set_target_tex_page(page, view);
-  _left_eye->set_target_tex_page(page, view);
-  _right_eye->set_target_tex_page(page, view);
+set_target_tex_page(int page) {
+  DisplayRegion::set_target_tex_page(page);
+  _left_eye->set_target_tex_page(page);
+  _right_eye->set_target_tex_page(page);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 1 - 1
panda/src/display/stereoDisplayRegion.h

@@ -61,7 +61,7 @@ PUBLISHED:
   virtual void set_incomplete_render(bool incomplete_render);
   virtual void set_texture_reload_priority(int texture_reload_priority);
   virtual void set_cull_traverser(CullTraverser *trav);
-  virtual void set_target_tex_page(int page, int view);
+  virtual void set_target_tex_page(int page);
 
   virtual void output(ostream &out) const;
   virtual PT(PandaNode) make_cull_result_graph();

+ 14 - 12
panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx

@@ -1493,8 +1493,8 @@ end_draw_primitives() {
 //               copy.
 ////////////////////////////////////////////////////////////////////
 bool DXGraphicsStateGuardian8::
-framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
-                            const RenderBuffer &rb) {
+framebuffer_copy_to_texture(Texture *tex, int view, int z,
+                            const DisplayRegion *dr, const RenderBuffer &rb) {
   set_read_buffer(rb);
 
   int orig_x = tex->get_x_size();
@@ -1504,8 +1504,8 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
   int xo, yo, w, h;
   dr->get_region_pixels_i(xo, yo, w, h);
   tex->set_size_padded(w, h);
-  
-  TextureContext *tc = tex->prepare_now(0, get_prepared_objects(), this);
+
+  TextureContext *tc = tex->prepare_now(view, get_prepared_objects(), this);
   if (tc == (TextureContext *)NULL) {
     return false;
   }
@@ -1520,7 +1520,7 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
   if (tex->get_texture_type() != Texture::TT_2d_texture) {
     // For a specialty texture like a cube map, go the slow route
     // through RAM for now.
-    return do_framebuffer_copy_to_ram(tex, z, dr, rb, true);
+    return do_framebuffer_copy_to_ram(tex, view, z, dr, rb, true);
   }
   nassertr(dtc->get_d3d_2d_texture() != NULL, false);
 
@@ -1592,7 +1592,7 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
   if (FAILED(hr)) {
     dxgsg8_cat.info()
       << "CopyRects failed in copy_texture " << D3DERRORSTRING(hr);
-    okflag = framebuffer_copy_to_ram(tex, z, dr, rb);
+    okflag = framebuffer_copy_to_ram(tex, view, z, dr, rb);
   }
 
   SAFE_RELEASE(render_target);
@@ -1605,7 +1605,7 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
   } else {
     // The copy failed.  Fall back to copying it to RAM and back.
     // Terribly slow, but what are you going to do?
-    return do_framebuffer_copy_to_ram(tex, z, dr, rb, true);
+    return do_framebuffer_copy_to_ram(tex, view, z, dr, rb, true);
   }
 
   return true;
@@ -1623,8 +1623,9 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
 //               indicated texture.
 ////////////////////////////////////////////////////////////////////
 bool DXGraphicsStateGuardian8::
-framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb) {
-  return do_framebuffer_copy_to_ram(tex, z, dr, rb, false);
+framebuffer_copy_to_ram(Texture *tex, int view, int z,
+                        const DisplayRegion *dr, const RenderBuffer &rb) {
+  return do_framebuffer_copy_to_ram(tex, view, z, dr, rb, false);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1637,8 +1638,9 @@ framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr, const Rend
 //               copies to texture memory).
 ////////////////////////////////////////////////////////////////////
 bool DXGraphicsStateGuardian8::
-do_framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr, 
-                           const RenderBuffer &rb, bool inverted) {
+do_framebuffer_copy_to_ram(Texture *tex, int view, int z,
+                           const DisplayRegion *dr, const RenderBuffer &rb,
+                           bool inverted) {
   set_read_buffer(rb);
 
   RECT rect;
@@ -1779,7 +1781,7 @@ do_framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr,
     copy_inverted = !copy_inverted;
   }
   DXTextureContext8::d3d_surface_to_texture(rect, temp_surface,
-                                            copy_inverted, tex, z);
+                                            copy_inverted, tex, view, z);
 
   RELEASE(temp_surface, dxgsg8, "temp_surface", RELEASE_ONCE);
 

+ 8 - 4
panda/src/dxgsg8/dxGraphicsStateGuardian8.h

@@ -98,12 +98,16 @@ public:
                            bool force);
   virtual void end_draw_primitives();
 
-  virtual bool framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
+  virtual bool framebuffer_copy_to_texture(Texture *tex, int view, int z,
+                                           const DisplayRegion *dr,
                                            const RenderBuffer &rb);
-  virtual bool framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr,
+  virtual bool framebuffer_copy_to_ram(Texture *tex, int view, int z,
+                                       const DisplayRegion *dr,
                                        const RenderBuffer &rb);
-  bool do_framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr,
-                                  const RenderBuffer &rb, bool inverted);
+  bool do_framebuffer_copy_to_ram(Texture *tex, int view, int z,
+                                  const DisplayRegion *dr,
+                                  const RenderBuffer &rb,
+                                  bool inverted);
 
   virtual void reset();
 

+ 5 - 1
panda/src/dxgsg8/dxTextureContext8.cxx

@@ -1062,7 +1062,8 @@ extract_texture_data() {
 ////////////////////////////////////////////////////////////////////
 HRESULT DXTextureContext8::
 d3d_surface_to_texture(RECT &source_rect, IDirect3DSurface8 *d3d_surface,
-           bool inverted, Texture *result, int z) {
+           bool inverted, Texture *result, int view, int z) {
+
   // still need custom conversion since d3d/d3dx has no way to convert
   // arbitrary fmt to ARGB in-memory user buffer
 
@@ -1079,6 +1080,9 @@ d3d_surface_to_texture(RECT &source_rect, IDirect3DSurface8 *d3d_surface,
     nassertr(z < result->get_z_size(), E_FAIL);
     buf += z * result->get_expected_ram_page_size();
   }
+  if (view > 0) {
+    buf += (view * result->get_z_size()) * result->get_expected_ram_page_size();
+  }
 
   if (IsBadWritePtr(d3d_surface, sizeof(DWORD))) {
     dxgsg8_cat.error()

+ 1 - 1
panda/src/dxgsg8/dxTextureContext8.h

@@ -44,7 +44,7 @@ public:
   static HRESULT d3d_surface_to_texture(RECT &source_rect,
           IDirect3DSurface8 *d3d_surface,
           bool inverted, Texture *result,
-          int z);
+          int view, int z);
 
 private:
   HRESULT fill_d3d_texture_mipmap_pixels(int mip_level, int depth_index, D3DFORMAT source_format);

+ 1 - 1
panda/src/dxgsg8/wdxGraphicsBuffer8.cxx

@@ -403,7 +403,7 @@ rebuild_bitplanes() {
 //               the indicated face.
 ////////////////////////////////////////////////////////////////////
 void wdxGraphicsBuffer8::
-select_target_tex_page(int page, int view) {
+select_target_tex_page(int page) {
   _cube_map_index = page;
 
   HRESULT hr;

+ 2 - 2
panda/src/dxgsg8/wdxGraphicsBuffer8.h

@@ -45,8 +45,8 @@ public:
 
   virtual bool begin_frame(FrameMode mode, Thread *current_thread);
   virtual void end_frame(FrameMode mode, Thread *current_thread);
-  
-  virtual void select_target_tex_page(int page, int view);
+
+  virtual void select_target_tex_page(int page);
 
   virtual void process_events();
 

+ 12 - 11
panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx

@@ -1887,8 +1887,8 @@ end_draw_primitives() {
 //               copy.
 ////////////////////////////////////////////////////////////////////
 bool DXGraphicsStateGuardian9::
-framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
-                            const RenderBuffer &rb) {
+framebuffer_copy_to_texture(Texture *tex, int view, int z,
+                            const DisplayRegion *dr, const RenderBuffer &rb) {
   set_read_buffer(rb);
 
   int orig_x = tex->get_x_size();
@@ -1918,7 +1918,7 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
   if (tex->get_texture_type() != Texture::TT_2d_texture) {
     // For a specialty texture like a cube map, go the slow route
     // through RAM for now.
-    return do_framebuffer_copy_to_ram(tex, z, dr, rb, true);
+    return do_framebuffer_copy_to_ram(tex, view, z, dr, rb, true);
   }
   nassertr(dtc->get_d3d_2d_texture() != NULL, false);
 
@@ -2020,7 +2020,7 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
   } else {
     // The copy failed.  Fall back to copying it to RAM and back.
     // Terribly slow, but what are you going to do?
-    return do_framebuffer_copy_to_ram(tex, z, dr, rb, true);
+    return do_framebuffer_copy_to_ram(tex, view, z, dr, rb, true);
   }
 
   return true;
@@ -2038,9 +2038,9 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
 //               indicated texture.
 ////////////////////////////////////////////////////////////////////
 bool DXGraphicsStateGuardian9::
-framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr, 
-                        const RenderBuffer &rb) {
-  return do_framebuffer_copy_to_ram(tex, z, dr, rb, false);
+framebuffer_copy_to_ram(Texture *tex, int view, int z,
+                        const DisplayRegion *dr, const RenderBuffer &rb) {
+  return do_framebuffer_copy_to_ram(tex, view, z, dr, rb, false);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -2053,8 +2053,9 @@ framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr,
 //               copies to texture memory).
 ////////////////////////////////////////////////////////////////////
 bool DXGraphicsStateGuardian9::
-do_framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr, 
-                           const RenderBuffer &rb, bool inverted) {
+do_framebuffer_copy_to_ram(Texture *tex, int view, int z,
+                           const DisplayRegion *dr, const RenderBuffer &rb,
+                           bool inverted) {
   set_read_buffer(rb);
 
   RECT rect;
@@ -2212,7 +2213,7 @@ do_framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr,
     copy_inverted = !copy_inverted;
   }
   DXTextureContext9::d3d_surface_to_texture(rect, temp_surface,
-                                            copy_inverted, tex, z);
+                                            copy_inverted, tex, view, z);
 
   RELEASE(temp_surface, dxgsg9, "temp_surface", RELEASE_ONCE);
 
@@ -2445,7 +2446,7 @@ reset() {
   _supports_stencil_wrap = (d3d_caps.StencilCaps & D3DSTENCILCAPS_INCR) && (d3d_caps.StencilCaps & D3DSTENCILCAPS_DECR);
   _supports_two_sided_stencil = ((d3d_caps.StencilCaps & D3DSTENCILCAPS_TWOSIDED) != 0);
 
-  _maximum_simultaneous_render_targets = d3d_caps.NumSimultaneousRTs;
+  _max_color_targets = d3d_caps.NumSimultaneousRTs;
 
   _supports_depth_bias = ((d3d_caps.RasterCaps & (D3DPRASTERCAPS_DEPTHBIAS | D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS)) == (D3DPRASTERCAPS_DEPTHBIAS | D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS));
 

+ 8 - 4
panda/src/dxgsg9/dxGraphicsStateGuardian9.h

@@ -126,12 +126,16 @@ public:
                            bool force);
   virtual void end_draw_primitives();
 
-  virtual bool framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
+  virtual bool framebuffer_copy_to_texture(Texture *tex, int view, int z,
+                                           const DisplayRegion *dr,
                                            const RenderBuffer &rb);
-  virtual bool framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr,
+  virtual bool framebuffer_copy_to_ram(Texture *tex, int view, int z,
+                                       const DisplayRegion *dr,
                                        const RenderBuffer &rb);
-  bool do_framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr,
-                                  const RenderBuffer &rb, bool inverted);
+  bool do_framebuffer_copy_to_ram(Texture *tex, int view, int z,
+                                  const DisplayRegion *dr,
+                                  const RenderBuffer &rb,
+                                  bool inverted);
 
   void reset_render_states (void);
   virtual void reset();

+ 5 - 1
panda/src/dxgsg9/dxTextureContext9.cxx

@@ -1303,7 +1303,8 @@ extract_texture_data(DXScreenData &screen) {
 ////////////////////////////////////////////////////////////////////
 HRESULT DXTextureContext9::
 d3d_surface_to_texture(RECT &source_rect, IDirect3DSurface9 *d3d_surface,
-           bool inverted, Texture *result, int z) {
+           bool inverted, Texture *result, int view, int z) {
+
   // still need custom conversion since d3d/d3dx has no way to convert
   // arbitrary fmt to ARGB in-memory user buffer
 
@@ -1320,6 +1321,9 @@ d3d_surface_to_texture(RECT &source_rect, IDirect3DSurface9 *d3d_surface,
     nassertr(z < result->get_z_size(), E_FAIL);
     buf += z * result->get_expected_ram_page_size();
   }
+  if (view > 0) {
+    buf += (view * result->get_z_size()) * result->get_expected_ram_page_size();
+  }
 
   if (IsBadWritePtr(d3d_surface, sizeof(DWORD))) {
     dxgsg9_cat.error()

+ 1 - 1
panda/src/dxgsg9/dxTextureContext9.h

@@ -46,7 +46,7 @@ public:
   static HRESULT d3d_surface_to_texture(RECT &source_rect,
           IDirect3DSurface9 *d3d_surface,
           bool inverted, Texture *result,
-          int z);
+          int view, int z);
 
 private:
   HRESULT fill_d3d_texture_mipmap_pixels(int mip_level, int depth_index, D3DFORMAT source_format);

+ 1 - 1
panda/src/dxgsg9/wdxGraphicsBuffer9.cxx

@@ -591,7 +591,7 @@ rebuild_bitplanes() {
 //               the indicated face.
 ////////////////////////////////////////////////////////////////////
 void wdxGraphicsBuffer9::
-select_target_tex_page(int page, int view) {
+select_target_tex_page(int page) {
 
   DWORD render_target_index;
   

+ 2 - 2
panda/src/dxgsg9/wdxGraphicsBuffer9.h

@@ -46,8 +46,8 @@ public:
   virtual bool begin_frame(FrameMode mode, Thread *current_thread);
   virtual void end_frame(FrameMode mode, Thread *current_thread);
 
-  virtual void select_target_tex_page(int page, int view);
-  
+  virtual void select_target_tex_page(int page);
+
   virtual void process_events();
 
   virtual bool share_depth_buffer(GraphicsOutput *graphics_output);

+ 56 - 48
panda/src/glstuff/glGraphicsBuffer_src.cxx

@@ -81,7 +81,6 @@ CLP(GraphicsBuffer)(GraphicsEngine *engine, GraphicsPipe *pipe,
 
   _shared_depth_buffer = 0;
   _bound_tex_page = -1;
-  _bound_tex_view = 0;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -431,6 +430,17 @@ rebuild_bitplanes() {
     int next = GL_COLOR_ATTACHMENT0_EXT;
     if (attach[RTP_color] || _fb_properties.get_color_bits() > 0) {
       bind_slot(layer, rb_resize, attach, RTP_color, next++);
+
+      if (_fb_properties.is_stereo()) {
+        // The texture has already been initialized, so bind it straight away.
+        if (attach[RTP_color] != NULL) {
+          attach_tex(layer, 1, attach[RTP_color], next++);
+        } else {
+          //XXX hack: I needed a slot to use, and we don't currently use RTP_stencil
+          // which is treated as a color attachment below, so this fits the bill.
+          bind_slot(layer, rb_resize, attach, RTP_stencil, next++);
+        }
+      }
       _have_any_color = true;
     }
 
@@ -471,6 +481,9 @@ rebuild_bitplanes() {
     int next = GL_COLOR_ATTACHMENT0_EXT;
     if (attach[RTP_color] || _fb_properties.get_color_bits() > 0) {
       bind_slot_multisample(rb_resize, attach, RTP_color, next++);
+      if (_fb_properties.is_stereo()) {
+        //TODO: figure out how multisample is supposed to work with stereo buffers.
+      }
     }
 
     for (int i=0; i<_fb_properties.get_aux_rgba(); i++) {
@@ -498,7 +511,6 @@ rebuild_bitplanes() {
     _fb_properties.set_alpha_bits(0);
   }
 
-  _bound_tex_view = 0;
   _initial_clear = false;
   report_my_gl_errors();
 
@@ -763,6 +775,7 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot,
 
     // Allocate and bind the renderbuffer.
     glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, _rb[slot]);
+
     if (slot == RTP_depth_stencil) {
       GLCAT.debug() << "Creating depth stencil renderbuffer.\n";
       // Allocate renderbuffer storage for depth stencil.
@@ -811,13 +824,16 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot,
     } else {
       GLCAT.debug() << "Creating color renderbuffer.\n";
       glgsg->_glRenderbufferStorage(GL_RENDERBUFFER_EXT, gl_format, _rb_size_x, _rb_size_y);
-      GLint red_size = 0, green_size = 0, blue_size = 0, alpha_size = 0;
-      glgsg->_glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_RED_SIZE_EXT, &red_size);
-      glgsg->_glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_GREEN_SIZE_EXT, &green_size);
-      glgsg->_glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_BLUE_SIZE_EXT, &blue_size);
-      glgsg->_glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_ALPHA_SIZE_EXT, &alpha_size);
-      _fb_properties.set_color_bits(red_size + green_size + blue_size);
-      _fb_properties.set_alpha_bits(alpha_size);
+
+      if (attachpoint == GL_COLOR_ATTACHMENT0_EXT) {
+        GLint red_size = 0, green_size = 0, blue_size = 0, alpha_size = 0;
+        glgsg->_glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_RED_SIZE_EXT, &red_size);
+        glgsg->_glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_GREEN_SIZE_EXT, &green_size);
+        glgsg->_glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_BLUE_SIZE_EXT, &blue_size);
+        glgsg->_glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_ALPHA_SIZE_EXT, &alpha_size);
+        _fb_properties.set_color_bits(red_size + green_size + blue_size);
+        _fb_properties.set_alpha_bits(alpha_size);
+      }
       glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, 0);
       glgsg->_glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, attachpoint,
                                         GL_RENDERBUFFER_EXT, _rb[slot]);
@@ -962,6 +978,10 @@ attach_tex(int layer, int view, Texture *attach, GLenum attachpoint) {
   CLP(GraphicsStateGuardian) *glgsg;
   DCAST_INTO_V(glgsg, _gsg);
 
+  if (view >= attach->get_num_views()) {
+    attach->set_num_views(view + 1);
+  }
+
   // Create the OpenGL texture object.
   TextureContext *tc = attach->prepare_now(view, glgsg->get_prepared_objects(), glgsg);
   nassertv(tc != (TextureContext *)NULL);
@@ -985,7 +1005,7 @@ attach_tex(int layer, int view, Texture *attach, GLenum attachpoint) {
   GLenum target = glgsg->get_texture_target(attach->get_texture_type());
   if (target == GL_TEXTURE_CUBE_MAP) {
     target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer;
-  } 
+  }
 
   switch (target) {
 #ifndef OPENGLES_1
@@ -1097,19 +1117,17 @@ set_size(int x, int y) {
 //  Description: Called internally when the window is in
 //               render-to-a-texture mode and we are in the process of
 //               rendering the six faces of a cube map, or any other
-//               multi-page and/or multi-view texture.  This should do
-//               whatever needs to be done to switch the buffer to the
-//               indicated page and view.
+//               multi-page texture.  This should do whatever needs
+//               to be done to switch the buffer to the indicated page.
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsBuffer)::
-select_target_tex_page(int page, int view) {
+select_target_tex_page(int page) {
   nassertv(page >= 0 && page < _fbo.size());
 
   CLP(GraphicsStateGuardian) *glgsg;
   DCAST_INTO_V(glgsg, _gsg);
 
   bool switched_page = (_bound_tex_page != page);
-  bool switched_view = (_bound_tex_view != view);
 
   if (switched_page) {
     if (_bound_tex_page != -1) {
@@ -1123,32 +1141,6 @@ select_target_tex_page(int page, int view) {
     _bound_tex_page = page;
   }
 
-  if (switched_view || switched_page) {
-    // We assume that we've already configured the texture earlier
-    // in bind_bitplanes.  Therefore, since we can safely assume that
-    // all texture views have the same format, we can just bind the
-    // new view here.
-
-    Texture *tex = _tex[RTP_color];
-    if (tex != NULL) {
-      if (view >= tex->get_num_views()) {
-        tex->set_num_views(view + 1);
-      }
-
-      if (GLCAT.is_spam()) {
-        GLCAT.spam()
-          << "Binding texture " << *tex
-          << " view " << view << " to color attachment.\n";
-      }
-
-      attach_tex(_bound_tex_page, view, tex, GL_COLOR_ATTACHMENT0_EXT);
-
-      report_my_gl_errors();
-    }
-
-    _bound_tex_view = view;
-  }
-
   report_my_gl_errors();
 }
 
@@ -1167,7 +1159,8 @@ open_buffer() {
   nassertr(_host != 0, false);
 
   // Count total color buffers.
-  int totalcolor = 1 +
+  int totalcolor =
+   (_fb_properties.is_stereo() ? 2 : 1) +
     _fb_properties.get_aux_rgba() +
     _fb_properties.get_aux_hrgba() +
     _fb_properties.get_aux_float();
@@ -1229,8 +1222,10 @@ open_buffer() {
   _fb_properties.set_accum_bits(0);
   _fb_properties.set_multisamples(_host->get_fb_properties().get_multisamples());
 
-  // Update aux settings to reflect the GL_MAX_DRAW_BUFFERS limit.
-  int availcolor = glgsg->_max_draw_buffers;
+  // Update aux settings to reflect the GL_MAX_DRAW_BUFFERS limit,
+  // if we exceed it, that is.
+  int availcolor = glgsg->_max_color_targets;
+
   if (totalcolor > availcolor) {
     int aux_rgba = _fb_properties.get_aux_rgba();
     int aux_hrgba = _fb_properties.get_aux_hrgba();
@@ -1238,6 +1233,13 @@ open_buffer() {
 
     if (_fb_properties.get_color_bits() > 0 && availcolor > 0) {
       --availcolor;
+      if (_fb_properties.is_stereo()) {
+        if (availcolor > 0) {
+          --availcolor;
+        } else {
+          _fb_properties.set_stereo(0);
+        }
+      }
     }
     aux_rgba = min(aux_rgba, availcolor);
     availcolor -= aux_rgba;
@@ -1254,7 +1256,6 @@ open_buffer() {
   _fb_properties.set_back_buffers(0);
   _fb_properties.set_indexed_color(0);
   _fb_properties.set_rgb_color(1);
-  //_fb_properties.set_stereo(0);
   _fb_properties.set_force_hardware(_host->get_fb_properties().get_force_hardware());
   _fb_properties.set_force_software(_host->get_fb_properties().get_force_software());
 
@@ -1537,21 +1538,28 @@ resolve_multisamples() {
 #ifndef OPENGLES
   // Now handle the other color buffers.
   int next = GL_COLOR_ATTACHMENT1_EXT;
-  for (int i=0; i<_fb_properties.get_aux_rgba(); i++) {
+  if (_fb_properties.is_stereo()) {
+    glReadBuffer(next);
+    glDrawBuffer(next);
+    glgsg->_glBlitFramebuffer(0, 0, _rb_size_x, _rb_size_y, 0, 0, _rb_size_x, _rb_size_y,
+                              GL_COLOR_BUFFER_BIT, GL_NEAREST);
+    next += 1;
+  }
+  for (int i = 0; i < _fb_properties.get_aux_rgba(); ++i) {
     glReadBuffer(next);
     glDrawBuffer(next);
     glgsg->_glBlitFramebuffer(0, 0, _rb_size_x, _rb_size_y, 0, 0, _rb_size_x, _rb_size_y,
                               GL_COLOR_BUFFER_BIT, GL_NEAREST);
     next += 1;
   }
-  for (int i=0; i<_fb_properties.get_aux_hrgba(); i++) {
+  for (int i = 0; i < _fb_properties.get_aux_hrgba(); ++i) {
     glReadBuffer(next);
     glDrawBuffer(next);
     glgsg->_glBlitFramebuffer(0, 0, _rb_size_x, _rb_size_y, 0, 0, _rb_size_x, _rb_size_y,
                               GL_COLOR_BUFFER_BIT, GL_NEAREST);
     next += 1;
   }
-  for (int i=0; i<_fb_properties.get_aux_float(); i++) {
+  for (int i = 0; i < _fb_properties.get_aux_float(); ++i) {
     glReadBuffer(next);
     glDrawBuffer(next);
     glgsg->_glBlitFramebuffer(0, 0, _rb_size_x, _rb_size_y, 0, 0, _rb_size_x, _rb_size_y,

+ 2 - 3
panda/src/glstuff/glGraphicsBuffer_src.h

@@ -74,7 +74,7 @@ public:
 
   virtual void set_size(int x, int y);
 
-  virtual void select_target_tex_page(int page, int view);
+  virtual void select_target_tex_page(int page);
 
   virtual bool share_depth_buffer(GraphicsOutput *graphics_output);
   virtual void unshare_depth_buffer();
@@ -94,7 +94,7 @@ protected:
 
 private:
   
-  void bind_slot(int face, bool rb_resize, Texture **attach,
+  void bind_slot(int layer, bool rb_resize, Texture **attach,
                  RenderTexturePlane plane, GLenum attachpoint);
   void bind_slot_multisample(bool rb_resize, Texture **attach,
                  RenderTexturePlane plane, GLenum attachpoint);
@@ -130,7 +130,6 @@ private:
   // The cube map face we are currently drawing to or have just
   // finished drawing to, or -1 if we are not drawing to a cube map.
   int _bound_tex_page;
-  int _bound_tex_view;
 
   bool _initial_clear;
   bool _needs_rebuild;

+ 55 - 45
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -49,20 +49,19 @@
 #include "load_prc_file.h"
 #include "bamCache.h"
 #include "bamCacheRecord.h"
-#include "colorWriteAttrib.h"
-#include "depthWriteAttrib.h"
-#include "shadeModelAttrib.h"
-#include "rescaleNormalAttrib.h"
-#include "clipPlaneAttrib.h"
 #include "alphaTestAttrib.h"
+#include "clipPlaneAttrib.h"
+#include "colorWriteAttrib.h"
 #include "cullFaceAttrib.h"
-#include "fogAttrib.h"
 #include "depthOffsetAttrib.h"
-#include "materialAttrib.h"
-#include "stencilAttrib.h"
+#include "depthWriteAttrib.h"
+#include "fogAttrib.h"
 #include "lightAttrib.h"
+#include "materialAttrib.h"
+#include "rescaleNormalAttrib.h"
 #include "scissorAttrib.h"
-#include "clipPlaneAttrib.h"
+#include "shadeModelAttrib.h"
+#include "stencilAttrib.h"
 #include "graphicsEngine.h"
 #include "shaderGenerator.h"
 
@@ -955,21 +954,23 @@ reset() {
 
       // cgGLGetLatestProfile doesn't seem to return anything other
       // arbvp1/arbfp1 on non-NVIDIA cards, which is severely limiting.
-      if ((_shader_caps._active_vprofile == CG_PROFILE_ARBVP1 ||
-           _shader_caps._active_fprofile == CG_PROFILE_ARBFP1) &&
-          cgGLIsProfileSupported(CG_PROFILE_GLSLV) &&
-          cgGLIsProfileSupported(CG_PROFILE_GLSLF)) {
-
-        // So, if this happens, we set it to GLSL, which is
-        // usually supported on all cards.
-        _shader_caps._active_vprofile = (int)CG_PROFILE_GLSLV;
-        _shader_caps._active_fprofile = (int)CG_PROFILE_GLSLF;
+      // Actually, it seems that these profiles are horribly broken on these
+      // cards.  Let's not do this.
+      //if ((_shader_caps._active_vprofile == CG_PROFILE_ARBVP1 ||
+      //     _shader_caps._active_fprofile == CG_PROFILE_ARBFP1) &&
+      //    cgGLIsProfileSupported(CG_PROFILE_GLSLV) &&
+      //    cgGLIsProfileSupported(CG_PROFILE_GLSLF)) {
+
+      //  // So, if this happens, we set it to GLSL, which is
+      //  // usually supported on all cards.
+      //  _shader_caps._active_vprofile = (int)CG_PROFILE_GLSLV;
+      //  _shader_caps._active_fprofile = (int)CG_PROFILE_GLSLF;
 #if CG_VERSION_NUM >= 2200
-        if (cgGLIsProfileSupported(CG_PROFILE_GLSLG)) {
-          _shader_caps._active_gprofile = (int)CG_PROFILE_GLSLG;
-        }
+      //  if (cgGLIsProfileSupported(CG_PROFILE_GLSLG)) {
+      //    _shader_caps._active_gprofile = (int)CG_PROFILE_GLSLG;
+      //  }
 #endif
-      }
+      //}
     }
     _shader_caps._ultimate_vprofile = (int)CG_PROFILE_VP40;
     _shader_caps._ultimate_fprofile = (int)CG_PROFILE_FP40;
@@ -1254,12 +1255,12 @@ reset() {
     _glDrawBuffers = (PFNGLDRAWBUFFERSPROC)
       get_extension_func(GLPREFIX_QUOTED, "DrawBuffersARB");
   }
-  _max_draw_buffers = 1;
+
+  _max_color_targets = 1;
   if (_glDrawBuffers != 0) {
     GLint max_draw_buffers = 0;
     GLP(GetIntegerv)(GL_MAX_DRAW_BUFFERS, &max_draw_buffers);
-    _max_draw_buffers = max_draw_buffers;
-    _maximum_simultaneous_render_targets = max_draw_buffers;
+    _max_color_targets = max_draw_buffers;
   }
 #endif  // OPENGLES
 
@@ -4200,8 +4201,8 @@ make_geom_munger(const RenderState *state, Thread *current_thread) {
 //               into which to copy.
 ////////////////////////////////////////////////////////////////////
 bool CLP(GraphicsStateGuardian)::
-framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
-                            const RenderBuffer &rb) {
+framebuffer_copy_to_texture(Texture *tex, int view, int z,
+                            const DisplayRegion *dr, const RenderBuffer &rb) {
   nassertr(tex != NULL && dr != NULL, false);
   set_read_buffer(rb._buffer_type);
   if (CLP(color_mask)) {
@@ -4282,7 +4283,6 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
     }
   }
 
-  int view = dr->get_target_tex_view();
   TextureContext *tc = tex->prepare_now(view, get_prepared_objects(), this);
   nassertr(tc != (TextureContext *)NULL, false);
   CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
@@ -4390,8 +4390,8 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
 //               indicated texture.
 ////////////////////////////////////////////////////////////////////
 bool CLP(GraphicsStateGuardian)::
-framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr,
-                        const RenderBuffer &rb) {
+framebuffer_copy_to_ram(Texture *tex, int view, int z,
+                        const DisplayRegion *dr, const RenderBuffer &rb) {
   nassertr(tex != NULL && dr != NULL, false);
   set_read_buffer(rb._buffer_type);
   GLP(PixelStorei)(GL_PACK_ALIGNMENT, 1);
@@ -4465,11 +4465,6 @@ framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr,
 
   nassertr(z < tex->get_z_size(), false);
 
-  int view = dr->get_target_tex_view();
-  if (view >= tex->get_num_views()) {
-    tex->set_num_views(view + 1);
-  }
-
   GLenum external_format = get_external_image_format(tex);
 
   if (GLCAT.is_spam()) {
@@ -5853,27 +5848,37 @@ set_draw_buffer(int rbtype) {
   if (_current_fbo) {
 
     GLuint buffers[16];
-    int nbuffers=0;
+    int nbuffers = 0;
     int index = 0;
     if (_current_properties->get_color_bits() > 0) {
-      if (rbtype & RenderBuffer::T_color) {
-        buffers[nbuffers++] = GL_COLOR_ATTACHMENT0_EXT + (index++);
+      if (rbtype & RenderBuffer::T_left) {
+        buffers[nbuffers++] = GL_COLOR_ATTACHMENT0_EXT + index;
+      }
+      ++index;
+      if (_current_properties->is_stereo()) {
+        if (rbtype & RenderBuffer::T_right) {
+          buffers[nbuffers++] = GL_COLOR_ATTACHMENT0_EXT + index;
+        }
+        ++index;
       }
     }
     for (int i=0; i<_current_properties->get_aux_rgba(); i++) {
       if (rbtype & (RenderBuffer::T_aux_rgba_0 << i)) {
-        buffers[nbuffers++] = GL_COLOR_ATTACHMENT0_EXT + (index++);
+        buffers[nbuffers++] = GL_COLOR_ATTACHMENT0_EXT + index;
       }
+      ++index;
     }
     for (int i=0; i<_current_properties->get_aux_hrgba(); i++) {
       if (rbtype & (RenderBuffer::T_aux_hrgba_0 << i)) {
-        buffers[nbuffers++] = GL_COLOR_ATTACHMENT0_EXT + (index++);
+        buffers[nbuffers++] = GL_COLOR_ATTACHMENT0_EXT + index;
       }
+      ++index;
     }
     for (int i=0; i<_current_properties->get_aux_float(); i++) {
       if (rbtype & (RenderBuffer::T_aux_float_0 << i)) {
-        buffers[nbuffers++] = GL_COLOR_ATTACHMENT0_EXT + (index++);
+        buffers[nbuffers++] = GL_COLOR_ATTACHMENT0_EXT + index;
       }
+      ++index;
     }
     _glDrawBuffers(nbuffers, buffers);
 
@@ -5950,26 +5955,31 @@ set_read_buffer(int rbtype) {
   }
 
   if (_current_fbo) {
-
     GLuint buffer = GL_COLOR_ATTACHMENT0_EXT;
     int index = 1;
+    if (_current_properties->is_stereo()) {
+      if (rbtype & RenderBuffer::T_right) {
+        buffer = GL_COLOR_ATTACHMENT1_EXT;
+      }
+      ++index;
+    }
     for (int i=0; i<_current_properties->get_aux_rgba(); i++) {
       if (rbtype & (RenderBuffer::T_aux_rgba_0 << i)) {
         buffer = GL_COLOR_ATTACHMENT0_EXT + index;
       }
-      index += 1;
+      ++index;
     }
     for (int i=0; i<_current_properties->get_aux_hrgba(); i++) {
       if (rbtype & (RenderBuffer::T_aux_hrgba_0 << i)) {
         buffer = GL_COLOR_ATTACHMENT0_EXT + index;
       }
-      index += 1;
+      ++index;
     }
     for (int i=0; i<_current_properties->get_aux_float(); i++) {
       if (rbtype & (RenderBuffer::T_aux_float_0 << i)) {
         buffer = GL_COLOR_ATTACHMENT0_EXT + index;
       }
-      index += 1;
+      ++index;
     }
     GLP(ReadBuffer)(buffer);
 

+ 2 - 3
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -266,9 +266,9 @@ public:
   virtual void clear(DrawableRegion *region);
   
   virtual bool framebuffer_copy_to_texture
-    (Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb);
+    (Texture *tex, int view, int z, const DisplayRegion *dr, const RenderBuffer &rb);
   virtual bool framebuffer_copy_to_ram
-    (Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb);
+    (Texture *tex, int view, int z, const DisplayRegion *dr, const RenderBuffer &rb);
 
   void apply_fog(Fog *fog);
 
@@ -637,7 +637,6 @@ public:
   INLINE bool get_supports_framebuffer_blit();
   PFNGLBLITFRAMEBUFFEREXTPROC _glBlitFramebuffer;
   PFNGLDRAWBUFFERSPROC _glDrawBuffers;
-  int _max_draw_buffers;
   int _max_fb_samples;
 
   PFNGLGENQUERIESPROC _glGenQueries;

+ 3 - 3
panda/src/gsgbase/graphicsStateGuardianBase.h

@@ -208,10 +208,10 @@ public:
   virtual void end_draw_primitives()=0;
 
   virtual bool framebuffer_copy_to_texture
-  (Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb)=0;
+  (Texture *tex, int view, int z, const DisplayRegion *dr, const RenderBuffer &rb)=0;
   virtual bool framebuffer_copy_to_ram
-  (Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb)=0;
-  
+  (Texture *tex, int view, int z, const DisplayRegion *dr, const RenderBuffer &rb)=0;
+
   virtual CoordinateSystem get_internal_coordinate_system() const=0;
 
   virtual void bind_light(PointLight *light_obj, const NodePath &light, 

+ 6 - 11
panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx

@@ -1350,16 +1350,16 @@ end_draw_primitives() {
 //               copy.
 ////////////////////////////////////////////////////////////////////
 bool TinyGraphicsStateGuardian::
-framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
+framebuffer_copy_to_texture(Texture *tex, int view, int z,
+                            const DisplayRegion *dr,
                             const RenderBuffer &rb) {
   nassertr(tex != NULL && dr != NULL, false);
-  
+
   int xo, yo, w, h;
   dr->get_region_pixels_i(xo, yo, w, h);
 
   tex->setup_2d_texture(w, h, Texture::T_unsigned_byte, Texture::F_rgba);
 
-  int view = dr->get_target_tex_view();
   TextureContext *tc = tex->prepare_now(view, get_prepared_objects(), this);
   nassertr(tc != (TextureContext *)NULL, false);
   TinyTextureContext *gtc = DCAST(TinyTextureContext, tc);
@@ -1389,7 +1389,6 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
   return true;
 }
 
-
 ////////////////////////////////////////////////////////////////////
 //     Function: TinyGraphicsStateGuardian::framebuffer_copy_to_ram
 //       Access: Public, Virtual
@@ -1401,10 +1400,11 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
 //               indicated texture.
 ////////////////////////////////////////////////////////////////////
 bool TinyGraphicsStateGuardian::
-framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr,
+framebuffer_copy_to_ram(Texture *tex, int view, int z,
+                        const DisplayRegion *dr,
                         const RenderBuffer &rb) {
   nassertr(tex != NULL && dr != NULL, false);
-  
+
   int xo, yo, w, h;
   dr->get_region_pixels_i(xo, yo, w, h);
 
@@ -1433,11 +1433,6 @@ framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr,
 
   nassertr(z < tex->get_z_size(), false);
 
-  int view = dr->get_target_tex_view();
-  if (view >= tex->get_num_views()) {
-    tex->set_num_views(view + 1);
-  }
-
   unsigned char *image_ptr = tex->modify_ram_image();
   size_t image_size = tex->get_ram_image_size();
   if (z >= 0 || view > 0) {

+ 2 - 2
panda/src/tinydisplay/tinyGraphicsStateGuardian.h

@@ -82,9 +82,9 @@ public:
   virtual void end_draw_primitives();
 
   virtual bool framebuffer_copy_to_texture
-  (Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb);
+  (Texture *tex, int view, int z, const DisplayRegion *dr, const RenderBuffer &rb);
   virtual bool framebuffer_copy_to_ram
-  (Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb);
+  (Texture *tex, int view, int z, const DisplayRegion *dr, const RenderBuffer &rb);
 
   virtual void set_state_and_transform(const RenderState *state,
                                        const TransformState *transform);

+ 1 - 1
panda/src/wgldisplay/wglGraphicsBuffer.cxx

@@ -214,7 +214,7 @@ bind_texture_to_pbuffer() {
 //               the indicated face.
 ////////////////////////////////////////////////////////////////////
 void wglGraphicsBuffer::
-select_target_tex_page(int page, int view) {
+select_target_tex_page(int page) {
   wglGraphicsStateGuardian *wglgsg;
   DCAST_INTO_V(wglgsg, _gsg);
 

+ 1 - 1
panda/src/wgldisplay/wglGraphicsBuffer.h

@@ -49,7 +49,7 @@ public:
   virtual bool begin_frame(FrameMode mode, Thread *current_thread);
   virtual void end_frame(FrameMode mode, Thread *current_thread);
 
-  virtual void select_target_tex_page(int page, int view);
+  virtual void select_target_tex_page(int page);
 
   virtual void process_events();