Browse Source

generalize render-to-texture operations

David Rose 21 years ago
parent
commit
b82f3bac1e

+ 2 - 2
panda/src/display/config_display.cxx

@@ -89,10 +89,10 @@ ConfigVariableBool show_buffers
 
 
 ConfigVariableBool prefer_parasite_buffer
 ConfigVariableBool prefer_parasite_buffer
 ("prefer-parasite-buffer", true,
 ("prefer-parasite-buffer", true,
- PRC_DESC("Set this true to make GraphicsOutput::make_render_texture() try to "
+ PRC_DESC("Set this true to make GraphicsOutput::make_texture_buffer() try to "
           "create a parasite buffer before it tries to create an offscreen "
           "create a parasite buffer before it tries to create an offscreen "
           "buffer.  This may be desired if you know your graphics API does not "
           "buffer.  This may be desired if you know your graphics API does not "
-          "support render-directly-to-texture and you want to minimize "
+          "support render-to-texture and you want to minimize "
           "framebuffer memory."));
           "framebuffer memory."));
 
 
 ConfigVariableBool prefer_single_buffer
 ConfigVariableBool prefer_single_buffer

+ 1 - 5
panda/src/display/graphicsBuffer.cxx

@@ -29,7 +29,7 @@ TypeHandle GraphicsBuffer::_type_handle;
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GraphicsBuffer::
 GraphicsBuffer::
 GraphicsBuffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
 GraphicsBuffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
