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