00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
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
00094
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
00122
00123
00124
00125
00126
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
00158
00159
00160
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
00175
00176
00177
00178
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
00211
00212
00213
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
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
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
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
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
00299
00300
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
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
00341 if ((flags & GraphicsPipe::BF_require_callback_window)!=0) {
00342 PT(GraphicsStateGuardian) this_gsg = gsg;
00343 if (this_gsg == (GraphicsStateGuardian *)NULL) {
00344
00345
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
00358
00359 return NULL;
00360 }
00361
00362
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
00379
00380
00381
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
00397
00398
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
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
00452 bool removed = remove_window(window);
00453 nassertr(removed, NULL);
00454 }
00455 }
00456
00457
00458
00459
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
00471
00472 return NULL;
00473 }
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499 bool GraphicsEngine::
00500 remove_window(GraphicsOutput *window) {
00501 nassertr(window != NULL, false);
00502 Thread *current_thread = Thread::get_current_thread();
00503
00504
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
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
00526
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
00541
00542
00543
00544
00545
00546 pgo->release_all();
00547 }
00548 }
00549 }
00550
00551 nassertr(count == 1, true);
00552 return true;
00553 }
00554
00555
00556
00557
00558
00559
00560
00561
00562 void GraphicsEngine::
00563 remove_all_windows() {
00564 Thread *current_thread = Thread::get_current_thread();
00565
00566
00567
00568
00569
00570
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
00589
00590
00591
00592
00593 BamCache *cache = BamCache::get_global_ptr();
00594 cache->flush_index();
00595
00596
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
00606 Thread::prepare_for_exit();
00607 }
00608
00609
00610
00611
00612
00613
00614
00615
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
00623 win->reset_window(swapchain);
00624 }
00625 }
00626
00627
00628
00629
00630
00631
00632
00633
00634 bool GraphicsEngine::
00635 is_empty() const {
00636 return _windows.empty();
00637 }
00638
00639
00640
00641
00642
00643
00644
00645 int GraphicsEngine::
00646 get_num_windows() const {
00647 return _windows.size();
00648 }
00649
00650
00651
00652
00653
00654
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
00668
00669
00670
00671
00672 void GraphicsEngine::
00673 render_frame() {
00674 Thread *current_thread = Thread::get_current_thread();
00675 ReMutexHolder public_holder(_public_lock);
00676
00677
00678
00679 BamCache *cache = BamCache::get_global_ptr();
00680 cache->consider_flush_index();
00681
00682
00683
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
00693
00694
00695
00696
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
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
00732
00733
00734
00735
00736
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
00759
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
00773
00774 _app.do_frame(this, current_thread);
00775
00776
00777
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
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
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
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
00907
00908 _flip_state = _auto_flip ? FS_flip : FS_draw;
00909 }
00910
00911
00912
00913 if (yield_timeslice) {
00914
00915
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
00924
00925 _app_pcollector.start();
00926 _render_frame_pcollector.stop();
00927 }
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
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
00952
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
00978
00979
00980
00981
00982
00983
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
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
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
01022
01023
01024
01025
01026
01027
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
01041
01042
01043
01044
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
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
01075 return gsg->extract_texture_data(tex);
01076
01077 } else {
01078
01079
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
01089
01090
01091
01092 return gsg->extract_texture_data(tex);
01093 }
01094 }
01095
01096
01097
01098
01099
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
01112
01113
01114
01115
01116
01117
01118
01119
01120
01121
01122
01123 void GraphicsEngine::
01124 texture_uploaded(Texture *tex) {
01125 MutexHolder holder(_loaded_textures_lock);
01126
01127
01128
01129 _loaded_textures.push_back(LoadedTexture());
01130 LoadedTexture < = _loaded_textures.back();
01131 lt._tex = tex;
01132 lt._image_modified = tex->get_image_modified();
01133
01134 }
01135
01136
01137
01138
01139
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
01154
01155
01156
01157
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
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
01182
01183
01184
01185
01186 bool GraphicsEngine::
01187 scene_root_func(const PandaNode *node) {
01188 return _global_ptr->is_scene_root(node);
01189 }
01190
01191
01192
01193
01194
01195
01196
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
01224
01225
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
01242
01243
01244
01245
01246
01247
01248
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
01259
01260
01261
01262
01263
01264
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
01317
01318
01319
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
01340
01341 } else if (dr_reader->get_object()->is_stereo()) {
01342
01343
01344 } else if (!gsg->set_scene(scene_setup)) {
01345
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
01358 DisplayRegionCullCallbackData cbdata(&cull_handler, scene_setup);
01359 cbobj->do_callback(&cbdata);
01360
01361
01362
01363 } else {
01364
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
01379
01380
01381
01382
01383
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
01393
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
01412
01413 delete dr_reader;
01414 dr_reader = NULL;
01415 (*aci).second = dr;
01416 cull_to_bins(win, dr, current_thread);
01417
01418 } else {
01419
01420
01421
01422
01423
01424
01425
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
01443
01444
01445
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
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
01476 DisplayRegionCullCallbackData cbdata(&cull_handler, scene_setup);
01477 cbobj->do_callback(&cbdata);
01478
01479
01480
01481 } else {
01482
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
01491 dr->set_cull_result(cull_result, scene_setup, current_thread);
01492 }
01493
01494
01495
01496
01497
01498
01499
01500
01501
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
01568
01569
01570
01571
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
01587
01588
01589
01590
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
01605
01606
01607
01608
01609
01610 void GraphicsEngine::
01611 process_events(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
01612
01613
01614
01615 for (size_t i = 0; i < wlist.size(); ++i) {
01616 wlist[i]->process_events();
01617 }
01618 }
01619
01620
01621
01622
01623
01624
01625
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
01656
01657
01658
01659
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
01677
01678
01679
01680
01681 void GraphicsEngine::
01682 do_sync_frame(Thread *current_thread) {
01683 nassertv(_lock.debug_is_locked());
01684
01685
01686 PStatTimer timer(_sync_pcollector, current_thread);
01687
01688 nassertv(_flip_state == FS_draw);
01689
01690
01691
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
01705
01706
01707
01708
01709 void GraphicsEngine::
01710 do_ready_flip(Thread *current_thread) {
01711 nassertv(_lock.debug_is_locked());
01712
01713
01714 PStatTimer timer(_sync_pcollector, current_thread);
01715
01716 nassertv(_flip_state == FS_draw);
01717
01718
01719
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
01734
01735
01736
01737
01738 void GraphicsEngine::
01739 do_flip_frame(Thread *current_thread) {
01740 nassertv(_lock.debug_is_locked());
01741
01742
01743 PStatTimer timer(_flip_pcollector, current_thread);
01744
01745 nassertv(_flip_state == FS_draw || _flip_state == FS_sync);
01746
01747
01748
01749
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
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
01782
01783
01784
01785
01786
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
01795
01796
01797 nassertr(window != (GraphicsOutput *)NULL, NULL);
01798
01799 NodePath camera = dr->get_camera();
01800 if (camera.is_empty()) {
01801
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
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
01818 return NULL;
01819 }
01820
01821 NodePath scene_root = camera_node->get_scene();
01822 if (scene_root.is_empty()) {
01823
01824
01825
01826 scene_root = camera.get_top(current_thread);
01827 }
01828
01829 PT(SceneSetup) scene_setup = new SceneSetup;
01830
01831
01832
01833
01834
01835
01836
01837
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
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
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
01868
01869
01870 scene_setup->set_inverted(true);
01871
01872
01873
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
01892
01893
01894
01895 void GraphicsEngine::
01896 do_draw(CullResult *cull_result, SceneSetup *scene_setup,
01897 GraphicsOutput *win, DisplayRegion *dr, Thread *current_thread) {
01898
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
01917
01918
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
01926 gsg->clear_state_and_transform();
01927
01928
01929 return;
01930 }
01931
01932 if (cull_result == NULL || scene_setup == NULL) {
01933
01934
01935 } else if (dr->is_stereo()) {
01936
01937
01938
01939
01940
01941
01942
01943 } else if (!gsg->set_scene(scene_setup)) {
01944
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
01958
01959
01960
01961
01962
01963
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
01973
01974
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
01996
01997
01998
01999
02000
02001
02002
02003
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
02026
02027
02028
02029
02030
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
02053
02054
02055
02056
02057
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
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
02078
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
02089
02090
02091
02092
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
02110
02111
02112
02113
02114
02115
02116
02117
02118
02119
02120
02121
02122
02123
02124
02125
02126
02127
02128
02129
02130
02131
02132
02133
02134
02135
02136
02137 void GraphicsEngine::
02138 auto_adjust_capabilities(GraphicsStateGuardian *gsg) {
02139
02140
02141
02142
02143
02144
02145
02146
02147
02148
02149
02150
02151
02152
02153
02154
02155
02156
02157
02158
02159
02160
02161
02162
02163
02164
02165
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;
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
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;
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
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
02259
02260
02261
02262
02263 void GraphicsEngine::
02264 terminate_threads(Thread *current_thread) {
02265 ReMutexHolder holder(_lock, current_thread);
02266
02267
02268
02269 PStatTimer timer(_wait_pcollector, current_thread);
02270
02271
02272
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
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
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
02300
02301
02302
02303
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
02320
02321
02322
02323
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
02339
02340
02341
02342
02343
02344
02345 const RenderState *GraphicsEngine::
02346 get_invert_polygon_state() {
02347
02348
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
02359
02360
02361
02362
02363
02364
02365
02366
02367
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
02397
02398
02399
02400 GraphicsEngine::WindowRenderer::
02401 WindowRenderer(const string &name) :
02402 _wl_lock(string("GraphicsEngine::WindowRenderer::_wl_lock ") + name)
02403 {
02404 }
02405
02406
02407
02408
02409
02410
02411
02412 void GraphicsEngine::WindowRenderer::
02413 add_gsg(GraphicsStateGuardian *gsg) {
02414 LightReMutexHolder holder(_wl_lock);
02415 _gsgs.insert(gsg);
02416 }
02417
02418
02419
02420
02421
02422
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
02432
02433
02434
02435
02436
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
02453
02454
02455
02456
02457 ptwin->request_close();
02458
02459
02460
02461
02462 if (ptwin->is_valid()) {
02463 _pending_close.push_back(ptwin);
02464 }
02465
02466 _window.erase(wi);
02467 }
02468 }
02469
02470
02471
02472
02473
02474
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
02509
02510
02511
02512
02513
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
02526
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
02534 GraphicsPipe *pipe = gsg->get_pipe();
02535 engine->close_gsg(pipe, gsg);
02536 } else {
02537
02538 new_gsgs.insert(gsg);
02539 }
02540 }
02541
02542 _gsgs.swap(new_gsgs);
02543 }
02544 }
02545
02546
02547
02548
02549
02550
02551
02552
02553
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
02567
02568
02569
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
02580
02581
02582
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
02594
02595
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
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
02613 GraphicsPipe *pipe = gsg->get_pipe();
02614 engine->close_gsg(pipe, gsg);
02615 } else {
02616
02617 new_gsgs.insert(gsg);
02618 }
02619 }
02620
02621 _gsgs.swap(new_gsgs);
02622 }
02623
02624
02625
02626
02627
02628
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
02641
02642
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
02655
02656
02657
02658
02659
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
02675
02676
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
02692
02693
02694
02695
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
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 }