-               const string &name, int x_size, int y_size, bool want_texture) :
+               const string &name, int x_size, int y_size) :
   GraphicsOutput(pipe, gsg, name)
   GraphicsOutput(pipe, gsg, name)
 {
 {
 #ifdef DO_MEMORY_USAGE
 #ifdef DO_MEMORY_USAGE
@@ -47,10 +47,6 @@ GraphicsBuffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
   _has_size = true;
   _has_size = true;
   _default_display_region->compute_pixels(_x_size, _y_size);
   _default_display_region->compute_pixels(_x_size, _y_size);
   _open_request = OR_none;
   _open_request = OR_none;
-
-  if (want_texture) {
-    setup_copy_texture(_name);
-  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 1 - 9
panda/src/display/graphicsBuffer.h

@@ -30,19 +30,11 @@
 // Description : An offscreen buffer for rendering into.  This is
 // Description : An offscreen buffer for rendering into.  This is
 //               similar in function to a GraphicsWindow, except that
 //               similar in function to a GraphicsWindow, except that
 //               the output is not visible to the user.
 //               the output is not visible to the user.
-//
-//               If want_texture is passed true into the constructor,
-//               the GraphicsBuffer will render directly into a
-//               texture which can be retrieved via get_texture().
-//               This may then be applied to geometry for rendering in
-//               other windows or buffers using the same
-//               GraphicsStateGuardian.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA GraphicsBuffer : public GraphicsOutput {
 class EXPCL_PANDA GraphicsBuffer : public GraphicsOutput {
 protected:
 protected:
   GraphicsBuffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
   GraphicsBuffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
-                 const string &name,
-                 int x_size, int y_size, bool want_texture);
+                 const string &name, int x_size, int y_size);
 
 
 PUBLISHED:
 PUBLISHED:
   virtual ~GraphicsBuffer();
   virtual ~GraphicsBuffer();

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

@@ -250,7 +250,7 @@ make_buffer(GraphicsStateGuardian *gsg, const string &name,
       window->request_properties(props);
       window->request_properties(props);
 
 
       if (want_texture) {
       if (want_texture) {
-        window->setup_copy_texture(name);
+        window->setup_render_texture();
       }
       }
 
 
       return window;
       return window;
@@ -265,9 +265,12 @@ make_buffer(GraphicsStateGuardian *gsg, const string &name,
 
 
   // TODO: ask the window thread to make the buffer.
   // TODO: ask the window thread to make the buffer.
   PT(GraphicsBuffer) buffer = 
   PT(GraphicsBuffer) buffer = 
-    gsg->get_pipe()->make_buffer(gsg, name, x_size, y_size, want_texture);
+    gsg->get_pipe()->make_buffer(gsg, name, x_size, y_size);
   if (buffer != (GraphicsBuffer *)NULL) {
   if (buffer != (GraphicsBuffer *)NULL) {
     buffer->_sort = sort;
     buffer->_sort = sort;
+    if (want_texture) {
+      buffer->setup_render_texture();
+    }
     do_add_window(buffer, gsg, threading_model);
     do_add_window(buffer, gsg, threading_model);
   }
   }
   return buffer;
   return buffer;
@@ -299,7 +302,7 @@ make_parasite(GraphicsOutput *host, const string &name,
       props.set_fixed_size(true);
       props.set_fixed_size(true);
       props.set_title(name);
       props.set_title(name);
       window->request_properties(props);
       window->request_properties(props);
-      window->setup_copy_texture(name);
+      window->setup_render_texture();
 
 
       return window;
       return window;
     }
     }
@@ -313,6 +316,7 @@ make_parasite(GraphicsOutput *host, const string &name,
 
 
   ParasiteBuffer *buffer = new ParasiteBuffer(host, name, x_size, y_size);
   ParasiteBuffer *buffer = new ParasiteBuffer(host, name, x_size, y_size);
   buffer->_sort = sort;
   buffer->_sort = sort;
+  buffer->setup_render_texture();
   do_add_window(buffer, gsg, threading_model);
   do_add_window(buffer, gsg, threading_model);
 
 
   return buffer;
   return buffer;

+ 59 - 19
panda/src/display/graphicsOutput.cxx

@@ -53,6 +53,7 @@ GraphicsOutput(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
   _has_size = false;
   _has_size = false;
   _is_valid = false;
   _is_valid = false;
   _copy_texture = false;
   _copy_texture = false;
+  _render_texture = false;
   _flip_ready = false;
   _flip_ready = false;
   _needs_context = true;
   _needs_context = true;
   _sort = 0;
   _sort = 0;
@@ -158,32 +159,48 @@ GraphicsOutput::
 //       Access: Published
 //       Access: Published
 //  Description: Disassociates the texture from the GraphicsOutput.
 //  Description: Disassociates the texture from the GraphicsOutput.
 //               The texture will no longer be filled as the frame
 //               The texture will no longer be filled as the frame
-//               renders, and it may be used (with its current
-//               contents) as an ordinary texture in its own right.
+//               renders, and it may be used as an ordinary texture in
+//               its own right.  However, its contents may be
+//               undefined.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GraphicsOutput::
 void GraphicsOutput::
 detach_texture() {
 detach_texture() {
   MutexHolder holder(_lock);
   MutexHolder holder(_lock);
+
+  if (_render_texture && _gsg != (GraphicsStateGuardian *)NULL) {
+    _gsg->framebuffer_release_texture(this, get_texture());
+  }
+
   _texture = NULL;
   _texture = NULL;
   _copy_texture = false;
   _copy_texture = false;
+  _render_texture = false;
 
 
   set_inverted(window_inverted);
   set_inverted(window_inverted);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GraphicsOutput::setup_copy_texture
-//       Access: Published
-//  Description: Creates a new Texture object, suitable for copying
+//     Function: GraphicsOutput::setup_render_texture
+//       Access: Published, Virtual
+//  Description: Creates a new Texture object, suitable for rendering
 //               the contents of this buffer into, and stores it in
 //               the contents of this buffer into, and stores it in
 //               _texture.  This also disassociates the previous
 //               _texture.  This also disassociates the previous
 //               texture (if any).
 //               texture (if any).
+//
+//               If the backend supports it, this will actually set up
+//               the framebuffer to render directly into texture
+//               memory; otherwise, the framebuffer will be copied
+//               into the texture after each frame.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GraphicsOutput::
 void GraphicsOutput::
-setup_copy_texture(const string &name) {
+setup_render_texture() {
   MutexHolder holder(_lock);
   MutexHolder holder(_lock);
 
 
+  if (_render_texture && _gsg != (GraphicsStateGuardian *)NULL) {
+    _gsg->framebuffer_release_texture(this, get_texture());
+  }
+
   _texture = new Texture(true);
   _texture = new Texture(true);
-  _texture->set_name(name);
+  _texture->set_name(get_name());
   _texture->set_wrapu(Texture::WM_clamp);
   _texture->set_wrapu(Texture::WM_clamp);
   _texture->set_wrapv(Texture::WM_clamp);
   _texture->set_wrapv(Texture::WM_clamp);
 
 
@@ -195,6 +212,7 @@ setup_copy_texture(const string &name) {
   }
   }
 
 
   _copy_texture = true;
   _copy_texture = true;
+  _render_texture = false;
 
 
   nassertv(_gsg != (GraphicsStateGuardian *)NULL);
   nassertv(_gsg != (GraphicsStateGuardian *)NULL);
   set_inverted(_gsg->get_copy_texture_inverted());
   set_inverted(_gsg->get_copy_texture_inverted());
@@ -428,7 +446,7 @@ make_texture_buffer(const string &name, int x_size, int y_size) {
 
 
   GraphicsOutput *buffer = NULL;
   GraphicsOutput *buffer = NULL;
 
 
-  // If the user so indicated in the Configrc file, try to create a
+  // If the user so indicated in the Config.prc file, try to create a
   // parasite buffer first.  We can only do this if the requested size
   // parasite buffer first.  We can only do this if the requested size
   // fits within the available framebuffer size.
   // fits within the available framebuffer size.
   if (prefer_parasite_buffer && 
   if (prefer_parasite_buffer && 
@@ -575,6 +593,12 @@ begin_frame() {
 
 
   // Okay, we already have a GSG, so activate it.
   // Okay, we already have a GSG, so activate it.
   make_current();
   make_current();
+
+  if (_render_texture) {
+    // Release the texture so we can render into the pbuffer.
+    _gsg->framebuffer_release_texture(this, get_texture());
+  }
+
   return _gsg->begin_frame();
   return _gsg->begin_frame();
 }
 }
 
 
@@ -611,20 +635,36 @@ end_frame() {
   nassertv(_gsg != (GraphicsStateGuardian *)NULL);
   nassertv(_gsg != (GraphicsStateGuardian *)NULL);
   _gsg->end_frame();
   _gsg->end_frame();
 
 
-  // If _copy_texture is true, it means we should copy the framebuffer
-  // to the GraphicsOutput's associated texture after the frame has
-  // rendered.  GraphicsBuffer objects that are set up to render
-  // directly into texture memory don't need to do this; they will set
-  // _copy_texture to false.
+  // If _copy_texture is true, it means we should copy or lock the
+  // framebuffer to the GraphicsOutput's associated texture after the
+  // frame has rendered.
   if (_copy_texture) {
   if (_copy_texture) {
-    if (display_cat.is_debug()) {
-      display_cat.debug()
-        << "Copying texture for " << (void *)this << " at frame end.\n";
-    }
     PStatTimer timer(_copy_texture_pcollector);
     PStatTimer timer(_copy_texture_pcollector);
     nassertv(has_texture());
     nassertv(has_texture());
-    RenderBuffer buffer = _gsg->get_render_buffer(get_draw_buffer_type());
-    _gsg->copy_texture(get_texture(), _default_display_region, buffer);
+
+    // If _render_texture is true, it means we should attempt to lock
+    // the framebuffer directly to the texture memory, avoiding the
+    // copy.
+    if (_render_texture) {
+      if (display_cat.is_debug()) {
+        display_cat.debug()
+          << "Locking texture for " << (void *)this << " at frame end.\n";
+      }
+      if (!_gsg->framebuffer_bind_to_texture(this, get_texture())) {
+        display_cat.warning()
+          << "Lock-to-texture failed, resorting to copy.\n";
+        _render_texture = false;
+      }
+    }
+
+    if (!_render_texture) {
+      if (display_cat.is_debug()) {
+        display_cat.debug()
+          << "Copying texture for " << (void *)this << " at frame end.\n";
+      }
+      RenderBuffer buffer = _gsg->get_render_buffer(get_draw_buffer_type());
+      _gsg->copy_texture(get_texture(), _default_display_region, buffer);
+    }
   }
   }
 
 
   // If we're not single-buffered, we're now ready to flip.
   // If we're not single-buffered, we're now ready to flip.

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

@@ -75,7 +75,7 @@ PUBLISHED:
   INLINE bool has_texture() const;  
   INLINE bool has_texture() const;  
   INLINE Texture *get_texture() const;  
   INLINE Texture *get_texture() const;  
   void detach_texture();
   void detach_texture();
-  void setup_copy_texture(const string &name);
+  virtual void setup_render_texture();
 
 
   INLINE int get_x_size() const;
   INLINE int get_x_size() const;
   INLINE int get_y_size() const;
   INLINE int get_y_size() const;
@@ -157,6 +157,7 @@ protected:
   string _name;
   string _name;
   PT(Texture) _texture;
   PT(Texture) _texture;
   bool _copy_texture;
   bool _copy_texture;
+  bool _render_texture;
   bool _flip_ready;
   bool _flip_ready;
   bool _needs_context;
   bool _needs_context;
 
 

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

@@ -203,7 +203,7 @@ make_window(GraphicsStateGuardian *, const string &) {
 //  Description: Creates a new offscreen buffer on the pipe, if possible.
 //  Description: Creates a new offscreen buffer on the pipe, if possible.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 PT(GraphicsBuffer) GraphicsPipe::
 PT(GraphicsBuffer) GraphicsPipe::
-make_buffer(GraphicsStateGuardian *, const string &, int, int, bool) {
+make_buffer(GraphicsStateGuardian *, const string &, int, int) {
   display_cat.error()
   display_cat.error()
     << get_type() << " cannot create offscreen buffers.\n";
     << get_type() << " cannot create offscreen buffers.\n";
   return NULL;
   return NULL;

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

@@ -100,7 +100,7 @@ protected:
                                          const string &name);
                                          const string &name);
   virtual PT(GraphicsBuffer) make_buffer(GraphicsStateGuardian *gsg, 
   virtual PT(GraphicsBuffer) make_buffer(GraphicsStateGuardian *gsg, 
                                          const string &name,
                                          const string &name,
-                                         int x_size, int y_size, bool want_texture);
+                                         int x_size, int y_size);
 
 
   Mutex _lock;
   Mutex _lock;
 
 

+ 13 - 0
panda/src/display/graphicsStateGuardian.I

@@ -193,6 +193,19 @@ get_supports_generate_mipmap() const {
   return _supports_generate_mipmap;
   return _supports_generate_mipmap;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::get_supports_render_texture
+//       Access: Published
+//  Description: Returns true if this particular GSG can render
+//               directly into a texture, or false if it must always
+//               copy-to-texture at the end of each frame to achieve
+//               this effect.
+////////////////////////////////////////////////////////////////////
+INLINE bool GraphicsStateGuardian::
+get_supports_render_texture() const {
+  return _supports_render_texture;
+}
+
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::set_scene
 //     Function: GraphicsStateGuardian::set_scene

+ 34 - 0
panda/src/display/graphicsStateGuardian.cxx

@@ -97,6 +97,7 @@ GraphicsStateGuardian(const FrameBufferProperties &properties,
   // Similarly with these capabilities flags.
   // Similarly with these capabilities flags.
   _supports_multisample = false;
   _supports_multisample = false;
   _supports_generate_mipmap = false;
   _supports_generate_mipmap = false;
+  _supports_render_texture = false;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -585,6 +586,39 @@ finish_decal() {
   // No need to do anything special here.
   // No need to do anything special here.
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::framebuffer_bind_to_texture
+//       Access: Public, Virtual
+//  Description: Works in lieu of copy_texture() to bind the primary
+//               render buffer of the framebuffer to the indicated
+//               texture (which must have been created via
+//               GraphicsOutput::setup_render_texture()).
+//
+//               If supported by the graphics backend, this will make
+//               the framebuffer memory directly accessible within the
+//               texture, but the frame cannot be rendered again until
+//               framebuffer_release_texture() is called.
+//
+//               The return value is true if successful, false on
+//               failure.
+////////////////////////////////////////////////////////////////////
+bool GraphicsStateGuardian::
+framebuffer_bind_to_texture(GraphicsOutput *, Texture *) {
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::framebuffer_release_texture
+//       Access: Public, Virtual
+//  Description: Undoes a previous call to
+//               framebuffer_bind_to_texture().  The framebuffer may
+//               again be rendered into, and the contents of the
+//               texture is undefined.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+framebuffer_release_texture(GraphicsOutput *, Texture *) {
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::set_coordinate_system
 //     Function: GraphicsStateGuardian::set_coordinate_system
 //       Access: Public
 //       Access: Public

+ 5 - 0
panda/src/display/graphicsStateGuardian.h

@@ -87,6 +87,7 @@ PUBLISHED:
   INLINE bool get_copy_texture_inverted() const;
   INLINE bool get_copy_texture_inverted() const;
   virtual bool get_supports_multisample() const;
   virtual bool get_supports_multisample() const;
   INLINE bool get_supports_generate_mipmap() const;
   INLINE bool get_supports_generate_mipmap() const;
+  INLINE bool get_supports_render_texture() const;
 
 
 public:
 public:
   INLINE bool set_scene(SceneSetup *scene_setup);
   INLINE bool set_scene(SceneSetup *scene_setup);
@@ -135,6 +136,9 @@ public:
   virtual CPT(RenderState) begin_decal_base_second();
   virtual CPT(RenderState) begin_decal_base_second();
   virtual void finish_decal();
   virtual void finish_decal();
 
 
+  virtual bool framebuffer_bind_to_texture(GraphicsOutput *win, Texture *tex);
+  virtual void framebuffer_release_texture(GraphicsOutput *win, Texture *tex);
+
   INLINE bool reset_if_new();
   INLINE bool reset_if_new();
   virtual void reset();
   virtual void reset();
 
 
@@ -285,6 +289,7 @@ protected:
   bool _copy_texture_inverted;
   bool _copy_texture_inverted;
   bool _supports_multisample;
   bool _supports_multisample;
   bool _supports_generate_mipmap;
   bool _supports_generate_mipmap;
+  bool _supports_render_texture;
 
 
 public:
 public:
   // Statistics
   // Statistics

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

@@ -51,8 +51,6 @@ ParasiteBuffer(GraphicsOutput *host, const string &name,
 
 
   _is_valid = true;
   _is_valid = true;
 
 
-  setup_copy_texture(_name);
-
   nassertv(_x_size <= host->get_x_size() && _y_size <= host->get_y_size());
   nassertv(_x_size <= host->get_x_size() && _y_size <= host->get_y_size());
 }
 }
 
 

+ 2 - 2
panda/src/glxdisplay/glxGraphicsPipe.cxx

@@ -304,13 +304,13 @@ make_window(GraphicsStateGuardian *gsg, const string &name) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 PT(GraphicsBuffer) glxGraphicsPipe::
 PT(GraphicsBuffer) glxGraphicsPipe::
 make_buffer(GraphicsStateGuardian *gsg, const string &name,
 make_buffer(GraphicsStateGuardian *gsg, const string &name,
-            int x_size, int y_size, bool want_texture) {
+            int x_size, int y_size) {
   if (!_is_valid) {
   if (!_is_valid) {
     return NULL;
     return NULL;
   }
   }
 
 
 #ifdef HAVE_GLXFBCONFIG
 #ifdef HAVE_GLXFBCONFIG
-  return new glxGraphicsBuffer(this, gsg, name, x_size, y_size, want_texture);
+  return new glxGraphicsBuffer(this, gsg, name, x_size, y_size);
 #else
 #else
   return NULL;
   return NULL;
 #endif  // HAVE_GLXFBCONFIG
 #endif  // HAVE_GLXFBCONFIG

+ 1 - 1
panda/src/glxdisplay/glxGraphicsPipe.h

@@ -112,7 +112,7 @@ protected:
                                          const string &name);
                                          const string &name);
   virtual PT(GraphicsBuffer) make_buffer(GraphicsStateGuardian *gsg, 
   virtual PT(GraphicsBuffer) make_buffer(GraphicsStateGuardian *gsg, 
                                          const string &name,
                                          const string &name,
-                                         int x_size, int y_size, bool want_texture);
+                                         int x_size, int y_size);
 
 
 private:
 private:
 #ifdef HAVE_GLXFBCONFIG
 #ifdef HAVE_GLXFBCONFIG

+ 4 - 0
panda/src/gsgbase/graphicsStateGuardianBase.h

@@ -45,6 +45,7 @@ class GeomTrifan;
 class GeomSphere;
 class GeomSphere;
 
 
 class PreparedGraphicsObjects;
 class PreparedGraphicsObjects;
+class GraphicsOutput;
 class TextureContext;
 class TextureContext;
 class Texture;
 class Texture;
 class PixelBuffer;
 class PixelBuffer;
@@ -169,6 +170,9 @@ public:
   virtual void copy_texture(Texture *tex, const DisplayRegion *dr,
   virtual void copy_texture(Texture *tex, const DisplayRegion *dr,
                             const RenderBuffer &rb)=0;
                             const RenderBuffer &rb)=0;
 
 
+  virtual bool framebuffer_bind_to_texture(GraphicsOutput *win, Texture *tex)=0;
+  virtual void framebuffer_release_texture(GraphicsOutput *win, Texture *tex)=0;
+
   virtual void texture_to_pixel_buffer(TextureContext *tc, PixelBuffer *pb)=0;
   virtual void texture_to_pixel_buffer(TextureContext *tc, PixelBuffer *pb)=0;
   virtual void texture_to_pixel_buffer(TextureContext *tc, PixelBuffer *pb,
   virtual void texture_to_pixel_buffer(TextureContext *tc, PixelBuffer *pb,
                                 const DisplayRegion *dr)=0;
                                 const DisplayRegion *dr)=0;

+ 2 - 2
panda/src/mesadisplay/osMesaGraphicsBuffer.cxx

@@ -31,8 +31,8 @@ TypeHandle OsMesaGraphicsBuffer::_type_handle;
 OsMesaGraphicsBuffer::
 OsMesaGraphicsBuffer::
 OsMesaGraphicsBuffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
 OsMesaGraphicsBuffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
                      const string &name,
                      const string &name,
-                     int x_size, int y_size, bool want_texture) :
-  GraphicsBuffer(pipe, gsg, name, x_size, y_size, want_texture) 
+                     int x_size, int y_size) :
+  GraphicsBuffer(pipe, gsg, name, x_size, y_size) 
 {
 {
   _type = GL_UNSIGNED_BYTE;
   _type = GL_UNSIGNED_BYTE;
 }
 }

+ 1 - 1
panda/src/mesadisplay/osMesaGraphicsBuffer.h

@@ -34,7 +34,7 @@ class EXPCL_PANDAMESA OsMesaGraphicsBuffer : public GraphicsBuffer {
 public:
 public:
   OsMesaGraphicsBuffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
   OsMesaGraphicsBuffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
                        const string &name,
                        const string &name,
-                       int x_size, int y_size, bool want_texture);
+                       int x_size, int y_size);
 
 
   virtual ~OsMesaGraphicsBuffer();
   virtual ~OsMesaGraphicsBuffer();
 
 

+ 2 - 2
panda/src/mesadisplay/osMesaGraphicsPipe.cxx

@@ -125,6 +125,6 @@ make_gsg(const FrameBufferProperties &properties,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 PT(GraphicsBuffer) OsMesaGraphicsPipe::
 PT(GraphicsBuffer) OsMesaGraphicsPipe::
 make_buffer(GraphicsStateGuardian *gsg, const string &name,
 make_buffer(GraphicsStateGuardian *gsg, const string &name,
-            int x_size, int y_size, bool want_texture) {
-  return new OsMesaGraphicsBuffer(this, gsg, name, x_size, y_size, want_texture);
+            int x_size, int y_size) {
+  return new OsMesaGraphicsBuffer(this, gsg, name, x_size, y_size);
 }
 }

+ 1 - 1
panda/src/mesadisplay/osMesaGraphicsPipe.h

@@ -50,7 +50,7 @@ protected:
                                              GraphicsStateGuardian *share_with);
                                              GraphicsStateGuardian *share_with);
   virtual PT(GraphicsBuffer) make_buffer(GraphicsStateGuardian *gsg, 
   virtual PT(GraphicsBuffer) make_buffer(GraphicsStateGuardian *gsg, 
                                          const string &name,
                                          const string &name,
-                                         int x_size, int y_size, bool want_texture);
+                                         int x_size, int y_size);
 
 
 private:
 private:
 
 

+ 2 - 83
panda/src/wgldisplay/wglGraphicsBuffer.cxx

@@ -34,8 +34,8 @@ TypeHandle wglGraphicsBuffer::_type_handle;
 wglGraphicsBuffer::
 wglGraphicsBuffer::
 wglGraphicsBuffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
 wglGraphicsBuffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
                   const string &name,
                   const string &name,
-                  int x_size, int y_size, bool want_texture) :
-  GraphicsBuffer(pipe, gsg, name, x_size, y_size, want_texture) 
+                  int x_size, int y_size) :
+  GraphicsBuffer(pipe, gsg, name, x_size, y_size) 
 {
 {
   _pbuffer = (HPBUFFERARB)0;
   _pbuffer = (HPBUFFERARB)0;
   _pbuffer_dc = (HDC)0;
   _pbuffer_dc = (HDC)0;
@@ -73,12 +73,6 @@ begin_frame() {
   wglGraphicsStateGuardian *wglgsg;
   wglGraphicsStateGuardian *wglgsg;
   DCAST_INTO_R(wglgsg, _gsg, false);
   DCAST_INTO_R(wglgsg, _gsg, false);
 
 
-  if (_render_texture) {
-    // Release the texture so we can render into the pbuffer.
-    //    wglgsg->_wglReleaseTexImageARB(_pbuffer, get_draw_buffer_type() == RenderBuffer::T_back ? WGL_BACK_LEFT_ARB : WGL_FRONT_LEFT_ARB);
-    wglgsg->_wglReleaseTexImageARB(_pbuffer, WGL_FRONT_LEFT_ARB);
-  }
-
   if (_pbuffer_dc) {
   if (_pbuffer_dc) {
     int flag = 0;
     int flag = 0;
     wglgsg->_wglQueryPbufferARB(_pbuffer, WGL_PBUFFER_LOST_ARB, &flag);
     wglgsg->_wglQueryPbufferARB(_pbuffer, WGL_PBUFFER_LOST_ARB, &flag);
@@ -95,81 +89,6 @@ begin_frame() {
   return GraphicsBuffer::begin_frame();
   return GraphicsBuffer::begin_frame();
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: wglGraphicsBuffer::end_frame
-//       Access: Public, Virtual
-//  Description: This function will be called within the draw thread
-//               after rendering is completed for a given frame.  It
-//               should do whatever finalization is required.
-////////////////////////////////////////////////////////////////////
-void wglGraphicsBuffer::
-end_frame() {
-  nassertv(_gsg != (GraphicsStateGuardian *)NULL);
-  _gsg->end_frame();
-
-  wglGraphicsStateGuardian *wglgsg;
-  DCAST_INTO_V(wglgsg, _gsg);
-
-  // If we've lost the pbuffer image (due to a mode-switch, for
-  // instance), don't attempt to copy it to the texture, since the
-  // frame is invalid.  In fact, now we need to recreate the
-  // pbuffer.
-  if (_pbuffer_dc) {
-    int flag = 0;
-    wglgsg->_wglQueryPbufferARB(_pbuffer, WGL_PBUFFER_LOST_ARB, &flag);
-    if (flag != 0) {
-      wgldisplay_cat.info()
-        << "Pbuffer contents lost.\n";
-      return;
-    }
-  }
-  
-  if (_copy_texture) {
-    nassertv(has_texture());
-    Texture *tex = get_texture();
-
-    if (_render_texture) {
-      // Bind the pbuffer to our associated texture.  This is a newer
-      // extension that might allow us to use the same memory directly
-      // without having to pay for a copy operation.  But we can't
-      // render again to the pbuffer while the texture is valid.
-      TextureContext *tc = tex->prepare_now(wglgsg->get_prepared_objects(), wglgsg);
-      nassertv(tc != (TextureContext *)NULL);
-      wglgsg->bind_texture(tc);
-
-      //      wglgsg->_wglBindTexImageARB(_pbuffer, get_draw_buffer_type() == RenderBuffer::T_back ? WGL_BACK_LEFT_ARB : WGL_FRONT_LEFT_ARB);
-      wglgsg->_wglBindTexImageARB(_pbuffer, WGL_FRONT_LEFT_ARB);
-      
-    } else {
-      // Copy the contents of the frame buffer to our associated
-      // texture.  This is an older interface that guarantees a copy
-      // operation will take place, and it might even require
-      // reformatting pixels on the way, so it may be slower.
-      if (display_cat.is_debug()) {
-        display_cat.debug()
-          << "Copying texture for " << (void *)this << " at frame end.\n";
-      }
-      PStatTimer timer(_copy_texture_pcollector);
-      RenderBuffer buffer = wglgsg->get_render_buffer(get_draw_buffer_type());
-      wglgsg->copy_texture(tex, _default_display_region, buffer);
-    }
-  }
-
-  // If we're not single-buffered, we're now ready to flip.
-  if (!_gsg->get_properties().is_single_buffered()) {
-    _flip_ready = true;
-  }
-
-  if (_one_shot && !show_buffers) {
-    // In one-shot mode, we request the GraphicsEngine to delete the
-    // window after we have rendered a frame.  But when show-buffers
-    // mode is enabled, we don't do this, to give the user a chance to
-    // see the output.
-    _active = false;
-    _delete_flag = true;
-  }
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: wglGraphicsBuffer::make_current
 //     Function: wglGraphicsBuffer::make_current
 //       Access: Public, Virtual
 //       Access: Public, Virtual

+ 3 - 2
panda/src/wgldisplay/wglGraphicsBuffer.h

@@ -43,11 +43,10 @@ class EXPCL_PANDAGL wglGraphicsBuffer : public GraphicsBuffer {
 public:
 public:
   wglGraphicsBuffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
   wglGraphicsBuffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
                     const string &name,
                     const string &name,
-                    int x_size, int y_size, bool want_texture);
+                    int x_size, int y_size);
   virtual ~wglGraphicsBuffer();
   virtual ~wglGraphicsBuffer();
 
 
   virtual bool begin_frame();
   virtual bool begin_frame();
-  virtual void end_frame();
 
 
   virtual void make_current();
   virtual void make_current();
   virtual void release_gsg();
   virtual void release_gsg();
@@ -84,6 +83,8 @@ public:
 
 
 private:
 private:
   static TypeHandle _type_handle;
   static TypeHandle _type_handle;
+
+  friend class wglGraphicsStateGuardian;
 };
 };
 
 
 #include "wglGraphicsBuffer.I"
 #include "wglGraphicsBuffer.I"

+ 2 - 2
panda/src/wgldisplay/wglGraphicsPipe.cxx

@@ -206,8 +206,8 @@ make_window(GraphicsStateGuardian *gsg, const string &name) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 PT(GraphicsBuffer) wglGraphicsPipe::
 PT(GraphicsBuffer) wglGraphicsPipe::
 make_buffer(GraphicsStateGuardian *gsg, const string &name,
 make_buffer(GraphicsStateGuardian *gsg, const string &name,
-            int x_size, int y_size, bool want_texture) {
-  return new wglGraphicsBuffer(this, gsg, name, x_size, y_size, want_texture);
+            int x_size, int y_size) {
+  return new wglGraphicsBuffer(this, gsg, name, x_size, y_size);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

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

@@ -45,7 +45,7 @@ protected:
                                          const string &name);
                                          const string &name);
   virtual PT(GraphicsBuffer) make_buffer(GraphicsStateGuardian *gsg, 
   virtual PT(GraphicsBuffer) make_buffer(GraphicsStateGuardian *gsg, 
                                          const string &name,
                                          const string &name,
-                                         int x_size, int y_size, bool want_texture);
+                                         int x_size, int y_size);
 private:
 private:
   static int choose_pfnum(const FrameBufferProperties &properties, HDC hdc);
   static int choose_pfnum(const FrameBufferProperties &properties, HDC hdc);
   static int try_for_pfnum(HDC hdc, bool hardware, bool software, 
   static int try_for_pfnum(HDC hdc, bool hardware, bool software, 

+ 55 - 1
panda/src/wgldisplay/wglGraphicsStateGuardian.cxx

@@ -17,6 +17,7 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 #include "wglGraphicsStateGuardian.h"
 #include "wglGraphicsStateGuardian.h"
+#include "wglGraphicsBuffer.h"
 #include "string_utils.h"
 #include "string_utils.h"
 
 
 TypeHandle wglGraphicsStateGuardian::_type_handle;
 TypeHandle wglGraphicsStateGuardian::_type_handle;
@@ -46,7 +47,6 @@ wglGraphicsStateGuardian(const FrameBufferProperties &properties,
   _supports_pbuffer = false;
   _supports_pbuffer = false;
   _supports_pixel_format = false;
   _supports_pixel_format = false;
   _supports_wgl_multisample = false;
   _supports_wgl_multisample = false;
-  _supports_render_texture = false;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -63,6 +63,60 @@ wglGraphicsStateGuardian::
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: wglGraphicsStateGuardian::framebuffer_bind_to_texture
+//       Access: Public, Virtual
+//  Description: Works in lieu of copy_texture() to bind the primary
+//               render buffer of the framebuffer to the indicated
+//               texture (which must have been created via
+//               GraphicsOutput::setup_render_texture()).
+//
+//               If supported by the graphics backend, this will make
+//               the framebuffer memory directly accessible within the
+//               texture, but the frame cannot be rendered again until
+//               framebuffer_release_texture() is called.
+//
+//               The return value is true if successful, false on
+//               failure.
+////////////////////////////////////////////////////////////////////
+bool wglGraphicsStateGuardian::
+framebuffer_bind_to_texture(GraphicsOutput *win, Texture *tex) {
+  wglGraphicsBuffer *buffer;
+  DCAST_INTO_R(buffer, win, false);
+
+  TextureContext *tc = tex->prepare_now(get_prepared_objects(), this);
+  nassertr(tc != (TextureContext *)NULL, false);
+  bind_texture(tc);
+  
+  if (get_properties().is_single_buffered()) {
+    _wglBindTexImageARB(buffer->_pbuffer, WGL_FRONT_LEFT_ARB);
+  } else {
+    _wglBindTexImageARB(buffer->_pbuffer, WGL_BACK_LEFT_ARB);
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: wglGraphicsStateGuardian::framebuffer_release_texture
+//       Access: Public, Virtual
+//  Description: Undoes a previous call to
+//               framebuffer_bind_to_texture().  The framebuffer may
+//               again be rendered into, and the contents of the
+//               texture is undefined.
+////////////////////////////////////////////////////////////////////
+void wglGraphicsStateGuardian::
+framebuffer_release_texture(GraphicsOutput *win, Texture *) {
+  wglGraphicsBuffer *buffer;
+  DCAST_INTO_V(buffer, win);
+
+  if (get_properties().is_single_buffered()) {
+    _wglReleaseTexImageARB(buffer->_pbuffer, WGL_FRONT_LEFT_ARB);
+  } else {
+    _wglReleaseTexImageARB(buffer->_pbuffer, WGL_BACK_LEFT_ARB);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: wglGraphicsStateGuardian::reset
 //     Function: wglGraphicsStateGuardian::reset
 //       Access: Public, Virtual
 //       Access: Public, Virtual

+ 3 - 1
panda/src/wgldisplay/wglGraphicsStateGuardian.h

@@ -43,6 +43,9 @@ public:
   INLINE bool made_context() const;
   INLINE bool made_context() const;
   INLINE HGLRC get_context(HDC hdc);
   INLINE HGLRC get_context(HDC hdc);
 
 
+  virtual bool framebuffer_bind_to_texture(GraphicsOutput *win, Texture *tex);
+  virtual void framebuffer_release_texture(GraphicsOutput *win, Texture *tex);
+
   virtual void reset();
   virtual void reset();
 
 
   INLINE HDC get_twindow_dc();
   INLINE HDC get_twindow_dc();
@@ -95,7 +98,6 @@ public:
 
 
   bool _supports_wgl_multisample;
   bool _supports_wgl_multisample;
 
 
-  bool _supports_render_texture;
   PFNWGLBINDTEXIMAGEARBPROC _wglBindTexImageARB;
   PFNWGLBINDTEXIMAGEARBPROC _wglBindTexImageARB;
   PFNWGLRELEASETEXIMAGEARBPROC _wglReleaseTexImageARB;
   PFNWGLRELEASETEXIMAGEARBPROC _wglReleaseTexImageARB;
   PFNWGLSETPBUFFERATTRIBARBPROC _wglSetPbufferAttribARB;
   PFNWGLSETPBUFFERATTRIBARBPROC _wglSetPbufferAttribARB;