Переглянути джерело

add GraphicsOutput::make_texture_buffer()

David Rose 22 роки тому
батько
коміт
2bf87f010a

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

@@ -81,6 +81,24 @@ const string screenshot_extension = config_display.GetString("screenshot-extensi
 // interactively.  Handy during development of multipass algorithms.
 const bool show_buffers = config_display.GetBool("show-buffers", false);
 
+// Set this true to make GraphicsOutput::make_render_texture() try to
+// create a parasite buffer before it tries to create an offscreen
+// buffer.  This may be desired if you know your graphics API does not
+// support render-directly-to-texture and you want to minimize
+// framebuffer memory.
+const bool prefer_parasite_buffer = config_display.GetBool("prefer-parasite-buffer", false);
+
+// Set this true to make GraphicsOutput::make_render_texture() first
+// try to create a single-buffered offscreen buffer, before falling
+// back to a double-buffered one (or whatever kind the source window
+// has).  This is true by default to reduce waste of framebuffer
+// memory, but you may get a performance benefit by setting it to
+// false (since in that case the buffer can share a graphics context
+// with the window).
+const bool prefer_single_buffer = config_display.GetBool("prefer-single-buffer", true);
+
+
+
 // Use the variable load-display to specify the name of the default
 // graphics display library or GraphicsPipe to load.  It is the name
 // of a shared library (or * for all libraries named in aux-display),

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

@@ -42,6 +42,9 @@ extern const string screenshot_extension;
 
 extern const bool show_buffers;
 
+extern const bool prefer_parasite_buffer;
+extern const bool prefer_single_buffer;
+
 extern EXPCL_PANDA const bool multiple_windows;
 
 extern EXPCL_PANDA void init_libdisplay();

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

@@ -298,6 +298,94 @@ get_display_region(int n) const {
   return result;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::make_texture_buffer
+//       Access: Published
+//  Description: Creates and returns an offscreen buffer for rendering
+//               into, the result of which will be a texture suitable
+//               for applying to geometry within the scene rendered
+//               into this window.
+//
+//               This will attempt to be smart about maximizing render
+//               performance while minimizing framebuffer waste.  It
+//               might return a GraphicsBuffer set to render directly
+//               into a texture, if possible; or it might return a
+//               ParasiteBuffer that renders into this window.  The
+//               return value is NULL if the buffer could not be
+//               created for some reason.
+//
+//               Assuming the return value is not NULL, the texture
+//               that is represents the scene rendered to the new
+//               buffer can be accessed by buffer->get_texture().
+//               When you are done using the buffer, you should remove
+//               it with a call to GraphicsEngine::remove_window().
+////////////////////////////////////////////////////////////////////
+GraphicsOutput *GraphicsOutput::
+make_texture_buffer(const string &name, int x_size, int y_size) {
+  GraphicsStateGuardian *gsg = get_gsg();
+  GraphicsEngine *engine = gsg->get_engine();
+  GraphicsOutput *host = get_host();
+
+  // The new buffer should be drawn before this buffer is drawn.  If
+  // the user requires more control than this, he can set the sort
+  // value himself.
+  int sort = get_sort() - 1;
+
+  if (show_buffers) {
+    // If show_buffers is true, just go ahead and call make_buffer(),
+    // since it all amounts to the same thing anyway--this will
+    // actually create a new GraphicsWindow.
+    return engine->make_buffer(gsg, name, sort, x_size, y_size, true);
+  }
+
+  GraphicsOutput *buffer = NULL;
+
+  // If the user so indicated in the Configrc file, try to create a
+  // parasite buffer first.  We can only do this if the requested size
+  // fits within the available framebuffer size.
+  if (prefer_parasite_buffer && 
+      (x_size <= host->get_x_size() && y_size <= host->get_y_size())) {
+    buffer = engine->make_parasite(host, name, sort, x_size, y_size);
+    if (buffer != (GraphicsOutput *)NULL) {
+      return buffer;
+    }
+  }
+
+  // Attempt to create a single-buffered offscreen buffer.
+  if (prefer_single_buffer) {
+    FrameBufferProperties sb_props = gsg->get_properties();
+    int orig_mode = sb_props.get_frame_buffer_mode();
+    int sb_mode = (orig_mode & ~FrameBufferProperties::FM_buffer) | FrameBufferProperties::FM_single_buffer;
+    sb_props.set_frame_buffer_mode(sb_mode);
+    
+    if (sb_mode != orig_mode) {
+      PT(GraphicsStateGuardian) sb_gsg = 
+        engine->make_gsg(gsg->get_pipe(), sb_props, gsg);
+      if (sb_gsg != (GraphicsStateGuardian *)NULL) {
+        buffer = engine->make_buffer(sb_gsg, name, sort, x_size, y_size, true);
+        if (buffer != (GraphicsOutput *)NULL) {
+          return buffer;
+        }
+      }
+    }
+  }
+
+  // All right, attempt to create an offscreen buffer, using the same
+  // GSG.  This will be a double-buffered offscreen buffer, if the
+  // source window is double-buffered.
+  buffer = engine->make_buffer(gsg, name, sort, x_size, y_size, true);
+  if (buffer != (GraphicsOutput *)NULL) {
+    return buffer;
+  }
+
+  // Looks like we have to settle for a parasite buffer.
+  if (x_size <= host->get_x_size() && y_size <= host->get_y_size()) {
+    return engine->make_parasite(host, name, sort, x_size, y_size);
+  }
+
+  return NULL;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsOutput::make_scratch_display_region
 //       Access: Public
@@ -325,6 +413,20 @@ make_scratch_display_region(int x_size, int y_size) {
   region->copy_clear_settings(*this);
   return region;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::get_host
+//       Access: Public, Virtual
+//  Description: This is normally called only from within
+//               make_texture_buffer().  When called on a
+//               ParasiteBuffer, it returns the host of that buffer;
+//               but when called on some other buffer, it returns the
+//               buffer itself.
+////////////////////////////////////////////////////////////////////
+GraphicsOutput *GraphicsOutput::
+get_host() {
+  return this;
+}
  
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsOutput::request_open

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

@@ -95,6 +95,8 @@ PUBLISHED:
   int get_num_display_regions() const;
   DisplayRegion *get_display_region(int n) const;
 
+  GraphicsOutput *make_texture_buffer(const string &name, int x_size, int y_size);
+
   INLINE Filename save_screenshot_default(const string &prefix = "screenshot");
   INLINE bool save_screenshot(const Filename &filename);
   INLINE bool get_screenshot(PNMImage &image);
@@ -109,6 +111,8 @@ public:
 
   INLINE bool operator < (const GraphicsOutput &other) const;
 
+  virtual GraphicsOutput *get_host();
+
   virtual void request_open();
   virtual void request_close();
 

+ 15 - 1
panda/src/display/parasiteBuffer.cxx

@@ -54,7 +54,7 @@ ParasiteBuffer(GraphicsOutput *host, const string &name,
 
   _is_valid = true;
 
-  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());
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -77,6 +77,20 @@ is_active() const {
   return _host->is_active();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: ParasiteBuffer::get_host
+//       Access: Public, Virtual
+//  Description: This is normally called only from within
+//               make_texture_buffer().  When called on a
+//               ParasiteBuffer, it returns the host of that buffer;
+//               but when called on some other buffer, it returns the
+//               buffer itself.
+////////////////////////////////////////////////////////////////////
+GraphicsOutput *ParasiteBuffer::
+get_host() {
+  return _host;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: ParasiteBuffer::make_current
 //       Access: Public, Virtual

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

@@ -63,6 +63,7 @@ PUBLISHED:
   virtual bool is_active() const;
 
 public:
+  virtual GraphicsOutput *get_host();
   virtual void make_current();
 
 private: