Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/display/graphicsEngine.cxx

Go to the documentation of this file.
00001 // Filename: graphicsEngine.cxx
00002 // Created by:  drose (24Feb02)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "graphicsEngine.h"
00020 #include "graphicsPipe.h"
00021 #include "config_display.h"
00022 #include "pipeline.h"
00023 #include "drawCullHandler.h"
00024 #include "binCullHandler.h"
00025 #include "cullResult.h"
00026 #include "cullTraverser.h"
00027 #include "clockObject.h"
00028 #include "pStatTimer.h"
00029 #include "pStatClient.h"
00030 #include "mutexHolder.h"
00031 #include "string_utils.h"
00032 
00033 #ifndef CPPPARSER
00034 PStatCollector GraphicsEngine::_cull_pcollector("Cull");
00035 PStatCollector GraphicsEngine::_draw_pcollector("Draw");
00036 #endif  // CPPPARSER
00037 
00038 ////////////////////////////////////////////////////////////////////
00039 //     Function: GraphicsEngine::Constructor
00040 //       Access: Published
00041 //  Description: Creates a new GraphicsEngine object.  The Pipeline is
00042 //               normally left to default to NULL, which indicates the
00043 //               global render pipeline, but it may be any Pipeline
00044 //               you choose.
00045 ////////////////////////////////////////////////////////////////////
00046 GraphicsEngine::
00047 GraphicsEngine(Pipeline *pipeline) :
00048   _pipeline(pipeline)
00049 {
00050   if (_pipeline == (Pipeline *)NULL) {
00051     _pipeline = Pipeline::get_render_pipeline();
00052   }
00053 
00054   // Default frame buffer properties.
00055   _frame_buffer_properties.set_depth_bits(1);
00056   _frame_buffer_properties.set_color_bits(1);
00057   _frame_buffer_properties.set_frame_buffer_mode
00058     (FrameBufferProperties::FM_rgba | 
00059      FrameBufferProperties::FM_double_buffer | 
00060      FrameBufferProperties::FM_depth);
00061 
00062   set_threading_model(GraphicsThreadingModel(threading_model));
00063   if (!_threading_model.is_default()) {
00064     display_cat.info()
00065       << "Using threading model " << _threading_model << "\n";
00066   }
00067   _auto_flip = auto_flip;
00068   _flip_state = FS_flip;
00069 }
00070 
00071 ////////////////////////////////////////////////////////////////////
00072 //     Function: GraphicsEngine::Destructor
00073 //       Access: Published
00074 //  Description: Gracefully cleans up the graphics engine and its
00075 //               related threads and windows.
00076 ////////////////////////////////////////////////////////////////////
00077 GraphicsEngine::
00078 ~GraphicsEngine() {
00079   remove_all_windows();
00080 }
00081 
00082 ////////////////////////////////////////////////////////////////////
00083 //     Function: GraphicsEngine::set_frame_buffer_properties
00084 //       Access: Published
00085 //  Description: Specifies the default frame buffer properties for
00086 //               future gsg's created using the one-parameter
00087 //               make_gsg() method.
00088 ////////////////////////////////////////////////////////////////////
00089 void GraphicsEngine::
00090 set_frame_buffer_properties(const FrameBufferProperties &properties) {
00091   MutexHolder holder(_lock);
00092   _frame_buffer_properties = properties;
00093 }
00094 
00095 ////////////////////////////////////////////////////////////////////
00096 //     Function: GraphicsEngine::get_frame_buffer_properties
00097 //       Access: Published
00098 //  Description: Returns the current default threading model.  See
00099 //               set_frame_buffer_properties().
00100 ////////////////////////////////////////////////////////////////////
00101 FrameBufferProperties GraphicsEngine::
00102 get_frame_buffer_properties() const {
00103   FrameBufferProperties result;
00104   {
00105     MutexHolder holder(_lock);
00106     result = _frame_buffer_properties;
00107   }
00108   return result;
00109 }
00110 
00111 ////////////////////////////////////////////////////////////////////
00112 //     Function: GraphicsEngine::set_threading_model
00113 //       Access: Published
00114 //  Description: Specifies how windows created using future calls to
00115 //               the one-parameter version of make_gsg() will be
00116 //               threaded.
00117 ////////////////////////////////////////////////////////////////////
00118 void GraphicsEngine::
00119 set_threading_model(const GraphicsThreadingModel &threading_model) {
00120   if (!threading_model.is_single_threaded() && 
00121       !Thread::is_threading_supported()) {
00122     display_cat.warning()
00123       << "Threading model " << threading_model
00124       << " requested but threading not supported.\n";
00125     return;
00126   }
00127   MutexHolder holder(_lock);
00128   _threading_model = threading_model;
00129 }
00130 
00131 ////////////////////////////////////////////////////////////////////
00132 //     Function: GraphicsEngine::get_threading_model
00133 //       Access: Published
00134 //  Description: Returns the current default threading model.  See
00135 //               set_threading_model().
00136 ////////////////////////////////////////////////////////////////////
00137 GraphicsThreadingModel GraphicsEngine::
00138 get_threading_model() const {
00139   GraphicsThreadingModel result;
00140   {
00141     MutexHolder holder(_lock);
00142     result = _threading_model;
00143   }
00144   return result;
00145 }
00146 
00147 ////////////////////////////////////////////////////////////////////
00148 //     Function: GraphicsEngine::make_gsg
00149 //       Access: Published
00150 //  Description: Creates a new gsg using the indicated GraphicsPipe
00151 //               and returns it.  The GraphicsEngine does not
00152 //               officially own the pointer to the gsg; but if any
00153 //               windows are created using this GSG, the
00154 //               GraphicsEngine will own the pointers to these
00155 //               windows, which in turn will own the pointer to the
00156 //               GSG.
00157 //
00158 //               There is no explicit way to release a GSG, but it
00159 //               will be destructed when all windows that reference it
00160 //               are destructed, and the draw thread that owns the GSG
00161 //               runs one more time.
00162 ////////////////////////////////////////////////////////////////////
00163 PT(GraphicsStateGuardian) GraphicsEngine::
00164 make_gsg(GraphicsPipe *pipe, const FrameBufferProperties &properties,
00165          const GraphicsThreadingModel &threading_model) {
00166   // TODO: ask the draw thread to make the GSG.
00167   PT(GraphicsStateGuardian) gsg = pipe->make_gsg(properties);
00168   if (gsg != (GraphicsStateGuardian *)NULL) {
00169     gsg->_threading_model = threading_model;
00170     gsg->_pipe = pipe;
00171   }
00172 
00173   return gsg;
00174 }
00175 
00176 ////////////////////////////////////////////////////////////////////
00177 //     Function: GraphicsEngine::make_window
00178 //       Access: Published
00179 //  Description: Creates a new window using the indicated
00180 //               GraphicsStateGuardian and returns it.  The
00181 //               GraphicsEngine becomes the owner of the window; it
00182 //               will persist at least until remove_window() is called
00183 //               later.
00184 ////////////////////////////////////////////////////////////////////
00185 GraphicsWindow *GraphicsEngine::
00186 make_window(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
00187             const GraphicsThreadingModel &threading_model) {
00188   if (gsg != (GraphicsStateGuardian *)NULL) {
00189     nassertr(pipe == gsg->get_pipe(), NULL);
00190     nassertr(threading_model.get_draw_name() ==
00191              gsg->get_threading_model().get_draw_name(), NULL);
00192   }
00193 
00194   // TODO: ask the window thread to make the window.
00195   PT(GraphicsWindow) window = pipe->make_window(gsg);
00196   if (window != (GraphicsWindow *)NULL) {
00197     MutexHolder holder(_lock);
00198     _windows.insert(window);
00199 
00200     WindowRenderer *cull = get_window_renderer(threading_model.get_cull_name());
00201     WindowRenderer *draw = get_window_renderer(threading_model.get_draw_name());
00202     draw->add_gsg(gsg);
00203 
00204     if (threading_model.get_cull_sorting()) {
00205       cull->add_window(cull->_cull, window);
00206       draw->add_window(draw->_draw, window);
00207     } else {
00208       cull->add_window(cull->_cdraw, window);
00209     }
00210 
00211     // We should ask the pipe which thread it prefers to run its
00212     // windowing commands in (the "window thread").  This is the
00213     // thread that handles the commands to open, resize, etc. the
00214     // window.  X requires this to be done in the app thread, but some
00215     // pipes might prefer this to be done in draw, for instance.  For
00216     // now, we assume this is the app thread.
00217     _app.add_window(_app._window, window);
00218 
00219     display_cat.info()
00220       << "Created " << window->get_type() << "\n";
00221   }
00222   return window;
00223 }
00224 
00225 ////////////////////////////////////////////////////////////////////
00226 //     Function: GraphicsEngine::remove_window
00227 //       Access: Published
00228 //  Description: Removes the indicated window from the set of windows
00229 //               that will be processed when render_frame() is called.
00230 //               This also closes the window if it is open, and
00231 //               removes the window from its GraphicsPipe, allowing
00232 //               the window to be destructed if there are no other
00233 //               references to it.  (However, the window may not be
00234 //               actually closed until next frame, if it is controlled
00235 //               by a sub-thread.)
00236 //
00237 //               The return value is true if the window was removed,
00238 //               false if it was not found.
00239 //
00240 //               Unlike remove_all_windows(), this function does not
00241 //               terminate any of the threads that may have been
00242 //               started to service this window; they are left running
00243 //               (since you might open a new window later on these
00244 //               threads).  If your intention is to clean up before
00245 //               shutting down, it is better to call
00246 //               remove_all_windows() then to call remove_window() one
00247 //               at a time.
00248 ////////////////////////////////////////////////////////////////////
00249 bool GraphicsEngine::
00250 remove_window(GraphicsWindow *window) {
00251   // First, make sure we know what this window is.
00252   PT(GraphicsWindow) ptwin = window;
00253   size_t count;
00254   {
00255     MutexHolder holder(_lock);
00256     count = _windows.erase(ptwin);
00257   }
00258   if (count == 0) {
00259     // Never heard of this window.  Do nothing.
00260     return false;
00261   }
00262 
00263   do_remove_window(window);
00264   return true;
00265 }
00266 
00267 ////////////////////////////////////////////////////////////////////
00268 //     Function: GraphicsEngine::remove_all_windows
00269 //       Access: Published
00270 //  Description: Removes and closes all windows from the engine.  This
00271 //               also cleans up and terminates any threads that have
00272 //               been started to service those windows.
00273 ////////////////////////////////////////////////////////////////////
00274 void GraphicsEngine::
00275 remove_all_windows() {
00276   Windows::iterator wi;
00277   for (wi = _windows.begin(); wi != _windows.end(); ++wi) {
00278     GraphicsWindow *win = (*wi);
00279     do_remove_window(win);
00280   }
00281 
00282   _windows.clear();
00283 
00284   _app.do_release(this);
00285   _app.do_close(this);
00286   terminate_threads();
00287 }
00288 
00289 ////////////////////////////////////////////////////////////////////
00290 //     Function: GraphicsEngine::is_empty
00291 //       Access: Published
00292 //  Description: Returns true if there are no windows managed by the
00293 //               engine, false if there is at least one.
00294 ////////////////////////////////////////////////////////////////////
00295 bool GraphicsEngine::
00296 is_empty() const {
00297   return _windows.empty();
00298 }
00299 
00300 ////////////////////////////////////////////////////////////////////
00301 //     Function: GraphicsEngine::render_frame
00302 //       Access: Published
00303 //  Description: Renders the next frame in all the registered windows,
00304 //               and flips all of the frame buffers.
00305 ////////////////////////////////////////////////////////////////////
00306 void GraphicsEngine::
00307 render_frame() {
00308   // We hold the GraphicsEngine mutex while we wait for all of the
00309   // threads.  Doing this puts us at risk for deadlock if any of the
00310   // threads tries to call any methods on the GraphicsEngine.  So
00311   // don't do that.
00312   MutexHolder holder(_lock);
00313 
00314   if (_flip_state != FS_flip) {
00315     do_flip_frame();
00316   }
00317   
00318   // Grab each thread's mutex again after all windows have flipped.
00319   Threads::const_iterator ti;
00320   for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
00321     RenderThread *thread = (*ti).second;
00322     thread->_cv_mutex.lock();
00323   }
00324   
00325   // Now cycle the pipeline and officially begin the next frame.
00326   _pipeline->cycle();
00327   ClockObject::get_global_clock()->tick();
00328   PStatClient::main_tick();
00329   
00330   // Now signal all of our threads to begin their next frame.
00331   _app.do_frame(this);
00332   for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
00333     RenderThread *thread = (*ti).second;
00334     if (thread->_thread_state == TS_wait) {
00335       thread->_thread_state = TS_do_frame;
00336       thread->_cv.signal();
00337     }
00338     thread->_cv_mutex.release();
00339   }
00340 
00341   // Some threads may still be drawing, so indicate that we have to
00342   // wait for those threads before we can flip.
00343   _flip_state = FS_draw;
00344 
00345   // But if we don't have any threads, go ahead and flip the frame
00346   // now.  No point in waiting if we're single-threaded.
00347   if (_threads.empty() && _auto_flip) {
00348     do_flip_frame();
00349   }
00350 }
00351 
00352 ////////////////////////////////////////////////////////////////////
00353 //     Function: GraphicsEngine::sync_frame
00354 //       Access: Published
00355 //  Description: Waits for all the threads that started drawing their
00356 //               last frame to finish drawing.  The windows are not
00357 //               yet flipped when this returns; see also flip_frame().
00358 //               It is not usually necessary to call this explicitly,
00359 //               unless you need to see the previous frame right away.
00360 ////////////////////////////////////////////////////////////////////
00361 void GraphicsEngine::
00362 sync_frame() {
00363   MutexHolder holder(_lock);
00364 
00365   if (_flip_state == FS_draw) {
00366     do_sync_frame();
00367   }
00368 }
00369 
00370 ////////////////////////////////////////////////////////////////////
00371 //     Function: GraphicsEngine::flip_frame
00372 //       Access: Published
00373 //  Description: Waits for all the threads that started drawing their
00374 //               last frame to finish drawing, and then flips all the
00375 //               windows.  It is not usually necessary to call this
00376 //               explicitly, unless you need to see the previous frame
00377 //               right away.
00378 ////////////////////////////////////////////////////////////////////
00379 void GraphicsEngine::
00380 flip_frame() {
00381   MutexHolder holder(_lock);
00382 
00383   if (_flip_state != FS_flip) {
00384     do_flip_frame();
00385   }
00386 }
00387 
00388 
00389 ////////////////////////////////////////////////////////////////////
00390 //     Function: GraphicsEngine::render_subframe
00391 //       Access: Published
00392 //  Description: Performs a complete cull and draw pass for one
00393 //               particular display region.  This is normally useful
00394 //               only for special effects, like shaders, that require
00395 //               a complete offscreen render pass before they can
00396 //               complete.
00397 //
00398 //               This always executes completely within the calling
00399 //               thread, regardless of the threading model in use.
00400 //               Thus, it must always be called from the draw thread,
00401 //               whichever thread that may be.
00402 ////////////////////////////////////////////////////////////////////
00403 void GraphicsEngine::
00404 render_subframe(GraphicsStateGuardian *gsg, DisplayRegion *dr,
00405                 bool cull_sorting) {
00406   if (cull_sorting) {
00407     cull_bin_draw(gsg, dr);
00408   } else {
00409     cull_and_draw_together(gsg, dr);
00410   }
00411 }
00412 
00413 ////////////////////////////////////////////////////////////////////
00414 //     Function: GraphicsEngine::cull_and_draw_together
00415 //       Access: Private
00416 //  Description: This is called in the cull+draw thread by individual
00417 //               RenderThread objects during the frame rendering.  It
00418 //               culls the geometry and immediately draws it, without
00419 //               first collecting it into bins.  This is used when the
00420 //               threading model begins with the "-" character.
00421 ////////////////////////////////////////////////////////////////////
00422 void GraphicsEngine::
00423 cull_and_draw_together(const GraphicsEngine::Windows &wlist) {
00424   Windows::const_iterator wi;
00425   for (wi = wlist.begin(); wi != wlist.end(); ++wi) {
00426     GraphicsWindow *win = (*wi);
00427     if (win->is_active()) {
00428       if (win->begin_frame()) {
00429         win->clear();
00430       
00431         int num_display_regions = win->get_num_display_regions();
00432         for (int i = 0; i < num_display_regions; i++) {
00433           DisplayRegion *dr = win->get_display_region(i);
00434           cull_and_draw_together(win->get_gsg(), dr);
00435         }
00436         win->end_frame();
00437       }
00438     }
00439   }
00440 }
00441 
00442 ////////////////////////////////////////////////////////////////////
00443 //     Function: GraphicsEngine::cull_and_draw_together
00444 //       Access: Private
00445 //  Description: This variant of cull_and_draw_together() is called
00446 //               only by render_subframe().
00447 ////////////////////////////////////////////////////////////////////
00448 void GraphicsEngine::
00449 cull_and_draw_together(GraphicsStateGuardian *gsg, DisplayRegion *dr) {
00450   nassertv(gsg != (GraphicsStateGuardian *)NULL);
00451 
00452   PT(SceneSetup) scene_setup = setup_scene(dr->get_camera(), gsg);
00453   if (setup_gsg(gsg, scene_setup)) {
00454     DisplayRegionStack old_dr = gsg->push_display_region(dr);
00455     gsg->prepare_display_region();
00456     if (dr->is_any_clear_active()) {
00457       gsg->clear(dr);
00458     }
00459 
00460     DrawCullHandler cull_handler(gsg);
00461     if (gsg->begin_scene()) {
00462       do_cull(&cull_handler, scene_setup, gsg);
00463       gsg->end_scene();
00464     }
00465     
00466     gsg->pop_display_region(old_dr);
00467   }
00468 }
00469 
00470 ////////////////////////////////////////////////////////////////////
00471 //     Function: GraphicsEngine::cull_bin_draw
00472 //       Access: Private
00473 //  Description: This is called in the cull thread by individual
00474 //               RenderThread objects during the frame rendering.  It
00475 //               collects the geometry into bins in preparation for
00476 //               drawing.
00477 ////////////////////////////////////////////////////////////////////
00478 void GraphicsEngine::
00479 cull_bin_draw(const GraphicsEngine::Windows &wlist) {
00480   Windows::const_iterator wi;
00481   for (wi = wlist.begin(); wi != wlist.end(); ++wi) {
00482     GraphicsWindow *win = (*wi);
00483     if (win->is_active()) {
00484       // This should be done in the draw thread, not here.
00485       if (win->begin_frame()) {
00486         win->clear();
00487       
00488         int num_display_regions = win->get_num_display_regions();
00489         for (int i = 0; i < num_display_regions; i++) {
00490           DisplayRegion *dr = win->get_display_region(i);
00491           cull_bin_draw(win->get_gsg(), dr);
00492         }
00493 
00494         win->end_frame();
00495       }
00496     }
00497   }
00498 }
00499 
00500 ////////////////////////////////////////////////////////////////////
00501 //     Function: GraphicsEngine::cull_bin_draw
00502 //       Access: Private
00503 //  Description: This variant of cull_bin_draw() is called
00504 //               by render_subframe(), as well as within the
00505 //               implementation of cull_bin_draw(), above.
00506 ////////////////////////////////////////////////////////////////////
00507 void GraphicsEngine::
00508 cull_bin_draw(GraphicsStateGuardian *gsg, DisplayRegion *dr) {
00509   nassertv(gsg != (GraphicsStateGuardian *)NULL);
00510 
00511   PT(CullResult) cull_result = dr->_cull_result;
00512   if (cull_result != (CullResult *)NULL) {
00513     cull_result = cull_result->make_next();
00514   } else {
00515     cull_result = new CullResult(gsg);
00516   }
00517 
00518   PT(SceneSetup) scene_setup = setup_scene(dr->get_camera(), gsg);
00519   if (scene_setup != (SceneSetup *)NULL) {
00520     BinCullHandler cull_handler(cull_result);
00521     do_cull(&cull_handler, scene_setup, gsg);
00522     
00523     cull_result->finish_cull();
00524     
00525     // Save the results for next frame.
00526     dr->_cull_result = cull_result;
00527     
00528     // Now draw.
00529     // This should get deferred into the next pipeline stage.
00530     do_draw(cull_result, scene_setup, gsg, dr);
00531   }
00532 }
00533 
00534 ////////////////////////////////////////////////////////////////////
00535 //     Function: GraphicsEngine::process_events
00536 //       Access: Private
00537 //  Description: This is called by the RenderThread object to process
00538 //               all the windows events (resize, etc.) for the given
00539 //               list of windows.  This is run in the window thread.
00540 ////////////////////////////////////////////////////////////////////
00541 void GraphicsEngine::
00542 process_events(const GraphicsEngine::Windows &wlist) {
00543   Windows::const_iterator wi;
00544   for (wi = wlist.begin(); wi != wlist.end(); ++wi) {
00545     GraphicsWindow *win = (*wi);
00546     win->process_events();
00547   }
00548 }
00549 
00550 ////////////////////////////////////////////////////////////////////
00551 //     Function: GraphicsEngine::flip_windows
00552 //       Access: Private
00553 //  Description: This is called by the RenderThread object to flip the
00554 //               buffers (resize, etc.) for the given list of windows.
00555 //               This is run in the draw thread.
00556 ////////////////////////////////////////////////////////////////////
00557 void GraphicsEngine::
00558 flip_windows(const GraphicsEngine::Windows &wlist) {
00559   Windows::const_iterator wi;
00560   for (wi = wlist.begin(); wi != wlist.end(); ++wi) {
00561     GraphicsWindow *win = (*wi);
00562     win->begin_flip();
00563   }
00564   for (wi = wlist.begin(); wi != wlist.end(); ++wi) {
00565     GraphicsWindow *win = (*wi);
00566     win->end_flip();
00567   }
00568 }
00569 
00570 ////////////////////////////////////////////////////////////////////
00571 //     Function: GraphicsEngine::do_sync_frame
00572 //       Access: Private
00573 //  Description: The implementation of sync_frame().  We assume _lock
00574 //               is already held before this method is called.
00575 ////////////////////////////////////////////////////////////////////
00576 void GraphicsEngine::
00577 do_sync_frame() {
00578   nassertv(_flip_state == FS_draw);
00579 
00580   // Wait for all the threads to finish their current frame.  Grabbing
00581   // and releasing the mutex should achieve that.
00582   Threads::const_iterator ti;
00583   for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
00584     RenderThread *thread = (*ti).second;
00585     thread->_cv_mutex.lock();
00586     thread->_cv_mutex.release();
00587   }
00588 
00589   _flip_state = FS_sync;
00590 }
00591 
00592 ////////////////////////////////////////////////////////////////////
00593 //     Function: GraphicsEngine::do_flip_frame
00594 //       Access: Private
00595 //  Description: The implementation of flip_frame().  We assume _lock
00596 //               is already held before this method is called.
00597 ////////////////////////////////////////////////////////////////////
00598 void GraphicsEngine::
00599 do_flip_frame() {
00600   nassertv(_flip_state == FS_draw || _flip_state == FS_sync);
00601 
00602   // First, wait for all the threads to finish their current frame, if
00603   // necessary.  Grabbing the mutex should achieve that.
00604   Threads::const_iterator ti;
00605   for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
00606     RenderThread *thread = (*ti).second;
00607     thread->_cv_mutex.lock();
00608   }
00609   
00610   // Now signal all of our threads to flip the windows.
00611   _app.do_flip(this);
00612   for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
00613     RenderThread *thread = (*ti).second;
00614     if (thread->_thread_state == TS_wait) {
00615       thread->_thread_state = TS_do_flip;
00616       thread->_cv.signal();
00617     }
00618     thread->_cv_mutex.release();
00619   }
00620 
00621   _flip_state = FS_flip;
00622 }
00623 
00624 ////////////////////////////////////////////////////////////////////
00625 //     Function: GraphicsEngine::setup_scene
00626 //       Access: Private
00627 //  Description: Returns a new SceneSetup object appropriate for
00628 //               rendering the scene from the indicated camera, or
00629 //               NULL if the scene should not be rendered for some
00630 //               reason.
00631 ////////////////////////////////////////////////////////////////////
00632 PT(SceneSetup) GraphicsEngine::
00633 setup_scene(const NodePath &camera, GraphicsStateGuardian *gsg) {
00634   if (camera.is_empty()) {
00635     // No camera, no draw.
00636     return NULL;
00637   }
00638 
00639   Camera *camera_node;
00640   DCAST_INTO_R(camera_node, camera.node(), NULL);
00641 
00642   if (!camera_node->is_active()) {
00643     // Camera inactive, no draw.
00644     return NULL;
00645   }
00646 
00647   Lens *lens = camera_node->get_lens();
00648   if (lens == (Lens *)NULL) {
00649     // No lens, no draw.
00650     return NULL;
00651   }
00652 
00653   NodePath scene_root = camera_node->get_scene();
00654   if (scene_root.is_empty()) {
00655     // No scene, no draw.
00656     return NULL;
00657   }
00658 
00659   PT(SceneSetup) scene_setup = new SceneSetup;
00660 
00661   // We will need both the camera transform (the net transform to the
00662   // camera from the scene) and the world transform (the camera
00663   // transform inverse, or the net transform to the scene from the
00664   // camera).
00665   CPT(TransformState) camera_transform = camera.get_transform(scene_root);
00666   CPT(TransformState) world_transform = scene_root.get_transform(camera);
00667 
00668   // The render transform is the same as the world transform, except
00669   // it is converted into the GSG's internal coordinate system.  This
00670   // is the transform that the GSG will apply to all of its vertices.
00671   CPT(TransformState) cs_transform = TransformState::make_identity();
00672   CoordinateSystem external_cs = gsg->get_coordinate_system();
00673   CoordinateSystem internal_cs = gsg->get_internal_coordinate_system();
00674   if (internal_cs != CS_default && internal_cs != external_cs) {
00675     cs_transform = 
00676       TransformState::make_mat(LMatrix4f::convert_mat(external_cs, internal_cs));
00677   }
00678 
00679   scene_setup->set_scene_root(scene_root);
00680   scene_setup->set_camera_path(camera);
00681   scene_setup->set_camera_node(camera_node);
00682   scene_setup->set_lens(lens);
00683   scene_setup->set_camera_transform(camera_transform);
00684   scene_setup->set_world_transform(world_transform);
00685   scene_setup->set_cs_transform(cs_transform);
00686 
00687   return scene_setup;
00688 }
00689 
00690 ////////////////////////////////////////////////////////////////////
00691 //     Function: GraphicsEngine::do_cull
00692 //       Access: Private
00693 //  Description: Fires off a cull traversal using the indicated camera.
00694 ////////////////////////////////////////////////////////////////////
00695 void GraphicsEngine::
00696 do_cull(CullHandler *cull_handler, SceneSetup *scene_setup,
00697         GraphicsStateGuardian *gsg) {
00698   // Statistics
00699   PStatTimer timer(_cull_pcollector);
00700 
00701   CullTraverser trav;
00702   trav.set_cull_handler(cull_handler);
00703   trav.set_depth_offset_decals(gsg->depth_offset_decals());
00704   trav.set_scene(scene_setup);
00705   trav.set_camera_mask(scene_setup->get_camera_node()->get_camera_mask());
00706 
00707   if (view_frustum_cull) {
00708     // If we're to be performing view-frustum culling, determine the
00709     // bounding volume associated with the current viewing frustum.
00710 
00711     // First, we have to get the current viewing frustum, which comes
00712     // from the lens.
00713     PT(BoundingVolume) bv = scene_setup->get_lens()->make_bounds();
00714 
00715     if (bv != (BoundingVolume *)NULL &&
00716         bv->is_of_type(GeometricBoundingVolume::get_class_type())) {
00717       // Transform it into the appropriate coordinate space.
00718       PT(GeometricBoundingVolume) local_frustum;
00719       local_frustum = DCAST(GeometricBoundingVolume, bv->make_copy());
00720       local_frustum->xform(scene_setup->get_camera_transform()->get_mat());
00721 
00722       trav.set_view_frustum(local_frustum);
00723     }
00724   }
00725   
00726   trav.traverse(scene_setup->get_scene_root());
00727 }
00728 
00729 ////////////////////////////////////////////////////////////////////
00730 //     Function: GraphicsEngine::do_draw
00731 //       Access: Private
00732 //  Description: Draws the previously-culled scene.
00733 ////////////////////////////////////////////////////////////////////
00734 void GraphicsEngine::
00735 do_draw(CullResult *cull_result, SceneSetup *scene_setup,
00736         GraphicsStateGuardian *gsg, DisplayRegion *dr) {
00737   // Statistics
00738   PStatTimer timer(_draw_pcollector);
00739 
00740   if (setup_gsg(gsg, scene_setup)) {
00741     DisplayRegionStack old_dr = gsg->push_display_region(dr);
00742     gsg->prepare_display_region();
00743     if (dr->is_any_clear_active()) {
00744       gsg->clear(dr);
00745     }
00746     if (gsg->begin_scene()) {
00747       cull_result->draw();
00748       gsg->end_scene();
00749     }
00750     gsg->pop_display_region(old_dr);
00751   }
00752 }
00753 
00754 ////////////////////////////////////////////////////////////////////
00755 //     Function: GraphicsEngine::setup_gsg
00756 //       Access: Private
00757 //  Description: Sets up the GSG to draw the indicated scene.  Returns
00758 //               true if the scene (and its lens) is acceptable, false
00759 //               otherwise.
00760 ////////////////////////////////////////////////////////////////////
00761 bool GraphicsEngine::
00762 setup_gsg(GraphicsStateGuardian *gsg, SceneSetup *scene_setup) {
00763   if (scene_setup == (SceneSetup *)NULL) {
00764     // No scene, no draw.
00765     return false;
00766   }
00767 
00768   const Lens *lens = scene_setup->get_lens();
00769   if (lens == (const Lens *)NULL) {
00770     // No lens, no draw.
00771     return false;
00772   }
00773 
00774   if (!gsg->set_lens(lens)) {
00775     // The lens is inappropriate somehow.
00776     display_cat.error()
00777       << gsg->get_type() << " cannot render with " << lens->get_type()
00778       << "\n";
00779     return false;
00780   }
00781 
00782   gsg->set_scene(scene_setup);
00783 
00784   return true;
00785 }
00786 
00787 ////////////////////////////////////////////////////////////////////
00788 //     Function: GraphicsEngine::do_remove_window
00789 //       Access: Private
00790 //  Description: An internal function called by remove_window() and
00791 //               remove_all_windows() to actually remove the indicated
00792 //               window from all relevant structures, except the
00793 //               _windows list itself.
00794 ////////////////////////////////////////////////////////////////////
00795 void GraphicsEngine::
00796 do_remove_window(GraphicsWindow *window) {
00797   PT(GraphicsPipe) pipe = window->get_pipe();
00798   window->_pipe = (GraphicsPipe *)NULL;
00799 
00800   // Now remove the window from all threads that know about it.
00801   _app.remove_window(window);
00802   Threads::const_iterator ti;
00803   for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
00804     RenderThread *thread = (*ti).second;
00805     thread->remove_window(window);
00806   }
00807 
00808   // If the window happened to be controlled by the app thread, we
00809   // might as well close it now rather than waiting for next frame.
00810   _app.do_pending(this);
00811 }
00812 
00813 ////////////////////////////////////////////////////////////////////
00814 //     Function: GraphicsEngine::terminate_threads
00815 //       Access: Private
00816 //  Description: Signals our child threads to terminate and waits for
00817 //               them to clean up.
00818 ////////////////////////////////////////////////////////////////////
00819 void GraphicsEngine::
00820 terminate_threads() {
00821   MutexHolder holder(_lock);
00822   
00823   // First, wait for all the threads to finish their current frame.
00824   // Grabbing the mutex should achieve that.
00825   Threads::const_iterator ti;
00826   for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
00827     RenderThread *thread = (*ti).second;
00828     thread->_cv_mutex.lock();
00829   }
00830 
00831   // Now tell them to release their windows' graphics contexts.
00832   for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
00833     RenderThread *thread = (*ti).second;
00834     if (thread->_thread_state == TS_wait) {
00835       thread->_thread_state = TS_do_release;
00836       thread->_cv.signal();
00837     }
00838     thread->_cv_mutex.release();
00839   }
00840 
00841   // Grab the mutex again to wait for the above to complete.
00842   for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
00843     RenderThread *thread = (*ti).second;
00844     thread->_cv_mutex.lock();
00845   }
00846 
00847   // Now tell them to close their windows and terminate.
00848   for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
00849     RenderThread *thread = (*ti).second;
00850     MutexHolder cv_holder(thread->_cv_mutex);
00851     thread->_thread_state = TS_terminate;
00852     thread->_cv.signal();
00853     thread->_cv_mutex.release();
00854   }
00855 
00856   // Finally, wait for them all to finish cleaning up.
00857   for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
00858     RenderThread *thread = (*ti).second;
00859     thread->join();
00860   }
00861   
00862   _threads.clear();
00863 }
00864 
00865 ////////////////////////////////////////////////////////////////////
00866 //     Function: GraphicsEngine::get_window_renderer
00867 //       Access: Private
00868 //  Description: Returns the WindowRenderer with the given name.
00869 //               Creates a new RenderThread if there is no such thread
00870 //               already.
00871 ////////////////////////////////////////////////////////////////////
00872 GraphicsEngine::WindowRenderer *GraphicsEngine::
00873 get_window_renderer(const string &name) {
00874   if (name.empty()) {
00875     return &_app;
00876   }
00877 
00878   MutexHolder holder(_lock);
00879   Threads::iterator ti = _threads.find(name);
00880   if (ti != _threads.end()) {
00881     return (*ti).second.p();
00882   }
00883 
00884   PT(RenderThread) thread = new RenderThread(name, this);
00885   thread->start(TP_normal, true, true);
00886   _threads[name] = thread;
00887 
00888   return thread.p();
00889 }
00890 
00891 ////////////////////////////////////////////////////////////////////
00892 //     Function: GraphicsEngine::WindowRenderer::add_gsg
00893 //       Access: Public
00894 //  Description: Adds a new GSG to the _gsg list, if it is not already
00895 //               there.
00896 ////////////////////////////////////////////////////////////////////
00897 void GraphicsEngine::WindowRenderer::
00898 add_gsg(GraphicsStateGuardian *gsg) {
00899   MutexHolder holder(_wl_lock);
00900   _gsgs.insert(gsg);
00901 }
00902 
00903 ////////////////////////////////////////////////////////////////////
00904 //     Function: GraphicsEngine::WindowRenderer::add_window
00905 //       Access: Public
00906 //  Description: Adds a new window to the indicated list, which should
00907 //               be a member of the WindowRenderer.
00908 ////////////////////////////////////////////////////////////////////
00909 void GraphicsEngine::WindowRenderer::
00910 add_window(Windows &wlist, GraphicsWindow *window) {
00911   MutexHolder holder(_wl_lock);
00912   wlist.insert(window);
00913 }
00914 
00915 ////////////////////////////////////////////////////////////////////
00916 //     Function: GraphicsEngine::WindowRenderer::remove_window_now
00917 //       Access: Public
00918 //  Description: Immediately removes the indicated window from all
00919 //               lists.  If the window is currently open and is
00920 //               already on the _window list, moves it to the _pending_close
00921 //               list for later closure.
00922 ////////////////////////////////////////////////////////////////////
00923 void GraphicsEngine::WindowRenderer::
00924 remove_window(GraphicsWindow *window) {
00925   MutexHolder holder(_wl_lock);
00926   PT(GraphicsWindow) ptwin = window;
00927 
00928   _cull.erase(ptwin);
00929 
00930   Windows::iterator wi;
00931 
00932   wi = _cdraw.find(ptwin);
00933   if (wi != _cdraw.end()) {
00934     // The window is on our _cdraw list, meaning its GSG operations are
00935     // serviced by this thread (cull and draw in the same operation).
00936     
00937     // Move it to the pending release thread so we can release the GSG
00938     // when the thread next runs.  We can't do this immediately,
00939     // because we might not have been called from the subthread.
00940     _pending_release.insert(ptwin);
00941     _cdraw.erase(wi);
00942   }
00943 
00944   wi = _draw.find(ptwin);
00945   if (wi != _draw.end()) {
00946     // The window is on our _draw list, meaning its GSG operations are
00947     // serviced by this thread (draw performed on this thread).
00948     
00949     // Move it to the pending release thread so we can release the GSG
00950     // when the thread next runs.  We can't do this immediately,
00951     // because we might not have been called from the subthread.
00952     _pending_release.insert(ptwin);
00953     _draw.erase(wi);
00954   }
00955 
00956   wi = _window.find(ptwin);
00957   if (wi != _window.end()) {
00958     // The window is on our _window list, meaning its open/close
00959     // operations (among other window ops) are serviced by this
00960     // thread.
00961 
00962     // Make sure the window isn't about to request itself open.
00963     WindowProperties close_properties;
00964     close_properties.set_open(false);
00965     ptwin->request_properties(close_properties);
00966 
00967     // If the window is already open, move it to the _pending_close list so
00968     // it can be closed later.  We can't close it immediately, because
00969     // we might not have been called from the subthread.
00970     if (!ptwin->is_closed()) {
00971       _pending_close.insert(ptwin);
00972     }
00973 
00974     _window.erase(wi);
00975   }
00976 }
00977 
00978 ////////////////////////////////////////////////////////////////////
00979 //     Function: GraphicsEngine::WindowRenderer::do_frame
00980 //       Access: Public
00981 //  Description: Executes one stage of the pipeline for the current
00982 //               thread: calls cull on all windows that are on the
00983 //               cull list for this thread, draw on all the windows on
00984 //               the draw list, etc.
00985 ////////////////////////////////////////////////////////////////////
00986 void GraphicsEngine::WindowRenderer::
00987 do_frame(GraphicsEngine *engine) {
00988   MutexHolder holder(_wl_lock);
00989   engine->cull_bin_draw(_cull);
00990   engine->cull_and_draw_together(_cdraw);
00991   engine->process_events(_window);
00992 
00993   // If any GSG's on the list have no more outstanding pointers, clean
00994   // them up.  (We are in the draw thread for all of these GSG's.)
00995   if (any_done_gsgs()) {
00996     GSGs new_gsgs;
00997     GSGs::iterator gi;
00998     for (gi = _gsgs.begin(); gi != _gsgs.end(); ++gi) {
00999       GraphicsStateGuardian *gsg = (*gi);
01000       if (gsg->get_ref_count() == 1) {
01001         // This one has no outstanding pointers; clean it up.
01002         GraphicsPipe *pipe = gsg->get_pipe();
01003         engine->close_gsg(pipe, gsg);
01004       } else { 
01005         // This one is ok; preserve it.
01006         new_gsgs.insert(gsg);
01007       }
01008     }
01009 
01010     _gsgs.swap(new_gsgs);
01011   }
01012 }
01013 
01014 ////////////////////////////////////////////////////////////////////
01015 //     Function: GraphicsEngine::WindowRenderer::do_flip
01016 //       Access: Public
01017 //  Description: Flips the windows as appropriate for the current
01018 //               thread.
01019 ////////////////////////////////////////////////////////////////////
01020 void GraphicsEngine::WindowRenderer::
01021 do_flip(GraphicsEngine *engine) {
01022   MutexHolder holder(_wl_lock);
01023   engine->flip_windows(_cdraw);
01024   engine->flip_windows(_draw);
01025 }
01026 
01027 ////////////////////////////////////////////////////////////////////
01028 //     Function: GraphicsEngine::WindowRenderer::do_release
01029 //       Access: Public
01030 //  Description: Releases the rendering contexts for all windows on
01031 //               the _draw list.
01032 ////////////////////////////////////////////////////////////////////
01033 void GraphicsEngine::WindowRenderer::
01034 do_release(GraphicsEngine *) {
01035   MutexHolder holder(_wl_lock);
01036   Windows::iterator wi;
01037   for (wi = _draw.begin(); wi != _draw.end(); ++wi) {
01038     GraphicsWindow *win = (*wi);
01039     win->release_gsg();
01040   }
01041 }
01042 
01043 ////////////////////////////////////////////////////////////////////
01044 //     Function: GraphicsEngine::WindowRenderer::do_close
01045 //       Access: Public
01046 //  Description: Closes all the windows on the _window list.
01047 ////////////////////////////////////////////////////////////////////
01048 void GraphicsEngine::WindowRenderer::
01049 do_close(GraphicsEngine *engine) {
01050   WindowProperties close_properties;
01051   close_properties.set_open(false);
01052 
01053   MutexHolder holder(_wl_lock);
01054   Windows::iterator wi;
01055   for (wi = _window.begin(); wi != _window.end(); ++wi) {
01056     GraphicsWindow *win = (*wi);
01057     win->set_properties_now(close_properties);
01058   }
01059 
01060   // Also close all of the GSG's.
01061   GSGs new_gsgs;
01062   GSGs::iterator gi;
01063   for (gi = _gsgs.begin(); gi != _gsgs.end(); ++gi) {
01064     GraphicsStateGuardian *gsg = (*gi);
01065     if (gsg->get_ref_count() == 1) {
01066       // This one has no outstanding pointers; clean it up.
01067       GraphicsPipe *pipe = gsg->get_pipe();
01068       engine->close_gsg(pipe, gsg);
01069     } else { 
01070       // This one is ok; preserve it.
01071       new_gsgs.insert(gsg);
01072     }
01073   }
01074   
01075   _gsgs.swap(new_gsgs);
01076 }
01077 
01078 ////////////////////////////////////////////////////////////////////
01079 //     Function: GraphicsEngine::WindowRenderer::do_pending
01080 //       Access: Public
01081 //  Description: Actually closes any windows that were recently
01082 //               removed from the WindowRenderer.
01083 ////////////////////////////////////////////////////////////////////
01084 void GraphicsEngine::WindowRenderer::
01085 do_pending(GraphicsEngine *engine) {
01086   MutexHolder holder(_wl_lock);
01087 
01088   if (!_pending_release.empty()) {
01089     // Release any GSG's that were waiting.
01090     Windows::iterator wi;
01091     for (wi = _pending_release.begin(); wi != _pending_release.end(); ++wi) {
01092       GraphicsWindow *win = (*wi);
01093       win->release_gsg();
01094     }
01095     _pending_release.clear();
01096   }
01097 
01098   if (!_pending_close.empty()) {
01099     WindowProperties close_properties;
01100     close_properties.set_open(false);
01101 
01102     // Close any windows that were pending closure, but only if their
01103     // associated GSG has already been released.
01104     Windows new_pending_close;
01105     Windows::iterator wi;
01106     for (wi = _pending_close.begin(); wi != _pending_close.end(); ++wi) {
01107       GraphicsWindow *win = (*wi);
01108       if (win->get_gsg() == (GraphicsStateGuardian *)NULL) {
01109         win->set_properties_now(close_properties);
01110       } else {
01111         // If the GSG hasn't been released yet, we have to save the
01112         // close operation for next frame.
01113         new_pending_close.insert(win);
01114       }
01115     }
01116     _pending_close.swap(new_pending_close);
01117   }
01118 }
01119 
01120 ////////////////////////////////////////////////////////////////////
01121 //     Function: GraphicsEngine::WindowRenderer::any_done_gsgs
01122 //       Access: Public
01123 //  Description: Returns true if any of the GSG's on this thread's
01124 //               draw list are done (they have no outstanding pointers
01125 //               other than this one), or false if all of them are
01126 //               still good.
01127 ////////////////////////////////////////////////////////////////////
01128 bool GraphicsEngine::WindowRenderer::
01129 any_done_gsgs() const {
01130   GSGs::const_iterator gi;
01131   for (gi = _gsgs.begin(); gi != _gsgs.end(); ++gi) {
01132     if ((*gi)->get_ref_count() == 1) {
01133       return true;
01134     }
01135   }
01136 
01137   return false;
01138 }
01139 
01140 ////////////////////////////////////////////////////////////////////
01141 //     Function: GraphicsEngine::RenderThread::Constructor
01142 //       Access: Public
01143 //  Description: 
01144 ////////////////////////////////////////////////////////////////////
01145 GraphicsEngine::RenderThread::
01146 RenderThread(const string &name, GraphicsEngine *engine) : 
01147   Thread(name),
01148   _engine(engine),
01149   _cv(_cv_mutex)
01150 {
01151   _thread_state = TS_wait;
01152 }
01153 
01154 ////////////////////////////////////////////////////////////////////
01155 //     Function: GraphicsEngine::RenderThread::thread_main
01156 //       Access: Public, Virtual
01157 //  Description: The main loop for a particular render thread.  The
01158 //               thread will process whatever cull or draw windows it
01159 //               has assigned to it.
01160 ////////////////////////////////////////////////////////////////////
01161 void GraphicsEngine::RenderThread::
01162 thread_main() {
01163   MutexHolder holder(_cv_mutex);
01164   while (true) {
01165     _cv.wait();
01166     switch (_thread_state) {
01167     case TS_wait:
01168       break;
01169 
01170     case TS_do_frame:
01171       do_pending(_engine);
01172       do_frame(_engine);
01173       _thread_state = TS_wait;
01174       break;
01175 
01176     case TS_do_flip:
01177       do_flip(_engine);
01178       _thread_state = TS_wait;
01179       break;
01180 
01181     case TS_do_release:
01182       do_pending(_engine);
01183       do_release(_engine);
01184       _thread_state = TS_wait;
01185       break;
01186 
01187     case TS_terminate:
01188       do_pending(_engine);
01189       do_close(_engine);
01190       return;
01191     }
01192   }
01193 }

Generated on Fri May 2 00:36:26 2003 for Panda by doxygen1.3