Browse Source

Support for stereo FBOs

rdb 12 years ago
parent
commit
eaab45dc9a

+ 36 - 0
panda/src/display/graphicsOutput.cxx

@@ -108,6 +108,7 @@ GraphicsOutput(GraphicsEngine *engine, GraphicsPipe *pipe,
   _flip_ready = false;
   _cube_map_index = -1;
   _cube_map_dr = NULL;
+  _tex_view_offset = -1;
   _sort = 0;
   _child_sort = 0;
   _got_child_sort = false;
@@ -1384,6 +1385,29 @@ change_scenes(DisplayRegionPipelineReader *new_dr) {
       }
     }
   }
+
+  int new_tex_view_offset = new_dr->get_tex_view_offset();
+  if (new_tex_view_offset != _tex_view_offset) {
+    int old_tex_view_offset = _tex_view_offset;
+    //DisplayRegion *old_cube_map_dr = _cube_map_dr;
+    _tex_view_offset = new_tex_view_offset;
+    //_cube_map_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;
+      Texture *texture = (*ri)._texture;
+      if (rtm_mode == RTM_bind_or_copy || rtm_mode == RTM_bind_layered) {
+        // In render-to-texture mode, switch the rendering backend to
+        // the new view, so that the subsequent frame will be
+        // rendered to the new view.
+
+        select_tex_view(new_tex_view_offset);
+        break;
+      }
+    }
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1399,6 +1423,18 @@ void GraphicsOutput::
 select_cube_map(int) {
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::select_tex_view
+//       Access: Public, Virtual
+//  Description: Called internally when the window is in
+//               render-to-a-texture mode and the DisplayRegion
+//               requests that we switch rendering to a different
+//               texture view.
+////////////////////////////////////////////////////////////////////
+void GraphicsOutput::
+select_tex_view(int) {
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsOutput::begin_flip
 //       Access: Public, Virtual

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

@@ -261,6 +261,7 @@ public:
 
   void change_scenes(DisplayRegionPipelineReader *new_dr);
   virtual void select_cube_map(int cube_map_index);
+  virtual void select_tex_view(int tex_view_offset);
 
   // These methods will be called within the app (main) thread.
   virtual void begin_flip();
@@ -312,6 +313,7 @@ protected:
   bool _flip_ready;
   int _cube_map_index;
   DisplayRegion *_cube_map_dr;
+  int _tex_view_offset;
   PT(Geom) _texture_card;
   bool _trigger_copy;
 

+ 4 - 19
panda/src/display/stereoDisplayRegion.cxx

@@ -52,24 +52,9 @@ StereoDisplayRegion::
 ////////////////////////////////////////////////////////////////////
 void StereoDisplayRegion::
 set_clear_active(int n, bool clear_active) {
-  // The clear_active flag gets set only on the parent, stereo display
-  // region.
-  DisplayRegion::set_clear_active(n, clear_active);
-
-  // Except for depth and stencil 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.
-  switch (n) {
-  case RTP_stencil:
-  case RTP_depth_stencil:
-  case RTP_depth:
-    _right_eye->set_clear_active(n, clear_active);
-    break;
-
-  default:
-    break;
-  }
+  //DisplayRegion::set_clear_active(n, clear_active);
+  _left_eye->set_clear_active(n, clear_active);
+  _right_eye->set_clear_active(n, clear_active);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -79,7 +64,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);
 }

+ 100 - 5
panda/src/glstuff/glGraphicsBuffer_src.cxx

@@ -81,6 +81,7 @@ CLP(GraphicsBuffer)(GraphicsEngine *engine, GraphicsPipe *pipe,
 
   _shared_depth_buffer = 0;
   _active_cube_map_index = -1;
+  _bound_tex_view = 0;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -304,6 +305,7 @@ rebuild_bitplanes() {
     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;
       Texture *tex = rt._texture;
 
       if (rtm_mode == RTM_bind_layered) {
@@ -311,11 +313,13 @@ rebuild_bitplanes() {
           GLCAT.warning()
            << "All textures attached to layered FBO should have the same layer count!\n";
         }
-      } else if (tex->get_z_size() > 1) {
-        num_fbos = max(num_fbos, tex->get_z_size());
+
+        // Assign the texture to this slot.
+        attach[plane] = tex;
+        continue;
       }
 
-      if (rtm_mode != RTM_bind_or_copy && rtm_mode != RTM_bind_layered) {
+      if (rtm_mode != RTM_bind_or_copy) {
         continue;
       }
 
@@ -339,12 +343,15 @@ rebuild_bitplanes() {
       // If I can't find an appropriate slot, or if there's
       // already a texture bound to this slot, then punt
       // this texture.
-      RenderTexturePlane plane = rt._plane;
       if (attach[plane]) {
         ((CData *)cdata.p())->_textures[i]._rtm_mode = RTM_copy_texture;
         continue;
       }
 
+      if (tex->get_z_size() > 1) {
+        num_fbos = max(num_fbos, tex->get_z_size());
+      }
+
       // Assign the texture to this slot.
       attach[plane] = tex;
     }
@@ -491,6 +498,7 @@ rebuild_bitplanes() {
     _fb_properties.set_alpha_bits(0);
   }
 
+  _bound_tex_view = 0;
   _initial_clear = false;
   report_my_gl_errors();
 
@@ -1030,6 +1038,20 @@ end_frame(FrameMode mode, Thread *current_thread) {
   report_my_gl_errors();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: glGraphicsBuffer::set_size
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+void CLP(GraphicsBuffer)::
+set_size(int x, int y) {
+  if (_x_size != x || _y_size != y) {
+    _needs_rebuild = true;
+  }
+
+  set_size_and_recalc(x, y);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: glGraphicsBuffer::select_cube_map
 //       Access: Public, Virtual
@@ -1059,6 +1081,79 @@ select_cube_map(int cube_map_index) {
   report_my_gl_errors();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: glGraphicsBuffer::select_tex_view
+//       Access: Public, Virtual
+//  Description: Called internally when the window is in
+//               render-to-a-texture mode and the DisplayRegion
+//               requests that we switch rendering to a different
+//               texture view.
+//
+//               In the FBO case, we do this by re-binding the
+//               texture that is attached to the color plane.
+////////////////////////////////////////////////////////////////////
+void CLP(GraphicsBuffer)::
+select_tex_view(int view) {
+  CLP(GraphicsStateGuardian) *glgsg;
+  DCAST_INTO_V(glgsg, _gsg);
+
+  if (view == _bound_tex_view) {
+    return;
+  }
+
+  // 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);
+    }
+
+    GLenum target = glgsg->get_texture_target(tex->get_texture_type());
+    if (target == GL_TEXTURE_CUBE_MAP) {
+      target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + _active_cube_map_index;
+    }
+
+    // Create the OpenGL texture object.
+    TextureContext *tc = tex->prepare_now(view, glgsg->get_prepared_objects(), glgsg);
+    nassertv(tc != (TextureContext *)NULL);
+    CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
+    glgsg->update_texture(tc, true);
+
+    GLCAT.spam() << "Binding texture " << *tex
+      << " view " << view << " to color attachment.\n";
+
+  #ifndef OPENGLES
+    GLclampf priority = 1.0f;
+    glPrioritizeTextures(1, &gtc->_index, &priority);
+  #endif
+    glgsg->update_texture(tc, true);
+
+    if (_rb_size_z == 1) {
+      if (target == GL_TEXTURE_3D) {
+        glgsg->_glFramebufferTexture3D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+                                       target, gtc->_index, 0, _active_cube_map_index);
+      } else if (target == GL_TEXTURE_2D_ARRAY_EXT) {
+        glgsg->_glFramebufferTextureLayer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+                                          gtc->_index, 0, _active_cube_map_index);
+      } else {
+        glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+                                       target, gtc->_index, 0);
+      }
+    } else {
+      glgsg->_glFramebufferTexture(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+                                   gtc->_index, 0);
+    }
+
+    report_my_gl_errors();
+  }
+
+  _bound_tex_view = view;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: glGraphicsBuffer::open_buffer
 //       Access: Protected, Virtual
@@ -1139,7 +1234,7 @@ 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_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());
 

+ 4 - 0
panda/src/glstuff/glGraphicsBuffer_src.h

@@ -72,7 +72,10 @@ public:
   virtual bool begin_frame(FrameMode mode, Thread *current_thread);
   virtual void end_frame(FrameMode mode, Thread *current_thread);
 
+  virtual void set_size(int x, int y);
+
   virtual void select_cube_map(int cube_map_index);
+  virtual void select_tex_view(int tex_view_offset);
 
   virtual bool share_depth_buffer(GraphicsOutput *graphics_output);
   virtual void unshare_depth_buffer();
@@ -127,6 +130,7 @@ 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 _active_cube_map_index;
+  int _bound_tex_view;
 
   bool _initial_clear;
   bool _needs_rebuild;

+ 15 - 14
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -1939,6 +1939,16 @@ clear(DrawableRegion *clearable) {
     }
   }
 
+  // In the past, it was possible to set the draw buffer
+  // once in prepare_display_region and then forget about it.
+  // Now, with aux layers, it is necessary to occasionally
+  // change the draw buffer.  In time, I think there will need
+  // to be a draw buffer attrib.  Until then, this little hack
+  // to put things back the way they were after
+  // prepare_display_region will do.
+  
+  set_draw_buffer(_draw_buffer_type);
+
   if (_current_properties->get_color_bits() > 0) {
     if (clearable->get_clear_color_active()) {
       LColor v = clearable->get_clear_color();
@@ -1948,7 +1958,6 @@ clear(DrawableRegion *clearable) {
       }
       _state_mask.clear_bit(ColorWriteAttrib::get_class_slot());
       mask |= GL_COLOR_BUFFER_BIT;
-      set_draw_buffer(clearable->get_draw_buffer_type());
     }
   }
   
@@ -1971,18 +1980,8 @@ clear(DrawableRegion *clearable) {
     GLP(ClearStencil)(clearable->get_clear_stencil());
     mask |= GL_STENCIL_BUFFER_BIT;
   }
-  
+
   GLP(Clear)(mask);
-  
-  // In the past, it was possible to set the draw buffer
-  // once in prepare_display_region and then forget about it.
-  // Now, with aux layers, it is necessary to occasionally
-  // change the draw buffer.  In time, I think there will need
-  // to be a draw buffer attrib.  Until then, this little hack
-  // to put things back the way they were after
-  // prepare_display_region will do.
-  
-  set_draw_buffer(_draw_buffer_type);
 
   if (GLCAT.is_spam()) {
     GLCAT.spam() << "glClear(";
@@ -2225,7 +2224,8 @@ end_scene() {
   GraphicsStateGuardian::end_scene();
 
 #ifndef OPENGLES_1
-  if (_vertex_array_shader_context != 0) {
+  // This breaks shaders across multiple regions.
+  /*if (_vertex_array_shader_context != 0) {
     _vertex_array_shader_context->disable_shader_vertex_arrays(this);
     _vertex_array_shader = (Shader *)NULL;
     _vertex_array_shader_context = (CLP(ShaderContext) *)NULL;
@@ -2239,7 +2239,7 @@ end_scene() {
     _current_shader_context->unbind(this);
     _current_shader = (Shader *)NULL;
     _current_shader_context = (CLP(ShaderContext) *)NULL;
-  }
+  }*/
 #endif
 
   _dlights.clear();
@@ -4648,6 +4648,7 @@ do_issue_shader(bool state_has_changed) {
   if (!shader) {
     shader = _default_shader;
   }
+
 #endif
   if (shader) {
     context = (CLP(ShaderContext) *)(shader->prepare_now(get_prepared_objects(), this));