Kaynağa Gözat

FBO changes

Josh Yelon 20 yıl önce
ebeveyn
işleme
cfdd323a13

+ 28 - 2
doc/makepanda/makepanda.py

@@ -2344,6 +2344,18 @@ EnqueueIgate(ipath=IPATH, opts=OPTS, outd='liblerp.in', obj='liblerp_igate.obj',
             src='panda/src/lerp',  module='panda', library='liblerp',
             src='panda/src/lerp',  module='panda', library='liblerp',
             skip=["lerp_headers.h","lerpchans.h"], also=["lerp_composite.cxx"])
             skip=["lerp_headers.h","lerpchans.h"], also=["lerp_composite.cxx"])
 
 
+#
+# DIRECTORY: panda/src/cull/
+#
+
+IPATH=['panda/src/cull']
+OPTS=['BUILDING_PANDA', 'NSPR']
+CopyAllHeaders('panda/src/cull')
+EnqueueCxx(ipath=IPATH, opts=OPTS, src='cull_composite.cxx', obj='cull_composite.obj')
+EnqueueIgate(ipath=IPATH, opts=OPTS, outd='libcull.in', obj='libcull_igate.obj',
+            src='panda/src/cull',  module='panda', library='libcull',
+            skip=[], also=["cull_composite.cxx"])
+
 #
 #
 # DIRECTORY: panda/src/pgraph/
 # DIRECTORY: panda/src/pgraph/
 #
 #
@@ -2425,6 +2437,18 @@ EnqueueIgate(ipath=IPATH, opts=OPTS, outd='libdisplay.in', obj='libdisplay_igate
             src='panda/src/display',  module='panda', library='libdisplay',
             src='panda/src/display',  module='panda', library='libdisplay',
             skip=['renderBuffer.h'], also=["display_composite.cxx"])
             skip=['renderBuffer.h'], also=["display_composite.cxx"])
 
 
+#
+# DIRECTORY: panda/src/display/
+#
+
+IPATH=['panda/src/pipeline']
+OPTS=['BUILDING_PANDA', 'NSPR']
+CopyAllHeaders('panda/src/pipeline')
+EnqueueCxx(ipath=IPATH, opts=OPTS, src='pipeline_composite.cxx', obj='pipeline_composite.obj')
+EnqueueIgate(ipath=IPATH, opts=OPTS, outd='libpipeline.in', obj='libpipeline_igate.obj',
+            src='panda/src/pipeline',  module='panda', library='libpipeline',
+            skip=[], also=["pipeline_composite.cxx"])
+
 #
 #
 # DIRECTORY: panda/src/device/
 # DIRECTORY: panda/src/device/
 #
 #
@@ -2601,8 +2625,8 @@ CopyAllHeaders('panda/src/particlesystem')
 IPATH=['panda/metalibs/panda']
 IPATH=['panda/metalibs/panda']
 OPTS=['BUILDING_PANDA', 'ZLIB', 'VRPN', 'JPEG', 'PNG', 'TIFF', 'NSPR', 'FREETYPE', 'HELIX', 'FFTW', 'OPENCV',
 OPTS=['BUILDING_PANDA', 'ZLIB', 'VRPN', 'JPEG', 'PNG', 'TIFF', 'NSPR', 'FREETYPE', 'HELIX', 'FFTW', 'OPENCV',
       'ADVAPI', 'WINSOCK2', 'WINUSER', 'WINMM']
       'ADVAPI', 'WINSOCK2', 'WINUSER', 'WINMM']
-INFILES=['librecorder.in', 'libpgraph.in', 'libgrutil.in', 'libchan.in', 'libpstatclient.in',
-         'libchar.in', 'libcollide.in', 'libdevice.in', 'libdgraph.in', 'libdisplay.in', 'libevent.in',
+INFILES=['librecorder.in', 'libpgraph.in', 'libcull.in', 'libgrutil.in', 'libchan.in', 'libpstatclient.in',
+         'libchar.in', 'libcollide.in', 'libdevice.in', 'libdgraph.in', 'libdisplay.in', 'libpipeline.in', 'libevent.in',
          'libgobj.in', 'libgsgbase.in', 'liblinmath.in', 'libmathutil.in', 'libparametrics.in',
          'libgobj.in', 'libgsgbase.in', 'liblinmath.in', 'libmathutil.in', 'libparametrics.in',
          'libpnmimage.in', 'libtext.in', 'libtform.in', 'liblerp.in', 'libputil.in', 'libaudio.in',
          'libpnmimage.in', 'libtext.in', 'libtform.in', 'liblerp.in', 'libputil.in', 'libaudio.in',
          'libpgui.in']
          'libpgui.in']
