52#if defined(_WIN32) && defined(HAVE_THREADS) && defined(SIMPLE_THREADS)
57 #define WINDOWS_LEAN_AND_MEAN
60 #undef WINDOWS_LEAN_AND_MEAN
65#if defined(__APPLE__) && !defined(CPPPARSER)
66#include <AvailabilityMacros.h>
68#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
70 void *objc_autoreleasePoolPush();
71 void objc_autoreleasePoolPop(
void *);
80PStatCollector GraphicsEngine::_wait_pcollector(
"Wait:Thread sync");
82PStatCollector GraphicsEngine::_app_pcollector(
"App:Show code:General");
83PStatCollector GraphicsEngine::_render_frame_pcollector(
"App:render_frame");
87PStatCollector GraphicsEngine::_cull_setup_pcollector(
"Cull:Setup");
92PStatCollector GraphicsEngine::_flip_begin_pcollector(
"Wait:Flip:Begin");
93PStatCollector GraphicsEngine::_flip_end_pcollector(
"Wait:Flip:End");
94PStatCollector GraphicsEngine::_transform_states_pcollector(
"TransformStates");
95PStatCollector GraphicsEngine::_transform_states_unused_pcollector(
"TransformStates:Unused");
96PStatCollector GraphicsEngine::_render_states_pcollector(
"RenderStates");
97PStatCollector GraphicsEngine::_render_states_unused_pcollector(
"RenderStates:Unused");
98PStatCollector GraphicsEngine::_cyclers_pcollector(
"PipelineCyclers");
99PStatCollector GraphicsEngine::_dirty_cyclers_pcollector(
"Dirty PipelineCyclers");
103PStatCollector GraphicsEngine::_sw_sprites_pcollector(
"SW Sprites");
104PStatCollector GraphicsEngine::_vertex_data_small_pcollector(
"Vertex Data:Small");
105PStatCollector GraphicsEngine::_vertex_data_independent_pcollector(
"Vertex Data:Independent");
106PStatCollector GraphicsEngine::_vertex_data_pending_pcollector(
"Vertex Data:Pending");
107PStatCollector GraphicsEngine::_vertex_data_resident_pcollector(
"Vertex Data:Resident");
108PStatCollector GraphicsEngine::_vertex_data_compressed_pcollector(
"Vertex Data:Compressed");
109PStatCollector GraphicsEngine::_vertex_data_unused_disk_pcollector(
"Vertex Data:Disk:Unused");
110PStatCollector GraphicsEngine::_vertex_data_used_disk_pcollector(
"Vertex Data:Disk:Used");
114PStatCollector GraphicsEngine::_cnode_volume_pcollector(
"Collision Volumes:CollisionNode");
115PStatCollector GraphicsEngine::_gnode_volume_pcollector(
"Collision Volumes:GeomNode");
116PStatCollector GraphicsEngine::_geom_volume_pcollector(
"Collision Volumes:Geom");
117PStatCollector GraphicsEngine::_node_volume_pcollector(
"Collision Volumes:PandaNode");
118PStatCollector GraphicsEngine::_volume_pcollector(
"Collision Volumes:CollisionSolid");
119PStatCollector GraphicsEngine::_test_pcollector(
"Collision Tests:CollisionSolid");
120PStatCollector GraphicsEngine::_volume_polygon_pcollector(
"Collision Volumes:CollisionPolygon");
121PStatCollector GraphicsEngine::_test_polygon_pcollector(
"Collision Tests:CollisionPolygon");
122PStatCollector GraphicsEngine::_volume_plane_pcollector(
"Collision Volumes:CollisionPlane");
123PStatCollector GraphicsEngine::_test_plane_pcollector(
"Collision Tests:CollisionPlane");
124PStatCollector GraphicsEngine::_volume_sphere_pcollector(
"Collision Volumes:CollisionSphere");
125PStatCollector GraphicsEngine::_test_sphere_pcollector(
"Collision Tests:CollisionSphere");
126PStatCollector GraphicsEngine::_volume_box_pcollector(
"Collision Volumes:CollisionBox");
127PStatCollector GraphicsEngine::_test_box_pcollector(
"Collision Tests:CollisionBox");
128PStatCollector GraphicsEngine::_volume_capsule_pcollector(
"Collision Volumes:CollisionCapsule");
129PStatCollector GraphicsEngine::_test_capsule_pcollector(
"Collision Tests:CollisionCapsule");
130PStatCollector GraphicsEngine::_volume_inv_sphere_pcollector(
"Collision Volumes:CollisionInvSphere");
131PStatCollector GraphicsEngine::_test_inv_sphere_pcollector(
"Collision Tests:CollisionInvSphere");
132PStatCollector GraphicsEngine::_volume_geom_pcollector(
"Collision Volumes:CollisionGeom");
133PStatCollector GraphicsEngine::_test_geom_pcollector(
"Collision Tests:CollisionGeom");
134PStatCollector GraphicsEngine::_occlusion_untested_pcollector(
"Occlusion results:Not tested");
135PStatCollector GraphicsEngine::_occlusion_passed_pcollector(
"Occlusion results:Visible");
136PStatCollector GraphicsEngine::_occlusion_failed_pcollector(
"Occlusion results:Occluded");
137PStatCollector GraphicsEngine::_occlusion_tests_pcollector(
"Occlusion tests");
146INLINE
static bool operator < (
const CullKey &a,
const CullKey &b) {
147 if (a._gsg != b._gsg) {
148 return a._gsg < b._gsg;
150 if (a._camera != b._camera) {
151 return a._camera < b._camera;
153 return a._lens_index < b._lens_index;
165 _lock(
"GraphicsEngine::_lock"),
166 _loaded_textures_lock(
"GraphicsEngine::_loaded_textures_lock")
168 if (_pipeline ==
nullptr) {
172 _windows_sorted =
true;
173 _window_sort_index = 0;
178 <<
"Using threading model " << _threading_model <<
"\n";
180 _auto_flip = auto_flip;
181 _portal_enabled =
false;
182 _flip_state = FS_flip;
184 _singular_warning_last_frame =
false;
185 _singular_warning_this_frame =
false;
195 if (_app_pcollector.is_started()) {
196 _app_pcollector.stop();
211 if (!threading_model.is_single_threaded()) {
212 display_cat.warning()
213 <<
"Threading model " << threading_model
214 <<
" requested but threading is not available. Ignoring.\n";
219#ifndef THREADED_PIPELINE
220 if (!threading_model.is_single_threaded()) {
221 display_cat.warning()
222 <<
"Threading model " << threading_model
223 <<
" requested but multithreaded render pipelines not enabled in build.\n";
224 if (!allow_nonpipeline_threads) {
225 display_cat.warning()
226 <<
"Ignoring requested threading model.\n";
229 display_cat.warning()
230 <<
"Danger! Creating requested render threads anyway!\n";
234 _threading_model = threading_model;
246 result = _threading_model;
269 const string &name,
int sort,
301 int x_size = 0, y_size = 0;
306 if ((x_size == 0)&&(y_size == 0)) {
307 flags |= GraphicsPipe::BF_size_track_host;
309 if (host !=
nullptr) {
317 if (host ==
nullptr) {
318 if (gsg !=
nullptr) {
327 if ((host->
get_gsg()==
nullptr)||
329 (!host->
get_gsg()->is_valid())||
330 (host->
get_gsg()->needs_reset())) {
333 if ((host->
get_gsg()==
nullptr)||
335 (!host->
get_gsg()->is_valid())||
336 (host->
get_gsg()->needs_reset())) {
346 nassertr(pipe !=
nullptr,
nullptr);
347 if (gsg !=
nullptr) {
348 nassertr(pipe == gsg->
get_pipe(),
nullptr);
353 if ((flags & GraphicsPipe::BF_require_callback_window)!=0) {
355 if (this_gsg ==
nullptr) {
358 this_gsg = pipe->make_callback_gsg(
this);
360 if (this_gsg !=
nullptr) {
362 window->_sort = sort;
363 do_add_window(window);
364 do_add_gsg(window->
get_gsg(), pipe);
365 display_cat.info() <<
"Created output of type CallbackGraphicsWindow\n";
376 bool can_use_parasite =
false;
377 if ((host !=
nullptr)&&
378 ((flags&GraphicsPipe::BF_require_window)==0)&&
379 ((flags&GraphicsPipe::BF_require_callback_window)==0)&&
380 ((flags&GraphicsPipe::BF_refuse_parasite)==0)&&
381 ((flags&GraphicsPipe::BF_can_bind_color)==0)&&
382 ((flags&GraphicsPipe::BF_can_bind_every)==0)&&
383 ((flags&GraphicsPipe::BF_rtt_cumulative)==0)&&
384 ((flags&GraphicsPipe::BF_can_bind_layered)==0)) {
385 if ((flags&GraphicsPipe::BF_fb_props_optional) ||
387 can_use_parasite =
true;
396 if ((prefer_parasite_buffer) &&
397 (can_use_parasite) &&
398 (x_size <= host->get_x_size())&&
399 (y_size <= host->get_y_size())&&
402 buffer->_sort = sort;
403 do_add_window(buffer);
404 do_add_gsg(host->
get_gsg(), pipe);
405 display_cat.info() <<
"Created output of type ParasiteBuffer\n";
412 if (force_parasite_buffer && can_use_parasite) {
414 buffer->_sort = sort;
415 do_add_window(buffer);
416 do_add_gsg(host->
get_gsg(), pipe);
417 display_cat.info() <<
"Created output of type ParasiteBuffer\n";
423 for (
int retry=0; retry<10; retry++) {
424 bool precertify =
false;
426 pipe->make_output(name, fb_prop, win_prop, flags,
this, gsg, host, retry, precertify);
427 if (window !=
nullptr) {
428 window->_sort = sort;
429 if (precertify && gsg !=
nullptr && window->
get_gsg() == gsg) {
430 do_add_window(window);
432 <<
"Created output of type " << window->get_type() <<
"\n";
435 do_add_window(window);
437 if (window->is_valid()) {
439 <<
"Created output of type " << window->get_type() <<
"\n";
441 if (window->get_fb_properties().subsumes(fb_prop)) {
444 if (flags & GraphicsPipe::BF_fb_props_optional) {
445 display_cat.warning()
446 <<
"FrameBufferProperties available less than requested.\n";
447 display_cat.warning(
false)
448 <<
" requested: " << fb_prop <<
"\n"
449 <<
" got: " << window->get_fb_properties() <<
"\n";
453 <<
"Could not get requested FrameBufferProperties; abandoning window.\n";
454 display_cat.error(
false)
455 <<
" requested: " << fb_prop <<
"\n"
456 <<
" got: " << window->get_fb_properties() <<
"\n";
460 << window->get_type() <<
" wouldn't open; abandoning.\n";
461 display_cat.debug(
false)
462 <<
" requested: " << fb_prop <<
"\n";
473 if (can_use_parasite) {
475 buffer->_sort = sort;
476 do_add_window(buffer);
477 do_add_gsg(host->
get_gsg(), pipe);
478 display_cat.info() <<
"Created output of type ParasiteBuffer\n";
501 nassertr(window !=
nullptr,
false);
502 nassertr(
this == window->
get_engine(),
false);
504 window->_sort = sort;
505 do_add_window(window);
508 <<
"Added output of type " << window->get_type() <<
"\n";
532 nassertr(window !=
nullptr,
false);
540 if (!_windows_sorted) {
543 count = _windows.erase(ptwin);
548 MutexHolder new_windows_holder(_new_windows_lock, current_thread);
549 size_t old_size = _new_windows.size();
550 _new_windows.erase(std::remove(_new_windows.begin(), _new_windows.end(), ptwin), _new_windows.end());
551 if (count == 0 && _new_windows.size() < old_size) {
561 do_remove_window(window, current_thread);
564 if (gsg !=
nullptr) {
566 if (pgo !=
nullptr) {
568 bool any_common =
false;
571 Windows::iterator wi;
572 for (wi = _windows.
begin(); wi != _windows.
end() && !any_common; ++wi) {
574 if (gsg2 !=
nullptr &&
591 nassertr(count == 1,
true);
610 old_windows.
swap(_windows);
612 nassertv(win !=
nullptr);
613 do_remove_window(win, current_thread);
615 if (gsg !=
nullptr) {
621 MutexHolder new_windows_holder(_new_windows_lock, current_thread);
623 nassertv(win !=
nullptr);
624 do_remove_window(win, current_thread);
626 if (gsg !=
nullptr) {
630 _new_windows.clear();
633 _app.do_close(
this, current_thread);
634 _app.do_pending(
this, current_thread);
635 terminate_threads(current_thread);
652 PStatClient::get_global_pstats()->
disconnect();
655#if defined(_WIN32) && defined(HAVE_THREADS) && defined(SIMPLE_THREADS)
658 WinInputDeviceManager::stop_thread();
672 Windows::iterator wi;
673 for (wi = _windows.
begin(); wi != _windows.
end(); ++wi) {
686 return _windows.
empty();
694 return _windows.
size();
702 nassertr(n >= 0 && n < (
int)_windows.
size(),
nullptr);
704 if (!_windows_sorted) {
726 _render_frame_pcollector.start();
727 if (_app_pcollector.is_started()) {
728 _app_pcollector.stop();
741 if (display_cat.is_spam()) {
743 <<
"render_frame() - frame " << global_clock->
get_frame_count() <<
"\n";
749 if (!_windows_sorted) {
753 if (sync_flip && _flip_state != FS_flip) {
754 do_flip_frame(current_thread);
760 Windows::iterator wi;
761 for (wi = _windows.
begin(); wi != _windows.
end(); ++wi) {
763 nassertv(win !=
nullptr);
765 do_remove_window(win, current_thread);
775 int num_drs = win->get_num_active_display_regions();
776 for (
int i = 0; i < num_drs; ++i) {
784 scene = camera_np.
get_top(current_thread);
787 scene.get_bounds(current_thread);
794 _windows.
swap(new_windows);
800 LoadedTextures::iterator lti;
801 for (lti = _loaded_textures.begin(); lti != _loaded_textures.end(); ++lti) {
802 LoadedTexture < = (*lti);
803 if (lt._tex->get_image_modified() == lt._image_modified) {
804 lt._tex->texture_uploaded();
807 _loaded_textures.clear();
812 _app.do_frame(
this, current_thread);
817 PStatTimer timer(_wait_pcollector, current_thread);
818 Threads::const_iterator ti;
819 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
820 RenderThread *thread = (*ti).second;
823 while (thread->_thread_state != TS_wait) {
824 thread->_cv_done.
wait();
829#if defined(THREADED_PIPELINE) && defined(DO_PSTATS)
830 _cyclers_pcollector.set_level(_pipeline->get_num_cyclers());
831 _dirty_cyclers_pcollector.set_level(_pipeline->get_num_dirty_cyclers());
835 _pipeline->iterate_all_cycler_types(pstats_count_cycler_type,
this);
836 _pipeline->iterate_dirty_cycler_types(pstats_count_dirty_cycler_type,
this);
845 TransformState::flush_level();
849#ifdef THREADED_PIPELINE
851 PStatTimer timer(_cycle_pcollector, current_thread);
856 global_clock->
tick(current_thread);
858 throw_event(
"clock_error");
862 PStatClient::main_tick();
865 CullTraverser::_nodes_pcollector.clear_level();
866 CullTraverser::_geom_nodes_pcollector.clear_level();
867 CullTraverser::_geoms_pcollector.clear_level();
868 GeomCacheManager::_geom_cache_active_pcollector.clear_level();
869 GeomCacheManager::_geom_cache_record_pcollector.clear_level();
870 GeomCacheManager::_geom_cache_erase_pcollector.clear_level();
871 GeomCacheManager::_geom_cache_evict_pcollector.clear_level();
873 GraphicsStateGuardian::init_frame_pstats();
875 _transform_states_pcollector.set_level(TransformState::get_num_states());
877 if (pstats_unused_states) {
878 _transform_states_unused_pcollector.set_level(TransformState::get_num_unused_states());
882 _sw_sprites_pcollector.clear_level();
884 _cnode_volume_pcollector.clear_level();
885 _gnode_volume_pcollector.clear_level();
886 _geom_volume_pcollector.clear_level();
887 _node_volume_pcollector.clear_level();
888 _volume_pcollector.clear_level();
889 _test_pcollector.clear_level();
890 _volume_polygon_pcollector.clear_level();
891 _test_polygon_pcollector.clear_level();
892 _volume_plane_pcollector.clear_level();
893 _test_plane_pcollector.clear_level();
894 _volume_sphere_pcollector.clear_level();
895 _test_sphere_pcollector.clear_level();
896 _volume_box_pcollector.clear_level();
897 _test_box_pcollector.clear_level();
898 _volume_capsule_pcollector.clear_level();
899 _test_capsule_pcollector.clear_level();
900 _volume_inv_sphere_pcollector.clear_level();
901 _test_inv_sphere_pcollector.clear_level();
902 _volume_geom_pcollector.clear_level();
903 _test_geom_pcollector.clear_level();
904 _occlusion_untested_pcollector.clear_level();
905 _occlusion_passed_pcollector.clear_level();
906 _occlusion_failed_pcollector.clear_level();
907 _occlusion_tests_pcollector.clear_level();
920 _vertex_data_small_pcollector.set_level(small_buf);
921 _vertex_data_independent_pcollector.set_level(independent);
922 _vertex_data_pending_pcollector.set_level(pending);
923 _vertex_data_resident_pcollector.set_level(resident);
924 _vertex_data_compressed_pcollector.set_level(compressed);
925 _vertex_data_unused_disk_pcollector.set_level(total_disk - used_disk);
926 _vertex_data_used_disk_pcollector.set_level(used_disk);
934 Threads::const_iterator ti;
935 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
936 RenderThread *thread = (*ti).second;
937 if (thread->_thread_state == TS_wait) {
938 thread->_thread_state = TS_do_frame;
939 thread->_cv_start.
notify();
946 _flip_state = _auto_flip ? FS_flip : FS_draw;
951 if (yield_timeslice) {
954 PStatTimer timer(_yield_pcollector, current_thread);
957 PStatTimer timer(_yield_pcollector, current_thread);
963 _app_pcollector.start();
964 _render_frame_pcollector.stop();
983 MutexHolder new_windows_holder(_new_windows_lock, current_thread);
984 if (_new_windows.empty()) {
988 for (
auto it = _new_windows.begin(); it != _new_windows.end(); ++it) {
991 WindowRenderer *cull =
994 WindowRenderer *draw =
999 cull->add_window(cull->_cull, window);
1000 draw->add_window(draw->_draw, window);
1002 cull->add_window(cull->_cdraw, window);
1014 switch (window->
get_pipe()->get_preferred_window_thread()) {
1015 case GraphicsPipe::PWT_app:
1016 _app.add_window(_app._window, window);
1019 case GraphicsPipe::PWT_draw:
1020 draw->add_window(draw->_window, window);
1028 new_windows.swap(_new_windows);
1031 do_resort_windows();
1034 for (
int i = 0; i < 2; ++i) {
1035 _app.do_windows(
this, current_thread);
1036 _app.do_pending(
this, current_thread);
1038 PStatTimer timer(_wait_pcollector, current_thread);
1039 Threads::const_iterator ti;
1040 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
1041 RenderThread *thread = (*ti).second;
1044 while (thread->_thread_state != TS_wait) {
1045 thread->_cv_done.
wait();
1048 thread->_thread_state = TS_do_windows;
1049 thread->_cv_start.
notify();
1055 for (
auto it = new_windows.begin(); it != new_windows.end(); ++it) {
1076 if (_flip_state == FS_draw) {
1077 do_sync_frame(current_thread);
1097 if (_flip_state == FS_draw) {
1098 do_ready_flip(current_thread);
1112 if (_flip_state != FS_flip) {
1113 do_flip_frame(current_thread);
1143 if (draw_name.empty()) {
1150 WindowRenderer *wr = get_window_renderer(draw_name, 0);
1151 RenderThread *thread = (RenderThread *)wr;
1154 while (thread->_thread_state != TS_wait) {
1155 thread->_cv_done.
wait();
1165 thread->_texture = tex;
1166 thread->_thread_state = TS_do_extract;
1167 thread->_cv_start.
notify();
1172 while (thread->_thread_state != TS_wait) {
1173 thread->_cv_done.
wait();
1177 thread->_gsg =
nullptr;
1178 thread->_texture =
nullptr;
1179 return thread->_result;
1198 const Shader *shader = sattr->get_shader();
1199 nassertv(shader !=
nullptr);
1200 nassertv(gsg !=
nullptr);
1204 CPT(
RenderState) state = RenderState::make(sattr);
1207 if (draw_name.empty()) {
1212 gsg->pop_group_marker();
1217 WindowRenderer *wr = get_window_renderer(draw_name, 0);
1218 RenderThread *thread = (RenderThread *)wr;
1221 while (thread->_thread_state != TS_wait) {
1222 thread->_cv_done.
wait();
1232 thread->_state = state.p();
1233 thread->_work_groups = work_groups;
1234 thread->_thread_state = TS_do_compute;
1235 thread->_cv_start.
notify();
1240 while (thread->_thread_state != TS_wait) {
1241 thread->_cv_done.
wait();
1245 thread->_gsg =
nullptr;
1246 thread->_state =
nullptr;
1255 if (_global_ptr ==
nullptr) {
1276 _loaded_textures.push_back(LoadedTexture());
1277 LoadedTexture < = _loaded_textures.back();
1294 WindowRenderer *wr = get_window_renderer(draw_name, 0);
1295 RenderThread *thread = (RenderThread *)wr;
1298 while (thread->_thread_state != TS_wait) {
1299 thread->_cv_done.wait();
1303 thread->_region = region;
1304 thread->_thread_state = TS_do_screenshot;
1305 thread->_cv_start.notify();
1306 thread->_cv_mutex.release();
1307 thread->_cv_mutex.acquire();
1310 while (thread->_thread_state != TS_wait) {
1311 thread->_cv_done.wait();
1314 PT(
Texture) tex = std::move(thread->_texture);
1315 thread->_region =
nullptr;
1316 thread->_texture =
nullptr;
1334 if (view_frustum_cull) {
1342 if (bv !=
nullptr && !bv->is_infinite() &&
1343 bv->as_geometric_bounding_volume() !=
nullptr) {
1346 local_frustum = bv->make_copy()->as_geometric_bounding_volume();
1347 nassertv(!local_frustum.is_null());
1352 local_frustum->xform(cull_center_transform->get_mat());
1367bool GraphicsEngine::
1369 return _global_ptr->is_scene_root(node);
1376bool GraphicsEngine::
1380 Windows::const_iterator wi;
1381 for (wi = _windows.
begin(); wi != _windows.
end(); ++wi) {
1384 int num_display_regions = win->get_num_active_display_regions();
1385 for (
int i = 0; i < num_display_regions; i++) {
1387 if (dr !=
nullptr) {
1394 DCAST_INTO_R(camera_node, camera.
node(),
false);
1404 scene_root = camera.
get_top(current_thread);
1407 if (scene_root.
node() == node) {
1424void GraphicsEngine::
1427 window->_sort = sort;
1428 _windows_sorted =
false;
1437void GraphicsEngine::
1439 Thread *current_thread) {
1440 PStatTimer timer(_cull_pcollector, current_thread);
1442 size_t wlist_size = wlist.
size();
1443 for (
size_t wi = 0; wi < wlist_size; ++wi) {
1447 if (display_cat.is_spam()) {
1449 <<
"Flipping window " << win->
get_name() <<
"\n";
1452 PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
1456 PStatTimer timer(GraphicsEngine::_flip_end_pcollector, current_thread);
1461 if (win->
begin_frame(GraphicsOutput::FM_render, current_thread)) {
1465 gsg->push_group_marker(
"Clear");
1466 win->
clear(current_thread);
1467 gsg->pop_group_marker();
1470 if (display_cat.is_spam()) {
1472 <<
"Culling and drawing window " << win->
get_name() <<
"\n";
1475 int num_display_regions = win->get_num_active_display_regions();
1476 for (
int i = 0; i < num_display_regions; i++) {
1478 if (dr !=
nullptr) {
1479 cull_and_draw_together(win, dr, current_thread);
1482 win->
end_frame(GraphicsOutput::FM_render, current_thread);
1486 if (display_cat.is_spam()) {
1488 <<
"Flipping window " << win->
get_name() <<
"\n";
1491 PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
1495 PStatTimer timer(GraphicsEngine::_flip_end_pcollector, current_thread);
1508void GraphicsEngine::
1510 Thread *current_thread) {
1512 nassertv(gsg !=
nullptr);
1523 if (dr_reader.is_any_clear_active()) {
1528 scene_setup = setup_scene(gsg, &dr_reader);
1531 if (scene_setup ==
nullptr) {
1537 }
else if (!gsg->
set_scene(scene_setup)) {
1540 << gsg->get_type() <<
" cannot render scene with specified lens.\n";
1546 if (cbobj !=
nullptr) {
1555 dr->do_cull(&cull_handler, scene_setup, gsg, current_thread);
1562 gsg->pop_group_marker();
1570void GraphicsEngine::
1572 PStatTimer timer(_cull_pcollector, current_thread);
1574 _singular_warning_last_frame = _singular_warning_this_frame;
1575 _singular_warning_this_frame =
false;
1580 AlreadyCulled already_culled;
1582 size_t wlist_size = wlist.
size();
1583 for (
size_t wi = 0; wi < wlist_size; ++wi) {
1586 if (display_cat.is_spam()) {
1588 <<
"Culling window " << win->
get_name() <<
"\n";
1593 int num_display_regions = win->get_num_active_display_regions();
1594 for (
int i = 0; i < num_display_regions; ++i) {
1596 if (dr !=
nullptr) {
1601 PStatTimer timer(_cull_setup_pcollector, current_thread);
1603 scene_setup = setup_scene(gsg, &dr_reader);
1604 if (scene_setup ==
nullptr) {
1609 key._camera = dr_reader.get_camera();
1610 key._lens_index = dr_reader.get_lens_index();
1613 AlreadyCulled::iterator aci = already_culled.insert(AlreadyCulled::value_type(std::move(key),
nullptr)).first;
1614 if ((*aci).second ==
nullptr) {
1618 if (cull_result !=
nullptr) {
1619 cull_result = cull_result->make_next();
1625 cull_to_bins(win, gsg, dr, scene_setup, cull_result, current_thread);
1639 dr->
set_cull_result(std::move(cull_result), MOVE(scene_setup), current_thread);
1649void GraphicsEngine::
1656 if (cbobj !=
nullptr) {
1665 dr->do_cull(&cull_handler, scene_setup, gsg, current_thread);
1668 PStatTimer timer(_cull_sort_pcollector, current_thread);
1669 cull_result->
finish_cull(scene_setup, current_thread);
1677void GraphicsEngine::
1681 size_t wlist_size = wlist.
size();
1682 for (
size_t wi = 0; wi < wlist_size; ++wi) {
1690 if (display_cat.is_spam()) {
1692 <<
"Flipping window " << host->
get_name()
1693 <<
" before drawing window " << win->
get_name() <<
"\n";
1698 PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
1702 PStatTimer timer(GraphicsEngine::_flip_end_pcollector, current_thread);
1707 if (win->
begin_frame(GraphicsOutput::FM_render, current_thread)) {
1714 win->
get_gsg()->push_group_marker(
"Clear");
1715 win->
clear(current_thread);
1716 win->
get_gsg()->pop_group_marker();
1719 if (display_cat.is_spam()) {
1721 <<
"Drawing window " << win->
get_name() <<
"\n";
1723 int num_display_regions = win->get_num_active_display_regions();
1724 for (
int i = 0; i < num_display_regions; ++i) {
1726 if (dr !=
nullptr) {
1727 do_draw(win, gsg, dr, current_thread);
1731 win->
end_frame(GraphicsOutput::FM_render, current_thread);
1737 gsg->issue_timer_query(GraphicsStateGuardian::_command_latency_pcollector.get_index());
1742 if (display_cat.is_spam()) {
1744 <<
"Flipping window " << win->
get_name() <<
"\n";
1749 PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
1753 PStatGPUTimer timer(gsg, GraphicsEngine::_flip_end_pcollector, current_thread);
1760 if (display_cat.is_spam()) {
1762 <<
"Not drawing window " << win->
get_name() <<
"\n";
1767 if (display_cat.is_spam()) {
1769 <<
"Window " << win->
get_name() <<
" is inactive\n";
1779void GraphicsEngine::
1781 Windows::const_iterator wi;
1782 for (wi = wlist.
begin(); wi != wlist.
end(); ++wi) {
1784 if (win->
begin_frame(GraphicsOutput::FM_refresh, current_thread)) {
1785 win->
end_frame(GraphicsOutput::FM_refresh, current_thread);
1795void GraphicsEngine::
1800 for (
size_t i = 0; i < wlist.
size(); ++i) {
1801 wlist[i]->process_events();
1810void GraphicsEngine::
1812 size_t num_windows = wlist.
size();
1814 size_t warray_count = 0;
1818 for (i = 0; i < num_windows; ++i) {
1821 if (display_cat.is_spam()) {
1823 <<
"Flipping window " << win->
get_name() <<
"\n";
1826 nassertv(warray_count < num_windows);
1827 warray[warray_count] = win;
1830 PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
1835 for (i = 0; i < warray_count; ++i) {
1837 PStatTimer timer(GraphicsEngine::_flip_end_pcollector, current_thread);
1847void GraphicsEngine::
1849 Windows::const_iterator wi;
1850 for (wi = wlist.
begin(); wi != wlist.
end(); ++wi) {
1853 PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
1863void GraphicsEngine::
1864do_sync_frame(
Thread *current_thread) {
1868 PStatTimer timer(_sync_pcollector, current_thread);
1870 nassertv(_flip_state == FS_draw);
1874 Threads::const_iterator ti;
1875 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
1876 RenderThread *thread = (*ti).second;
1877 thread->_cv_mutex.acquire();
1878 thread->_cv_mutex.release();
1881 _flip_state = FS_sync;
1888void GraphicsEngine::
1889do_ready_flip(
Thread *current_thread) {
1893 PStatTimer timer(_sync_pcollector, current_thread);
1895 nassertv(_flip_state == FS_draw);
1899 Threads::const_iterator ti;
1900 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
1901 RenderThread *thread = (*ti).second;
1902 thread->_cv_mutex.acquire();
1903 thread->_cv_mutex.release();
1905 _app.do_ready_flip(
this,current_thread);
1906 _flip_state = FS_sync;
1913void GraphicsEngine::
1914do_flip_frame(
Thread *current_thread) {
1918 PStatTimer timer(_flip_pcollector, current_thread);
1920 nassertv(_flip_state == FS_draw || _flip_state == FS_sync);
1926 PStatTimer timer(_wait_pcollector, current_thread);
1927 Threads::const_iterator ti;
1928 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
1929 RenderThread *thread = (*ti).second;
1930 thread->_cv_mutex.acquire();
1932 while (thread->_thread_state != TS_wait) {
1933 thread->_cv_done.wait();
1939 _app.do_flip(
this, current_thread);
1942 Threads::const_iterator ti;
1943 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
1944 RenderThread *thread = (*ti).second;
1945 nassertv(thread->_thread_state == TS_wait);
1946 thread->_thread_state = TS_do_flip;
1947 thread->_cv_start.notify();
1948 thread->_cv_mutex.release();
1952 _flip_state = FS_flip;
1962 Thread *current_thread = dr->get_current_thread();
1963 PStatTimer timer(_cull_setup_pcollector, current_thread);
1968 nassertr(window !=
nullptr,
nullptr);
1977 DCAST_INTO_R(camera_node, camera.
node(),
nullptr);
1997 scene_root = camera.
get_top(current_thread);
2013 if (camera_transform->is_invalid()) {
2015 if (!_singular_warning_last_frame) {
2016 display_cat.warning()
2017 <<
"Scene " << scene_root <<
" has net scale ("
2019 _singular_warning_this_frame =
true;
2024 if (world_transform->is_invalid()) {
2026 if (!_singular_warning_last_frame) {
2027 display_cat.warning()
2028 <<
"Camera " << camera <<
" has net scale ("
2031 _singular_warning_this_frame =
true;
2035 CPT(
RenderState) initial_state = camera_node->get_initial_state();
2045 initial_state = initial_state->compose(get_invert_polygon_state());
2054 scene_setup->set_initial_state(initial_state);
2061 CPT(
TransformState) cs_world_transform = cs_transform->compose(world_transform);
2070void GraphicsEngine::
2081 cull_result = cdata->_cull_result;
2082 scene_setup = cdata->_scene_setup;
2091 if (dr_reader.is_any_clear_active()) {
2093 gsg->
clear(dr_reader.get_object());
2096 cbobj = dr_reader.get_draw_callback();
2099 if (cbobj !=
nullptr) {
2104 static CPT(
RenderState) state = RenderState::make(
2105 DepthTestAttrib::make(DepthTestAttrib::M_none));
2115 }
else if (cull_result ==
nullptr || scene_setup ==
nullptr) {
2125 }
else if (!gsg->
set_scene(scene_setup)) {
2128 << gsg->get_type() <<
" cannot render scene with specified lens.\n";
2132 cull_result->
draw(current_thread);
2137 gsg->pop_group_marker();
2145void GraphicsEngine::
2147 nassertv(window !=
nullptr);
2154 window->_internal_sort_index = _window_sort_index;
2155 ++_window_sort_index;
2157 if (display_cat.is_debug()) {
2159 <<
"Created " << window->get_type() <<
" " << (
void *)window <<
"\n";
2163 _new_windows.push_back(window);
2171void GraphicsEngine::
2173 nassertv(gsg !=
nullptr);
2177 gsg->_threading_model = _threading_model;
2178 if (!_default_loader.is_null()) {
2182 auto_adjust_capabilities(gsg);
2184 WindowRenderer *draw =
2196void GraphicsEngine::
2198 nassertv(window !=
nullptr);
2202 if (!_windows_sorted) {
2203 do_resort_windows();
2207 _app.remove_window(window);
2208 Threads::const_iterator ti;
2209 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
2210 RenderThread *thread = (*ti).second;
2211 thread->remove_window(window);
2216 _app.do_pending(
this, current_thread);
2218 if (display_cat.is_debug()) {
2220 <<
"Removed " << window->get_type() <<
" " << (
void *)window <<
"\n";
2228void GraphicsEngine::
2229do_resort_windows() {
2230 _windows_sorted =
true;
2232 if (display_cat.is_spam()) {
2234 <<
"Re-sorting window list.\n";
2237 _app.resort_windows();
2238 Threads::const_iterator ti;
2239 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
2240 RenderThread *thread = (*ti).second;
2241 thread->resort_windows();
2267void GraphicsEngine::
2289 if (textures_auto_power_2 && (textures_power_2 == ATS_none)) {
2291 <<
"Invalid panda config file: if you set the config-variable\n"
2292 <<
"textures_auto_power_2 to true, you must set the config-variable"
2293 <<
"textures_power_2 to 'up' or 'down'.\n";
2294 textures_power_2 = ATS_down;
2311 <<
"The 'textures_power_2' configuration is set to 'none', meaning \n"
2312 <<
"that non-power-of-two texture support is required, but the video \n"
2313 <<
"driver I'm trying to use does not support non-power-of-two textures.\n";
2315 if (textures_power_2 != ATS_none) {
2317 <<
"The 'none' did not come from the config file. In other words,\n"
2318 <<
"the variable 'textures_power_2' was altered procedurally.\n";
2320 if (textures_auto_power_2) {
2322 <<
"It is possible that it was set by panda's automatic mechanisms,\n"
2323 <<
"which are currently enabled, because 'textures_auto_power_2' is\n"
2324 <<
"true. Panda's automatic mechanisms assume that if one\n"
2325 <<
"window supports non-power-of-two textures, then they all will.\n"
2326 <<
"This assumption works for most games, but not all.\n"
2327 <<
"In particular, it can fail if the game creates multiple windows\n"
2328 <<
"on multiple displays with different video cards.\n";
2337void GraphicsEngine::
2338terminate_threads(
Thread *current_thread) {
2343 PStatTimer timer(_wait_pcollector, current_thread);
2347 Threads::const_iterator ti;
2348 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
2349 RenderThread *thread = (*ti).second;
2350 thread->_cv_mutex.acquire();
2354 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
2355 RenderThread *thread = (*ti).second;
2356 thread->_thread_state = TS_terminate;
2357 thread->_cv_start.notify();
2358 thread->_cv_mutex.release();
2362 for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
2363 RenderThread *thread = (*ti).second;
2376void GraphicsEngine::
2377pstats_count_cycler_type(
TypeHandle type,
int count,
void *data) {
2379 CyclerTypeCounters::iterator ci = self->_all_cycler_types.find(type);
2380 if (ci == self->_all_cycler_types.end()) {
2382 ci = self->_all_cycler_types.insert(CyclerTypeCounters::value_type(type, collector)).first;
2384 (*ci).second.set_level(count);
2393void GraphicsEngine::
2394pstats_count_dirty_cycler_type(
TypeHandle type,
int count,
void *data) {
2396 CyclerTypeCounters::iterator ci = self->_dirty_cycler_types.find(type);
2397 if (ci == self->_dirty_cycler_types.end()) {
2399 ci = self->_dirty_cycler_types.insert(CyclerTypeCounters::value_type(type, collector)).first;
2401 (*ci).second.set_level(count);
2411get_invert_polygon_state() {
2415 if (state ==
nullptr) {
2416 state = RenderState::make(CullFaceAttrib::make_reverse());
2430GraphicsEngine::WindowRenderer *GraphicsEngine::
2431get_window_renderer(
const string &name,
int pipeline_stage) {
2438 Threads::iterator ti = _threads.find(name);
2439 if (ti != _threads.end()) {
2440 return (*ti).second.p();
2443 PT(RenderThread) thread =
new RenderThread(name,
this);
2444 thread->set_min_pipeline_stage(pipeline_stage);
2447 bool started = thread->start(TP_normal,
true);
2448 nassertr(started, thread.p());
2449 _threads[name] = thread;
2451 nassertr(thread->get_pipeline_stage() < _pipeline->
get_num_stages(), thread.p());
2459GraphicsEngine::WindowRenderer::
2460WindowRenderer(
const string &name) :
2461 _wl_lock(string(
"GraphicsEngine::WindowRenderer::_wl_lock ") + name)
2468void GraphicsEngine::WindowRenderer::
2478void GraphicsEngine::WindowRenderer::
2481 wlist.insert(window);
2489void GraphicsEngine::WindowRenderer::
2491 nassertv(window !=
nullptr);
2496 _cdraw.erase(ptwin);
2499 Windows::iterator wi;
2501 wi = _window.find(ptwin);
2502 if (wi != _window.end()) {
2512 if (ptwin->is_valid()) {
2513 _pending_close.push_back(ptwin);
2523void GraphicsEngine::WindowRenderer::
2532 if (display_cat.is_debug()) {
2534 <<
"Windows resorted:";
2535 Windows::const_iterator wi;
2536 for (wi = _window.begin(); wi != _window.end(); ++wi) {
2538 display_cat.debug(
false)
2541 display_cat.debug(
false)
2544 for (wi = _draw.begin(); wi != _draw.end(); ++wi) {
2546 display_cat.debug(
false)
2549 display_cat.debug(
false)
2559void GraphicsEngine::WindowRenderer::
2561 PStatTimer timer(engine->_do_frame_pcollector, current_thread);
2564#if defined(__APPLE__) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
2566 void *pool = objc_autoreleasePoolPush();
2569 engine->cull_to_bins(_cull, current_thread);
2570 engine->cull_and_draw_together(_cdraw, current_thread);
2571 engine->draw_bins(_draw, current_thread);
2572 engine->process_events(_window, current_thread);
2574#if defined(__APPLE__) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
2575 objc_autoreleasePoolPop(pool);
2580 if (any_done_gsgs()) {
2583 for (gi = _gsgs.begin(); gi != _gsgs.end(); ++gi) {
2588 engine->close_gsg(pipe, gsg);
2591 new_gsgs.insert(gsg);
2595 _gsgs.swap(new_gsgs);
2605void GraphicsEngine::WindowRenderer::
2609#if defined(__APPLE__) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
2610 void *pool = objc_autoreleasePoolPush();
2613 engine->process_events(_window, current_thread);
2615 engine->make_contexts(_cdraw, current_thread);
2616 engine->make_contexts(_draw, current_thread);
2618#if defined(__APPLE__) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
2619 objc_autoreleasePoolPop(pool);
2626void GraphicsEngine::WindowRenderer::
2629 engine->flip_windows(_cdraw, current_thread);
2630 engine->flip_windows(_draw, current_thread);
2636void GraphicsEngine::WindowRenderer::
2639 engine->ready_flip_windows(_cdraw, current_thread);
2640 engine->ready_flip_windows(_draw, current_thread);
2647void GraphicsEngine::WindowRenderer::
2650 Windows::iterator wi;
2651 for (wi = _window.begin(); wi != _window.end(); ++wi) {
2659 for (gi = _gsgs.begin(); gi != _gsgs.end(); ++gi) {
2664 engine->close_gsg(pipe, gsg);
2667 new_gsgs.insert(gsg);
2671 _gsgs.swap(new_gsgs);
2678void GraphicsEngine::WindowRenderer::
2682 if (!_pending_close.empty()) {
2683 if (display_cat.is_debug()) {
2685 <<
"_pending_close.size() = " << _pending_close.size() <<
"\n";
2691 Windows::iterator wi;
2692 Windows pending_close;
2693 _pending_close.
swap(pending_close);
2694 for (wi = pending_close.begin(); wi != pending_close.end(); ++wi) {
2706bool GraphicsEngine::WindowRenderer::
2707any_done_gsgs()
const {
2708 GSGs::const_iterator gi;
2709 for (gi = _gsgs.begin(); gi != _gsgs.end(); ++gi) {
2710 if ((*gi)->get_ref_count() == 1) {
2721GraphicsEngine::RenderThread::
2724 WindowRenderer(name),
2726 _cv_mutex(string(
"GraphicsEngine::RenderThread ") + name),
2727 _cv_start(_cv_mutex),
2730 _thread_state = TS_wait;
2737void GraphicsEngine::RenderThread::
2745 switch (_thread_state) {
2750 do_pending(_engine, current_thread);
2751 do_frame(_engine, current_thread);
2755 do_flip(_engine, current_thread);
2759 do_pending(_engine, current_thread);
2763 do_windows(_engine, current_thread);
2764 do_pending(_engine, current_thread);
2768 nassertd(_gsg !=
nullptr && _state !=
nullptr) break;
2771 _state->get_attrib(sattr);
2772 _gsg->push_group_marker(std::string(
"Compute ") + sattr->get_shader()->get_filename(Shader::ST_compute).get_basename());
2775 _gsg->pop_group_marker();
2780 nassertd(_gsg !=
nullptr && _texture !=
nullptr) break;
2784 case TS_do_screenshot:
2785 nassertd(_region !=
nullptr) break;
2786 _texture = _region->get_screenshot();
2790 do_pending(_engine, current_thread);
2791 do_close(_engine, current_thread);
2792 _thread_state = TS_done;
2802 _thread_state = TS_wait;
2806 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.