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