52 #if defined(_WIN32) && defined(HAVE_THREADS) && defined(SIMPLE_THREADS)
57 #define WINDOWS_LEAN_AND_MEAN
60 #undef WINDOWS_LEAN_AND_MEAN
69 PStatCollector GraphicsEngine::_wait_pcollector(
"Wait:Thread sync");
71 PStatCollector GraphicsEngine::_app_pcollector(
"App:Show code:General");
72 PStatCollector GraphicsEngine::_render_frame_pcollector(
"App:render_frame");
76 PStatCollector GraphicsEngine::_cull_setup_pcollector(
"Cull:Setup");
81 PStatCollector GraphicsEngine::_flip_begin_pcollector(
"Wait:Flip:Begin");
82 PStatCollector GraphicsEngine::_flip_end_pcollector(
"Wait:Flip:End");
83 PStatCollector GraphicsEngine::_transform_states_pcollector(
"TransformStates");
84 PStatCollector GraphicsEngine::_transform_states_unused_pcollector(
"TransformStates:Unused");
85 PStatCollector GraphicsEngine::_render_states_pcollector(
"RenderStates");
86 PStatCollector GraphicsEngine::_render_states_unused_pcollector(
"RenderStates:Unused");
87 PStatCollector GraphicsEngine::_cyclers_pcollector(
"PipelineCyclers");
88 PStatCollector GraphicsEngine::_dirty_cyclers_pcollector(
"Dirty PipelineCyclers");
92 PStatCollector GraphicsEngine::_sw_sprites_pcollector(
"SW Sprites");
93 PStatCollector GraphicsEngine::_vertex_data_small_pcollector(
"Vertex Data:Small");
94 PStatCollector GraphicsEngine::_vertex_data_independent_pcollector(
"Vertex Data:Independent");
95 PStatCollector GraphicsEngine::_vertex_data_pending_pcollector(
"Vertex Data:Pending");
96 PStatCollector GraphicsEngine::_vertex_data_resident_pcollector(
"Vertex Data:Resident");
97 PStatCollector GraphicsEngine::_vertex_data_compressed_pcollector(
"Vertex Data:Compressed");
98 PStatCollector GraphicsEngine::_vertex_data_unused_disk_pcollector(
"Vertex Data:Disk:Unused");
99 PStatCollector GraphicsEngine::_vertex_data_used_disk_pcollector(
"Vertex Data:Disk:Used");
103 PStatCollector GraphicsEngine::_cnode_volume_pcollector(
"Collision Volumes:CollisionNode");
104 PStatCollector GraphicsEngine::_gnode_volume_pcollector(
"Collision Volumes:GeomNode");
105 PStatCollector GraphicsEngine::_geom_volume_pcollector(
"Collision Volumes:Geom");
106 PStatCollector GraphicsEngine::_node_volume_pcollector(
"Collision Volumes:PandaNode");
107 PStatCollector GraphicsEngine::_volume_pcollector(
"Collision Volumes:CollisionSolid");
108 PStatCollector GraphicsEngine::_test_pcollector(
"Collision Tests:CollisionSolid");
109 PStatCollector GraphicsEngine::_volume_polygon_pcollector(
"Collision Volumes:CollisionPolygon");
110 PStatCollector GraphicsEngine::_test_polygon_pcollector(
"Collision Tests:CollisionPolygon");
111 PStatCollector GraphicsEngine::_volume_plane_pcollector(
"Collision Volumes:CollisionPlane");
112 PStatCollector GraphicsEngine::_test_plane_pcollector(
"Collision Tests:CollisionPlane");
113 PStatCollector GraphicsEngine::_volume_sphere_pcollector(
"Collision Volumes:CollisionSphere");
114 PStatCollector GraphicsEngine::_test_sphere_pcollector(
"Collision Tests:CollisionSphere");
115 PStatCollector GraphicsEngine::_volume_box_pcollector(
"Collision Volumes:CollisionBox");
116 PStatCollector GraphicsEngine::_test_box_pcollector(
"Collision Tests:CollisionBox");
117 PStatCollector GraphicsEngine::_volume_capsule_pcollector(
"Collision Volumes:CollisionCapsule");
118 PStatCollector GraphicsEngine::_test_capsule_pcollector(
"Collision Tests:CollisionCapsule");
119 PStatCollector GraphicsEngine::_volume_inv_sphere_pcollector(
"Collision Volumes:CollisionInvSphere");
120 PStatCollector GraphicsEngine::_test_inv_sphere_pcollector(
"Collision Tests:CollisionInvSphere");
121 PStatCollector GraphicsEngine::_volume_geom_pcollector(
"Collision Volumes:CollisionGeom");
122 PStatCollector GraphicsEngine::_test_geom_pcollector(
"Collision Tests:CollisionGeom");
123 PStatCollector GraphicsEngine::_occlusion_untested_pcollector(
"Occlusion results:Not tested");
124 PStatCollector GraphicsEngine::_occlusion_passed_pcollector(
"Occlusion results:Visible");
125 PStatCollector GraphicsEngine::_occlusion_failed_pcollector(
"Occlusion results:Occluded");
126 PStatCollector GraphicsEngine::_occlusion_tests_pcollector(
"Occlusion tests");
135 INLINE
static bool operator < (
const CullKey &a,
const CullKey &b) {
136 if (a._gsg != b._gsg) {
137 return a._gsg < b._gsg;
139 if (a._camera != b._camera) {
140 return a._camera < b._camera;
142 return a._lens_index < b._lens_index;
154 _lock(
"GraphicsEngine::_lock"),
155 _loaded_textures_lock(
"GraphicsEngine::_loaded_textures_lock")
157 if (_pipeline ==
nullptr) {
161 _windows_sorted =
true;
162 _window_sort_index = 0;
167 <<
"Using threading model " << _threading_model <<
"\n";
169 _auto_flip = auto_flip;
170 _portal_enabled =
false;
171 _flip_state = FS_flip;
173 _singular_warning_last_frame =
false;
174 _singular_warning_this_frame =
false;
184 if (_app_pcollector.is_started()) {
185 _app_pcollector.stop();
200 if (!threading_model.is_single_threaded()) {
201 display_cat.warning()
202 <<
"Threading model " << threading_model
203 <<
" requested but threading is not available. Ignoring.\n";
208 #ifndef THREADED_PIPELINE
209 if (!threading_model.is_single_threaded()) {
210 display_cat.warning()
211 <<
"Threading model " << threading_model
212 <<
" requested but multithreaded render pipelines not enabled in build.\n";
213 if (!allow_nonpipeline_threads) {
214 display_cat.warning()
215 <<
"Ignoring requested threading model.\n";
218 display_cat.warning()
219 <<
"Danger! Creating requested render threads anyway!\n";
221 #endif // THREADED_PIPELINE
223 _threading_model = threading_model;
235 result = _threading_model;
258 const string &name,
int sort,
290 int x_size = 0, y_size = 0;
295 if ((x_size == 0)&&(y_size == 0)) {
296 flags |= GraphicsPipe::BF_size_track_host;
298 if (host !=
nullptr) {
306 if (host ==
nullptr) {
307 if (gsg !=
nullptr) {
316 if ((host->
get_gsg()==
nullptr)||
318 (!host->
get_gsg()->is_valid())||
319 (host->
get_gsg()->needs_reset())) {
322 if ((host->
get_gsg()==
nullptr)||
324 (!host->
get_gsg()->is_valid())||
325 (host->
get_gsg()->needs_reset())) {
335 nassertr(pipe !=
nullptr,
nullptr);
336 if (gsg !=
nullptr) {
337 nassertr(pipe == gsg->
get_pipe(),
nullptr);
342 if ((flags & GraphicsPipe::BF_require_callback_window)!=0) {
344 if (this_gsg ==
nullptr) {
347 this_gsg = pipe->make_callback_gsg(
this);
349 if (this_gsg !=
nullptr) {
351 window->_sort = sort;
352 do_add_window(window);
353 do_add_gsg(window->
get_gsg(), pipe);
354 display_cat.info() <<
"Created output of type CallbackGraphicsWindow\n";
365 bool can_use_parasite =
false;
366 if ((host !=
nullptr)&&
367 ((flags&GraphicsPipe::BF_require_window)==0)&&
368 ((flags&GraphicsPipe::BF_require_callback_window)==0)&&
369 ((flags&GraphicsPipe::BF_refuse_parasite)==0)&&
370 ((flags&GraphicsPipe::BF_can_bind_color)==0)&&
371 ((flags&GraphicsPipe::BF_can_bind_every)==0)&&
372 ((flags&GraphicsPipe::BF_rtt_cumulative)==0)&&
373 ((flags&GraphicsPipe::BF_can_bind_layered)==0)) {
374 if ((flags&GraphicsPipe::BF_fb_props_optional) ||
376 can_use_parasite =
true;
385 if ((prefer_parasite_buffer) &&
386 (can_use_parasite) &&
387 (x_size <= host->get_x_size())&&
388 (y_size <= host->get_y_size())&&
391 buffer->_sort = sort;
392 do_add_window(buffer);
393 do_add_gsg(host->
get_gsg(), pipe);
394 display_cat.info() <<
"Created output of type ParasiteBuffer\n";
401 if (force_parasite_buffer && can_use_parasite) {
403 buffer->_sort = sort;
404 do_add_window(buffer);
405 do_add_gsg(host->
get_gsg(), pipe);
406 display_cat.info() <<
"Created output of type ParasiteBuffer\n";
412 for (
int retry=0; retry<10; retry++) {
413 bool precertify =
false;
415 pipe->make_output(name, fb_prop, win_prop, flags,
this, gsg, host, retry, precertify);
416 if (window !=
nullptr) {
417 window->_sort = sort;
418 if (precertify && gsg !=
nullptr && window->
get_gsg() == gsg) {
419 do_add_window(window);
421 <<
"Created output of type " << window->get_type() <<
"\n";
424 do_add_window(window);
426 if (window->is_valid()) {
428 <<
"Created output of type " << window->get_type() <<
"\n";
430 if (window->get_fb_properties().subsumes(fb_prop)) {
433 if (flags & GraphicsPipe::BF_fb_props_optional) {
434 display_cat.warning()
435 <<
"FrameBufferProperties available less than requested.\n";
436 display_cat.warning(
false)
437 <<
" requested: " << fb_prop <<
"\n"
438 <<
" got: " << window->get_fb_properties() <<
"\n";
442 <<
"Could not get requested FrameBufferProperties; abandoning window.\n";
443 display_cat.error(
false)
444 <<
" requested: " << fb_prop <<
"\n"
445 <<
" got: " << window->get_fb_properties() <<
"\n";
449 << window->get_type() <<
" wouldn't open; abandoning.\n";
450 display_cat.debug(
false)
451 <<
" requested: " << fb_prop <<
"\n";
462 if (can_use_parasite) {
464 buffer->_sort = sort;
465 do_add_window(buffer);
466 do_add_gsg(host->
get_gsg(), pipe);
467 display_cat.info() <<
"Created output of type ParasiteBuffer\n";
490 nassertr(window !=
nullptr,
false);
491 nassertr(
this == window->
get_engine(),
false);
493 window->_sort = sort;
494 do_add_window(window);
497 <<
"Added output of type " << window->get_type() <<
"\n";
521 nassertr(window !=
nullptr,
false);
529 if (!_windows_sorted) {
532 count = _windows.erase(ptwin);
537 MutexHolder new_windows_holder(_new_windows_lock, current_thread);
538 size_t old_size = _new_windows.size();
539 _new_windows.erase(std::remove(_new_windows.begin(), _new_windows.end(), ptwin), _new_windows.end());
540 if (count == 0 && _new_windows.size() < old_size) {
550 do_remove_window(window, current_thread);
553 if (gsg !=
nullptr) {
555 if (pgo !=
nullptr) {
557 bool any_common =
false;
560 Windows::iterator wi;
561 for (wi = _windows.
begin(); wi != _windows.
end() && !any_common; ++wi) {
563 if (gsg2 !=
nullptr &&
580 nassertr(count == 1,
true);
599 old_windows.
swap(_windows);
601 nassertv(win !=
nullptr);
602 do_remove_window(win, current_thread);
604 if (gsg !=
nullptr) {
610 MutexHolder new_windows_holder(_new_windows_lock, current_thread);
612 nassertv(win !=
nullptr);
613 do_remove_window(win, current_thread);
615 if (gsg !=
nullptr) {
619 _new_windows.clear();
622 _app.do_close(
this, current_thread);
623 _app.do_pending(
this, current_thread);
624 terminate_threads(current_thread);
641 PStatClient::get_global_pstats()->
disconnect();
644 #if defined(_WIN32) && defined(HAVE_THREADS) && defined(SIMPLE_THREADS)
647 WinInputDeviceManager::stop_thread();
661 Windows::iterator wi;
662 for (wi = _windows.
begin(); wi != _windows.
end(); ++wi) {
675 return _windows.
empty();
683 return _windows.
size();
691 nassertr(n >= 0 && n < (
int)_windows.
size(),
nullptr);
693 if (!_windows_sorted) {
715 _render_frame_pcollector.start();
716 if (_app_pcollector.is_started()) {
717 _app_pcollector.stop();
730 if (display_cat.is_spam()) {
732 <<
"render_frame() - frame " << global_clock->
get_frame_count() <<
"\n";
738 if (!_windows_sorted) {
742 if (sync_flip && _flip_state != FS_flip) {
743 do_flip_frame(current_thread);
749 Windows::iterator wi;
750 for (wi = _windows.
begin(); wi != _windows.
end(); ++wi) {
752 nassertv(win !=
nullptr);
754 do_remove_window(win, current_thread);
764 int num_drs = win->get_num_active_display_regions();
765 for (
int i = 0; i < num_drs; ++i) {
773 scene = camera_np.
get_top(current_thread);
776 scene.get_bounds(current_thread);
783 _windows.
swap(new_windows);
789 LoadedTextures::iterator lti;
790 for (lti = _loaded_textures.begin(); lti != _loaded_textures.end(); ++lti) {
791 LoadedTexture < = (*lti);
792 if (lt._tex->get_image_modified() == lt._image_modified) {
793 lt._tex->texture_uploaded();
796 _loaded_textures.clear();
801 _app.do_frame(
this, current_thread);
806 PStatTimer timer(_wait_pcollector, current_thread);
807 Threads::const_iterator ti;
808 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
809 RenderThread *thread = (*ti).second;
810 thread->_cv_mutex.acquire();
812 while (thread->_thread_state != TS_wait) {
813 thread->_cv_done.wait();
818 #if defined(THREADED_PIPELINE) && defined(DO_PSTATS)
819 _cyclers_pcollector.set_level(_pipeline->get_num_cyclers());
820 _dirty_cyclers_pcollector.set_level(_pipeline->get_num_dirty_cyclers());
824 _pipeline->iterate_all_cycler_types(pstats_count_cycler_type,
this);
825 _pipeline->iterate_dirty_cycler_types(pstats_count_dirty_cycler_type,
this);
827 #endif // DEBUG_THREADS
829 #endif // THREADED_PIPELINE && DO_PSTATS
834 TransformState::flush_level();
838 #ifdef THREADED_PIPELINE
840 PStatTimer timer(_cycle_pcollector, current_thread);
843 #endif // THREADED_PIPELINE
845 global_clock->
tick(current_thread);
847 throw_event(
"clock_error");
851 PStatClient::main_tick();
854 CullTraverser::_nodes_pcollector.clear_level();
855 CullTraverser::_geom_nodes_pcollector.clear_level();
856 CullTraverser::_geoms_pcollector.clear_level();
857 GeomCacheManager::_geom_cache_active_pcollector.clear_level();
858 GeomCacheManager::_geom_cache_record_pcollector.clear_level();
859 GeomCacheManager::_geom_cache_erase_pcollector.clear_level();
860 GeomCacheManager::_geom_cache_evict_pcollector.clear_level();
862 GraphicsStateGuardian::init_frame_pstats();
864 _transform_states_pcollector.set_level(TransformState::get_num_states());
866 if (pstats_unused_states) {
867 _transform_states_unused_pcollector.set_level(TransformState::get_num_unused_states());
871 _sw_sprites_pcollector.clear_level();
873 _cnode_volume_pcollector.clear_level();
874 _gnode_volume_pcollector.clear_level();
875 _geom_volume_pcollector.clear_level();
876 _node_volume_pcollector.clear_level();
877 _volume_pcollector.clear_level();
878 _test_pcollector.clear_level();
879 _volume_polygon_pcollector.clear_level();
880 _test_polygon_pcollector.clear_level();
881 _volume_plane_pcollector.clear_level();
882 _test_plane_pcollector.clear_level();
883 _volume_sphere_pcollector.clear_level();
884 _test_sphere_pcollector.clear_level();
885 _volume_box_pcollector.clear_level();
886 _test_box_pcollector.clear_level();
887 _volume_capsule_pcollector.clear_level();
888 _test_capsule_pcollector.clear_level();
889 _volume_inv_sphere_pcollector.clear_level();
890 _test_inv_sphere_pcollector.clear_level();
891 _volume_geom_pcollector.clear_level();
892 _test_geom_pcollector.clear_level();
893 _occlusion_untested_pcollector.clear_level();
894 _occlusion_passed_pcollector.clear_level();
895 _occlusion_failed_pcollector.clear_level();
896 _occlusion_tests_pcollector.clear_level();
909 _vertex_data_small_pcollector.set_level(small_buf);
910 _vertex_data_independent_pcollector.set_level(independent);
911 _vertex_data_pending_pcollector.set_level(pending);
912 _vertex_data_resident_pcollector.set_level(resident);
913 _vertex_data_compressed_pcollector.set_level(compressed);
914 _vertex_data_unused_disk_pcollector.set_level(total_disk - used_disk);
915 _vertex_data_used_disk_pcollector.set_level(used_disk);
923 Threads::const_iterator ti;
924 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
925 RenderThread *thread = (*ti).second;
926 if (thread->_thread_state == TS_wait) {
927 thread->_thread_state = TS_do_frame;
928 thread->_cv_start.notify();
930 thread->_cv_mutex.release();
935 _flip_state = _auto_flip ? FS_flip : FS_draw;
940 if (yield_timeslice) {
943 PStatTimer timer(_yield_pcollector, current_thread);
946 PStatTimer timer(_yield_pcollector, current_thread);
952 _app_pcollector.start();
953 _render_frame_pcollector.stop();
972 MutexHolder new_windows_holder(_new_windows_lock, current_thread);
973 if (_new_windows.empty()) {
977 for (
auto it = _new_windows.begin(); it != _new_windows.end(); ++it) {
980 WindowRenderer *cull =
983 WindowRenderer *draw =
988 cull->add_window(cull->_cull, window);
989 draw->add_window(draw->_draw, window);
991 cull->add_window(cull->_cdraw, window);
1003 switch (window->
get_pipe()->get_preferred_window_thread()) {
1004 case GraphicsPipe::PWT_app:
1005 _app.add_window(_app._window, window);
1008 case GraphicsPipe::PWT_draw:
1009 draw->add_window(draw->_window, window);
1017 new_windows.swap(_new_windows);
1020 do_resort_windows();
1023 for (
int i = 0; i < 2; ++i) {
1024 _app.do_windows(
this, current_thread);
1025 _app.do_pending(
this, current_thread);
1027 PStatTimer timer(_wait_pcollector, current_thread);
1028 Threads::const_iterator ti;
1029 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
1030 RenderThread *thread = (*ti).second;
1031 thread->_cv_mutex.acquire();
1033 while (thread->_thread_state != TS_wait) {
1034 thread->_cv_done.wait();
1037 thread->_thread_state = TS_do_windows;
1038 thread->_cv_start.notify();
1039 thread->_cv_mutex.release();
1044 for (
auto it = new_windows.begin(); it != new_windows.end(); ++it) {
1065 if (_flip_state == FS_draw) {
1066 do_sync_frame(current_thread);
1086 if (_flip_state == FS_draw) {
1087 do_ready_flip(current_thread);
1101 if (_flip_state != FS_flip) {
1102 do_flip_frame(current_thread);
1132 if (draw_name.empty()) {
1139 WindowRenderer *wr = get_window_renderer(draw_name, 0);
1140 RenderThread *thread = (RenderThread *)wr;
1143 while (thread->_thread_state != TS_wait) {
1144 thread->_cv_done.wait();
1149 int draw_pipeline_stage = thread->get_pipeline_stage();
1150 thread->set_pipeline_stage(pipeline_stage);
1154 thread->_texture = tex;
1155 thread->_thread_state = TS_do_extract;
1156 thread->_cv_start.notify();
1157 thread->_cv_mutex.release();
1158 thread->_cv_mutex.acquire();
1161 while (thread->_thread_state != TS_wait) {
1162 thread->_cv_done.wait();
1165 thread->set_pipeline_stage(draw_pipeline_stage);
1166 thread->_gsg =
nullptr;
1167 thread->_texture =
nullptr;
1168 return thread->_result;
1187 const Shader *shader = sattr->get_shader();
1188 nassertv(shader !=
nullptr);
1189 nassertv(gsg !=
nullptr);
1193 CPT(
RenderState) state = RenderState::make(sattr);
1196 if (draw_name.empty()) {
1201 gsg->pop_group_marker();
1206 WindowRenderer *wr = get_window_renderer(draw_name, 0);
1207 RenderThread *thread = (RenderThread *)wr;
1210 while (thread->_thread_state != TS_wait) {
1211 thread->_cv_done.wait();
1216 int draw_pipeline_stage = thread->get_pipeline_stage();
1217 thread->set_pipeline_stage(pipeline_stage);
1221 thread->_state = state.p();
1222 thread->_work_groups = work_groups;
1223 thread->_thread_state = TS_do_compute;
1224 thread->_cv_start.notify();
1225 thread->_cv_mutex.release();
1226 thread->_cv_mutex.acquire();
1229 while (thread->_thread_state != TS_wait) {
1230 thread->_cv_done.wait();
1233 thread->set_pipeline_stage(draw_pipeline_stage);
1234 thread->_gsg =
nullptr;
1235 thread->_state =
nullptr;
1244 if (_global_ptr ==
nullptr) {
1265 _loaded_textures.push_back(LoadedTexture());
1266 LoadedTexture < = _loaded_textures.back();
1283 WindowRenderer *wr = get_window_renderer(draw_name, 0);
1284 RenderThread *thread = (RenderThread *)wr;
1287 while (thread->_thread_state != TS_wait) {
1288 thread->_cv_done.wait();
1292 thread->_region = region;
1293 thread->_thread_state = TS_do_screenshot;
1294 thread->_cv_start.notify();
1295 thread->_cv_mutex.release();
1296 thread->_cv_mutex.acquire();
1299 while (thread->_thread_state != TS_wait) {
1300 thread->_cv_done.wait();
1303 PT(
Texture) tex = std::move(thread->_texture);
1304 thread->_region =
nullptr;
1305 thread->_texture =
nullptr;
1323 if (view_frustum_cull) {
1331 if (bv !=
nullptr && !bv->is_infinite() &&
1332 bv->as_geometric_bounding_volume() !=
nullptr) {
1335 local_frustum = bv->make_copy()->as_geometric_bounding_volume();
1336 nassertv(!local_frustum.is_null());
1341 local_frustum->xform(cull_center_transform->get_mat());
1356 bool GraphicsEngine::
1357 scene_root_func(
const PandaNode *node) {
1358 return _global_ptr->is_scene_root(node);
1365 bool GraphicsEngine::
1369 Windows::const_iterator wi;
1370 for (wi = _windows.
begin(); wi != _windows.
end(); ++wi) {
1373 int num_display_regions = win->get_num_active_display_regions();
1374 for (
int i = 0; i < num_display_regions; i++) {
1376 if (dr !=
nullptr) {
1383 DCAST_INTO_R(camera_node, camera.
node(),
false);
1393 scene_root = camera.
get_top(current_thread);
1396 if (scene_root.
node() == node) {
1413 void GraphicsEngine::
1416 window->_sort = sort;
1417 _windows_sorted =
false;
1426 void GraphicsEngine::
1428 Thread *current_thread) {
1429 PStatTimer timer(_cull_pcollector, current_thread);
1431 size_t wlist_size = wlist.
size();
1432 for (
size_t wi = 0; wi < wlist_size; ++wi) {
1437 PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
1441 PStatTimer timer(GraphicsEngine::_flip_end_pcollector, current_thread);
1446 if (win->
begin_frame(GraphicsOutput::FM_render, current_thread)) {
1450 gsg->push_group_marker(
"Clear");
1451 win->
clear(current_thread);
1452 gsg->pop_group_marker();
1455 int num_display_regions = win->get_num_active_display_regions();
1456 for (
int i = 0; i < num_display_regions; i++) {
1458 if (dr !=
nullptr) {
1459 cull_and_draw_together(win, dr, current_thread);
1462 win->
end_frame(GraphicsOutput::FM_render, current_thread);
1467 PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
1471 PStatTimer timer(GraphicsEngine::_flip_end_pcollector, current_thread);
1484 void GraphicsEngine::
1486 Thread *current_thread) {
1488 nassertv(gsg !=
nullptr);
1499 if (dr_reader.is_any_clear_active()) {
1504 scene_setup = setup_scene(gsg, &dr_reader);
1507 if (scene_setup ==
nullptr) {
1513 }
else if (!gsg->
set_scene(scene_setup)) {
1516 << gsg->get_type() <<
" cannot render scene with specified lens.\n";
1522 if (cbobj !=
nullptr) {
1531 dr->do_cull(&cull_handler, scene_setup, gsg, current_thread);
1538 gsg->pop_group_marker();
1546 void GraphicsEngine::
1548 PStatTimer timer(_cull_pcollector, current_thread);
1550 _singular_warning_last_frame = _singular_warning_this_frame;
1551 _singular_warning_this_frame =
false;
1556 AlreadyCulled already_culled;
1558 size_t wlist_size = wlist.
size();
1559 for (
size_t wi = 0; wi < wlist_size; ++wi) {
1564 int num_display_regions = win->get_num_active_display_regions();
1565 for (
int i = 0; i < num_display_regions; ++i) {
1567 if (dr !=
nullptr) {
1572 PStatTimer timer(_cull_setup_pcollector, current_thread);
1574 scene_setup = setup_scene(gsg, &dr_reader);
1575 if (scene_setup ==
nullptr) {
1580 key._camera = dr_reader.get_camera();
1581 key._lens_index = dr_reader.get_lens_index();
1584 AlreadyCulled::iterator aci = already_culled.insert(AlreadyCulled::value_type(std::move(key),
nullptr)).first;
1585 if ((*aci).second ==
nullptr) {
1589 if (cull_result !=
nullptr) {
1590 cull_result = cull_result->make_next();
1596 cull_to_bins(win, gsg, dr, scene_setup, cull_result, current_thread);
1610 dr->
set_cull_result(std::move(cull_result), MOVE(scene_setup), current_thread);
1620 void GraphicsEngine::
1627 if (cbobj !=
nullptr) {
1636 dr->do_cull(&cull_handler, scene_setup, gsg, current_thread);
1639 PStatTimer timer(_cull_sort_pcollector, current_thread);
1640 cull_result->
finish_cull(scene_setup, current_thread);
1648 void GraphicsEngine::
1652 size_t wlist_size = wlist.
size();
1653 for (
size_t wi = 0; wi < wlist_size; ++wi) {
1664 PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
1668 PStatTimer timer(GraphicsEngine::_flip_end_pcollector, current_thread);
1673 if (win->
begin_frame(GraphicsOutput::FM_render, current_thread)) {
1680 win->
get_gsg()->push_group_marker(
"Clear");
1681 win->
clear(current_thread);
1682 win->
get_gsg()->pop_group_marker();
1685 if (display_cat.is_spam()) {
1687 <<
"Drawing window " << win->
get_name() <<
"\n";
1689 int num_display_regions = win->get_num_active_display_regions();
1690 for (
int i = 0; i < num_display_regions; ++i) {
1692 if (dr !=
nullptr) {
1693 do_draw(win, gsg, dr, current_thread);
1697 win->
end_frame(GraphicsOutput::FM_render, current_thread);
1703 gsg->issue_timer_query(GraphicsStateGuardian::_command_latency_pcollector.get_index());
1711 PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
1715 PStatGPUTimer timer(gsg, GraphicsEngine::_flip_end_pcollector, current_thread);
1722 if (display_cat.is_spam()) {
1724 <<
"Not drawing window " << win->
get_name() <<
"\n";
1729 if (display_cat.is_spam()) {
1731 <<
"Window " << win->
get_name() <<
" is inactive\n";
1741 void GraphicsEngine::
1743 Windows::const_iterator wi;
1744 for (wi = wlist.
begin(); wi != wlist.
end(); ++wi) {
1746 if (win->
begin_frame(GraphicsOutput::FM_refresh, current_thread)) {
1747 win->
end_frame(GraphicsOutput::FM_refresh, current_thread);
1757 void GraphicsEngine::
1762 for (
size_t i = 0; i < wlist.
size(); ++i) {
1763 wlist[i]->process_events();
1772 void GraphicsEngine::
1774 size_t num_windows = wlist.
size();
1776 size_t warray_count = 0;
1780 for (i = 0; i < num_windows; ++i) {
1783 nassertv(warray_count < num_windows);
1784 warray[warray_count] = win;
1787 PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
1792 for (i = 0; i < warray_count; ++i) {
1794 PStatTimer timer(GraphicsEngine::_flip_end_pcollector, current_thread);
1804 void GraphicsEngine::
1806 Windows::const_iterator wi;
1807 for (wi = wlist.
begin(); wi != wlist.
end(); ++wi) {
1810 PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
1820 void GraphicsEngine::
1821 do_sync_frame(
Thread *current_thread) {
1825 PStatTimer timer(_sync_pcollector, current_thread);
1827 nassertv(_flip_state == FS_draw);
1831 Threads::const_iterator ti;
1832 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
1833 RenderThread *thread = (*ti).second;
1834 thread->_cv_mutex.acquire();
1835 thread->_cv_mutex.release();
1838 _flip_state = FS_sync;
1845 void GraphicsEngine::
1846 do_ready_flip(
Thread *current_thread) {
1850 PStatTimer timer(_sync_pcollector, current_thread);
1852 nassertv(_flip_state == FS_draw);
1856 Threads::const_iterator ti;
1857 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
1858 RenderThread *thread = (*ti).second;
1859 thread->_cv_mutex.acquire();
1860 thread->_cv_mutex.release();
1862 _app.do_ready_flip(
this,current_thread);
1863 _flip_state = FS_sync;
1870 void GraphicsEngine::
1871 do_flip_frame(
Thread *current_thread) {
1875 PStatTimer timer(_flip_pcollector, current_thread);
1877 nassertv(_flip_state == FS_draw || _flip_state == FS_sync);
1883 PStatTimer timer(_wait_pcollector, current_thread);
1884 Threads::const_iterator ti;
1885 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
1886 RenderThread *thread = (*ti).second;
1887 thread->_cv_mutex.acquire();
1889 while (thread->_thread_state != TS_wait) {
1890 thread->_cv_done.wait();
1896 _app.do_flip(
this, current_thread);
1899 Threads::const_iterator ti;
1900 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
1901 RenderThread *thread = (*ti).second;
1902 nassertv(thread->_thread_state == TS_wait);
1903 thread->_thread_state = TS_do_flip;
1904 thread->_cv_start.notify();
1905 thread->_cv_mutex.release();
1909 _flip_state = FS_flip;
1919 Thread *current_thread = dr->get_current_thread();
1920 PStatTimer timer(_cull_setup_pcollector, current_thread);
1925 nassertr(window !=
nullptr,
nullptr);
1934 DCAST_INTO_R(camera_node, camera.
node(),
nullptr);
1954 scene_root = camera.
get_top(current_thread);
1970 if (camera_transform->is_invalid()) {
1972 if (!_singular_warning_last_frame) {
1973 display_cat.warning()
1974 <<
"Scene " << scene_root <<
" has net scale ("
1976 _singular_warning_this_frame =
true;
1981 if (world_transform->is_invalid()) {
1983 if (!_singular_warning_last_frame) {
1984 display_cat.warning()
1985 <<
"Camera " << camera <<
" has net scale ("
1988 _singular_warning_this_frame =
true;
1992 CPT(
RenderState) initial_state = camera_node->get_initial_state();
2002 initial_state = initial_state->compose(get_invert_polygon_state());
2011 scene_setup->set_initial_state(initial_state);
2018 CPT(
TransformState) cs_world_transform = cs_transform->compose(world_transform);
2027 void GraphicsEngine::
2038 cull_result = cdata->_cull_result;
2039 scene_setup = cdata->_scene_setup;
2048 if (dr_reader.is_any_clear_active()) {
2050 gsg->
clear(dr_reader.get_object());
2053 cbobj = dr_reader.get_draw_callback();
2056 if (cbobj !=
nullptr) {
2061 static CPT(
RenderState) state = RenderState::make(
2062 DepthTestAttrib::make(DepthTestAttrib::M_none));
2072 }
else if (cull_result ==
nullptr || scene_setup ==
nullptr) {
2082 }
else if (!gsg->
set_scene(scene_setup)) {
2085 << gsg->get_type() <<
" cannot render scene with specified lens.\n";
2089 cull_result->
draw(current_thread);
2094 gsg->pop_group_marker();
2102 void GraphicsEngine::
2104 nassertv(window !=
nullptr);
2111 window->_internal_sort_index = _window_sort_index;
2112 ++_window_sort_index;
2114 if (display_cat.is_debug()) {
2116 <<
"Created " << window->get_type() <<
" " << (
void *)window <<
"\n";
2120 _new_windows.push_back(window);
2128 void GraphicsEngine::
2130 nassertv(gsg !=
nullptr);
2134 gsg->_threading_model = _threading_model;
2135 if (!_default_loader.is_null()) {
2139 auto_adjust_capabilities(gsg);
2141 WindowRenderer *draw =
2153 void GraphicsEngine::
2155 nassertv(window !=
nullptr);
2159 if (!_windows_sorted) {
2160 do_resort_windows();
2164 _app.remove_window(window);
2165 Threads::const_iterator ti;
2166 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
2167 RenderThread *thread = (*ti).second;
2168 thread->remove_window(window);
2173 _app.do_pending(
this, current_thread);
2175 if (display_cat.is_debug()) {
2177 <<
"Removed " << window->get_type() <<
" " << (
void *)window <<
"\n";
2185 void GraphicsEngine::
2186 do_resort_windows() {
2187 _windows_sorted =
true;
2189 _app.resort_windows();
2190 Threads::const_iterator ti;
2191 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
2192 RenderThread *thread = (*ti).second;
2193 thread->resort_windows();
2219 void GraphicsEngine::
2241 if (textures_auto_power_2 && (textures_power_2 == ATS_none)) {
2243 <<
"Invalid panda config file: if you set the config-variable\n"
2244 <<
"textures_auto_power_2 to true, you must set the config-variable"
2245 <<
"textures_power_2 to 'up' or 'down'.\n";
2246 textures_power_2 = ATS_down;
2263 <<
"The 'textures_power_2' configuration is set to 'none', meaning \n"
2264 <<
"that non-power-of-two texture support is required, but the video \n"
2265 <<
"driver I'm trying to use does not support non-power-of-two textures.\n";
2267 if (textures_power_2 != ATS_none) {
2269 <<
"The 'none' did not come from the config file. In other words,\n"
2270 <<
"the variable 'textures_power_2' was altered procedurally.\n";
2272 if (textures_auto_power_2) {
2274 <<
"It is possible that it was set by panda's automatic mechanisms,\n"
2275 <<
"which are currently enabled, because 'textures_auto_power_2' is\n"
2276 <<
"true. Panda's automatic mechanisms assume that if one\n"
2277 <<
"window supports non-power-of-two textures, then they all will.\n"
2278 <<
"This assumption works for most games, but not all.\n"
2279 <<
"In particular, it can fail if the game creates multiple windows\n"
2280 <<
"on multiple displays with different video cards.\n";
2289 void GraphicsEngine::
2290 terminate_threads(
Thread *current_thread) {
2295 PStatTimer timer(_wait_pcollector, current_thread);
2299 Threads::const_iterator ti;
2300 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
2301 RenderThread *thread = (*ti).second;
2302 thread->_cv_mutex.acquire();
2306 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
2307 RenderThread *thread = (*ti).second;
2308 thread->_thread_state = TS_terminate;
2309 thread->_cv_start.notify();
2310 thread->_cv_mutex.release();
2314 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
2315 RenderThread *thread = (*ti).second;
2328 void GraphicsEngine::
2329 pstats_count_cycler_type(
TypeHandle type,
int count,
void *data) {
2331 CyclerTypeCounters::iterator ci =
self->_all_cycler_types.find(type);
2332 if (ci == self->_all_cycler_types.end()) {
2334 ci =
self->_all_cycler_types.insert(CyclerTypeCounters::value_type(type, collector)).first;
2336 (*ci).second.set_level(count);
2345 void GraphicsEngine::
2346 pstats_count_dirty_cycler_type(
TypeHandle type,
int count,
void *data) {
2348 CyclerTypeCounters::iterator ci =
self->_dirty_cycler_types.find(type);
2349 if (ci == self->_dirty_cycler_types.end()) {
2351 ci =
self->_dirty_cycler_types.insert(CyclerTypeCounters::value_type(type, collector)).first;
2353 (*ci).second.set_level(count);
2363 get_invert_polygon_state() {
2367 if (state ==
nullptr) {
2368 state = RenderState::make(CullFaceAttrib::make_reverse());
2382 GraphicsEngine::WindowRenderer *GraphicsEngine::
2383 get_window_renderer(
const string &name,
int pipeline_stage) {
2390 Threads::iterator ti = _threads.find(name);
2391 if (ti != _threads.end()) {
2392 return (*ti).second.p();
2395 PT(RenderThread) thread =
new RenderThread(name,
this);
2396 thread->set_min_pipeline_stage(pipeline_stage);
2399 bool started = thread->start(TP_normal,
true);
2400 nassertr(started, thread.p());
2401 _threads[name] = thread;
2403 nassertr(thread->get_pipeline_stage() < _pipeline->
get_num_stages(), thread.p());
2411 GraphicsEngine::WindowRenderer::
2412 WindowRenderer(
const string &name) :
2413 _wl_lock(string(
"GraphicsEngine::WindowRenderer::_wl_lock ") + name)
2420 void GraphicsEngine::WindowRenderer::
2430 void GraphicsEngine::WindowRenderer::
2433 wlist.insert(window);
2441 void GraphicsEngine::WindowRenderer::
2443 nassertv(window !=
nullptr);
2448 _cdraw.erase(ptwin);
2451 Windows::iterator wi;
2453 wi = _window.find(ptwin);
2454 if (wi != _window.end()) {
2464 if (ptwin->is_valid()) {
2465 _pending_close.push_back(ptwin);
2475 void GraphicsEngine::WindowRenderer::
2484 if (display_cat.is_debug()) {
2486 <<
"Windows resorted:";
2487 Windows::const_iterator wi;
2488 for (wi = _window.begin(); wi != _window.end(); ++wi) {
2490 display_cat.debug(
false)
2493 display_cat.debug(
false)
2496 for (wi = _draw.begin(); wi != _draw.end(); ++wi) {
2498 display_cat.debug(
false)
2501 display_cat.debug(
false)
2511 void GraphicsEngine::WindowRenderer::
2513 PStatTimer timer(engine->_do_frame_pcollector, current_thread);
2516 engine->cull_to_bins(_cull, current_thread);
2517 engine->cull_and_draw_together(_cdraw, current_thread);
2518 engine->draw_bins(_draw, current_thread);
2519 engine->process_events(_window, current_thread);
2523 if (any_done_gsgs()) {
2526 for (gi = _gsgs.begin(); gi != _gsgs.end(); ++gi) {
2531 engine->close_gsg(pipe, gsg);
2534 new_gsgs.insert(gsg);
2538 _gsgs.swap(new_gsgs);
2548 void GraphicsEngine::WindowRenderer::
2552 engine->process_events(_window, current_thread);
2554 engine->make_contexts(_cdraw, current_thread);
2555 engine->make_contexts(_draw, current_thread);
2561 void GraphicsEngine::WindowRenderer::
2564 engine->flip_windows(_cdraw, current_thread);
2565 engine->flip_windows(_draw, current_thread);
2571 void GraphicsEngine::WindowRenderer::
2574 engine->ready_flip_windows(_cdraw, current_thread);
2575 engine->ready_flip_windows(_draw, current_thread);
2582 void GraphicsEngine::WindowRenderer::
2585 Windows::iterator wi;
2586 for (wi = _window.begin(); wi != _window.end(); ++wi) {
2594 for (gi = _gsgs.begin(); gi != _gsgs.end(); ++gi) {
2599 engine->close_gsg(pipe, gsg);
2602 new_gsgs.insert(gsg);
2606 _gsgs.swap(new_gsgs);
2613 void GraphicsEngine::WindowRenderer::
2617 if (!_pending_close.empty()) {
2618 if (display_cat.is_debug()) {
2620 <<
"_pending_close.size() = " << _pending_close.size() <<
"\n";
2626 Windows::iterator wi;
2627 Windows pending_close;
2628 _pending_close.swap(pending_close);
2629 for (wi = pending_close.begin(); wi != pending_close.end(); ++wi) {
2641 bool GraphicsEngine::WindowRenderer::
2642 any_done_gsgs()
const {
2643 GSGs::const_iterator gi;
2644 for (gi = _gsgs.begin(); gi != _gsgs.end(); ++gi) {
2645 if ((*gi)->get_ref_count() == 1) {
2656 GraphicsEngine::RenderThread::
2659 WindowRenderer(name),
2661 _cv_mutex(string(
"GraphicsEngine::RenderThread ") + name),
2662 _cv_start(_cv_mutex),
2665 _thread_state = TS_wait;
2672 void GraphicsEngine::RenderThread::
2678 nassertv(_cv_mutex.debug_is_locked());
2680 switch (_thread_state) {
2685 do_pending(_engine, current_thread);
2686 do_frame(_engine, current_thread);
2690 do_flip(_engine, current_thread);
2694 do_pending(_engine, current_thread);
2698 do_windows(_engine, current_thread);
2699 do_pending(_engine, current_thread);
2703 nassertd(_gsg !=
nullptr && _state !=
nullptr) break;
2706 _state->get_attrib(sattr);
2707 _gsg->push_group_marker(std::string(
"Compute ") + sattr->get_shader()->get_filename(Shader::ST_compute).get_basename());
2708 _gsg->set_state_and_transform(_state, TransformState::make_identity());
2709 _gsg->dispatch_compute(_work_groups[0], _work_groups[1], _work_groups[2]);
2710 _gsg->pop_group_marker();
2715 nassertd(_gsg !=
nullptr && _texture !=
nullptr) break;
2716 _result = _gsg->extract_texture_data(_texture);
2719 case TS_do_screenshot:
2720 nassertd(_region !=
nullptr) break;
2721 _texture = _region->get_screenshot();
2725 do_pending(_engine, current_thread);
2726 do_close(_engine, current_thread);
2727 _thread_state = TS_done;
2737 _thread_state = TS_wait;
2741 PStatTimer timer(_wait_pcollector, current_thread);