52#if defined(_WIN32) && defined(HAVE_THREADS) && defined(SIMPLE_THREADS)
57 #define WINDOWS_LEAN_AND_MEAN
60 #undef WINDOWS_LEAN_AND_MEAN
69PStatCollector GraphicsEngine::_wait_pcollector(
"Wait:Thread sync");
71PStatCollector GraphicsEngine::_app_pcollector(
"App:Show code:General");
72PStatCollector GraphicsEngine::_render_frame_pcollector(
"App:render_frame");
76PStatCollector GraphicsEngine::_cull_setup_pcollector(
"Cull:Setup");
81PStatCollector GraphicsEngine::_flip_begin_pcollector(
"Wait:Flip:Begin");
82PStatCollector GraphicsEngine::_flip_end_pcollector(
"Wait:Flip:End");
83PStatCollector GraphicsEngine::_transform_states_pcollector(
"TransformStates");
84PStatCollector GraphicsEngine::_transform_states_unused_pcollector(
"TransformStates:Unused");
85PStatCollector GraphicsEngine::_render_states_pcollector(
"RenderStates");
86PStatCollector GraphicsEngine::_render_states_unused_pcollector(
"RenderStates:Unused");
87PStatCollector GraphicsEngine::_cyclers_pcollector(
"PipelineCyclers");
88PStatCollector GraphicsEngine::_dirty_cyclers_pcollector(
"Dirty PipelineCyclers");
92PStatCollector GraphicsEngine::_sw_sprites_pcollector(
"SW Sprites");
93PStatCollector GraphicsEngine::_vertex_data_small_pcollector(
"Vertex Data:Small");
94PStatCollector GraphicsEngine::_vertex_data_independent_pcollector(
"Vertex Data:Independent");
95PStatCollector GraphicsEngine::_vertex_data_pending_pcollector(
"Vertex Data:Pending");
96PStatCollector GraphicsEngine::_vertex_data_resident_pcollector(
"Vertex Data:Resident");
97PStatCollector GraphicsEngine::_vertex_data_compressed_pcollector(
"Vertex Data:Compressed");
98PStatCollector GraphicsEngine::_vertex_data_unused_disk_pcollector(
"Vertex Data:Disk:Unused");
99PStatCollector GraphicsEngine::_vertex_data_used_disk_pcollector(
"Vertex Data:Disk:Used");
103PStatCollector GraphicsEngine::_cnode_volume_pcollector(
"Collision Volumes:CollisionNode");
104PStatCollector GraphicsEngine::_gnode_volume_pcollector(
"Collision Volumes:GeomNode");
105PStatCollector GraphicsEngine::_geom_volume_pcollector(
"Collision Volumes:Geom");
106PStatCollector GraphicsEngine::_node_volume_pcollector(
"Collision Volumes:PandaNode");
107PStatCollector GraphicsEngine::_volume_pcollector(
"Collision Volumes:CollisionSolid");
108PStatCollector GraphicsEngine::_test_pcollector(
"Collision Tests:CollisionSolid");
109PStatCollector GraphicsEngine::_volume_polygon_pcollector(
"Collision Volumes:CollisionPolygon");
110PStatCollector GraphicsEngine::_test_polygon_pcollector(
"Collision Tests:CollisionPolygon");
111PStatCollector GraphicsEngine::_volume_plane_pcollector(
"Collision Volumes:CollisionPlane");
112PStatCollector GraphicsEngine::_test_plane_pcollector(
"Collision Tests:CollisionPlane");
113PStatCollector GraphicsEngine::_volume_sphere_pcollector(
"Collision Volumes:CollisionSphere");
114PStatCollector GraphicsEngine::_test_sphere_pcollector(
"Collision Tests:CollisionSphere");
115PStatCollector GraphicsEngine::_volume_box_pcollector(
"Collision Volumes:CollisionBox");
116PStatCollector GraphicsEngine::_test_box_pcollector(
"Collision Tests:CollisionBox");
117PStatCollector GraphicsEngine::_volume_capsule_pcollector(
"Collision Volumes:CollisionCapsule");
118PStatCollector GraphicsEngine::_test_capsule_pcollector(
"Collision Tests:CollisionCapsule");
119PStatCollector GraphicsEngine::_volume_inv_sphere_pcollector(
"Collision Volumes:CollisionInvSphere");
120PStatCollector GraphicsEngine::_test_inv_sphere_pcollector(
"Collision Tests:CollisionInvSphere");
121PStatCollector GraphicsEngine::_volume_geom_pcollector(
"Collision Volumes:CollisionGeom");
122PStatCollector GraphicsEngine::_test_geom_pcollector(
"Collision Tests:CollisionGeom");
123PStatCollector GraphicsEngine::_occlusion_untested_pcollector(
"Occlusion results:Not tested");
124PStatCollector GraphicsEngine::_occlusion_passed_pcollector(
"Occlusion results:Visible");
125PStatCollector GraphicsEngine::_occlusion_failed_pcollector(
"Occlusion results:Occluded");
126PStatCollector GraphicsEngine::_occlusion_tests_pcollector(
"Occlusion tests");
135INLINE
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";
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;
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);
834 TransformState::flush_level();
838#ifdef THREADED_PIPELINE
840 PStatTimer timer(_cycle_pcollector, current_thread);
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();
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;
1033 while (thread->_thread_state != TS_wait) {
1034 thread->_cv_done.
wait();
1037 thread->_thread_state = TS_do_windows;
1038 thread->_cv_start.
notify();
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();
1154 thread->_texture = tex;
1155 thread->_thread_state = TS_do_extract;
1156 thread->_cv_start.
notify();
1161 while (thread->_thread_state != TS_wait) {
1162 thread->_cv_done.
wait();
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();
1221 thread->_state = state.p();
1222 thread->_work_groups = work_groups;
1223 thread->_thread_state = TS_do_compute;
1224 thread->_cv_start.
notify();
1229 while (thread->_thread_state != TS_wait) {
1230 thread->_cv_done.
wait();
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());
1356bool GraphicsEngine::
1358 return _global_ptr->is_scene_root(node);
1365bool 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) {
1413void GraphicsEngine::
1416 window->_sort = sort;
1417 _windows_sorted =
false;
1426void 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) {
1436 if (display_cat.is_spam()) {
1438 <<
"Flipping window " << win->
get_name() <<
"\n";
1441 PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
1445 PStatTimer timer(GraphicsEngine::_flip_end_pcollector, current_thread);
1450 if (win->
begin_frame(GraphicsOutput::FM_render, current_thread)) {
1454 gsg->push_group_marker(
"Clear");
1455 win->
clear(current_thread);
1456 gsg->pop_group_marker();
1459 if (display_cat.is_spam()) {
1461 <<
"Culling and drawing window " << win->
get_name() <<
"\n";
1464 int num_display_regions = win->get_num_active_display_regions();
1465 for (
int i = 0; i < num_display_regions; i++) {
1467 if (dr !=
nullptr) {
1468 cull_and_draw_together(win, dr, current_thread);
1471 win->
end_frame(GraphicsOutput::FM_render, current_thread);
1475 if (display_cat.is_spam()) {
1477 <<
"Flipping window " << win->
get_name() <<
"\n";
1480 PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
1484 PStatTimer timer(GraphicsEngine::_flip_end_pcollector, current_thread);
1497void GraphicsEngine::
1499 Thread *current_thread) {
1501 nassertv(gsg !=
nullptr);
1512 if (dr_reader.is_any_clear_active()) {
1517 scene_setup = setup_scene(gsg, &dr_reader);
1520 if (scene_setup ==
nullptr) {
1526 }
else if (!gsg->
set_scene(scene_setup)) {
1529 << gsg->get_type() <<
" cannot render scene with specified lens.\n";
1535 if (cbobj !=
nullptr) {
1544 dr->do_cull(&cull_handler, scene_setup, gsg, current_thread);
1551 gsg->pop_group_marker();
1559void GraphicsEngine::
1561 PStatTimer timer(_cull_pcollector, current_thread);
1563 _singular_warning_last_frame = _singular_warning_this_frame;
1564 _singular_warning_this_frame =
false;
1569 AlreadyCulled already_culled;
1571 size_t wlist_size = wlist.
size();
1572 for (
size_t wi = 0; wi < wlist_size; ++wi) {
1575 if (display_cat.is_spam()) {
1577 <<
"Culling window " << win->
get_name() <<
"\n";
1582 int num_display_regions = win->get_num_active_display_regions();
1583 for (
int i = 0; i < num_display_regions; ++i) {
1585 if (dr !=
nullptr) {
1590 PStatTimer timer(_cull_setup_pcollector, current_thread);
1592 scene_setup = setup_scene(gsg, &dr_reader);
1593 if (scene_setup ==
nullptr) {
1598 key._camera = dr_reader.get_camera();
1599 key._lens_index = dr_reader.get_lens_index();
1602 AlreadyCulled::iterator aci = already_culled.insert(AlreadyCulled::value_type(std::move(key),
nullptr)).first;
1603 if ((*aci).second ==
nullptr) {
1607 if (cull_result !=
nullptr) {
1608 cull_result = cull_result->make_next();
1614 cull_to_bins(win, gsg, dr, scene_setup, cull_result, current_thread);
1628 dr->
set_cull_result(std::move(cull_result), MOVE(scene_setup), current_thread);
1638void GraphicsEngine::
1645 if (cbobj !=
nullptr) {
1654 dr->do_cull(&cull_handler, scene_setup, gsg, current_thread);
1657 PStatTimer timer(_cull_sort_pcollector, current_thread);
1658 cull_result->
finish_cull(scene_setup, current_thread);
1666void GraphicsEngine::
1670 size_t wlist_size = wlist.
size();
1671 for (
size_t wi = 0; wi < wlist_size; ++wi) {
1679 if (display_cat.is_spam()) {
1681 <<
"Flipping window " << host->
get_name()
1682 <<
" before drawing window " << win->
get_name() <<
"\n";
1687 PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
1691 PStatTimer timer(GraphicsEngine::_flip_end_pcollector, current_thread);
1696 if (win->
begin_frame(GraphicsOutput::FM_render, current_thread)) {
1703 win->
get_gsg()->push_group_marker(
"Clear");
1704 win->
clear(current_thread);
1705 win->
get_gsg()->pop_group_marker();
1708 if (display_cat.is_spam()) {
1710 <<
"Drawing window " << win->
get_name() <<
"\n";
1712 int num_display_regions = win->get_num_active_display_regions();
1713 for (
int i = 0; i < num_display_regions; ++i) {
1715 if (dr !=
nullptr) {
1716 do_draw(win, gsg, dr, current_thread);
1720 win->
end_frame(GraphicsOutput::FM_render, current_thread);
1726 gsg->issue_timer_query(GraphicsStateGuardian::_command_latency_pcollector.get_index());
1731 if (display_cat.is_spam()) {
1733 <<
"Flipping window " << win->
get_name() <<
"\n";
1738 PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
1742 PStatGPUTimer timer(gsg, GraphicsEngine::_flip_end_pcollector, current_thread);
1749 if (display_cat.is_spam()) {
1751 <<
"Not drawing window " << win->
get_name() <<
"\n";
1756 if (display_cat.is_spam()) {
1758 <<
"Window " << win->
get_name() <<
" is inactive\n";
1768void GraphicsEngine::
1770 Windows::const_iterator wi;
1771 for (wi = wlist.
begin(); wi != wlist.
end(); ++wi) {
1773 if (win->
begin_frame(GraphicsOutput::FM_refresh, current_thread)) {
1774 win->
end_frame(GraphicsOutput::FM_refresh, current_thread);
1784void GraphicsEngine::
1789 for (
size_t i = 0; i < wlist.
size(); ++i) {
1790 wlist[i]->process_events();
1799void GraphicsEngine::
1801 size_t num_windows = wlist.
size();
1803 size_t warray_count = 0;
1807 for (i = 0; i < num_windows; ++i) {
1810 if (display_cat.is_spam()) {
1812 <<
"Flipping window " << win->
get_name() <<
"\n";
1815 nassertv(warray_count < num_windows);
1816 warray[warray_count] = win;
1819 PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
1824 for (i = 0; i < warray_count; ++i) {
1826 PStatTimer timer(GraphicsEngine::_flip_end_pcollector, current_thread);
1836void GraphicsEngine::
1838 Windows::const_iterator wi;
1839 for (wi = wlist.
begin(); wi != wlist.
end(); ++wi) {
1842 PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
1852void GraphicsEngine::
1853do_sync_frame(
Thread *current_thread) {
1857 PStatTimer timer(_sync_pcollector, current_thread);
1859 nassertv(_flip_state == FS_draw);
1863 Threads::const_iterator ti;
1864 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
1865 RenderThread *thread = (*ti).second;
1866 thread->_cv_mutex.acquire();
1867 thread->_cv_mutex.release();
1870 _flip_state = FS_sync;
1877void GraphicsEngine::
1878do_ready_flip(
Thread *current_thread) {
1882 PStatTimer timer(_sync_pcollector, current_thread);
1884 nassertv(_flip_state == FS_draw);
1888 Threads::const_iterator ti;
1889 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
1890 RenderThread *thread = (*ti).second;
1891 thread->_cv_mutex.acquire();
1892 thread->_cv_mutex.release();
1894 _app.do_ready_flip(
this,current_thread);
1895 _flip_state = FS_sync;
1902void GraphicsEngine::
1903do_flip_frame(
Thread *current_thread) {
1907 PStatTimer timer(_flip_pcollector, current_thread);
1909 nassertv(_flip_state == FS_draw || _flip_state == FS_sync);
1915 PStatTimer timer(_wait_pcollector, current_thread);
1916 Threads::const_iterator ti;
1917 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
1918 RenderThread *thread = (*ti).second;
1919 thread->_cv_mutex.acquire();
1921 while (thread->_thread_state != TS_wait) {
1922 thread->_cv_done.wait();
1928 _app.do_flip(
this, current_thread);
1931 Threads::const_iterator ti;
1932 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
1933 RenderThread *thread = (*ti).second;
1934 nassertv(thread->_thread_state == TS_wait);
1935 thread->_thread_state = TS_do_flip;
1936 thread->_cv_start.notify();
1937 thread->_cv_mutex.release();
1941 _flip_state = FS_flip;
1951 Thread *current_thread = dr->get_current_thread();
1952 PStatTimer timer(_cull_setup_pcollector, current_thread);
1957 nassertr(window !=
nullptr,
nullptr);
1966 DCAST_INTO_R(camera_node, camera.
node(),
nullptr);
1986 scene_root = camera.
get_top(current_thread);
2002 if (camera_transform->is_invalid()) {
2004 if (!_singular_warning_last_frame) {
2005 display_cat.warning()
2006 <<
"Scene " << scene_root <<
" has net scale ("
2008 _singular_warning_this_frame =
true;
2013 if (world_transform->is_invalid()) {
2015 if (!_singular_warning_last_frame) {
2016 display_cat.warning()
2017 <<
"Camera " << camera <<
" has net scale ("
2020 _singular_warning_this_frame =
true;
2024 CPT(
RenderState) initial_state = camera_node->get_initial_state();
2034 initial_state = initial_state->compose(get_invert_polygon_state());
2043 scene_setup->set_initial_state(initial_state);
2050 CPT(
TransformState) cs_world_transform = cs_transform->compose(world_transform);
2059void GraphicsEngine::
2070 cull_result = cdata->_cull_result;
2071 scene_setup = cdata->_scene_setup;
2080 if (dr_reader.is_any_clear_active()) {
2082 gsg->
clear(dr_reader.get_object());
2085 cbobj = dr_reader.get_draw_callback();
2088 if (cbobj !=
nullptr) {
2093 static CPT(
RenderState) state = RenderState::make(
2094 DepthTestAttrib::make(DepthTestAttrib::M_none));
2104 }
else if (cull_result ==
nullptr || scene_setup ==
nullptr) {
2114 }
else if (!gsg->
set_scene(scene_setup)) {
2117 << gsg->get_type() <<
" cannot render scene with specified lens.\n";
2121 cull_result->
draw(current_thread);
2126 gsg->pop_group_marker();
2134void GraphicsEngine::
2136 nassertv(window !=
nullptr);
2143 window->_internal_sort_index = _window_sort_index;
2144 ++_window_sort_index;
2146 if (display_cat.is_debug()) {
2148 <<
"Created " << window->get_type() <<
" " << (
void *)window <<
"\n";
2152 _new_windows.push_back(window);
2160void GraphicsEngine::
2162 nassertv(gsg !=
nullptr);
2166 gsg->_threading_model = _threading_model;
2167 if (!_default_loader.is_null()) {
2171 auto_adjust_capabilities(gsg);
2173 WindowRenderer *draw =
2185void GraphicsEngine::
2187 nassertv(window !=
nullptr);
2191 if (!_windows_sorted) {
2192 do_resort_windows();
2196 _app.remove_window(window);
2197 Threads::const_iterator ti;
2198 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
2199 RenderThread *thread = (*ti).second;
2200 thread->remove_window(window);
2205 _app.do_pending(
this, current_thread);
2207 if (display_cat.is_debug()) {
2209 <<
"Removed " << window->get_type() <<
" " << (
void *)window <<
"\n";
2217void GraphicsEngine::
2218do_resort_windows() {
2219 _windows_sorted =
true;
2221 if (display_cat.is_spam()) {
2223 <<
"Re-sorting window list.\n";
2226 _app.resort_windows();
2227 Threads::const_iterator ti;
2228 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
2229 RenderThread *thread = (*ti).second;
2230 thread->resort_windows();
2256void GraphicsEngine::
2278 if (textures_auto_power_2 && (textures_power_2 == ATS_none)) {
2280 <<
"Invalid panda config file: if you set the config-variable\n"
2281 <<
"textures_auto_power_2 to true, you must set the config-variable"
2282 <<
"textures_power_2 to 'up' or 'down'.\n";
2283 textures_power_2 = ATS_down;
2300 <<
"The 'textures_power_2' configuration is set to 'none', meaning \n"
2301 <<
"that non-power-of-two texture support is required, but the video \n"
2302 <<
"driver I'm trying to use does not support non-power-of-two textures.\n";
2304 if (textures_power_2 != ATS_none) {
2306 <<
"The 'none' did not come from the config file. In other words,\n"
2307 <<
"the variable 'textures_power_2' was altered procedurally.\n";
2309 if (textures_auto_power_2) {
2311 <<
"It is possible that it was set by panda's automatic mechanisms,\n"
2312 <<
"which are currently enabled, because 'textures_auto_power_2' is\n"
2313 <<
"true. Panda's automatic mechanisms assume that if one\n"
2314 <<
"window supports non-power-of-two textures, then they all will.\n"
2315 <<
"This assumption works for most games, but not all.\n"
2316 <<
"In particular, it can fail if the game creates multiple windows\n"
2317 <<
"on multiple displays with different video cards.\n";
2326void GraphicsEngine::
2327terminate_threads(
Thread *current_thread) {
2332 PStatTimer timer(_wait_pcollector, current_thread);
2336 Threads::const_iterator ti;
2337 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
2338 RenderThread *thread = (*ti).second;
2339 thread->_cv_mutex.acquire();
2343 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
2344 RenderThread *thread = (*ti).second;
2345 thread->_thread_state = TS_terminate;
2346 thread->_cv_start.notify();
2347 thread->_cv_mutex.release();
2351 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
2352 RenderThread *thread = (*ti).second;
2365void GraphicsEngine::
2366pstats_count_cycler_type(
TypeHandle type,
int count,
void *data) {
2368 CyclerTypeCounters::iterator ci = self->_all_cycler_types.find(type);
2369 if (ci == self->_all_cycler_types.end()) {
2371 ci = self->_all_cycler_types.insert(CyclerTypeCounters::value_type(type, collector)).first;
2373 (*ci).second.set_level(count);
2382void GraphicsEngine::
2383pstats_count_dirty_cycler_type(
TypeHandle type,
int count,
void *data) {
2385 CyclerTypeCounters::iterator ci = self->_dirty_cycler_types.find(type);
2386 if (ci == self->_dirty_cycler_types.end()) {
2388 ci = self->_dirty_cycler_types.insert(CyclerTypeCounters::value_type(type, collector)).first;
2390 (*ci).second.set_level(count);
2400get_invert_polygon_state() {
2404 if (state ==
nullptr) {
2405 state = RenderState::make(CullFaceAttrib::make_reverse());
2419GraphicsEngine::WindowRenderer *GraphicsEngine::
2420get_window_renderer(
const string &name,
int pipeline_stage) {
2427 Threads::iterator ti = _threads.find(name);
2428 if (ti != _threads.end()) {
2429 return (*ti).second.p();
2432 PT(RenderThread) thread =
new RenderThread(name,
this);
2433 thread->set_min_pipeline_stage(pipeline_stage);
2436 bool started = thread->start(TP_normal,
true);
2437 nassertr(started, thread.p());
2438 _threads[name] = thread;
2440 nassertr(thread->get_pipeline_stage() < _pipeline->
get_num_stages(), thread.p());
2448GraphicsEngine::WindowRenderer::
2449WindowRenderer(
const string &name) :
2450 _wl_lock(string(
"GraphicsEngine::WindowRenderer::_wl_lock ") + name)
2457void GraphicsEngine::WindowRenderer::
2467void GraphicsEngine::WindowRenderer::
2470 wlist.insert(window);
2478void GraphicsEngine::WindowRenderer::
2480 nassertv(window !=
nullptr);
2485 _cdraw.erase(ptwin);
2488 Windows::iterator wi;
2490 wi = _window.find(ptwin);
2491 if (wi != _window.end()) {
2501 if (ptwin->is_valid()) {
2502 _pending_close.push_back(ptwin);
2512void GraphicsEngine::WindowRenderer::
2521 if (display_cat.is_debug()) {
2523 <<
"Windows resorted:";
2524 Windows::const_iterator wi;
2525 for (wi = _window.begin(); wi != _window.end(); ++wi) {
2527 display_cat.debug(
false)
2530 display_cat.debug(
false)
2533 for (wi = _draw.begin(); wi != _draw.end(); ++wi) {
2535 display_cat.debug(
false)
2538 display_cat.debug(
false)
2548void GraphicsEngine::WindowRenderer::
2550 PStatTimer timer(engine->_do_frame_pcollector, current_thread);
2553 engine->cull_to_bins(_cull, current_thread);
2554 engine->cull_and_draw_together(_cdraw, current_thread);
2555 engine->draw_bins(_draw, current_thread);
2556 engine->process_events(_window, current_thread);
2560 if (any_done_gsgs()) {
2563 for (gi = _gsgs.begin(); gi != _gsgs.end(); ++gi) {
2568 engine->close_gsg(pipe, gsg);
2571 new_gsgs.insert(gsg);
2575 _gsgs.swap(new_gsgs);
2585void GraphicsEngine::WindowRenderer::
2589 engine->process_events(_window, current_thread);
2591 engine->make_contexts(_cdraw, current_thread);
2592 engine->make_contexts(_draw, current_thread);
2598void GraphicsEngine::WindowRenderer::
2601 engine->flip_windows(_cdraw, current_thread);
2602 engine->flip_windows(_draw, current_thread);
2608void GraphicsEngine::WindowRenderer::
2611 engine->ready_flip_windows(_cdraw, current_thread);
2612 engine->ready_flip_windows(_draw, current_thread);
2619void GraphicsEngine::WindowRenderer::
2622 Windows::iterator wi;
2623 for (wi = _window.begin(); wi != _window.end(); ++wi) {
2631 for (gi = _gsgs.begin(); gi != _gsgs.end(); ++gi) {
2636 engine->close_gsg(pipe, gsg);
2639 new_gsgs.insert(gsg);
2643 _gsgs.swap(new_gsgs);
2650void GraphicsEngine::WindowRenderer::
2654 if (!_pending_close.empty()) {
2655 if (display_cat.is_debug()) {
2657 <<
"_pending_close.size() = " << _pending_close.size() <<
"\n";
2663 Windows::iterator wi;
2664 Windows pending_close;
2665 _pending_close.
swap(pending_close);
2666 for (wi = pending_close.begin(); wi != pending_close.end(); ++wi) {
2678bool GraphicsEngine::WindowRenderer::
2679any_done_gsgs()
const {
2680 GSGs::const_iterator gi;
2681 for (gi = _gsgs.begin(); gi != _gsgs.end(); ++gi) {
2682 if ((*gi)->get_ref_count() == 1) {
2693GraphicsEngine::RenderThread::
2696 WindowRenderer(name),
2698 _cv_mutex(string(
"GraphicsEngine::RenderThread ") + name),
2699 _cv_start(_cv_mutex),
2702 _thread_state = TS_wait;
2709void GraphicsEngine::RenderThread::
2717 switch (_thread_state) {
2722 do_pending(_engine, current_thread);
2723 do_frame(_engine, current_thread);
2727 do_flip(_engine, current_thread);
2731 do_pending(_engine, current_thread);
2735 do_windows(_engine, current_thread);
2736 do_pending(_engine, current_thread);
2740 nassertd(_gsg !=
nullptr && _state !=
nullptr) break;
2743 _state->get_attrib(sattr);
2744 _gsg->push_group_marker(std::string(
"Compute ") + sattr->get_shader()->get_filename(Shader::ST_compute).get_basename());
2747 _gsg->pop_group_marker();
2752 nassertd(_gsg !=
nullptr && _texture !=
nullptr) break;
2756 case TS_do_screenshot:
2757 nassertd(_region !=
nullptr) break;
2758 _texture = _region->get_screenshot();
2762 do_pending(_engine, current_thread);
2763 do_close(_engine, current_thread);
2764 _thread_state = TS_done;
2774 _thread_state = TS_wait;
2778 PStatTimer timer(_wait_pcollector, current_thread);
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void stop_threads()
Stops any threads that are currently running.
static AsyncTaskManager * get_global_ptr()
Returns a pointer to the global AsyncTaskManager.
static void consider_flush_global_index()
If there is a global BamCache object, calls consider_flush_index() on it.
static void flush_global_index()
If there is a global BamCache object, calls flush_index() on it.
This CullHandler sends all of the geoms it receives into a CullResult object, for binning (and later ...
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
This special window object doesn't represent a window in its own right, but instead hooks into some t...
This is a generic object that can be assigned to a callback at various points in the rendering proces...
virtual void do_callback(CallbackData *cbdata)
This method called when the callback is triggered; it *replaces* the original function.
A node that can be positioned around in the scene graph to represent a point of view for rendering a ...
is_active
Returns the current setting of the active flag on the camera.
get_scene
Returns the scene that will be rendered by the camera.
int cleanup_aux_scene_data(Thread *current_thread=Thread::get_current_thread())
Walks through the list of currently-assigned AuxSceneData objects and releases any that are past thei...
A ClockObject keeps track of elapsed real time and discrete time.
void tick(Thread *current_thread=Thread::get_current_thread())
Instructs the clock that a new frame has just begun.
get_frame_count
Returns the number of times tick() has been called since the ClockObject was created,...
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
bool check_errors(Thread *current_thread)
Returns true if a clock error was detected since the last time check_errors() was called.
void notify()
Informs one of the other threads who are currently blocked on wait() that the relevant condition has ...
void wait()
Waits on the condition.
This defines the abstract interface for an object that receives Geoms identified by the CullTraverser...
This stores the result of a BinCullHandler traversal: an ordered collection of CullBins,...
void draw(Thread *current_thread)
Asks all the bins to draw themselves in the correct order.
void finish_cull(SceneSetup *scene_setup, Thread *current_thread)
Called after all the geoms have been added, this indicates that the cull process is finished for this...
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
void set_view_frustum(GeometricBoundingVolume *view_frustum)
Specifies the bounding volume that corresponds to the view frustum.
virtual void end_traverse()
Should be called when the traverser has finished traversing its scene, this gives it a chance to do a...
virtual void set_scene(SceneSetup *scene_setup, GraphicsStateGuardianBase *gsg, bool dr_incomplete_render)
Sets the SceneSetup object that indicates the initial camera position, etc.
void set_cull_handler(CullHandler *cull_handler)
Specifies the object that will receive the culled Geoms.
static void flush_level()
Flushes the PStatCollectors used during traversal.
void traverse(const NodePath &root)
Begins the traversal from the indicated node.
static void flush_level()
Flushes the PStatCollectors used during traversal.
This template class calls PipelineCycler::read_unlocked(), and then provides a transparent read-only ...
This specialization on CallbackData is passed when the callback is initiated from the cull traversal,...
This specialization on CallbackData is passed when the callback is initiated from the draw traversal,...
Encapsulates the data from a DisplayRegion, pre-fetched for one stage of the pipeline.
GraphicsOutput * get_window() const
Returns the GraphicsOutput that this DisplayRegion is ultimately associated with, or NULL if no windo...
int get_lens_index() const
Gets the index into a lens_node lens array.
NodePath get_camera() const
Returns the camera associated with this DisplayRegion, or an empty NodePath if no camera is associate...
int get_pixel_width(int i=0) const
Returns the width of the DisplayRegion in pixels.
int get_pixel_height(int i=0) const
Returns the height of the DisplayRegion in pixels.
A rectangular subregion within a window for rendering into.
is_stereo
Returns true if this is a StereoDisplayRegion, false otherwise.
get_cull_traverser
Returns the CullTraverser that will be used to draw the contents of this DisplayRegion.
void set_cull_result(PT(CullResult) cull_result, PT(SceneSetup) scene_setup, Thread *current_thread)
Stores the result of performing a cull operation on this DisplayRegion.
get_incomplete_render
Returns the incomplete_render flag.
CullResult * get_cull_result(Thread *current_thread) const
Returns the CullResult value that was stored on this DisplayRegion, presumably by the last successful...
PStatCollector & get_draw_region_pcollector()
Returns a PStatCollector for timing the draw operation for just this DisplayRegion.
PStatCollector & get_cull_region_pcollector()
Returns a PStatCollector for timing the cull operation for just this DisplayRegion.
const std::string & get_debug_name() const
Returns a unique name used for debugging.
get_cull_callback
Returns the CallbackObject set by set_cull_callback().
This special kind of CullHandler immediately draws its contents as soon as it receives them.
virtual bool is_any_clear_active() const
Returns true if any of the clear types (so far there are just color or depth) have been set active,...
std::string get_basename() const
Returns the basename part of the filename.
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
bool subsumes(const FrameBufferProperties &other) const
Returns true if this set of properties makes strictly greater or equal demands of the framebuffer tha...
static void flush_level()
Flushes the PStatCollectors used during traversal.
static SimpleLru * get_small_lru()
Returns a pointer to the global LRU object that manages the GeomVertexArrayData's that are deemed too...
static SimpleLru * get_independent_lru()
Returns a pointer to the global LRU object that manages the GeomVertexArrayData's that have not (yet)...
static void lru_epoch()
Marks that an epoch has passed in each LRU.
This is another abstract class, for a general class of bounding volumes that actually enclose points ...
This class is the main interface to controlling the render process.
get_threading_model
Returns the threading model that will be applied to future objects.
get_window
Returns the nth window or buffers managed by the engine, in sorted order.
void reset_all_windows(bool swapchain)
Resets the framebuffer of the current window.
void remove_all_windows()
Removes and closes all windows from the engine.
bool add_window(GraphicsOutput *window, int sort)
This can be used to add a newly-created GraphicsOutput object (and its GSG) to the engine's list of w...
void ready_flip()
Waits for all the threads that started drawing their last frame to finish drawing.
void open_windows()
Fully opens (or closes) any windows that have recently been requested open or closed,...
void flip_frame()
Waits for all the threads that started drawing their last frame to finish drawing,...
bool extract_texture_data(Texture *tex, GraphicsStateGuardian *gsg)
Asks the indicated GraphicsStateGuardian to retrieve the texture memory image of the indicated textur...
bool is_empty() const
Returns true if there are no windows or buffers managed by the engine, false if there is at least one...
bool remove_window(GraphicsOutput *window)
Removes the indicated window or offscreen buffer from the set of windows that will be processed when ...
set_threading_model
Specifies how future objects created via make_gsg(), make_buffer(), and make_output() will be threade...
GraphicsOutput * make_output(GraphicsPipe *pipe, const std::string &name, int sort, const FrameBufferProperties &fb_prop, const WindowProperties &win_prop, int flags, GraphicsStateGuardian *gsg=nullptr, GraphicsOutput *host=nullptr)
Creates a new window (or buffer) and returns it.
void render_frame()
Renders the next frame in all the registered windows, and flips all of the frame buffers.
~GraphicsEngine()
Gracefully cleans up the graphics engine and its related threads and windows.
GraphicsEngine(Pipeline *pipeline=nullptr)
Creates a new GraphicsEngine object.
void texture_uploaded(Texture *tex)
This method is called by the GraphicsStateGuardian after a texture has been successfully uploaded to ...
void sync_frame()
Waits for all the threads that started drawing their last frame to finish drawing.
get_num_windows
Returns the number of windows (or buffers) managed by the engine.
void dispatch_compute(const LVecBase3i &work_groups, const ShaderAttrib *sattr, GraphicsStateGuardian *gsg)
Asks the indicated GraphicsStateGuardian to dispatch the compute shader in the given ShaderAttrib usi...
static void do_cull(CullHandler *cull_handler, SceneSetup *scene_setup, GraphicsStateGuardian *gsg, Thread *current_thread)
Fires off a cull traversal using the indicated camera.
This is a base class for the various different classes that represent the result of a frame of render...
virtual void ready_flip()
This function will be called within the draw thread after end_frame() has been called on all windows,...
get_inverted
Returns the current setting of the inverted flag.
get_pipe
Returns the GraphicsPipe that this window is associated with.
virtual void begin_flip()
This function will be called within the draw thread after end_frame() has been called on all windows,...
is_active
Returns true if the window is ready to be rendered into, false otherwise.
get_gsg
Returns the GSG that is associated with this window.
virtual void clear_pipe()
Sets the window's _pipe pointer to NULL; this is generally called only as a precursor to deleting the...
PStatCollector & get_draw_window_pcollector()
Returns a PStatCollector for timing the draw operation for just this GraphicsOutput.
PStatCollector & get_cull_window_pcollector()
Returns a PStatCollector for timing the cull operation for just this GraphicsOutput.
virtual void end_frame(FrameMode mode, Thread *current_thread)
This function will be called within the draw thread after rendering is completed for a given frame.
virtual void end_flip()
This function will be called within the draw thread after begin_flip() has been called on all windows...
bool get_delete_flag() const
Returns the current setting of the delete flag.
void change_scenes(DisplayRegionPipelineReader *new_dr)
Called by the GraphicsEngine when the window is about to change to another DisplayRegion.
const FrameBufferProperties & get_fb_properties() const
Returns the framebuffer properties of the window.
virtual bool begin_frame(FrameMode mode, Thread *current_thread)
This function will be called within the draw thread before beginning rendering for a given frame.
virtual void reset_window(bool swapchain)
Resets the window framebuffer from its derived children.
virtual GraphicsOutput * get_host()
This is normally called only from within make_texture_buffer().
get_engine
Returns the graphics engine that created this output.
bool is_valid() const
Returns true if the output is fully created and ready for rendering, false otherwise.
virtual void request_close()
This is called by the GraphicsEngine to request that the window (or whatever) close itself or,...
get_sort
Returns the sorting order of this particular GraphicsOutput.
get_name
Returns the name that was passed to the GraphicsOutput constructor.
PStatCollector & get_clear_window_pcollector()
Returns a PStatCollector for timing the clear operation for just this GraphicsOutput.
virtual void request_open()
This is called by the GraphicsEngine to request that the window (or whatever) open itself or,...
virtual bool flip_ready() const
Returns true if a frame has been rendered and needs to be flipped, false otherwise.
virtual void clear(Thread *current_thread)
Clears the entire framebuffer before rendering, according to the settings of get_color_clear_active()...
virtual void set_close_now()
This is called by the GraphicsEngine to insist that the output be closed immediately.
An object to create GraphicsOutputs that share a particular 3-D API.
get_gsg
Returns the nth GSG in the universe.
Encapsulates all the communication with a particular instance of a given rendering backend.
virtual void clear_before_callback()
Resets any non-standard graphics state that might give a callback apoplexy.
is_valid
Returns true if the GSG has been correctly initialized within a graphics context, false if there has ...
get_pipe
Returns the graphics pipe on which this GSG was created.
void release_all()
Releases all prepared objects.
set_scene
Sets the SceneSetup object that indicates the initial camera position, etc.
GraphicsEngine * get_engine() const
Returns the graphics engine that created this GSG.
bool needs_reset() const
Returns true if the gsg is marked as needing a reset.
get_supports_tex_non_pow2
Returns true if this GSG can handle non power of two sized textures.
virtual void clear_state_and_transform()
Forgets the current graphics state and current transform, so that the next call to set_state_and_tran...
set_loader
Sets the Loader object that will be used by this GSG to load textures when necessary,...
virtual void prepare_display_region(DisplayRegionPipelineReader *dr)
Makes the specified DisplayRegion current.
get_prepared_objects
Returns the set of texture and geom objects that have been prepared with this GSG (and possibly other...
virtual bool extract_texture_data(Texture *tex)
This method should only be called by the GraphicsEngine.
virtual void end_scene()
Called between begin_frame() and end_frame() to mark the end of drawing commands for a "scene" (usual...
get_timer_queries_active
Returns true if timer queries are currently enabled on this GSG.
virtual void set_state_and_transform(const RenderState *state, const TransformState *transform)
Simultaneously resets the render state and the transform state.
virtual void clear(DrawableRegion *clearable)
Clears the framebuffer within the current DisplayRegion, according to the flags indicated by the give...
const GraphicsThreadingModel & get_threading_model() const
Returns the threading model that was used to create this GSG.
virtual void dispatch_compute(int size_x, int size_y, int size_z)
Dispatches a currently bound compute shader using the given work group counts.
virtual bool begin_scene()
Called between begin_frame() and end_frame() to mark the beginning of drawing commands for a "scene" ...
This represents the user's specification of how a particular frame is handled by the various threads.
int get_cull_stage() const
Returns the pipeline stage from which the cull thread should access data.
bool get_cull_sorting() const
Returns true if the model involves a separate cull pass, or false if culling happens implicitly,...
const std::string & get_cull_name() const
Returns the name of the thread that will handle culling in this model.
bool is_default() const
Returns true if the threading model is the default, cull-then-draw single- threaded model,...
const std::string & get_draw_name() const
Returns the name of the thread that will handle sending the actual graphics primitives to the graphic...
int get_draw_stage() const
Returns the pipeline stage from which the draw thread should access data.
Lens * get_lens(int index=0) const
Returns a pointer to the particular Lens associated with this LensNode, or NULL if there is not yet a...
bool get_lens_active(int index) const
Returns the active flag for the nth lens.
A base class for any number of different kinds of lenses, linear and otherwise.
get_coordinate_system
Returns the coordinate system that all 3-d computations are performed within for this Lens.
Similar to MutexHolder, but for a light reentrant mutex.
void release() const
Releases the mutex.
void acquire() const
Grabs the mutex if it is available.
bool debug_is_locked() const
Returns true if the current thread has locked the Mutex, false otherwise.
A lightweight C++ object whose constructor calls acquire() and whose destructor calls release() on a ...
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
LVecBase3 get_scale() const
Retrieves the scale component of the transform.
bool is_empty() const
Returns true if the NodePath contains no nodes.
PandaNode * node() const
Returns the referenced node of the path.
NodePath get_top(Thread *current_thread=Thread::get_current_thread()) const
Returns a singleton NodePath that represents the top of the path, or empty NodePath if this path is e...
get_parent
Returns the NodePath to the parent of the referenced node: that is, this NodePath,...
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
static void disconnect()
Closes the connection previously established.
static bool is_connected()
Returns true if the client believes it is connected to a working PStatServer, false otherwise.
A lightweight class that represents a single element that may be timed and/or counted via stats.
This is a special type of PStatTimer that also uses a timer query on the GSG to measure how long a ta...
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
A basic node of the scene graph or data graph.
static void set_scene_root_func(SceneRootFunc *func)
This is used by the GraphicsEngine to hook in a pointer to the scene_root_func(), the function to det...
This is a special GraphicsOutput type that acts a lot like a GraphicsBuffer, effectively allowing ren...
This class manages a staged pipeline of data, for instance the render pipeline, so that each stage of...
void cycle()
Flows all the pipeline data down to the next stage.
int get_num_stages() const
Returns the number of stages required for the pipeline.
static Pipeline * get_render_pipeline()
Returns a pointer to the global render pipeline.
void set_min_stages(int min_stages)
Ensures that at least the indicated number of stages are in the pipeline.
A table of objects that are saved within the graphics context for reference by handle later.
void release_all()
Releases all prepared objects of all kinds at once.
bool debug_is_locked() const
Returns true if the current thread has locked the ReMutex, false otherwise.
Similar to MutexHolder, but for a reentrant mutex.
get_ref_count
Returns the current reference count.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
static int get_num_states()
Returns the total number of unique RenderState objects allocated in the world.
static void flush_level()
Flushes the PStatCollectors used during traversal.
static int get_num_unused_states()
Returns the total number of RenderState objects that have been allocated but have no references outsi...
This object holds the camera position, etc., and other general setup information for rendering a part...
void set_world_transform(const TransformState *world_transform)
Specifies the position of the starting node relative to the camera.
void set_viewport_size(int width, int height)
Specifies the size of the viewport (display region), in pixels.
DisplayRegion * get_display_region() const
Returns the display region for the scene.
void set_cs_world_transform(const TransformState *cs_world_transform)
Specifies the position from the starting node relative to the camera, in the GSG's internal coordinat...
const NodePath & get_scene_root() const
Returns the root node of the scene.
void set_scene_root(const NodePath &scene_root)
Specifies the root node of the scene.
void set_cs_transform(const TransformState *cs_transform)
Specifies the transform from the camera's coordinate system to the GSG's internal coordinate system.
void set_lens(const Lens *lens)
Indicates the particular Lens used for rendering.
void set_camera_path(const NodePath &camera_path)
Specifies the NodePath to the camera.
const NodePath & get_cull_center() const
Returns the point from which the culling operations will be performed.
void set_display_region(DisplayRegion *display_region)
Specifies the display region for the scene.
void set_camera_transform(const TransformState *camera_transform)
Specifies the position of the camera relative to the starting node.
void set_inverted(bool inverted)
Changes the current setting of the inverted flag.
void set_camera_node(Camera *camera_node)
Specifies the camera used to render the scene.
Filename get_filename(ShaderType type=ST_none) const
Return the Shader's filename for the given shader type.
size_t get_total_size() const
Returns the total size of all objects currently active on the LRU.
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
get_image_modified
Returns a sequence number which is guaranteed to change at least every time the texture image data (i...
static AutoTextureScale get_textures_power_2()
This flag returns ATS_none, ATS_up, or ATS_down and controls the scaling of textures in general.
static void set_textures_power_2(AutoTextureScale scale)
Set this flag to ATS_none, ATS_up, ATS_down, or ATS_pad to control the scaling of textures in general...
static bool has_textures_power_2()
If true, then get_textures_power_2 has been set using set_textures_power_2.
A thread; that is, a lightweight process.
get_pipeline_stage
Returns the Pipeline stage number associated with this thread.
is_threading_supported
Returns true if threading support has been compiled in and enabled, or false if no threading is avail...
get_current_pipeline_stage
Returns the integer pipeline stage associated with the current thread.
static void consider_yield()
Possibly suspends the current thread for the rest of the current epoch, if it has run for enough this...
set_pipeline_stage
Specifies the Pipeline stage number associated with this thread.
is_true_threads
Returns true if a real threading library is available that supports actual OS-implemented threads,...
get_current_thread
Returns a pointer to the currently-executing Thread object.
static void prepare_for_exit()
Should be called by the main thread just before exiting the program, this blocks until any remaining ...
static void force_yield()
Suspends the current thread for the rest of the current epoch.
TypeHandle is the identifier used to differentiate C++ class types.
get_name
Returns the name of the type.
static SimpleLru * get_pending_lru()
Returns a pointer to the global LRU object that manages the VertexDataPage's that are pending process...
static void stop_threads()
Call this to stop the paging threads, if they were started.
static SimpleLru * get_global_lru(RamClass rclass)
Returns a pointer to the global LRU object that manages the VertexDataPage's with the indicated RamCl...
get_save_file
Returns the global VertexDataSaveFile that will be used to save vertex data buffers to disk when nece...
A temporary file to hold the vertex data that has been evicted from memory and written to disk.
size_t get_total_file_size() const
Returns the amount of space consumed by the save file, including unused portions.
size_t get_used_file_size() const
Returns the amount of space within the save file that is currently in use.
A container for the various kinds of properties we might ask to have on a graphics window before we o...
int get_y_size() const
Returns size in pixels in the y dimension of the useful part of the window, not including decorations...
int get_x_size() const
Returns size in pixels in the x dimension of the useful part of the window, not including decorations...
has_size
Returns true if the window size has been specified, false otherwise.
void reserve(size_type_0 n)
Informs the vector of a planned change in size; ensures that the capacity of the vector is greater th...
iterator_0 begin()
Returns the iterator that marks the first element in the ordered vector.
void push_back(const value_type_0 &key)
Adds the new element to the end of the vector without regard for proper sorting.
void swap(ordered_vector< Key, Compare, Vector > &other)
Exchanges the contents of this vector and the other vector, in constant time (e.g....
size_type_0 size() const
Returns the number of elements in the ordered vector.
bool empty() const
Returns true if the ordered vector is empty, false otherwise.
iterator_0 end()
Returns the iterator that marks the end of the ordered vector.
void sort()
Maps to sort_unique().
bool verify_list() const
Maps to verify_list_unique().
This is our own Panda specialization on the default STL map.
This is our own Panda specialization on the default STL vector.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.