2
0
Эх сурвалжийг харах

add GraphicsEngine::open_windows(), GLGraphicsStateGuardian::_edge_clamp

David Rose 22 жил өмнө
parent
commit
587de59ae8

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

@@ -86,7 +86,7 @@ const bool show_buffers = config_display.GetBool("show-buffers", false);
 // 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);
+const bool prefer_parasite_buffer = config_display.GetBool("prefer-parasite-buffer", true);
 
 // Set this true to make GraphicsOutput::make_render_texture() first
 // try to create a single-buffered offscreen buffer, before falling

+ 88 - 0
panda/src/display/graphicsEngine.cxx

@@ -503,6 +503,50 @@ render_frame() {
   _app_pcollector.start();
 }
 
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsEngine::open_windows
+//       Access: Published
+//  Description: Fully opens (or closes) any windows that have
+//               recently been requested open or closed, without
+//               rendering any frames.  It is not necessary to call
+//               this explicitly, since windows will be automatically
+//               opened or closed when the next frame is rendered, but
+//               you may call this if you want your windows now
+//               without seeing a frame go by.
+////////////////////////////////////////////////////////////////////
+void GraphicsEngine::
+open_windows() {
+  MutexHolder holder(_lock);
+
+  if (!_windows_sorted) {
+    do_resort_windows();
+  }
+
+  _app.do_windows(this);
+
+  Threads::const_iterator ti;
+  for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
+    RenderThread *thread = (*ti).second;
+    if (thread->_thread_state == TS_wait) {
+      thread->_thread_state = TS_do_windows;
+      thread->_cv.signal();
+    }
+    thread->_cv_mutex.release();
+  }
+
+  // We do it twice, to allow both cull and draw to process the
+  // window.
+  for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
+    RenderThread *thread = (*ti).second;
+    if (thread->_thread_state == TS_wait) {
+      thread->_thread_state = TS_do_windows;
+      thread->_cv.signal();
+    }
+    thread->_cv_mutex.release();
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsEngine::sync_frame
 //       Access: Published
