diff --git a/dtool/Config.pp b/dtool/Config.pp index e4416c6601..f7ff395575 100644 --- a/dtool/Config.pp +++ b/dtool/Config.pp @@ -714,7 +714,8 @@ // This gives you control over when the context switch happens, and // may make mutexes unnecessary, if you are somewhat careful in your // code design. Disabling mutexes saves a tiny bit of runtime and -// memory overhead. +// memory overhead. NOT RECOMMENDED! Many internal Panda functions +// aren't quite secure enough to enable this mode for now. #define SIMPLE_THREADS_NO_MUTEX // Whether threading is defined or not, you might want to validate the diff --git a/panda/src/chan/bindAnimRequest.I b/panda/src/chan/bindAnimRequest.I index 65617eb973..ed221a11fd 100644 --- a/panda/src/chan/bindAnimRequest.I +++ b/panda/src/chan/bindAnimRequest.I @@ -19,11 +19,12 @@ // Description: //////////////////////////////////////////////////////////////////// INLINE BindAnimRequest:: -BindAnimRequest(const Filename &filename, const LoaderOptions &options, +BindAnimRequest(const string &name, + const Filename &filename, const LoaderOptions &options, Loader *loader, AnimControl *control, int hierarchy_match_flags, const PartSubset &subset) : - ModelLoadRequest(filename, options, loader), + ModelLoadRequest(name, filename, options, loader), _control(control), _hierarchy_match_flags(hierarchy_match_flags), _subset(subset) diff --git a/panda/src/chan/bindAnimRequest.h b/panda/src/chan/bindAnimRequest.h index d4d2e6dccf..4292c365cd 100644 --- a/panda/src/chan/bindAnimRequest.h +++ b/panda/src/chan/bindAnimRequest.h @@ -33,7 +33,8 @@ public: ALLOC_DELETED_CHAIN(BindAnimRequest); PUBLISHED: - INLINE BindAnimRequest(const Filename &filename, + INLINE BindAnimRequest(const string &name, + const Filename &filename, const LoaderOptions &options, Loader *loader, AnimControl *control, diff --git a/panda/src/chan/partBundle.cxx b/panda/src/chan/partBundle.cxx index f50455d6f1..317b16b2f6 100644 --- a/panda/src/chan/partBundle.cxx +++ b/panda/src/chan/partBundle.cxx @@ -363,7 +363,8 @@ load_bind_anim(Loader *loader, const Filename &filename, } PT(BindAnimRequest) request = - new BindAnimRequest(filename, anim_options, loader, control, + new BindAnimRequest(string("bind:") + filename.get_basename(), + filename, anim_options, loader, control, hierarchy_match_flags, subset); loader->load_async(request); diff --git a/panda/src/collide/collisionNode.cxx b/panda/src/collide/collisionNode.cxx index f09ae12fdf..947a9f6068 100644 --- a/panda/src/collide/collisionNode.cxx +++ b/panda/src/collide/collisionNode.cxx @@ -307,7 +307,9 @@ set_from_collide_mask(CollideMask mask) { // thing. //////////////////////////////////////////////////////////////////// void CollisionNode:: -compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage, +compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, + int &internal_vertices, + int pipeline_stage, Thread *current_thread) const { pvector child_volumes_ref; pvector child_volumes; @@ -345,9 +347,8 @@ compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage, ((BoundingVolume *)gbv)->around(child_begin, child_end); } - bdata->_internal_bounds = gbv; - bdata->_internal_vertices = 0; - bdata->_internal_bounds_stale = false; + internal_bounds = gbv; + internal_vertices = 0; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/collide/collisionNode.h b/panda/src/collide/collisionNode.h index f083b5aa59..23a8d82c33 100644 --- a/panda/src/collide/collisionNode.h +++ b/panda/src/collide/collisionNode.h @@ -71,7 +71,9 @@ PUBLISHED: INLINE static CollideMask get_default_collide_mask(); protected: - virtual void compute_internal_bounds(BoundsData *bdata, int pipeline_stage, + virtual void compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, + int &internal_vertices, + int pipeline_stage, Thread *current_thread) const; private: diff --git a/panda/src/collide/config_collide.cxx b/panda/src/collide/config_collide.cxx index b6751477d4..68b1754418 100644 --- a/panda/src/collide/config_collide.cxx +++ b/panda/src/collide/config_collide.cxx @@ -26,6 +26,7 @@ #include "collisionInvSphere.h" #include "collisionLine.h" #include "collisionLevelStateBase.h" +#include "collisionGeom.h" #include "collisionNode.h" #include "collisionParabola.h" #include "collisionPlane.h" @@ -129,6 +130,7 @@ init_libcollide() { CollisionInvSphere::init_type(); CollisionLine::init_type(); CollisionLevelStateBase::init_type(); + CollisionGeom::init_type(); CollisionNode::init_type(); CollisionParabola::init_type(); CollisionPlane::init_type(); diff --git a/panda/src/display/config_display.cxx b/panda/src/display/config_display.cxx index 58f454aed9..24f579f70a 100644 --- a/panda/src/display/config_display.cxx +++ b/panda/src/display/config_display.cxx @@ -206,13 +206,14 @@ ConfigVariableBool alpha_scale_via_texture "color-scale-via-lighting.")); ConfigVariableBool allow_incomplete_render -("allow-incomplete-render", false, +("allow-incomplete-render", true, PRC_DESC("When this is true, the frame may be rendered even if some of the " - "geometry in the scene has been paged out. The nonresident " - "geometry will be rendered as soon as it can be paged back in, " + "geometry in the scene has been paged out, or if the textures are " + "unavailable. The nonresident geometry and textures will be " + "rendered as soon as they can be read from disk, " "which may be several frames in the future. When this is false, " - "geometry is always paged in when needed, holding up the frame " - "render if necessary.")); + "geometry is always paged in immediately when needed, holding up " + "the frame render if necessary.")); ConfigVariableInt win_size ("win-size", "640 480", diff --git a/panda/src/display/graphicsEngine.cxx b/panda/src/display/graphicsEngine.cxx index 5356f7b7e5..3e2d97b9b3 100644 --- a/panda/src/display/graphicsEngine.cxx +++ b/panda/src/display/graphicsEngine.cxx @@ -610,191 +610,195 @@ render_frame() { << "render_frame() - frame " << global_clock->get_frame_count() << "\n"; } - ReMutexHolder holder(_lock, current_thread); + { + ReMutexHolder holder(_lock, current_thread); - if (!_windows_sorted) { - do_resort_windows(); - } - - if (sync_flip && _flip_state != FS_flip) { - do_flip_frame(current_thread); - } - - // Are any of the windows ready to be deleted? - Windows new_windows; - new_windows.reserve(_windows.size()); - Windows::iterator wi; - for (wi = _windows.begin(); wi != _windows.end(); ++wi) { - GraphicsOutput *win = (*wi); - if (win->get_delete_flag()) { - do_remove_window(win, current_thread); - - } else { - new_windows.push_back(win); - - // Let's calculate each scene's bounding volume here in App, - // before we cycle the pipeline. The cull traversal will - // calculate it anyway, but if we calculate it in App first - // before it gets calculated in the Cull thread, it will be more - // likely to stick for subsequent frames, so we won't have to - // recompute it each frame. - int num_drs = win->get_num_active_display_regions(); - for (int i = 0; i < num_drs; ++i) { - DisplayRegion *dr = win->get_active_display_region(i); - if (dr != (DisplayRegion *)NULL) { - NodePath camera_np = dr->get_camera(current_thread); - if (!camera_np.is_empty()) { - Camera *camera = DCAST(Camera, camera_np.node()); - NodePath scene = camera->get_scene(); - if (scene.is_empty()) { - scene = camera_np.get_top(current_thread); - } - if (!scene.is_empty()) { - scene.get_bounds(current_thread); + if (!_windows_sorted) { + do_resort_windows(); + } + + if (sync_flip && _flip_state != FS_flip) { + do_flip_frame(current_thread); + } + + // Are any of the windows ready to be deleted? + Windows new_windows; + new_windows.reserve(_windows.size()); + Windows::iterator wi; + for (wi = _windows.begin(); wi != _windows.end(); ++wi) { + GraphicsOutput *win = (*wi); + if (win->get_delete_flag()) { + do_remove_window(win, current_thread); + + } else { + new_windows.push_back(win); + + // Let's calculate each scene's bounding volume here in App, + // before we cycle the pipeline. The cull traversal will + // calculate it anyway, but if we calculate it in App first + // before it gets calculated in the Cull thread, it will be more + // likely to stick for subsequent frames, so we won't have to + // recompute it each frame. + int num_drs = win->get_num_active_display_regions(); + for (int i = 0; i < num_drs; ++i) { + DisplayRegion *dr = win->get_active_display_region(i); + if (dr != (DisplayRegion *)NULL) { + NodePath camera_np = dr->get_camera(current_thread); + if (!camera_np.is_empty()) { + Camera *camera = DCAST(Camera, camera_np.node()); + NodePath scene = camera->get_scene(); + if (scene.is_empty()) { + scene = camera_np.get_top(current_thread); + } + if (!scene.is_empty()) { + scene.get_bounds(current_thread); + } } } } } } - } - _windows.swap(new_windows); - - // Now it's time to do any drawing from the main frame--after all of - // the App code has executed, but before we begin the next frame. - _app.do_frame(this, current_thread); - - // Grab each thread's mutex again after all windows have flipped, - // and wait for the thread to finish. - { - PStatTimer timer(_wait_pcollector, current_thread); + _windows.swap(new_windows); + + // Now it's time to do any drawing from the main frame--after all of + // the App code has executed, but before we begin the next frame. + _app.do_frame(this, current_thread); + + // Grab each thread's mutex again after all windows have flipped, + // and wait for the thread to finish. + { + PStatTimer timer(_wait_pcollector, current_thread); + Threads::const_iterator ti; + for (ti = _threads.begin(); ti != _threads.end(); ++ti) { + RenderThread *thread = (*ti).second; + thread->_cv_mutex.lock(); + + while (thread->_thread_state != TS_wait) { + thread->_cv_done.wait(); + } + } + } + +#if defined(THREADED_PIPELINE) && defined(DO_PSTATS) + _cyclers_pcollector.set_level(_pipeline->get_num_cyclers()); + _dirty_cyclers_pcollector.set_level(_pipeline->get_num_dirty_cyclers()); + +#ifdef DEBUG_THREADS + if (PStatClient::is_connected()) { + _pipeline->iterate_all_cycler_types(pstats_count_cycler_type, this); + _pipeline->iterate_dirty_cycler_types(pstats_count_dirty_cycler_type, this); + } +#endif // DEBUG_THREADS + +#endif // THREADED_PIPELINE && DO_PSTATS + + GeomCacheManager::flush_level(); + CullTraverser::flush_level(); + RenderState::flush_level(); + TransformState::flush_level(); + CullableObject::flush_level(); + + // Now cycle the pipeline and officially begin the next frame. +#ifdef THREADED_PIPELINE + { + PStatTimer timer(_cycle_pcollector, current_thread); + _pipeline->cycle(); + } +#endif // THREADED_PIPELINE + + global_clock->tick(current_thread); + if (global_clock->check_errors(current_thread)) { + throw_event("clock_error"); + } + +#ifdef DO_PSTATS + PStatClient::main_tick(); + + // Reset our pcollectors that track data across the frame. + CullTraverser::_nodes_pcollector.clear_level(); + CullTraverser::_geom_nodes_pcollector.clear_level(); + CullTraverser::_geoms_pcollector.clear_level(); + GeomCacheManager::_geom_cache_active_pcollector.clear_level(); + GeomCacheManager::_geom_cache_record_pcollector.clear_level(); + GeomCacheManager::_geom_cache_erase_pcollector.clear_level(); + GeomCacheManager::_geom_cache_evict_pcollector.clear_level(); + + GraphicsStateGuardian::init_frame_pstats(); + + _transform_states_pcollector.set_level(TransformState::get_num_states()); + _render_states_pcollector.set_level(RenderState::get_num_states()); + if (pstats_unused_states) { + _transform_states_unused_pcollector.set_level(TransformState::get_num_unused_states()); + _render_states_unused_pcollector.set_level(RenderState::get_num_unused_states()); + } + + _sw_sprites_pcollector.clear_level(); + + _cnode_volume_pcollector.clear_level(); + _gnode_volume_pcollector.clear_level(); + _geom_volume_pcollector.clear_level(); + _node_volume_pcollector.clear_level(); + _volume_pcollector.clear_level(); + _test_pcollector.clear_level(); + _volume_polygon_pcollector.clear_level(); + _test_polygon_pcollector.clear_level(); + _volume_plane_pcollector.clear_level(); + _test_plane_pcollector.clear_level(); + _volume_sphere_pcollector.clear_level(); + _test_sphere_pcollector.clear_level(); + _volume_tube_pcollector.clear_level(); + _test_tube_pcollector.clear_level(); + _volume_inv_sphere_pcollector.clear_level(); + _test_inv_sphere_pcollector.clear_level(); + _volume_geom_pcollector.clear_level(); + _test_geom_pcollector.clear_level(); + _occlusion_untested_pcollector.clear_level(); + _occlusion_passed_pcollector.clear_level(); + _occlusion_failed_pcollector.clear_level(); + _occlusion_tests_pcollector.clear_level(); + + if (PStatClient::is_connected()) { + size_t small_buf = GeomVertexArrayData::get_small_lru()->get_total_size(); + size_t independent = GeomVertexArrayData::get_independent_lru()->get_total_size(); + size_t resident = VertexDataPage::get_global_lru(VertexDataPage::RC_resident)->get_total_size(); + size_t compressed = VertexDataPage::get_global_lru(VertexDataPage::RC_compressed)->get_total_size(); + size_t pending = VertexDataPage::get_pending_lru()->get_total_size(); + + VertexDataSaveFile *save_file = VertexDataPage::get_save_file(); + size_t total_disk = save_file->get_total_file_size(); + size_t used_disk = save_file->get_used_file_size(); + + _vertex_data_small_pcollector.set_level(small_buf); + _vertex_data_independent_pcollector.set_level(independent); + _vertex_data_pending_pcollector.set_level(pending); + _vertex_data_resident_pcollector.set_level(resident); + _vertex_data_compressed_pcollector.set_level(compressed); + _vertex_data_unused_disk_pcollector.set_level(total_disk - used_disk); + _vertex_data_used_disk_pcollector.set_level(used_disk); + } + +#endif // DO_PSTATS + + GeomVertexArrayData::lru_epoch(); + + // Now signal all of our threads to begin their next frame. Threads::const_iterator ti; for (ti = _threads.begin(); ti != _threads.end(); ++ti) { RenderThread *thread = (*ti).second; - thread->_cv_mutex.lock(); - - while (thread->_thread_state != TS_wait) { - thread->_cv_done.wait(); + if (thread->_thread_state == TS_wait) { + thread->_thread_state = TS_do_frame; + thread->_cv_start.signal(); } + thread->_cv_mutex.release(); } + + // Some threads may still be drawing, so indicate that we have to + // wait for those threads before we can flip. + _flip_state = _auto_flip ? FS_flip : FS_draw; } -#if defined(THREADED_PIPELINE) && defined(DO_PSTATS) - _cyclers_pcollector.set_level(_pipeline->get_num_cyclers()); - _dirty_cyclers_pcollector.set_level(_pipeline->get_num_dirty_cyclers()); - -#ifdef DEBUG_THREADS - if (PStatClient::is_connected()) { - _pipeline->iterate_all_cycler_types(pstats_count_cycler_type, this); - _pipeline->iterate_dirty_cycler_types(pstats_count_dirty_cycler_type, this); - } -#endif // DEBUG_THREADS - -#endif // THREADED_PIPELINE && DO_PSTATS - - GeomCacheManager::flush_level(); - CullTraverser::flush_level(); - RenderState::flush_level(); - TransformState::flush_level(); - CullableObject::flush_level(); - - // Now cycle the pipeline and officially begin the next frame. -#ifdef THREADED_PIPELINE - { - PStatTimer timer(_cycle_pcollector, current_thread); - _pipeline->cycle(); - } -#endif // THREADED_PIPELINE - - global_clock->tick(current_thread); - if (global_clock->check_errors(current_thread)) { - throw_event("clock_error"); - } - -#ifdef DO_PSTATS - PStatClient::main_tick(); - - // Reset our pcollectors that track data across the frame. - CullTraverser::_nodes_pcollector.clear_level(); - CullTraverser::_geom_nodes_pcollector.clear_level(); - CullTraverser::_geoms_pcollector.clear_level(); - GeomCacheManager::_geom_cache_active_pcollector.clear_level(); - GeomCacheManager::_geom_cache_record_pcollector.clear_level(); - GeomCacheManager::_geom_cache_erase_pcollector.clear_level(); - GeomCacheManager::_geom_cache_evict_pcollector.clear_level(); + // Now the lock is released. - GraphicsStateGuardian::init_frame_pstats(); - - _transform_states_pcollector.set_level(TransformState::get_num_states()); - _render_states_pcollector.set_level(RenderState::get_num_states()); - if (pstats_unused_states) { - _transform_states_unused_pcollector.set_level(TransformState::get_num_unused_states()); - _render_states_unused_pcollector.set_level(RenderState::get_num_unused_states()); - } - - _sw_sprites_pcollector.clear_level(); - - _cnode_volume_pcollector.clear_level(); - _gnode_volume_pcollector.clear_level(); - _geom_volume_pcollector.clear_level(); - _node_volume_pcollector.clear_level(); - _volume_pcollector.clear_level(); - _test_pcollector.clear_level(); - _volume_polygon_pcollector.clear_level(); - _test_polygon_pcollector.clear_level(); - _volume_plane_pcollector.clear_level(); - _test_plane_pcollector.clear_level(); - _volume_sphere_pcollector.clear_level(); - _test_sphere_pcollector.clear_level(); - _volume_tube_pcollector.clear_level(); - _test_tube_pcollector.clear_level(); - _volume_inv_sphere_pcollector.clear_level(); - _test_inv_sphere_pcollector.clear_level(); - _volume_geom_pcollector.clear_level(); - _test_geom_pcollector.clear_level(); - _occlusion_untested_pcollector.clear_level(); - _occlusion_passed_pcollector.clear_level(); - _occlusion_failed_pcollector.clear_level(); - _occlusion_tests_pcollector.clear_level(); - - if (PStatClient::is_connected()) { - size_t small_buf = GeomVertexArrayData::get_small_lru()->get_total_size(); - size_t independent = GeomVertexArrayData::get_independent_lru()->get_total_size(); - size_t resident = VertexDataPage::get_global_lru(VertexDataPage::RC_resident)->get_total_size(); - size_t compressed = VertexDataPage::get_global_lru(VertexDataPage::RC_compressed)->get_total_size(); - size_t pending = VertexDataPage::get_pending_lru()->get_total_size(); - - VertexDataSaveFile *save_file = VertexDataPage::get_save_file(); - size_t total_disk = save_file->get_total_file_size(); - size_t used_disk = save_file->get_used_file_size(); - - _vertex_data_small_pcollector.set_level(small_buf); - _vertex_data_independent_pcollector.set_level(independent); - _vertex_data_pending_pcollector.set_level(pending); - _vertex_data_resident_pcollector.set_level(resident); - _vertex_data_compressed_pcollector.set_level(compressed); - _vertex_data_unused_disk_pcollector.set_level(total_disk - used_disk); - _vertex_data_used_disk_pcollector.set_level(used_disk); - } - -#endif // DO_PSTATS - - GeomVertexArrayData::lru_epoch(); - - // Now signal all of our threads to begin their next frame. - Threads::const_iterator ti; - for (ti = _threads.begin(); ti != _threads.end(); ++ti) { - RenderThread *thread = (*ti).second; - if (thread->_thread_state == TS_wait) { - thread->_thread_state = TS_do_frame; - thread->_cv_start.signal(); - } - thread->_cv_mutex.release(); - } - - // Some threads may still be drawing, so indicate that we have to - // wait for those threads before we can flip. - _flip_state = _auto_flip ? FS_flip : FS_draw; - if (yield_timeslice) { // Nap for a moment to yield the timeslice, to be polite to other // running applications. @@ -804,7 +808,7 @@ render_frame() { PStatTimer timer(_yield_pcollector, current_thread); Thread::consider_yield(); } - + // Anything that happens outside of GraphicsEngine::render_frame() // is deemed to be App. _app_pcollector.start(); diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index 0a3d58eb2b..d1c9817c03 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -2240,7 +2240,8 @@ async_reload_texture(TextureContext *tc) { nassertv(_loader != (Loader *)NULL); PT(AsyncTask) request = - new TextureReloadRequest(_prepared_objects, tc->get_texture(), + new TextureReloadRequest(string("reload:") + tc->get_texture()->get_name(), + _prepared_objects, tc->get_texture(), _supports_compressed_texture); _loader->load_async(request); } diff --git a/panda/src/downloader/bioStreamBuf.cxx b/panda/src/downloader/bioStreamBuf.cxx index 100a382882..97eb39081b 100644 --- a/panda/src/downloader/bioStreamBuf.cxx +++ b/panda/src/downloader/bioStreamBuf.cxx @@ -144,6 +144,7 @@ sync() { size_t num_wrote = write_chars(pbase(), n); pbump(-(int)n); + if (num_wrote != n) { return EOF; } @@ -213,6 +214,12 @@ underflow() { } gbump(num_bytes); return EOF; + + } + + if (downloader_cat.is_spam()) { + downloader_cat.spam() + << "read " << read_count << " bytes from " << _source << "\n"; } // Slide what we did read to the top of the buffer. @@ -241,7 +248,7 @@ write_chars(const char *start, size_t length) { int write_count = BIO_write(*_source, start, length); if (downloader_cat.is_spam()) { downloader_cat.spam() - << "wrote " << write_count << " bytes.\n"; + << "wrote " << write_count << " bytes to " << _source << "\n"; } thread_consider_yield(); while (write_count != (int)(length - wrote_so_far)) { @@ -272,10 +279,17 @@ write_chars(const char *start, size_t length) { downloader_cat.spam() << "waiting to write to BIO.\n"; } +#if defined(HAVE_THREADS) && defined(SIMPLE_THREADS) + // In SIMPLE_THREADS mode, instead of blocking, simply yield + // the thread. + thread_yield(); +#else + // In any other threading mode, we actually want to block. fd_set wset; FD_ZERO(&wset); FD_SET(fd, &wset); select(fd + 1, NULL, &wset, NULL, NULL); +#endif // SIMPLE_THREADS } } else { diff --git a/panda/src/event/asyncTaskManager.cxx b/panda/src/event/asyncTaskManager.cxx index b0eb0b1c04..807ed73f63 100644 --- a/panda/src/event/asyncTaskManager.cxx +++ b/panda/src/event/asyncTaskManager.cxx @@ -37,6 +37,7 @@ TypeHandle AsyncTaskManager::_type_handle; AsyncTaskManager:: AsyncTaskManager(const string &name) : Namable(name), + _lock("AsyncTaskManager::_lock"), _num_tasks(0), _clock(ClockObject::get_global_clock()), _frame_cvar(_lock) diff --git a/panda/src/event/eventQueue.cxx b/panda/src/event/eventQueue.cxx index 858a3e13b7..c83dbaa8ee 100644 --- a/panda/src/event/eventQueue.cxx +++ b/panda/src/event/eventQueue.cxx @@ -25,7 +25,7 @@ EventQueue *EventQueue::_global_event_queue = NULL; // Description: //////////////////////////////////////////////////////////////////// EventQueue:: -EventQueue() : _lock("EventQueue") { +EventQueue() : _lock("EventQueue::_lock") { } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/gobj/geom.cxx b/panda/src/gobj/geom.cxx index 0baa60967d..79fc44e3a3 100644 --- a/panda/src/gobj/geom.cxx +++ b/panda/src/gobj/geom.cxx @@ -1421,15 +1421,18 @@ combine_primitives(GeomPrimitive *a_prim, const GeomPrimitive *b_prim, b_prim2 = b_prim_copy; } - PT(GeomVertexArrayDataHandle) a_handle = a_prim->modify_vertices()->modify_handle(current_thread); - CPT(GeomVertexArrayDataHandle) b_handle = b_prim2->get_vertices()->get_handle(current_thread); + PT(GeomVertexArrayData) a_vertices = a_prim->modify_vertices(); + CPT(GeomVertexArrayData) b_vertices = b_prim2->get_vertices(); if (a_prim->requires_unused_vertices()) { - GeomVertexReader index(b_handle->get_object(), 0); + GeomVertexReader index(b_vertices, 0); int b_vertex = index.get_data1i(); - a_prim->append_unused_vertices(a_handle->get_object(), b_vertex); + a_prim->append_unused_vertices(a_vertices, b_vertex); } + PT(GeomVertexArrayDataHandle) a_handle = a_vertices->modify_handle(current_thread); + CPT(GeomVertexArrayDataHandle) b_handle = b_vertices->get_handle(current_thread); + size_t orig_a_vertices = a_handle->get_num_rows(); a_handle->copy_subdata_from(a_handle->get_data_size_bytes(), 0, diff --git a/panda/src/gobj/geomPrimitive.cxx b/panda/src/gobj/geomPrimitive.cxx index 51902f9691..f18b64ee44 100644 --- a/panda/src/gobj/geomPrimitive.cxx +++ b/panda/src/gobj/geomPrimitive.cxx @@ -1385,11 +1385,11 @@ calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, } else { // Indexed case. GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0, current_thread); - int num_vertices = get_num_vertices(); if (got_mat) { - for (int i = 0; i < num_vertices; ++i) { - reader.set_row(index.get_data1i()); + while (!index.is_at_end()) { + int ii = index.get_data1i(); + reader.set_row(ii); LPoint3f vertex = mat.xform_point(reader.get_data3f()); if (found_any) { @@ -1406,7 +1406,7 @@ calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, } } } else { - for (int i = 0; i < num_vertices; ++i) { + while (!index.is_at_end()) { int ii = index.get_data1i(); reader.set_row(ii); const LVecBase3f &vertex = reader.get_data3f(); @@ -1523,76 +1523,79 @@ recompute_minmax(GeomPrimitive::CData *cdata) { cdata->_mins.clear(); cdata->_maxs.clear(); - } else if (get_num_vertices() == 0) { - // Or if we don't have any vertices, the minmax is also trivial. - cdata->_min_vertex = 0; - cdata->_max_vertex = 0; - cdata->_mins.clear(); - cdata->_maxs.clear(); + } else { + int num_vertices = cdata->_vertices.get_read_pointer()->get_num_rows(); - } else if (get_num_vertices_per_primitive() == 0) { - // This is a complex primitive type like a triangle strip; compute - // the minmax of each primitive (as well as the overall minmax). - GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0); - - cdata->_mins = make_index_data(); - cdata->_maxs = make_index_data(); - - GeomVertexWriter mins(cdata->_mins.get_write_pointer(), 0); - GeomVertexWriter maxs(cdata->_maxs.get_write_pointer(), 0); - - int pi = 0; - - unsigned int vertex = index.get_data1i(); - cdata->_min_vertex = vertex; - cdata->_max_vertex = vertex; - unsigned int min_prim = vertex; - unsigned int max_prim = vertex; - - int num_vertices = get_num_vertices(); - for (int vi = 1; vi < num_vertices; ++vi) { - nassertv(!index.is_at_end()); + if (num_vertices == 0) { + // Or if we don't have any vertices, the minmax is also trivial. + cdata->_min_vertex = 0; + cdata->_max_vertex = 0; + cdata->_mins.clear(); + cdata->_maxs.clear(); + + } else if (get_num_vertices_per_primitive() == 0) { + // This is a complex primitive type like a triangle strip; compute + // the minmax of each primitive (as well as the overall minmax). + GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0); + + cdata->_mins = make_index_data(); + cdata->_maxs = make_index_data(); + + GeomVertexWriter mins(cdata->_mins.get_write_pointer(), 0); + GeomVertexWriter maxs(cdata->_maxs.get_write_pointer(), 0); + + int pi = 0; + unsigned int vertex = index.get_data1i(); - cdata->_min_vertex = min(cdata->_min_vertex, vertex); - cdata->_max_vertex = max(cdata->_max_vertex, vertex); + cdata->_min_vertex = vertex; + cdata->_max_vertex = vertex; + unsigned int min_prim = vertex; + unsigned int max_prim = vertex; + + for (int vi = 1; vi < num_vertices; ++vi) { + nassertv(!index.is_at_end()); + unsigned int vertex = index.get_data1i(); + cdata->_min_vertex = min(cdata->_min_vertex, vertex); + cdata->_max_vertex = max(cdata->_max_vertex, vertex); - if (vi == cdata->_ends[pi]) { - mins.add_data1i(min_prim); - maxs.add_data1i(max_prim); - min_prim = vertex; - max_prim = vertex; - ++pi; - - } else { - min_prim = min(min_prim, vertex); - max_prim = max(max_prim, vertex); + nassertv(pi < cdata->_ends.size()); + if (vi == cdata->_ends[pi]) { + mins.add_data1i(min_prim); + maxs.add_data1i(max_prim); + min_prim = vertex; + max_prim = vertex; + ++pi; + + } else { + min_prim = min(min_prim, vertex); + max_prim = max(max_prim, vertex); + } + } + mins.add_data1i(min_prim); + maxs.add_data1i(max_prim); + nassertv(mins.get_array_data()->get_num_rows() == (int)cdata->_ends.size()); + + } else { + // This is a simple primitive type like a triangle; just compute + // the overall minmax. + GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0); + + cdata->_mins.clear(); + cdata->_maxs.clear(); + + unsigned int vertex = index.get_data1i(); + cdata->_min_vertex = vertex; + cdata->_max_vertex = vertex; + + for (int vi = 1; vi < num_vertices; ++vi) { + nassertv(!index.is_at_end()); + unsigned int vertex = index.get_data1i(); + cdata->_min_vertex = min(cdata->_min_vertex, vertex); + cdata->_max_vertex = max(cdata->_max_vertex, vertex); } } - mins.add_data1i(min_prim); - maxs.add_data1i(max_prim); - nassertv(mins.get_array_data()->get_num_rows() == (int)cdata->_ends.size()); - - } else { - // This is a simple primitive type like a triangle; just compute - // the overall minmax. - GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0); - - cdata->_mins.clear(); - cdata->_maxs.clear(); - - unsigned int vertex = index.get_data1i(); - cdata->_min_vertex = vertex; - cdata->_max_vertex = vertex; - - int num_vertices = get_num_vertices(); - for (int vi = 1; vi < num_vertices; ++vi) { - nassertv(!index.is_at_end()); - unsigned int vertex = index.get_data1i(); - cdata->_min_vertex = min(cdata->_min_vertex, vertex); - cdata->_max_vertex = max(cdata->_max_vertex, vertex); - } } - + cdata->_got_minmax = true; } diff --git a/panda/src/gobj/textureReloadRequest.I b/panda/src/gobj/textureReloadRequest.I index d58d83a69d..5e18335b53 100644 --- a/panda/src/gobj/textureReloadRequest.I +++ b/panda/src/gobj/textureReloadRequest.I @@ -20,9 +20,10 @@ // via load_async(), to begin an asynchronous load. //////////////////////////////////////////////////////////////////// INLINE TextureReloadRequest:: -TextureReloadRequest(PreparedGraphicsObjects *pgo, Texture *texture, +TextureReloadRequest(const string &name, + PreparedGraphicsObjects *pgo, Texture *texture, bool allow_compressed) : - AsyncTask(texture->get_name()), + AsyncTask(name), _pgo(pgo), _texture(texture), _allow_compressed(allow_compressed), diff --git a/panda/src/gobj/textureReloadRequest.h b/panda/src/gobj/textureReloadRequest.h index f18a83c671..408800b3f6 100644 --- a/panda/src/gobj/textureReloadRequest.h +++ b/panda/src/gobj/textureReloadRequest.h @@ -36,7 +36,8 @@ public: ALLOC_DELETED_CHAIN(TextureReloadRequest); PUBLISHED: - INLINE TextureReloadRequest(PreparedGraphicsObjects *pgo, Texture *texture, + INLINE TextureReloadRequest(const string &name, + PreparedGraphicsObjects *pgo, Texture *texture, bool allow_compressed); INLINE PreparedGraphicsObjects *get_prepared_graphics_objects() const; diff --git a/panda/src/parametrics/ropeNode.cxx b/panda/src/parametrics/ropeNode.cxx index 7f097bb2bc..ac02eac62c 100644 --- a/panda/src/parametrics/ropeNode.cxx +++ b/panda/src/parametrics/ropeNode.cxx @@ -238,15 +238,16 @@ reset_bound(const NodePath &rel_to) { // thing. //////////////////////////////////////////////////////////////////// void RopeNode:: -compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage, +compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, + int &internal_vertices, + int pipeline_stage, Thread *current_thread) const { PT(BoundingVolume) bounds = do_recompute_bounds(NodePath((PandaNode *)this), pipeline_stage, current_thread); - bdata->_internal_bounds = bounds; - bdata->_internal_vertices = 0; // TODO--estimate this better. - bdata->_internal_bounds_stale = false; + internal_bounds = bounds; + internal_vertices = 0; // TODO--estimate this better. } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/parametrics/ropeNode.h b/panda/src/parametrics/ropeNode.h index 771df3a976..d2679ed0f6 100644 --- a/panda/src/parametrics/ropeNode.h +++ b/panda/src/parametrics/ropeNode.h @@ -142,7 +142,9 @@ PUBLISHED: void reset_bound(const NodePath &rel_to); protected: - virtual void compute_internal_bounds(BoundsData *bdata, int pipeline_stage, + virtual void compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, + int &internal_vertices, + int pipeline_stage, Thread *current_thread) const; private: diff --git a/panda/src/parametrics/sheetNode.cxx b/panda/src/parametrics/sheetNode.cxx index 254f45362b..a4abc5ba4f 100644 --- a/panda/src/parametrics/sheetNode.cxx +++ b/panda/src/parametrics/sheetNode.cxx @@ -220,15 +220,16 @@ reset_bound(const NodePath &rel_to) { // thing. //////////////////////////////////////////////////////////////////// void SheetNode:: -compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage, +compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, + int &internal_vertices, + int pipeline_stage, Thread *current_thread) const { PT(BoundingVolume) bounds = do_recompute_bounds(NodePath((PandaNode *)this), pipeline_stage, current_thread); - bdata->_internal_bounds = bounds; - bdata->_internal_vertices = 0; // TODO--estimate this better. - bdata->_internal_bounds_stale = false; + internal_bounds = bounds; + internal_vertices = 0; // TODO--estimate this better. } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/parametrics/sheetNode.h b/panda/src/parametrics/sheetNode.h index 9a7b5a1311..6211679a97 100644 --- a/panda/src/parametrics/sheetNode.h +++ b/panda/src/parametrics/sheetNode.h @@ -63,7 +63,9 @@ PUBLISHED: void reset_bound(const NodePath &rel_to); protected: - virtual void compute_internal_bounds(BoundsData *bdata, int pipeline_stage, + virtual void compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, + int &internal_vertices, + int pipeline_stage, Thread *current_thread) const; private: diff --git a/panda/src/pgraph/geomNode.cxx b/panda/src/pgraph/geomNode.cxx index 4efac4e6f9..b89005d033 100644 --- a/panda/src/pgraph/geomNode.cxx +++ b/panda/src/pgraph/geomNode.cxx @@ -366,10 +366,13 @@ safe_to_combine() const { //////////////////////////////////////////////////////////////////// void GeomNode:: r_prepare_scene(const RenderState *state, - PreparedGraphicsObjects *prepared_objects) { - int num_geoms = get_num_geoms(); - for (int i = 0; i < num_geoms; i++) { - CPT(RenderState) geom_state = state->compose(get_geom_state(i)); + PreparedGraphicsObjects *prepared_objects, + Thread *current_thread) { + CDReader cdata(_cycler, current_thread); + GeomList::const_iterator gi; + CPT(GeomList) geoms = cdata->get_geoms(); + for (gi = geoms->begin(); gi != geoms->end(); ++gi) { + CPT(RenderState) geom_state = state->compose((*gi)._state); const RenderAttrib *attrib = geom_state->get_attrib(TextureAttrib::get_class_type()); if (attrib != (const RenderAttrib *)NULL) { @@ -382,7 +385,7 @@ r_prepare_scene(const RenderState *state, } } - PandaNode::r_prepare_scene(state, prepared_objects); + PandaNode::r_prepare_scene(state, prepared_objects, current_thread); } @@ -842,24 +845,31 @@ do_premunge(GraphicsStateGuardianBase *gsg, // something internally. //////////////////////////////////////////////////////////////////// void GeomNode:: -compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage, +compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, + int &internal_vertices, + int pipeline_stage, Thread *current_thread) const { int num_vertices = 0; CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread); pvector child_volumes; + pvector child_volumes_ref; bool all_box = true; GeomList::const_iterator gi; CPT(GeomList) geoms = cdata->get_geoms(); + child_volumes.reserve(geoms->size()); + child_volumes_ref.reserve(geoms->size()); + for (gi = geoms->begin(); gi != geoms->end(); ++gi) { const GeomEntry &entry = (*gi); CPT(Geom) geom = entry._geom.get_read_pointer(); - const BoundingVolume *volume = geom->get_bounds(); + CPT(BoundingVolume) volume = geom->get_bounds(); if (!volume->is_empty()) { child_volumes.push_back(volume); + child_volumes_ref.push_back(volume); if (!volume->is_exact_type(BoundingBox::get_class_type())) { all_box = false; } @@ -885,9 +895,8 @@ compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage, ((BoundingVolume *)gbv)->around(child_begin, child_end); } - bdata->_internal_bounds = gbv; - bdata->_internal_vertices = num_vertices; - bdata->_internal_bounds_stale = false; + internal_bounds = gbv; + internal_vertices = num_vertices; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pgraph/geomNode.h b/panda/src/pgraph/geomNode.h index feb919e758..ffea47e5a0 100644 --- a/panda/src/pgraph/geomNode.h +++ b/panda/src/pgraph/geomNode.h @@ -60,7 +60,8 @@ public: virtual bool safe_to_combine() const; virtual void r_prepare_scene(const RenderState *state, - PreparedGraphicsObjects *prepared_objects); + PreparedGraphicsObjects *prepared_objects, + Thread *current_thread); PUBLISHED: INLINE void set_preserved(bool value); @@ -97,7 +98,9 @@ public: GeomTransformer &transformer); protected: - virtual void compute_internal_bounds(BoundsData *bdata, int pipeline_stage, + virtual void compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, + int &internal_vertices, + int pipeline_stage, Thread *current_thread) const; public: diff --git a/panda/src/pgraph/loader.cxx b/panda/src/pgraph/loader.cxx index 7bb17777d0..488d9217be 100644 --- a/panda/src/pgraph/loader.cxx +++ b/panda/src/pgraph/loader.cxx @@ -17,6 +17,7 @@ #include "loaderFileTypeRegistry.h" #include "config_pgraph.h" #include "modelPool.h" +#include "modelLoadRequest.h" #include "config_express.h" #include "config_util.h" #include "virtualFileSystem.h" @@ -63,6 +64,18 @@ Loader(const string &name) : } } +//////////////////////////////////////////////////////////////////// +// Function: Loader::make_async_request +// Access: Published +// Description: Returns a new AsyncTask object suitable for adding to +// load_async() to start an asynchronous model load. +//////////////////////////////////////////////////////////////////// +PT(AsyncTask) Loader:: +make_async_request(const Filename &filename, const LoaderOptions &options) { + return new ModelLoadRequest(string("model:")+filename.get_basename(), + filename, options, this); +} + //////////////////////////////////////////////////////////////////// // Function: Loader::load_bam_stream // Access: Published @@ -367,6 +380,6 @@ void Loader:: make_global_ptr() { nassertv(_global_ptr == (Loader *)NULL); - _global_ptr = new Loader("taskMgr"); + _global_ptr = new Loader("loader"); } diff --git a/panda/src/pgraph/loader.h b/panda/src/pgraph/loader.h index fd81201e5c..288cd3f1c7 100644 --- a/panda/src/pgraph/loader.h +++ b/panda/src/pgraph/loader.h @@ -86,6 +86,8 @@ PUBLISHED: BLOCKING INLINE PT(PandaNode) load_sync(const Filename &filename, const LoaderOptions &options = LoaderOptions()) const; + PT(AsyncTask) make_async_request(const Filename &filename, + const LoaderOptions &options = LoaderOptions()); INLINE void load_async(AsyncTask *request); BLOCKING PT(PandaNode) load_bam_stream(istream &in); diff --git a/panda/src/pgraph/lodNode.cxx b/panda/src/pgraph/lodNode.cxx index a7c0a5e37b..1c7882e770 100644 --- a/panda/src/pgraph/lodNode.cxx +++ b/panda/src/pgraph/lodNode.cxx @@ -476,7 +476,9 @@ show_switches_cull_callback(CullTraverser *trav, CullTraverserData &data) { // something internally. //////////////////////////////////////////////////////////////////// void LODNode:: -compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage, +compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, + int &internal_vertices, + int pipeline_stage, Thread *current_thread) const { // First, get ourselves a fresh, empty bounding volume. PT(BoundingVolume) bound = new BoundingSphere; @@ -508,9 +510,8 @@ compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage, bound->around(child_begin, child_end); } - bdata->_internal_bounds = bound; - bdata->_internal_vertices = 0; - bdata->_internal_bounds_stale = false; + internal_bounds = bound; + internal_vertices = 0; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pgraph/lodNode.h b/panda/src/pgraph/lodNode.h index 19b54fb056..c0a0498c95 100644 --- a/panda/src/pgraph/lodNode.h +++ b/panda/src/pgraph/lodNode.h @@ -83,7 +83,9 @@ protected: int compute_child(CullTraverser *trav, CullTraverserData &data); bool show_switches_cull_callback(CullTraverser *trav, CullTraverserData &data); - virtual void compute_internal_bounds(BoundsData *bdata, int pipeline_stage, + virtual void compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, + int &internal_vertices, + int pipeline_stage, Thread *current_thread) const; INLINE void consider_verify_lods(CullTraverser *trav, CullTraverserData &data); diff --git a/panda/src/pgraph/modelLoadRequest.I b/panda/src/pgraph/modelLoadRequest.I index 5268d598bc..49286ee120 100644 --- a/panda/src/pgraph/modelLoadRequest.I +++ b/panda/src/pgraph/modelLoadRequest.I @@ -20,9 +20,10 @@ // via load_async(), to begin an asynchronous load. //////////////////////////////////////////////////////////////////// INLINE ModelLoadRequest:: -ModelLoadRequest(const Filename &filename, const LoaderOptions &options, +ModelLoadRequest(const string &name, + const Filename &filename, const LoaderOptions &options, Loader *loader) : - AsyncTask(filename.get_basename()), + AsyncTask(name), _filename(filename), _options(options), _loader(loader), diff --git a/panda/src/pgraph/modelLoadRequest.h b/panda/src/pgraph/modelLoadRequest.h index 95deec1bf3..0a4a70e684 100644 --- a/panda/src/pgraph/modelLoadRequest.h +++ b/panda/src/pgraph/modelLoadRequest.h @@ -36,7 +36,8 @@ public: ALLOC_DELETED_CHAIN(ModelLoadRequest); PUBLISHED: - INLINE ModelLoadRequest(const Filename &filename, + INLINE ModelLoadRequest(const string &name, + const Filename &filename, const LoaderOptions &options, Loader *loader); diff --git a/panda/src/pgraph/pandaNode.I b/panda/src/pgraph/pandaNode.I index 22543526e2..2e848fe6ca 100644 --- a/panda/src/pgraph/pandaNode.I +++ b/panda/src/pgraph/pandaNode.I @@ -708,7 +708,7 @@ INLINE void PandaNode:: mark_internal_bounds_stale(int pipeline_stage, Thread *current_thread) { { CDStageWriter cdata(_cycler, pipeline_stage, current_thread); - cdata->_internal_bounds_stale = true; + ++cdata->_internal_bounds_mark; } mark_bounds_stale(pipeline_stage, current_thread); } @@ -942,9 +942,9 @@ get_parent() const { INLINE PandaNode::BoundsData:: BoundsData() : _internal_bounds(NULL), - _internal_vertices(0), - _internal_bounds_stale(true) + _internal_vertices(0) { + ++_internal_bounds_mark; } //////////////////////////////////////////////////////////////////// @@ -956,10 +956,24 @@ INLINE PandaNode::BoundsData:: BoundsData(const PandaNode::BoundsData ©) : _internal_bounds(copy._internal_bounds), _internal_vertices(copy._internal_vertices), - _internal_bounds_stale(copy._internal_bounds_stale) + _internal_bounds_mark(copy._internal_bounds_mark), + _internal_bounds_computed(copy._internal_bounds_computed) { } +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::BoundsData::copy_bounds +// Access: Protected +// Description: Copies just the BoundsData part of the structure. +//////////////////////////////////////////////////////////////////// +INLINE void PandaNode::BoundsData:: +copy_bounds(const PandaNode::BoundsData ©) { + _internal_bounds = copy._internal_bounds; + _internal_vertices = copy._internal_vertices; + _internal_bounds_mark = copy._internal_bounds_mark; + _internal_bounds_computed = copy._internal_bounds_computed; +} + //////////////////////////////////////////////////////////////////// // Function: PandaNode::CData::set_fancy_bit // Access: Public diff --git a/panda/src/pgraph/pandaNode.cxx b/panda/src/pgraph/pandaNode.cxx index 0902023fc8..d441e949d5 100644 --- a/panda/src/pgraph/pandaNode.cxx +++ b/panda/src/pgraph/pandaNode.cxx @@ -162,7 +162,9 @@ PandaNode(const PandaNode ©) : cdata->_into_collide_mask = copy_cdata->_into_collide_mask; cdata->_user_bounds = copy_cdata->_user_bounds; cdata->_internal_bounds = NULL; - cdata->_internal_bounds_stale = true; + cdata->_internal_bounds_computed = UpdateSeq::initial(); + cdata->_internal_bounds_mark = UpdateSeq::initial(); + ++cdata->_internal_bounds_mark; cdata->_final_bounds = copy_cdata->_final_bounds; cdata->_fancy_bits = copy_cdata->_fancy_bits; @@ -1772,7 +1774,7 @@ copy_all_properties(PandaNode *other) { //////////////////////////////////////////////////////////////////// void PandaNode:: replace_node(PandaNode *other) { - nassertv(Thread::get_current_pipeline_stage() == 0); + // nassertv(Thread::get_current_pipeline_stage() == 0); if (other == this) { // Trivial. @@ -2123,8 +2125,9 @@ get_off_clip_planes(Thread *current_thread) const { //////////////////////////////////////////////////////////////////// void PandaNode:: prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *net_state) { + Thread *current_thread = Thread::get_current_thread(); PreparedGraphicsObjects *prepared_objects = gsg->get_prepared_objects(); - r_prepare_scene(net_state, prepared_objects); + r_prepare_scene(net_state, prepared_objects, current_thread); } //////////////////////////////////////////////////////////////////// @@ -2421,18 +2424,42 @@ as_light() { //////////////////////////////////////////////////////////////////// CPT(BoundingVolume) PandaNode:: get_internal_bounds(int pipeline_stage, Thread *current_thread) const { - CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread); - if (cdata->_user_bounds != (BoundingVolume *)NULL) { - return cdata->_user_bounds; - } + while (true) { + UpdateSeq mark; + { + CDStageReader cdata(_cycler, pipeline_stage, current_thread); + if (cdata->_user_bounds != (BoundingVolume *)NULL) { + return cdata->_user_bounds; + } + + if (cdata->_internal_bounds_mark == cdata->_internal_bounds_computed) { + return cdata->_internal_bounds; + } - if (cdata->_internal_bounds_stale) { - CDStageWriter cdataw(((PandaNode *)this)->_cycler, pipeline_stage, cdata); - compute_internal_bounds(cdataw, pipeline_stage, current_thread); - nassertr(!cdataw->_internal_bounds.is_null(), NULL); - return cdataw->_internal_bounds; + mark = cdata->_internal_bounds_mark; + } + + // First, call compute_internal_bounds without acquiring the lock. + // This avoids a deadlock condition. + CPT(BoundingVolume) internal_bounds; + int internal_vertices; + compute_internal_bounds(internal_bounds, internal_vertices, + pipeline_stage, current_thread); + nassertr(!internal_bounds.is_null(), NULL); + + // Now, acquire the lock, and apply the above-computed bounds. + CDStageWriter cdataw(((PandaNode *)this)->_cycler, pipeline_stage); + if (cdataw->_internal_bounds_mark == mark) { + cdataw->_internal_bounds_computed = mark; + cdataw->_internal_bounds = internal_bounds; + cdataw->_internal_vertices = internal_vertices; + return cdataw->_internal_bounds; + } + + // Dang, someone in another thread incremented + // _internal_bounds_mark while we weren't holding the lock. That + // means we need to go back and do it again. } - return cdata->_internal_bounds; } //////////////////////////////////////////////////////////////////// @@ -2447,14 +2474,38 @@ get_internal_bounds(int pipeline_stage, Thread *current_thread) const { //////////////////////////////////////////////////////////////////// int PandaNode:: get_internal_vertices(int pipeline_stage, Thread *current_thread) const { - CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread); - if (cdata->_internal_bounds_stale) { - CDStageWriter cdataw(((PandaNode *)this)->_cycler, pipeline_stage, cdata); - compute_internal_bounds(cdataw, pipeline_stage, current_thread); - nassertr(!cdataw->_internal_bounds.is_null(), 0); - return cdataw->_internal_vertices; + while (true) { + UpdateSeq mark; + { + CDStageReader cdata(_cycler, pipeline_stage, current_thread); + if (cdata->_internal_bounds_mark == cdata->_internal_bounds_computed) { + return cdata->_internal_vertices; + } + + mark = cdata->_internal_bounds_mark; + } + + // First, call compute_internal_bounds without acquiring the lock. + // This avoids a deadlock condition. + CPT(BoundingVolume) internal_bounds; + int internal_vertices; + compute_internal_bounds(internal_bounds, internal_vertices, + pipeline_stage, current_thread); + nassertr(!internal_bounds.is_null(), NULL); + + // Now, acquire the lock, and apply the above-computed bounds. + CDStageWriter cdataw(((PandaNode *)this)->_cycler, pipeline_stage); + if (cdataw->_internal_bounds_mark == mark) { + cdataw->_internal_bounds_computed = mark; + cdataw->_internal_bounds = internal_bounds; + cdataw->_internal_vertices = internal_vertices; + return cdataw->_internal_vertices; + } + + // Dang, someone in another thread incremented + // _internal_bounds_mark while we weren't holding the lock. That + // means we need to go back and do it again. } - return cdata->_internal_vertices; } //////////////////////////////////////////////////////////////////// @@ -2472,7 +2523,7 @@ set_internal_bounds(const BoundingVolume *volume) { OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { CDStageWriter cdataw(_cycler, pipeline_stage, current_thread); cdataw->_internal_bounds = volume; - cdataw->_internal_bounds_stale = false; + cdataw->_internal_bounds_computed = cdataw->_internal_bounds_mark; } CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); mark_bounds_stale(current_thread); @@ -2539,11 +2590,12 @@ force_bounds_stale(int pipeline_stage, Thread *current_thread) { // something internally. //////////////////////////////////////////////////////////////////// void PandaNode:: -compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage, +compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, + int &internal_vertices, + int pipeline_stage, Thread *current_thread) const { - bdata->_internal_bounds = new BoundingSphere; - bdata->_internal_vertices = 0; - bdata->_internal_bounds_stale = false; + internal_bounds = new BoundingSphere; + internal_vertices = 0; } //////////////////////////////////////////////////////////////////// @@ -2693,12 +2745,15 @@ r_copy_children(const PandaNode *from, PandaNode::InstanceMap &inst_map, //////////////////////////////////////////////////////////////////// void PandaNode:: r_prepare_scene(const RenderState *state, - PreparedGraphicsObjects *prepared_objects) { - int num_children = get_num_children(); - for (int i = 0; i < num_children; i++) { - PandaNode *child = get_child(i); + PreparedGraphicsObjects *prepared_objects, + Thread *current_thread) { + Children children = get_children(current_thread); + // We must call get_num_children() each time through the loop, in + // case we're running SIMPLE_THREADS and we get interrupted. + for (int i = 0; i < children.get_num_children(); i++) { + PandaNode *child = children.get_child(i); CPT(RenderState) child_state = state->compose(child->get_state()); - child->r_prepare_scene(child_state, prepared_objects); + child->r_prepare_scene(child_state, prepared_objects, current_thread); } } @@ -3546,6 +3601,8 @@ update_bounds(int pipeline_stage, PandaNode::CDLockedStageReader &cdata) { // Also get the list of the node's children. Children children(cdata); + int num_vertices = cdata->_internal_vertices; + // Now that we've got all the data we need from the node, we can // release the lock. _cycler.release_read_stage(pipeline_stage, cdata.take_pointer()); @@ -3579,8 +3636,6 @@ update_bounds(int pipeline_stage, PandaNode::CDLockedStageReader &cdata) { } } - int num_vertices = cdata->_internal_vertices; - // Now expand those contents to include all of our children. for (int i = 0; i < num_children; ++i) { @@ -3754,6 +3809,7 @@ update_bounds(int pipeline_stage, PandaNode::CDLockedStageReader &cdata) { << "} " << *this << "::update_bounds();\n"; } + nassertr(cdataw->_last_update == cdataw->_next_update, cdataw) return cdataw; } diff --git a/panda/src/pgraph/pandaNode.h b/panda/src/pgraph/pandaNode.h index 577c155d60..20a4432338 100644 --- a/panda/src/pgraph/pandaNode.h +++ b/panda/src/pgraph/pandaNode.h @@ -301,7 +301,9 @@ protected: void force_bounds_stale(int pipeline_stage, Thread *current_thread); INLINE void mark_internal_bounds_stale(int pipeline_stage, Thread *current_thread); - virtual void compute_internal_bounds(BoundsData *bdata, int pipeline_stage, + virtual void compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, + int &internal_vertices, + int pipeline_stage, Thread *current_thread) const; virtual void parents_changed(); virtual void children_changed(); @@ -319,7 +321,8 @@ protected: public: virtual void r_prepare_scene(const RenderState *state, - PreparedGraphicsObjects *prepared_objects); + PreparedGraphicsObjects *prepared_objects, + Thread *current_thread); protected: // This is a base class of CData, defined below. It contains just @@ -329,6 +332,7 @@ protected: protected: INLINE BoundsData(); INLINE BoundsData(const BoundsData ©); + INLINE void copy_bounds(const BoundsData ©); public: // This is the "internal" bounding volume, which is normally @@ -337,7 +341,8 @@ protected: // overriding compute_internal_bounds(). CPT(BoundingVolume) _internal_bounds; int _internal_vertices; - bool _internal_bounds_stale; + UpdateSeq _internal_bounds_mark; // incremented on mark_stale + UpdateSeq _internal_bounds_computed; // set to above when computing }; private: diff --git a/panda/src/pgraph/planeNode.cxx b/panda/src/pgraph/planeNode.cxx index 8a47785884..0c76e279a8 100644 --- a/panda/src/pgraph/planeNode.cxx +++ b/panda/src/pgraph/planeNode.cxx @@ -201,12 +201,13 @@ is_renderable() const { // something internally. //////////////////////////////////////////////////////////////////// void PlaneNode:: -compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage, +compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, + int &internal_vertices, + int pipeline_stage, Thread *current_thread) const { CDStageReader cdata(_cycler, pipeline_stage, current_thread); - bdata->_internal_bounds = new BoundingPlane(cdata->_plane); - bdata->_internal_vertices = 0; - bdata->_internal_bounds_stale = false; + internal_bounds = new BoundingPlane(cdata->_plane); + internal_vertices = 0; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pgraph/planeNode.h b/panda/src/pgraph/planeNode.h index 3ef700c684..5e3334c616 100644 --- a/panda/src/pgraph/planeNode.h +++ b/panda/src/pgraph/planeNode.h @@ -72,7 +72,9 @@ public: INLINE static UpdateSeq get_sort_seq(); protected: - virtual void compute_internal_bounds(BoundsData *bdata, int pipeline_stage, + virtual void compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, + int &internal_vertices, + int pipeline_stage, Thread *current_thread) const; PT(Geom) get_viz(CullTraverser *trav, CullTraverserData &data); diff --git a/panda/src/pgraph/portalNode.cxx b/panda/src/pgraph/portalNode.cxx index 3f1afe5a38..d064a6c94c 100755 --- a/panda/src/pgraph/portalNode.cxx +++ b/panda/src/pgraph/portalNode.cxx @@ -379,7 +379,9 @@ draw() const { // thing. //////////////////////////////////////////////////////////////////// void PortalNode:: -compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage, +compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, + int &internal_vertices, + int pipeline_stage, Thread *current_thread) const { // First, get ourselves a fresh, empty bounding volume. PT(BoundingVolume) bound = new BoundingSphere; @@ -394,9 +396,8 @@ compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage, // Now actually compute the bounding volume by putting it around all gbv->around(vertices_begin, vertices_end); - bdata->_internal_bounds = bound; - bdata->_internal_vertices = 0; - bdata->_internal_bounds_stale = false; + internal_bounds = bound; + internal_vertices = 0; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pgraph/portalNode.h b/panda/src/pgraph/portalNode.h index e14c30359d..a07d827eb8 100755 --- a/panda/src/pgraph/portalNode.h +++ b/panda/src/pgraph/portalNode.h @@ -93,7 +93,9 @@ PUBLISHED: // void draw () const; protected: - virtual void compute_internal_bounds(BoundsData *bdata, int pipeline_stage, + virtual void compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, + int &internal_vertices, + int pipeline_stage, Thread *current_thread) const; private: diff --git a/panda/src/pgui/pgButton.I b/panda/src/pgui/pgButton.I index d57ae2938a..37316a8e51 100644 --- a/panda/src/pgui/pgButton.I +++ b/panda/src/pgui/pgButton.I @@ -93,7 +93,8 @@ get_click_prefix() { //////////////////////////////////////////////////////////////////// INLINE string PGButton:: get_click_event(const ButtonHandle &button) const { - return "click-" + button.get_name() + "-" + get_id(); + ReMutexHolder holder(_lock); + return get_click_prefix() + button.get_name() + "-" + get_id(); } //////////////////////////////////////////////////////////////////// @@ -104,5 +105,6 @@ get_click_event(const ButtonHandle &button) const { //////////////////////////////////////////////////////////////////// INLINE bool PGButton:: is_button_down() { + ReMutexHolder holder(_lock); return _button_down; } diff --git a/panda/src/pgui/pgButton.cxx b/panda/src/pgui/pgButton.cxx index 68be5fb8a9..05f4153023 100644 --- a/panda/src/pgui/pgButton.cxx +++ b/panda/src/pgui/pgButton.cxx @@ -69,6 +69,7 @@ PGButton(const PGButton ©) : //////////////////////////////////////////////////////////////////// PandaNode *PGButton:: make_copy() const { + ReMutexHolder holder(_lock); return new PGButton(*this); } @@ -80,6 +81,7 @@ make_copy() const { //////////////////////////////////////////////////////////////////// void PGButton:: enter_region(const MouseWatcherParameter ¶m) { + ReMutexHolder holder(_lock); if (get_active()) { set_state(_button_down ? S_depressed : S_rollover); } @@ -94,6 +96,7 @@ enter_region(const MouseWatcherParameter ¶m) { //////////////////////////////////////////////////////////////////// void PGButton:: exit_region(const MouseWatcherParameter ¶m) { + ReMutexHolder holder(_lock); if (get_active()) { set_state(S_ready); } @@ -109,6 +112,7 @@ exit_region(const MouseWatcherParameter ¶m) { //////////////////////////////////////////////////////////////////// void PGButton:: press(const MouseWatcherParameter ¶m, bool background) { + ReMutexHolder holder(_lock); if (has_click_button(param.get_button())) { if (get_active()) { _button_down = true; @@ -127,6 +131,7 @@ press(const MouseWatcherParameter ¶m, bool background) { //////////////////////////////////////////////////////////////////// void PGButton:: release(const MouseWatcherParameter ¶m, bool background) { + ReMutexHolder holder(_lock); if (has_click_button(param.get_button())) { _button_down = false; if (get_active()) { @@ -149,6 +154,7 @@ release(const MouseWatcherParameter ¶m, bool background) { //////////////////////////////////////////////////////////////////// void PGButton:: click(const MouseWatcherParameter ¶m) { + ReMutexHolder holder(_lock); PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param); string event = get_click_event(param.get_button()); play_sound(event); @@ -170,6 +176,7 @@ click(const MouseWatcherParameter ¶m) { //////////////////////////////////////////////////////////////////// void PGButton:: setup(const string &label, float bevel) { + ReMutexHolder holder(_lock); clear_state_def(S_ready); clear_state_def(S_depressed); clear_state_def(S_rollover); @@ -226,6 +233,7 @@ setup(const string &label, float bevel) { void PGButton:: setup(const NodePath &ready, const NodePath &depressed, const NodePath &rollover, const NodePath &inactive) { + ReMutexHolder holder(_lock); clear_state_def(S_ready); clear_state_def(S_depressed); clear_state_def(S_rollover); @@ -246,6 +254,7 @@ setup(const NodePath &ready, const NodePath &depressed, //////////////////////////////////////////////////////////////////// void PGButton:: set_active(bool active) { + ReMutexHolder holder(_lock); if (active != get_active()) { PGItem::set_active(active); set_state(active ? S_ready : S_inactive); @@ -262,6 +271,7 @@ set_active(bool active) { //////////////////////////////////////////////////////////////////// bool PGButton:: add_click_button(const ButtonHandle &button) { + ReMutexHolder holder(_lock); return _click_buttons.insert(button).second; } @@ -276,6 +286,7 @@ add_click_button(const ButtonHandle &button) { //////////////////////////////////////////////////////////////////// bool PGButton:: remove_click_button(const ButtonHandle &button) { + ReMutexHolder holder(_lock); return (_click_buttons.erase(button) != 0); } @@ -288,5 +299,6 @@ remove_click_button(const ButtonHandle &button) { //////////////////////////////////////////////////////////////////// bool PGButton:: has_click_button(const ButtonHandle &button) { + ReMutexHolder holder(_lock); return (_click_buttons.count(button) != 0); } diff --git a/panda/src/pgui/pgEntry.I b/panda/src/pgui/pgEntry.I index 396874c91b..ce3b1240f7 100644 --- a/panda/src/pgui/pgEntry.I +++ b/panda/src/pgui/pgEntry.I @@ -27,6 +27,7 @@ //////////////////////////////////////////////////////////////////// INLINE bool PGEntry:: set_text(const string &text) { + ReMutexHolder holder(_lock); TextNode *text_node = get_text_def(S_focus); nassertr(text_node != (TextNode *)NULL, false); return set_wtext(text_node->decode_text(text)); @@ -44,6 +45,7 @@ set_text(const string &text) { //////////////////////////////////////////////////////////////////// INLINE string PGEntry:: get_plain_text() const { + ReMutexHolder holder(_lock); TextNode *text_node = get_text_def(S_focus); nassertr(text_node != (TextNode *)NULL, string()); return text_node->encode_wtext(get_plain_wtext()); @@ -59,6 +61,7 @@ get_plain_text() const { //////////////////////////////////////////////////////////////////// INLINE string PGEntry:: get_text() const { + ReMutexHolder holder(_lock); TextNode *text_node = get_text_def(S_focus); nassertr(text_node != (TextNode *)NULL, string()); return text_node->encode_wtext(get_wtext()); @@ -79,6 +82,7 @@ get_text() const { //////////////////////////////////////////////////////////////////// INLINE int PGEntry:: get_num_characters() const { + ReMutexHolder holder(_lock); return _text.get_num_characters(); } @@ -91,6 +95,7 @@ get_num_characters() const { //////////////////////////////////////////////////////////////////// INLINE wchar_t PGEntry:: get_character(int n) const { + ReMutexHolder holder(_lock); return _text.get_character(n); } @@ -104,6 +109,7 @@ get_character(int n) const { //////////////////////////////////////////////////////////////////// INLINE const TextGraphic *PGEntry:: get_graphic(int n) const { + ReMutexHolder holder(_lock); return _text.get_graphic(n); } @@ -116,6 +122,7 @@ get_graphic(int n) const { //////////////////////////////////////////////////////////////////// INLINE const TextProperties &PGEntry:: get_properties(int n) const { + ReMutexHolder holder(_lock); return _text.get_properties(n); } @@ -129,6 +136,7 @@ get_properties(int n) const { //////////////////////////////////////////////////////////////////// INLINE void PGEntry:: set_cursor_position(int position) { + ReMutexHolder holder(_lock); if (_cursor_position != position) { _cursor_position = position; _cursor_stale = true; @@ -143,6 +151,7 @@ set_cursor_position(int position) { //////////////////////////////////////////////////////////////////// INLINE int PGEntry:: get_cursor_position() const { + ReMutexHolder holder(_lock); return _cursor_position; } @@ -158,6 +167,7 @@ get_cursor_position() const { //////////////////////////////////////////////////////////////////// INLINE void PGEntry:: set_max_chars(int max_chars) { + ReMutexHolder holder(_lock); _max_chars = max_chars; } @@ -170,6 +180,7 @@ set_max_chars(int max_chars) { //////////////////////////////////////////////////////////////////// INLINE int PGEntry:: get_max_chars() const { + ReMutexHolder holder(_lock); return _max_chars; } @@ -190,6 +201,7 @@ get_max_chars() const { //////////////////////////////////////////////////////////////////// INLINE void PGEntry:: set_max_width(float max_width) { + ReMutexHolder holder(_lock); _max_width = max_width; _text_geom_stale = true; } @@ -203,6 +215,7 @@ set_max_width(float max_width) { //////////////////////////////////////////////////////////////////// INLINE float PGEntry:: get_max_width() const { + ReMutexHolder holder(_lock); return _max_width; } @@ -215,6 +228,7 @@ get_max_width() const { //////////////////////////////////////////////////////////////////// INLINE void PGEntry:: set_num_lines(int num_lines) { + ReMutexHolder holder(_lock); nassertv(num_lines >= 1); _num_lines = num_lines; _text_geom_stale = true; @@ -228,6 +242,7 @@ set_num_lines(int num_lines) { //////////////////////////////////////////////////////////////////// INLINE int PGEntry:: get_num_lines() const { + ReMutexHolder holder(_lock); return _num_lines; } @@ -242,6 +257,7 @@ get_num_lines() const { //////////////////////////////////////////////////////////////////// INLINE void PGEntry:: set_blink_rate(float blink_rate) { + ReMutexHolder holder(_lock); _blink_rate = blink_rate; } @@ -253,6 +269,7 @@ set_blink_rate(float blink_rate) { //////////////////////////////////////////////////////////////////// INLINE float PGEntry:: get_blink_rate() const { + ReMutexHolder holder(_lock); return _blink_rate; } @@ -265,6 +282,7 @@ get_blink_rate() const { //////////////////////////////////////////////////////////////////// INLINE const NodePath &PGEntry:: get_cursor_def() { + ReMutexHolder holder(_lock); return _cursor_def; } @@ -276,6 +294,7 @@ get_cursor_def() { //////////////////////////////////////////////////////////////////// INLINE void PGEntry:: clear_cursor_def() { + ReMutexHolder holder(_lock); _cursor_def.remove_node(); _cursor_def = _cursor_scale.attach_new_node("cursor"); } @@ -289,6 +308,7 @@ clear_cursor_def() { //////////////////////////////////////////////////////////////////// INLINE void PGEntry:: set_cursor_keys_active(bool flag) { + ReMutexHolder holder(_lock); _cursor_keys_active = flag; } @@ -301,6 +321,7 @@ set_cursor_keys_active(bool flag) { //////////////////////////////////////////////////////////////////// INLINE bool PGEntry:: get_cursor_keys_active() const { + ReMutexHolder holder(_lock); return _cursor_keys_active; } @@ -320,6 +341,7 @@ get_cursor_keys_active() const { //////////////////////////////////////////////////////////////////// INLINE void PGEntry:: set_obscure_mode(bool flag) { + ReMutexHolder holder(_lock); if (_obscure_mode != flag) { _obscure_mode = flag; _text_geom_stale = true; @@ -334,6 +356,7 @@ set_obscure_mode(bool flag) { //////////////////////////////////////////////////////////////////// INLINE bool PGEntry:: get_obscure_mode() const { + ReMutexHolder holder(_lock); return _obscure_mode; } @@ -356,6 +379,7 @@ get_obscure_mode() const { //////////////////////////////////////////////////////////////////// INLINE void PGEntry:: set_candidate_active(const string &candidate_active) { + ReMutexHolder holder(_lock); _candidate_active = candidate_active; } @@ -366,6 +390,7 @@ set_candidate_active(const string &candidate_active) { //////////////////////////////////////////////////////////////////// INLINE const string &PGEntry:: get_candidate_active() const { + ReMutexHolder holder(_lock); return _candidate_active; } @@ -388,6 +413,7 @@ get_candidate_active() const { //////////////////////////////////////////////////////////////////// INLINE void PGEntry:: set_candidate_inactive(const string &candidate_inactive) { + ReMutexHolder holder(_lock); _candidate_inactive = candidate_inactive; } @@ -398,6 +424,7 @@ set_candidate_inactive(const string &candidate_inactive) { //////////////////////////////////////////////////////////////////// INLINE const string &PGEntry:: get_candidate_inactive() const { + ReMutexHolder holder(_lock); return _candidate_inactive; } @@ -469,7 +496,7 @@ get_erase_prefix() { //////////////////////////////////////////////////////////////////// INLINE string PGEntry:: get_accept_event(const ButtonHandle &button) const { - return "accept-" + button.get_name() + "-" + get_id(); + return get_accept_prefix() + button.get_name() + "-" + get_id(); } //////////////////////////////////////////////////////////////////// @@ -480,7 +507,7 @@ get_accept_event(const ButtonHandle &button) const { //////////////////////////////////////////////////////////////////// INLINE string PGEntry:: get_accept_failed_event(const ButtonHandle &button) const { - return "acceptfailed-" + button.get_name() + "-" + get_id(); + return get_accept_failed_prefix() + button.get_name() + "-" + get_id(); } //////////////////////////////////////////////////////////////////// @@ -493,7 +520,7 @@ get_accept_failed_event(const ButtonHandle &button) const { //////////////////////////////////////////////////////////////////// INLINE string PGEntry:: get_overflow_event() const { - return "overflow-" + get_id(); + return get_overflow_prefix() + get_id(); } //////////////////////////////////////////////////////////////////// @@ -504,7 +531,7 @@ get_overflow_event() const { //////////////////////////////////////////////////////////////////// INLINE string PGEntry:: get_type_event() const { - return "type-" + get_id(); + return get_type_prefix() + get_id(); } //////////////////////////////////////////////////////////////////// @@ -515,7 +542,7 @@ get_type_event() const { //////////////////////////////////////////////////////////////////// INLINE string PGEntry:: get_erase_event() const { - return "erase-" + get_id(); + return get_erase_prefix() + get_id(); } //////////////////////////////////////////////////////////////////// @@ -530,6 +557,7 @@ get_erase_event() const { //////////////////////////////////////////////////////////////////// INLINE bool PGEntry:: set_wtext(const wstring &wtext) { + ReMutexHolder holder(_lock); bool ret = _text.set_wtext(wtext); if (_obscure_mode) { ret = _obscure_text.set_wtext(wstring(_text.get_num_characters(), '*')); @@ -547,6 +575,7 @@ set_wtext(const wstring &wtext) { //////////////////////////////////////////////////////////////////// INLINE wstring PGEntry:: get_plain_wtext() const { + ReMutexHolder holder(_lock); return _text.get_plain_wtext(); } @@ -558,6 +587,7 @@ get_plain_wtext() const { //////////////////////////////////////////////////////////////////// INLINE wstring PGEntry:: get_wtext() const { + ReMutexHolder holder(_lock); return _text.get_wtext(); } @@ -569,5 +599,6 @@ get_wtext() const { //////////////////////////////////////////////////////////////////// INLINE void PGEntry:: set_accept_enabled(bool enabled) { + ReMutexHolder holder(_lock); _accept_enabled = enabled; } diff --git a/panda/src/pgui/pgEntry.cxx b/panda/src/pgui/pgEntry.cxx index 9d7171a5a2..8966e7d333 100644 --- a/panda/src/pgui/pgEntry.cxx +++ b/panda/src/pgui/pgEntry.cxx @@ -124,6 +124,7 @@ PGEntry(const PGEntry ©) : //////////////////////////////////////////////////////////////////// PandaNode *PGEntry:: make_copy() const { + ReMutexHolder holder(_lock); return new PGEntry(*this); } @@ -136,6 +137,7 @@ make_copy() const { //////////////////////////////////////////////////////////////////// void PGEntry:: xform(const LMatrix4f &mat) { + ReMutexHolder holder(_lock); PGItem::xform(mat); _text_render_root.set_mat(_text_render_root.get_mat() * mat); } @@ -167,6 +169,7 @@ xform(const LMatrix4f &mat) { //////////////////////////////////////////////////////////////////// bool PGEntry:: cull_callback(CullTraverser *trav, CullTraverserData &data) { + ReMutexHolder holder(_lock); PGItem::cull_callback(trav, data); update_text(); update_cursor(); @@ -188,6 +191,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { //////////////////////////////////////////////////////////////////// void PGEntry:: press(const MouseWatcherParameter ¶m, bool background) { + ReMutexHolder holder(_lock); if (get_active()) { if (param.has_button()) { // Make sure _text is initialized properly. @@ -296,6 +300,7 @@ press(const MouseWatcherParameter ¶m, bool background) { //////////////////////////////////////////////////////////////////// void PGEntry:: keystroke(const MouseWatcherParameter ¶m, bool background) { + ReMutexHolder holder(_lock); if (get_active()) { if (param.has_keycode()) { // Make sure _text is initialized properly. @@ -402,6 +407,7 @@ keystroke(const MouseWatcherParameter ¶m, bool background) { //////////////////////////////////////////////////////////////////// void PGEntry:: candidate(const MouseWatcherParameter ¶m, bool background) { + ReMutexHolder holder(_lock); if (get_active()) { if (param.has_candidate()) { // Save the candidate string so it can be displayed. @@ -426,6 +432,7 @@ candidate(const MouseWatcherParameter ¶m, bool background) { //////////////////////////////////////////////////////////////////// void PGEntry:: accept(const MouseWatcherParameter ¶m) { + ReMutexHolder holder(_lock); PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param); string event = get_accept_event(param.get_button()); play_sound(event); @@ -441,6 +448,7 @@ accept(const MouseWatcherParameter ¶m) { //////////////////////////////////////////////////////////////////// void PGEntry:: accept_failed(const MouseWatcherParameter ¶m) { + ReMutexHolder holder(_lock); PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param); string event = get_accept_failed_event(param.get_button()); play_sound(event); @@ -458,6 +466,7 @@ accept_failed(const MouseWatcherParameter ¶m) { //////////////////////////////////////////////////////////////////// void PGEntry:: overflow(const MouseWatcherParameter ¶m) { + ReMutexHolder holder(_lock); PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param); string event = get_overflow_event(); play_sound(event); @@ -472,6 +481,7 @@ overflow(const MouseWatcherParameter ¶m) { //////////////////////////////////////////////////////////////////// void PGEntry:: type(const MouseWatcherParameter ¶m) { + ReMutexHolder holder(_lock); PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param); string event = get_type_event(); play_sound(event); @@ -486,6 +496,7 @@ type(const MouseWatcherParameter ¶m) { //////////////////////////////////////////////////////////////////// void PGEntry:: erase(const MouseWatcherParameter ¶m) { + ReMutexHolder holder(_lock); PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param); string event = get_erase_event(); play_sound(event); @@ -503,6 +514,7 @@ erase(const MouseWatcherParameter ¶m) { //////////////////////////////////////////////////////////////////// void PGEntry:: setup(float width, int num_lines) { + ReMutexHolder holder(_lock); setup_minimal(width, num_lines); TextNode *text_node = get_text_def(S_focus); @@ -570,6 +582,7 @@ setup(float width, int num_lines) { //////////////////////////////////////////////////////////////////// void PGEntry:: setup_minimal(float width, int num_lines) { + ReMutexHolder holder(_lock); set_text(string()); _cursor_position = 0; set_max_chars(0); @@ -608,6 +621,7 @@ setup_minimal(float width, int num_lines) { //////////////////////////////////////////////////////////////////// void PGEntry:: set_text_def(int state, TextNode *node) { + ReMutexHolder holder(_lock); nassertv(state >= 0 && state < 1000); // Sanity check. if (node == (TextNode *)NULL && state >= (int)_text_defs.size()) { // If we're setting it to NULL, we don't need to slot a new one. @@ -627,6 +641,7 @@ set_text_def(int state, TextNode *node) { //////////////////////////////////////////////////////////////////// TextNode *PGEntry:: get_text_def(int state) const { + ReMutexHolder holder(_lock); if (state < 0 || state >= (int)_text_defs.size()) { // If we don't have a definition, use the global one. return get_text_node(); @@ -646,6 +661,7 @@ get_text_def(int state) const { //////////////////////////////////////////////////////////////////// void PGEntry:: set_active(bool active) { + ReMutexHolder holder(_lock); PGItem::set_active(active); update_state(); } @@ -658,6 +674,7 @@ set_active(bool active) { //////////////////////////////////////////////////////////////////// void PGEntry:: set_focus(bool focus) { + ReMutexHolder holder(_lock); PGItem::set_focus(focus); _blink_start = ClockObject::get_global_clock()->get_frame_time(); update_state(); @@ -673,6 +690,7 @@ set_focus(bool focus) { //////////////////////////////////////////////////////////////////// bool PGEntry:: is_wtext() const { + ReMutexHolder holder(_lock); for (int i = 0; i < _text.get_num_characters(); ++i) { wchar_t ch = _text.get_character(i); if ((ch & ~0x7f) != 0) { diff --git a/panda/src/pgui/pgItem.I b/panda/src/pgui/pgItem.I index 5044f28992..618ee8b160 100644 --- a/panda/src/pgui/pgItem.I +++ b/panda/src/pgui/pgItem.I @@ -13,6 +13,17 @@ //////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////// +// Function: PGItem::set_name +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void PGItem:: +set_name(const string &name) { + Namable::set_name(name); + _lock.set_name(name); +} + //////////////////////////////////////////////////////////////////// // Function: PGItem::get_region // Access: Public @@ -26,6 +37,7 @@ //////////////////////////////////////////////////////////////////// INLINE PGMouseWatcherRegion *PGItem:: get_region() const { + ReMutexHolder holder(_lock); return _region; } @@ -40,6 +52,7 @@ get_region() const { //////////////////////////////////////////////////////////////////// INLINE void PGItem:: set_notify(PGItemNotify *notify) { + ReMutexHolder holder(_lock); if (_notify != (PGItemNotify *)NULL) { _notify->remove_item(this); } @@ -57,6 +70,7 @@ set_notify(PGItemNotify *notify) { //////////////////////////////////////////////////////////////////// INLINE bool PGItem:: has_notify() const { + ReMutexHolder holder(_lock); return (_notify != (PGItemNotify *)NULL); } @@ -69,6 +83,7 @@ has_notify() const { //////////////////////////////////////////////////////////////////// INLINE PGItemNotify *PGItem:: get_notify() const { + ReMutexHolder holder(_lock); return _notify; } @@ -97,6 +112,7 @@ set_frame(float left, float right, float bottom, float top) { //////////////////////////////////////////////////////////////////// INLINE void PGItem:: set_frame(const LVecBase4f &frame) { + ReMutexHolder holder(_lock); if (!_has_frame || _frame != frame) { _has_frame = true; _frame = frame; @@ -113,6 +129,7 @@ set_frame(const LVecBase4f &frame) { //////////////////////////////////////////////////////////////////// INLINE const LVecBase4f &PGItem:: get_frame() const { + ReMutexHolder holder(_lock); nassertr(has_frame(), _frame); return _frame; } @@ -125,6 +142,7 @@ get_frame() const { //////////////////////////////////////////////////////////////////// INLINE bool PGItem:: has_frame() const { + ReMutexHolder holder(_lock); return _has_frame; } @@ -137,6 +155,7 @@ has_frame() const { //////////////////////////////////////////////////////////////////// INLINE void PGItem:: clear_frame() { + ReMutexHolder holder(_lock); if (_has_frame) { _has_frame = false; frame_changed(); @@ -154,6 +173,7 @@ clear_frame() { //////////////////////////////////////////////////////////////////// INLINE void PGItem:: set_state(int state) { + ReMutexHolder holder(_lock); _state = state; } @@ -165,6 +185,7 @@ set_state(int state) { //////////////////////////////////////////////////////////////////// INLINE int PGItem:: get_state() const { + ReMutexHolder holder(_lock); return _state; } @@ -176,6 +197,7 @@ get_state() const { //////////////////////////////////////////////////////////////////// INLINE bool PGItem:: get_active() const { + ReMutexHolder holder(_lock); return (_flags & F_active) != 0; } @@ -187,6 +209,7 @@ get_active() const { //////////////////////////////////////////////////////////////////// INLINE bool PGItem:: get_focus() const { + ReMutexHolder holder(_lock); return (_flags & F_focus) != 0; } @@ -198,6 +221,7 @@ get_focus() const { //////////////////////////////////////////////////////////////////// INLINE bool PGItem:: get_background_focus() const { + ReMutexHolder holder(_lock); return (_flags & F_background_focus) != 0; } @@ -210,6 +234,7 @@ get_background_focus() const { //////////////////////////////////////////////////////////////////// INLINE void PGItem:: set_suppress_flags(int suppress_flags) { + ReMutexHolder holder(_lock); _region->set_suppress_flags(suppress_flags); } @@ -222,6 +247,7 @@ set_suppress_flags(int suppress_flags) { //////////////////////////////////////////////////////////////////// INLINE int PGItem:: get_suppress_flags() const { + ReMutexHolder holder(_lock); return _region->get_suppress_flags(); } @@ -235,6 +261,7 @@ get_suppress_flags() const { //////////////////////////////////////////////////////////////////// INLINE const string &PGItem:: get_id() const { + ReMutexHolder holder(_lock); return _region->get_name(); } @@ -253,6 +280,7 @@ get_id() const { //////////////////////////////////////////////////////////////////// INLINE void PGItem:: set_id(const string &id) { + ReMutexHolder holder(_lock); _region->set_name(id); } @@ -395,6 +423,7 @@ get_keystroke_prefix() { //////////////////////////////////////////////////////////////////// INLINE string PGItem:: get_enter_event() const { + ReMutexHolder holder(_lock); return get_enter_prefix() + get_id(); } @@ -407,6 +436,7 @@ get_enter_event() const { //////////////////////////////////////////////////////////////////// INLINE string PGItem:: get_exit_event() const { + ReMutexHolder holder(_lock); return get_exit_prefix() + get_id(); } @@ -421,6 +451,7 @@ get_exit_event() const { //////////////////////////////////////////////////////////////////// INLINE string PGItem:: get_within_event() const { + ReMutexHolder holder(_lock); return get_within_prefix() + get_id(); } @@ -436,6 +467,7 @@ get_within_event() const { //////////////////////////////////////////////////////////////////// INLINE string PGItem:: get_without_event() const { + ReMutexHolder holder(_lock); return get_without_prefix() + get_id(); } @@ -447,6 +479,7 @@ get_without_event() const { //////////////////////////////////////////////////////////////////// INLINE string PGItem:: get_focus_in_event() const { + ReMutexHolder holder(_lock); return get_focus_in_prefix() + get_id(); } @@ -458,6 +491,7 @@ get_focus_in_event() const { //////////////////////////////////////////////////////////////////// INLINE string PGItem:: get_focus_out_event() const { + ReMutexHolder holder(_lock); return get_focus_out_prefix() + get_id(); } @@ -471,6 +505,7 @@ get_focus_out_event() const { //////////////////////////////////////////////////////////////////// INLINE string PGItem:: get_press_event(const ButtonHandle &button) const { + ReMutexHolder holder(_lock); return get_press_prefix() + button.get_name() + "-" + get_id(); } @@ -484,6 +519,7 @@ get_press_event(const ButtonHandle &button) const { //////////////////////////////////////////////////////////////////// INLINE string PGItem:: get_repeat_event(const ButtonHandle &button) const { + ReMutexHolder holder(_lock); return get_repeat_prefix() + button.get_name() + "-" + get_id(); } @@ -497,6 +533,7 @@ get_repeat_event(const ButtonHandle &button) const { //////////////////////////////////////////////////////////////////// INLINE string PGItem:: get_release_event(const ButtonHandle &button) const { + ReMutexHolder holder(_lock); return get_release_prefix() + button.get_name() + "-" + get_id(); } @@ -508,6 +545,7 @@ get_release_event(const ButtonHandle &button) const { //////////////////////////////////////////////////////////////////// INLINE string PGItem:: get_keystroke_event() const { + ReMutexHolder holder(_lock); return get_keystroke_prefix() + get_id(); } @@ -543,6 +581,7 @@ get_focus_item() { //////////////////////////////////////////////////////////////////// INLINE LMatrix4f PGItem:: get_frame_inv_xform() const { + ReMutexHolder holder(_lock); return _frame_inv_xform; } diff --git a/panda/src/pgui/pgItem.cxx b/panda/src/pgui/pgItem.cxx index e12f8b2a3c..48ce10dd9f 100644 --- a/panda/src/pgui/pgItem.cxx +++ b/panda/src/pgui/pgItem.cxx @@ -58,7 +58,8 @@ is_right(const LVector2f &v1, const LVector2f &v2) { //////////////////////////////////////////////////////////////////// PGItem:: PGItem(const string &name) : - PandaNode(name) + PandaNode(name), + _lock(name) { set_cull_callback(); @@ -142,6 +143,7 @@ PGItem(const PGItem ©) : //////////////////////////////////////////////////////////////////// PandaNode *PGItem:: make_copy() const { + ReMutexHolder holder(_lock); return new PGItem(*this); } @@ -154,6 +156,7 @@ make_copy() const { //////////////////////////////////////////////////////////////////// void PGItem:: transform_changed() { + ReMutexHolder holder(_lock); PandaNode::transform_changed(); if (has_notify()) { get_notify()->item_transform_changed(this); @@ -169,6 +172,7 @@ transform_changed() { //////////////////////////////////////////////////////////////////// void PGItem:: draw_mask_changed() { + ReMutexHolder holder(_lock); PandaNode::draw_mask_changed(); if (has_notify()) { get_notify()->item_draw_mask_changed(this); @@ -202,6 +206,7 @@ draw_mask_changed() { //////////////////////////////////////////////////////////////////// bool PGItem:: cull_callback(CullTraverser *trav, CullTraverserData &data) { + ReMutexHolder holder(_lock); bool this_node_hidden = data.is_this_node_hidden(trav); if (!this_node_hidden && has_frame() && get_active()) { // The item has a frame, so we want to generate a region for it @@ -296,8 +301,11 @@ is_renderable() const { // thing. //////////////////////////////////////////////////////////////////// void PGItem:: -compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage, +compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, + int &internal_vertices, + int pipeline_stage, Thread *current_thread) const { + ReMutexHolder holder(_lock, current_thread); int num_vertices = 0; // First, get ourselves a fresh, empty bounding volume. @@ -330,9 +338,8 @@ compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage, bound->around(child_begin, child_end); - bdata->_internal_bounds = bound; - bdata->_internal_vertices = num_vertices; - bdata->_internal_bounds_stale = false; + internal_bounds = bound; + internal_vertices = num_vertices; } //////////////////////////////////////////////////////////////////// @@ -345,18 +352,20 @@ compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage, //////////////////////////////////////////////////////////////////// void PGItem:: r_prepare_scene(const RenderState *state, - PreparedGraphicsObjects *prepared_objects) { + PreparedGraphicsObjects *prepared_objects, + Thread *current_thread) { + ReMutexHolder holder(_lock); StateDefs::iterator di; for (di = _state_defs.begin(); di != _state_defs.end(); ++di) { NodePath &root = (*di)._root; if (!root.is_empty()) { PandaNode *child = root.node(); CPT(RenderState) child_state = state->compose(child->get_state()); - child->r_prepare_scene(child_state, prepared_objects); + child->r_prepare_scene(child_state, prepared_objects, current_thread); } } - PandaNode::r_prepare_scene(state, prepared_objects); + PandaNode::r_prepare_scene(state, prepared_objects, current_thread); } //////////////////////////////////////////////////////////////////// @@ -368,6 +377,7 @@ r_prepare_scene(const RenderState *state, //////////////////////////////////////////////////////////////////// void PGItem:: xform(const LMatrix4f &mat) { + ReMutexHolder holder(_lock); // Transform the frame. LPoint3f ll(_frame[0], 0.0f, _frame[2]); LPoint3f ur(_frame[1], 0.0f, _frame[3]); @@ -407,6 +417,7 @@ bool PGItem:: activate_region(const LMatrix4f &transform, int sort, const ClipPlaneAttrib *cpa, const ScissorAttrib *sa) { + ReMutexHolder holder(_lock); // Transform all four vertices, and get the new bounding box. This // way the region works (mostly) even if has been rotated. LPoint3f ll(_frame[0], 0.0f, _frame[2]); @@ -503,6 +514,7 @@ activate_region(const LMatrix4f &transform, int sort, //////////////////////////////////////////////////////////////////// void PGItem:: enter_region(const MouseWatcherParameter ¶m) { + ReMutexHolder holder(_lock); if (pgui_cat.is_debug()) { pgui_cat.debug() << *this << "::enter_region(" << param << ")\n"; @@ -529,6 +541,7 @@ enter_region(const MouseWatcherParameter ¶m) { //////////////////////////////////////////////////////////////////// void PGItem:: exit_region(const MouseWatcherParameter ¶m) { + ReMutexHolder holder(_lock); if (pgui_cat.is_debug()) { pgui_cat.debug() << *this << "::exit_region(" << param << ")\n"; @@ -558,6 +571,7 @@ exit_region(const MouseWatcherParameter ¶m) { //////////////////////////////////////////////////////////////////// void PGItem:: within_region(const MouseWatcherParameter ¶m) { + ReMutexHolder holder(_lock); if (pgui_cat.is_debug()) { pgui_cat.debug() << *this << "::within_region(" << param << ")\n"; @@ -582,6 +596,7 @@ within_region(const MouseWatcherParameter ¶m) { //////////////////////////////////////////////////////////////////// void PGItem:: without_region(const MouseWatcherParameter ¶m) { + ReMutexHolder holder(_lock); if (pgui_cat.is_debug()) { pgui_cat.debug() << *this << "::without_region(" << param << ")\n"; @@ -605,6 +620,7 @@ without_region(const MouseWatcherParameter ¶m) { //////////////////////////////////////////////////////////////////// void PGItem:: focus_in() { + ReMutexHolder holder(_lock); if (pgui_cat.is_debug()) { pgui_cat.debug() << *this << "::focus_in()\n"; @@ -627,6 +643,7 @@ focus_in() { //////////////////////////////////////////////////////////////////// void PGItem:: focus_out() { + ReMutexHolder holder(_lock); if (pgui_cat.is_debug()) { pgui_cat.debug() << *this << "::focus_out()\n"; @@ -650,6 +667,7 @@ focus_out() { //////////////////////////////////////////////////////////////////// void PGItem:: press(const MouseWatcherParameter ¶m, bool background) { + ReMutexHolder holder(_lock); if (pgui_cat.is_debug()) { pgui_cat.debug() << *this << "::press(" << param << ", " << background << ")\n"; @@ -681,6 +699,7 @@ press(const MouseWatcherParameter ¶m, bool background) { //////////////////////////////////////////////////////////////////// void PGItem:: release(const MouseWatcherParameter ¶m, bool background) { + ReMutexHolder holder(_lock); if (pgui_cat.is_debug()) { pgui_cat.debug() << *this << "::release(" << param << ", " << background << ")\n"; @@ -706,6 +725,7 @@ release(const MouseWatcherParameter ¶m, bool background) { //////////////////////////////////////////////////////////////////// void PGItem:: keystroke(const MouseWatcherParameter ¶m, bool background) { + ReMutexHolder holder(_lock); if (pgui_cat.is_debug()) { pgui_cat.debug() << *this << "::keystroke(" << param << ", " << background << ")\n"; @@ -731,6 +751,7 @@ keystroke(const MouseWatcherParameter ¶m, bool background) { //////////////////////////////////////////////////////////////////// void PGItem:: candidate(const MouseWatcherParameter ¶m, bool background) { + ReMutexHolder holder(_lock); if (pgui_cat.is_debug()) { pgui_cat.debug() << *this << "::candidate(" << param << ", " << background << ")\n"; @@ -752,6 +773,7 @@ candidate(const MouseWatcherParameter ¶m, bool background) { //////////////////////////////////////////////////////////////////// void PGItem:: move(const MouseWatcherParameter ¶m) { + ReMutexHolder holder(_lock); if (pgui_cat.is_debug()) { pgui_cat.debug() << *this << "::move(" << param << ")\n"; @@ -841,6 +863,7 @@ background_candidate(const MouseWatcherParameter ¶m) { //////////////////////////////////////////////////////////////////// void PGItem:: set_active(bool active) { + ReMutexHolder holder(_lock); if (active) { _flags |= F_active; } else { @@ -867,6 +890,7 @@ set_active(bool active) { //////////////////////////////////////////////////////////////////// void PGItem:: set_focus(bool focus) { + ReMutexHolder holder(_lock); if (focus) { if (!get_active()) { // Cannot set focus on an inactive item. @@ -911,6 +935,7 @@ set_focus(bool focus) { //////////////////////////////////////////////////////////////////// void PGItem:: set_background_focus(bool focus) { + ReMutexHolder holder(_lock); if (focus != get_background_focus()) { if (focus) { // Activate background focus. @@ -940,6 +965,7 @@ set_background_focus(bool focus) { //////////////////////////////////////////////////////////////////// int PGItem:: get_num_state_defs() const { + ReMutexHolder holder(_lock); return _state_defs.size(); } @@ -952,6 +978,7 @@ get_num_state_defs() const { //////////////////////////////////////////////////////////////////// bool PGItem:: has_state_def(int state) const { + ReMutexHolder holder(_lock); if (state < 0 || state >= (int)_state_defs.size()) { return false; } @@ -967,6 +994,7 @@ has_state_def(int state) const { //////////////////////////////////////////////////////////////////// void PGItem:: clear_state_def(int state) { + ReMutexHolder holder(_lock); if (state < 0 || state >= (int)_state_defs.size()) { return; } @@ -988,6 +1016,7 @@ clear_state_def(int state) { //////////////////////////////////////////////////////////////////// NodePath &PGItem:: get_state_def(int state) { + ReMutexHolder holder(_lock); nassertr(state >= 0 && state < 1000, get_state_def(0)); // Sanity check. slot_state_def(state); @@ -1012,6 +1041,7 @@ get_state_def(int state) { //////////////////////////////////////////////////////////////////// NodePath PGItem:: instance_to_state_def(int state, const NodePath &path) { + ReMutexHolder holder(_lock); if (path.is_empty()) { // If the source is empty, quietly do nothing. return NodePath(); @@ -1030,6 +1060,7 @@ instance_to_state_def(int state, const NodePath &path) { //////////////////////////////////////////////////////////////////// PGFrameStyle PGItem:: get_frame_style(int state) { + ReMutexHolder holder(_lock); if (state < 0 || state >= (int)_state_defs.size()) { return PGFrameStyle(); } @@ -1044,14 +1075,15 @@ get_frame_style(int state) { //////////////////////////////////////////////////////////////////// void PGItem:: set_frame_style(int state, const PGFrameStyle &style) { + ReMutexHolder holder(_lock); // Get the state def node, mainly to ensure that this state is // slotted and listed as having been defined. NodePath &root = get_state_def(state); nassertv(!root.is_empty()); - + _state_defs[state]._frame_style = style; _state_defs[state]._frame_stale = true; - + mark_internal_bounds_stale(); } @@ -1064,6 +1096,7 @@ set_frame_style(int state, const PGFrameStyle &style) { //////////////////////////////////////////////////////////////////// void PGItem:: set_sound(const string &event, AudioSound *sound) { + ReMutexHolder holder(_lock); _sounds[event] = sound; } @@ -1075,6 +1108,7 @@ set_sound(const string &event, AudioSound *sound) { //////////////////////////////////////////////////////////////////// void PGItem:: clear_sound(const string &event) { + ReMutexHolder holder(_lock); _sounds.erase(event); } @@ -1086,6 +1120,7 @@ clear_sound(const string &event) { //////////////////////////////////////////////////////////////////// AudioSound *PGItem:: get_sound(const string &event) const { + ReMutexHolder holder(_lock); Sounds::const_iterator si = _sounds.find(event); if (si != _sounds.end()) { return (*si).second; @@ -1101,6 +1136,7 @@ get_sound(const string &event) const { //////////////////////////////////////////////////////////////////// bool PGItem:: has_sound(const string &event) const { + ReMutexHolder holder(_lock); return (_sounds.count(event) != 0); } #endif // HAVE_AUDIO @@ -1134,6 +1170,7 @@ get_text_node() { void PGItem:: play_sound(const string &event) { #ifdef HAVE_AUDIO + ReMutexHolder holder(_lock); Sounds::const_iterator si = _sounds.find(event); if (si != _sounds.end()) { AudioSound *sound = (*si).second; diff --git a/panda/src/pgui/pgItem.h b/panda/src/pgui/pgItem.h index 1c2daed7af..6d017305dd 100644 --- a/panda/src/pgui/pgItem.h +++ b/panda/src/pgui/pgItem.h @@ -29,6 +29,8 @@ #include "textNode.h" #include "plane.h" #include "pmap.h" +#include "reMutex.h" +#include "reMutexHolder.h" class PGTop; class MouseWatcherParameter; @@ -55,6 +57,8 @@ PUBLISHED: PGItem(const string &name); virtual ~PGItem(); + INLINE void set_name(const string &name); + protected: PGItem(const PGItem ©); @@ -65,11 +69,14 @@ protected: virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data); virtual bool is_renderable() const; - virtual void compute_internal_bounds(BoundsData *bdata, int pipeline_stage, + virtual void compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, + int &internal_vertices, + int pipeline_stage, Thread *current_thread) const; virtual void r_prepare_scene(const RenderState *state, - PreparedGraphicsObjects *prepared_objects); + PreparedGraphicsObjects *prepared_objects, + Thread *current_thread); public: virtual void xform(const LMatrix4f &mat); @@ -191,6 +198,9 @@ private: bool clip_frame(pvector &source_points, const Planef &plane) const; +protected: + ReMutex _lock; + private: PGItemNotify *_notify; diff --git a/panda/src/pgui/pgScrollFrame.I b/panda/src/pgui/pgScrollFrame.I index 1412c41245..c13ba5bc38 100644 --- a/panda/src/pgui/pgScrollFrame.I +++ b/panda/src/pgui/pgScrollFrame.I @@ -34,6 +34,7 @@ set_virtual_frame(float left, float right, float bottom, float top) { //////////////////////////////////////////////////////////////////// INLINE void PGScrollFrame:: set_virtual_frame(const LVecBase4f &frame) { + ReMutexHolder holder(_lock); _has_virtual_frame = true; _virtual_frame = frame; @@ -52,6 +53,7 @@ set_virtual_frame(const LVecBase4f &frame) { //////////////////////////////////////////////////////////////////// INLINE const LVecBase4f &PGScrollFrame:: get_virtual_frame() const { + ReMutexHolder holder(_lock); return _has_virtual_frame ? _virtual_frame : get_clip_frame(); } @@ -64,6 +66,7 @@ get_virtual_frame() const { //////////////////////////////////////////////////////////////////// INLINE bool PGScrollFrame:: has_virtual_frame() const { + ReMutexHolder holder(_lock); return _has_virtual_frame; } @@ -77,6 +80,7 @@ has_virtual_frame() const { //////////////////////////////////////////////////////////////////// INLINE void PGScrollFrame:: clear_virtual_frame() { + ReMutexHolder holder(_lock); _has_virtual_frame = false; } @@ -92,6 +96,7 @@ clear_virtual_frame() { //////////////////////////////////////////////////////////////////// INLINE void PGScrollFrame:: set_manage_pieces(bool manage_pieces) { + ReMutexHolder holder(_lock); _manage_pieces = manage_pieces; _needs_remanage = true; _needs_recompute_clip = true; @@ -105,6 +110,7 @@ set_manage_pieces(bool manage_pieces) { //////////////////////////////////////////////////////////////////// INLINE bool PGScrollFrame:: get_manage_pieces() const { + ReMutexHolder holder(_lock); return _manage_pieces; } @@ -122,6 +128,7 @@ get_manage_pieces() const { //////////////////////////////////////////////////////////////////// INLINE void PGScrollFrame:: set_auto_hide(bool auto_hide) { + ReMutexHolder holder(_lock); _auto_hide = auto_hide; if (_auto_hide) { set_manage_pieces(true); @@ -137,6 +144,7 @@ set_auto_hide(bool auto_hide) { //////////////////////////////////////////////////////////////////// INLINE bool PGScrollFrame:: get_auto_hide() const { + ReMutexHolder holder(_lock); return _auto_hide; } @@ -150,6 +158,7 @@ get_auto_hide() const { //////////////////////////////////////////////////////////////////// INLINE void PGScrollFrame:: set_horizontal_slider(PGSliderBar *horizontal_slider) { + ReMutexHolder holder(_lock); if (_horizontal_slider != (PGSliderBar *)NULL) { _horizontal_slider->set_notify(NULL); } @@ -181,6 +190,7 @@ clear_horizontal_slider() { //////////////////////////////////////////////////////////////////// INLINE PGSliderBar *PGScrollFrame:: get_horizontal_slider() const { + ReMutexHolder holder(_lock); return _horizontal_slider; } @@ -194,6 +204,7 @@ get_horizontal_slider() const { //////////////////////////////////////////////////////////////////// INLINE void PGScrollFrame:: set_vertical_slider(PGSliderBar *vertical_slider) { + ReMutexHolder holder(_lock); if (_vertical_slider != (PGSliderBar *)NULL) { _vertical_slider->set_notify(NULL); } @@ -225,6 +236,7 @@ clear_vertical_slider() { //////////////////////////////////////////////////////////////////// INLINE PGSliderBar *PGScrollFrame:: get_vertical_slider() const { + ReMutexHolder holder(_lock); return _vertical_slider; } @@ -236,6 +248,7 @@ get_vertical_slider() const { //////////////////////////////////////////////////////////////////// INLINE void PGScrollFrame:: recompute() { + ReMutexHolder holder(_lock); recompute_clip(); recompute_canvas(); } diff --git a/panda/src/pgui/pgScrollFrame.cxx b/panda/src/pgui/pgScrollFrame.cxx index 0d1651fbe9..acd4756b75 100644 --- a/panda/src/pgui/pgScrollFrame.cxx +++ b/panda/src/pgui/pgScrollFrame.cxx @@ -76,6 +76,7 @@ PGScrollFrame(const PGScrollFrame ©) : //////////////////////////////////////////////////////////////////// PandaNode *PGScrollFrame:: make_copy() const { + ReMutexHolder holder(_lock); return new PGScrollFrame(*this); } @@ -106,6 +107,7 @@ make_copy() const { //////////////////////////////////////////////////////////////////// bool PGScrollFrame:: cull_callback(CullTraverser *trav, CullTraverserData &data) { + ReMutexHolder holder(_lock); if (_manage_pieces && _needs_remanage) { remanage(); } @@ -127,6 +129,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { //////////////////////////////////////////////////////////////////// void PGScrollFrame:: xform(const LMatrix4f &mat) { + ReMutexHolder holder(_lock); PGVirtualFrame::xform(mat); _needs_remanage = true; @@ -143,6 +146,7 @@ void PGScrollFrame:: setup(float width, float height, float left, float right, float bottom, float top, float slider_width, float bevel) { + ReMutexHolder holder(_lock); set_state(0); clear_state_def(0); @@ -196,6 +200,7 @@ setup(float width, float height, //////////////////////////////////////////////////////////////////// void PGScrollFrame:: remanage() { + ReMutexHolder holder(_lock); _needs_remanage = false; const LVecBase4f &frame = get_frame(); @@ -312,6 +317,7 @@ remanage() { //////////////////////////////////////////////////////////////////// void PGScrollFrame:: frame_changed() { + ReMutexHolder holder(_lock); PGVirtualFrame::frame_changed(); _needs_remanage = true; _needs_recompute_clip = true; @@ -325,6 +331,7 @@ frame_changed() { //////////////////////////////////////////////////////////////////// void PGScrollFrame:: item_transform_changed(PGItem *) { + ReMutexHolder holder(_lock); _needs_recompute_clip = true; } @@ -336,6 +343,7 @@ item_transform_changed(PGItem *) { //////////////////////////////////////////////////////////////////// void PGScrollFrame:: item_frame_changed(PGItem *) { + ReMutexHolder holder(_lock); _needs_recompute_clip = true; } @@ -347,6 +355,7 @@ item_frame_changed(PGItem *) { //////////////////////////////////////////////////////////////////// void PGScrollFrame:: item_draw_mask_changed(PGItem *) { + ReMutexHolder holder(_lock); _needs_remanage = true; _needs_recompute_clip = true; } @@ -359,6 +368,7 @@ item_draw_mask_changed(PGItem *) { //////////////////////////////////////////////////////////////////// void PGScrollFrame:: slider_bar_adjust(PGSliderBar *) { + ReMutexHolder holder(_lock); _needs_recompute_canvas = true; } @@ -370,6 +380,7 @@ slider_bar_adjust(PGSliderBar *) { //////////////////////////////////////////////////////////////////// void PGScrollFrame:: recompute_clip() { + ReMutexHolder holder(_lock); _needs_recompute_clip = false; _needs_recompute_canvas = true; @@ -397,6 +408,7 @@ recompute_clip() { //////////////////////////////////////////////////////////////////// void PGScrollFrame:: recompute_canvas() { + ReMutexHolder holder(_lock); _needs_recompute_canvas = false; const LVecBase4f &clip = get_clip_frame(); @@ -423,6 +435,7 @@ float PGScrollFrame:: interpolate_canvas(float clip_min, float clip_max, float canvas_min, float canvas_max, PGSliderBar *slider_bar) { + ReMutexHolder holder(_lock); float t = 0.0f; if (slider_bar != (PGSliderBar *)NULL) { t = slider_bar->get_ratio(); diff --git a/panda/src/pgui/pgSliderBar.I b/panda/src/pgui/pgSliderBar.I index 20a9eb4c73..f1e3298a0a 100755 --- a/panda/src/pgui/pgSliderBar.I +++ b/panda/src/pgui/pgSliderBar.I @@ -60,6 +60,7 @@ get_notify() const { //////////////////////////////////////////////////////////////////// INLINE void PGSliderBar:: set_axis(const LVector3f &axis) { + ReMutexHolder holder(_lock); _axis = axis; _needs_remanage = true; _needs_recompute = true; @@ -73,6 +74,7 @@ set_axis(const LVector3f &axis) { //////////////////////////////////////////////////////////////////// INLINE const LVector3f &PGSliderBar:: get_axis() const { + ReMutexHolder holder(_lock); return _axis; } @@ -83,6 +85,7 @@ get_axis() const { //////////////////////////////////////////////////////////////////// INLINE void PGSliderBar:: set_range(float min_value, float max_value) { + ReMutexHolder holder(_lock); nassertv(min_value != max_value); _min_value = min_value; _max_value = max_value; @@ -101,6 +104,7 @@ set_range(float min_value, float max_value) { //////////////////////////////////////////////////////////////////// INLINE float PGSliderBar:: get_min_value() const { + ReMutexHolder holder(_lock); return _min_value; } @@ -112,6 +116,7 @@ get_min_value() const { //////////////////////////////////////////////////////////////////// INLINE float PGSliderBar:: get_max_value() const { + ReMutexHolder holder(_lock); return _max_value; } @@ -123,6 +128,7 @@ get_max_value() const { //////////////////////////////////////////////////////////////////// INLINE void PGSliderBar:: set_scroll_size(float value) { + ReMutexHolder holder(_lock); _scroll_value = value; _needs_recompute = true; } @@ -134,6 +140,7 @@ set_scroll_size(float value) { //////////////////////////////////////////////////////////////////// INLINE float PGSliderBar:: get_scroll_size() const { + ReMutexHolder holder(_lock); return _scroll_value; } @@ -148,6 +155,7 @@ get_scroll_size() const { //////////////////////////////////////////////////////////////////// INLINE void PGSliderBar:: set_page_size(float value) { + ReMutexHolder holder(_lock); _page_value = value; _needs_recompute = true; } @@ -159,6 +167,7 @@ set_page_size(float value) { //////////////////////////////////////////////////////////////////// INLINE float PGSliderBar:: get_page_size() const { + ReMutexHolder holder(_lock); return _page_value; } @@ -171,6 +180,7 @@ get_page_size() const { //////////////////////////////////////////////////////////////////// INLINE void PGSliderBar:: set_value(float value) { + ReMutexHolder holder(_lock); set_ratio((value - _min_value) / (_max_value - _min_value)); } @@ -181,6 +191,7 @@ set_value(float value) { //////////////////////////////////////////////////////////////////// INLINE float PGSliderBar:: get_value() const { + ReMutexHolder holder(_lock); return get_ratio() * (_max_value - _min_value) + _min_value; } @@ -192,6 +203,7 @@ get_value() const { //////////////////////////////////////////////////////////////////// INLINE void PGSliderBar:: set_ratio(float ratio) { + ReMutexHolder holder(_lock); if (!is_button_down()) { internal_set_ratio(ratio); } @@ -205,6 +217,7 @@ set_ratio(float ratio) { //////////////////////////////////////////////////////////////////// INLINE float PGSliderBar:: get_ratio() const { + ReMutexHolder holder(_lock); return _ratio; } @@ -218,6 +231,7 @@ get_ratio() const { //////////////////////////////////////////////////////////////////// INLINE bool PGSliderBar:: is_button_down() const { + ReMutexHolder holder(_lock); return _dragging || _mouse_button_page || (_scroll_button_held != (PGItem *)NULL); } @@ -232,6 +246,7 @@ is_button_down() const { //////////////////////////////////////////////////////////////////// INLINE void PGSliderBar:: set_resize_thumb(bool resize_thumb) { + ReMutexHolder holder(_lock); _resize_thumb = resize_thumb; _needs_recompute = true; } @@ -244,6 +259,7 @@ set_resize_thumb(bool resize_thumb) { //////////////////////////////////////////////////////////////////// INLINE bool PGSliderBar:: get_resize_thumb() const { + ReMutexHolder holder(_lock); return _resize_thumb; } @@ -258,6 +274,7 @@ get_resize_thumb() const { //////////////////////////////////////////////////////////////////// INLINE void PGSliderBar:: set_manage_pieces(bool manage_pieces) { + ReMutexHolder holder(_lock); _manage_pieces = manage_pieces; _needs_remanage = true; _needs_recompute = true; @@ -271,6 +288,7 @@ set_manage_pieces(bool manage_pieces) { //////////////////////////////////////////////////////////////////// INLINE bool PGSliderBar:: get_manage_pieces() const { + ReMutexHolder holder(_lock); return _manage_pieces; } @@ -288,6 +306,7 @@ get_manage_pieces() const { //////////////////////////////////////////////////////////////////// INLINE void PGSliderBar:: set_thumb_button(PGButton *thumb_button) { + ReMutexHolder holder(_lock); if (_thumb_button != (PGButton *)NULL) { _thumb_button->set_notify(NULL); } @@ -319,6 +338,7 @@ clear_thumb_button() { //////////////////////////////////////////////////////////////////// INLINE PGButton *PGSliderBar:: get_thumb_button() const { + ReMutexHolder holder(_lock); return _thumb_button; } @@ -336,6 +356,7 @@ get_thumb_button() const { //////////////////////////////////////////////////////////////////// INLINE void PGSliderBar:: set_left_button(PGButton *left_button) { + ReMutexHolder holder(_lock); if (_left_button != (PGButton *)NULL) { _left_button->set_notify(NULL); } @@ -368,6 +389,7 @@ clear_left_button() { //////////////////////////////////////////////////////////////////// INLINE PGButton *PGSliderBar:: get_left_button() const { + ReMutexHolder holder(_lock); return _left_button; } @@ -385,6 +407,7 @@ get_left_button() const { //////////////////////////////////////////////////////////////////// INLINE void PGSliderBar:: set_right_button(PGButton *right_button) { + ReMutexHolder holder(_lock); if (_right_button != (PGButton *)NULL) { _right_button->set_notify(NULL); } @@ -417,6 +440,7 @@ clear_right_button() { //////////////////////////////////////////////////////////////////// INLINE PGButton *PGSliderBar:: get_right_button() const { + ReMutexHolder holder(_lock); return _right_button; } @@ -441,6 +465,7 @@ get_adjust_prefix() { //////////////////////////////////////////////////////////////////// INLINE string PGSliderBar:: get_adjust_event() const { + ReMutexHolder holder(_lock); return get_adjust_prefix() + get_id(); } diff --git a/panda/src/pgui/pgSliderBar.cxx b/panda/src/pgui/pgSliderBar.cxx index bc0c52f80e..74813e9333 100755 --- a/panda/src/pgui/pgSliderBar.cxx +++ b/panda/src/pgui/pgSliderBar.cxx @@ -98,6 +98,7 @@ PGSliderBar(const PGSliderBar ©) : //////////////////////////////////////////////////////////////////// PandaNode *PGSliderBar:: make_copy() const { + ReMutexHolder holder(_lock); return new PGSliderBar(*this); } @@ -110,6 +111,7 @@ make_copy() const { //////////////////////////////////////////////////////////////////// void PGSliderBar:: press(const MouseWatcherParameter ¶m, bool background) { + ReMutexHolder holder(_lock); if (param.has_mouse()) { _mouse_pos = param.get_mouse(); } @@ -138,6 +140,7 @@ press(const MouseWatcherParameter ¶m, bool background) { //////////////////////////////////////////////////////////////////// void PGSliderBar:: release(const MouseWatcherParameter ¶m, bool background) { + ReMutexHolder holder(_lock); if (MouseButton::is_mouse_button(param.get_button())) { _mouse_button_page = false; } @@ -155,6 +158,7 @@ release(const MouseWatcherParameter ¶m, bool background) { //////////////////////////////////////////////////////////////////// void PGSliderBar:: move(const MouseWatcherParameter ¶m) { + ReMutexHolder holder(_lock); _mouse_pos = param.get_mouse(); if (_dragging) { // We only get here if we the user originally clicked on the @@ -193,6 +197,7 @@ move(const MouseWatcherParameter ¶m) { //////////////////////////////////////////////////////////////////// bool PGSliderBar:: cull_callback(CullTraverser *trav, CullTraverserData &data) { + ReMutexHolder holder(_lock); if (_manage_pieces && _needs_remanage) { remanage(); } @@ -226,6 +231,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { //////////////////////////////////////////////////////////////////// void PGSliderBar:: xform(const LMatrix4f &mat) { + ReMutexHolder holder(_lock); PGItem::xform(mat); _axis = _axis * mat; @@ -248,6 +254,7 @@ xform(const LMatrix4f &mat) { //////////////////////////////////////////////////////////////////// void PGSliderBar:: adjust() { + ReMutexHolder holder(_lock); string event = get_adjust_event(); play_sound(event); throw_event(event); @@ -273,6 +280,7 @@ adjust() { //////////////////////////////////////////////////////////////////// void PGSliderBar:: setup_scroll_bar(bool vertical, float length, float width, float bevel) { + ReMutexHolder holder(_lock); set_state(0); clear_state_def(0); @@ -346,6 +354,7 @@ setup_scroll_bar(bool vertical, float length, float width, float bevel) { //////////////////////////////////////////////////////////////////// void PGSliderBar:: setup_slider(bool vertical, float length, float width, float bevel) { + ReMutexHolder holder(_lock); set_state(0); clear_state_def(0); @@ -401,6 +410,7 @@ setup_slider(bool vertical, float length, float width, float bevel) { //////////////////////////////////////////////////////////////////// void PGSliderBar:: set_active(bool active) { + ReMutexHolder holder(_lock); PGItem::set_active(active); // This also implicitly sets the managed pieces. @@ -424,6 +434,7 @@ set_active(bool active) { //////////////////////////////////////////////////////////////////// void PGSliderBar:: remanage() { + ReMutexHolder holder(_lock); _needs_remanage = false; const LVecBase4f &frame = get_frame(); @@ -475,6 +486,7 @@ remanage() { //////////////////////////////////////////////////////////////////// void PGSliderBar:: recompute() { + ReMutexHolder holder(_lock); _needs_recompute = false; if (_min_value != _max_value) { @@ -486,88 +498,101 @@ recompute() { _page_ratio = 0.0f; } - LVecBase4f frame = get_frame(); - reduce_region(frame, _left_button); - reduce_region(frame, _right_button); - - if (fabs(_axis[0]) > fabs(_axis[1] + _axis[2])) { - // The slider is X-dominant. - - _min_x = frame[0]; - _max_x = frame[1]; - - float trough_width = _max_x - _min_x; - - if (_thumb_button != (PGButton *)NULL) { - const LVecBase4f &thumb_frame = _thumb_button->get_frame(); - - if (_resize_thumb) { - // If we're allowed to adjust the thumb's size, we don't need to - // find out how wide it is. - _thumb_width = trough_width * min(1.0f, _page_ratio); - _thumb_button->set_frame(-_thumb_width / 2.0f, _thumb_width / 2.0f, - thumb_frame[2], thumb_frame[3]); - } else { - // If we're not adjusting the thumb's size, we do need to know - // its current width. - _thumb_width = thumb_frame[1] - thumb_frame[0]; - } - } - - _range_x = trough_width - _thumb_width; - - const LVecBase4f &thumb_frame = _thumb_button->get_frame(); - if (_axis[0] >= 0.0f) { - // The slider runs forwards, left to right. - _thumb_start = (_min_x - thumb_frame[0]) * _axis; - } else { - // The slider runs backwards: right to left. - _thumb_start = (thumb_frame[1] - _max_x) * _axis; - } - _thumb_start += LVector3f::rfu(0.0f, 0.0f, (frame[2] + frame[3]) / 2.0f); + if (!has_frame()) { + _min_x = 0.0f; + _max_x = 0.0f; + _thumb_width = 0.0f; + _range_x = 0.0f; + _thumb_start.set(0.0f, 0.0f, 0.0f); } else { - // The slider is Y-dominant. We call it X in the variable names, - // but it's really Y (or even Z). + LVecBase4f frame = get_frame(); + reduce_region(frame, _left_button); + reduce_region(frame, _right_button); - _min_x = frame[2]; - _max_x = frame[3]; - - float trough_width = _max_x - _min_x; - - if (_thumb_button == (PGButton *)NULL) { - _thumb_width = 0.0f; - _range_x = 0.0f; - _thumb_start.set(0.0f, 0.0f, 0.0f); - + if (fabs(_axis[0]) > fabs(_axis[1] + _axis[2])) { + // The slider is X-dominant. + + _min_x = frame[0]; + _max_x = frame[1]; + + float trough_width = _max_x - _min_x; + + if (_thumb_button == (PGButton *)NULL) { + _thumb_width = 0.0f; + _range_x = 0.0f; + _thumb_start.set(0.0f, 0.0f, 0.0f); + + } else { + const LVecBase4f &thumb_frame = _thumb_button->get_frame(); + + if (_resize_thumb) { + // If we're allowed to adjust the thumb's size, we don't need to + // find out how wide it is. + _thumb_width = trough_width * min(1.0f, _page_ratio); + _thumb_button->set_frame(-_thumb_width / 2.0f, _thumb_width / 2.0f, + thumb_frame[2], thumb_frame[3]); + } else { + // If we're not adjusting the thumb's size, we do need to know + // its current width. + _thumb_width = thumb_frame[1] - thumb_frame[0]; + } + + _range_x = trough_width - _thumb_width; + + if (_axis[0] >= 0.0f) { + // The slider runs forwards, left to right. + _thumb_start = (_min_x - thumb_frame[0]) * _axis; + } else { + // The slider runs backwards: right to left. + _thumb_start = (thumb_frame[1] - _max_x) * _axis; + } + _thumb_start += LVector3f::rfu(0.0f, 0.0f, (frame[2] + frame[3]) / 2.0f); + } + } else { - const LVecBase4f &thumb_frame = _thumb_button->get_frame(); - - if (_resize_thumb) { - // If we're allowed to adjust the thumb's size, we don't need to - // find out how wide it is. - _thumb_width = trough_width * min(1.0f, _page_ratio); - _thumb_button->set_frame(thumb_frame[0], thumb_frame[1], - -_thumb_width / 2.0f, _thumb_width / 2.0f); + // The slider is Y-dominant. We call it X in the variable names, + // but it's really Y (or even Z). + + _min_x = frame[2]; + _max_x = frame[3]; + + float trough_width = _max_x - _min_x; + + if (_thumb_button == (PGButton *)NULL) { + _thumb_width = 0.0f; + _range_x = 0.0f; + _thumb_start.set(0.0f, 0.0f, 0.0f); + } else { - // If we're not adjusting the thumb's size, we do need to know - // its current width. - _thumb_width = thumb_frame[3] - thumb_frame[2]; + const LVecBase4f &thumb_frame = _thumb_button->get_frame(); + + if (_resize_thumb) { + // If we're allowed to adjust the thumb's size, we don't need to + // find out how wide it is. + _thumb_width = trough_width * min(1.0f, _page_ratio); + _thumb_button->set_frame(thumb_frame[0], thumb_frame[1], + -_thumb_width / 2.0f, _thumb_width / 2.0f); + } else { + // If we're not adjusting the thumb's size, we do need to know + // its current width. + _thumb_width = thumb_frame[3] - thumb_frame[2]; + } + + _range_x = trough_width - _thumb_width; + + if (_axis[1] >= 0.0f && _axis[2] >= 0.0f) { + // The slider runs forwards, bottom to top. + _thumb_start = (_min_x - thumb_frame[2]) * _axis; + } else { + // The slider runs backwards: top to bottom. + _thumb_start = (thumb_frame[3] - _max_x) * _axis; + } + _thumb_start += LVector3f::rfu((frame[0] + frame[1]) / 2.0f, 0.0f, 0.0f); } - - _range_x = trough_width - _thumb_width; - - if (_axis[1] >= 0.0f && _axis[2] >= 0.0f) { - // The slider runs forwards, bottom to top. - _thumb_start = (_min_x - thumb_frame[2]) * _axis; - } else { - // The slider runs backwards: top to bottom. - _thumb_start = (thumb_frame[3] - _max_x) * _axis; - } - _thumb_start += LVector3f::rfu((frame[0] + frame[1]) / 2.0f, 0.0f, 0.0f); } } - + reposition(); } @@ -578,6 +603,7 @@ recompute() { //////////////////////////////////////////////////////////////////// void PGSliderBar:: frame_changed() { + ReMutexHolder holder(_lock); PGItem::frame_changed(); _needs_remanage = true; _needs_recompute = true; @@ -591,6 +617,7 @@ frame_changed() { //////////////////////////////////////////////////////////////////// void PGSliderBar:: item_transform_changed(PGItem *) { + ReMutexHolder holder(_lock); _needs_recompute = true; } @@ -602,6 +629,7 @@ item_transform_changed(PGItem *) { //////////////////////////////////////////////////////////////////// void PGSliderBar:: item_frame_changed(PGItem *) { + ReMutexHolder holder(_lock); _needs_recompute = true; } @@ -613,6 +641,7 @@ item_frame_changed(PGItem *) { //////////////////////////////////////////////////////////////////// void PGSliderBar:: item_draw_mask_changed(PGItem *) { + ReMutexHolder holder(_lock); _needs_recompute = true; } @@ -624,6 +653,7 @@ item_draw_mask_changed(PGItem *) { //////////////////////////////////////////////////////////////////// void PGSliderBar:: item_press(PGItem *item, const MouseWatcherParameter ¶m) { + ReMutexHolder holder(_lock); if (param.has_mouse()) { _mouse_pos = param.get_mouse(); } @@ -648,6 +678,7 @@ item_press(PGItem *item, const MouseWatcherParameter ¶m) { //////////////////////////////////////////////////////////////////// void PGSliderBar:: item_release(PGItem *item, const MouseWatcherParameter &) { + ReMutexHolder holder(_lock); if (item == _scroll_button_held) { _scroll_button_held = NULL; @@ -667,6 +698,7 @@ item_release(PGItem *item, const MouseWatcherParameter &) { //////////////////////////////////////////////////////////////////// void PGSliderBar:: item_move(PGItem *item, const MouseWatcherParameter ¶m) { + ReMutexHolder holder(_lock); _mouse_pos = param.get_mouse(); if (item == _thumb_button) { if (_dragging) { diff --git a/panda/src/pgui/pgVirtualFrame.I b/panda/src/pgui/pgVirtualFrame.I index a8e7e14213..6c4baed0b1 100644 --- a/panda/src/pgui/pgVirtualFrame.I +++ b/panda/src/pgui/pgVirtualFrame.I @@ -37,6 +37,7 @@ set_clip_frame(float left, float right, float bottom, float top) { //////////////////////////////////////////////////////////////////// INLINE const LVecBase4f &PGVirtualFrame:: get_clip_frame() const { + ReMutexHolder holder(_lock); return _has_clip_frame ? _clip_frame : get_frame(); } @@ -49,6 +50,7 @@ get_clip_frame() const { //////////////////////////////////////////////////////////////////// INLINE bool PGVirtualFrame:: has_clip_frame() const { + ReMutexHolder holder(_lock); return _has_clip_frame; } @@ -61,6 +63,7 @@ has_clip_frame() const { //////////////////////////////////////////////////////////////////// INLINE void PGVirtualFrame:: set_canvas_transform(const TransformState *transform) { + ReMutexHolder holder(_lock); _canvas_node->set_transform(transform); } @@ -73,6 +76,7 @@ set_canvas_transform(const TransformState *transform) { //////////////////////////////////////////////////////////////////// INLINE const TransformState *PGVirtualFrame:: get_canvas_transform() const { + ReMutexHolder holder(_lock); return _canvas_node->get_transform(); } @@ -84,6 +88,7 @@ get_canvas_transform() const { //////////////////////////////////////////////////////////////////// INLINE PandaNode *PGVirtualFrame:: get_canvas_node() const { + ReMutexHolder holder(_lock); return _canvas_node; } @@ -94,5 +99,6 @@ get_canvas_node() const { //////////////////////////////////////////////////////////////////// INLINE PandaNode *PGVirtualFrame:: get_canvas_parent() const { + ReMutexHolder holder(_lock); return _canvas_parent; } diff --git a/panda/src/pgui/pgVirtualFrame.cxx b/panda/src/pgui/pgVirtualFrame.cxx index 143ab4d232..da0cee35bb 100644 --- a/panda/src/pgui/pgVirtualFrame.cxx +++ b/panda/src/pgui/pgVirtualFrame.cxx @@ -72,6 +72,7 @@ PGVirtualFrame(const PGVirtualFrame ©) : //////////////////////////////////////////////////////////////////// PandaNode *PGVirtualFrame:: make_copy() const { + ReMutexHolder holder(_lock); return new PGVirtualFrame(*this); } @@ -93,6 +94,7 @@ make_copy() const { void PGVirtualFrame:: r_copy_children(const PandaNode *from, PandaNode::InstanceMap &inst_map, Thread *current_thread) { + ReMutexHolder holder(_lock); PandaNode::r_copy_children(from, inst_map, current_thread); // Reassign the canvas_node to point to the new copy, if it's there. @@ -129,6 +131,7 @@ r_copy_children(const PandaNode *from, PandaNode::InstanceMap &inst_map, //////////////////////////////////////////////////////////////////// void PGVirtualFrame:: setup(float width, float height) { + ReMutexHolder holder(_lock); set_state(0); clear_state_def(0); @@ -159,6 +162,7 @@ setup(float width, float height) { //////////////////////////////////////////////////////////////////// void PGVirtualFrame:: set_clip_frame(const LVecBase4f &frame) { + ReMutexHolder holder(_lock); if (!_has_clip_frame || _clip_frame != frame) { _has_clip_frame = true; _clip_frame = frame; @@ -182,6 +186,7 @@ set_clip_frame(const LVecBase4f &frame) { //////////////////////////////////////////////////////////////////// void PGVirtualFrame:: clear_clip_frame() { + ReMutexHolder holder(_lock); if (_has_clip_frame) { _has_clip_frame = false; diff --git a/panda/src/pgui/pgWaitBar.I b/panda/src/pgui/pgWaitBar.I index e4c035531a..acdc5db800 100644 --- a/panda/src/pgui/pgWaitBar.I +++ b/panda/src/pgui/pgWaitBar.I @@ -20,6 +20,7 @@ //////////////////////////////////////////////////////////////////// INLINE void PGWaitBar:: set_range(float range) { + ReMutexHolder holder(_lock); _range = range; _bar_state = -1; } @@ -31,6 +32,7 @@ set_range(float range) { //////////////////////////////////////////////////////////////////// INLINE float PGWaitBar:: get_range() const { + ReMutexHolder holder(_lock); return _range; } @@ -42,6 +44,7 @@ get_range() const { //////////////////////////////////////////////////////////////////// INLINE void PGWaitBar:: set_value(float value) { + ReMutexHolder holder(_lock); _value = value; _bar_state = -1; } @@ -53,6 +56,7 @@ set_value(float value) { //////////////////////////////////////////////////////////////////// INLINE float PGWaitBar:: get_value() const { + ReMutexHolder holder(_lock); return _value; } @@ -63,6 +67,7 @@ get_value() const { //////////////////////////////////////////////////////////////////// INLINE float PGWaitBar:: get_percent() const { + ReMutexHolder holder(_lock); return (_value / _range) * 100.0f; } @@ -74,6 +79,7 @@ get_percent() const { //////////////////////////////////////////////////////////////////// INLINE void PGWaitBar:: set_bar_style(const PGFrameStyle &style) { + ReMutexHolder holder(_lock); _bar_style = style; _bar_state = -1; } @@ -86,5 +92,6 @@ set_bar_style(const PGFrameStyle &style) { //////////////////////////////////////////////////////////////////// INLINE PGFrameStyle PGWaitBar:: get_bar_style() const { + ReMutexHolder holder(_lock); return _bar_style; } diff --git a/panda/src/pgui/pgWaitBar.cxx b/panda/src/pgui/pgWaitBar.cxx index 00fa567e20..40ccfe805f 100644 --- a/panda/src/pgui/pgWaitBar.cxx +++ b/panda/src/pgui/pgWaitBar.cxx @@ -67,6 +67,7 @@ PGWaitBar(const PGWaitBar ©) : //////////////////////////////////////////////////////////////////// PandaNode *PGWaitBar:: make_copy() const { + ReMutexHolder holder(_lock); return new PGWaitBar(*this); } @@ -97,6 +98,7 @@ make_copy() const { //////////////////////////////////////////////////////////////////// bool PGWaitBar:: cull_callback(CullTraverser *trav, CullTraverserData &data) { + ReMutexHolder holder(_lock); update(); return PGItem::cull_callback(trav, data); } @@ -109,6 +111,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { //////////////////////////////////////////////////////////////////// void PGWaitBar:: setup(float width, float height, float range) { + ReMutexHolder holder(_lock); set_state(0); clear_state_def(0); @@ -136,6 +139,7 @@ setup(float width, float height, float range) { //////////////////////////////////////////////////////////////////// void PGWaitBar:: update() { + ReMutexHolder holder(_lock); int state = get_state(); // If the bar was last drawn in this state and is still current, we diff --git a/panda/src/pipeline/conditionVarPosixImpl.cxx b/panda/src/pipeline/conditionVarPosixImpl.cxx index a2162e5295..adff94c249 100644 --- a/panda/src/pipeline/conditionVarPosixImpl.cxx +++ b/panda/src/pipeline/conditionVarPosixImpl.cxx @@ -41,7 +41,7 @@ wait(double timeout) { ts.tv_nsec += (int)((timeout - seconds) * 1000000.0); int result = pthread_cond_timedwait(&_cvar, &_mutex._lock, &ts); - nassertv(result == 0); + nassertv(result == 0 || errno == ETIMEDOUT); } #endif // HAVE_POSIX_THREADS diff --git a/panda/src/pipeline/conditionVarSimpleImpl.cxx b/panda/src/pipeline/conditionVarSimpleImpl.cxx index 221ffde18e..5658508dfe 100644 --- a/panda/src/pipeline/conditionVarSimpleImpl.cxx +++ b/panda/src/pipeline/conditionVarSimpleImpl.cxx @@ -65,7 +65,13 @@ wait(double timeout) { void ConditionVarSimpleImpl:: do_signal() { ThreadSimpleManager *manager = ThreadSimpleManager::get_global_ptr(); - manager->unblock_one(this); + if (manager->unblock_one(this)) { + // There had been a thread waiting on this condition variable. + // Switch contexts immediately, to make fairness more likely. + ThreadSimpleImpl *thread = manager->get_current_thread(); + manager->enqueue_ready(thread); + manager->next_context(); + } } //////////////////////////////////////////////////////////////////// @@ -76,7 +82,13 @@ do_signal() { void ConditionVarSimpleImpl:: do_signal_all() { ThreadSimpleManager *manager = ThreadSimpleManager::get_global_ptr(); - manager->unblock_all(this); + if (manager->unblock_all(this)) { + // There had been a thread waiting on this condition variable. + // Switch contexts immediately, to make fairness more likely. + ThreadSimpleImpl *thread = manager->get_current_thread(); + manager->enqueue_ready(thread); + manager->next_context(); + } } #endif // THREAD_SIMPLE_IMPL diff --git a/panda/src/pipeline/mutexDebug.cxx b/panda/src/pipeline/mutexDebug.cxx index dd77309e3d..16653600e7 100755 --- a/panda/src/pipeline/mutexDebug.cxx +++ b/panda/src/pipeline/mutexDebug.cxx @@ -27,7 +27,7 @@ MutexTrueImpl *MutexDebug::_global_lock; //////////////////////////////////////////////////////////////////// MutexDebug:: MutexDebug(const string &name, bool allow_recursion) : - _name(name), + Namable(name), _allow_recursion(allow_recursion), _locking_thread(NULL), _lock_count(0), @@ -58,9 +58,9 @@ MutexDebug:: void MutexDebug:: output(ostream &out) const { if (_allow_recursion) { - out << "ReMutex " << _name << " " << (void *)this; + out << "ReMutex " << get_name() << " " << (void *)this; } else { - out << "Mutex " << _name << " " << (void *)this; + out << "Mutex " << get_name() << " " << (void *)this; } } @@ -90,7 +90,7 @@ do_lock() { nassertv(_lock_count > 0); if (!_allow_recursion) { ostringstream ostr; - ostr << *_locking_thread << " attempted to double-lock non-reentrant " + ostr << *this_thread << " attempted to double-lock non-reentrant " << *this; nassert_raise(ostr.str()); } @@ -99,6 +99,26 @@ do_lock() { } else { // The mutex is locked by some other thread. +#ifdef PHONY_MUTEX + // In this case, we don't really have mutexes anyway. + MissedThreads::iterator mi = _missed_threads.insert(MissedThreads::value_type(this_thread, 0)).first; + if ((*mi).second == 0) { + thread_cat.info() + << *this_thread << " not stopped by " << *this << " (held by " + << *_locking_thread << ")\n"; + } else { + if (!_allow_recursion) { + ostringstream ostr; + ostr << *this_thread << " attempted to double-lock non-reentrant " + << *this; + nassert_raise(ostr.str()); + } + } + ++((*mi).second); + +#else // PHONY_MUTEX + // This is the real case. We have mutexes, so enforce it. + // Check for deadlock. MutexDebug *next_mutex = this; while (next_mutex != NULL) { @@ -133,6 +153,7 @@ do_lock() { << *this_thread << " blocking on " << *this << " (held by " << *_locking_thread << ")\n"; } + while (_locking_thread != (Thread *)NULL) { _cvar_impl.wait(); } @@ -147,6 +168,7 @@ do_lock() { _locking_thread = this_thread; ++_lock_count; nassertv(_lock_count == 1); +#endif // PHONY_MUTEX } } @@ -165,10 +187,27 @@ do_release() { Thread *this_thread = Thread::get_current_thread(); if (_locking_thread != this_thread) { +#ifdef PHONY_MUTEX + // No real mutexes. This just means we blew past a mutex without + // locking it, above. + + MissedThreads::iterator mi = _missed_threads.find(this_thread); + nassertv(mi != _missed_threads.end()); + nassertv((*mi).second > 0); + --((*mi).second); + + if ((*mi).second == 0) { + _missed_threads.erase(mi); + } + +#else // PHONY_MUTEX + // In the real-mutex case, this is an error condition. ostringstream ostr; ostr << *this_thread << " attempted to release " << *this << " which it does not own"; nassert_raise(ostr.str()); +#endif // PHONY_MUTEX + _global_lock->release(); return; } @@ -179,7 +218,19 @@ do_release() { if (_lock_count == 0) { // That was the last lock held by this thread. Release the lock. _locking_thread = (Thread *)NULL; + +#ifdef PHONY_MUTEX + if (!_missed_threads.empty()) { + // Promote some other thread to be the honorary lock holder. + MissedThreads::iterator mi = _missed_threads.begin(); + _locking_thread = (*mi).first; + _lock_count = (*mi).second; + _missed_threads.erase(mi); + nassertv(_lock_count > 0); + } +#else _cvar_impl.signal(); +#endif } } @@ -191,7 +242,20 @@ do_release() { //////////////////////////////////////////////////////////////////// bool MutexDebug:: do_debug_is_locked() const { - return (_locking_thread == Thread::get_current_thread()); + Thread *this_thread = Thread::get_current_thread(); + if (_locking_thread == this_thread) { + return true; + } + +#ifdef PHONY_MUTEX + MissedThreads::const_iterator mi = _missed_threads.find(this_thread); + if (mi != _missed_threads.end()) { + nassertr((*mi).second > 0, false); + return true; + } +#endif + + return false; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pipeline/mutexDebug.h b/panda/src/pipeline/mutexDebug.h index 7e5b26bed2..7525b5e170 100644 --- a/panda/src/pipeline/mutexDebug.h +++ b/panda/src/pipeline/mutexDebug.h @@ -19,16 +19,25 @@ #include "mutexTrueImpl.h" #include "conditionVarImpl.h" #include "thread.h" +#include "namable.h" #ifdef DEBUG_THREADS +#if defined(SIMPLE_THREADS) && defined(SIMPLE_THREADS_NO_MUTEX) +// In this mode, we don't actually lock and unlock a mutex. We just +// wave at them as they go by. This actually involves a bit more +// work, here in the debug mode, than a real mutex, because we have to +// track all the threads that failed to lock the mutex. +#define PHONY_MUTEX +#endif + //////////////////////////////////////////////////////////////////// // Class : MutexDebug // Description : This class implements a standard mutex the hard way, // by doing everything by hand. This does allow fancy // things like deadlock detection, however. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA_PIPELINE MutexDebug { +class EXPCL_PANDA_PIPELINE MutexDebug : public Namable { protected: MutexDebug(const string &name, bool allow_recursion); virtual ~MutexDebug(); @@ -57,10 +66,13 @@ private: private: INLINE static MutexTrueImpl *get_global_lock(); - string _name; bool _allow_recursion; Thread *_locking_thread; int _lock_count; +#ifdef PHONY_MUTEX + typedef pmap MissedThreads; + MissedThreads _missed_threads; +#endif ConditionVarImpl _cvar_impl; diff --git a/panda/src/pipeline/mutexDirect.I b/panda/src/pipeline/mutexDirect.I index edf81b9226..1bcdcb0f4e 100755 --- a/panda/src/pipeline/mutexDirect.I +++ b/panda/src/pipeline/mutexDirect.I @@ -102,3 +102,60 @@ INLINE bool MutexDirect:: debug_is_locked() const { return true; } + +//////////////////////////////////////////////////////////////////// +// Function: MutexDirect::debug_is_locked +// Access: Published +// Description: Returns true if the current thread has locked the +// Mutex, false otherwise. This method is only intended +// for use in debugging, hence the method name; in the +// MutexDirect case, it always returns true, since +// there's not a reliable way to determine this +// otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool MutexDirect:: +debug_is_locked() const { + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: MutexDirect::set_name +// Access: Public +// Description: The mutex name is only defined when compiling in +// DEBUG_THREADS mode. +//////////////////////////////////////////////////////////////////// +INLINE void MutexDirect:: +set_name(const string &) { +} + +//////////////////////////////////////////////////////////////////// +// Function: MutexDirect::clear_name +// Access: Public +// Description: The mutex name is only defined when compiling in +// DEBUG_THREADS mode. +//////////////////////////////////////////////////////////////////// +INLINE void MutexDirect:: +clear_name() { +} + +//////////////////////////////////////////////////////////////////// +// Function: MutexDirect::has_name +// Access: Public +// Description: The mutex name is only defined when compiling in +// DEBUG_THREADS mode. +//////////////////////////////////////////////////////////////////// +INLINE bool MutexDirect:: +has_name() const { + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: MutexDirect::get_name +// Access: Public +// Description: The mutex name is only defined when compiling in +// DEBUG_THREADS mode. +//////////////////////////////////////////////////////////////////// +INLINE string MutexDirect:: +get_name() const { + return string(); +} diff --git a/panda/src/pipeline/mutexDirect.h b/panda/src/pipeline/mutexDirect.h index a3331f273f..203081680f 100644 --- a/panda/src/pipeline/mutexDirect.h +++ b/panda/src/pipeline/mutexDirect.h @@ -42,6 +42,11 @@ PUBLISHED: INLINE void release() const; INLINE bool debug_is_locked() const; + INLINE void set_name(const string &name); + INLINE void clear_name(); + INLINE bool has_name() const; + INLINE string get_name() const; + void output(ostream &out) const; private: diff --git a/panda/src/pipeline/mutexSimpleImpl.cxx b/panda/src/pipeline/mutexSimpleImpl.cxx index d66553a4a3..8a44163877 100644 --- a/panda/src/pipeline/mutexSimpleImpl.cxx +++ b/panda/src/pipeline/mutexSimpleImpl.cxx @@ -46,7 +46,13 @@ do_lock() { void MutexSimpleImpl:: do_release() { ThreadSimpleManager *manager = ThreadSimpleManager::get_global_ptr(); - manager->unblock_one(this); + if (manager->unblock_one(this)) { + // There had been a thread waiting on this mutex. Switch contexts + // immediately, to make fairness more likely. + ThreadSimpleImpl *thread = manager->get_current_thread(); + manager->enqueue_ready(thread); + manager->next_context(); + } } #endif // THREAD_SIMPLE_IMPL diff --git a/panda/src/pipeline/reMutexDirect.I b/panda/src/pipeline/reMutexDirect.I index ee8e476d1a..d5dc240803 100755 --- a/panda/src/pipeline/reMutexDirect.I +++ b/panda/src/pipeline/reMutexDirect.I @@ -165,6 +165,48 @@ debug_is_locked() const { return true; } +//////////////////////////////////////////////////////////////////// +// Function: ReMutexDirect::set_name +// Access: Public +// Description: The mutex name is only defined when compiling in +// DEBUG_THREADS mode. +//////////////////////////////////////////////////////////////////// +INLINE void ReMutexDirect:: +set_name(const string &) { +} + +//////////////////////////////////////////////////////////////////// +// Function: ReMutexDirect::clear_name +// Access: Public +// Description: The mutex name is only defined when compiling in +// DEBUG_THREADS mode. +//////////////////////////////////////////////////////////////////// +INLINE void ReMutexDirect:: +clear_name() { +} + +//////////////////////////////////////////////////////////////////// +// Function: ReMutexDirect::has_name +// Access: Public +// Description: The mutex name is only defined when compiling in +// DEBUG_THREADS mode. +//////////////////////////////////////////////////////////////////// +INLINE bool ReMutexDirect:: +has_name() const { + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: ReMutexDirect::get_name +// Access: Public +// Description: The mutex name is only defined when compiling in +// DEBUG_THREADS mode. +//////////////////////////////////////////////////////////////////// +INLINE string ReMutexDirect:: +get_name() const { + return string(); +} + #ifndef HAVE_REMUTEXIMPL //////////////////////////////////////////////////////////////////// // Function: ReMutexDirect::do_lock diff --git a/panda/src/pipeline/reMutexDirect.h b/panda/src/pipeline/reMutexDirect.h index d25ba233d7..6fc07f74b5 100644 --- a/panda/src/pipeline/reMutexDirect.h +++ b/panda/src/pipeline/reMutexDirect.h @@ -43,6 +43,11 @@ PUBLISHED: INLINE bool debug_is_locked() const; + INLINE void set_name(const string &name); + INLINE void clear_name(); + INLINE bool has_name() const; + INLINE string get_name() const; + void output(ostream &out) const; private: diff --git a/panda/src/pipeline/thread.cxx b/panda/src/pipeline/thread.cxx index 5c412ae237..9b1921f3a0 100644 --- a/panda/src/pipeline/thread.cxx +++ b/panda/src/pipeline/thread.cxx @@ -245,11 +245,10 @@ call_python_func(PyObject *function, PyObject *args) { } else { #ifdef SIMPLE_THREADS - // We can't use the PyGILState interface, which assumes we are using - // true OS-level threading (and we might be just using - // SIMPLE_THREADS). PyGILState enforces policies like only one - // thread state per OS-level thread, which is not true in the case - // of SIMPLE_THREADS. + // We can't use the PyGILState interface, which assumes we are + // using true OS-level threading. PyGILState enforces policies + // like only one thread state per OS-level thread, which is not + // true in the case of SIMPLE_THREADS. PyThreadState *orig_thread_state = PyThreadState_Get(); PyInterpreterState *istate = orig_thread_state->interp; diff --git a/panda/src/pipeline/threadSimpleManager.cxx b/panda/src/pipeline/threadSimpleManager.cxx index 73a8c6e63f..89b9f9de3a 100644 --- a/panda/src/pipeline/threadSimpleManager.cxx +++ b/panda/src/pipeline/threadSimpleManager.cxx @@ -106,16 +106,17 @@ enqueue_block(ThreadSimpleImpl *thread, BlockerSimple *blocker) { // Function: ThreadSimpleManager::unblock_one // Access: Public // Description: Unblocks one thread waiting on the indicated blocker, -// if any. +// if any. Returns true if anything was unblocked, +// false otherwise. //////////////////////////////////////////////////////////////////// -void ThreadSimpleManager:: +bool ThreadSimpleManager:: unblock_one(BlockerSimple *blocker) { Blocked::iterator bi = _blocked.find(blocker); if (bi != _blocked.end()) { - nassertv(blocker->_flags & BlockerSimple::F_has_waiters); + nassertr(blocker->_flags & BlockerSimple::F_has_waiters, false); FifoThreads &threads = (*bi).second; - nassertv(!threads.empty()); + nassertr(!threads.empty(), false); ThreadSimpleImpl *thread = threads.front(); threads.pop_front(); _ready.push_back(thread); @@ -123,23 +124,27 @@ unblock_one(BlockerSimple *blocker) { blocker->_flags &= ~BlockerSimple::F_has_waiters; _blocked.erase(bi); } + return true; } + + return false; } //////////////////////////////////////////////////////////////////// // Function: ThreadSimpleManager::unblock_all // Access: Public // Description: Unblocks all threads waiting on the indicated -// blocker. +// blocker. Returns true if anything was unblocked, +// false otherwise. //////////////////////////////////////////////////////////////////// -void ThreadSimpleManager:: +bool ThreadSimpleManager:: unblock_all(BlockerSimple *blocker) { Blocked::iterator bi = _blocked.find(blocker); if (bi != _blocked.end()) { - nassertv(blocker->_flags & BlockerSimple::F_has_waiters); + nassertr(blocker->_flags & BlockerSimple::F_has_waiters, false); FifoThreads &threads = (*bi).second; - nassertv(!threads.empty()); + nassertr(!threads.empty(), false); while (!threads.empty()) { ThreadSimpleImpl *thread = threads.front(); threads.pop_front(); @@ -147,7 +152,9 @@ unblock_all(BlockerSimple *blocker) { } blocker->_flags &= ~BlockerSimple::F_has_waiters; _blocked.erase(bi); + return true; } + return false; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pipeline/threadSimpleManager.h b/panda/src/pipeline/threadSimpleManager.h index feef150935..684fc07319 100644 --- a/panda/src/pipeline/threadSimpleManager.h +++ b/panda/src/pipeline/threadSimpleManager.h @@ -60,8 +60,8 @@ public: void enqueue_ready(ThreadSimpleImpl *thread); void enqueue_sleep(ThreadSimpleImpl *thread, double seconds); void enqueue_block(ThreadSimpleImpl *thread, BlockerSimple *blocker); - void unblock_one(BlockerSimple *blocker); - void unblock_all(BlockerSimple *blocker); + bool unblock_one(BlockerSimple *blocker); + bool unblock_all(BlockerSimple *blocker); void enqueue_finished(ThreadSimpleImpl *thread); void preempt(ThreadSimpleImpl *thread); void next_context(); diff --git a/panda/src/putil/copyOnWriteObject.I b/panda/src/putil/copyOnWriteObject.I index f691f5c647..6b1116f496 100644 --- a/panda/src/putil/copyOnWriteObject.I +++ b/panda/src/putil/copyOnWriteObject.I @@ -26,17 +26,17 @@ TypeHandle CopyOnWriteObj1::_type_handle; //////////////////////////////////////////////////////////////////// INLINE CopyOnWriteObject:: CopyOnWriteObject() -#ifdef HAVE_THREADS +#ifdef COW_THREADED : _lock_cvar(_lock_mutex) #endif { #ifdef DO_MEMORY_USAGE MemoryUsage::update_type(this, this); #endif -#ifdef HAVE_THREADS +#ifdef COW_THREADED _lock_status = LS_unlocked; _locking_thread = NULL; -#endif // HAVE_THREADS +#endif // COW_THREADED } //////////////////////////////////////////////////////////////////// @@ -47,17 +47,17 @@ CopyOnWriteObject() INLINE CopyOnWriteObject:: CopyOnWriteObject(const CopyOnWriteObject ©) : CachedTypedWritableReferenceCount(copy) -#ifdef HAVE_THREADS +#ifdef COW_THREADED , _lock_cvar(_lock_mutex) #endif { #ifdef DO_MEMORY_USAGE MemoryUsage::update_type(this, this); #endif -#ifdef HAVE_THREADS +#ifdef COW_THREADED _lock_status = LS_unlocked; _locking_thread = NULL; -#endif // HAVE_THREADS +#endif // COW_THREADED } //////////////////////////////////////////////////////////////////// @@ -70,7 +70,7 @@ operator = (const CopyOnWriteObject ©) { CachedTypedWritableReferenceCount::operator = (copy); } -#ifdef HAVE_THREADS +#ifdef COW_THREADED //////////////////////////////////////////////////////////////////// // Function: CopyOnWriteObject::cache_ref // Access: Published @@ -81,7 +81,7 @@ cache_ref() const { MutexHolder holder(_lock_mutex); CachedTypedWritableReferenceCount::cache_ref(); } -#endif // HAVE_THREADS +#endif // COW_THREADED //////////////////////////////////////////////////////////////////// // Function: CopyOnWriteObj::Constructor diff --git a/panda/src/putil/copyOnWriteObject.cxx b/panda/src/putil/copyOnWriteObject.cxx index b99e078d8d..86c22333ed 100644 --- a/panda/src/putil/copyOnWriteObject.cxx +++ b/panda/src/putil/copyOnWriteObject.cxx @@ -18,7 +18,7 @@ TypeHandle CopyOnWriteObject::_type_handle; -#ifdef HAVE_THREADS +#ifdef COW_THREADED //////////////////////////////////////////////////////////////////// // Function: CopyOnWriteObject::unref // Access: Public @@ -40,4 +40,4 @@ unref() const { } return is_zero; } -#endif // HAVE_THREADS +#endif // COW_THREADED diff --git a/panda/src/putil/copyOnWriteObject.h b/panda/src/putil/copyOnWriteObject.h index 3ca4c6c2d1..48b87b25a5 100644 --- a/panda/src/putil/copyOnWriteObject.h +++ b/panda/src/putil/copyOnWriteObject.h @@ -22,6 +22,15 @@ #include "conditionVar.h" #include "mutexHolder.h" +// Should we implement full thread protection for CopyOnWritePointer? +// If we can be assured that no other thread will interrupt while a +// write pointer is held, we don't need thread protection. +#if defined(HAVE_THREADS) && !(defined(SIMPLE_THREADS) && defined(SIMPLE_THREADS_NO_MUTEX)) + #define COW_THREADED 1 +#else + #undef COW_THREADED +#endif + //////////////////////////////////////////////////////////////////// // Class : CopyOnWriteObject // Description : This base class provides basic reference counting, @@ -35,16 +44,16 @@ public: INLINE void operator = (const CopyOnWriteObject ©); PUBLISHED: -#ifdef HAVE_THREADS +#ifdef COW_THREADED bool unref() const; INLINE void cache_ref() const; -#endif // HAVE_THREADS +#endif // COW_THREADED protected: virtual PT(CopyOnWriteObject) make_cow_copy()=0; private: -#ifdef HAVE_THREADS +#ifdef COW_THREADED enum LockStatus { LS_unlocked, LS_locked_read, @@ -54,7 +63,7 @@ private: ConditionVar _lock_cvar; LockStatus _lock_status; Thread *_locking_thread; -#endif // HAVE_THREADS +#endif // COW_THREADED public: virtual TypeHandle get_type() const { diff --git a/panda/src/putil/copyOnWritePointer.cxx b/panda/src/putil/copyOnWritePointer.cxx index 1fe9c8b5df..82437dd4b4 100644 --- a/panda/src/putil/copyOnWritePointer.cxx +++ b/panda/src/putil/copyOnWritePointer.cxx @@ -51,7 +51,7 @@ get_read_pointer() const { } _object->_lock_status = CopyOnWriteObject::LS_locked_read; - _object->_locking_thread = Thread::get_current_thread(); + _object->_locking_thread = current_thread; return _object; } #endif // COW_THREADED @@ -129,7 +129,7 @@ get_write_pointer() { // have saved himself a reference. } _object->_lock_status = CopyOnWriteObject::LS_locked_write; - _object->_locking_thread = Thread::get_current_thread(); + _object->_locking_thread = current_thread; return _object; } diff --git a/panda/src/putil/copyOnWritePointer.h b/panda/src/putil/copyOnWritePointer.h index dc8963ecd7..d0dd679ed7 100644 --- a/panda/src/putil/copyOnWritePointer.h +++ b/panda/src/putil/copyOnWritePointer.h @@ -21,15 +21,6 @@ #include "pointerTo.h" #include "dcast.h" -// Should we implement full thread protection for CopyOnWritePointer? -// If we can be assured that no other thread will interrupt while a -// write pointer is held, we don't need thread protection. -#if defined(HAVE_THREADS) && !(defined(SIMPLE_THREADS) && defined(SIMPLE_THREADS_NO_MUTEX)) - #define COW_THREADED 1 -#else - #undef COW_THREADED -#endif - //////////////////////////////////////////////////////////////////// // Class : CopyOnWritePointer // Description : This safely stores the primary, owned pointer to a diff --git a/panda/src/text/textNode.cxx b/panda/src/text/textNode.cxx index e6072767f1..4b85f9aa7a 100644 --- a/panda/src/text/textNode.cxx +++ b/panda/src/text/textNode.cxx @@ -620,7 +620,9 @@ is_renderable() const { // thing. //////////////////////////////////////////////////////////////////// void TextNode:: -compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage, +compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, + int &internal_vertices, + int pipeline_stage, Thread *current_thread) const { // First, get ourselves a fresh, empty bounding volume. PT(BoundingVolume) bound = new BoundingSphere; @@ -644,9 +646,8 @@ compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage, gbv->around(vertices, vertices + 8); - bdata->_internal_bounds = bound; - bdata->_internal_vertices = 0; // TODO: estimate this better. - bdata->_internal_bounds_stale = false; + internal_bounds = bound; + internal_vertices = 0; // TODO: estimate this better. } //////////////////////////////////////////////////////////////////// @@ -659,16 +660,17 @@ compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage, //////////////////////////////////////////////////////////////////// void TextNode:: r_prepare_scene(const RenderState *state, - PreparedGraphicsObjects *prepared_objects) { + PreparedGraphicsObjects *prepared_objects, + Thread *current_thread) { check_rebuild(); PandaNode *child = _internal_geom; if (child != (PandaNode *)NULL) { CPT(RenderState) child_state = state->compose(child->get_state()); - child->r_prepare_scene(child_state, prepared_objects); + child->r_prepare_scene(child_state, prepared_objects, current_thread); } - PandaNode::r_prepare_scene(state, prepared_objects); + PandaNode::r_prepare_scene(state, prepared_objects, current_thread); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/text/textNode.h b/panda/src/text/textNode.h index 5678d35d12..44da4a4d8e 100644 --- a/panda/src/text/textNode.h +++ b/panda/src/text/textNode.h @@ -239,11 +239,14 @@ public: virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data); virtual bool is_renderable() const; - virtual void compute_internal_bounds(BoundsData *bdata, int pipeline_stage, + virtual void compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, + int &internal_vertices, + int pipeline_stage, Thread *current_thread) const; virtual void r_prepare_scene(const RenderState *state, - PreparedGraphicsObjects *prepared_objects); + PreparedGraphicsObjects *prepared_objects, + Thread *current_thread); private: INLINE void invalidate_no_measure();