@@ -2610,6 +2634,7 @@ OBJFILES=['panda_panda.obj', 'libpanda_module.obj',
           'recorder_composite.obj', 'librecorder_igate.obj',
           'recorder_composite.obj', 'librecorder_igate.obj',
           'pgraph_nodePath.obj', 
           'pgraph_nodePath.obj', 
           'pgraph_composite1.obj', 'pgraph_composite2.obj', 'pgraph_composite3.obj', 'pgraph_composite4.obj', 'libpgraph_igate.obj',
           'pgraph_composite1.obj', 'pgraph_composite2.obj', 'pgraph_composite3.obj', 'pgraph_composite4.obj', 'libpgraph_igate.obj',
+          'cull_composite.obj',
           'grutil_multitexReducer.obj', 'grutil_composite.obj', 'libgrutil_igate.obj',
           'grutil_multitexReducer.obj', 'grutil_composite.obj', 'libgrutil_igate.obj',
           'chan_composite.obj', 'libchan_igate.obj',
           'chan_composite.obj', 'libchan_igate.obj',
           'pstatclient_composite.obj', 'libpstatclient_igate.obj',
           'pstatclient_composite.obj', 'libpstatclient_igate.obj',
@@ -2618,6 +2643,7 @@ OBJFILES=['panda_panda.obj', 'libpanda_module.obj',
           'device_composite.obj', 'libdevice_igate.obj',
           'device_composite.obj', 'libdevice_igate.obj',
           'dgraph_composite.obj', 'libdgraph_igate.obj',
           'dgraph_composite.obj', 'libdgraph_igate.obj',
           'display_composite.obj', 'libdisplay_igate.obj',
           'display_composite.obj', 'libdisplay_igate.obj',
+          'pipeline_composite.obj', 'libpipeline_igate.obj',
           'event_composite.obj', 'libevent_igate.obj',
           'event_composite.obj', 'libevent_igate.obj',
           'gobj_composite1.obj', 'gobj_composite2.obj', 'libgobj_igate.obj',
           'gobj_composite1.obj', 'gobj_composite2.obj', 'libgobj_igate.obj',
           'gsgbase_composite.obj', 'libgsgbase_igate.obj',
           'gsgbase_composite.obj', 'libgsgbase_igate.obj',

+ 2 - 0
panda/src/cull/cull_composite.cxx

@@ -0,0 +1,2 @@
+#include "cull_composite1.cxx"
+#include "cull_composite2.cxx"

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

@@ -47,9 +47,6 @@ extern EXPCL_PANDA ConfigVariableBool yield_timeslice;
 extern EXPCL_PANDA ConfigVariableString screenshot_filename;
 extern EXPCL_PANDA ConfigVariableString screenshot_filename;
 extern EXPCL_PANDA ConfigVariableString screenshot_extension;
 extern EXPCL_PANDA ConfigVariableString screenshot_extension;
 
 
-// I'll remove this permanently in a few days. - Josh
-// extern EXPCL_PANDA ConfigVariableBool show_buffers;
-
 extern EXPCL_PANDA ConfigVariableBool prefer_texture_buffer;
 extern EXPCL_PANDA ConfigVariableBool prefer_texture_buffer;
 extern EXPCL_PANDA ConfigVariableBool prefer_parasite_buffer;
 extern EXPCL_PANDA ConfigVariableBool prefer_parasite_buffer;
 extern EXPCL_PANDA ConfigVariableBool prefer_single_buffer;
 extern EXPCL_PANDA ConfigVariableBool prefer_single_buffer;

+ 27 - 0
panda/src/display/frameBufferProperties.I

@@ -123,6 +123,20 @@ is_single_buffered() const {
   return (_frame_buffer_mode & FM_buffer) == FM_single_buffer;
   return (_frame_buffer_mode & FM_buffer) == FM_single_buffer;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: FrameBufferProperties::has_mode
+//       Access: Published
+//  Description: Returns true if the frame buffer mode, logically
+//               anded with the given mask, is nonzero.  This is a
+//               convenience function to access this useful tidbit of
+//               data.
+////////////////////////////////////////////////////////////////////
+INLINE bool FrameBufferProperties::
+has_mode(int bits) const {
+  nassertr(has_frame_buffer_mode(), false);
+  return (_frame_buffer_mode & bits) != 0;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: FrameBufferProperties::is_stereo
 //     Function: FrameBufferProperties::is_stereo
 //       Access: Published
 //       Access: Published
@@ -514,6 +528,19 @@ clear_aux_float() {
   recalc_buffer_mask();
   recalc_buffer_mask();
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: FrameBufferProperties::set_specified
+//       Access: Published
+//  Description: Sets all the specified bits.  Effectively, this
+//               causes the default values to be specified for all
+//               not-yet-specified fields.
+////////////////////////////////////////////////////////////////////
+INLINE void FrameBufferProperties::
+set_specified() {
+  _specified = S_ALL_SPECIFIED;
+  recalc_buffer_mask();
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: FrameBufferProperties::get_buffer_mask
 //     Function: FrameBufferProperties::get_buffer_mask
 //       Access: Public
 //       Access: Public

+ 13 - 0
panda/src/display/frameBufferProperties.cxx

@@ -51,6 +51,19 @@ operator = (const FrameBufferProperties &copy) {
   _buffer_mask = copy._buffer_mask;
   _buffer_mask = copy._buffer_mask;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: FrameBufferProperties::subsumes
+//       Access: Public
+//  Description: Returns true if this set of properties makes
+//               strictly greater or equal demands of the framebuffer
+//               than the other set of framebuffer properties.
+////////////////////////////////////////////////////////////////////
+bool FrameBufferProperties::
+subsumes(const FrameBufferProperties &other) const {
+  // NOT IMPLEMENTED YET
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: FrameBufferProperties::get_default
 //     Function: FrameBufferProperties::get_default
 //       Access: Published, Static
 //       Access: Published, Static

+ 8 - 4
panda/src/display/frameBufferProperties.h

@@ -56,18 +56,21 @@ PUBLISHED:
     FM_software       = 0x0200,
     FM_software       = 0x0200,
     FM_hardware       = 0x0400,
     FM_hardware       = 0x0400,
   };
   };
-
+  
   void clear();
   void clear();
+  INLINE void set_specified();
   INLINE int get_buffer_mask() const;
   INLINE int get_buffer_mask() const;
   INLINE bool is_any_specified() const;
   INLINE bool is_any_specified() const;
-
+  INLINE bool has_mode(int bit) const;
+  INLINE bool is_single_buffered() const;
+  INLINE bool is_stereo() const;
+  bool subsumes(const FrameBufferProperties &prop) const;
+  
   INLINE void set_frame_buffer_mode(int frameBuffer_mode);
   INLINE void set_frame_buffer_mode(int frameBuffer_mode);
   INLINE int get_frame_buffer_mode() const;
   INLINE int get_frame_buffer_mode() const;
   INLINE bool has_frame_buffer_mode() const;
   INLINE bool has_frame_buffer_mode() const;
   INLINE void clear_frame_buffer_mode();
   INLINE void clear_frame_buffer_mode();
 
 
-  INLINE bool is_single_buffered() const;
-  INLINE bool is_stereo() const;
   INLINE void set_depth_bits(int depth_bits);
   INLINE void set_depth_bits(int depth_bits);
   INLINE int get_depth_bits() const;
   INLINE int get_depth_bits() const;
   INLINE bool has_depth_bits() const;
   INLINE bool has_depth_bits() const;
@@ -132,6 +135,7 @@ private:
     S_aux_rgba          = 0x0040,
     S_aux_rgba          = 0x0040,
     S_aux_hrgba         = 0x0080,
     S_aux_hrgba         = 0x0080,
     S_aux_float         = 0x0100,
     S_aux_float         = 0x0100,
+    S_ALL_SPECIFIED     = 0x01FF,
   };
   };
 
 
   int _specified;
   int _specified;

+ 17 - 7
panda/src/display/graphicsEngine.I

@@ -139,11 +139,20 @@ make_window(GraphicsStateGuardian *gsg, const string &name, int sort) {
 INLINE GraphicsOutput *GraphicsEngine::
 INLINE GraphicsOutput *GraphicsEngine::
 make_buffer(GraphicsStateGuardian *gsg, const string &name,
 make_buffer(GraphicsStateGuardian *gsg, const string &name,
             int sort, int x_size, int y_size) {
             int sort, int x_size, int y_size) {
-   GraphicsOutput *result = make_output(gsg->get_pipe(), name, sort,
-                                        gsg->get_default_properties(), x_size, y_size,
-                                        GraphicsPipe::BF_refuse_window,
-                                        gsg, NULL);
-   return result;
+  FrameBufferProperties props = gsg->get_default_properties();
+  int clear =
+        FrameBufferProperties::FM_buffer |
+        FrameBufferProperties::FM_stereo |
+        FrameBufferProperties::FM_accum |
+        FrameBufferProperties::FM_multisample |
+        FrameBufferProperties::FM_hardware |
+        FrameBufferProperties::FM_software;
+  props.set_frame_buffer_mode(props.get_frame_buffer_mode() & (~clear));
+  GraphicsOutput *result = make_output(gsg->get_pipe(), name, sort,
+                                       gsg->get_default_properties(), x_size, y_size,
+                                       GraphicsPipe::BF_refuse_window,
+                                       gsg, NULL);
+  return result;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -154,11 +163,12 @@ make_buffer(GraphicsStateGuardian *gsg, const string &name,
 INLINE GraphicsOutput *GraphicsEngine::
 INLINE GraphicsOutput *GraphicsEngine::
 make_parasite(GraphicsOutput *host, const string &name, 
 make_parasite(GraphicsOutput *host, const string &name, 
               int sort, int x_size, int y_size) {
               int sort, int x_size, int y_size) {
+  FrameBufferProperties props;
   GraphicsOutput *result = make_output(host->get_pipe(), name, sort,
   GraphicsOutput *result = make_output(host->get_pipe(), name, sort,
-                                       host->get_fb_properties(), x_size, y_size,
+                                       props, x_size, y_size,
                                        GraphicsPipe::BF_require_parasite,
                                        GraphicsPipe::BF_require_parasite,
                                        host->get_gsg(), host);
                                        host->get_gsg(), host);
-   return result;
+  return result;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 11 - 3
panda/src/display/graphicsOutput.cxx

@@ -687,12 +687,20 @@ get_texture_card() {
 GraphicsOutput *GraphicsOutput::
 GraphicsOutput *GraphicsOutput::
 make_texture_buffer(const string &name, int x_size, int y_size,
 make_texture_buffer(const string &name, int x_size, int y_size,
                     Texture *tex, bool to_ram) {
                     Texture *tex, bool to_ram) {
-
+  FrameBufferProperties props = get_gsg()->get_default_properties();
+  int clear =
+    FrameBufferProperties::FM_buffer |
+    FrameBufferProperties::FM_stereo |
+    FrameBufferProperties::FM_accum |
+    FrameBufferProperties::FM_multisample |
+    FrameBufferProperties::FM_hardware |
+    FrameBufferProperties::FM_software;
+  props.set_frame_buffer_mode(props.get_frame_buffer_mode() & (~clear));  
+  
   GraphicsOutput *buffer = get_gsg()->get_engine()->
   GraphicsOutput *buffer = get_gsg()->get_engine()->
     make_output(get_gsg()->get_pipe(),
     make_output(get_gsg()->get_pipe(),
                 name, get_sort()-1,
                 name, get_sort()-1,
-                get_host()->get_fb_properties(),
-                x_size, y_size, GraphicsPipe::BF_refuse_window,
+                props, x_size, y_size, GraphicsPipe::BF_refuse_window,
                 get_gsg(), get_host());
                 get_gsg(), get_host());
 
 
   if (buffer != (GraphicsOutput *)NULL) {
   if (buffer != (GraphicsOutput *)NULL) {

+ 11 - 8
panda/src/display/graphicsPipe.h

@@ -75,16 +75,19 @@ PUBLISHED:
 
 
   enum BufferCreationFlags {
   enum BufferCreationFlags {
     // Flags that control what type of output is returned.
     // Flags that control what type of output is returned.
-    BF_refuse_parasite     = 0x00000100,
-    BF_require_parasite    = 0x00000200,
-    BF_refuse_window       = 0x00000400,
-    BF_require_window      = 0x00000800,
+    BF_refuse_parasite     = 0x0001,
+    BF_require_parasite    = 0x0002,
+    BF_refuse_window       = 0x0004,
+    BF_require_window      = 0x0008,
+
+    // Flags that control gsg creation.
+    BF_share_gsg           = 0x0010, // New window must use the old gsg.
+    BF_share_textures      = 0x0020, // New window must share textures with old gsg.
 
 
     // Miscellaneous control flags.
     // Miscellaneous control flags.
-    BF_can_bind_color      = 0x00010000, // Need capability: bind the color bitplane to a tex.
-    BF_can_bind_every      = 0x00020000, // Need capability: bind all bitplanes to a tex.
-    BF_size_track_host     = 0x00040000, // Buffer should track the host size.
-    BF_no_new_gsg          = 0x00080000, // Do not create a new gsg, no matter what.
+    BF_can_bind_color      = 0x0040, // Need capability: bind the color bitplane to a tex.
+    BF_can_bind_every      = 0x0080, // Need capability: bind all bitplanes to a tex.
+    BF_size_track_host     = 0x0100, // Buffer should track the host size.
   };
   };
 
 
   INLINE bool is_valid() const;
   INLINE bool is_valid() const;

+ 1 - 1
panda/src/express/atomicAdjust.h

@@ -30,7 +30,7 @@
 //               others to guarantee that a multibyte value is changed
 //               others to guarantee that a multibyte value is changed
 //               in one atomic operation.
 //               in one atomic operation.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA AtomicAdjust {
+class EXPCL_PANDAEXPRESS AtomicAdjust {
 public:
 public:
   INLINE static PN_int32 inc(PN_int32 &var);
   INLINE static PN_int32 inc(PN_int32 &var);
   INLINE static PN_int32 dec(PN_int32 &var);
   INLINE static PN_int32 dec(PN_int32 &var);

+ 1 - 1
panda/src/express/atomicAdjustDummyImpl.h

@@ -33,7 +33,7 @@
 //               systems that don't require multiprogramming, and
 //               systems that don't require multiprogramming, and
 //               therefore don't require special atomic operations.
 //               therefore don't require special atomic operations.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA AtomicAdjustDummyImpl {
+class EXPCL_PANDAEXPRESS AtomicAdjustDummyImpl {
 public:
 public:
   INLINE static PN_int32 inc(PN_int32 &var);
   INLINE static PN_int32 inc(PN_int32 &var);
   INLINE static PN_int32 dec(PN_int32 &var);
   INLINE static PN_int32 dec(PN_int32 &var);

+ 1 - 1
panda/src/express/atomicAdjustNsprImpl.h

@@ -33,7 +33,7 @@
 //       Class : AtomicAdjustNsprImpl
 //       Class : AtomicAdjustNsprImpl
 // Description : Uses NSPR to implement atomic adjustments.
 // Description : Uses NSPR to implement atomic adjustments.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA AtomicAdjustNsprImpl {
+class EXPCL_PANDAEXPRESS AtomicAdjustNsprImpl {
 public:
 public:
   INLINE static PN_int32 inc(PN_int32 &var);
   INLINE static PN_int32 inc(PN_int32 &var);
   INLINE static PN_int32 dec(PN_int32 &var);
   INLINE static PN_int32 dec(PN_int32 &var);

+ 1 - 1
panda/src/express/atomicAdjustPosixImpl.h

@@ -33,7 +33,7 @@
 //       Class : AtomicAdjustPosixImpl
 //       Class : AtomicAdjustPosixImpl
 // Description : Uses POSIX to implement atomic adjustments.
 // Description : Uses POSIX to implement atomic adjustments.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA AtomicAdjustPosixImpl {
+class EXPCL_PANDAEXPRESS AtomicAdjustPosixImpl {
 public:
 public:
   INLINE static PN_int32 inc(PN_int32 &var);
   INLINE static PN_int32 inc(PN_int32 &var);
   INLINE static PN_int32 dec(PN_int32 &var);
   INLINE static PN_int32 dec(PN_int32 &var);

+ 1 - 1
panda/src/express/atomicAdjustWin32Impl.h

@@ -34,7 +34,7 @@
 // Description : Uses Windows native calls to implement atomic
 // Description : Uses Windows native calls to implement atomic
 //               adjustments.
 //               adjustments.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA AtomicAdjustWin32Impl {
+class EXPCL_PANDAEXPRESS AtomicAdjustWin32Impl {
 public:
 public:
   INLINE static PN_int32 inc(PN_int32 &var);
   INLINE static PN_int32 inc(PN_int32 &var);
   INLINE static PN_int32 dec(PN_int32 &var);
   INLINE static PN_int32 dec(PN_int32 &var);

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

@@ -111,7 +111,7 @@ begin_frame(FrameMode mode) {
       default:
       default:
         GLCAT.error() << "OTHER PROBLEM\n"; break;
         GLCAT.error() << "OTHER PROBLEM\n"; break;
       }
       }
-      glgsg->_glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
+      glgsg->bind_fbo(0);
       return false;
       return false;
     }
     }
   }
   }
@@ -140,7 +140,7 @@ rebuild_bitplanes() {
       return;
       return;
     }
     }
   }
   }
-  glgsg->_glBindFramebuffer(GL_FRAMEBUFFER_EXT, _fbo);
+  glgsg->bind_fbo(_fbo);
 
 
   // Calculate bitplane size.  This can be larger than the buffer.
   // Calculate bitplane size.  This can be larger than the buffer.
 
 
@@ -185,7 +185,7 @@ rebuild_bitplanes() {
       slot = SLOT_depth;
       slot = SLOT_depth;
     } else if (fmt == Texture::F_stencil_index) {
     } else if (fmt == Texture::F_stencil_index) {
       slot = SLOT_stencil;
       slot = SLOT_stencil;
-    } else if (fmt == Texture::F_rgba) {
+    } else if ((fmt == Texture::F_rgba)||(fmt == Texture::F_rgb)) {
       slot = SLOT_color;
       slot = SLOT_color;
     } else {
     } else {
       _textures[i]._rtm_mode = RTM_copy_texture;
       _textures[i]._rtm_mode = RTM_copy_texture;
@@ -226,6 +226,7 @@ rebuild_bitplanes() {
       CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
       CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
       
       
       if (tex->get_texture_type() == Texture::TT_2d_texture) {
       if (tex->get_texture_type() == Texture::TT_2d_texture) {
+        glgsg->upload_blank_image(tex, gtc);
         glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, _attach_point[slot],
         glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, _attach_point[slot],
                                        GL_TEXTURE_2D, gtc->_index, 0);
                                        GL_TEXTURE_2D, gtc->_index, 0);
       } else {
       } else {
@@ -326,7 +327,7 @@ end_frame(FrameMode mode) {
   // Unbind the FBO
   // Unbind the FBO
   CLP(GraphicsStateGuardian) *glgsg;
   CLP(GraphicsStateGuardian) *glgsg;
   DCAST_INTO_V(glgsg, _gsg);
   DCAST_INTO_V(glgsg, _gsg);
-  glgsg->_glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
+  glgsg->bind_fbo(0);
   
   
   if (mode == FM_render) {
   if (mode == FM_render) {
     generate_mipmaps();
     generate_mipmaps();

+ 194 - 115
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -999,6 +999,7 @@ reset() {
   }
   }
   _current_vbuffer_index = 0;
   _current_vbuffer_index = 0;
   _current_ibuffer_index = 0;
   _current_ibuffer_index = 0;
+  _current_fbo = 0;
   _auto_antialias_mode = false;
   _auto_antialias_mode = false;
   _render_mode = RenderModeAttrib::M_filled;
   _render_mode = RenderModeAttrib::M_filled;
   _point_size = 1.0f;
   _point_size = 1.0f;
@@ -1122,7 +1123,7 @@ prepare_display_region(DisplayRegion *dr, Lens::StereoChannel stereo_channel) {
   enable_scissor(true);
   enable_scissor(true);
   GLP(Scissor)(x, y, width, height);
   GLP(Scissor)(x, y, width, height);
   GLP(Viewport)(x, y, width, height);
   GLP(Viewport)(x, y, width, height);
-
+  
   report_my_gl_errors();
   report_my_gl_errors();
   do_point_size();
   do_point_size();
 }
 }
@@ -2920,14 +2921,11 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
   TextureContext *tc = tex->prepare_now(get_prepared_objects(), this);
   TextureContext *tc = tex->prepare_now(get_prepared_objects(), this);
   nassertv(tc != (TextureContext *)NULL);
   nassertv(tc != (TextureContext *)NULL);
   CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
   CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
-  GLenum target = get_texture_target(tex->get_texture_type());
-  GLP(BindTexture)(target, gtc->_index);
-
-  GLint internal_format = get_internal_image_format(tex);
 
 
   if (z >= 0) {
   if (z >= 0) {
     // Copy to a cube map face.  This doesn't seem to work too well
     // Copy to a cube map face.  This doesn't seem to work too well
     // with CopyTexSubImage2D, so we always use CopyTexImage2D.
     // with CopyTexSubImage2D, so we always use CopyTexImage2D.
+    GLP(BindTexture)(GL_TEXTURE_CUBE_MAP_ARB, gtc->_index);
     GLP(CopyTexImage2D)(GL_TEXTURE_CUBE_MAP_POSITIVE_X + z, 0,
     GLP(CopyTexImage2D)(GL_TEXTURE_CUBE_MAP_POSITIVE_X + z, 0,
                         get_internal_image_format(tex),
                         get_internal_image_format(tex),
                         xo, yo, w, h, 0);
                         xo, yo, w, h, 0);
@@ -2937,42 +2935,8 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
     // cannot use glCopyTexImage2D to create a texture that may be
     // cannot use glCopyTexImage2D to create a texture that may be
     // larger than the screen, so use glTexImage2D with arbitrary
     // larger than the screen, so use glTexImage2D with arbitrary
     // data.
     // data.
-
-    if ((gtc->_already_applied == false)||
-        (gtc->_internal_format != internal_format)||
-        (gtc->_width  != tex->get_x_size())||
-        (gtc->_height != tex->get_y_size())||
-        (gtc->_depth  != 1)) {
-      
-      char *image = new char[tex->get_x_size() * tex->get_y_size()];
-      memset(image, 128, tex->get_x_size() * tex->get_y_size());
-      switch (tex->get_format()) {
-      case Texture::F_depth_component:
-        GLP(TexImage2D)(GL_TEXTURE_2D, 0, internal_format,
-                        tex->get_x_size(), tex->get_y_size(), 0,
-                        GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, image);
-        break;
-        
-      case Texture::F_stencil_index:
-        GLP(TexImage2D)(GL_TEXTURE_2D, 0, internal_format,
-                        tex->get_x_size(), tex->get_y_size(), 0,
-                        GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, image);
-        break;
-        
-      default:
-        GLP(TexImage2D)(GL_TEXTURE_2D, 0, internal_format,
-                        tex->get_x_size(), tex->get_y_size(), 0,
-                        GL_LUMINANCE, GL_UNSIGNED_BYTE, image);
-        break;
-      }
-      delete image;
-      
-      gtc->_already_applied = true;
-      gtc->_internal_format = internal_format;
-      gtc->_width  = tex->get_x_size();
-      gtc->_height = tex->get_y_size();
-      gtc->_depth  = 1;
-    }
+    GLP(BindTexture)(GL_TEXTURE_2D, gtc->_index);
+    upload_blank_image(tex, gtc);
 
 
     // Copy the pixel data from the frame buffer.
     // Copy the pixel data from the frame buffer.
     GLP(CopyTexSubImage2D)(GL_TEXTURE_2D, 0, 0, 0, xo, yo, w, h);
     GLP(CopyTexSubImage2D)(GL_TEXTURE_2D, 0, 0, 0, xo, yo, w, h);
@@ -2985,6 +2949,7 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
   _state._texture = 0;
   _state._texture = 0;
 }
 }
 
 
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::framebuffer_copy_to_ram
 //     Function: GLGraphicsStateGuardian::framebuffer_copy_to_ram
 //       Access: Public, Virtual
 //       Access: Public, Virtual
@@ -4151,45 +4116,64 @@ get_extension_func(const char *, const char *) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
 set_draw_buffer(const RenderBuffer &rb) {
 set_draw_buffer(const RenderBuffer &rb) {
-  switch (rb._buffer_type & RenderBuffer::T_color) {
-  case RenderBuffer::T_front:
-    GLP(DrawBuffer)(GL_FRONT);
-    break;
-    
-  case RenderBuffer::T_back:
-    GLP(DrawBuffer)(GL_BACK);
-    break;
-    
-  case RenderBuffer::T_right:
-    GLP(DrawBuffer)(GL_RIGHT);
-    break;
-    
-  case RenderBuffer::T_left:
-    GLP(DrawBuffer)(GL_LEFT);
-    break;
-    
-  case RenderBuffer::T_front_right:
-    nassertv(_current_properties->is_stereo());
-    GLP(DrawBuffer)(GL_FRONT_RIGHT);
-    break;
-    
-  case RenderBuffer::T_front_left:
-    nassertv(_current_properties->is_stereo());
-    GLP(DrawBuffer)(GL_FRONT_LEFT);
-    break;
-    
-  case RenderBuffer::T_back_right:
-    nassertv(_current_properties->is_stereo());
-    GLP(DrawBuffer)(GL_BACK_RIGHT);
-    break;
-    
-  case RenderBuffer::T_back_left:
-    nassertv(_current_properties->is_stereo());
-    GLP(DrawBuffer)(GL_BACK_LEFT);
-    break;
-    
-  default:
-    GLP(DrawBuffer)(GL_FRONT_AND_BACK);
+
+  if (_current_fbo) {
+
+    GLuint buffers[16];
+    int nbuffers = 0;
+    if (rb._buffer_type & RenderBuffer::T_front) {
+      nbuffers += 1;
+    }
+    nbuffers += _current_properties->get_aux_rgba();
+    nbuffers += _current_properties->get_aux_hrgba();
+    nbuffers += _current_properties->get_aux_float();
+    for (int i=0; i<nbuffers; i++) {
+      buffers[i] = GL_COLOR_ATTACHMENT0_EXT + i;
+    }
+    _glDrawBuffers(nbuffers, buffers);
+
+  } else {
+
+    switch (rb._buffer_type & RenderBuffer::T_color) {
+    case RenderBuffer::T_front:
+      GLP(DrawBuffer)(GL_FRONT);
+      break;
+      
+    case RenderBuffer::T_back:
+      GLP(DrawBuffer)(GL_BACK);
+      break;
+      
+    case RenderBuffer::T_right:
+      GLP(DrawBuffer)(GL_RIGHT);
+      break;
+      
+    case RenderBuffer::T_left:
+      GLP(DrawBuffer)(GL_LEFT);
+      break;
+      
+    case RenderBuffer::T_front_right:
+      nassertv(_current_properties->is_stereo());
+      GLP(DrawBuffer)(GL_FRONT_RIGHT);
+      break;
+      
+    case RenderBuffer::T_front_left:
+      nassertv(_current_properties->is_stereo());
+      GLP(DrawBuffer)(GL_FRONT_LEFT);
+      break;
+      
+    case RenderBuffer::T_back_right:
+      nassertv(_current_properties->is_stereo());
+      GLP(DrawBuffer)(GL_BACK_RIGHT);
+      break;
+      
+    case RenderBuffer::T_back_left:
+      nassertv(_current_properties->is_stereo());
+      GLP(DrawBuffer)(GL_BACK_LEFT);
+      break;
+      
+    default:
+      GLP(DrawBuffer)(GL_FRONT_AND_BACK);
+    }
   }
   }
 
 
   // Also ensure that any global color channels are masked out.
   // Also ensure that any global color channels are masked out.
@@ -4211,41 +4195,69 @@ set_draw_buffer(const RenderBuffer &rb) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
 set_read_buffer(const RenderBuffer &rb) {
 set_read_buffer(const RenderBuffer &rb) {
-  switch (rb._buffer_type & RenderBuffer::T_color) {
-  case RenderBuffer::T_front:
-    GLP(ReadBuffer)(GL_FRONT);
-    break;
-    
-  case RenderBuffer::T_back:
-    GLP(ReadBuffer)(GL_BACK);
-    break;
-    
-  case RenderBuffer::T_right:
-    GLP(ReadBuffer)(GL_RIGHT);
-    break;
-    
-  case RenderBuffer::T_left:
-    GLP(ReadBuffer)(GL_LEFT);
-    break;
-    
-  case RenderBuffer::T_front_right:
-    GLP(ReadBuffer)(GL_FRONT_RIGHT);
-    break;
-    
-  case RenderBuffer::T_front_left:
-    GLP(ReadBuffer)(GL_FRONT_LEFT);
-    break;
-    
-  case RenderBuffer::T_back_right:
-    GLP(ReadBuffer)(GL_BACK_RIGHT);
-    break;
-    
-  case RenderBuffer::T_back_left:
-    GLP(ReadBuffer)(GL_BACK_LEFT);
-    break;
-    
-  default:
-    GLP(ReadBuffer)(GL_FRONT_AND_BACK);
+
+  if (_current_fbo) {
+
+    GLuint buffer = GL_COLOR_ATTACHMENT0_EXT;
+    int index = 1;
+    for (int i=0; i<_current_properties->get_aux_rgba(); i++) {
+      if (rb._buffer_type & (RenderBuffer::T_aux_rgba_0 << i)) {
+        buffer = GL_COLOR_ATTACHMENT0_EXT + index;
+      }
+      index += 1;
+    }
+    for (int i=0; i<_current_properties->get_aux_rgba(); i++) {
+      if (rb._buffer_type & (RenderBuffer::T_aux_hrgba_0 << i)) {
+        buffer = GL_COLOR_ATTACHMENT0_EXT + index;
+      }
+      index += 1;
+    }
+    for (int i=0; i<_current_properties->get_aux_rgba(); i++) {
+      if (rb._buffer_type & (RenderBuffer::T_aux_float_0 << i)) {
+        buffer = GL_COLOR_ATTACHMENT0_EXT + index;
+      }
+      index += 1;
+    }
+    GLP(ReadBuffer)(buffer);
+
+  } else {
+
+    switch (rb._buffer_type & RenderBuffer::T_color) {
+    case RenderBuffer::T_front:
+      GLP(ReadBuffer)(GL_FRONT);
+      break;
+      
+    case RenderBuffer::T_back:
+      GLP(ReadBuffer)(GL_BACK);
+      break;
+      
+    case RenderBuffer::T_right:
+      GLP(ReadBuffer)(GL_RIGHT);
+      break;
+      
+    case RenderBuffer::T_left:
+      GLP(ReadBuffer)(GL_LEFT);
+      break;
+      
+    case RenderBuffer::T_front_right:
+      GLP(ReadBuffer)(GL_FRONT_RIGHT);
+      break;
+      
+    case RenderBuffer::T_front_left:
+      GLP(ReadBuffer)(GL_FRONT_LEFT);
+      break;
+      
+    case RenderBuffer::T_back_right:
+      GLP(ReadBuffer)(GL_BACK_RIGHT);
+      break;
+      
+    case RenderBuffer::T_back_left:
+      GLP(ReadBuffer)(GL_BACK_LEFT);
+      break;
+      
+    default:
+      GLP(ReadBuffer)(GL_FRONT_AND_BACK);
+    }
   }
   }
   
   
   report_my_gl_errors();
   report_my_gl_errors();
@@ -6437,6 +6449,60 @@ upload_texture(CLP(TextureContext) *gtc) {
   return false;
   return false;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::upload_blank_image
+//       Access: Private
+//  Description: Uploads a blank, non-mipmapped image to the specified
+//               texture object.  This is usually used to prepare the
+//               texture for render-to-texture operations.
+////////////////////////////////////////////////////////////////////
+bool CLP(GraphicsStateGuardian)::
+upload_blank_image(Texture *tex, CLP(TextureContext) *gtc)
+
+{
+  GLint internal_format = get_internal_image_format(tex);
+  
+  if ((gtc->_already_applied == false)||
+      (gtc->_internal_format != internal_format)||
+      (gtc->_width  != tex->get_x_size())||
+      (gtc->_height != tex->get_y_size())||
+      (gtc->_depth  != 1)) {
+    
+    GLP(BindTexture)(GL_TEXTURE_2D, gtc->_index);
+    
+    char *image = new char[tex->get_x_size() * tex->get_y_size()];
+    memset(image, 128, tex->get_x_size() * tex->get_y_size());
+
+    switch (tex->get_format()) {
+    case Texture::F_depth_component:
+      GLP(TexImage2D)(GL_TEXTURE_2D, 0, internal_format,
+                      tex->get_x_size(), tex->get_y_size(), 0,
+                      GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, image);
+      break;
+    case Texture::F_stencil_index:
+      GLP(TexImage2D)(GL_TEXTURE_2D, 0, internal_format,
+                      tex->get_x_size(), tex->get_y_size(), 0,
+                      GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, image);
+      break;
+    default:
+      GLP(TexImage2D)(GL_TEXTURE_2D, 0, internal_format,
+                      tex->get_x_size(), tex->get_y_size(), 0,
+                      GL_LUMINANCE, GL_UNSIGNED_BYTE, image);
+      break;
+    }
+
+    delete image;
+    
+    gtc->_already_applied = true;
+    gtc->_internal_format = internal_format;
+    gtc->_width  = tex->get_x_size();
+    gtc->_height = tex->get_y_size();
+    gtc->_depth  = 1;
+  }
+  
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::upload_texture_image
 //     Function: GLGraphicsStateGuardian::upload_texture_image
 //       Access: Protected
 //       Access: Protected
@@ -6945,3 +7011,16 @@ do_point_size() {
 
 
   report_my_gl_errors();
   report_my_gl_errors();
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::bind_fbo
+//       Access: Protected
+//  Description: Binds an FBO object.
+////////////////////////////////////////////////////////////////////
+void CLP(GraphicsStateGuardian)::
+bind_fbo(GLuint fbo) {
+  nassertv(_glBindFramebuffer != 0);
+  _glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo);
+  _current_fbo = fbo;
+}
+

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

@@ -172,6 +172,8 @@ public:
   virtual void set_state_and_transform(const RenderState *state,
   virtual void set_state_and_transform(const RenderState *state,
                                        const TransformState *transform);
                                        const TransformState *transform);
 
 
+  void bind_fbo(GLuint fbo);
+  
 protected:
 protected:
   void do_issue_transform();
   void do_issue_transform();
   void do_issue_render_mode();
   void do_issue_render_mode();
@@ -271,6 +273,7 @@ protected:
   void specify_texture(Texture *tex);
   void specify_texture(Texture *tex);
   void apply_texture(TextureContext *tc);
   void apply_texture(TextureContext *tc);
   bool upload_texture(CLP(TextureContext) *gtc);
   bool upload_texture(CLP(TextureContext) *gtc);
+  bool upload_blank_image(Texture *tex, CLP(TextureContext) *gtc);
   bool upload_texture_image(CLP(TextureContext) *gtc, bool uses_mipmaps, 
   bool upload_texture_image(CLP(TextureContext) *gtc, bool uses_mipmaps, 
                             GLenum target, GLint internal_format, 
                             GLenum target, GLint internal_format, 
                             int width, int height, int depth,
                             int width, int height, int depth,
@@ -340,6 +343,7 @@ protected:
   GLuint _geom_display_list;
   GLuint _geom_display_list;
   GLuint _current_vbuffer_index;
   GLuint _current_vbuffer_index;
   GLuint _current_ibuffer_index;
   GLuint _current_ibuffer_index;
+  GLuint _current_fbo;
   
   
   int _error_count;
   int _error_count;
 
 

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

@@ -72,7 +72,6 @@ ConfigVariableBool CLP(compile_and_execute)
             "for the first time, by allowing the display list to be "
             "for the first time, by allowing the display list to be "
             "rendered at the same time it is being compiled."));
             "rendered at the same time it is being compiled."));
 
 
-
 void CLP(init_classes)() {
 void CLP(init_classes)() {
   CLP(GraphicsStateGuardian)::init_type();
   CLP(GraphicsStateGuardian)::init_type();
   CLP(TextureContext)::init_type();
   CLP(TextureContext)::init_type();

+ 6 - 0
panda/src/wgldisplay/config_wgldisplay.cxx

@@ -46,6 +46,12 @@ ConfigVariableBool gl_do_vidmemsize_check
           "fullscreen windows, no matter what resolution of window was "
           "fullscreen windows, no matter what resolution of window was "
           "requested.  It only affects fullscreen windows."));
           "requested.  It only affects fullscreen windows."));
 
 
+ConfigVariableBool gl_support_fbo
+  ("gl-support-fbo", false,
+   PRC_DESC("Configure this false if your GL's implementation of "
+            "EXT_framebuffer_object is broken.  The system might still be "
+            "able to create buffers using pbuffers or the like."));
+
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: init_libwgldisplay
 //     Function: init_libwgldisplay

+ 1 - 0
panda/src/wgldisplay/config_wgldisplay.h

@@ -29,6 +29,7 @@ NotifyCategoryDecl(wgldisplay, EXPCL_PANDAGL, EXPTP_PANDAGL);
 extern ConfigVariableInt gl_force_pixfmt;
 extern ConfigVariableInt gl_force_pixfmt;
 extern ConfigVariableBool gl_force_invalid;
 extern ConfigVariableBool gl_force_invalid;
 extern ConfigVariableBool gl_do_vidmemsize_check;
 extern ConfigVariableBool gl_do_vidmemsize_check;
+extern ConfigVariableBool gl_support_fbo;
 
 
 extern EXPCL_PANDAGL void init_libwgldisplay();
 extern EXPCL_PANDAGL void init_libwgldisplay();
 
 

+ 6 - 0
panda/src/wgldisplay/wglGraphicsBuffer.cxx

@@ -303,6 +303,12 @@ open_buffer() {
   wglGraphicsStateGuardian *wglgsg;
   wglGraphicsStateGuardian *wglgsg;
   DCAST_INTO_R(wglgsg, _gsg, false);
   DCAST_INTO_R(wglgsg, _gsg, false);
 
 
+  // Make sure a pixel format is chosen, and take its properties.
+  if (wglgsg->get_pfnum() < 0) {
+    wglgsg->choose_pixel_format(_fb_properties);
+  }
+  _fb_properties = wglgsg->get_pfnum_properties();
+
   HDC twindow_dc = wglgsg->get_twindow_dc();
   HDC twindow_dc = wglgsg->get_twindow_dc();
   if (twindow_dc == 0) {
   if (twindow_dc == 0) {
     // If we couldn't make a window, we can't get a GL context.
     // If we couldn't make a window, we can't get a GL context.

+ 25 - 111
panda/src/wgldisplay/wglGraphicsPipe.cxx

@@ -78,17 +78,12 @@ pipe_constructor() {
 //               have been created yet for the GSG).
 //               have been created yet for the GSG).
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 PT(GraphicsStateGuardian) wglGraphicsPipe::
 PT(GraphicsStateGuardian) wglGraphicsPipe::
-make_gsg(const FrameBufferProperties &properties, 
+make_gsg(const FrameBufferProperties &properties,
          GraphicsStateGuardian *share_with) {
          GraphicsStateGuardian *share_with) {
   if (!_is_valid) {
   if (!_is_valid) {
     return NULL;
     return NULL;
   }
   }
 
 
-  // THIS CODE IS INCORRECT.  THIS ROUTINE IS NOT CALLED IN THE
-  // DRAW THREAD.  THE FIX IS THAT PIXEL FORMAT SELECTION NEEDS TO
-  // BE DONE ON A PER-WINDOW BASIS, AND IT NEEDS TO BE DONE IN
-  // OPEN_WINDOW, NOT HERE.
-  
   wglGraphicsStateGuardian *share_gsg = NULL;
   wglGraphicsStateGuardian *share_gsg = NULL;
 
 
   if (share_with != (GraphicsStateGuardian *)NULL) {
   if (share_with != (GraphicsStateGuardian *)NULL) {
@@ -102,95 +97,7 @@ make_gsg(const FrameBufferProperties &properties,
     DCAST_INTO_R(share_gsg, share_with, NULL);
     DCAST_INTO_R(share_gsg, share_with, NULL);
   }
   }
 
 
-  int frame_buffer_mode = 0;
-  if (properties.has_frame_buffer_mode()) {
-    frame_buffer_mode = properties.get_frame_buffer_mode();
-  }
-
-  // We need a DC to examine the available pixel formats.  We'll use
-  // the screen DC.
-  HDC hdc = GetDC(NULL);
-  int temp_pfnum;
-
-  if (!gl_force_pixfmt.has_value()) {
-    temp_pfnum = choose_pfnum(properties, hdc);
-    if (temp_pfnum == 0) {
-      return NULL;
-    }
-
-  } else {
-    wgldisplay_cat.info()
-      << "overriding pixfmt choice with gl-force-pixfmt(" 
-      << gl_force_pixfmt << ")\n";
-    temp_pfnum = gl_force_pixfmt;
-  }
-
-  FrameBufferProperties temp_properties;
-  get_properties(temp_properties, hdc, temp_pfnum);
-
-  // We're done with hdc now.
-  ReleaseDC(NULL, hdc);
-
-  if (wgldisplay_cat.is_debug()) {
-    wgldisplay_cat.debug()
-      << "Preliminary pixfmt #" << temp_pfnum << " = " 
-      << temp_properties << "\n";
-  }
-
-  // Now we need to create a temporary GSG to query the WGL
-  // extensions, so we can look for more advanced properties like
-  // multisampling.
-  PT(wglGraphicsStateGuardian) temp_gsg = 
-    new wglGraphicsStateGuardian(temp_properties, share_gsg, temp_pfnum);
-
-  int pfnum = temp_pfnum;
-  FrameBufferProperties new_properties = temp_properties;
-
-  // Actually, don't bother with the advanced stuff unless the
-  // requested frame buffer requires multisample, since at the moment
-  // that's the only reason we'd need to use the advanced query.
-  if (frame_buffer_mode & (FrameBufferProperties::FM_multisample)) {
-    HDC twindow_dc = temp_gsg->get_twindow_dc();
-    if (twindow_dc != 0) {
-      wglMakeCurrent(twindow_dc, temp_gsg->get_context(twindow_dc));
-      temp_gsg->reset_if_new();
-      
-      if (temp_gsg->_supports_pixel_format) {
-        pfnum = choose_pfnum_advanced(properties, temp_gsg, twindow_dc, 
-                                      temp_pfnum);
-        if (!get_properties_advanced(new_properties, temp_gsg, twindow_dc, 
-                                     pfnum)) {
-          wgldisplay_cat.debug()
-            << "Unable to query properties using extension interface.\n";
-          
-          get_properties(new_properties, twindow_dc, pfnum);
-        }
-      }
-    }
-  }
-
-  if (wgldisplay_cat.is_debug()) {
-    wgldisplay_cat.debug()
-      << "Picking pixfmt #" << pfnum << " = " 
-      << new_properties << "\n";
-  }
-
-  // Now create the actual GSG.  If we happen to have ended up with
-  // the same pfnum that we had the first time around, we can just
-  // keep our initial, temporary GSG.
-  PT(wglGraphicsStateGuardian) gsg = temp_gsg;
-  if (pfnum != temp_pfnum) {
-    gsg = new wglGraphicsStateGuardian(new_properties, share_gsg, pfnum);
-  }
-
-  // Ideally, we should be able to detect whether the share_gsg will
-  // be successful, and return NULL if it won't work.  But we can't do
-  // that yet, because we can't try to actually share the gsg until we
-  // create the context, for which we need to have a window.  That
-  // means the app will just have to trust it will work; if it doesn't
-  // work, too bad.
-
-  return gsg.p();
+  return new wglGraphicsStateGuardian(properties, share_gsg, -1);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -231,22 +138,29 @@ make_output(const string &name,
   
   
   // Second thing to try: a GLGraphicsBuffer
   // Second thing to try: a GLGraphicsBuffer
   
   
-  //  if (retry == 1) {
-  //    if ((!support_render_texture)||
-  //        ((flags&BF_require_parasite)!=0)||
-  //        ((flags&BF_require_window)!=0)) {
-  //      return NULL;
-  //    }
-  //    if ((wglgsg != 0) &&
-  //        (wglgsg->is_valid()) &&
-  //        (!wglgsg->needs_reset()) &&
-  //        (wglgsg->_supports_framebuffer_object) &&
-  //        (wglgsg->_glDrawBuffers != 0)) {
-  //      precertify = true;
-  //    }
-  //    return new GLGraphicsBuffer(this, name, properties,
-  //                                x_size, y_size, flags, gsg, host);
-  //  }
+  if (retry == 1) {
+    if ((!support_render_texture)||
+        (!gl_support_fbo)||
+        (host==0)||
+        ((flags&BF_require_parasite)!=0)||
+        ((flags&BF_require_window)!=0)||
+        (properties.has_mode(FrameBufferProperties::FM_index))||
+        (properties.has_mode(FrameBufferProperties::FM_buffer))||
+        (properties.has_mode(FrameBufferProperties::FM_accum))||
+        (properties.has_mode(FrameBufferProperties::FM_stencil))||
+        (properties.has_mode(FrameBufferProperties::FM_multisample))) {
+      return NULL;
+    }
+    if ((wglgsg != 0) &&
+        (wglgsg->is_valid()) &&
+        (!wglgsg->needs_reset()) &&
+        (wglgsg->_supports_framebuffer_object) &&
+        (wglgsg->_glDrawBuffers != 0)) {
+      precertify = true;
+    }
+    return new GLGraphicsBuffer(this, name, properties,
+                                x_size, y_size, flags, gsg, host);
+  }
   
   
   // Third thing to try: a wglGraphicsBuffer
   // Third thing to try: a wglGraphicsBuffer
   
   

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

@@ -50,7 +50,7 @@ protected:
                                              GraphicsStateGuardian *share_with);
                                              GraphicsStateGuardian *share_with);
 
 
 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, 
                            int frame_buffer_mode,
                            int frame_buffer_mode,
@@ -93,6 +93,7 @@ private:
 
 
   friend class wglGraphicsBuffer;
   friend class wglGraphicsBuffer;
   friend class wglGraphicsWindow;
   friend class wglGraphicsWindow;
+  friend class wglGraphicsStateGuardian;
 };
 };
 
 
 #include "wglGraphicsPipe.I"
 #include "wglGraphicsPipe.I"

+ 16 - 0
panda/src/wgldisplay/wglGraphicsStateGuardian.I

@@ -32,6 +32,22 @@ get_pfnum() const {
   return _pfnum;
   return _pfnum;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: wglGraphicsStateGuardian::get_pfnum_properties
+//       Access: Public
+//  Description: Returns the properties of the pixel format that
+//               was chosen for this gsg.  In OpenGL under Microsoft
+//               Windows, the window must be created first and then
+//               the GL context is created from the window, and the
+//               context inherits the pixel format of the window.
+//               Therefore, all windows that share a particular
+//               context must also share the same pixel format.
+////////////////////////////////////////////////////////////////////
+INLINE const FrameBufferProperties &wglGraphicsStateGuardian::
+get_pfnum_properties() const {
+  return _pfnum_properties;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: wglGraphicsStateGuardian::made_context
 //     Function: wglGraphicsStateGuardian::made_context
 //       Access: Public
 //       Access: Public

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

@@ -43,7 +43,7 @@ wglGraphicsStateGuardian(const FrameBufferProperties &properties,
 
 
   _twindow = (HWND)0;
   _twindow = (HWND)0;
   _twindow_dc = (HDC)0;
   _twindow_dc = (HDC)0;
-
+  
   _supports_pbuffer = false;
   _supports_pbuffer = false;
   _supports_pixel_format = false;
   _supports_pixel_format = false;
   _supports_wgl_multisample = false;
   _supports_wgl_multisample = false;
@@ -63,6 +63,91 @@ wglGraphicsStateGuardian::
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: wglGraphicsStateGuardian::choose_pixel_format
+//       Access: Private
+//  Description: Selects a pixel format.
+////////////////////////////////////////////////////////////////////
+bool wglGraphicsStateGuardian::
+choose_pixel_format(const FrameBufferProperties &properties) {
+  
+  int frame_buffer_mode = 0;
+  if (properties.has_frame_buffer_mode()) {
+    frame_buffer_mode = properties.get_frame_buffer_mode();
+  }
+
+  wglGraphicsPipe *pipe;
+  DCAST_INTO_R(pipe, get_pipe(), false);
+
+  // We need a DC to examine the available pixel formats.  We'll use
+  // the screen DC.
+  HDC hdc = GetDC(NULL);
+
+  if (!gl_force_pixfmt.has_value()) {
+    _pfnum = pipe->choose_pfnum(properties, hdc);
+    if (_pfnum == 0) {
+      ReleaseDC(NULL, hdc);
+      return false;
+    }
+  } else {
+    wgldisplay_cat.info()
+      << "overriding pixfmt choice with gl-force-pixfmt(" 
+      << gl_force_pixfmt << ")\n";
+    _pfnum = gl_force_pixfmt;
+  }
+
+  // Query the properties of the pixel format we chose.
+  pipe->get_properties(_pfnum_properties, hdc, _pfnum);
+  
+  // We're done with hdc now.
+  ReleaseDC(NULL, hdc);
+
+  if (wgldisplay_cat.is_debug()) {
+    wgldisplay_cat.debug()
+      << "Preliminary pixfmt #" << _pfnum << " = " 
+      << _pfnum_properties << "\n";
+  }
+
+  // We need to create a temporary GSG to query the WGL
+  // extensions, so we can look for more advanced properties like
+  // multisampling.
+  //
+  // Don't bother with the advanced stuff unless the
+  // requested frame buffer requires multisample, since at the moment
+  // that's the only reason we'd need to use the advanced query.
+  //
+  // Now that this is in the draw thread, it's probably possible
+  // to write this code in a more elegant manner.
+
+  if (frame_buffer_mode & (FrameBufferProperties::FM_multisample)) {
+
+    PT(wglGraphicsStateGuardian) temp_gsg = 
+      new wglGraphicsStateGuardian(_pfnum_properties, _share_with, _pfnum);
+
+    FrameBufferProperties adv_properties = _pfnum_properties;
+
+    HDC twindow_dc = temp_gsg->get_twindow_dc();
+    if (twindow_dc != 0) {
+      wglMakeCurrent(twindow_dc, temp_gsg->get_context(twindow_dc));
+      temp_gsg->reset_if_new();
+      
+      if (temp_gsg->_supports_pixel_format) {
+        int adv_pfnum = pipe->
+          choose_pfnum_advanced(properties, temp_gsg, twindow_dc, _pfnum);
+        if (pipe->get_properties_advanced
+            (adv_properties, temp_gsg, twindow_dc, adv_pfnum)) {
+          _pfnum_properties = adv_properties;
+          _pfnum = adv_pfnum;
+        } else {
+          wgldisplay_cat.debug()
+            << "Unable to query properties using extension interface.\n";
+        }
+      }
+    }
+  }
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: wglGraphicsStateGuardian::reset
 //     Function: wglGraphicsStateGuardian::reset
 //       Access: Public, Virtual
 //       Access: Public, Virtual

+ 4 - 2
panda/src/wgldisplay/wglGraphicsStateGuardian.h

@@ -40,9 +40,10 @@ public:
   virtual ~wglGraphicsStateGuardian();
   virtual ~wglGraphicsStateGuardian();
 
 
   INLINE int get_pfnum() const;
   INLINE int get_pfnum() const;
+  INLINE const FrameBufferProperties &get_pfnum_properties() const;
   INLINE bool made_context() const;
   INLINE bool made_context() const;
   INLINE HGLRC get_context(HDC hdc);
   INLINE HGLRC get_context(HDC hdc);
-
+  bool choose_pixel_format(const FrameBufferProperties &properties);
   virtual void reset();
   virtual void reset();
 
 
   INLINE HDC get_twindow_dc();
   INLINE HDC get_twindow_dc();
@@ -68,7 +69,8 @@ private:
 
 
   // All windows that share a particular GL context must also share
   // All windows that share a particular GL context must also share
   // the same pixel format; therefore, we store the pixel format
   // the same pixel format; therefore, we store the pixel format
-  // number in the GSG.
+  // number and the actual properties in the GSG.
+  FrameBufferProperties _pfnum_properties;
   int _pfnum;
   int _pfnum;
 
 
   bool _made_context;
   bool _made_context;

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

@@ -291,6 +291,12 @@ open_window() {
 
 
   _hdc = GetDC(_hWnd);
   _hdc = GetDC(_hWnd);
 
 
+  // Make sure a pixel format is chosen, and take its properties.
+  if (wglgsg->get_pfnum() < 0) {
+    wglgsg->choose_pixel_format(_fb_properties);
+  }
+  _fb_properties = wglgsg->get_pfnum_properties();
+
   // Set up the pixel format of the window appropriately for GL.
   // Set up the pixel format of the window appropriately for GL.
   int pfnum = wglgsg->get_pfnum();
   int pfnum = wglgsg->get_pfnum();
   PIXELFORMATDESCRIPTOR pixelformat;
   PIXELFORMATDESCRIPTOR pixelformat;