@@ -747,6 +791,24 @@ cull_bin_draw(GraphicsStateGuardian *gsg, DisplayRegion *dr) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsEngine::make_contexts
+//       Access: Private
+//  Description: Called in the draw thread, this calls make_context()
+//               on each window on the list to guarantee its graphics
+//               context gets created.
+////////////////////////////////////////////////////////////////////
+void GraphicsEngine::
+make_contexts(const GraphicsEngine::Windows &wlist) {
+  Windows::const_iterator wi;
+  for (wi = wlist.begin(); wi != wlist.end(); ++wi) {
+    GraphicsOutput *win = (*wi);
+    if (win->needs_context()) {
+      win->make_context();
+    }
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsEngine::process_events
 //       Access: Private
@@ -1321,6 +1383,25 @@ do_frame(GraphicsEngine *engine) {
   do_callbacks(CB_post_frame);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsEngine::WindowRenderer::do_windows
+//       Access: Public
+//  Description: Attempts to fully open or close any windows or
+//               buffers associated with this thread, but does not
+//               otherwise perform any rendering.  (Normally, this
+//               step is handled during do_frame(); call this method
+//               only if you want these things to open immediately.)
+////////////////////////////////////////////////////////////////////
+void GraphicsEngine::WindowRenderer::
+do_windows(GraphicsEngine *engine) {
+  MutexHolder holder(_wl_lock);
+
+  engine->process_events(_window);
+
+  engine->make_contexts(_cdraw);
+  engine->make_contexts(_draw);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsEngine::WindowRenderer::do_flip
 //       Access: Public
@@ -1542,6 +1623,13 @@ thread_main() {
       _thread_state = TS_wait;
       break;
 
+    case TS_do_windows:
+      do_windows(_engine);
+      do_pending(_engine);
+      do_release(_engine);
+      _thread_state = TS_wait;
+      break;
+
     case TS_terminate:
       do_pending(_engine);
       do_close(_engine);

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

@@ -88,6 +88,7 @@ PUBLISHED:
   bool is_empty() const;
 
   void render_frame();
+  void open_windows();
   void sync_frame();
   void flip_frame();
   
@@ -100,6 +101,7 @@ public:
     TS_do_frame,
     TS_do_flip,
     TS_do_release,
+    TS_do_windows,
     TS_terminate
   };
 
@@ -139,6 +141,7 @@ private:
 
   void cull_bin_draw(const Windows &wlist);
   void cull_bin_draw(GraphicsStateGuardian *gsg, DisplayRegion *dr);
+  void make_contexts(const Windows &wlist);
 
   void process_events(const Windows &wlist);
   void flip_windows(const Windows &wlist);
@@ -171,6 +174,7 @@ private:
     void remove_window(GraphicsOutput *window);
     void resort_windows();
     void do_frame(GraphicsEngine *engine);
+    void do_windows(GraphicsEngine *engine);
     void do_flip(GraphicsEngine *engine);
     void do_release(GraphicsEngine *engine);
     void do_close(GraphicsEngine *engine);

+ 22 - 11
panda/src/display/graphicsOutput.I

@@ -160,17 +160,6 @@ is_valid() const {
   return _is_valid;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsOutput::flip_ready
-//       Access: Published
-//  Description: Returns true if a frame has been rendered and needs
-//               to be flipped, false otherwise.
-////////////////////////////////////////////////////////////////////
-INLINE bool GraphicsOutput::
-flip_ready() const {
-  return _flip_ready;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsOutput::get_sort
 //       Access: Published
@@ -243,6 +232,28 @@ win_display_regions_changed() {
   _display_regions_stale = true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::flip_ready
+//       Access: Public
+//  Description: Returns true if a frame has been rendered and needs
+//               to be flipped, false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool GraphicsOutput::
+flip_ready() const {
+  return _flip_ready;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::needs_context
+//       Access: Public
+//  Description: Returns true if make_context() still needs to be
+//               called, false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool GraphicsOutput::
+needs_context() const {
+  return _needs_context;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsOutput::operator <
 //       Access: Public

+ 39 - 2
panda/src/display/graphicsOutput.cxx

@@ -52,6 +52,7 @@ GraphicsOutput(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
   _is_valid = false;
   _copy_texture = false;
   _flip_ready = false;
+  _needs_context = true;
   _sort = 0;
 
   int mode = gsg->get_properties().get_frame_buffer_mode();
@@ -365,7 +366,15 @@ make_texture_buffer(const string &name, int x_size, int y_size) {
       if (sb_gsg != (GraphicsStateGuardian *)NULL) {
         buffer = engine->make_buffer(sb_gsg, name, sort, x_size, y_size, true);
         if (buffer != (GraphicsOutput *)NULL) {
-          return buffer;
+          // Check the buffer for goodness.
+          engine->open_windows();
+          if (buffer->is_valid()) {
+            return buffer;
+          }
+
+          // No good; delete the buffer and keep trying.
+          engine->remove_window(buffer);
+          buffer = (GraphicsOutput *)NULL;
         }
       }
     }
@@ -376,7 +385,13 @@ make_texture_buffer(const string &name, int x_size, int y_size) {
   // source window is double-buffered.
   buffer = engine->make_buffer(gsg, name, sort, x_size, y_size, true);
   if (buffer != (GraphicsOutput *)NULL) {
-    return buffer;
+    engine->open_windows();
+    if (buffer->is_valid()) {
+      return buffer;
+    }
+    
+    engine->remove_window(buffer);
+    buffer = (GraphicsOutput *)NULL;
   }
 
   // Looks like we have to settle for a parasite buffer.
@@ -492,6 +507,12 @@ begin_frame() {
     return false;
   }
 
+  if (needs_context()) {
+    if (!make_context()) {
+      return false;
+    }
+  }
+
   // Okay, we already have a GSG, so activate it.
   make_current();
   return _gsg->begin_frame();
@@ -550,6 +571,22 @@ end_frame() {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::make_context
+//       Access: Public, Virtual
+//  Description: If _needs_context is true, this will be called
+//               in the draw thread prior to rendering into the
+//               window.  It should attempt to create a graphics
+//               context, and return true if successful, false
+//               otherwise.  If it returns false the window will be
+//               considered failed.
+////////////////////////////////////////////////////////////////////
+bool GraphicsOutput::
+make_context() {
+  _needs_context = false;
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsOutput::make_current
 //       Access: Public, Virtual

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

@@ -80,7 +80,6 @@ PUBLISHED:
   INLINE int get_y_size() const;
   INLINE bool has_size() const;
   INLINE bool is_valid() const;
-  INLINE bool flip_ready() const;
 
   virtual bool is_active() const;
 
@@ -109,6 +108,8 @@ public:
 public:
   // These are not intended to be called directly by the user.
   INLINE void win_display_regions_changed();
+  INLINE bool needs_context() const;
+  INLINE bool flip_ready() const;
 
   INLINE bool operator < (const GraphicsOutput &other) const;
 
@@ -129,6 +130,7 @@ public:
 
   // This method is called in the draw thread prior to issuing any
   // drawing commands for the window.
+  virtual bool make_context();
   virtual void make_current();
   virtual void release_gsg();
 
@@ -151,6 +153,7 @@ protected:
   PT(Texture) _texture;
   bool _copy_texture;
   bool _flip_ready;
+  bool _needs_context;
 
 private:
   INLINE void determine_display_regions() const;

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

@@ -64,6 +64,7 @@ ParasiteBuffer(GraphicsOutput *host, const string &name,
 ////////////////////////////////////////////////////////////////////
 ParasiteBuffer::
 ~ParasiteBuffer() {
+  _is_valid = false;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 6 - 6
panda/src/glstuff/glGraphicsStateGuardian_src.I

@@ -615,14 +615,14 @@ enable_multisample(bool val) {
   if (_multisample_enabled != val) {
     _multisample_enabled = val;
     if (val) {
-#ifdef GL_MULTISAMPLE_SGIS
-      GLP(Enable)(GL_MULTISAMPLE_SGIS);
-#endif
+      if (_supports_multisample) {
+        GLP(Enable)(GL_MULTISAMPLE);
+      }
       GLP(Hint)(GL_POINT_SMOOTH_HINT, GL_NICEST);
     } else {
-#ifdef GL_MULTISAMPLE_SGIS
-      GLP(Disable)(GL_MULTISAMPLE_SGIS);
-#endif
+      if (_supports_multisample) {
+        GLP(Disable)(GL_MULTISAMPLE);
+      }
       GLP(Hint)(GL_POINT_SMOOTH_HINT, GL_FASTEST);
     }
   }

+ 80 - 18
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -380,6 +380,8 @@ reset() {
   _current_projection_mat = LMatrix4f::ident_mat();
   _projection_mat_stack_count = 0;
 
+  report_my_gl_errors();
+
   // Make sure the GL state matches all of our initial attribute
   // states.
   CPT(RenderAttrib) dta = DepthTestAttrib::make(DepthTestAttrib::M_less);
@@ -419,7 +421,7 @@ reset() {
   // Output the vendor and version strings.
   show_gl_string("GL_VENDOR", GL_VENDOR);
   show_gl_string("GL_RENDERER", GL_RENDERER);
-  show_gl_string("GL_VERSION", GL_VERSION);
+  get_gl_version();
 
   // Save the extensions tokens.
   save_extensions((const char *)glGetString(GL_EXTENSIONS));
@@ -427,6 +429,14 @@ reset() {
   report_extensions();
 
   _supports_bgr = has_extension("GL_EXT_bgra");
+  _supports_multisample = has_extension("GL_ARB_multisample");
+
+  _edge_clamp = GL_CLAMP;
+  if (has_extension("GL_SGIS_texture_edge_clamp") ||
+      is_at_least_version(1, 2)) {
+    _edge_clamp = GL_CLAMP_TO_EDGE;
+  }
+
   _error_count = 0;
 
   report_my_gl_errors();
@@ -2663,6 +2673,47 @@ show_gl_string(const string &name, GLenum id) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::get_gl_version
+//       Access: Protected
+//  Description: Queries the runtime version of OpenGL in use.
+////////////////////////////////////////////////////////////////////
+void CLP(GraphicsStateGuardian)::
+get_gl_version() {
+  _gl_version_major = 0;
+  _gl_version_minor = 0;
+  _gl_version_release = 0;
+
+  const GLubyte *text = GLP(GetString)(GL_VERSION);
+  if (text == (const GLubyte *)NULL) {
+    GLCAT.debug()
+      << "Unable to query GL_VERSION\n";
+  } else {
+    string input((const char *)text);
+    size_t space = input.find(' ');
+    if (space != string::npos) {
+      input = input.substr(0, space);
+    }
+
+    vector_string components;
+    tokenize(input, components, ".");
+    if (components.size() >= 1) {
+      string_to_int(components[0], _gl_version_major);
+    }
+    if (components.size() >= 2) {
+      string_to_int(components[1], _gl_version_minor);
+    }
+    if (components.size() >= 3) {
+      string_to_int(components[2], _gl_version_release);
+    }
+
+    GLCAT.debug()
+      << "GL_VERSION = " << (const char *)text << ", decoded to "
+      << _gl_version_major << "." << _gl_version_minor 
+      << "." << _gl_version_release << "\n";
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::save_extensions
 //       Access: Protected
@@ -2725,6 +2776,26 @@ has_extension(const string &extension) const {
   return (_extensions.find(extension) != _extensions.end());
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CLP(GraphicsStateGuardian)::is_at_least_version
+//       Access: Public
+//  Description: Returns true if the runtime GL version number is at
+//               least the indicated value, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool CLP(GraphicsStateGuardian)::
+is_at_least_version(int major, int minor, int release) const {
+  if (_gl_version_major < major) {
+    return false;
+  }
+  if (_gl_version_minor < minor) {
+    return false;
+  }
+  if (_gl_version_release < release) {
+    return false;
+  }
+  return true;
+}
+
 
 ////////////////////////////////////////////////////////////////////
 //     Function: CLP(GraphicsStateGuardian)::set_draw_buffer
@@ -2918,12 +2989,10 @@ compute_gl_image_size(int xsize, int ysize, int external_format, int type) {
     pixel_width = 2 * num_components;
     break;
 
-#ifdef GL_UNSIGNED_BYTE_3_3_2_EXT
-  case GL_UNSIGNED_BYTE_3_3_2_EXT:
+  case GL_UNSIGNED_BYTE_3_3_2:
     nassertr(num_components == 3, 0);
     pixel_width = 1;
     break;
-#endif
 
   case GL_FLOAT:
     pixel_width = 4 * num_components;
@@ -3255,7 +3324,7 @@ get_texture_wrap_mode(Texture::WrapMode wm) {
   }
   switch (wm) {
   case Texture::WM_clamp:
-    return GL_CLAMP;
+    return _edge_clamp;
   case Texture::WM_repeat:
     return GL_REPEAT;
 
@@ -3269,7 +3338,7 @@ get_texture_wrap_mode(Texture::WrapMode wm) {
     break;
   }
   GLCAT.error() << "Invalid Texture::WrapMode value!\n";
-  return GL_CLAMP;
+  return _edge_clamp;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -3332,10 +3401,8 @@ get_image_type(PixelBuffer::Type type) {
     return GL_UNSIGNED_BYTE;
   case PixelBuffer::T_unsigned_short:
     return GL_UNSIGNED_SHORT;
-#ifdef GL_UNSIGNED_BYTE_3_3_2_EXT
   case PixelBuffer::T_unsigned_byte_332:
-    return GL_UNSIGNED_BYTE_3_3_2_EXT;
-#endif
+    return GL_UNSIGNED_BYTE_3_3_2;
   case PixelBuffer::T_float:
     return GL_FLOAT;
 
@@ -3480,9 +3547,7 @@ get_fog_mode_type(Fog::Mode m) const {
   case Fog::M_exponential: return GL_EXP;
   case Fog::M_exponential_squared: return GL_EXP2;
     /*
-      #ifdef GL_FOG_FUNC_SGIS
       case Fog::M_spline: return GL_FOG_FUNC_SGIS;
-      #endif
     */
 
   default:
@@ -3525,13 +3590,10 @@ print_gfx_visual() {
 
   GLP(GetBooleanv)( GL_STEREO, &j ); cout << "Stereo? " << (int)j << endl;
 
-#ifdef GL_MULTISAMPLE_SGIS
-  GLP(GetBooleanv)( GL_MULTISAMPLE_SGIS, &j ); cout << "Multisample? "
-                                                 << (int)j << endl;
-#endif
-#ifdef GL_SAMPLES_SGIS
-  GLP(GetIntegerv)( GL_SAMPLES_SGIS, &i ); cout << "Samples: " << i << endl;
-#endif
+  if (_supports_multisample) {
+    GLP(GetBooleanv)( GL_MULTISAMPLE, &j ); cout << "Multisample? " << (int)j << endl;
+    GLP(GetIntegerv)( GL_SAMPLES, &i ); cout << "Samples: " << i << endl;
+  }
 
   GLP(GetBooleanv)( GL_BLEND, &j ); cout << "Blend? " << (int)j << endl;
   GLP(GetBooleanv)( GL_POINT_SMOOTH, &j ); cout << "Point Smooth? "

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

@@ -133,10 +133,12 @@ protected:
   static bool report_errors_loop(int line, const char *source_file, 
                                  GLenum error_code, int &error_count);
   void show_gl_string(const string &name, GLenum id);
+  void get_gl_version();
   void save_extensions(const char *extensions);
   virtual void get_extra_extensions();
   void report_extensions() const;
   bool has_extension(const string &extension) const;
+  bool is_at_least_version(int major, int minor, int release = 0) const;
 
   virtual bool slot_new_light(int light_id);
   virtual void enable_lighting(bool enable);
@@ -299,8 +301,11 @@ protected:
 
   int _pass_number;
 
+  int _gl_version_major, _gl_version_minor, _gl_version_release;
   pset<string> _extensions;
   bool _supports_bgr;
+  bool _supports_multisample;
+  GLenum _edge_clamp;
 
   int _error_count;
 

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

@@ -152,6 +152,45 @@ end_frame() {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: wglGraphicsBuffer::make_context
+//       Access: Public, Virtual
+//  Description: If _needs_context is true, this will be called
+//               in the draw thread prior to rendering into the
+//               window.  It should attempt to create a graphics
+//               context, and return true if successful, false
+//               otherwise.  If it returns false the window will be
+//               considered failed.
+////////////////////////////////////////////////////////////////////
+bool wglGraphicsBuffer::
+make_context() {
+  PStatTimer timer(_make_current_pcollector);
+
+  wglGraphicsStateGuardian *wglgsg;
+  DCAST_INTO_R(wglgsg, _gsg, false);
+
+  if (_pbuffer_dc) {
+    HGLRC context = wglgsg->get_context(_pbuffer_dc);
+    if (context) {
+      wglMakeCurrent(_pbuffer_dc, context);
+      wglgsg->reset_if_new();
+      _needs_context = false;
+      return true;
+    }
+
+  } else {
+    HGLRC context = wglgsg->get_context(_window_dc);
+    if (context) {
+      wglMakeCurrent(_window_dc, context);
+      wglgsg->reset_if_new();
+      _needs_context = false;
+      return true;
+    }
+  }
+
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: wglGraphicsBuffer::make_current
 //       Access: Public, Virtual

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

@@ -49,6 +49,7 @@ public:
   virtual bool begin_frame();
   virtual void end_frame();
 
+  virtual bool make_context();
   virtual void make_current();
   virtual void release_gsg();
 

+ 29 - 9
panda/src/wgldisplay/wglGraphicsWindow.cxx

@@ -147,6 +147,33 @@ wglGraphicsWindow::
 ~wglGraphicsWindow() {
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: wglGraphicsWindow::make_context
+//       Access: Public, Virtual
+//  Description: If _needs_context is true, this will be called
+//               in the draw thread prior to rendering into the
+//               window.  It should attempt to create a graphics
+//               context, and return true if successful, false
+//               otherwise.  If it returns false the window will be
+//               considered failed.
+////////////////////////////////////////////////////////////////////
+bool wglGraphicsWindow::
+make_context() {
+  PStatTimer timer(_make_current_pcollector);
+
+  wglGraphicsStateGuardian *wglgsg;
+  DCAST_INTO_R(wglgsg, _gsg, false);
+
+  HGLRC context = wglgsg->get_context(_hdc);
+  if (context) {
+    wglMakeCurrent(_hdc, context);
+    wglgsg->reset_if_new();
+    _needs_context = false;
+    return true;
+  }
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: wglGraphicsWindow::make_current
 //       Access: Public, Virtual
@@ -161,15 +188,8 @@ make_current() {
   wglGraphicsStateGuardian *wglgsg;
   DCAST_INTO_V(wglgsg, _gsg);
   HGLRC context = wglgsg->get_context(_hdc);
-  if (context) {
-    wglMakeCurrent(_hdc, context);
-
-    // Now that we have made the context current to a window, we can
-    // reset the GSG state if this is the first time it has been used.
-    // (We can't just call reset() when we construct the GSG, because
-    // reset() requires having a current context.)
-    wglgsg->reset_if_new();
-  }
+  nassertv(context);
+  wglMakeCurrent(_hdc, context);
 }
 
 ////////////////////////////////////////////////////////////////////

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

@@ -33,6 +33,7 @@ public:
                     const string &name);
   virtual ~wglGraphicsWindow();
 
+  virtual bool make_context();
   virtual void make_current();
   virtual void release_gsg();