Panda3D

graphicsEngine.cxx

00001 // Filename: graphicsEngine.cxx
00002 // Created by:  drose (24Feb02)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "graphicsEngine.h"
00016 #include "graphicsPipe.h"
00017 #include "parasiteBuffer.h"
00018 #include "config_gobj.h"
00019 #include "config_display.h"
00020 #include "pipeline.h"
00021 #include "drawCullHandler.h"
00022 #include "binCullHandler.h"
00023 #include "cullResult.h"
00024 #include "cullTraverser.h"
00025 #include "clockObject.h"
00026 #include "pStatTimer.h"
00027 #include "pStatClient.h"
00028 #include "pStatCollector.h"
00029 #include "mutexHolder.h"
00030 #include "reMutexHolder.h"
00031 #include "lightReMutexHolder.h"
00032 #include "cullFaceAttrib.h"
00033 #include "string_utils.h"
00034 #include "geomCacheManager.h"
00035 #include "renderState.h"
00036 #include "transformState.h"
00037 #include "thread.h"
00038 #include "pipeline.h"
00039 #include "throw_event.h"
00040 #include "bamCache.h"
00041 #include "cullableObject.h"
00042 #include "geomVertexArrayData.h"
00043 #include "vertexDataSaveFile.h"
00044 #include "vertexDataBook.h"
00045 #include "vertexDataPage.h"
00046 #include "config_pgraph.h"
00047 #include "displayRegionCullCallbackData.h"
00048 #include "displayRegionDrawCallbackData.h"
00049 
00050 #if defined(WIN32)
00051   #define WINDOWS_LEAN_AND_MEAN
00052   #include <WinSock2.h>
00053   #include <wtypes.h>
00054   #undef WINDOWS_LEAN_AND_MEAN  
00055 #else
00056   #include <sys/time.h>
00057 #endif
00058 
00059 PT(GraphicsEngine) GraphicsEngine::_global_ptr;
00060 
00061 PStatCollector GraphicsEngine::_wait_pcollector("Wait:Thread sync");
00062 PStatCollector GraphicsEngine::_cycle_pcollector("App:Cycle");
00063 PStatCollector GraphicsEngine::_app_pcollector("App:Show code:General");
00064 PStatCollector GraphicsEngine::_render_frame_pcollector("App:render_frame");
00065 PStatCollector GraphicsEngine::_do_frame_pcollector("*:do_frame");
00066 PStatCollector GraphicsEngine::_yield_pcollector("App:Yield");
00067 PStatCollector GraphicsEngine::_cull_pcollector("Cull");
00068 PStatCollector GraphicsEngine::_cull_setup_pcollector("Cull:Setup");
00069 PStatCollector GraphicsEngine::_cull_sort_pcollector("Cull:Sort");
00070 PStatCollector GraphicsEngine::_draw_pcollector("Draw");
00071 PStatCollector GraphicsEngine::_sync_pcollector("Draw:Sync");
00072 PStatCollector GraphicsEngine::_flip_pcollector("Wait:Flip");
00073 PStatCollector GraphicsEngine::_flip_begin_pcollector("Wait:Flip:Begin");
00074 PStatCollector GraphicsEngine::_flip_end_pcollector("Wait:Flip:End");
00075 PStatCollector GraphicsEngine::_transform_states_pcollector("TransformStates");
00076 PStatCollector GraphicsEngine::_transform_states_unused_pcollector("TransformStates:Unused");
00077 PStatCollector GraphicsEngine::_render_states_pcollector("RenderStates");
00078 PStatCollector GraphicsEngine::_render_states_unused_pcollector("RenderStates:Unused");
00079 PStatCollector GraphicsEngine::_cyclers_pcollector("PipelineCyclers");
00080 PStatCollector GraphicsEngine::_dirty_cyclers_pcollector("Dirty PipelineCyclers");
00081 PStatCollector GraphicsEngine::_delete_pcollector("App:Delete");
00082 
00083 
00084 PStatCollector GraphicsEngine::_sw_sprites_pcollector("SW Sprites");
00085 PStatCollector GraphicsEngine::_vertex_data_small_pcollector("Vertex Data:Small");
00086 PStatCollector GraphicsEngine::_vertex_data_independent_pcollector("Vertex Data:Independent");
00087 PStatCollector GraphicsEngine::_vertex_data_pending_pcollector("Vertex Data:Pending");
00088 PStatCollector GraphicsEngine::_vertex_data_resident_pcollector("Vertex Data:Resident");
00089 PStatCollector GraphicsEngine::_vertex_data_compressed_pcollector("Vertex Data:Compressed");
00090 PStatCollector GraphicsEngine::_vertex_data_unused_disk_pcollector("Vertex Data:Disk:Unused");
00091 PStatCollector GraphicsEngine::_vertex_data_used_disk_pcollector("Vertex Data:Disk:Used");
00092 
00093 // These are counted independently by the collision system; we
00094 // redefine them here so we can reset them at each frame.
00095 PStatCollector GraphicsEngine::_cnode_volume_pcollector("Collision Volumes:CollisionNode");
00096 PStatCollector GraphicsEngine::_gnode_volume_pcollector("Collision Volumes:GeomNode");
00097 PStatCollector GraphicsEngine::_geom_volume_pcollector("Collision Volumes:Geom");
00098 PStatCollector GraphicsEngine::_node_volume_pcollector("Collision Volumes:PandaNode");
00099 PStatCollector GraphicsEngine::_volume_pcollector("Collision Volumes:CollisionSolid");
00100 PStatCollector GraphicsEngine::_test_pcollector("Collision Tests:CollisionSolid");
00101 PStatCollector GraphicsEngine::_volume_polygon_pcollector("Collision Volumes:CollisionPolygon");
00102 PStatCollector GraphicsEngine::_test_polygon_pcollector("Collision Tests:CollisionPolygon");
00103 PStatCollector GraphicsEngine::_volume_plane_pcollector("Collision Volumes:CollisionPlane");
00104 PStatCollector GraphicsEngine::_test_plane_pcollector("Collision Tests:CollisionPlane");
00105 PStatCollector GraphicsEngine::_volume_sphere_pcollector("Collision Volumes:CollisionSphere");
00106 PStatCollector GraphicsEngine::_test_sphere_pcollector("Collision Tests:CollisionSphere");
00107 PStatCollector GraphicsEngine::_volume_box_pcollector("Collision Volumes:CollisionBox");
00108 PStatCollector GraphicsEngine::_test_box_pcollector("Collision Tests:CollisionBox");
00109 PStatCollector GraphicsEngine::_volume_tube_pcollector("Collision Volumes:CollisionTube");
00110 PStatCollector GraphicsEngine::_test_tube_pcollector("Collision Tests:CollisionTube");
00111 PStatCollector GraphicsEngine::_volume_inv_sphere_pcollector("Collision Volumes:CollisionInvSphere");
00112 PStatCollector GraphicsEngine::_test_inv_sphere_pcollector("Collision Tests:CollisionInvSphere");
00113 PStatCollector GraphicsEngine::_volume_geom_pcollector("Collision Volumes:CollisionGeom");
00114 PStatCollector GraphicsEngine::_test_geom_pcollector("Collision Tests:CollisionGeom");
00115 PStatCollector GraphicsEngine::_occlusion_untested_pcollector("Occlusion results:Not tested");
00116 PStatCollector GraphicsEngine::_occlusion_passed_pcollector("Occlusion results:Visible");
00117 PStatCollector GraphicsEngine::_occlusion_failed_pcollector("Occlusion results:Occluded");
00118 PStatCollector GraphicsEngine::_occlusion_tests_pcollector("Occlusion tests");
00119 
00120 ////////////////////////////////////////////////////////////////////
00121 //     Function: GraphicsEngine::Constructor
00122 //       Access: Published
00123 //  Description: Creates a new GraphicsEngine object.  The Pipeline is
00124 //               normally left to default to NULL, which indicates the
00125 //               global render pipeline, but it may be any Pipeline
00126 //               you choose.
00127 ////////////////////////////////////////////////////////////////////
00128 GraphicsEngine::
00129 GraphicsEngine(Pipeline *pipeline) :
00130   _pipeline(pipeline),
00131   _app("app"),
00132   _lock("GraphicsEngine::_lock"),
00133   _loaded_textures_lock("GraphicsEngine::_loaded_textures_lock")
00134 {
00135   if (_pipeline == (Pipeline *)NULL) {
00136     _pipeline = Pipeline::get_render_pipeline();
00137   }
00138 
00139   _windows_sorted = true;
00140   _window_sort_index = 0;
00141   _needs_open_windows = false;
00142   
00143   set_threading_model(GraphicsThreadingModel(threading_model));
00144   if (!_threading_model.is_default()) {
00145     display_cat.info()
00146       << "Using threading model " << _threading_model << "\n";
00147   }
00148   _auto_flip = auto_flip;
00149   _portal_enabled = false;
00150   _flip_state = FS_flip;
00151 
00152   _singular_warning_last_frame = false;
00153   _singular_warning_this_frame = false;
00154 }
00155 
00156 ////////////////////////////////////////////////////////////////////
00157 //     Function: GraphicsEngine::Destructor
00158 //       Access: Published
00159 //  Description: Gracefully cleans up the graphics engine and its
00160 //               related threads and windows.
00161 ////////////////////////////////////////////////////////////////////
00162 GraphicsEngine::
00163 ~GraphicsEngine() {
00164 #ifdef DO_PSTATS
00165   if (_app_pcollector.is_started()) {
00166     _app_pcollector.stop();
00167   }
00168 #endif
00169 
00170   remove_all_windows();
00171 }
00172 
00173 ////////////////////////////////////////////////////////////////////
00174 //     Function: GraphicsEngine::set_threading_model
00175 //       Access: Published
00176 //  Description: Specifies how future objects created via make_gsg(),
00177 //               make_buffer(), and make_window() will be threaded.
00178 //               This does not affect any already-created objects.
00179 ////////////////////////////////////////////////////////////////////
00180 void GraphicsEngine::
00181 set_threading_model(const GraphicsThreadingModel &threading_model) {
00182   if (!Thread::is_threading_supported()) {
00183     if (!threading_model.is_single_threaded()) {
00184       display_cat.warning()
00185         << "Threading model " << threading_model
00186         << " requested but threading is not available.  Ignoring.\n";
00187       return;
00188     }
00189   }
00190     
00191 #ifndef THREADED_PIPELINE
00192   if (!threading_model.is_single_threaded()) {
00193     display_cat.warning()
00194       << "Threading model " << threading_model
00195       << " requested but multithreaded render pipelines not enabled in build.\n";
00196     if (!allow_nonpipeline_threads) {
00197       display_cat.warning()
00198         << "Ignoring requested threading model.\n";
00199       return;
00200     }
00201     display_cat.warning()
00202       << "Danger!  Creating requested render threads anyway!\n";
00203   }
00204 #endif  // THREADED_PIPELINE
00205   ReMutexHolder holder(_lock);
00206   _threading_model = threading_model;
00207 }
00208 
00209 ////////////////////////////////////////////////////////////////////
00210 //     Function: GraphicsEngine::get_threading_model
00211 //       Access: Published
00212 //  Description: Returns the threading model that will be applied to
00213 //               future objects.  See set_threading_model().
00214 ////////////////////////////////////////////////////////////////////
00215 GraphicsThreadingModel GraphicsEngine::
00216 get_threading_model() const {
00217   GraphicsThreadingModel result;
00218   {
00219     ReMutexHolder holder(_lock);
00220     result = _threading_model;
00221   }
00222   return result;
00223 }
00224 
00225 // THIS IS THE OLD CODE FOR make_gsg
00226 //  PT(GraphicsStateGuardian) gsg = pipe->make_gsg(properties, share_with);
00227 
00228 
00229 
00230 ////////////////////////////////////////////////////////////////////
00231 //     Function: GraphicsEngine::make_output
00232 //       Access: Published
00233 //  Description: Creates a new window (or buffer) and returns it.
00234 //               The GraphicsEngine becomes the owner of the window,
00235 //               it will persist at least until remove_window() is
00236 //               called later.
00237 //
00238 //               If a null pointer is supplied for the gsg, then this
00239 //               routine will create a new gsg.
00240 //               
00241 //               This routine is only called from the app thread.
00242 ////////////////////////////////////////////////////////////////////
00243 
00244 GraphicsOutput *GraphicsEngine::
00245 make_output(GraphicsPipe *pipe,
00246             const string &name, int sort,
00247             const FrameBufferProperties &fb_prop,
00248             const WindowProperties &win_prop,
00249             int flags,
00250             GraphicsStateGuardian *gsg,
00251             GraphicsOutput *host) {
00252 
00253   //  The code here is tricky because the gsg that is passed in
00254   //  might be in the uninitialized state.  As a result,
00255   //  pipe::make_output may not be able to tell which DirectX
00256   //  capabilities or OpenGL extensions are supported and which
00257   //  are not.  Worse yet, it can't query the API, because that
00258   //  can only be done from the draw thread, and this is the app
00259   //  thread.
00260   //
00261   //  So here's the workaround: this routine calls pipe::make_output,
00262   //  which returns a "non-certified" window.  That means that
00263   //  the pipe doesn't promise that the draw thread will actually
00264   //  succeed in initializing the window.  This routine then calls
00265   //  open_windows, which attempts to initialize the window.
00266   //
00267   //  If open_windows fails to initialize the window, then
00268   //  this routine will ask pipe::make_output to try again, this
00269   //  time using a different set of OpenGL extensions or DirectX
00270   //  capabilities.   This is what the "retry" parameter to
00271   //  pipe::make_output is for - it specifies, in an abstract
00272   //  manner, which set of capabilties/extensions to try.
00273   //
00274   //  The only problem with this design is that it requires the
00275   //  engine to call open_windows, which is slow.  To make
00276   //  things faster, the pipe can choose to "precertify"
00277   //  its creations.  If it chooses to do so, this is a guarantee
00278   //  that the windows it returns will not fail in open_windows.
00279   //  However, most graphics pipes will only precertify if you
00280   //  pass them an already-initialized gsg.  Long story short,
00281   //  if you want make_output to be fast, use an
00282   //  already-initialized gsg.
00283 
00284   // Simplify the input parameters.
00285   
00286   int x_size = 0, y_size = 0;
00287   if (win_prop.has_size()) {
00288     x_size = win_prop.get_x_size();
00289     y_size = win_prop.get_y_size();
00290   }
00291   if ((x_size == 0)&&(y_size == 0)) {
00292     flags |= GraphicsPipe::BF_size_track_host;
00293   }
00294   if (host != 0) {
00295     host = host->get_host();
00296   }
00297 
00298   // If a gsg or host was supplied, and either is not yet initialized,
00299   // then call open_windows to get both ready.  If that fails,
00300   // give up on using the supplied gsg and host.
00301 
00302   if (host == (GraphicsOutput *)NULL) {
00303     if (gsg != (GraphicsStateGuardian*)NULL) {
00304       if ((!gsg->is_valid())||(gsg->needs_reset())) {
00305         open_windows();
00306       }
00307       if ((!gsg->is_valid())||(gsg->needs_reset())) {
00308         gsg = NULL;
00309       }
00310     }
00311   } else {
00312     if ((host->get_gsg()==0)||
00313         (!host->is_valid())||
00314         (!host->get_gsg()->is_valid())||
00315         (host->get_gsg()->needs_reset())) {
00316       open_windows();
00317     }
00318     if ((host->get_gsg()==0)||
00319         (!host->is_valid())||
00320         (!host->get_gsg()->is_valid())||
00321         (host->get_gsg()->needs_reset())) {
00322       host = NULL;
00323       gsg = NULL;
00324     } else {
00325       gsg = host->get_gsg();
00326     }
00327   }
00328 
00329   // Sanity check everything.
00330 
00331   GraphicsThreadingModel threading_model = get_threading_model();
00332   nassertr(pipe != (GraphicsPipe *)NULL, NULL);
00333   if (gsg != (GraphicsStateGuardian *)NULL) {
00334     nassertr(pipe == gsg->get_pipe(), NULL);
00335     nassertr(this == gsg->get_engine(), NULL);
00336     nassertr(threading_model.get_draw_name() ==
00337              gsg->get_threading_model().get_draw_name(), NULL);
00338   }
00339 
00340   // Are we really asking for a callback window?
00341   if ((flags & GraphicsPipe::BF_require_callback_window)!=0) {
00342     PT(GraphicsStateGuardian) this_gsg = gsg;
00343     if (this_gsg == (GraphicsStateGuardian *)NULL) {
00344       // If we don't already have a GSG, we have to ask the pipe to
00345       // make a new one, unencumbered by window dressing.
00346       this_gsg = pipe->make_callback_gsg(this);
00347     }
00348     if (this_gsg != (GraphicsStateGuardian *)NULL) {
00349       CallbackGraphicsWindow *window = new CallbackGraphicsWindow(this, pipe, name, fb_prop, win_prop, flags, this_gsg);
00350       window->_sort = sort;
00351       do_add_window(window, threading_model);
00352       do_add_gsg(window->get_gsg(), pipe, threading_model);
00353       display_cat.info() << "Created output of type CallbackGraphicsWindow\n";
00354       return window;
00355     }
00356 
00357     // Couldn't make a callback window, because the pipe wouldn't make
00358     // an unencumbered GSG.
00359     return NULL;
00360   }
00361   
00362   // Determine if a parasite buffer meets the user's specs.
00363 
00364   bool can_use_parasite = false;
00365   if ((host != 0)&&
00366       ((flags&GraphicsPipe::BF_require_window)==0)&&
00367       ((flags&GraphicsPipe::BF_require_callback_window)==0)&&
00368       ((flags&GraphicsPipe::BF_refuse_parasite)==0)&&
00369       ((flags&GraphicsPipe::BF_can_bind_color)==0)&&
00370       ((flags&GraphicsPipe::BF_can_bind_every)==0)&&
00371       ((flags&GraphicsPipe::BF_rtt_cumulative)==0)) {
00372     if ((flags&GraphicsPipe::BF_fb_props_optional) ||
00373         (host->get_fb_properties().subsumes(fb_prop))) {
00374       can_use_parasite = true;
00375     }
00376   }
00377 
00378   // If parasite buffers are preferred, then try a parasite first.
00379   // Even if prefer-parasite-buffer is set, parasites are not preferred
00380   // if the host window is too small, or if the host window does not
00381   // have the requested properties.
00382   
00383   if ((prefer_parasite_buffer) &&
00384       (can_use_parasite) &&
00385       (x_size <= host->get_x_size())&&
00386       (y_size <= host->get_y_size())&&
00387       (host->get_fb_properties().subsumes(fb_prop))) {
00388     ParasiteBuffer *buffer = new ParasiteBuffer(host, name, x_size, y_size, flags);
00389     buffer->_sort = sort;
00390     do_add_window(buffer, threading_model);
00391     do_add_gsg(host->get_gsg(), pipe, threading_model);
00392     display_cat.info() << "Created output of type ParasiteBuffer\n";
00393     return buffer;
00394   }
00395 
00396   // If force-parasite-buffer is set, we create a parasite buffer even
00397   // if it's less than ideal.  You might set this if you really don't
00398   // trust your graphics driver's support for offscreen buffers.
00399   if (force_parasite_buffer && can_use_parasite) {
00400     ParasiteBuffer *buffer = new ParasiteBuffer(host, name, x_size, y_size, flags);
00401     buffer->_sort = sort;
00402     do_add_window(buffer, threading_model);
00403     do_add_gsg(host->get_gsg(), pipe, threading_model);
00404     display_cat.info() << "Created output of type ParasiteBuffer\n";
00405     return buffer;
00406   }
00407 
00408   // Ask the pipe to create a window.
00409   
00410   for (int retry=0; retry<10; retry++) {
00411     bool precertify = false;
00412     PT(GraphicsOutput) window = 
00413       pipe->make_output(name, fb_prop, win_prop, flags, this, gsg, host, retry, precertify);
00414     if (window != (GraphicsOutput *)NULL) {
00415       window->_sort = sort;
00416       if ((precertify) && (gsg != 0) && (window->get_gsg()==gsg)) {
00417         do_add_window(window, threading_model);
00418         do_add_gsg(window->get_gsg(), pipe, threading_model);
00419         display_cat.info()
00420           << "Created output of type " << window->get_type() << "\n";
00421         return window;
00422       }
00423       do_add_window(window, threading_model);
00424       open_windows();
00425       if (window->is_valid()) {
00426         do_add_gsg(window->get_gsg(), pipe, threading_model);
00427         display_cat.info()
00428           << "Created output of type " << window->get_type() << "\n";
00429 
00430         if (window->get_fb_properties().subsumes(fb_prop)) {
00431           return window;
00432         } else {
00433           if (flags & GraphicsPipe::BF_fb_props_optional) {
00434             display_cat.warning()
00435               << "FrameBufferProperties available less than requested.\n";
00436             return window;
00437           }
00438           display_cat.error()
00439             << "Could not get requested FrameBufferProperties; abandoning window.\n";
00440           display_cat.error(false)
00441             << "  requested: " << fb_prop << "\n"
00442             << "  got: " << window->get_fb_properties() << "\n";
00443         }
00444       } else {
00445         display_cat.info()
00446           << window->get_type() << " wouldn't open; abandoning.\n";
00447         display_cat.debug(false)
00448           << "  requested: " << fb_prop << "\n";
00449       }
00450 
00451       // No good; delete the window and keep trying.
00452       bool removed = remove_window(window);
00453       nassertr(removed, NULL);
00454     }
00455   }
00456   
00457   // Parasite buffers were not preferred, but the pipe could not
00458   // create a window to the user's specs.  Try a parasite as a
00459   // last hope.
00460   
00461   if (can_use_parasite) {
00462     ParasiteBuffer *buffer = new ParasiteBuffer(host, name, x_size, y_size, flags);
00463     buffer->_sort = sort;
00464     do_add_window(buffer, threading_model);
00465     do_add_gsg(host->get_gsg(), pipe, threading_model);
00466     display_cat.info() << "Created output of type ParasiteBuffer\n";
00467     return buffer;
00468   }
00469 
00470   // Could not create a window to the user's specs.
00471 
00472   return NULL;
00473 }
00474 
00475 ////////////////////////////////////////////////////////////////////
00476 //     Function: GraphicsEngine::remove_window
00477 //       Access: Published
00478 //  Description: Removes the indicated window or offscreen buffer from
00479 //               the set of windows that will be processed when
00480 //               render_frame() is called.  This also closes the
00481 //               window if it is open, and removes the window from its
00482 //               GraphicsPipe, allowing the window to be destructed if
00483 //               there are no other references to it.  (However, the
00484 //               window may not be actually closed until next frame,
00485 //               if it is controlled by a sub-thread.)
00486 //
00487 //               The return value is true if the window was removed,
00488 //               false if it was not found.
00489 //
00490 //               Unlike remove_all_windows(), this function does not
00491 //               terminate any of the threads that may have been
00492 //               started to service this window; they are left running
00493 //               (since you might open a new window later on these
00494 //               threads).  If your intention is to clean up before
00495 //               shutting down, it is better to call
00496 //               remove_all_windows() then to call remove_window() one
00497 //               at a time.
00498 ////////////////////////////////////////////////////////////////////
00499 bool GraphicsEngine::
00500 remove_window(GraphicsOutput *window) {
00501   nassertr(window != NULL, false);
00502   Thread *current_thread = Thread::get_current_thread();
00503 
00504   // First, make sure we know what this window is.
00505   PT(GraphicsOutput) ptwin = window;
00506   size_t count;
00507   {
00508     ReMutexHolder holder(_lock, current_thread);
00509     if (!_windows_sorted) {
00510       do_resort_windows();
00511     }
00512     count = _windows.erase(ptwin);
00513   }
00514   if (count == 0) {
00515     // Never heard of this window.  Do nothing.
00516     return false;
00517   }
00518 
00519   do_remove_window(window, current_thread);
00520 
00521   GraphicsStateGuardian *gsg = window->get_gsg();
00522   if (gsg != (GraphicsStateGuardian *)NULL) {
00523     PreparedGraphicsObjects *pgo = gsg->get_prepared_objects();
00524     if (pgo != (PreparedGraphicsObjects *)NULL) {
00525       // Check to see if any other still-active windows share this
00526       // context.
00527       bool any_common = false;
00528       {
00529         ReMutexHolder holder(_lock, current_thread);
00530         Windows::iterator wi;
00531         for (wi = _windows.begin(); wi != _windows.end() && !any_common; ++wi) {
00532           GraphicsStateGuardian *gsg2 = (*wi)->get_gsg();
00533           if (gsg2 != (GraphicsStateGuardian *)NULL &&
00534               gsg2->get_prepared_objects() == pgo) {
00535             any_common = true;
00536           }
00537         }
00538       }
00539       if (!any_common) {
00540         // If no windows still use this context, release all textures,
00541         // etc.  We do this in case there is a floating pointer
00542         // somewhere keeping the GSG from destructing when its window
00543         // goes away.  A leaked GSG pointer is bad enough, but there's
00544         // no reason we also need to keep around all of the objects
00545         // allocated on graphics memory.
00546         pgo->release_all();
00547       }
00548     }
00549   }
00550 
00551   nassertr(count == 1, true);
00552   return true;
00553 }
00554 
00555 ////////////////////////////////////////////////////////////////////
00556 //     Function: GraphicsEngine::remove_all_windows
00557 //       Access: Published
00558 //  Description: Removes and closes all windows from the engine.  This
00559 //               also cleans up and terminates any threads that have
00560 //               been started to service those windows.
00561 ////////////////////////////////////////////////////////////////////
00562 void GraphicsEngine::
00563 remove_all_windows() {
00564   Thread *current_thread = Thread::get_current_thread();
00565 
00566   // Let's move the _windows vector into a local copy first, and walk
00567   // through that local copy, just in case someone we call during the
00568   // loop attempts to modify _windows.  I don't know what code would
00569   // be doing this, but it appeared to be happening, and this worked
00570   // around it.
00571   Windows old_windows;
00572   old_windows.swap(_windows);
00573   Windows::iterator wi;
00574   for (wi = old_windows.begin(); wi != old_windows.end(); ++wi) {
00575     GraphicsOutput *win = (*wi);
00576     nassertv(win != NULL);
00577     do_remove_window(win, current_thread);
00578     GraphicsStateGuardian *gsg = win->get_gsg();
00579     if (gsg != (GraphicsStateGuardian *)NULL) {
00580       gsg->release_all();
00581     }
00582   }
00583 
00584   _app.do_close(this, current_thread);
00585   _app.do_pending(this, current_thread);
00586   terminate_threads(current_thread);
00587 
00588   // It seems a safe assumption that we're about to exit the
00589   // application or otherwise shut down Panda.  Although it's a bit of
00590   // a hack, since it's not really related to removing windows, this
00591   // would nevertheless be a fine time to ensure the model cache (if
00592   // any) has been flushed to disk.
00593   BamCache *cache = BamCache::get_global_ptr();
00594   cache->flush_index();
00595 
00596   // And, hey, let's stop the vertex paging threads, if any.
00597   VertexDataPage::stop_threads();
00598 
00599   AsyncTaskManager::get_global_ptr()->stop_threads();
00600 
00601 #ifdef DO_PSTATS
00602   PStatClient::get_global_pstats()->disconnect();
00603 #endif
00604 
00605   // Well, and why not clean up all threads here?
00606   Thread::prepare_for_exit();
00607 }
00608 
00609 ////////////////////////////////////////////////////////////////////
00610 //     Function: GraphicsEngine::reset_all_windows
00611 //       Access: Published
00612 //  Description: Resets the framebuffer of the current window.  This
00613 //               is currently used by DirectX 8 only. It calls a
00614 //               reset_window function on each active window to 
00615 //               release/create old/new framebuffer
00616 ////////////////////////////////////////////////////////////////////
00617 void GraphicsEngine::
00618 reset_all_windows(bool swapchain) {
00619   Windows::iterator wi;
00620   for (wi = _windows.begin(); wi != _windows.end(); ++wi) {
00621     GraphicsOutput *win = (*wi);
00622     //    if (win->is_active())
00623     win->reset_window(swapchain);
00624   }
00625 }
00626 
00627 ////////////////////////////////////////////////////////////////////
00628 //     Function: GraphicsEngine::is_empty
00629 //       Access: Published
00630 //  Description: Returns true if there are no windows or buffers
00631 //               managed by the engine, false if there is at least
00632 //               one.
00633 ////////////////////////////////////////////////////////////////////
00634 bool GraphicsEngine::
00635 is_empty() const {
00636   return _windows.empty();
00637 }
00638 
00639 ////////////////////////////////////////////////////////////////////
00640 //     Function: GraphicsEngine::get_num_windows
00641 //       Access: Published
00642 //  Description: Returns the number of windows (or buffers) managed by
00643 //               the engine.
00644 ////////////////////////////////////////////////////////////////////
00645 int GraphicsEngine::
00646 get_num_windows() const {
00647   return _windows.size();
00648 }
00649 
00650 ////////////////////////////////////////////////////////////////////
00651 //     Function: GraphicsEngine::get_window
00652 //       Access: Published
00653 //  Description: Returns the nth window or buffers managed by the
00654 //               engine, in sorted order.
00655 ////////////////////////////////////////////////////////////////////
00656 GraphicsOutput *GraphicsEngine::
00657 get_window(int n) const {
00658   nassertr(n >= 0 && n < (int)_windows.size(), NULL);
00659 
00660   if (!_windows_sorted) {
00661     ((GraphicsEngine *)this)->do_resort_windows();
00662   }
00663   return _windows[n];
00664 }
00665 
00666 ////////////////////////////////////////////////////////////////////
00667 //     Function: GraphicsEngine::render_frame
00668 //       Access: Published
00669 //  Description: Renders the next frame in all the registered windows,
00670 //               and flips all of the frame buffers.
00671 ////////////////////////////////////////////////////////////////////
00672 void GraphicsEngine::
00673 render_frame() {
00674   Thread *current_thread = Thread::get_current_thread();
00675   ReMutexHolder public_holder(_public_lock);
00676 
00677   // Since this gets called every frame, we should take advantage of
00678   // the opportunity to flush the cache if necessary.
00679   BamCache *cache = BamCache::get_global_ptr();
00680   cache->consider_flush_index();
00681 
00682   // Anything that happens outside of GraphicsEngine::render_frame()
00683   // is deemed to be App.
00684 #ifdef DO_PSTATS
00685   _render_frame_pcollector.start();
00686   if (_app_pcollector.is_started()) {
00687     _app_pcollector.stop();
00688   }
00689 #endif
00690 
00691   if (_needs_open_windows) {
00692     // Make sure our buffers and windows are fully realized before we
00693     // render a frame.  We do this particularly to realize our
00694     // offscreen buffers, so that we don't render a frame before the
00695     // offscreen buffers are ready (which might result in a frame
00696     // going by without some textures having been rendered).
00697     open_windows();
00698   }
00699 
00700   ClockObject *global_clock = ClockObject::get_global_clock();
00701 
00702   if (display_cat.is_spam()) {
00703     display_cat.spam()
00704       << "render_frame() - frame " << global_clock->get_frame_count() << "\n";
00705   }
00706 
00707   {
00708     ReMutexHolder holder(_lock, current_thread);
00709 
00710     if (!_windows_sorted) {
00711       do_resort_windows();
00712     }
00713     
00714     if (sync_flip && _flip_state != FS_flip) {
00715       do_flip_frame(current_thread);
00716     }
00717     
00718     // Are any of the windows ready to be deleted?
00719     Windows new_windows;
00720     new_windows.reserve(_windows.size());
00721     Windows::iterator wi;
00722     for (wi = _windows.begin(); wi != _windows.end(); ++wi) {
00723       GraphicsOutput *win = (*wi);
00724       nassertv(win != NULL);
00725       if (win->get_delete_flag()) {
00726         do_remove_window(win, current_thread);
00727         
00728       } else {
00729         new_windows.push_back(win);
00730         
00731         // Let's calculate each scene's bounding volume here in App,
00732         // before we cycle the pipeline.  The cull traversal will
00733         // calculate it anyway, but if we calculate it in App first
00734         // before it gets calculated in the Cull thread, it will be more
00735         // likely to stick for subsequent frames, so we won't have to
00736         // recompute it each frame.
00737         int num_drs = win->get_num_active_display_regions();
00738         for (int i = 0; i < num_drs; ++i) {
00739           DisplayRegion *dr = win->get_active_display_region(i);
00740           if (dr != (DisplayRegion *)NULL) {
00741             NodePath camera_np = dr->get_camera(current_thread);
00742             if (!camera_np.is_empty()) {
00743               Camera *camera = DCAST(Camera, camera_np.node());
00744               NodePath scene = camera->get_scene();
00745               if (scene.is_empty()) {
00746                 scene = camera_np.get_top(current_thread);
00747               }
00748               if (!scene.is_empty()) {
00749                 scene.get_bounds(current_thread);
00750               }
00751             }
00752           }
00753         }
00754       }
00755     }
00756     _windows.swap(new_windows);
00757 
00758     // Go ahead and release any textures' ram images for textures that
00759     // were drawn in the previous frame.
00760     {
00761       MutexHolder holder2(_loaded_textures_lock);
00762       LoadedTextures::iterator lti;
00763       for (lti = _loaded_textures.begin(); lti != _loaded_textures.end(); ++lti) {
00764         LoadedTexture &lt = (*lti);
00765         if (lt._tex->get_image_modified() == lt._image_modified) {
00766           lt._tex->texture_uploaded();
00767         }
00768       }
00769       _loaded_textures.clear();
00770     }
00771     
00772     // Now it's time to do any drawing from the main frame--after all of
00773     // the App code has executed, but before we begin the next frame.
00774     _app.do_frame(this, current_thread);
00775     
00776     // Grab each thread's mutex again after all windows have flipped,
00777     // and wait for the thread to finish.
00778     {
00779       PStatTimer timer(_wait_pcollector, current_thread);
00780       Threads::const_iterator ti;
00781       for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
00782         RenderThread *thread = (*ti).second;
00783         thread->_cv_mutex.acquire();
00784         
00785         while (thread->_thread_state != TS_wait) {
00786           thread->_cv_done.wait();
00787         }
00788       }
00789     }
00790     
00791 #if defined(THREADED_PIPELINE) && defined(DO_PSTATS)
00792     _cyclers_pcollector.set_level(_pipeline->get_num_cyclers());
00793     _dirty_cyclers_pcollector.set_level(_pipeline->get_num_dirty_cyclers());
00794     
00795 #ifdef DEBUG_THREADS
00796     if (PStatClient::is_connected()) {
00797       _pipeline->iterate_all_cycler_types(pstats_count_cycler_type, this);
00798       _pipeline->iterate_dirty_cycler_types(pstats_count_dirty_cycler_type, this);
00799     }
00800 #endif  // DEBUG_THREADS
00801     
00802 #endif  // THREADED_PIPELINE && DO_PSTATS
00803     
00804     GeomCacheManager::flush_level();
00805     CullTraverser::flush_level();
00806     RenderState::flush_level();
00807     TransformState::flush_level();
00808     CullableObject::flush_level();
00809     
00810     // Now cycle the pipeline and officially begin the next frame.
00811 #ifdef THREADED_PIPELINE
00812     {
00813       PStatTimer timer(_cycle_pcollector, current_thread);
00814       _pipeline->cycle();
00815     }
00816 #endif  // THREADED_PIPELINE
00817     
00818     global_clock->tick(current_thread);
00819     if (global_clock->check_errors(current_thread)) {
00820       throw_event("clock_error");
00821     }
00822     
00823 #ifdef DO_PSTATS
00824     PStatClient::main_tick();
00825     
00826     // Reset our pcollectors that track data across the frame.
00827     CullTraverser::_nodes_pcollector.clear_level();
00828     CullTraverser::_geom_nodes_pcollector.clear_level();
00829     CullTraverser::_geoms_pcollector.clear_level();
00830     GeomCacheManager::_geom_cache_active_pcollector.clear_level();
00831     GeomCacheManager::_geom_cache_record_pcollector.clear_level();
00832     GeomCacheManager::_geom_cache_erase_pcollector.clear_level();
00833     GeomCacheManager::_geom_cache_evict_pcollector.clear_level();
00834     
00835     GraphicsStateGuardian::init_frame_pstats();
00836     
00837     _transform_states_pcollector.set_level(TransformState::get_num_states());
00838     _render_states_pcollector.set_level(RenderState::get_num_states());
00839     if (pstats_unused_states) {
00840       _transform_states_unused_pcollector.set_level(TransformState::get_num_unused_states());
00841       _render_states_unused_pcollector.set_level(RenderState::get_num_unused_states());
00842     }
00843     
00844     _sw_sprites_pcollector.clear_level();
00845     
00846     _cnode_volume_pcollector.clear_level();
00847     _gnode_volume_pcollector.clear_level();
00848     _geom_volume_pcollector.clear_level();
00849     _node_volume_pcollector.clear_level();
00850     _volume_pcollector.clear_level();
00851     _test_pcollector.clear_level();
00852     _volume_polygon_pcollector.clear_level();
00853     _test_polygon_pcollector.clear_level();
00854     _volume_plane_pcollector.clear_level();
00855     _test_plane_pcollector.clear_level();
00856     _volume_sphere_pcollector.clear_level();
00857     _test_sphere_pcollector.clear_level();
00858     _volume_box_pcollector.clear_level();
00859     _test_box_pcollector.clear_level();
00860     _volume_tube_pcollector.clear_level();
00861     _test_tube_pcollector.clear_level();
00862     _volume_inv_sphere_pcollector.clear_level();
00863     _test_inv_sphere_pcollector.clear_level();
00864     _volume_geom_pcollector.clear_level();
00865     _test_geom_pcollector.clear_level();
00866     _occlusion_untested_pcollector.clear_level();
00867     _occlusion_passed_pcollector.clear_level();
00868     _occlusion_failed_pcollector.clear_level();
00869     _occlusion_tests_pcollector.clear_level();
00870     
00871     if (PStatClient::is_connected()) {
00872       size_t small_buf = GeomVertexArrayData::get_small_lru()->get_total_size();
00873       size_t independent = GeomVertexArrayData::get_independent_lru()->get_total_size();
00874       size_t resident = VertexDataPage::get_global_lru(VertexDataPage::RC_resident)->get_total_size();
00875       size_t compressed = VertexDataPage::get_global_lru(VertexDataPage::RC_compressed)->get_total_size();
00876       size_t pending = VertexDataPage::get_pending_lru()->get_total_size();
00877       
00878       VertexDataSaveFile *save_file = VertexDataPage::get_save_file();
00879       size_t total_disk = save_file->get_total_file_size();
00880       size_t used_disk = save_file->get_used_file_size();
00881       
00882       _vertex_data_small_pcollector.set_level(small_buf);
00883       _vertex_data_independent_pcollector.set_level(independent);
00884       _vertex_data_pending_pcollector.set_level(pending);
00885       _vertex_data_resident_pcollector.set_level(resident);
00886       _vertex_data_compressed_pcollector.set_level(compressed);
00887       _vertex_data_unused_disk_pcollector.set_level(total_disk - used_disk);
00888       _vertex_data_used_disk_pcollector.set_level(used_disk);
00889     }
00890     
00891 #endif  // DO_PSTATS
00892     
00893     GeomVertexArrayData::lru_epoch();
00894     
00895     // Now signal all of our threads to begin their next frame.
00896     Threads::const_iterator ti;
00897     for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
00898       RenderThread *thread = (*ti).second;
00899       if (thread->_thread_state == TS_wait) {
00900         thread->_thread_state = TS_do_frame;
00901         thread->_cv_start.notify();
00902       }
00903       thread->_cv_mutex.release();
00904     }
00905     
00906     // Some threads may still be drawing, so indicate that we have to
00907     // wait for those threads before we can flip.
00908     _flip_state = _auto_flip ? FS_flip : FS_draw;
00909   }
00910 
00911   // Now the lock is released.
00912   
00913   if (yield_timeslice) {
00914     // Nap for a moment to yield the timeslice, to be polite to other
00915     // running applications.
00916     PStatTimer timer(_yield_pcollector, current_thread);
00917     Thread::force_yield();
00918   } else if (!Thread::is_true_threads()) { 
00919     PStatTimer timer(_yield_pcollector, current_thread);
00920     Thread::consider_yield();
00921   }
00922   
00923   // Anything that happens outside of GraphicsEngine::render_frame()
00924   // is deemed to be App.
00925   _app_pcollector.start();
00926   _render_frame_pcollector.stop();
00927 }
00928 
00929 
00930 ////////////////////////////////////////////////////////////////////
00931 //     Function: GraphicsEngine::open_windows
00932 //       Access: Published
00933 //  Description: Fully opens (or closes) any windows that have
00934 //               recently been requested open or closed, without
00935 //               rendering any frames.  It is not necessary to call
00936 //               this explicitly, since windows will be automatically
00937 //               opened or closed when the next frame is rendered, but
00938 //               you may call this if you want your windows now
00939 //               without seeing a frame go by.
00940 ////////////////////////////////////////////////////////////////////
00941 void GraphicsEngine::
00942 open_windows() {
00943   Thread *current_thread = Thread::get_current_thread();
00944 
00945   ReMutexHolder holder(_lock, current_thread);
00946 
00947   if (!_windows_sorted) {
00948     do_resort_windows();
00949   }
00950 
00951   // We do it twice, to allow both cull and draw to process the
00952   // window.
00953   for (int i = 0; i < 2; ++i) {
00954     _app.do_windows(this, current_thread);
00955     _app.do_pending(this, current_thread);
00956 
00957     PStatTimer timer(_wait_pcollector, current_thread);
00958     Threads::const_iterator ti;
00959     for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
00960       RenderThread *thread = (*ti).second;
00961       thread->_cv_mutex.acquire();
00962       
00963       while (thread->_thread_state != TS_wait) {
00964         thread->_cv_done.wait();
00965       }
00966       
00967       thread->_thread_state = TS_do_windows;
00968       thread->_cv_start.notify();
00969       thread->_cv_mutex.release();
00970     }
00971   }
00972 
00973   _needs_open_windows = false;
00974 }
00975 
00976 ////////////////////////////////////////////////////////////////////
00977 //     Function: GraphicsEngine::sync_frame
00978 //       Access: Published
00979 //  Description: Waits for all the threads that started drawing their
00980 //               last frame to finish drawing.  The windows are not
00981 //               yet flipped when this returns; see also flip_frame().
00982 //               It is not usually necessary to call this explicitly,
00983 //               unless you need to see the previous frame right away.
00984 ////////////////////////////////////////////////////////////////////
00985 void GraphicsEngine::
00986 sync_frame() {
00987   Thread *current_thread = Thread::get_current_thread();
00988   ReMutexHolder holder(_lock, current_thread);
00989 
00990   if (_flip_state == FS_draw) {
00991     do_sync_frame(current_thread);
00992   }
00993 }
00994 
00995 
00996 ////////////////////////////////////////////////////////////////////
00997 //     Function: GraphicsEngine::ready_flip
00998 //       Access: Published
00999 //  Description: Waits for all the threads that started drawing their
01000 //               last frame to finish drawing. Returns when all threads have
01001 //               actually finished drawing, as opposed to 'sync_frame'
01002 //               we seems to return once all draw calls have been submitted.
01003 //               Calling 'flip_frame' after this function should immediately
01004 //               cause a buffer flip.  This function will only work in
01005 //               opengl right now, for all other graphics pipelines it will 
01006 //               simply return immediately.  In opengl it's a bit of a hack:
01007 //               it will attempt to read a single pixel from the frame buffer to
01008 //               force the graphics card to finish drawing before it returns
01009 ////////////////////////////////////////////////////////////////////
01010 void GraphicsEngine::
01011 ready_flip() {
01012   Thread *current_thread = Thread::get_current_thread();
01013   ReMutexHolder holder(_lock, current_thread);
01014 
01015   if (_flip_state == FS_draw) {
01016     do_ready_flip(current_thread);
01017   }
01018 }
01019 
01020 ////////////////////////////////////////////////////////////////////
01021 //     Function: GraphicsEngine::flip_frame
01022 //       Access: Published
01023 //  Description: Waits for all the threads that started drawing their
01024 //               last frame to finish drawing, and then flips all the
01025 //               windows.  It is not usually necessary to call this
01026 //               explicitly, unless you need to see the previous frame
01027 //               right away.
01028 ////////////////////////////////////////////////////////////////////
01029 void GraphicsEngine::
01030 flip_frame() {
01031   Thread *current_thread = Thread::get_current_thread();
01032   ReMutexHolder holder(_lock, current_thread);
01033 
01034   if (_flip_state != FS_flip) {
01035     do_flip_frame(current_thread);
01036   }
01037 }
01038 
01039 ////////////////////////////////////////////////////////////////////
01040 //     Function: GraphicsEngine::extract_texture_data
01041 //       Access: Published
01042 //  Description: Asks the indicated GraphicsStateGuardian to retrieve
01043 //               the texture memory image of the indicated texture and
01044 //               store it in the texture's ram_image field.  The image
01045 //               can then be written to disk via Texture::write(), or
01046 //               otherwise manipulated on the CPU.
01047 //
01048 //               This is useful for retrieving the contents of a
01049 //               texture that has been somehow generated on the
01050 //               graphics card, instead of having been loaded the
01051 //               normal way via Texture::read() or Texture::load().
01052 //               It is particularly useful for getting the data
01053 //               associated with a compressed texture image.
01054 //
01055 //               Since this requires a round-trip to the draw thread,
01056 //               it may require waiting for the current thread to
01057 //               finish rendering if it is called in a multithreaded
01058 //               environment.  However, you can call this several
01059 //               consecutive times on different textures for little
01060 //               additional cost.
01061 //
01062 //               If the texture has not yet been loaded to the GSG in
01063 //               question, it will be loaded immediately.
01064 //
01065 //               The return value is true if the operation is
01066 //               successful, false otherwise.
01067 ////////////////////////////////////////////////////////////////////
01068 bool GraphicsEngine::
01069 extract_texture_data(Texture *tex, GraphicsStateGuardian *gsg) {
01070   ReMutexHolder holder(_lock);
01071 
01072   string draw_name = gsg->get_threading_model().get_draw_name();
01073   if (draw_name.empty()) {
01074     // A single-threaded environment.  No problem.
01075     return gsg->extract_texture_data(tex);
01076 
01077   } else {
01078     // A multi-threaded environment.  We have to wait until the draw
01079     // thread has finished its current task.
01080     WindowRenderer *wr = get_window_renderer(draw_name, 0);
01081     RenderThread *thread = (RenderThread *)wr;
01082     MutexHolder holder2(thread->_cv_mutex);
01083       
01084     while (thread->_thread_state != TS_wait) {
01085       thread->_cv_done.wait();
01086     }
01087 
01088     // OK, now the draw thread is idle.  That's really good enough for
01089     // our purposes; we don't *actually* need to make the draw thread
01090     // do the work--it's sufficient that it's not doing anything else
01091     // while we access the GSG.
01092     return gsg->extract_texture_data(tex);
01093   }
01094 }
01095  
01096 ////////////////////////////////////////////////////////////////////
01097 //     Function: GraphicsEngine::get_global_ptr
01098 //       Access: Published, Static
01099 //  Description: 
01100 ////////////////////////////////////////////////////////////////////
01101 GraphicsEngine *GraphicsEngine::
01102 get_global_ptr() {
01103   if (_global_ptr == NULL) {
01104     _global_ptr = new GraphicsEngine;
01105     PandaNode::set_scene_root_func(&scene_root_func);
01106   }
01107   return _global_ptr;
01108 }
01109 
01110 ////////////////////////////////////////////////////////////////////
01111 //     Function: GraphicsEngine::texture_uploaded
01112 //       Access: Public
01113 //  Description: This method is called by the GraphicsStateGuardian
01114 //               after a texture has been successfully uploaded to
01115 //               graphics memory.  It is intended as a callback so the
01116 //               texture can release its RAM image, if _keep_ram_image
01117 //               is false.
01118 //
01119 //               Normally, this is not called directly except by the
01120 //               GraphicsStateGuardian.  It will be called in the draw
01121 //               thread.
01122 ////////////////////////////////////////////////////////////////////
01123 void GraphicsEngine::
01124 texture_uploaded(Texture *tex) {
01125   MutexHolder holder(_loaded_textures_lock);
01126   // We defer this until the end of the frame; multiple GSG's might be
01127   // rendering the texture within the same frame, and we don't want to
01128   // dump the texture image until they've all had a chance at it.
01129   _loaded_textures.push_back(LoadedTexture());
01130   LoadedTexture &lt = _loaded_textures.back();
01131   lt._tex = tex;
01132   lt._image_modified = tex->get_image_modified();
01133 //               Usually only called by DisplayRegion::do_cull.
01134 }
01135 
01136 ////////////////////////////////////////////////////////////////////
01137 //     Function: GraphicsEngine::do_cull
01138 //       Access: Public, Static
01139 //  Description: Fires off a cull traversal using the indicated camera.
01140 ////////////////////////////////////////////////////////////////////
01141 void GraphicsEngine::
01142 do_cull(CullHandler *cull_handler, SceneSetup *scene_setup,
01143         GraphicsStateGuardian *gsg, Thread *current_thread) {
01144   DisplayRegion *dr = scene_setup->get_display_region();
01145   PStatTimer timer(dr->get_cull_region_pcollector(), current_thread);
01146 
01147   CullTraverser *trav = dr->get_cull_traverser();
01148   trav->set_cull_handler(cull_handler);
01149   trav->set_scene(scene_setup, gsg, dr->get_incomplete_render());
01150 
01151   trav->set_view_frustum(NULL);
01152   if (view_frustum_cull) {
01153     // If we're to be performing view-frustum culling, determine the
01154     // bounding volume associated with the current viewing frustum.
01155 
01156     // First, we have to get the current viewing frustum, which comes
01157     // from the lens.
01158     PT(BoundingVolume) bv = scene_setup->get_cull_bounds();
01159 
01160     if (bv != (BoundingVolume *)NULL &&
01161         bv->is_of_type(GeometricBoundingVolume::get_class_type())) {
01162       // Transform it into the appropriate coordinate space.
01163       PT(GeometricBoundingVolume) local_frustum;
01164       local_frustum = DCAST(GeometricBoundingVolume, bv->make_copy());
01165 
01166       NodePath scene_parent = scene_setup->get_scene_root().get_parent(current_thread);
01167       CPT(TransformState) cull_center_transform = 
01168         scene_setup->get_cull_center().get_transform(scene_parent, current_thread);
01169       local_frustum->xform(cull_center_transform->get_mat());
01170 
01171       trav->set_view_frustum(local_frustum);
01172     }
01173   }
01174 
01175   trav->traverse(scene_setup->get_scene_root());
01176   trav->end_traverse();
01177 }
01178 
01179 
01180 ////////////////////////////////////////////////////////////////////
01181 //     Function: GraphicsEngine::scene_root_func
01182 //       Access: Private, Static
01183 //  Description: This function is added to PandaNode::scene_root_func
01184 //               to implement PandaNode::is_scene_root().
01185 ////////////////////////////////////////////////////////////////////
01186 bool GraphicsEngine::
01187 scene_root_func(const PandaNode *node) {
01188   return _global_ptr->is_scene_root(node);
01189 }
01190 
01191 ////////////////////////////////////////////////////////////////////
01192 //     Function: GraphicsEngine::is_scene_root
01193 //       Access: Private
01194 //  Description: Returns true if the indicated node is known to be
01195 //               the render root of some active DisplayRegion
01196 //               associated with this GraphicsEngine, false otherwise.
01197 ////////////////////////////////////////////////////////////////////
01198 bool GraphicsEngine::
01199 is_scene_root(const PandaNode *node) {
01200   Thread *current_thread = Thread::get_current_thread();
01201 
01202   Windows::const_iterator wi;
01203   for (wi = _windows.begin(); wi != _windows.end(); ++wi) {
01204     GraphicsOutput *win = (*wi);
01205     if (win->is_active() && win->get_gsg()->is_active()) {
01206       int num_display_regions = win->get_num_active_display_regions();
01207       for (int i = 0; i < num_display_regions; i++) {
01208         DisplayRegion *dr = win->get_active_display_region(i);
01209         if (dr != (DisplayRegion *)NULL) {
01210           NodePath camera = dr->get_camera();
01211           if (camera.is_empty()) {
01212             continue;
01213           }
01214 
01215           Camera *camera_node;
01216           DCAST_INTO_R(camera_node, camera.node(), false);
01217           if (!camera_node->is_active()) {
01218             continue;
01219           }
01220 
01221           NodePath scene_root = camera_node->get_scene();
01222           if (scene_root.is_empty()) {
01223             // If there's no explicit scene specified, use whatever scene the
01224             // camera is parented within.  This is the normal and preferred
01225             // case; the use of an explicit scene is now deprecated.
01226             scene_root = camera.get_top(current_thread);
01227           }
01228 
01229           if (scene_root.node() == node) {
01230             return true;
01231           }
01232         }
01233       }
01234     }
01235   }
01236 
01237   return false;
01238 }
01239 
01240 ////////////////////////////////////////////////////////////////////
01241 //     Function: GraphicsEngine::set_window_sort
01242 //       Access: Private
01243 //  Description: Changes the sort value of a particular window (or
01244 //               buffer) on the GraphicsEngine.  This requires
01245 //               securing the mutex.
01246 //
01247 //               Users shouldn't call this directly; use
01248 //               GraphicsOutput::set_sort() instead.
01249 ////////////////////////////////////////////////////////////////////
01250 void GraphicsEngine::
01251 set_window_sort(GraphicsOutput *window, int sort) {
01252   ReMutexHolder holder(_lock);
01253   window->_sort = sort;
01254   _windows_sorted = false;
01255 }
01256 
01257 ////////////////////////////////////////////////////////////////////
01258 //     Function: GraphicsEngine::cull_and_draw_together
01259 //       Access: Private
01260 //  Description: This is called in the cull+draw thread by individual
01261 //               RenderThread objects during the frame rendering.  It
01262 //               culls the geometry and immediately draws it, without
01263 //               first collecting it into bins.  This is used when the
01264 //               threading model begins with the "-" character.
01265 ////////////////////////////////////////////////////////////////////
01266 void GraphicsEngine::
01267 cull_and_draw_together(const GraphicsEngine::Windows &wlist,
01268                        Thread *current_thread) {
01269   PStatTimer timer(_cull_pcollector, current_thread);
01270 
01271   Windows::const_iterator wi;
01272   for (wi = wlist.begin(); wi != wlist.end(); ++wi) {
01273     GraphicsOutput *win = (*wi);
01274     if (win->is_active() && win->get_gsg()->is_active()) {
01275       if (win->flip_ready()) {
01276         {
01277           PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
01278           win->begin_flip();
01279         }
01280         {
01281           PStatTimer timer(GraphicsEngine::_flip_end_pcollector, current_thread);
01282           win->end_flip();
01283         }
01284       }
01285 
01286       if (win->begin_frame(GraphicsOutput::FM_render, current_thread)) {
01287         win->clear(current_thread);
01288       
01289         int num_display_regions = win->get_num_active_display_regions();
01290         for (int i = 0; i < num_display_regions; i++) {
01291           DisplayRegion *dr = win->get_active_display_region(i);
01292           if (dr != (DisplayRegion *)NULL) {
01293             cull_and_draw_together(win, dr, current_thread);
01294           }
01295         }
01296         win->end_frame(GraphicsOutput::FM_render, current_thread);
01297 
01298         if (_auto_flip) {
01299           if (win->flip_ready()) {
01300             {
01301               PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
01302               win->begin_flip();
01303             }
01304             {
01305               PStatTimer timer(GraphicsEngine::_flip_end_pcollector, current_thread);
01306               win->end_flip();
01307             }
01308           }
01309         }
01310       }
01311     }
01312   }
01313 }
01314 
01315 ////////////////////////////////////////////////////////////////////
01316 //     Function: GraphicsEngine::cull_and_draw_together
01317 //       Access: Private
01318 //  Description: Called only from within the inner loop in
01319 //               cull_and_draw_together(), above.
01320 ////////////////////////////////////////////////////////////////////
01321 void GraphicsEngine::
01322 cull_and_draw_together(GraphicsOutput *win, DisplayRegion *dr,
01323                        Thread *current_thread) {
01324   GraphicsStateGuardian *gsg = win->get_gsg();
01325   nassertv(gsg != (GraphicsStateGuardian *)NULL);
01326 
01327   DisplayRegionPipelineReader *dr_reader = 
01328     new DisplayRegionPipelineReader(dr, current_thread);
01329 
01330   win->change_scenes(dr_reader);
01331   gsg->prepare_display_region(dr_reader);
01332 
01333   if (dr_reader->is_any_clear_active()) {
01334     gsg->clear(dr);
01335   }
01336 
01337   PT(SceneSetup) scene_setup = setup_scene(gsg, dr_reader);
01338   if (scene_setup == (SceneSetup *)NULL) {
01339     // Never mind.
01340 
01341   } else if (dr_reader->get_object()->is_stereo()) {
01342     // Don't draw stereo DisplayRegions directly.
01343 
01344   } else if (!gsg->set_scene(scene_setup)) {
01345     // The scene or lens is inappropriate somehow.
01346     display_cat.error()
01347       << gsg->get_type() << " cannot render scene with specified lens.\n";
01348 
01349   } else {
01350     DrawCullHandler cull_handler(gsg);
01351     if (gsg->begin_scene()) {
01352       delete dr_reader;
01353       dr_reader = NULL;
01354 
01355       CallbackObject *cbobj = dr->get_cull_callback();
01356       if (cbobj != (CallbackObject *)NULL) {
01357         // Issue the cull callback on this DisplayRegion.
01358         DisplayRegionCullCallbackData cbdata(&cull_handler, scene_setup);
01359         cbobj->do_callback(&cbdata);
01360         
01361         // The callback has taken care of the culling.
01362         
01363       } else {
01364         // Perform the cull normally.
01365         dr->do_cull(&cull_handler, scene_setup, gsg, current_thread);
01366       }
01367 
01368       gsg->end_scene();
01369     }
01370   }
01371 
01372   if (dr_reader != (DisplayRegionPipelineReader *)NULL) {
01373     delete dr_reader;
01374   }
01375 }
01376 
01377 ////////////////////////////////////////////////////////////////////
01378 //     Function: GraphicsEngine::cull_to_bins
01379 //       Access: Private
01380 //  Description: This is called in the cull thread by individual
01381 //               RenderThread objects during the frame rendering.  It
01382 //               collects the geometry into bins in preparation for
01383 //               drawing.
01384 ////////////////////////////////////////////////////////////////////
01385 void GraphicsEngine::
01386 cull_to_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
01387   PStatTimer timer(_cull_pcollector, current_thread);
01388 
01389   _singular_warning_last_frame = _singular_warning_this_frame;
01390   _singular_warning_this_frame = false;
01391 
01392   // Keep track of the cameras we have already used in this thread to
01393   // render DisplayRegions.
01394   typedef pmap<NodePath, DisplayRegion *> AlreadyCulled;
01395   AlreadyCulled already_culled;
01396 
01397   Windows::const_iterator wi;
01398   for (wi = wlist.begin(); wi != wlist.end(); ++wi) {
01399     GraphicsOutput *win = (*wi);
01400     if (win->is_active() && win->get_gsg()->is_active()) {
01401       PStatTimer timer(win->get_cull_window_pcollector(), current_thread);
01402       int num_display_regions = win->get_num_active_display_regions();
01403       for (int i = 0; i < num_display_regions; ++i) {
01404         DisplayRegion *dr = win->get_active_display_region(i);
01405         if (dr != (DisplayRegion *)NULL) {
01406           DisplayRegionPipelineReader *dr_reader = 
01407             new DisplayRegionPipelineReader(dr, current_thread);
01408           NodePath camera = dr_reader->get_camera();
01409           AlreadyCulled::iterator aci = already_culled.insert(AlreadyCulled::value_type(camera, (DisplayRegion *)NULL)).first;
01410           if ((*aci).second == NULL) {
01411             // We have not used this camera already in this thread.
01412             // Perform the cull operation.
01413             delete dr_reader;
01414             dr_reader = NULL;
01415             (*aci).second = dr;
01416             cull_to_bins(win, dr, current_thread);
01417             
01418           } else {
01419             // We have already culled a scene using this camera in
01420             // this thread, and now we're being asked to cull another
01421             // scene using the same camera.  (Maybe this represents
01422             // two different DisplayRegions for the left and right
01423             // channels of a stereo image.)  Of course, the cull
01424             // result will be the same, so just use the result from
01425             // the other DisplayRegion.
01426             DisplayRegion *other_dr = (*aci).second;
01427             dr->set_cull_result(other_dr->get_cull_result(current_thread),
01428                                 setup_scene(win->get_gsg(), dr_reader),
01429                                 current_thread);
01430           }
01431         
01432           if (dr_reader != (DisplayRegionPipelineReader *)NULL) {
01433             delete dr_reader;
01434           }
01435         }
01436       }
01437     }
01438   }
01439 }
01440 
01441 ////////////////////////////////////////////////////////////////////
01442 //     Function: GraphicsEngine::cull_to_bins
01443 //       Access: Private
01444 //  Description: Called only within the inner loop of cull_to_bins(),
01445 //               above.
01446 ////////////////////////////////////////////////////////////////////
01447 void GraphicsEngine::
01448 cull_to_bins(GraphicsOutput *win, DisplayRegion *dr, Thread *current_thread) {
01449   GraphicsStateGuardian *gsg = win->get_gsg();
01450   if (gsg == (GraphicsStateGuardian *)NULL) {
01451     return;
01452   }
01453 
01454   PT(CullResult) cull_result;
01455   PT(SceneSetup) scene_setup;
01456   {
01457     PStatTimer timer(_cull_setup_pcollector, current_thread);
01458     DisplayRegionPipelineReader dr_reader(dr, current_thread);
01459     scene_setup = setup_scene(gsg, &dr_reader);
01460     cull_result = dr->get_cull_result(current_thread);
01461 
01462     if (cull_result != (CullResult *)NULL) {
01463       cull_result = cull_result->make_next();
01464 
01465     } else {
01466       // This DisplayRegion has no cull results; draw it.
01467       cull_result = new CullResult(gsg, dr->get_draw_region_pcollector());
01468     }
01469   }
01470 
01471   if (scene_setup != (SceneSetup *)NULL) {
01472     BinCullHandler cull_handler(cull_result);
01473     CallbackObject *cbobj = dr->get_cull_callback();
01474     if (cbobj != (CallbackObject *)NULL) {
01475       // Issue the cull callback on this DisplayRegion.
01476       DisplayRegionCullCallbackData cbdata(&cull_handler, scene_setup);
01477       cbobj->do_callback(&cbdata);
01478 
01479       // The callback has taken care of the culling.
01480 
01481     } else {
01482       // Perform the cull normally.
01483       dr->do_cull(&cull_handler, scene_setup, gsg, current_thread);
01484     }
01485 
01486     PStatTimer timer(_cull_sort_pcollector, current_thread);
01487     cull_result->finish_cull(scene_setup, current_thread);
01488   }
01489   
01490   // Save the results for next frame.
01491   dr->set_cull_result(cull_result, scene_setup, current_thread);
01492 }
01493 
01494 ////////////////////////////////////////////////////////////////////
01495 //     Function: GraphicsEngine::draw_bins
01496 //       Access: Private
01497 //  Description: This is called in the draw thread by individual
01498 //               RenderThread objects during the frame rendering.  It
01499 //               issues the graphics commands to draw the objects that
01500 //               have been collected into bins by a previous call to
01501 //               cull_to_bins().
01502 ////////////////////////////////////////////////////////////////////
01503 void GraphicsEngine::
01504 draw_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
01505   nassertv(wlist.verify_list());
01506 
01507   size_t wlist_size = wlist.size();
01508   for (size_t wi = 0; wi < wlist_size; ++wi) {
01509     GraphicsOutput *win = wlist[wi];
01510     if (win->is_active()) {
01511       if (win->flip_ready()) {
01512         {
01513           PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
01514           win->begin_flip();
01515         }
01516         {
01517           PStatTimer timer(GraphicsEngine::_flip_end_pcollector, current_thread);
01518           win->end_flip();
01519         }
01520       }
01521 
01522       PStatTimer timer(win->get_draw_window_pcollector(), current_thread);
01523       if (win->begin_frame(GraphicsOutput::FM_render, current_thread)) {
01524         win->clear(current_thread);
01525 
01526         if (display_cat.is_spam()) {
01527           display_cat.spam()
01528             << "Drawing window " << win->get_name() << "\n";
01529         }
01530         int num_display_regions = win->get_num_active_display_regions();
01531         for (int i = 0; i < num_display_regions; ++i) {
01532           DisplayRegion *dr = win->get_active_display_region(i);
01533           if (dr != (DisplayRegion *)NULL) {
01534             draw_bins(win, dr, current_thread);
01535           }
01536         }
01537         win->end_frame(GraphicsOutput::FM_render, current_thread);
01538 
01539         if (_auto_flip) {
01540           if (win->flip_ready()) {
01541             {
01542               PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
01543               win->begin_flip();
01544             }
01545             {
01546               PStatTimer timer(GraphicsEngine::_flip_end_pcollector, current_thread);
01547               win->end_flip();
01548             }
01549           }
01550         }
01551       } else {
01552         if (display_cat.is_spam()) {
01553           display_cat.spam()
01554             << "Not drawing window " << win->get_name() << "\n";
01555         }
01556       }
01557     } else {
01558       if (display_cat.is_spam()) {
01559         display_cat.spam()
01560           << "Window " << win->get_name() << " is inactive\n";
01561       }
01562     }
01563   }
01564 }
01565 
01566 ////////////////////////////////////////////////////////////////////
01567 //     Function: GraphicsEngine::draw_bins
01568 //       Access: Private
01569 //  Description: This variant on draw_bins() is only called from
01570 //               draw_bins(), above.  It draws the cull result for a
01571 //               particular DisplayRegion.
01572 ////////////////////////////////////////////////////////////////////
01573 void GraphicsEngine::
01574 draw_bins(GraphicsOutput *win, DisplayRegion *dr, Thread *current_thread) {
01575   GraphicsStateGuardian *gsg = win->get_gsg();
01576   if (gsg == (GraphicsStateGuardian *)NULL) {
01577     return;
01578   }
01579 
01580   PT(CullResult) cull_result = dr->get_cull_result(current_thread);
01581   PT(SceneSetup) scene_setup = dr->get_scene_setup(current_thread);
01582   do_draw(cull_result, scene_setup, win, dr, current_thread);
01583 }
01584 
01585 ////////////////////////////////////////////////////////////////////
01586 //     Function: GraphicsEngine::make_contexts
01587 //       Access: Private
01588 //  Description: Called in the draw thread, this calls make_context()
01589 //               on each window on the list to guarantee its gsg and
01590 //               graphics context both get created.
01591 ////////////////////////////////////////////////////////////////////
01592 void GraphicsEngine::
01593 make_contexts(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
01594   Windows::const_iterator wi;
01595   for (wi = wlist.begin(); wi != wlist.end(); ++wi) {
01596     GraphicsOutput *win = (*wi);
01597     if (win->begin_frame(GraphicsOutput::FM_refresh, current_thread)) {
01598       win->end_frame(GraphicsOutput::FM_refresh, current_thread);
01599     }
01600   }
01601 }
01602 
01603 ////////////////////////////////////////////////////////////////////
01604 //     Function: GraphicsEngine::process_events
01605 //       Access: Private
01606 //  Description: This is called by the RenderThread object to process
01607 //               all the windows events (resize, etc.) for the given
01608 //               list of windows.  This is run in the window thread.
01609 ////////////////////////////////////////////////////////////////////
01610 void GraphicsEngine::
01611 process_events(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
01612   // We're not using a vector iterator here, since it's possible that
01613   // the window list changes in an event, which would invalidate the
01614   // iterator and cause a crash.
01615   for (size_t i = 0; i < wlist.size(); ++i) {
01616     wlist[i]->process_events();
01617   }
01618 }
01619 
01620 ////////////////////////////////////////////////////////////////////
01621 //     Function: GraphicsEngine::flip_windows
01622 //       Access: Private
01623 //  Description: This is called by the RenderThread object to flip the
01624 //               buffers for all of the non-single-buffered windows in
01625 //               the given list.  This is run in the draw thread.
01626 ////////////////////////////////////////////////////////////////////
01627 void GraphicsEngine::
01628 flip_windows(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
01629   size_t num_windows = wlist.size();
01630   size_t warray_size = num_windows * sizeof(GraphicsOutput *);
01631   size_t warray_count = 0;
01632   GraphicsOutput **warray = (GraphicsOutput **)alloca(warray_size);
01633 
01634   size_t i;
01635   for (i = 0; i < num_windows; ++i) {
01636     GraphicsOutput *win = wlist[i];
01637     if (win->flip_ready()) {
01638       nassertv(warray_count < num_windows);
01639       warray[warray_count] = win;
01640       ++warray_count;
01641 
01642       PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
01643       win->begin_flip();
01644     }
01645   }
01646 
01647   for (i = 0; i < warray_count; ++i) {
01648     GraphicsOutput *win = warray[i];
01649     PStatTimer timer(GraphicsEngine::_flip_end_pcollector, current_thread);
01650     win->end_flip();
01651   }
01652 }
01653 
01654 ////////////////////////////////////////////////////////////////////
01655 //     Function: GraphicsEngine::ready_flip_windows
01656 //       Access: Private
01657 //  Description: This is called by the RenderThread object to flip the
01658 //               buffers for all of the non-single-buffered windows in
01659 //               the given list.  This is run in the draw thread.
01660 ////////////////////////////////////////////////////////////////////
01661 void GraphicsEngine::
01662 ready_flip_windows(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
01663   Windows::const_iterator wi;
01664   for (wi = wlist.begin(); wi != wlist.end(); ++wi) {
01665     GraphicsOutput *win = (*wi);
01666     if (win->flip_ready()) {
01667       PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
01668       win->ready_flip();
01669     }
01670   }
01671 }
01672 
01673 
01674 
01675 ////////////////////////////////////////////////////////////////////
01676 //     Function: GraphicsEngine::do_sync_frame
01677 //       Access: Private
01678 //  Description: The implementation of sync_frame().  We assume _lock
01679 //               is already held before this method is called.
01680 ////////////////////////////////////////////////////////////////////
01681 void GraphicsEngine::
01682 do_sync_frame(Thread *current_thread) {
01683   nassertv(_lock.debug_is_locked());
01684 
01685   // Statistics
01686   PStatTimer timer(_sync_pcollector, current_thread);
01687 
01688   nassertv(_flip_state == FS_draw);
01689 
01690   // Wait for all the threads to finish their current frame.  Grabbing
01691   // and releasing the mutex should achieve that.
01692   Threads::const_iterator ti;
01693   for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
01694     RenderThread *thread = (*ti).second;
01695     thread->_cv_mutex.acquire();
01696     thread->_cv_mutex.release();
01697   }
01698 
01699   _flip_state = FS_sync;
01700 }
01701 
01702 
01703 ////////////////////////////////////////////////////////////////////
01704 //     Function: GraphicsEngine::do_ready_flip
01705 //       Access: Private
01706 //  Description: Wait until all draw calls have finished drawing and
01707 //               the frame is ready to flip
01708 ////////////////////////////////////////////////////////////////////
01709 void GraphicsEngine::
01710 do_ready_flip(Thread *current_thread) {
01711   nassertv(_lock.debug_is_locked());
01712 
01713   // Statistics
01714   PStatTimer timer(_sync_pcollector, current_thread);
01715 
01716   nassertv(_flip_state == FS_draw);
01717 
01718   // Wait for all the threads to finish their current frame.  Grabbing
01719   // and releasing the mutex should achieve that.
01720   Threads::const_iterator ti;
01721   for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
01722     RenderThread *thread = (*ti).second;
01723     thread->_cv_mutex.acquire();
01724     thread->_cv_mutex.release();
01725   }
01726   _app.do_ready_flip(this,current_thread);
01727   _flip_state = FS_sync;
01728   
01729 
01730 }
01731 
01732 ////////////////////////////////////////////////////////////////////
01733 //     Function: GraphicsEngine::do_flip_frame
01734 //       Access: Private
01735 //  Description: The implementation of flip_frame().  We assume _lock
01736 //               is already held before this method is called.
01737 ////////////////////////////////////////////////////////////////////
01738 void GraphicsEngine::
01739 do_flip_frame(Thread *current_thread) {
01740   nassertv(_lock.debug_is_locked());
01741 
01742   // Statistics
01743   PStatTimer timer(_flip_pcollector, current_thread);
01744 
01745   nassertv(_flip_state == FS_draw || _flip_state == FS_sync);
01746 
01747   // First, wait for all the threads to finish their current frame, if
01748   // necessary.  Grabbing the mutex (and waiting for TS_wait) should
01749   // achieve that.
01750   {
01751     PStatTimer timer(_wait_pcollector, current_thread);
01752     Threads::const_iterator ti;
01753     for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
01754       RenderThread *thread = (*ti).second;
01755       thread->_cv_mutex.acquire();
01756 
01757       while (thread->_thread_state != TS_wait) {
01758         thread->_cv_done.wait();
01759       }
01760     }
01761   }
01762   
01763   // Now signal all of our threads to flip the windows.
01764   _app.do_flip(this, current_thread);
01765 
01766   {
01767     Threads::const_iterator ti;
01768     for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
01769       RenderThread *thread = (*ti).second;
01770       nassertv(thread->_thread_state == TS_wait);
01771       thread->_thread_state = TS_do_flip;
01772       thread->_cv_start.notify();
01773       thread->_cv_mutex.release();
01774     }
01775   }
01776 
01777   _flip_state = FS_flip;
01778 }
01779 
01780 ////////////////////////////////////////////////////////////////////
01781 //     Function: GraphicsEngine::setup_scene
01782 //       Access: Private
01783 //  Description: Returns a new SceneSetup object appropriate for
01784 //               rendering the scene from the indicated camera, or
01785 //               NULL if the scene should not be rendered for some
01786 //               reason.
01787 ////////////////////////////////////////////////////////////////////
01788 PT(SceneSetup) GraphicsEngine::
01789 setup_scene(GraphicsStateGuardian *gsg, DisplayRegionPipelineReader *dr) {
01790   Thread *current_thread = dr->get_current_thread();
01791   PStatTimer timer(_cull_setup_pcollector, current_thread);
01792 
01793   GraphicsOutput *window = dr->get_window();
01794   // The window pointer shouldn't be NULL, since we presumably got to
01795   // this particular DisplayRegion by walking through a list on a
01796   // window.
01797   nassertr(window != (GraphicsOutput *)NULL, NULL);
01798 
01799   NodePath camera = dr->get_camera();
01800   if (camera.is_empty()) {
01801     // No camera, no draw.
01802     return NULL;
01803   }
01804 
01805   Camera *camera_node;
01806   DCAST_INTO_R(camera_node, camera.node(), NULL);
01807 
01808   if (!camera_node->is_active()) {
01809     // Camera inactive, no draw.
01810     return NULL;
01811   }
01812   camera_node->cleanup_aux_scene_data(current_thread);
01813 
01814   int lens_index = dr->get_lens_index();
01815   Lens *lens = camera_node->get_lens(lens_index);
01816   if (lens == (Lens *)NULL || !camera_node->get_lens_active(lens_index)) {
01817     // No lens, no draw.
01818     return NULL;
01819   }
01820 
01821   NodePath scene_root = camera_node->get_scene();
01822   if (scene_root.is_empty()) {
01823     // If there's no explicit scene specified, use whatever scene the
01824     // camera is parented within.  This is the normal and preferred
01825     // case; the use of an explicit scene is now deprecated.
01826     scene_root = camera.get_top(current_thread);
01827   }
01828 
01829   PT(SceneSetup) scene_setup = new SceneSetup;
01830 
01831   // We will need both the camera transform (the net transform to the
01832   // camera from the scene) and the world transform (the camera
01833   // transform inverse, or the net transform to the scene from the
01834   // camera).  These are actually defined from the parent of the
01835   // scene_root, because the scene_root's own transform is immediately
01836   // applied to these during rendering.  (Normally, the parent of the
01837   // scene_root is the empty NodePath, although it need not be.)
01838   NodePath scene_parent = scene_root.get_parent(current_thread);
01839   CPT(TransformState) camera_transform = camera.get_transform(scene_parent, current_thread);
01840   CPT(TransformState) world_transform = scene_parent.get_transform(camera, current_thread);
01841 
01842   if (camera_transform->is_invalid()) {
01843     // There must be a singular transform over the scene.
01844     if (!_singular_warning_last_frame) {
01845       display_cat.warning()
01846         << "Scene " << scene_root << " has net scale (" 
01847         << scene_root.get_scale(NodePath()) << "); cannot render.\n";
01848       _singular_warning_this_frame = true;
01849     }
01850     return NULL;
01851   }
01852 
01853   if (world_transform->is_invalid()) {
01854     // There must be a singular transform over the camera.
01855     if (!_singular_warning_last_frame) {
01856       display_cat.warning()
01857         << "Camera " << camera << " has net scale (" 
01858         << camera.get_scale(NodePath()) << "); cannot render.\n";
01859     }
01860     _singular_warning_this_frame = true;
01861     return NULL;
01862   }
01863 
01864   CPT(RenderState) initial_state = camera_node->get_initial_state();
01865 
01866   if (window->get_inverted()) {
01867     // If the window is to be inverted, we must set the inverted flag
01868     // on the SceneSetup object, so that the GSG will be able to
01869     // invert the projection matrix at the last minute.
01870     scene_setup->set_inverted(true);
01871 
01872     // This also means we need to globally invert the sense of polygon
01873     // vertex ordering.
01874     initial_state = initial_state->compose(get_invert_polygon_state());
01875   }
01876 
01877   scene_setup->set_display_region(dr->get_object());
01878   scene_setup->set_viewport_size(dr->get_pixel_width(), dr->get_pixel_height());
01879   scene_setup->set_scene_root(scene_root);
01880   scene_setup->set_camera_path(camera);
01881   scene_setup->set_camera_node(camera_node);
01882   scene_setup->set_lens(lens);
01883   scene_setup->set_initial_state(initial_state);
01884   scene_setup->set_camera_transform(camera_transform);
01885   scene_setup->set_world_transform(world_transform);
01886 
01887   return scene_setup;
01888 }
01889 
01890 ////////////////////////////////////////////////////////////////////
01891 //     Function: GraphicsEngine::do_draw
01892 //       Access: Private
01893 //  Description: Draws the previously-culled scene.
01894 ////////////////////////////////////////////////////////////////////
01895 void GraphicsEngine::
01896 do_draw(CullResult *cull_result, SceneSetup *scene_setup,
01897         GraphicsOutput *win, DisplayRegion *dr, Thread *current_thread) {
01898   // Statistics
01899   PStatTimer timer(dr->get_draw_region_pcollector(), current_thread);
01900 
01901   GraphicsStateGuardian *gsg = win->get_gsg();
01902   CallbackObject *cbobj;
01903 
01904   {
01905     DisplayRegionPipelineReader dr_reader(dr, current_thread);
01906     win->change_scenes(&dr_reader);
01907     gsg->prepare_display_region(&dr_reader);
01908     if (dr_reader.is_any_clear_active()) {
01909       gsg->clear(dr_reader.get_object());
01910     }
01911 
01912     cbobj = dr_reader.get_draw_callback();
01913   }
01914 
01915   if (cbobj != (CallbackObject *)NULL) {
01916     // Issue the draw callback on this DisplayRegion.
01917 
01918     // Set the GSG to the initial state.
01919     gsg->clear_before_callback();
01920     gsg->set_state_and_transform(RenderState::make_empty(), TransformState::make_identity());
01921 
01922     DisplayRegionDrawCallbackData cbdata(cull_result, scene_setup);
01923     cbobj->do_callback(&cbdata);
01924 
01925     // We don't trust the state the callback may have left us in.
01926     gsg->clear_state_and_transform();
01927 
01928     // The callback has taken care of the drawing.
01929     return;
01930   }
01931 
01932   if (cull_result == NULL || scene_setup == NULL) {
01933     // Nothing to see here.
01934 
01935   } else if (dr->is_stereo()) {
01936     // We don't actually draw the stereo DisplayRegions.  These are
01937     // just placeholders; we draw the individual left and right eyes
01938     // instead.  (We might still clear the stereo DisplayRegions,
01939     // though, since it's probably faster to clear right and left
01940     // channels in one pass, than to clear them in two separate
01941     // passes.)
01942 
01943   } else if (!gsg->set_scene(scene_setup)) {
01944     // The scene or lens is inappropriate somehow.
01945     display_cat.error()
01946       << gsg->get_type() << " cannot render scene with specified lens.\n";
01947 
01948   } else {
01949     if (gsg->begin_scene()) {
01950       cull_result->draw(current_thread);
01951       gsg->end_scene();
01952     }
01953   }
01954 }
01955 
01956 ////////////////////////////////////////////////////////////////////
01957 //     Function: GraphicsEngine::do_add_window
01958 //       Access: Private
01959 //  Description: An internal function called by make_window() and
01960 //               make_buffer() and similar functions to add the
01961 //               newly-created GraphicsOutput object to the engine's
01962 //               list of windows, and to request that the window be
01963 //               opened.
01964 ////////////////////////////////////////////////////////////////////
01965 void GraphicsEngine::
01966 do_add_window(GraphicsOutput *window,
01967               const GraphicsThreadingModel &threading_model) {
01968   nassertv(window != NULL);
01969   ReMutexHolder holder(_lock);
01970   nassertv(window->get_engine() == this);
01971 
01972   // We have a special counter that is unique per window that allows
01973   // us to assure that recently-added windows end up on the end of the
01974   // list.
01975   window->_internal_sort_index = _window_sort_index;
01976   ++_window_sort_index;
01977 
01978   _windows_sorted = false;
01979   _windows.push_back(window);
01980 
01981   WindowRenderer *cull = 
01982     get_window_renderer(threading_model.get_cull_name(),
01983                         threading_model.get_cull_stage());
01984   WindowRenderer *draw = 
01985     get_window_renderer(threading_model.get_draw_name(),
01986                         threading_model.get_draw_stage());
01987   
01988   if (threading_model.get_cull_sorting()) {
01989     cull->add_window(cull->_cull, window);
01990     draw->add_window(draw->_draw, window);
01991   } else {
01992     cull->add_window(cull->_cdraw, window);
01993   }
01994   
01995   // Ask the pipe which thread it prefers to run its windowing
01996   // commands in (the "window thread").  This is the thread that
01997   // handles the commands to open, resize, etc. the window.  X
01998   // requires this to be done in the app thread (along with all the
01999   // other windows, since X is strictly single-threaded), but Windows
02000   // requires this to be done in draw (because once an OpenGL context
02001   // has been bound in a given thread, it cannot subsequently be bound
02002   // in any other thread, and we have to bind a context in
02003   // open_window()).
02004   
02005   switch (window->get_pipe()->get_preferred_window_thread()) {
02006   case GraphicsPipe::PWT_app:
02007     _app.add_window(_app._window, window);
02008     break;
02009 
02010   case GraphicsPipe::PWT_draw:
02011     draw->add_window(draw->_window, window);
02012     break;
02013   }
02014 
02015   if (display_cat.is_debug()) {
02016     display_cat.debug()
02017       << "Created " << window->get_type() << " " << (void *)window << "\n";
02018   }
02019 
02020   window->request_open();
02021   _needs_open_windows = true;
02022 }
02023 
02024 ////////////////////////////////////////////////////////////////////
02025 //     Function: GraphicsEngine::do_add_gsg
02026 //       Access: Private
02027 //  Description: An internal function called by make_output to add
02028 //               the newly-created gsg object to the engine's
02029 //               list of gsg's.  It also adjusts various config
02030 //               variables based on the gsg's capabilities.
02031 ////////////////////////////////////////////////////////////////////
02032 void GraphicsEngine::
02033 do_add_gsg(GraphicsStateGuardian *gsg, GraphicsPipe *pipe,
02034            const GraphicsThreadingModel &threading_model) {
02035   ReMutexHolder holder(_lock);
02036   nassertv(gsg->get_pipe() == pipe && gsg->get_engine() == this);
02037   gsg->_threading_model = threading_model;
02038   if (!_default_loader.is_null()) {
02039     gsg->set_loader(_default_loader);
02040   }
02041 
02042   auto_adjust_capabilities(gsg);
02043   
02044   WindowRenderer *draw = 
02045     get_window_renderer(threading_model.get_draw_name(),
02046                         threading_model.get_draw_stage());
02047 
02048   draw->add_gsg(gsg);
02049 }
02050 
02051 ////////////////////////////////////////////////////////////////////
02052 //     Function: GraphicsEngine::do_remove_window
02053 //       Access: Private
02054 //  Description: An internal function called by remove_window() and
02055 //               remove_all_windows() to actually remove the indicated
02056 //               window from all relevant structures, except the
02057 //               _windows list itself.
02058 ////////////////////////////////////////////////////////////////////
02059 void GraphicsEngine::
02060 do_remove_window(GraphicsOutput *window, Thread *current_thread) {
02061   nassertv(window != NULL);
02062   PT(GraphicsPipe) pipe = window->get_pipe();
02063   window->clear_pipe();
02064 
02065   if (!_windows_sorted) {
02066     do_resort_windows();
02067   }
02068 
02069   // Now remove the window from all threads that know about it.
02070   _app.remove_window(window);
02071   Threads::const_iterator ti;
02072   for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
02073     RenderThread *thread = (*ti).second;
02074     thread->remove_window(window);
02075   }
02076 
02077   // If the window happened to be controlled by the app thread, we
02078   // might as well close it now rather than waiting for next frame.
02079   _app.do_pending(this, current_thread);
02080 
02081   if (display_cat.is_debug()) {
02082     display_cat.debug()
02083       << "Removed " << window->get_type() << " " << (void *)window << "\n";
02084   }
02085 }
02086 
02087 ////////////////////////////////////////////////////////////////////
02088 //     Function: GraphicsEngine::do_resort_windows
02089 //       Access: Private
02090 //  Description: Resorts all of the Windows lists.  This may need to
02091 //               be done if one or more of the windows' sort
02092 //               properties has changed.
02093 ////////////////////////////////////////////////////////////////////
02094 void GraphicsEngine::
02095 do_resort_windows() {
02096   _windows_sorted = true;
02097 
02098   _app.resort_windows();
02099   Threads::const_iterator ti;
02100   for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
02101     RenderThread *thread = (*ti).second;
02102     thread->resort_windows();
02103   }
02104 
02105   _windows.sort();
02106 }
02107 
02108 ////////////////////////////////////////////////////////////////////
02109 //     Function: GraphicsEngine::auto_adjust_capabilities
02110 //       Access: Private
02111 //  Description: Video card capability flags are stored on a
02112 //               per-gsg basis.  However, there are a few cases
02113 //               where panda needs to know not the capabilities
02114 //               of an individual GSG, but rather, the
02115 //               collective capabilities of all the GSGs.
02116 //
02117 //               Non-power-of-two (NPOT) texture support is the
02118 //               classic example.  Panda makes a single global
02119 //               decision to either create NPOT textures, or not.
02120 //               Therefore, it doesn't need to know whether one GSG
02121 //               supports NPOT textures.  It needs to know whether ALL
02122 //               the GSGs support NPOT textures.
02123 //
02124 //               The purpose of this routine is to maintain global
02125 //               capability flags that summarize the collective
02126 //               capabilities of the computer as a whole.
02127 //
02128 //               These global capability flags are initialized from
02129 //               config variables.  Then, they can be auto-reconfigured
02130 //               using built-in heuristic mechanisms if the user so
02131 //               desires.  Whether auto-reconfiguration is enabled or
02132 //               not, the configured values are checked against
02133 //               the actual capabilities of the machine and error
02134 //               messages will be printed if there is a mismatch.
02135 //
02136 ////////////////////////////////////////////////////////////////////
02137 void GraphicsEngine::
02138 auto_adjust_capabilities(GraphicsStateGuardian *gsg) {
02139 
02140   // The rule we use when auto-reconfiguring is as follows.  The
02141   // global capabilities must initially be set to conservative
02142   // values.  When the first GSG comes into existence, its
02143   // capabilities will be checked, and the global capabilities
02144   // may be elevated to more aggressive values.
02145   //
02146   // At first glance, this might seem backward, and it might seem
02147   // better to do it the other way: start with all global capabilities
02148   // aggressively set, and then disable capabilities when you discover
02149   // a gsg that doesn't support them.
02150   //
02151   // However, that approach doesn't work, because once a global
02152   // capability is enabled, there is no going back.  If
02153   // textures_power_2 has ever been set to 'none', there may be NPOT
02154   // textures already floating about the system.  Ie, it's too late:
02155   // you can't turn these global capability flags off, once they've
02156   // been turned on.
02157   //
02158   // That's why we have to start with conservative settings, and then
02159   // elevate those settings to more aggressive values later when
02160   // we're fairly sure it's OK to do so.
02161   //
02162   // For each global capability, we must:
02163   //   1. Make sure the initial setting is conservative.
02164   //   2. Possibly elevate to a more aggressive value.
02165   //   3. Check that we haven't over-elevated.
02166   //
02167 
02168   if (textures_auto_power_2 && (textures_power_2 == ATS_none)) {
02169     display_cat.error()
02170       << "Invalid panda config file: if you set the config-variable\n"
02171       << "textures_auto_power_2 to true, you must set the config-variable"
02172       << "textures_power_2 to 'up' or 'down'.\n";
02173     textures_power_2 = ATS_down; // Not a fix.  Just suppresses further error messages.
02174   }
02175   
02176   if (textures_auto_power_2 && !Texture::has_textures_power_2()) {
02177     if (gsg->get_supports_tex_non_pow2()) {
02178       Texture::set_textures_power_2(ATS_none);
02179     } else {
02180       Texture::set_textures_power_2(textures_power_2);
02181     }
02182   }
02183   
02184   if ((Texture::get_textures_power_2() == ATS_none) && 
02185       (!gsg->get_supports_tex_non_pow2())) {
02186     
02187     // Overaggressive configuration detected
02188     
02189     display_cat.error() 
02190       << "The 'textures_power_2' configuration is set to 'none', meaning \n"
02191       << "that non-power-of-two texture support is required, but the video \n"
02192       << "driver I'm trying to use does not support non-power-of-two textures.\n";
02193 
02194     if (textures_power_2 != ATS_none) {
02195       display_cat.error()
02196         << "The 'none' did not come from the config file.  In other words,\n"
02197         << "the variable 'textures_power_2' was altered procedurally.\n";
02198     
02199       if (textures_auto_power_2) {
02200         display_cat.error()
02201           << "It is possible that it was set by panda's automatic mechanisms,\n"
02202           << "which are currently enabled, because 'textures_auto_power_2' is\n"
02203           << "true.  Panda's automatic mechanisms assume that if one\n"
02204           << "window supports non-power-of-two textures, then they all will.\n"
02205           << "This assumption works for most games, but not all.\n"
02206           << "In particular, it can fail if the game creates multiple windows\n"
02207           << "on multiple displays with different video cards.\n";
02208       }
02209     }
02210   }
02211   
02212   if (shader_auto_utilization && (shader_utilization != SUT_none)) {
02213     display_cat.error()
02214       << "Invalid panda config file: if you set the config-variable\n"
02215       << "shader_auto_utilization to true, you must set the config-variable"
02216       << "shader_utilization to 'none'.\n";
02217     shader_utilization = SUT_none; // Not a fix.  Just suppresses further error messages.
02218   }
02219   
02220   if (shader_auto_utilization && !Shader::have_shader_utilization()) {
02221     if (gsg->get_supports_basic_shaders()) {
02222       Shader::set_shader_utilization(SUT_basic);
02223     } else {
02224       Shader::set_shader_utilization(SUT_none);
02225     }
02226   }
02227   
02228   if ((Shader::get_shader_utilization() != SUT_none) && 
02229       (!gsg->get_supports_basic_shaders())) {
02230     
02231     // Overaggressive configuration detected
02232     
02233     display_cat.error() 
02234       << "The 'shader_utilization' config variable is set, meaning\n"
02235       << "that panda may try to generate shaders.  However, the video \n"
02236       << "driver I'm trying to use does not support shaders.\n";
02237 
02238     if (shader_utilization == SUT_none) {
02239       display_cat.error()
02240         << "The 'shader_utilization' setting did not come from the config\n"
02241         << "file.  In other words, it was altered procedurally.\n";
02242     
02243       if (shader_auto_utilization) {
02244         display_cat.error()
02245           << "It is possible that it was set by panda's automatic mechanisms,\n"
02246           << "which are currently enabled, because 'shader_auto_utilization' is\n"
02247           << "true.  Panda's automatic mechanisms assume that if one\n"
02248           << "window supports shaders, then they all will.\n"
02249           << "This assumption works for most games, but not all.\n"
02250           << "In particular, it can fail if the game creates multiple windows\n"
02251           << "on multiple displays with different video cards.\n";
02252       }
02253     }
02254   }
02255 }
02256 
02257 ////////////////////////////////////////////////////////////////////
02258 //     Function: GraphicsEngine::terminate_threads
02259 //       Access: Private
02260 //  Description: Signals our child threads to terminate and waits for
02261 //               them to clean up.
02262 ////////////////////////////////////////////////////////////////////
02263 void GraphicsEngine::
02264 terminate_threads(Thread *current_thread) {
02265   ReMutexHolder holder(_lock, current_thread);
02266 
02267   // We spend almost our entire time in this method just waiting for
02268   // threads.  Time it appropriately.
02269   PStatTimer timer(_wait_pcollector, current_thread);
02270   
02271   // First, wait for all the threads to finish their current frame.
02272   // Grabbing the mutex should achieve that.
02273   Threads::const_iterator ti;
02274   for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
02275     RenderThread *thread = (*ti).second;
02276     thread->_cv_mutex.acquire();
02277   }
02278   
02279   // Now tell them to close their windows and terminate.
02280   for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
02281     RenderThread *thread = (*ti).second;
02282     thread->_thread_state = TS_terminate;
02283     thread->_cv_start.notify();
02284     thread->_cv_mutex.release();
02285   }
02286 
02287   // Finally, wait for them all to finish cleaning up.
02288   for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
02289     RenderThread *thread = (*ti).second;
02290     thread->join();
02291   }
02292   
02293   _threads.clear();
02294 }
02295 
02296 
02297 #ifdef DO_PSTATS
02298 ////////////////////////////////////////////////////////////////////
02299 //     Function: GraphicsEngine::pstats_count_cycler_type
02300 //       Access: Private, Static
02301 //  Description: A callback function for
02302 //               Pipeline::iterate_all_cycler_types() to report the
02303 //               cycler types to PStats.
02304 ////////////////////////////////////////////////////////////////////
02305 void GraphicsEngine::
02306 pstats_count_cycler_type(TypeHandle type, int count, void *data) {
02307   GraphicsEngine *self = (GraphicsEngine *)data;
02308   CyclerTypeCounters::iterator ci = self->_all_cycler_types.find(type);
02309   if (ci == self->_all_cycler_types.end()) {
02310     PStatCollector collector(_cyclers_pcollector, type.get_name());
02311     ci = self->_all_cycler_types.insert(CyclerTypeCounters::value_type(type, collector)).first;
02312   }
02313   (*ci).second.set_level(count);
02314 }
02315 #endif // DO_PSTATS
02316 
02317 #ifdef DO_PSTATS
02318 ////////////////////////////////////////////////////////////////////
02319 //     Function: GraphicsEngine::pstats_count_dirty_cycler_type
02320 //       Access: Private, Static
02321 //  Description: A callback function for
02322 //               Pipeline::iterate_dirty_cycler_types() to report the
02323 //               cycler types to PStats.
02324 ////////////////////////////////////////////////////////////////////
02325 void GraphicsEngine::
02326 pstats_count_dirty_cycler_type(TypeHandle type, int count, void *data) {
02327   GraphicsEngine *self = (GraphicsEngine *)data;
02328   CyclerTypeCounters::iterator ci = self->_dirty_cycler_types.find(type);
02329   if (ci == self->_dirty_cycler_types.end()) {
02330     PStatCollector collector(_dirty_cyclers_pcollector, type.get_name());
02331     ci = self->_dirty_cycler_types.insert(CyclerTypeCounters::value_type(type, collector)).first;
02332   }
02333   (*ci).second.set_level(count);
02334 }
02335 #endif // DO_PSTATS
02336 
02337 ////////////////////////////////////////////////////////////////////
02338 //     Function: GraphicsEngine::get_invert_polygon_state
02339 //       Access: Protected, Static
02340 //  Description: Returns a RenderState for inverting the sense of
02341 //               polygon vertex ordering: if the scene graph specifies
02342 //               a clockwise ordering, this changes it to
02343 //               counterclockwise, and vice-versa.
02344 ////////////////////////////////////////////////////////////////////
02345 const RenderState *GraphicsEngine::
02346 get_invert_polygon_state() {
02347   // Once someone asks for this pointer, we hold its reference count
02348   // and never free it.
02349   static CPT(RenderState) state = (const RenderState *)NULL;
02350   if (state == (const RenderState *)NULL) {
02351     state = RenderState::make(CullFaceAttrib::make_reverse());
02352   }
02353 
02354   return state;
02355 }
02356 
02357 ////////////////////////////////////////////////////////////////////
02358 //     Function: GraphicsEngine::get_window_renderer
02359 //       Access: Private
02360 //  Description: Returns the WindowRenderer with the given name.
02361 //               Creates a new RenderThread if there is no such thread
02362 //               already.  The pipeline_stage number specifies the
02363 //               pipeline stage that will be assigned to the thread
02364 //               (unless was previously given a higher stage).
02365 //
02366 //               You must already be holding the lock before calling
02367 //               this method.
02368 ////////////////////////////////////////////////////////////////////
02369 GraphicsEngine::WindowRenderer *GraphicsEngine::
02370 get_window_renderer(const string &name, int pipeline_stage) {
02371   nassertr(_lock.debug_is_locked(), NULL);
02372 
02373   if (name.empty()) {
02374     return &_app;
02375   }
02376 
02377   Threads::iterator ti = _threads.find(name);
02378   if (ti != _threads.end()) {
02379     return (*ti).second.p();
02380   }
02381 
02382   PT(RenderThread) thread = new RenderThread(name, this);
02383   thread->set_min_pipeline_stage(pipeline_stage);
02384   _pipeline->set_min_stages(pipeline_stage + 1);
02385 
02386   bool started = thread->start(TP_normal, true);
02387   nassertr(started, thread.p());
02388   _threads[name] = thread;
02389 
02390   nassertr(thread->get_pipeline_stage() < _pipeline->get_num_stages(), thread.p());
02391 
02392   return thread.p();
02393 }
02394 
02395 ////////////////////////////////////////////////////////////////////
02396 //     Function: GraphicsEngine::WindowRenderer::Constructor
02397 //       Access: Public
02398 //  Description: 
02399 ////////////////////////////////////////////////////////////////////
02400 GraphicsEngine::WindowRenderer::
02401 WindowRenderer(const string &name) :
02402   _wl_lock(string("GraphicsEngine::WindowRenderer::_wl_lock ") + name)
02403 {
02404 }
02405 
02406 ////////////////////////////////////////////////////////////////////
02407 //     Function: GraphicsEngine::WindowRenderer::add_gsg
02408 //       Access: Public
02409 //  Description: Adds a new GSG to the _gsg list, if it is not already
02410 //               there.
02411 ////////////////////////////////////////////////////////////////////
02412 void GraphicsEngine::WindowRenderer::
02413 add_gsg(GraphicsStateGuardian *gsg) {
02414   LightReMutexHolder holder(_wl_lock);
02415   _gsgs.insert(gsg);
02416 }
02417 
02418 ////////////////////////////////////////////////////////////////////
02419 //     Function: GraphicsEngine::WindowRenderer::add_window
02420 //       Access: Public
02421 //  Description: Adds a new window to the indicated list, which should
02422 //               be a member of the WindowRenderer.
02423 ////////////////////////////////////////////////////////////////////
02424 void GraphicsEngine::WindowRenderer::
02425 add_window(Windows &wlist, GraphicsOutput *window) {
02426   LightReMutexHolder holder(_wl_lock);
02427   wlist.insert(window);
02428 }
02429 
02430 ////////////////////////////////////////////////////////////////////
02431 //     Function: GraphicsEngine::WindowRenderer::remove_window
02432 //       Access: Public
02433 //  Description: Immediately removes the indicated window from all
02434 //               lists.  If the window is currently open and is
02435 //               already on the _window list, moves it to the _pending_close
02436 //               list for later closure.
02437 ////////////////////////////////////////////////////////////////////
02438 void GraphicsEngine::WindowRenderer::
02439 remove_window(GraphicsOutput *window) {
02440   nassertv(window != NULL);
02441   LightReMutexHolder holder(_wl_lock);
02442   PT(GraphicsOutput) ptwin = window;
02443 
02444   _cull.erase(ptwin);
02445   _cdraw.erase(ptwin);
02446   _draw.erase(ptwin);
02447 
02448   Windows::iterator wi;
02449 
02450   wi = _window.find(ptwin);
02451   if (wi != _window.end()) {
02452     // The window is on our _window list, meaning its open/close
02453     // operations (among other window ops) are serviced by this
02454     // thread.
02455 
02456     // Make sure the window isn't about to request itself open.
02457     ptwin->request_close();
02458 
02459     // If the window is already open, move it to the _pending_close list so
02460     // it can be closed later.  We can't close it immediately, because
02461     // we might not have been called from the subthread.
02462     if (ptwin->is_valid()) {
02463       _pending_close.push_back(ptwin);
02464     }
02465 
02466     _window.erase(wi);
02467   }
02468 }
02469 
02470 ////////////////////////////////////////////////////////////////////
02471 //     Function: GraphicsEngine::WindowRenderer::resort_windows
02472 //       Access: Public
02473 //  Description: Resorts all the lists of windows, assuming they may
02474 //               have become unsorted.
02475 ////////////////////////////////////////////////////////////////////
02476 void GraphicsEngine::WindowRenderer::
02477 resort_windows() {
02478   LightReMutexHolder holder(_wl_lock);
02479 
02480   _cull.sort();
02481   _cdraw.sort();
02482   _draw.sort();
02483   _window.sort();
02484 
02485   if (display_cat.is_debug()) {
02486     display_cat.debug()
02487       << "Windows resorted:";
02488     Windows::const_iterator wi;
02489     for (wi = _window.begin(); wi != _window.end(); ++wi) {
02490       GraphicsOutput *win = (*wi);
02491       display_cat.debug(false)
02492         << " " << win->get_name() << "(" << win->get_sort() << ")";
02493     }
02494     display_cat.debug(false)
02495       << "\n";
02496 
02497     for (wi = _draw.begin(); wi != _draw.end(); ++wi) {
02498       GraphicsOutput *win = (*wi);
02499       display_cat.debug(false)
02500         << " " << win->get_name() << "(" << win->get_sort() << ")";
02501     }
02502     display_cat.debug(false)
02503       << "\n";
02504   }
02505 }
02506 
02507 ////////////////////////////////////////////////////////////////////
02508 //     Function: GraphicsEngine::WindowRenderer::do_frame
02509 //       Access: Public
02510 //  Description: Executes one stage of the pipeline for the current
02511 //               thread: calls cull on all windows that are on the
02512 //               cull list for this thread, draw on all the windows on
02513 //               the draw list, etc.
02514 ////////////////////////////////////////////////////////////////////
02515 void GraphicsEngine::WindowRenderer::
02516 do_frame(GraphicsEngine *engine, Thread *current_thread) {
02517   PStatTimer timer(engine->_do_frame_pcollector, current_thread);
02518   LightReMutexHolder holder(_wl_lock);
02519 
02520   engine->cull_to_bins(_cull, current_thread);
02521   engine->cull_and_draw_together(_cdraw, current_thread);
02522   engine->draw_bins(_draw, current_thread);
02523   engine->process_events(_window, current_thread);
02524 
02525   // If any GSG's on the list have no more outstanding pointers, clean
02526   // them up.  (We are in the draw thread for all of these GSG's.)
02527   if (any_done_gsgs()) {
02528     GSGs new_gsgs;
02529     GSGs::iterator gi;
02530     for (gi = _gsgs.begin(); gi != _gsgs.end(); ++gi) {
02531       GraphicsStateGuardian *gsg = (*gi);
02532       if (gsg->get_ref_count() == 1) {
02533         // This one has no outstanding pointers; clean it up.
02534         GraphicsPipe *pipe = gsg->get_pipe();
02535         engine->close_gsg(pipe, gsg);
02536       } else { 
02537         // This one is ok; preserve it.
02538         new_gsgs.insert(gsg);
02539       }
02540     }
02541 
02542     _gsgs.swap(new_gsgs);
02543   }
02544 }
02545 
02546 ////////////////////////////////////////////////////////////////////
02547 //     Function: GraphicsEngine::WindowRenderer::do_windows
02548 //       Access: Public
02549 //  Description: Attempts to fully open or close any windows or
02550 //               buffers associated with this thread, but does not
02551 //               otherwise perform any rendering.  (Normally, this
02552 //               step is handled during do_frame(); call this method
02553 //               only if you want these things to open immediately.)
02554 ////////////////////////////////////////////////////////////////////
02555 void GraphicsEngine::WindowRenderer::
02556 do_windows(GraphicsEngine *engine, Thread *current_thread) {
02557   LightReMutexHolder holder(_wl_lock);
02558 
02559   engine->process_events(_window, current_thread);
02560 
02561   engine->make_contexts(_cdraw, current_thread);
02562   engine->make_contexts(_draw, current_thread);
02563 }
02564 
02565 ////////////////////////////////////////////////////////////////////
02566 //     Function: GraphicsEngine::WindowRenderer::do_flip
02567 //       Access: Public
02568 //  Description: Flips the windows as appropriate for the current
02569 //               thread.
02570 ////////////////////////////////////////////////////////////////////
02571 void GraphicsEngine::WindowRenderer::
02572 do_flip(GraphicsEngine *engine, Thread *current_thread) {
02573   LightReMutexHolder holder(_wl_lock);
02574   engine->flip_windows(_cdraw, current_thread);
02575   engine->flip_windows(_draw, current_thread);
02576 }
02577 
02578 ////////////////////////////////////////////////////////////////////
02579 //     Function: GraphicsEngine::WindowRenderer::do_ready_flip
02580 //       Access: Public
02581 //  Description: Prepares windows for flipping by waiting until all draw
02582 //               calls are finished
02583 ////////////////////////////////////////////////////////////////////
02584 void GraphicsEngine::WindowRenderer::
02585 do_ready_flip(GraphicsEngine *engine, Thread *current_thread) {
02586   LightReMutexHolder holder(_wl_lock);
02587   engine->ready_flip_windows(_cdraw, current_thread);
02588   engine->ready_flip_windows(_draw, current_thread);
02589 }
02590 
02591 
02592 ////////////////////////////////////////////////////////////////////
02593 //     Function: GraphicsEngine::WindowRenderer::do_close
02594 //       Access: Public
02595 //  Description: Closes all the windows on the _window list.
02596 ////////////////////////////////////////////////////////////////////
02597 void GraphicsEngine::WindowRenderer::
02598 do_close(GraphicsEngine *engine, Thread *current_thread) {
02599   LightReMutexHolder holder(_wl_lock);
02600   Windows::iterator wi;
02601   for (wi = _window.begin(); wi != _window.end(); ++wi) {
02602     GraphicsOutput *win = (*wi);
02603     win->set_close_now();
02604   }
02605 
02606   // Also close all of the GSG's.
02607   GSGs new_gsgs;
02608   GSGs::iterator gi;
02609   for (gi = _gsgs.begin(); gi != _gsgs.end(); ++gi) {
02610     GraphicsStateGuardian *gsg = (*gi);
02611     if (gsg->get_ref_count() == 1) {
02612       // This one has no outstanding pointers; clean it up.
02613       GraphicsPipe *pipe = gsg->get_pipe();
02614       engine->close_gsg(pipe, gsg);
02615     } else { 
02616       // This one is ok; preserve it.
02617       new_gsgs.insert(gsg);
02618     }
02619   }
02620   
02621   _gsgs.swap(new_gsgs);
02622 }
02623 
02624 ////////////////////////////////////////////////////////////////////
02625 //     Function: GraphicsEngine::WindowRenderer::do_pending
02626 //       Access: Public
02627 //  Description: Actually closes any windows that were recently
02628 //               removed from the WindowRenderer.
02629 ////////////////////////////////////////////////////////////////////
02630 void GraphicsEngine::WindowRenderer::
02631 do_pending(GraphicsEngine *engine, Thread *current_thread) {
02632   LightReMutexHolder holder(_wl_lock);
02633 
02634   if (!_pending_close.empty()) {
02635     if (display_cat.is_debug()) {
02636       display_cat.debug()
02637         << "_pending_close.size() = " << _pending_close.size() << "\n";
02638     }
02639 
02640     // Close any windows that were pending closure.  Carefully protect
02641     // against recursive entry to this function by swapping the vector
02642     // to a local copy first.
02643     Windows::iterator wi;
02644     Windows pending_close;
02645     _pending_close.swap(pending_close);
02646     for (wi = pending_close.begin(); wi != pending_close.end(); ++wi) {
02647       GraphicsOutput *win = (*wi);
02648       win->set_close_now();
02649     }
02650   }
02651 }
02652 
02653 ////////////////////////////////////////////////////////////////////
02654 //     Function: GraphicsEngine::WindowRenderer::any_done_gsgs
02655 //       Access: Public
02656 //  Description: Returns true if any of the GSG's on this thread's
02657 //               draw list are done (they have no outstanding pointers
02658 //               other than this one), or false if all of them are
02659 //               still good.
02660 ////////////////////////////////////////////////////////////////////
02661 bool GraphicsEngine::WindowRenderer::
02662 any_done_gsgs() const {
02663   GSGs::const_iterator gi;
02664   for (gi = _gsgs.begin(); gi != _gsgs.end(); ++gi) {
02665     if ((*gi)->get_ref_count() == 1) {
02666       return true;
02667     }
02668   }
02669 
02670   return false;
02671 }
02672 
02673 ////////////////////////////////////////////////////////////////////
02674 //     Function: GraphicsEngine::RenderThread::Constructor
02675 //       Access: Public
02676 //  Description: 
02677 ////////////////////////////////////////////////////////////////////
02678 GraphicsEngine::RenderThread::
02679 RenderThread(const string &name, GraphicsEngine *engine) : 
02680   Thread(name, "Main"),
02681   WindowRenderer(name),
02682   _engine(engine),
02683   _cv_mutex(string("GraphicsEngine::RenderThread ") + name),
02684   _cv_start(_cv_mutex),
02685   _cv_done(_cv_mutex)
02686 {
02687   _thread_state = TS_wait;
02688 }
02689 
02690 ////////////////////////////////////////////////////////////////////
02691 //     Function: GraphicsEngine::RenderThread::thread_main
02692 //       Access: Public, Virtual
02693 //  Description: The main loop for a particular render thread.  The
02694 //               thread will process whatever cull or draw windows it
02695 //               has assigned to it.
02696 ////////////////////////////////////////////////////////////////////
02697 void GraphicsEngine::RenderThread::
02698 thread_main() {
02699   Thread *current_thread = Thread::get_current_thread();
02700 
02701   MutexHolder holder(_cv_mutex);
02702   while (true) {
02703     nassertv(_cv_mutex.debug_is_locked());
02704 
02705     switch (_thread_state) {
02706     case TS_wait:
02707       break;
02708 
02709     case TS_do_frame:
02710       do_pending(_engine, current_thread);
02711       do_frame(_engine, current_thread);
02712       break;
02713 
02714     case TS_do_flip:
02715       do_flip(_engine, current_thread);
02716       break;
02717 
02718     case TS_do_release:
02719       do_pending(_engine, current_thread);
02720       break;
02721 
02722     case TS_do_windows:
02723       do_windows(_engine, current_thread);
02724       do_pending(_engine, current_thread);
02725       break;
02726 
02727     case TS_terminate:
02728       do_pending(_engine, current_thread);
02729       do_close(_engine, current_thread);
02730       _thread_state = TS_done;
02731       _cv_done.notify();
02732       return;
02733 
02734     case TS_done:
02735       // Shouldn't be possible to get here.
02736       nassertv(false);
02737       return;
02738     }
02739 
02740     _thread_state = TS_wait;
02741     _cv_done.notify();
02742 
02743     {
02744       PStatTimer timer(_wait_pcollector, current_thread);
02745       _cv_start.wait();
02746     }
02747   }
02748 }
 All Classes Functions Variables Enumerations