diff --git a/panda/src/display/graphicsEngine.cxx b/panda/src/display/graphicsEngine.cxx index b13dac97db..34f6893d2e 100644 --- a/panda/src/display/graphicsEngine.cxx +++ b/panda/src/display/graphicsEngine.cxx @@ -43,6 +43,7 @@ #include "objectDeletor.h" #include "bamCache.h" #include "cullableObject.h" +#include "geomVertexArrayData.h" #if defined(WIN32) #define WINDOWS_LEAN_AND_MEAN @@ -75,6 +76,12 @@ PStatCollector GraphicsEngine::_cyclers_pcollector("PipelineCyclers"); PStatCollector GraphicsEngine::_dirty_cyclers_pcollector("Dirty PipelineCyclers"); PStatCollector GraphicsEngine::_delete_pcollector("App:Delete"); + +PStatCollector GraphicsEngine::_sw_sprites_pcollector("SW Sprites"); +PStatCollector GraphicsEngine::_vertex_data_resident_pcollector("Vertex Data:Resident"); +PStatCollector GraphicsEngine::_vertex_data_compressed_pcollector("Vertex Data:Compressed"); +PStatCollector GraphicsEngine::_vertex_data_disk_pcollector("Vertex Data:Disk"); + // These are counted independently by the collision system; we // redefine them here so we can reset them at each frame. PStatCollector GraphicsEngine::_cnode_volume_pcollector("Collision Volumes:CollisionNode"); @@ -95,7 +102,6 @@ PStatCollector GraphicsEngine::_volume_inv_sphere_pcollector("Collision Volumes: PStatCollector GraphicsEngine::_test_inv_sphere_pcollector("Collision Tests:CollisionInvSphere"); PStatCollector GraphicsEngine::_volume_geom_pcollector("Collision Volumes:CollisionGeom"); PStatCollector GraphicsEngine::_test_geom_pcollector("Collision Tests:CollisionGeom"); -PStatCollector GraphicsEngine::_sw_sprites_pcollector("SW Sprites"); //////////////////////////////////////////////////////////////////// // Function: GraphicsEngine::Constructor @@ -672,6 +678,8 @@ render_frame() { PStatTimer timer(_delete_pcollector, current_thread); deletor->flush(); } + + GeomVertexArrayData::lru_epoch(); GeomCacheManager::flush_level(); CullTraverser::flush_level(); @@ -714,6 +722,11 @@ render_frame() { _render_states_unused_pcollector.set_level(RenderState::get_num_unused_states()); } + _sw_sprites_pcollector.clear_level(); + _vertex_data_resident_pcollector.set_level(GeomVertexArrayData::get_global_lru(GeomVertexArrayData::RC_resident)->get_total_size()); + _vertex_data_compressed_pcollector.set_level(GeomVertexArrayData::get_global_lru(GeomVertexArrayData::RC_compressed)->get_total_size()); + _vertex_data_disk_pcollector.set_level(GeomVertexArrayData::get_global_lru(GeomVertexArrayData::RC_disk)->get_total_size()); + _cnode_volume_pcollector.clear_level(); _gnode_volume_pcollector.clear_level(); _geom_volume_pcollector.clear_level(); @@ -732,7 +745,6 @@ render_frame() { _test_inv_sphere_pcollector.clear_level(); _volume_geom_pcollector.clear_level(); _test_geom_pcollector.clear_level(); - _sw_sprites_pcollector.clear_level(); #endif // DO_PSTATS diff --git a/panda/src/display/graphicsEngine.h b/panda/src/display/graphicsEngine.h index ed0ea7ae6b..cbe9b80445 100644 --- a/panda/src/display/graphicsEngine.h +++ b/panda/src/display/graphicsEngine.h @@ -359,6 +359,11 @@ private: static PStatCollector _dirty_cyclers_pcollector; static PStatCollector _delete_pcollector; + static PStatCollector _sw_sprites_pcollector; + static PStatCollector _vertex_data_resident_pcollector; + static PStatCollector _vertex_data_compressed_pcollector; + static PStatCollector _vertex_data_disk_pcollector; + static PStatCollector _cnode_volume_pcollector; static PStatCollector _gnode_volume_pcollector; static PStatCollector _geom_volume_pcollector; @@ -377,7 +382,6 @@ private: static PStatCollector _test_inv_sphere_pcollector; static PStatCollector _volume_geom_pcollector; static PStatCollector _test_geom_pcollector; - static PStatCollector _sw_sprites_pcollector; friend class WindowRenderer; friend class GraphicsOutput; diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx index b48bc8ad71..2b800f8d07 100644 --- a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx @@ -305,7 +305,7 @@ prepare_vertex_buffer(GeomVertexArrayData *data) { //////////////////////////////////////////////////////////////////// void DXGraphicsStateGuardian8:: apply_vertex_buffer(VertexBufferContext *vbc, - const GeomVertexArrayDataPipelineReader *reader) { + const GeomVertexArrayDataHandle *reader) { DXVertexBufferContext8 *dvbc = DCAST(DXVertexBufferContext8, vbc); if (dvbc->_vbuffer == NULL) { @@ -807,7 +807,7 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader, const GeomVertexFormat *format = _data_reader->get_format(); // The munger should have put the FVF data in the first array. - const GeomVertexArrayDataPipelineReader *data = _data_reader->get_array_reader(0); + const GeomVertexArrayDataHandle *data = _data_reader->get_array_reader(0); VertexBufferContext *vbc = ((GeomVertexArrayData *)(data->get_object()))->prepare_now(get_prepared_objects(), this); nassertr(vbc != (VertexBufferContext *)NULL, false); @@ -930,9 +930,9 @@ draw_triangles(const GeomPrimitivePipelineReader *reader) { (D3DPT_TRIANGLELIST, min_vertex, max_vertex, reader->get_num_primitives(), - reader->get_data(), + reader->get_pointer(), index_type, - _data_reader->get_array_reader(0)->get_data(), + _data_reader->get_array_reader(0)->get_pointer(), _data_reader->get_format()->get_array(0)->get_stride()); } } else { @@ -949,7 +949,7 @@ draw_triangles(const GeomPrimitivePipelineReader *reader) { draw_primitive_up(D3DPT_TRIANGLELIST, reader->get_num_primitives(), reader->get_first_vertex(), reader->get_num_vertices(), - _data_reader->get_array_reader(0)->get_data(), + _data_reader->get_array_reader(0)->get_pointer(), _data_reader->get_format()->get_array(0)->get_stride()); } } @@ -990,8 +990,8 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader) { (D3DPT_TRIANGLESTRIP, min_vertex, max_vertex, reader->get_num_vertices() - 2, - reader->get_data(), index_type, - _data_reader->get_array_reader(0)->get_data(), + reader->get_pointer(), index_type, + _data_reader->get_array_reader(0)->get_pointer(), _data_reader->get_format()->get_array(0)->get_stride()); } } else { @@ -1008,7 +1008,7 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader) { reader->get_num_vertices() - 2, reader->get_first_vertex(), reader->get_num_vertices(), - _data_reader->get_array_reader(0)->get_data(), + _data_reader->get_array_reader(0)->get_pointer(), _data_reader->get_format()->get_array(0)->get_stride()); } } @@ -1050,9 +1050,9 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader) { } else { // Indexed, client arrays, individual triangle strips. - CPTA_uchar array_data = _data_reader->get_array_reader(0)->get_data(); + const unsigned char *array_data = _data_reader->get_array_reader(0)->get_pointer(); int stride = _data_reader->get_format()->get_array(0)->get_stride(); - CPTA_uchar vertices = reader->get_data(); + const unsigned char *vertices = reader->get_pointer(); D3DFORMAT index_type = get_index_type(reader->get_index_type()); unsigned int start = 0; @@ -1087,7 +1087,7 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader) { } else { // Nonindexed, client arrays, individual triangle strips. - CPTA_uchar array_data = _data_reader->get_array_reader(0)->get_data(); + const unsigned char *array_data = _data_reader->get_array_reader(0)->get_pointer(); int stride = _data_reader->get_format()->get_array(0)->get_stride(); unsigned int start = 0; @@ -1150,9 +1150,9 @@ draw_trifans(const GeomPrimitivePipelineReader *reader) { } else { // Indexed, client arrays. - CPTA_uchar array_data = _data_reader->get_array_reader(0)->get_data(); + const unsigned char *array_data = _data_reader->get_array_reader(0)->get_pointer(); int stride = _data_reader->get_format()->get_array(0)->get_stride(); - CPTA_uchar vertices = reader->get_data(); + const unsigned char *vertices = reader->get_pointer(); D3DFORMAT index_type = get_index_type(reader->get_index_type()); unsigned int start = 0; @@ -1187,7 +1187,7 @@ draw_trifans(const GeomPrimitivePipelineReader *reader) { } else { // Nonindexed, client arrays. - CPTA_uchar array_data = _data_reader->get_array_reader(0)->get_data(); + const unsigned char *array_data = _data_reader->get_array_reader(0)->get_pointer(); int stride = _data_reader->get_format()->get_array(0)->get_stride(); unsigned int start = 0; @@ -1238,9 +1238,9 @@ draw_lines(const GeomPrimitivePipelineReader *reader) { (D3DPT_LINELIST, min_vertex, max_vertex, reader->get_num_primitives(), - reader->get_data(), + reader->get_pointer(), index_type, - _data_reader->get_array_reader(0)->get_data(), + _data_reader->get_array_reader(0)->get_pointer(), _data_reader->get_format()->get_array(0)->get_stride()); } } else { @@ -1256,7 +1256,7 @@ draw_lines(const GeomPrimitivePipelineReader *reader) { draw_primitive_up(D3DPT_LINELIST, reader->get_num_primitives(), reader->get_first_vertex(), reader->get_num_vertices(), - _data_reader->get_array_reader(0)->get_data(), + _data_reader->get_array_reader(0)->get_pointer(), _data_reader->get_format()->get_array(0)->get_stride()); } } @@ -1299,7 +1299,7 @@ draw_points(const GeomPrimitivePipelineReader *reader) { draw_primitive_up(D3DPT_POINTLIST, reader->get_num_primitives(), reader->get_first_vertex(), reader->get_num_vertices(), - _data_reader->get_array_reader(0)->get_data(), + _data_reader->get_array_reader(0)->get_pointer(), _data_reader->get_format()->get_array(0)->get_stride()); } } diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.h b/panda/src/dxgsg8/dxGraphicsStateGuardian8.h index b6a4336c65..091531e8cf 100644 --- a/panda/src/dxgsg8/dxGraphicsStateGuardian8.h +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.h @@ -57,7 +57,7 @@ public: virtual VertexBufferContext *prepare_vertex_buffer(GeomVertexArrayData *data); void apply_vertex_buffer(VertexBufferContext *vbc, - const GeomVertexArrayDataPipelineReader *reader); + const GeomVertexArrayDataHandle *reader); virtual void release_vertex_buffer(VertexBufferContext *vbc); virtual IndexBufferContext *prepare_index_buffer(GeomPrimitive *data); diff --git a/panda/src/dxgsg8/dxIndexBufferContext8.cxx b/panda/src/dxgsg8/dxIndexBufferContext8.cxx index 6c237d5e05..7c368f9214 100644 --- a/panda/src/dxgsg8/dxIndexBufferContext8.cxx +++ b/panda/src/dxgsg8/dxIndexBufferContext8.cxx @@ -131,7 +131,7 @@ upload_data(const GeomPrimitivePipelineReader *reader) { } GraphicsStateGuardian::_data_transferred_pcollector.add_level(data_size); - memcpy(local_pointer, reader->get_data(), data_size); + memcpy(local_pointer, reader->get_pointer(), data_size); _ibuffer->Unlock(); } diff --git a/panda/src/dxgsg8/dxVertexBufferContext8.cxx b/panda/src/dxgsg8/dxVertexBufferContext8.cxx index 77a31c8a4e..66a2696534 100644 --- a/panda/src/dxgsg8/dxVertexBufferContext8.cxx +++ b/panda/src/dxgsg8/dxVertexBufferContext8.cxx @@ -189,7 +189,7 @@ DXVertexBufferContext8:: //////////////////////////////////////////////////////////////////// void DXVertexBufferContext8:: create_vbuffer(DXScreenData &scrn, - const GeomVertexArrayDataPipelineReader *reader) { + const GeomVertexArrayDataHandle *reader) { nassertv(reader->get_object() == get_data()); Thread *current_thread = reader->get_current_thread(); @@ -232,7 +232,7 @@ create_vbuffer(DXScreenData &scrn, // DirectX. //////////////////////////////////////////////////////////////////// void DXVertexBufferContext8:: -upload_data(const GeomVertexArrayDataPipelineReader *reader) { +upload_data(const GeomVertexArrayDataHandle *reader) { nassertv(reader->get_object() == get_data()); nassertv(_vbuffer != NULL); Thread *current_thread = reader->get_current_thread(); @@ -257,7 +257,7 @@ upload_data(const GeomVertexArrayDataPipelineReader *reader) { } GraphicsStateGuardian::_data_transferred_pcollector.add_level(data_size); - memcpy(local_pointer, reader->get_data(), data_size); + memcpy(local_pointer, reader->get_pointer(), data_size); _vbuffer->Unlock(); } diff --git a/panda/src/dxgsg8/dxVertexBufferContext8.h b/panda/src/dxgsg8/dxVertexBufferContext8.h index e4cb6f9783..d908d73e9b 100644 --- a/panda/src/dxgsg8/dxVertexBufferContext8.h +++ b/panda/src/dxgsg8/dxVertexBufferContext8.h @@ -34,8 +34,8 @@ public: virtual ~DXVertexBufferContext8(); void create_vbuffer(DXScreenData &scrn, - const GeomVertexArrayDataPipelineReader *reader); - void upload_data(const GeomVertexArrayDataPipelineReader *reader); + const GeomVertexArrayDataHandle *reader); + void upload_data(const GeomVertexArrayDataHandle *reader); IDirect3DVertexBuffer8 *_vbuffer; int _fvf; diff --git a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx index b71ef1b650..d5dea48b91 100755 --- a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx +++ b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx @@ -393,7 +393,7 @@ prepare_vertex_buffer(GeomVertexArrayData *data) { void DXGraphicsStateGuardian9:: apply_vertex_buffer(VertexBufferContext *vbc, CLP(ShaderContext) *shader_context, - const GeomVertexArrayDataPipelineReader *reader) { + const GeomVertexArrayDataHandle *reader) { DXVertexBufferContext9 *dvbc = DCAST(DXVertexBufferContext9, vbc); DBG_SH3 dxgsg9_cat.debug ( ) << "apply_vertex_buffer\n"; DBG_E @@ -1186,7 +1186,7 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader, _vertex_array_shader_context = _current_shader_context; const GeomVertexFormat *format = _data_reader->get_format ( ); - const GeomVertexArrayDataPipelineReader *data; + const GeomVertexArrayDataHandle *data; int number_of_arrays = _data_reader -> get_num_arrays ( ); if (_current_shader_context && number_of_arrays > 1) { @@ -1422,9 +1422,9 @@ draw_triangles(const GeomPrimitivePipelineReader *reader) { (D3DPT_TRIANGLELIST, min_vertex, max_vertex, reader->get_num_primitives(), - reader->get_data(), + reader->get_pointer(), index_type, - _data_reader->get_array_reader(0)->get_data(), + _data_reader->get_array_reader(0)->get_pointer(), _data_reader->get_format()->get_array(0)->get_stride()); } } else { @@ -1446,7 +1446,7 @@ draw_triangles(const GeomPrimitivePipelineReader *reader) { draw_primitive_up(D3DPT_TRIANGLELIST, reader->get_num_primitives(), reader->get_first_vertex(), reader->get_num_vertices(), - _data_reader->get_array_reader(0)->get_data(), + _data_reader->get_array_reader(0)->get_pointer(), _data_reader->get_format()->get_array(0)->get_stride()); } } @@ -1497,8 +1497,8 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader) { (D3DPT_TRIANGLESTRIP, min_vertex, max_vertex, reader->get_num_vertices() - 2, - reader->get_data(), index_type, - _data_reader->get_array_reader(0)->get_data(), + reader->get_pointer(), index_type, + _data_reader->get_array_reader(0)->get_pointer(), _data_reader->get_format()->get_array(0)->get_stride()); } } else { @@ -1518,7 +1518,7 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader) { reader->get_num_vertices() - 2, reader->get_first_vertex(), reader->get_num_vertices(), - _data_reader->get_array_reader(0)->get_data(), + _data_reader->get_array_reader(0)->get_pointer(), _data_reader->get_format()->get_array(0)->get_stride()); } } @@ -1561,9 +1561,9 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader) { } else { // Indexed, client arrays, individual triangle strips. - CPTA_uchar array_data = _data_reader->get_array_reader(0)->get_data(); + const unsigned char *array_data = _data_reader->get_array_reader(0)->get_pointer(); int stride = _data_reader->get_format()->get_array(0)->get_stride(); - CPTA_uchar vertices = reader->get_data(); + const unsigned char *vertices = reader->get_pointer(); D3DFORMAT index_type = get_index_type(reader->get_index_type()); unsigned int start = 0; @@ -1598,7 +1598,7 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader) { } else { // Nonindexed, client arrays, individual triangle strips. - CPTA_uchar array_data = _data_reader->get_array_reader(0)->get_data(); + const unsigned char *array_data = _data_reader->get_array_reader(0)->get_pointer(); int stride = _data_reader->get_format()->get_array(0)->get_stride(); unsigned int start = 0; @@ -1664,9 +1664,9 @@ draw_trifans(const GeomPrimitivePipelineReader *reader) { } else { // Indexed, client arrays. - CPTA_uchar array_data = _data_reader->get_array_reader(0)->get_data(); + const unsigned char *array_data = _data_reader->get_array_reader(0)->get_pointer(); int stride = _data_reader->get_format()->get_array(0)->get_stride(); - CPTA_uchar vertices = reader->get_data(); + const unsigned char *vertices = reader->get_pointer(); D3DFORMAT index_type = get_index_type(reader->get_index_type()); unsigned int start = 0; @@ -1701,7 +1701,7 @@ draw_trifans(const GeomPrimitivePipelineReader *reader) { } else { // Nonindexed, client arrays. - CPTA_uchar array_data = _data_reader->get_array_reader(0)->get_data(); + const unsigned char *array_data = _data_reader->get_array_reader(0)->get_pointer(); int stride = _data_reader->get_format()->get_array(0)->get_stride(); unsigned int start = 0; @@ -1753,9 +1753,9 @@ draw_lines(const GeomPrimitivePipelineReader *reader) { (D3DPT_LINELIST, min_vertex, max_vertex, reader->get_num_primitives(), - reader->get_data(), + reader->get_pointer(), index_type, - _data_reader->get_array_reader(0)->get_data(), + _data_reader->get_array_reader(0)->get_pointer(), _data_reader->get_format()->get_array(0)->get_stride()); } } else { @@ -1771,7 +1771,7 @@ draw_lines(const GeomPrimitivePipelineReader *reader) { draw_primitive_up(D3DPT_LINELIST, reader->get_num_primitives(), reader->get_first_vertex(), reader->get_num_vertices(), - _data_reader->get_array_reader(0)->get_data(), + _data_reader->get_array_reader(0)->get_pointer(), _data_reader->get_format()->get_array(0)->get_stride()); } } @@ -1814,7 +1814,7 @@ draw_points(const GeomPrimitivePipelineReader *reader) { draw_primitive_up(D3DPT_POINTLIST, reader->get_num_primitives(), reader->get_first_vertex(), reader->get_num_vertices(), - _data_reader->get_array_reader(0)->get_data(), + _data_reader->get_array_reader(0)->get_pointer(), _data_reader->get_format()->get_array(0)->get_stride()); } } @@ -2220,11 +2220,11 @@ bool vertex_buffer_page_in_function (LruPage *lru_page) // allocate vertex buffer Thread *current_thread = Thread::get_current_thread(); - GeomVertexArrayDataPipelineReader reader(vertex_buffer->get_data(), current_thread); - vertex_buffer -> allocate_vbuffer (*(gsg->_screen), &reader); + CPT(GeomVertexArrayDataHandle) reader = vertex_buffer->get_data()->get_handle(current_thread); + vertex_buffer -> allocate_vbuffer (*(gsg->_screen), reader); // update vertex buffer - vertex_buffer -> upload_data(&reader); + vertex_buffer -> upload_data(reader); vertex_buffer -> set_resident(true); if (DEBUG_LRU && dxgsg9_cat.is_debug()) diff --git a/panda/src/dxgsg9/dxGraphicsStateGuardian9.h b/panda/src/dxgsg9/dxGraphicsStateGuardian9.h index 605a6b0755..276b506b09 100755 --- a/panda/src/dxgsg9/dxGraphicsStateGuardian9.h +++ b/panda/src/dxgsg9/dxGraphicsStateGuardian9.h @@ -94,7 +94,7 @@ public: virtual VertexBufferContext *prepare_vertex_buffer(GeomVertexArrayData *data); void apply_vertex_buffer(VertexBufferContext *vbc, CLP(ShaderContext) *shader_context, - const GeomVertexArrayDataPipelineReader *reader); + const GeomVertexArrayDataHandle *reader); virtual void release_vertex_buffer(VertexBufferContext *vbc); virtual IndexBufferContext *prepare_index_buffer(GeomPrimitive *data); diff --git a/panda/src/dxgsg9/dxIndexBufferContext9.cxx b/panda/src/dxgsg9/dxIndexBufferContext9.cxx index 2713f8fa66..01985a2189 100755 --- a/panda/src/dxgsg9/dxIndexBufferContext9.cxx +++ b/panda/src/dxgsg9/dxIndexBufferContext9.cxx @@ -237,7 +237,7 @@ upload_data(const GeomPrimitivePipelineReader *reader) { } GraphicsStateGuardian::_data_transferred_pcollector.add_level(data_size); - memcpy(local_pointer, reader->get_data(), data_size); + memcpy(local_pointer, reader->get_pointer(), data_size); _ibuffer->Unlock(); } diff --git a/panda/src/dxgsg9/dxShaderContext9.cxx b/panda/src/dxgsg9/dxShaderContext9.cxx index 7cd13f7962..ad0c91f6d3 100644 --- a/panda/src/dxgsg9/dxShaderContext9.cxx +++ b/panda/src/dxgsg9/dxShaderContext9.cxx @@ -459,7 +459,7 @@ update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg) { if (_vertex_element_array == 0) { bool error; - const GeomVertexArrayDataPipelineReader *array_reader; + const GeomVertexArrayDataHandle *array_reader; Geom::NumericType numeric_type; int start, stride, num_values; int nvarying = _expansion->_var_spec.size(); diff --git a/panda/src/dxgsg9/dxVertexBufferContext9.cxx b/panda/src/dxgsg9/dxVertexBufferContext9.cxx index f9ccd6d469..75411c3e08 100755 --- a/panda/src/dxgsg9/dxVertexBufferContext9.cxx +++ b/panda/src/dxgsg9/dxVertexBufferContext9.cxx @@ -341,7 +341,7 @@ free_vbuffer(void) { //////////////////////////////////////////////////////////////////// void DXVertexBufferContext9:: allocate_vbuffer(DXScreenData &scrn, - const GeomVertexArrayDataPipelineReader *reader) { + const GeomVertexArrayDataHandle *reader) { int data_size; HRESULT hr; @@ -393,7 +393,7 @@ allocate_vbuffer(DXScreenData &scrn, //////////////////////////////////////////////////////////////////// void DXVertexBufferContext9:: create_vbuffer(DXScreenData &scrn, - const GeomVertexArrayDataPipelineReader *reader) { + const GeomVertexArrayDataHandle *reader) { nassertv(reader->get_object() == get_data()); Thread *current_thread = reader->get_current_thread(); @@ -442,7 +442,7 @@ create_vbuffer(DXScreenData &scrn, // DirectX. //////////////////////////////////////////////////////////////////// void DXVertexBufferContext9:: -upload_data(const GeomVertexArrayDataPipelineReader *reader) { +upload_data(const GeomVertexArrayDataHandle *reader) { nassertv(reader->get_object() == get_data()); nassertv(_vbuffer != NULL); Thread *current_thread = reader->get_current_thread(); @@ -473,7 +473,7 @@ upload_data(const GeomVertexArrayDataPipelineReader *reader) { } GraphicsStateGuardian::_data_transferred_pcollector.add_level(data_size); - memcpy(local_pointer, reader->get_data(), data_size); + memcpy(local_pointer, reader->get_pointer(), data_size); _vbuffer->Unlock(); } diff --git a/panda/src/dxgsg9/dxVertexBufferContext9.h b/panda/src/dxgsg9/dxVertexBufferContext9.h index 81e0dffdb2..1385ebeef0 100755 --- a/panda/src/dxgsg9/dxVertexBufferContext9.h +++ b/panda/src/dxgsg9/dxVertexBufferContext9.h @@ -34,9 +34,9 @@ public: virtual ~DXVertexBufferContext9(); void free_vbuffer(); - void allocate_vbuffer(DXScreenData &scrn, const GeomVertexArrayDataPipelineReader *reader); - void create_vbuffer(DXScreenData &scrn, const GeomVertexArrayDataPipelineReader *reader); - void upload_data(const GeomVertexArrayDataPipelineReader *reader); + void allocate_vbuffer(DXScreenData &scrn, const GeomVertexArrayDataHandle *reader); + void create_vbuffer(DXScreenData &scrn, const GeomVertexArrayDataHandle *reader); + void upload_data(const GeomVertexArrayDataHandle *reader); IDirect3DVertexBuffer9 *_vbuffer; int _fvf; diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 8e30656456..3c4d50e614 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -1782,7 +1782,7 @@ update_standard_vertex_arrays() { #endif // SUPPORT_IMMEDIATE_MODE { // We may use vertex arrays or buffers to render primitives. - const GeomVertexArrayDataPipelineReader *array_reader; + const GeomVertexArrayDataHandle *array_reader; int num_values; Geom::NumericType numeric_type; int start; @@ -2697,7 +2697,7 @@ prepare_vertex_buffer(GeomVertexArrayData *data) { //////////////////////////////////////////////////////////////////// void CLP(GraphicsStateGuardian):: apply_vertex_buffer(VertexBufferContext *vbc, - const GeomVertexArrayDataPipelineReader *reader) { + const GeomVertexArrayDataHandle *reader) { nassertv(_supports_buffers); nassertv(reader->get_modified() != UpdateSeq::initial()); @@ -2724,12 +2724,12 @@ apply_vertex_buffer(VertexBufferContext *vbc, if (num_bytes != 0) { if (gvbc->changed_size(reader) || gvbc->changed_usage_hint(reader)) { _glBufferData(GL_ARRAY_BUFFER, num_bytes, - reader->get_data(), + reader->get_pointer(), get_usage(reader->get_usage_hint())); } else { _glBufferSubData(GL_ARRAY_BUFFER, 0, num_bytes, - reader->get_data()); + reader->get_pointer()); } _data_transferred_pcollector.add_level(num_bytes); } @@ -2795,10 +2795,10 @@ release_vertex_buffer(VertexBufferContext *vbc) { // in client memory, that is, the data array passed in. //////////////////////////////////////////////////////////////////// const unsigned char *CLP(GraphicsStateGuardian):: -setup_array_data(const GeomVertexArrayDataPipelineReader *array_reader) { +setup_array_data(const GeomVertexArrayDataHandle *array_reader) { if (!_supports_buffers) { // No support for buffer objects; always render from client. - return array_reader->get_data(); + return array_reader->get_pointer(); } if (!vertex_buffers || _geom_display_list != 0 || array_reader->get_usage_hint() == Geom::UH_client) { @@ -2812,12 +2812,12 @@ setup_array_data(const GeomVertexArrayDataPipelineReader *array_reader) { _glBindBuffer(GL_ARRAY_BUFFER, 0); _current_vbuffer_index = 0; } - return array_reader->get_data(); + return array_reader->get_pointer(); } // Prepare the buffer object and bind it. VertexBufferContext *vbc = ((GeomVertexArrayData *)array_reader->get_object())->prepare_now(get_prepared_objects(), this); - nassertr(vbc != (VertexBufferContext *)NULL, array_reader->get_data()); + nassertr(vbc != (VertexBufferContext *)NULL, array_reader->get_pointer()); apply_vertex_buffer(vbc, array_reader); // NULL is the OpenGL convention for the first byte of the buffer object. @@ -2884,6 +2884,7 @@ apply_index_buffer(IndexBufferContext *ibc, if (gibc->was_modified(reader)) { PStatTimer timer(_load_index_buffer_pcollector, reader->get_current_thread()); + int num_bytes = reader->get_data_size_bytes(); if (GLCAT.is_spam()) { GLCAT.spam() @@ -2893,12 +2894,12 @@ apply_index_buffer(IndexBufferContext *ibc, if (num_bytes != 0) { if (gibc->changed_size(reader) || gibc->changed_usage_hint(reader)) { _glBufferData(GL_ELEMENT_ARRAY_BUFFER, num_bytes, - reader->get_data(), + reader->get_pointer(), get_usage(reader->get_usage_hint())); } else { _glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, num_bytes, - reader->get_data()); + reader->get_pointer()); } _data_transferred_pcollector.add_level(num_bytes); } @@ -2966,7 +2967,7 @@ const unsigned char *CLP(GraphicsStateGuardian):: setup_primitive(const GeomPrimitivePipelineReader *reader) { if (!_supports_buffers) { // No support for buffer objects; always render from client. - return reader->get_data(); + return reader->get_pointer(); } if (!vertex_buffers || _geom_display_list != 0 || reader->get_usage_hint() == Geom::UH_client) { @@ -2980,12 +2981,12 @@ setup_primitive(const GeomPrimitivePipelineReader *reader) { _glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); _current_ibuffer_index = 0; } - return reader->get_data(); + return reader->get_pointer(); } // Prepare the buffer object and bind it. IndexBufferContext *ibc = ((GeomPrimitive *)reader->get_object())->prepare_now(get_prepared_objects(), this); - nassertr(ibc != (IndexBufferContext *)NULL, reader->get_data()); + nassertr(ibc != (IndexBufferContext *)NULL, reader->get_pointer()); apply_index_buffer(ibc, reader); // NULL is the OpenGL convention for the first byte of the buffer object. diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index 5358dfc663..c2a7758d95 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.h @@ -131,9 +131,9 @@ public: virtual VertexBufferContext *prepare_vertex_buffer(GeomVertexArrayData *data); void apply_vertex_buffer(VertexBufferContext *vbc, - const GeomVertexArrayDataPipelineReader *reader); + const GeomVertexArrayDataHandle *reader); virtual void release_vertex_buffer(VertexBufferContext *vbc); - const unsigned char *setup_array_data(const GeomVertexArrayDataPipelineReader *data); + const unsigned char *setup_array_data(const GeomVertexArrayDataHandle *data); virtual IndexBufferContext *prepare_index_buffer(GeomPrimitive *data); void apply_index_buffer(IndexBufferContext *ibc, diff --git a/panda/src/glstuff/glShaderContext_src.cxx b/panda/src/glstuff/glShaderContext_src.cxx index 56793f689e..865d068f2d 100755 --- a/panda/src/glstuff/glShaderContext_src.cxx +++ b/panda/src/glstuff/glShaderContext_src.cxx @@ -218,7 +218,7 @@ update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg) { } else #endif // SUPPORT_IMMEDIATE_MODE { - const GeomVertexArrayDataPipelineReader *array_reader; + const GeomVertexArrayDataHandle *array_reader; Geom::NumericType numeric_type; int start, stride, num_values; int nvarying = _expansion->_var_spec.size(); diff --git a/panda/src/gobj/Sources.pp b/panda/src/gobj/Sources.pp index 096032ab02..a1138c0661 100644 --- a/panda/src/gobj/Sources.pp +++ b/panda/src/gobj/Sources.pp @@ -50,6 +50,7 @@ savedContext.I savedContext.h \ shaderContext.h shaderContext.I \ shaderExpansion.h shaderExpansion.I \ + simpleLru.h simpleLru.I \ sliderTable.I sliderTable.h \ texture.I texture.h \ textureContext.I textureContext.h \ @@ -106,6 +107,7 @@ savedContext.cxx \ shaderContext.cxx \ shaderExpansion.cxx \ + simpleLru.cxx \ sliderTable.cxx \ texture.cxx textureContext.cxx texturePool.cxx \ texturePoolFilter.cxx \ @@ -162,6 +164,7 @@ savedContext.I savedContext.h \ shaderContext.h shaderContext.I \ shaderExpansion.h shaderExpansion.I \ + simpleLru.h simpleLru.I \ sliderTable.I sliderTable.h \ texture.I texture.h \ textureContext.I textureContext.h \ diff --git a/panda/src/gobj/config_gobj.cxx b/panda/src/gobj/config_gobj.cxx index df2de36ce4..5b726ac0d7 100644 --- a/panda/src/gobj/config_gobj.cxx +++ b/panda/src/gobj/config_gobj.cxx @@ -287,8 +287,7 @@ ConfigureFn(config_gobj) { GeomTrifans::init_type(); GeomTristrips::init_type(); GeomVertexArrayData::init_type(); - GeomVertexArrayDataPipelineReader::init_type(); - GeomVertexArrayDataPipelineWriter::init_type(); + GeomVertexArrayDataHandle::init_type(); GeomVertexArrayFormat::init_type(); GeomVertexData::init_type(); GeomVertexDataPipelineReader::init_type(); diff --git a/panda/src/gobj/geom.cxx b/panda/src/gobj/geom.cxx index b6956bc535..8202102534 100644 --- a/panda/src/gobj/geom.cxx +++ b/panda/src/gobj/geom.cxx @@ -223,6 +223,10 @@ offset_vertices(const GeomVertexData *data, int offset) { #ifndef NDEBUG if (!prim->check_valid(data)) { + gobj_cat.warning() + << *prim << " is invalid for " << *data << ":\n"; + prim->write(gobj_cat.warning(false), 4); + all_is_valid = false; } #endif diff --git a/panda/src/gobj/geomEnums.h b/panda/src/gobj/geomEnums.h index ab4cc8dc3a..9ca67f0d54 100644 --- a/panda/src/gobj/geomEnums.h +++ b/panda/src/gobj/geomEnums.h @@ -210,6 +210,17 @@ PUBLISHED: AT_hardware, // Hardware-accelerated animation on the graphics card. }; + // These are used to indicate the current residency state of vertex + // data, which may or may not have been temporarily evicted to + // satisfy memory requirements. + enum RamClass { + RC_resident, + RC_compressed, + RC_disk, + + RC_end_of_list, // list marker; do not use + }; + }; EXPCL_PANDA ostream &operator << (ostream &out, GeomEnums::NumericType numeric_type); diff --git a/panda/src/gobj/geomPrimitive.I b/panda/src/gobj/geomPrimitive.I index 2a816c96ce..6b957dc95b 100644 --- a/panda/src/gobj/geomPrimitive.I +++ b/panda/src/gobj/geomPrimitive.I @@ -303,18 +303,6 @@ get_index_stride() const { return reader.get_index_stride(); } -//////////////////////////////////////////////////////////////////// -// Function: GeomPrimitive::get_data -// Access: Public -// Description: A convenience function to return the actual data of -// the index array. -//////////////////////////////////////////////////////////////////// -INLINE CPTA_uchar GeomPrimitive:: -get_data() const { - nassertr(is_indexed(), CPTA_uchar()); - return get_vertices()->get_data(); -} - //////////////////////////////////////////////////////////////////// // Function: GeomPrimitive::get_ends // Access: Public @@ -486,8 +474,7 @@ GeomPrimitivePipelineReader(const GeomPrimitive *object, _cdata->ref(); #endif // DO_PIPELINING if (!_cdata->_vertices.is_null()) { - _vertices_reader = - new GeomVertexArrayDataPipelineReader(_cdata->_vertices.get_read_pointer(), _current_thread); + _vertices_reader = _cdata->_vertices.get_read_pointer()->get_handle(); } } @@ -518,9 +505,6 @@ operator = (const GeomPrimitivePipelineReader &) { //////////////////////////////////////////////////////////////////// INLINE GeomPrimitivePipelineReader:: ~GeomPrimitivePipelineReader() { - if (_vertices_reader != (GeomVertexArrayDataPipelineReader *)NULL) { - delete _vertices_reader; - } #ifdef _DEBUG nassertv(_object->test_ref_count_nonzero()); #endif // _DEBUG @@ -671,19 +655,19 @@ get_index_stride() const { // Access: Public // Description: //////////////////////////////////////////////////////////////////// -INLINE const GeomVertexArrayDataPipelineReader *GeomPrimitivePipelineReader:: +INLINE const GeomVertexArrayDataHandle *GeomPrimitivePipelineReader:: get_vertices_reader() const { return _vertices_reader; } //////////////////////////////////////////////////////////////////// -// Function: GeomPrimitivePipelineReader::get_data +// Function: GeomPrimitivePipelineReader::get_pointer // Access: Public // Description: //////////////////////////////////////////////////////////////////// -INLINE CPTA_uchar GeomPrimitivePipelineReader:: -get_data() const { - return _vertices_reader->get_data(); +INLINE const unsigned char *GeomPrimitivePipelineReader:: +get_pointer() const { + return _vertices_reader->get_pointer(); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/gobj/geomPrimitive.cxx b/panda/src/gobj/geomPrimitive.cxx index 43a6af3993..941c442584 100644 --- a/panda/src/gobj/geomPrimitive.cxx +++ b/panda/src/gobj/geomPrimitive.cxx @@ -1314,7 +1314,8 @@ calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, } } else { for (int i = 0; i < num_vertices; ++i) { - reader.set_row(index.get_data1i()); + int ii = index.get_data1i(); + reader.set_row(ii); const LVecBase3f &vertex = reader.get_data3f(); if (found_any) { diff --git a/panda/src/gobj/geomPrimitive.h b/panda/src/gobj/geomPrimitive.h index 5560b2785a..bbe35675fb 100644 --- a/panda/src/gobj/geomPrimitive.h +++ b/panda/src/gobj/geomPrimitive.h @@ -158,7 +158,6 @@ public: void set_nonindexed_vertices(int first_vertex, int num_vertices); INLINE int get_index_stride() const; - INLINE CPTA_uchar get_data() const; INLINE CPTA_int get_ends() const; PTA_int modify_ends(); @@ -346,8 +345,8 @@ public: INLINE UpdateSeq get_modified() const; bool check_valid(const GeomVertexDataPipelineReader *data_reader) const; INLINE int get_index_stride() const; - INLINE const GeomVertexArrayDataPipelineReader *get_vertices_reader() const; - INLINE CPTA_uchar get_data() const; + INLINE const GeomVertexArrayDataHandle *get_vertices_reader() const; + INLINE const unsigned char *get_pointer() const; INLINE CPTA_int get_ends() const; INLINE CPT(GeomVertexArrayData) get_mins() const; INLINE CPT(GeomVertexArrayData) get_maxs() const; @@ -357,7 +356,7 @@ private: Thread *_current_thread; const GeomPrimitive::CData *_cdata; - GeomVertexArrayDataPipelineReader *_vertices_reader; + CPT(GeomVertexArrayDataHandle) _vertices_reader; public: static TypeHandle get_class_type() { diff --git a/panda/src/gobj/geomVertexArrayData.I b/panda/src/gobj/geomVertexArrayData.I index c6464c2151..8bc77dd251 100644 --- a/panda/src/gobj/geomVertexArrayData.I +++ b/panda/src/gobj/geomVertexArrayData.I @@ -62,8 +62,7 @@ has_column(const InternalName *name) const { //////////////////////////////////////////////////////////////////// INLINE int GeomVertexArrayData:: get_num_rows() const { - GeomVertexArrayDataPipelineReader reader(this, Thread::get_current_thread()); - return reader.get_num_rows(); + return get_handle()->get_num_rows(); } //////////////////////////////////////////////////////////////////// @@ -90,8 +89,7 @@ get_num_rows() const { //////////////////////////////////////////////////////////////////// INLINE bool GeomVertexArrayData:: set_num_rows(int n) { - GeomVertexArrayDataPipelineWriter writer(this, true, Thread::get_current_thread()); - return writer.set_num_rows(n); + return modify_handle()->set_num_rows(n); } //////////////////////////////////////////////////////////////////// @@ -109,8 +107,7 @@ set_num_rows(int n) { //////////////////////////////////////////////////////////////////// INLINE bool GeomVertexArrayData:: unclean_set_num_rows(int n) { - GeomVertexArrayDataPipelineWriter writer(this, true, Thread::get_current_thread()); - return writer.unclean_set_num_rows(n); + return modify_handle()->unclean_set_num_rows(n); } //////////////////////////////////////////////////////////////////// @@ -121,7 +118,7 @@ unclean_set_num_rows(int n) { //////////////////////////////////////////////////////////////////// INLINE void GeomVertexArrayData:: clear_rows() { - set_data(PTA_uchar(GeomVertexArrayData::get_class_type())); + return modify_handle()->clear_rows(); } //////////////////////////////////////////////////////////////////// @@ -132,7 +129,7 @@ clear_rows() { INLINE int GeomVertexArrayData:: get_data_size_bytes() const { CDReader cdata(_cycler); - return cdata->_data.size(); + return cdata->_data_full_size; } //////////////////////////////////////////////////////////////////// @@ -149,49 +146,71 @@ get_modified() const { } //////////////////////////////////////////////////////////////////// -// Function: GeomVertexArrayData::get_data +// Function: GeomVertexArrayData::get_handle // Access: Published -// Description: Returns a const pointer to the actual vertex data, -// for application code to directly examine (but not -// modify). +// Description: Returns an object that can be used to read the actual +// data bytes stored in the array. Calling this method +// locks the data, and will block any other threads +// attempting to read or write the data, until the +// returned object destructs. //////////////////////////////////////////////////////////////////// -INLINE CPTA_uchar GeomVertexArrayData:: -get_data() const { - CDReader cdata(_cycler); - return cdata->_data; +INLINE CPT(GeomVertexArrayDataHandle) GeomVertexArrayData:: +get_handle(Thread *current_thread) const { + return new GeomVertexArrayDataHandle(this, current_thread, + _cycler.read_unlocked(current_thread), + false); } //////////////////////////////////////////////////////////////////// -// Function: GeomVertexArrayData::modify_data +// Function: GeomVertexArrayData::modify_handle // Access: Published -// Description: Returns a modifiable pointer to the actual vertex -// array, so that application code may directly -// manipulate it. Use with caution. -// -// Don't call this in a downstream thread unless you -// don't mind it blowing away other changes you might -// have recently made in an upstream thread. +// Description: Returns an object that can be used to read or write +// the actual data bytes stored in the array. Calling +// this method locks the data, and will block any other +// threads attempting to read or write the data, until +// the returned object destructs. //////////////////////////////////////////////////////////////////// -INLINE PTA_uchar GeomVertexArrayData:: -modify_data() { - GeomVertexArrayDataPipelineWriter writer(this, true, Thread::get_current_thread()); - return writer.modify_data(); +INLINE PT(GeomVertexArrayDataHandle) GeomVertexArrayData:: +modify_handle(Thread *current_thread) { + return new GeomVertexArrayDataHandle(this, current_thread, + _cycler.write_upstream(true, current_thread), + true); } //////////////////////////////////////////////////////////////////// -// Function: GeomVertexArrayData::set_data +// Function: GeomVertexArrayData::get_ram_class // Access: Published -// Description: Replaces the vertex data array with a completely new -// array. -// -// Don't call this in a downstream thread unless you -// don't mind it blowing away other changes you might -// have recently made in an upstream thread. +// Description: Returns the current ram class of the array. If this +// is other than RC_resident, the array data is not +// resident in memory. +//////////////////////////////////////////////////////////////////// +INLINE GeomVertexArrayData::RamClass GeomVertexArrayData:: +get_ram_class() const { + return _ram_class; +} + +//////////////////////////////////////////////////////////////////// +// Function: GeomVertexArrayData::get_global_lru +// Access: Published, Static +// Description: Returns a pointer to the global LRU object that +// manages the GeomVertexArrayData's with the indicated +// RamClass. +//////////////////////////////////////////////////////////////////// +INLINE SimpleLru *GeomVertexArrayData:: +get_global_lru(RamClass rclass) { + nassertr(rclass >= 0 && rclass < RC_end_of_list, NULL); + return &_global_lru[rclass]; +} + +//////////////////////////////////////////////////////////////////// +// Function: GeomVertexArrayData::set_ram_class +// Access: Private +// Description: Puts the data in a new ram class. //////////////////////////////////////////////////////////////////// INLINE void GeomVertexArrayData:: -set_data(CPTA_uchar array) { - GeomVertexArrayDataPipelineWriter writer(this, true, Thread::get_current_thread()); - writer.set_data(array); +set_ram_class(RamClass rclass) { + _ram_class = rclass; + mark_used_lru(&_global_lru[rclass]); } //////////////////////////////////////////////////////////////////// @@ -202,9 +221,9 @@ set_data(CPTA_uchar array) { INLINE GeomVertexArrayData::CData:: CData() : _usage_hint(UH_unspecified), - _data(GeomVertexArrayData::get_class_type()) + _data(GeomVertexArrayData::get_class_type()), + _data_full_size(0) { - _data.node_ref(); } //////////////////////////////////////////////////////////////////// @@ -215,24 +234,41 @@ CData() : INLINE GeomVertexArrayData::CData:: CData(const GeomVertexArrayData::CData ©) : _usage_hint(copy._usage_hint), - _data(copy._data), + _data(GeomVertexArrayData::get_class_type()), + _data_full_size(copy._data_full_size), _modified(copy._modified) { - _data.node_ref(); + _data.v() = copy._data.v(); } //////////////////////////////////////////////////////////////////// -// Function: GeomVertexArrayDataPipelineBase::Constructor +// Function: GeomVertexArrayData::CData::Copy Assignment // Access: Public // Description: //////////////////////////////////////////////////////////////////// -INLINE GeomVertexArrayDataPipelineBase:: -GeomVertexArrayDataPipelineBase(GeomVertexArrayData *object, - Thread *current_thread, - GeomVertexArrayData::CData *cdata) : - _object(object), +INLINE void GeomVertexArrayData::CData:: +operator = (const GeomVertexArrayData::CData ©) { + _usage_hint = copy._usage_hint; + _modified = copy._modified; + _data.v() = copy._data.v(); + _data_full_size = copy._data_full_size; +} + +//////////////////////////////////////////////////////////////////// +// Function: GeomVertexArrayDataHandle::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE GeomVertexArrayDataHandle:: +GeomVertexArrayDataHandle(const GeomVertexArrayData *object, + Thread *current_thread, + const GeomVertexArrayData::CData *cdata, + bool writable) : + _holder(((GeomVertexArrayData::CData *)cdata)->_rw_lock), + _object((GeomVertexArrayData *)object), _current_thread(current_thread), - _cdata(cdata) + _cdata((GeomVertexArrayData::CData *)cdata), + _writable(writable) { #ifdef _DEBUG nassertv(_object->test_ref_count_nonzero()); @@ -243,16 +279,42 @@ GeomVertexArrayDataPipelineBase(GeomVertexArrayData *object, } //////////////////////////////////////////////////////////////////// -// Function: GeomVertexArrayDataPipelineBase::Destructor +// Function: GeomVertexArrayDataHandle::Copy Constructor +// Access: Private +// Description: Don't attempt to copy these objects. +//////////////////////////////////////////////////////////////////// +INLINE GeomVertexArrayDataHandle:: +GeomVertexArrayDataHandle(const GeomVertexArrayDataHandle ©) : + _holder(copy._cdata->_rw_lock) +{ + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: GeomVertexArrayDataHandle::Copy Assignment Operator +// Access: Private +// Description: Don't attempt to copy these objects. +//////////////////////////////////////////////////////////////////// +INLINE void GeomVertexArrayDataHandle:: +operator = (const GeomVertexArrayDataHandle &) { + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: GeomVertexArrayDataHandle::Destructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// -INLINE GeomVertexArrayDataPipelineBase:: -~GeomVertexArrayDataPipelineBase() { +INLINE GeomVertexArrayDataHandle:: +~GeomVertexArrayDataHandle() { #ifdef _DEBUG nassertv(_object->test_ref_count_nonzero()); #endif // _DEBUG + if (_writable) { + _object->_cycler.release_write(_cdata); + } + #ifdef DO_PIPELINING unref_delete((CycleData *)_cdata); #endif // DO_PIPELINING @@ -264,184 +326,134 @@ INLINE GeomVertexArrayDataPipelineBase:: } //////////////////////////////////////////////////////////////////// -// Function: GeomVertexArrayDataPipelineBase::get_current_thread +// Function: GeomVertexArrayDataHandle::get_current_thread // Access: Public // Description: //////////////////////////////////////////////////////////////////// -INLINE Thread *GeomVertexArrayDataPipelineBase:: +INLINE Thread *GeomVertexArrayDataHandle:: get_current_thread() const { return _current_thread; } //////////////////////////////////////////////////////////////////// -// Function: GeomVertexArrayDataPipelineBase::get_array_format +// Function: GeomVertexArrayDataHandle::get_object +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE const GeomVertexArrayData *GeomVertexArrayDataHandle:: +get_object() const { + return _object; +} + +//////////////////////////////////////////////////////////////////// +// Function: GeomVertexArrayDataHandle::get_object +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE GeomVertexArrayData *GeomVertexArrayDataHandle:: +get_object() { + return _object; +} + +//////////////////////////////////////////////////////////////////// +// Function: GeomVertexArrayDataHandle::get_pointer +// Access: Public +// Description: Returns a pointer to the beginning of the actual data +// stream. +//////////////////////////////////////////////////////////////////// +INLINE const unsigned char *GeomVertexArrayDataHandle:: +get_pointer() const { + check_resident(); + return _cdata->_data.p(); +} + +//////////////////////////////////////////////////////////////////// +// Function: GeomVertexArrayDataHandle::get_pointer +// Access: Public +// Description: Returns a pointer to the beginning of the actual data +// stream. +//////////////////////////////////////////////////////////////////// +INLINE unsigned char *GeomVertexArrayDataHandle:: +get_pointer() { + nassertr(_writable, NULL); + check_resident(); + return _cdata->_data.p(); +} + +//////////////////////////////////////////////////////////////////// +// Function: GeomVertexArrayDataHandle::get_array_format // Access: Public // Description: //////////////////////////////////////////////////////////////////// -INLINE const GeomVertexArrayFormat *GeomVertexArrayDataPipelineBase:: +INLINE const GeomVertexArrayFormat *GeomVertexArrayDataHandle:: get_array_format() const { return _object->_array_format; } //////////////////////////////////////////////////////////////////// -// Function: GeomVertexArrayDataPipelineBase::get_usage_hint +// Function: GeomVertexArrayDataHandle::get_usage_hint // Access: Public // Description: //////////////////////////////////////////////////////////////////// -INLINE GeomVertexArrayDataPipelineBase::UsageHint GeomVertexArrayDataPipelineBase:: +INLINE GeomVertexArrayDataHandle::UsageHint GeomVertexArrayDataHandle:: get_usage_hint() const { return _cdata->_usage_hint; } //////////////////////////////////////////////////////////////////// -// Function: GeomVertexArrayDataPipelineBase::get_data -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE CPTA_uchar GeomVertexArrayDataPipelineBase:: -get_data() const { - return _cdata->_data; -} - -//////////////////////////////////////////////////////////////////// -// Function: GeomVertexArrayDataPipelineBase::get_num_rows +// Function: GeomVertexArrayDataHandle::get_num_rows // Access: Published // Description: //////////////////////////////////////////////////////////////////// -INLINE int GeomVertexArrayDataPipelineBase:: +INLINE int GeomVertexArrayDataHandle:: get_num_rows() const { return get_data_size_bytes() / _object->_array_format->get_stride(); } //////////////////////////////////////////////////////////////////// -// Function: GeomVertexArrayDataPipelineBase::get_data_size_bytes +// Function: GeomVertexArrayDataHandle::clear_rows // Access: Published // Description: //////////////////////////////////////////////////////////////////// -INLINE int GeomVertexArrayDataPipelineBase:: -get_data_size_bytes() const { - return _cdata->_data.size(); +INLINE void GeomVertexArrayDataHandle:: +clear_rows() { + set_num_rows(0); } //////////////////////////////////////////////////////////////////// -// Function: GeomVertexArrayDataPipelineBase::get_modified -// Access: Public +// Function: GeomVertexArrayDataHandle::get_data_size_bytes +// Access: Published // Description: //////////////////////////////////////////////////////////////////// -INLINE UpdateSeq GeomVertexArrayDataPipelineBase:: +INLINE int GeomVertexArrayDataHandle:: +get_data_size_bytes() const { + return _cdata->_data_full_size; +} + +//////////////////////////////////////////////////////////////////// +// Function: GeomVertexArrayDataHandle::get_modified +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE UpdateSeq GeomVertexArrayDataHandle:: get_modified() const { return _cdata->_modified; } //////////////////////////////////////////////////////////////////// -// Function: GeomVertexArrayDataPipelineReader::Constructor -// Access: Public -// Description: +// Function: GeomVertexArrayDataHandle::check_resident +// Access: Published +// Description: Forces the vertex data into system RAM, if it is not +// already there; also, marks it recently-used. //////////////////////////////////////////////////////////////////// -INLINE GeomVertexArrayDataPipelineReader:: -GeomVertexArrayDataPipelineReader(const GeomVertexArrayData *object, - Thread *current_thread) : - GeomVertexArrayDataPipelineBase((GeomVertexArrayData *)object, - current_thread, - (GeomVertexArrayData::CData *)object->_cycler.read_unlocked(current_thread)) -{ -} - -//////////////////////////////////////////////////////////////////// -// Function: GeomVertexArrayDataPipelineReader::Copy Constructor -// Access: Private -// Description: Don't attempt to copy these objects. -//////////////////////////////////////////////////////////////////// -INLINE GeomVertexArrayDataPipelineReader:: -GeomVertexArrayDataPipelineReader(const GeomVertexArrayDataPipelineReader ©) : - GeomVertexArrayDataPipelineBase(copy) -{ - nassertv(false); -} - -//////////////////////////////////////////////////////////////////// -// Function: GeomVertexArrayDataPipelineReader::Copy Assignment Operator -// Access: Private -// Description: Don't attempt to copy these objects. -//////////////////////////////////////////////////////////////////// -INLINE void GeomVertexArrayDataPipelineReader:: -operator = (const GeomVertexArrayDataPipelineReader &) { - nassertv(false); -} - -//////////////////////////////////////////////////////////////////// -// Function: GeomVertexArrayDataPipelineReader::Destructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE GeomVertexArrayDataPipelineReader:: -~GeomVertexArrayDataPipelineReader() { - // _object->_cycler.release_read(_cdata); -} - -//////////////////////////////////////////////////////////////////// -// Function: GeomVertexArrayDataPipelineReader::get_object -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE const GeomVertexArrayData *GeomVertexArrayDataPipelineReader:: -get_object() const { - return _object; -} - -//////////////////////////////////////////////////////////////////// -// Function: GeomVertexArrayDataPipelineWriter::Constructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE GeomVertexArrayDataPipelineWriter:: -GeomVertexArrayDataPipelineWriter(GeomVertexArrayData *object, bool force_to_0, - Thread *current_thread) : - GeomVertexArrayDataPipelineBase(object, current_thread, - object->_cycler.write_upstream(force_to_0, current_thread)) -{ -} - -//////////////////////////////////////////////////////////////////// -// Function: GeomVertexArrayDataPipelineWriter::Copy Constructor -// Access: Private -// Description: Don't attempt to copy these objects. -//////////////////////////////////////////////////////////////////// -INLINE GeomVertexArrayDataPipelineWriter:: -GeomVertexArrayDataPipelineWriter(const GeomVertexArrayDataPipelineWriter ©) : - GeomVertexArrayDataPipelineBase(copy) -{ - nassertv(false); -} - -//////////////////////////////////////////////////////////////////// -// Function: GeomVertexArrayDataPipelineWriter::Copy Assignment Operator -// Access: Private -// Description: Don't attempt to copy these objects. -//////////////////////////////////////////////////////////////////// -INLINE void GeomVertexArrayDataPipelineWriter:: -operator = (const GeomVertexArrayDataPipelineWriter &) { - nassertv(false); -} - -//////////////////////////////////////////////////////////////////// -// Function: GeomVertexArrayDataPipelineWriter::Destructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE GeomVertexArrayDataPipelineWriter:: -~GeomVertexArrayDataPipelineWriter() { - _object->_cycler.release_write(_cdata); -} - -//////////////////////////////////////////////////////////////////// -// Function: GeomVertexArrayDataPipelineWriter::get_object -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE GeomVertexArrayData *GeomVertexArrayDataPipelineWriter:: -get_object() const { - return _object; +void GeomVertexArrayDataHandle:: +check_resident() const { + if (_object->get_ram_class() != RC_resident) { + _object->make_resident(); + } else { + _object->mark_used_lru(); + } + nassertv(_cdata->_data.size() == _cdata->_data_full_size); } INLINE ostream & diff --git a/panda/src/gobj/geomVertexArrayData.cxx b/panda/src/gobj/geomVertexArrayData.cxx index 6382b590c1..4f997c633b 100644 --- a/panda/src/gobj/geomVertexArrayData.cxx +++ b/panda/src/gobj/geomVertexArrayData.cxx @@ -23,11 +23,55 @@ #include "bamReader.h" #include "bamWriter.h" #include "pset.h" +#include "config_gobj.h" +#include "pStatTimer.h" + +#ifdef HAVE_ZLIB +#include +#endif + +ConfigVariableInt max_ram_vertex_data +("max-ram-vertex-data", 0, + PRC_DESC("Specifies the maximum number of bytes of all vertex data " + "that is allowed to remain resident in system RAM at one time. " + "If more than this number of bytes of vertices are created, " + "the least-recently-used ones will be temporarily compressed in " + "system RAM until they are needed. Set it to 0 for no limit.")); + +ConfigVariableInt max_compressed_vertex_data +("max-compressed-vertex-data", 0, + PRC_DESC("Specifies the maximum number of bytes of all vertex data " + "that is allowed to remain compressed in system RAM at one time. " + "If more than this number of bytes of vertices are created, " + "the least-recently-used ones will be temporarily flushed to " + "disk until they are needed. Set it to 0 for no limit.")); + +// We make this a static constant rather than a dynamic variable, +// since we can't tolerate this value changing at runtime. +static const size_t min_vertex_data_compress_size = + ConfigVariableInt + ("min-vertex-data-compress-size", 64, + PRC_DESC("This is the minimum number of bytes that we deem worthy of " + "passing through zlib to compress, when a vertex buffer is " + "evicted from resident state and compressed for long-term " + "storage. Buffers smaller than this are assumed to be likely to " + "have minimal compression gains (or even end up larger).")); + + + +SimpleLru GeomVertexArrayData::_global_lru[RC_end_of_list] = { + SimpleLru(max_ram_vertex_data), + SimpleLru(max_compressed_vertex_data), + SimpleLru(0) +}; + +PStatCollector GeomVertexArrayData::_vdata_compress_pcollector("*:Vertex Data:Compress"); +PStatCollector GeomVertexArrayData::_vdata_decompress_pcollector("*:Vertex Data:Decompress"); + TypeHandle GeomVertexArrayData::_type_handle; TypeHandle GeomVertexArrayData::CData::_type_handle; -TypeHandle GeomVertexArrayDataPipelineReader::_type_handle; -TypeHandle GeomVertexArrayDataPipelineWriter::_type_handle; +TypeHandle GeomVertexArrayDataHandle::_type_handle; //////////////////////////////////////////////////////////////////// // Function: GeomVertexArrayData::Default Constructor @@ -36,8 +80,11 @@ TypeHandle GeomVertexArrayDataPipelineWriter::_type_handle; // reading from the bam file. //////////////////////////////////////////////////////////////////// GeomVertexArrayData:: -GeomVertexArrayData() { +GeomVertexArrayData() : SimpleLruPage(0) { _endian_reversed = false; + _ram_class = RC_resident; + + // Can't put it in the LRU until it has been read in and made valid. } //////////////////////////////////////////////////////////////////// @@ -47,6 +94,7 @@ GeomVertexArrayData() { //////////////////////////////////////////////////////////////////// PT(CopyOnWriteObject) GeomVertexArrayData:: make_cow_copy() { + make_resident(); return new GeomVertexArrayData(*this); } @@ -58,6 +106,7 @@ make_cow_copy() { GeomVertexArrayData:: GeomVertexArrayData(const GeomVertexArrayFormat *array_format, GeomVertexArrayData::UsageHint usage_hint) : + SimpleLruPage(0), _array_format(array_format) { OPEN_ITERATE_ALL_STAGES(_cycler) { @@ -67,6 +116,10 @@ GeomVertexArrayData(const GeomVertexArrayFormat *array_format, CLOSE_ITERATE_ALL_STAGES(_cycler); _endian_reversed = false; + + _ram_class = RC_resident; + mark_used_lru(&_global_lru[RC_resident]); + nassertv(_array_format->is_registered()); } @@ -78,10 +131,15 @@ GeomVertexArrayData(const GeomVertexArrayFormat *array_format, GeomVertexArrayData:: GeomVertexArrayData(const GeomVertexArrayData ©) : CopyOnWriteObject(copy), + SimpleLruPage(copy), _array_format(copy._array_format), _cycler(copy._cycler) { _endian_reversed = false; + + _ram_class = copy._ram_class; + mark_used_lru(&_global_lru[_ram_class]); + nassertv(_array_format->is_registered()); } @@ -96,6 +154,7 @@ GeomVertexArrayData(const GeomVertexArrayData ©) : void GeomVertexArrayData:: operator = (const GeomVertexArrayData ©) { CopyOnWriteObject::operator = (copy); + SimpleLruPage::operator = (copy); _array_format = copy._array_format; _cycler = copy._cycler; @@ -272,6 +331,155 @@ release_all() { return num_freed; } +//////////////////////////////////////////////////////////////////// +// Function: GeomVertexArrayData::lru_epoch +// Access: Published, Static +// Description: Marks that an epoch has passed in each LRU. Asks the +// LRU's to consider whether they should perform +// evictions. +//////////////////////////////////////////////////////////////////// +void GeomVertexArrayData:: +lru_epoch() { + for (int i = 0; i < (int)RC_end_of_list; ++i) { + get_global_lru((RamClass)i)->consider_evict(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: GeomVertexArrayData::make_resident +// Access: Published +// Description: Moves the vertex data to fully resident status by +// expanding it or reading it from disk as necessary. +//////////////////////////////////////////////////////////////////// +void GeomVertexArrayData:: +make_resident() { + // TODO: make this work with pipelining properly. + if (_ram_class == RC_compressed) { + CDWriter cdata(_cycler, true); +#ifdef HAVE_ZLIB + if (cdata->_data_full_size > min_vertex_data_compress_size) { + PStatTimer timer(_vdata_decompress_pcollector); + + if (gobj_cat.is_debug()) { + gobj_cat.debug() + << "Expanding " << *this << " from " << cdata->_data.size() + << " to " << cdata->_data_full_size << "\n"; + } + PTA_uchar new_data = PTA_uchar::empty_array(cdata->_data_full_size, get_class_type()); + uLongf dest_len = cdata->_data_full_size; + int result = uncompress(new_data.p(), &dest_len, + cdata->_data.p(), cdata->_data.size()); + if (result != Z_OK) { + gobj_cat.error() + << "Couldn't expand: zlib error " << result << "\n"; + } + nassertv(dest_len == new_data.size()); + cdata->_data = new_data; + } +#endif + set_lru_size(cdata->_data.size()); + } + + set_ram_class(RC_resident); +} + +//////////////////////////////////////////////////////////////////// +// Function: GeomVertexArrayData::make_compressed +// Access: Published +// Description: Moves the vertex data to compressed status by +// compressing it or reading it from disk as necessary. +//////////////////////////////////////////////////////////////////// +void GeomVertexArrayData:: +make_compressed() { + // TODO: make this work with pipelining properly. + if (_ram_class == RC_resident) { + + CDWriter cdata(_cycler, true); +#ifdef HAVE_ZLIB + if (cdata->_data_full_size > min_vertex_data_compress_size) { + PStatTimer timer(_vdata_compress_pcollector); + + // According to the zlib manual, we need to provide this much + // buffer to the compress algorithm: 0.1% bigger plus twelve + // bytes. + uLongf buffer_size = cdata->_data_full_size + ((cdata->_data_full_size + 999) / 1000) + 12; + Bytef *buffer = new Bytef[buffer_size]; + + int result = compress(buffer, &buffer_size, + cdata->_data.p(), cdata->_data_full_size); + if (result != Z_OK) { + gobj_cat.error() + << "Couldn't compress: zlib error " << result << "\n"; + } + + PTA_uchar new_data = PTA_uchar::empty_array(buffer_size, get_class_type()); + memcpy(new_data.p(), buffer, buffer_size); + delete[] buffer; + + cdata->_data = new_data; + if (gobj_cat.is_debug()) { + gobj_cat.debug() + << "Compressed " << *this << " from " << cdata->_data_full_size + << " to " << cdata->_data.size() << "\n"; + } + } +#endif + set_ram_class(RC_compressed); + set_lru_size(cdata->_data.size()); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: GeomVertexArrayData::make_disk +// Access: Published +// Description: Moves the vertex data to disk status by +// writing it to disk as necessary. +//////////////////////////////////////////////////////////////////// +void GeomVertexArrayData:: +make_disk() { + // TODO: make this work with pipelining properly. + if (_ram_class == RC_compressed) { + } +} + +//////////////////////////////////////////////////////////////////// +// Function: GeomVertexArrayData::evict_lru +// Access: Public, Virtual +// Description: Evicts the page from the LRU. Called internally when +// the LRU determines that it is full. May also be +// called externally when necessary to explicitly evict +// the page. +// +// It is legal for this method to either evict the page +// as requested, do nothing (in which case the eviction +// will be requested again at the next epoch), or +// requeue itself on the tail of the queue (in which +// case the eviction will be requested again much +// later). +//////////////////////////////////////////////////////////////////// +void GeomVertexArrayData:: +evict_lru() { + nassertv(get_lru() == get_global_lru(_ram_class)); + + switch (_ram_class) { + case RC_resident: + make_compressed(); + break; + + case RC_compressed: + make_disk(); + break; + + case RC_disk: + gobj_cat.warning() + << "Cannot evict array data from disk.\n"; + break; + + case RC_end_of_list: + break; + } +} + //////////////////////////////////////////////////////////////////// // Function: GeomVertexArrayData::clear_prepared // Access: Private @@ -359,6 +567,7 @@ register_with_read_factory() { //////////////////////////////////////////////////////////////////// void GeomVertexArrayData:: write_datagram(BamWriter *manager, Datagram &dg) { + make_resident(); CopyOnWriteObject::write_datagram(manager, dg); manager->write_pointer(dg, _array_format); @@ -465,6 +674,8 @@ finalize(BamReader *manager) { // Now is also the time to node_ref the data. cdata->_data.node_ref(); + + set_ram_class(RC_resident); } //////////////////////////////////////////////////////////////////// @@ -510,7 +721,6 @@ fillin(DatagramIterator &scan, BamReader *manager) { //////////////////////////////////////////////////////////////////// GeomVertexArrayData::CData:: ~CData() { - _data.node_unref(); } //////////////////////////////////////////////////////////////////// @@ -548,47 +758,41 @@ fillin(DatagramIterator &scan, BamReader *manager, void *extra_data) { GeomVertexArrayData *array_data = (GeomVertexArrayData *)extra_data; _usage_hint = (UsageHint)scan.get_uint8(); READ_PTA(manager, scan, array_data->read_raw_data, _data); + _data_full_size = _data.size(); + array_data->set_lru_size(_data_full_size); _modified = Geom::get_next_modified(); } //////////////////////////////////////////////////////////////////// -// Function: GeomVertexArrayDataPipelineWriter::set_num_rows +// Function: GeomVertexArrayDataHandle::set_num_rows // Access: Public // Description: //////////////////////////////////////////////////////////////////// -bool GeomVertexArrayDataPipelineWriter:: +bool GeomVertexArrayDataHandle:: set_num_rows(int n) { + nassertr(_writable, false); + check_resident(); + int stride = _object->_array_format->get_stride(); int delta = n - (_cdata->_data.size() / stride); if (delta != 0) { - if (_cdata->_data.get_node_ref_count() > 1) { - // Copy-on-write: the data is already reffed somewhere else, - // so we're just going to make a copy. - PTA_uchar new_data(GeomVertexArrayData::get_class_type()); - new_data.reserve(n * stride); - new_data.insert(new_data.end(), n * stride, 0); - memcpy(new_data, _cdata->_data, - min((size_t)(n * stride), _cdata->_data.size())); - _cdata->_data.node_unref(); - _cdata->_data = new_data; - _cdata->_data.node_ref(); + if (delta > 0) { + _cdata->_data.insert(_cdata->_data.end(), delta * stride, 0); } else { - // We've got the only reference to the data, so we can change - // it directly. - if (delta > 0) { - _cdata->_data.insert(_cdata->_data.end(), delta * stride, 0); - - } else { - _cdata->_data.erase(_cdata->_data.begin() + n * stride, - _cdata->_data.end()); - } + _cdata->_data.erase(_cdata->_data.begin() + n * stride, + _cdata->_data.end()); } _cdata->_modified = Geom::get_next_modified(); + _cdata->_data_full_size = _cdata->_data.size(); + if (get_current_thread()->get_pipeline_stage() == 0) { + _object->set_ram_class(RC_resident); + _object->set_lru_size(_cdata->_data_full_size); + } return true; } @@ -596,24 +800,30 @@ set_num_rows(int n) { } //////////////////////////////////////////////////////////////////// -// Function: GeomVertexArrayDataPipelineWriter::unclean_set_num_rows +// Function: GeomVertexArrayDataHandle::unclean_set_num_rows // Access: Public // Description: //////////////////////////////////////////////////////////////////// -bool GeomVertexArrayDataPipelineWriter:: +bool GeomVertexArrayDataHandle:: unclean_set_num_rows(int n) { + nassertr(_writable, false); + check_resident(); + int stride = _object->_array_format->get_stride(); int delta = n - (_cdata->_data.size() / stride); if (delta != 0) { // Just make a new array. No reason to keep the old one around. - PTA_uchar new_data = PTA_uchar::empty_array(n * stride, GeomVertexArrayData::get_class_type()); + //_cdata->_data = GeomVertexArrayData::Data('\0', n * stride, GeomVertexArrayData::get_class_type()); + _cdata->_data = PTA_uchar::empty_array(n * stride, GeomVertexArrayData::get_class_type()); - _cdata->_data.node_unref(); - _cdata->_data = new_data; - _cdata->_data.node_ref(); _cdata->_modified = Geom::get_next_modified(); + _cdata->_data_full_size = _cdata->_data.size(); + if (get_current_thread()->get_pipeline_stage() == 0) { + _object->set_ram_class(RC_resident); + _object->set_lru_size(_cdata->_data_full_size); + } return true; } @@ -621,37 +831,66 @@ unclean_set_num_rows(int n) { } //////////////////////////////////////////////////////////////////// -// Function: GeomVertexArrayDataPipelineWriter::modify_data -// Access: Published -// Description: +// Function: GeomVertexArrayDataHandle::copy_data_from +// Access: Public +// Description: Copies the entire data array from the other object. //////////////////////////////////////////////////////////////////// -PTA_uchar GeomVertexArrayDataPipelineWriter:: -modify_data() { - // Perform copy-on-write: if the *node* reference count on the - // vertex data is greater than 1, assume some other - // GeomVertexArrayData has the same pointer, so make a copy of it - // first. - if (_cdata->_data.get_node_ref_count() > 1) { - PTA_uchar orig_data = _cdata->_data; - _cdata->_data.node_unref(); - _cdata->_data = PTA_uchar(GeomVertexArrayData::get_class_type()); - _cdata->_data.v() = orig_data.v(); - _cdata->_data.node_ref(); +void GeomVertexArrayDataHandle:: +copy_data_from(const GeomVertexArrayDataHandle *other) { + nassertv(_writable); + check_resident(); + other->check_resident(); + + _cdata->_data.v() = other->_cdata->_data.v(); + _cdata->_modified = Geom::get_next_modified(); + _cdata->_data_full_size = _cdata->_data.size(); + + if (get_current_thread()->get_pipeline_stage() == 0) { + _object->set_ram_class(RC_resident); + _object->set_lru_size(_cdata->_data_full_size); } - _cdata->_modified = Geom::get_next_modified(); - - return _cdata->_data; } //////////////////////////////////////////////////////////////////// -// Function: GeomVertexArrayDataPipelineWriter::set_data -// Access: Published -// Description: +// Function: GeomVertexArrayDataHandle::copy_subdata_from +// Access: Public +// Description: Copies a portion of the data array from the other +// object into a portion of the data array of this +// object. If to_size != from_size, the size of this +// data array is adjusted accordingly. //////////////////////////////////////////////////////////////////// -void GeomVertexArrayDataPipelineWriter:: -set_data(CPTA_uchar array) { - _cdata->_data.node_unref(); - _cdata->_data = (PTA_uchar &)array; - _cdata->_data.node_ref(); +void GeomVertexArrayDataHandle:: +copy_subdata_from(size_t to_start, size_t to_size, + const GeomVertexArrayDataHandle *other, + size_t from_start, size_t from_size) { + nassertv(_writable); + check_resident(); + other->check_resident(); + + pvector &to_v = _cdata->_data.v(); + to_start = min(to_start, to_v.size()); + to_size = min(to_size, to_v.size() - to_start); + + from_start = min(from_start, other->_cdata->_data.size()); + from_size = min(from_size, other->_cdata->_data.size() - from_start); + + if (from_size < to_size) { + // Reduce the array. + to_v.erase(to_v.begin() + to_start + from_size, to_v.begin() + to_start + to_size); + + } else if (to_size < from_size) { + // Expand the array. + to_v.insert(to_v.begin() + to_start + to_size, from_size - to_size, char()); + } + + // Now copy the data. + memcpy(&to_v[0] + to_start, other->get_pointer() + from_start, from_size); _cdata->_modified = Geom::get_next_modified(); + _cdata->_data_full_size = _cdata->_data.size(); + + if (get_current_thread()->get_pipeline_stage() == 0) { + _object->set_ram_class(RC_resident); + _object->set_lru_size(_cdata->_data_full_size); + } } + diff --git a/panda/src/gobj/geomVertexArrayData.h b/panda/src/gobj/geomVertexArrayData.h index eda54c9957..23bc6a0973 100644 --- a/panda/src/gobj/geomVertexArrayData.h +++ b/panda/src/gobj/geomVertexArrayData.h @@ -33,11 +33,15 @@ #include "pipelineCycler.h" #include "pStatCollector.h" #include "pmap.h" +#include "reMutex.h" +#include "simpleLru.h" class PreparedGraphicsObjects; class VertexBufferContext; class GraphicsStateGuardianBase; +class GeomVertexArrayDataHandle; + //////////////////////////////////////////////////////////////////// // Class : GeomVertexArrayData // Description : This is the data for one array of a GeomVertexData @@ -57,7 +61,7 @@ class GraphicsStateGuardianBase; // GeomVertexReader/Writer/Rewriter for high-level tools // to manipulate the actual vertex data. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA GeomVertexArrayData : public CopyOnWriteObject, public GeomEnums { +class EXPCL_PANDA GeomVertexArrayData : public CopyOnWriteObject, public SimpleLruPage, public GeomEnums { private: GeomVertexArrayData(); @@ -90,9 +94,8 @@ PUBLISHED: void output(ostream &out) const; void write(ostream &out, int indent_level = 0) const; - INLINE CPTA_uchar get_data() const; - INLINE PTA_uchar modify_data(); - INLINE void set_data(CPTA_uchar data); + INLINE CPT(GeomVertexArrayDataHandle) get_handle(Thread *current_thread = Thread::get_current_thread()) const; + INLINE PT(GeomVertexArrayDataHandle) modify_handle(Thread *current_thread = Thread::get_current_thread()); void prepare(PreparedGraphicsObjects *prepared_objects); bool is_prepared(PreparedGraphicsObjects *prepared_objects) const; @@ -102,10 +105,25 @@ PUBLISHED: bool release(PreparedGraphicsObjects *prepared_objects); int release_all(); + INLINE RamClass get_ram_class() const; + + INLINE static SimpleLru *get_global_lru(RamClass rclass); + static void lru_epoch(); + + void make_resident(); + void make_compressed(); + void make_disk(); + +public: + virtual void evict_lru(); + private: void clear_prepared(PreparedGraphicsObjects *prepared_objects); PTA_uchar reverse_data_endianness(const PTA_uchar &data); + INLINE void set_ram_class(RamClass rclass); + + CPT(GeomVertexArrayFormat) _array_format; // A GeomVertexArrayData keeps a list (actually, a map) of all the @@ -120,11 +138,17 @@ private: // to indicate the data must be endian-reversed in finalize(). bool _endian_reversed; + RamClass _ram_class; + + typedef pvector Data; + // This is the data that must be cycled between pipeline stages. class EXPCL_PANDA CData : public CycleData { public: INLINE CData(); INLINE CData(const CData ©); + INLINE void operator = (const CData ©); + virtual ~CData(); ALLOC_DELETED_CHAIN(CData); virtual CycleData *make_copy() const; @@ -138,7 +162,12 @@ private: UsageHint _usage_hint; PTA_uchar _data; + size_t _data_full_size; UpdateSeq _modified; + + // This implements read-write locking. Anyone who gets the data for + // reading or writing will hold this mutex during the lock. + ReMutex _rw_lock; public: static TypeHandle get_class_type() { @@ -160,6 +189,11 @@ private: typedef CycleDataStageReader CDStageReader; typedef CycleDataStageWriter CDStageWriter; + static SimpleLru _global_lru[RC_end_of_list]; + + static PStatCollector _vdata_compress_pcollector; + static PStatCollector _vdata_decompress_pcollector; + public: static void register_with_read_factory(); virtual void write_datagram(BamWriter *manager, Datagram &dg); @@ -194,104 +228,92 @@ private: friend class GeomCacheManager; friend class GeomVertexData; friend class PreparedGraphicsObjects; - friend class GeomVertexArrayDataPipelineBase; - friend class GeomVertexArrayDataPipelineReader; - friend class GeomVertexArrayDataPipelineWriter; + friend class GeomVertexArrayDataHandle; }; //////////////////////////////////////////////////////////////////// -// Class : GeomVertexArrayDataPipelineBase -// Description : The common code from +// Class : GeomVertexArrayDataHandle +// Description : This data object is returned by +// GeomVertexArrayData::get_handle() or modify_handle(). +// As long as it exists, the data is locked; when the +// last of these destructs, the data is unlocked. +// +// Only one thread at a time may lock the data; other +// threads attempting to lock the data will block. A +// given thread may simultaneously lock the data +// multiple times. +// +// This class serves in lieu of a pair of // GeomVertexArrayDataPipelineReader and -// GeomVertexArrayDataPipelineWriter. +// GeomVertexArrayDataPipelineWriter classes //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA GeomVertexArrayDataPipelineBase : public GeomEnums { -protected: - INLINE GeomVertexArrayDataPipelineBase(GeomVertexArrayData *object, - Thread *current_thread, - GeomVertexArrayData::CData *cdata); +class EXPCL_PANDA GeomVertexArrayDataHandle : public ReferenceCount, public GeomEnums { +private: + INLINE GeomVertexArrayDataHandle(const GeomVertexArrayData *object, + Thread *current_thread, + const GeomVertexArrayData::CData *_cdata, + bool writable); + INLINE GeomVertexArrayDataHandle(const GeomVertexArrayDataHandle &); + INLINE void operator = (const GeomVertexArrayDataHandle &); + +PUBLISHED: + INLINE ~GeomVertexArrayDataHandle(); + public: - INLINE ~GeomVertexArrayDataPipelineBase(); + ALLOC_DELETED_CHAIN(GeomVertexArrayDataHandle); INLINE Thread *get_current_thread() const; + INLINE const GeomVertexArrayData *get_object() const; + INLINE GeomVertexArrayData *get_object(); + INLINE const unsigned char *get_pointer() const; + INLINE unsigned char *get_pointer(); + +PUBLISHED: INLINE const GeomVertexArrayFormat *get_array_format() const; - INLINE UsageHint get_usage_hint() const; - INLINE CPTA_uchar get_data() const; + INLINE int get_num_rows() const; + bool set_num_rows(int n); + bool unclean_set_num_rows(int n); + INLINE void clear_rows(); + INLINE int get_data_size_bytes() const; INLINE UpdateSeq get_modified() const; -protected: + void copy_data_from(const GeomVertexArrayDataHandle *other); + void copy_subdata_from(size_t to_start, size_t to_size, + const GeomVertexArrayDataHandle *other, + size_t from_start, size_t from_size); + + /* + INLINE string get_data() const; + void set_data(const string &data); + INLINE string get_subdata(size_t start, size_t size) const; + void set_subdata(size_t start, size_t size, const string &data); + */ + + INLINE void check_resident() const; + +private: + ReMutexHolder _holder; PT(GeomVertexArrayData) _object; Thread *_current_thread; GeomVertexArrayData::CData *_cdata; -}; - -//////////////////////////////////////////////////////////////////// -// Class : GeomVertexArrayDataPipelineReader -// Description : Encapsulates the data from a GeomVertexArrayData, -// pre-fetched for one stage of the pipeline. -//////////////////////////////////////////////////////////////////// -class EXPCL_PANDA GeomVertexArrayDataPipelineReader : public GeomVertexArrayDataPipelineBase { -public: - INLINE GeomVertexArrayDataPipelineReader(const GeomVertexArrayData *object, Thread *current_thread); -private: - INLINE GeomVertexArrayDataPipelineReader(const GeomVertexArrayDataPipelineReader ©); - INLINE void operator = (const GeomVertexArrayDataPipelineReader ©); - -public: - INLINE ~GeomVertexArrayDataPipelineReader(); - ALLOC_DELETED_CHAIN(GeomVertexArrayDataPipelineReader); - - INLINE const GeomVertexArrayData *get_object() const; + bool _writable; public: static TypeHandle get_class_type() { return _type_handle; } static void init_type() { - register_type(_type_handle, "GeomVertexArrayDataPipelineReader"); + register_type(_type_handle, "GeomVertexArrayDataHandle"); } private: static TypeHandle _type_handle; -}; -//////////////////////////////////////////////////////////////////// -// Class : GeomVertexArrayDataPipelineWriter -// Description : Encapsulates the data from a GeomVertexArrayData, -// pre-fetched for one stage of the pipeline. -//////////////////////////////////////////////////////////////////// -class EXPCL_PANDA GeomVertexArrayDataPipelineWriter : public GeomVertexArrayDataPipelineBase { -public: - INLINE GeomVertexArrayDataPipelineWriter(GeomVertexArrayData *object, bool force_to_0, Thread *current_thread); -private: - INLINE GeomVertexArrayDataPipelineWriter(const GeomVertexArrayDataPipelineWriter ©); - INLINE void operator = (const GeomVertexArrayDataPipelineWriter ©); - -public: - INLINE ~GeomVertexArrayDataPipelineWriter(); - ALLOC_DELETED_CHAIN(GeomVertexArrayDataPipelineWriter); - - bool set_num_rows(int n); - bool unclean_set_num_rows(int n); - - INLINE GeomVertexArrayData *get_object() const; - PTA_uchar modify_data(); - void set_data(CPTA_uchar data); - -public: - static TypeHandle get_class_type() { - return _type_handle; - } - static void init_type() { - register_type(_type_handle, "GeomVertexArrayDataPipelineWriter"); - } - -private: - static TypeHandle _type_handle; + friend class GeomVertexArrayData; }; INLINE ostream &operator << (ostream &out, const GeomVertexArrayData &obj); diff --git a/panda/src/gobj/geomVertexData.I b/panda/src/gobj/geomVertexData.I index d6044e6542..7483aff7d2 100644 --- a/panda/src/gobj/geomVertexData.I +++ b/panda/src/gobj/geomVertexData.I @@ -711,7 +711,7 @@ check_array_readers() const { // Access: Public // Description: //////////////////////////////////////////////////////////////////// -INLINE const GeomVertexArrayDataPipelineReader *GeomVertexDataPipelineReader:: +INLINE const GeomVertexArrayDataHandle *GeomVertexDataPipelineReader:: get_array_reader(int i) const { nassertr(_got_array_readers, NULL); nassertr(i >= 0 && i < (int)_array_readers.size(), NULL); @@ -846,7 +846,7 @@ check_array_writers() const { // Access: Public // Description: //////////////////////////////////////////////////////////////////// -INLINE GeomVertexArrayDataPipelineWriter *GeomVertexDataPipelineWriter:: +INLINE GeomVertexArrayDataHandle *GeomVertexDataPipelineWriter:: get_array_writer(int i) const { nassertr(_got_array_writers, NULL); nassertr(i >= 0 && i < (int)_array_writers.size(), NULL); diff --git a/panda/src/gobj/geomVertexData.cxx b/panda/src/gobj/geomVertexData.cxx index 0d0b798f9d..b3a0e286f8 100644 --- a/panda/src/gobj/geomVertexData.cxx +++ b/panda/src/gobj/geomVertexData.cxx @@ -426,10 +426,10 @@ set_slider_table(const SliderTable *table) { // more of the arrays can be copied without the need to // apply any conversion operation. If it is true, the // original GeomVertexArrayData objects in this object -// are retained, but their data arrays are copied -// pointerwise from the source; if it is false, then the -// GeomVertexArrayData objects themselves are copied -// pointerwise from the source. +// are retained, and their data arrays are copied +// byte-by-byte from the source; if it is false, then the +// GeomVertexArrayData objects are copied pointerwise +// from the source. // // Don't call this in a downstream thread unless you // don't mind it blowing away other changes you might @@ -465,13 +465,10 @@ copy_from(const GeomVertexData *source, bool keep_data_objects, // Great! Just use the same data for this one. if (keep_data_objects) { // Copy the data, but keep the same GeomVertexArrayData object. - - // Maybe it even has the same data pointer already. If so, - // avoid flipping the modified flag. - CPTA_uchar source_data = source->get_array(source_i)->get_data(); - if (get_array(dest_i)->get_data() != source_data) { - modify_array(dest_i)->set_data(source_data); - } + + PT(GeomVertexArrayData) dest_data = modify_array(dest_i); + CPT(GeomVertexArrayData) source_data = source->get_array(source_i); + dest_data->modify_handle()->copy_data_from(source_data->get_handle()); } else { // Copy the GeomVertexArrayData object. if (get_array(dest_i) != source->get_array(source_i)) { @@ -491,7 +488,8 @@ copy_from(const GeomVertexData *source, bool keep_data_objects, // Now go back through and copy any data that's left over. for (source_i = 0; source_i < num_arrays; ++source_i) { CPT(GeomVertexArrayData) array_obj = source->get_array(source_i); - CPTA_uchar array_data = array_obj->get_data(); + CPT(GeomVertexArrayDataHandle) array_handle = array_obj->get_handle(); + const unsigned char *array_data = array_handle->get_pointer(); const GeomVertexArrayFormat *source_array_format = source_format->get_array(source_i); int num_columns = source_array_format->get_num_columns(); for (int di = 0; di < num_columns; ++di) { @@ -509,7 +507,8 @@ copy_from(const GeomVertexData *source, bool keep_data_objects, if (dest_column->is_bytewise_equivalent(*source_column)) { // We can do a quick bytewise copy. PT(GeomVertexArrayData) dest_array_obj = modify_array(dest_i); - PTA_uchar dest_array_data = dest_array_obj->modify_data(); + PT(GeomVertexArrayDataHandle) dest_handle = dest_array_obj->modify_handle(); + unsigned char *dest_array_data = dest_handle->get_pointer(); bytewise_copy(dest_array_data + dest_column->get_start(), dest_array_format->get_stride(), @@ -520,7 +519,8 @@ copy_from(const GeomVertexData *source, bool keep_data_objects, source_column->is_uint8_rgba()) { // A common special case: OpenGL color to DirectX color. PT(GeomVertexArrayData) dest_array_obj = modify_array(dest_i); - PTA_uchar dest_array_data = dest_array_obj->modify_data(); + PT(GeomVertexArrayDataHandle) dest_handle = dest_array_obj->modify_handle(); + unsigned char *dest_array_data = dest_handle->get_pointer(); uint8_rgba_to_packed_argb (dest_array_data + dest_column->get_start(), @@ -533,7 +533,8 @@ copy_from(const GeomVertexData *source, bool keep_data_objects, // Another common special case: DirectX color to OpenGL // color. PT(GeomVertexArrayData) dest_array_obj = modify_array(dest_i); - PTA_uchar dest_array_data = dest_array_obj->modify_data(); + PT(GeomVertexArrayDataHandle) dest_handle = dest_array_obj->modify_handle(); + unsigned char *dest_array_data = dest_handle->get_pointer(); packed_argb_to_uint8_rgba (dest_array_data + dest_column->get_start(), @@ -654,10 +655,12 @@ copy_row_from(int dest_row, const GeomVertexData *source, for (int i = 0; i < num_arrays; ++i) { PT(GeomVertexArrayData) dest_array_obj = modify_array(i); - PTA_uchar dest_array_data = dest_array_obj->modify_data(); + PT(GeomVertexArrayDataHandle) dest_handle = dest_array_obj->modify_handle(); + unsigned char *dest_array_data = dest_handle->get_pointer(); CPT(GeomVertexArrayData) source_array_obj = source->get_array(i); - CPTA_uchar source_array_data = source_array_obj->get_data(); + CPT(GeomVertexArrayDataHandle) source_array_handle = source_array_obj->get_handle(); + const unsigned char *source_array_data = source_array_handle->get_pointer(); const GeomVertexArrayFormat *array_format = source_format->get_array(i); int stride = array_format->get_stride(); @@ -948,6 +951,7 @@ animate_vertices(Thread *current_thread) const { CDWriter cdataw(((GeomVertexData *)this)->_cycler, cdata, false); cdataw->_animated_vertices_modified = modified; ((GeomVertexData *)this)->update_animated_vertices(cdataw, current_thread); + return cdataw->_animated_vertices; } @@ -1270,7 +1274,7 @@ update_animated_vertices(GeomVertexData::CData *cdata, Thread *current_thread) { if (slider_value != 0.0f) { CPT(InternalName) base_name = orig_format->get_morph_base(mi); CPT(InternalName) delta_name = orig_format->get_morph_delta(mi); - + GeomVertexRewriter data(new_data, base_name); GeomVertexReader delta(this, delta_name); int num_subranges = rows.get_num_subranges(); @@ -1714,7 +1718,7 @@ get_num_rows() const { //////////////////////////////////////////////////////////////////// bool GeomVertexDataPipelineReader:: get_array_info(const InternalName *name, - const GeomVertexArrayDataPipelineReader *&array_reader, + const GeomVertexArrayDataHandle *&array_reader, int &num_values, GeomVertexDataPipelineReader::NumericType &numeric_type, int &start, int &stride) const { @@ -1738,7 +1742,7 @@ get_array_info(const InternalName *name, // Description: //////////////////////////////////////////////////////////////////// bool GeomVertexDataPipelineReader:: -get_vertex_info(const GeomVertexArrayDataPipelineReader *&array_reader, +get_vertex_info(const GeomVertexArrayDataHandle *&array_reader, int &num_values, GeomVertexDataPipelineReader::NumericType &numeric_type, int &start, int &stride) const { @@ -1763,7 +1767,7 @@ get_vertex_info(const GeomVertexArrayDataPipelineReader *&array_reader, // Description: //////////////////////////////////////////////////////////////////// bool GeomVertexDataPipelineReader:: -get_normal_info(const GeomVertexArrayDataPipelineReader *&array_reader, +get_normal_info(const GeomVertexArrayDataHandle *&array_reader, GeomVertexDataPipelineReader::NumericType &numeric_type, int &start, int &stride) const { nassertr(_got_array_readers, false); @@ -1787,7 +1791,7 @@ get_normal_info(const GeomVertexArrayDataPipelineReader *&array_reader, // Description: //////////////////////////////////////////////////////////////////// bool GeomVertexDataPipelineReader:: -get_color_info(const GeomVertexArrayDataPipelineReader *&array_reader, +get_color_info(const GeomVertexArrayDataHandle *&array_reader, int &num_values, GeomVertexDataPipelineReader::NumericType &numeric_type, int &start, int &stride) const { @@ -1818,7 +1822,8 @@ make_array_readers() { _array_readers.reserve(_cdata->_arrays.size()); GeomVertexData::Arrays::const_iterator ai; for (ai = _cdata->_arrays.begin(); ai != _cdata->_arrays.end(); ++ai) { - _array_readers.push_back(new GeomVertexArrayDataPipelineReader((*ai).get_read_pointer(), _current_thread)); + CPT(GeomVertexArrayData) array_obj = (*ai).get_read_pointer(); + _array_readers.push_back(array_obj->get_handle(_current_thread)); } _got_array_readers = true; @@ -1833,10 +1838,6 @@ void GeomVertexDataPipelineReader:: delete_array_readers() { nassertv(_got_array_readers); - ArrayReaders::iterator ri; - for (ri = _array_readers.begin(); ri != _array_readers.end(); ++ri) { - delete (*ri); - } _array_readers.clear(); _got_array_readers = false; } @@ -1888,15 +1889,15 @@ set_num_rows(int n) { } if (color_array >= 0 && orig_color_rows < n) { - // We have just added some rows, fill the "color" column with + // We have just added some rows; fill the "color" column with // (1, 1, 1, 1), for the programmer's convenience. - GeomVertexArrayDataPipelineWriter *array_writer = _array_writers[color_array]; + GeomVertexArrayDataHandle *array_writer = _array_writers[color_array]; const GeomVertexArrayFormat *array_format = array_writer->get_array_format(); const GeomVertexColumn *column = array_format->get_column(InternalName::get_color()); int stride = array_format->get_stride(); unsigned char *start = - array_writer->modify_data() + column->get_start(); + array_writer->get_pointer() + column->get_start(); unsigned char *stop = start + array_writer->get_data_size_bytes(); unsigned char *pointer = start + stride * orig_color_rows; int num_values = column->get_num_values(); @@ -1999,8 +2000,7 @@ set_array(int i, const GeomVertexArrayData *array) { _cdata->_animated_vertices_modified = UpdateSeq(); if (_got_array_writers) { - delete _array_writers[i]; - _array_writers[i] = new GeomVertexArrayDataPipelineWriter(_cdata->_arrays[i].get_write_pointer(), _force_to_0, _current_thread); + _array_writers[i] = _cdata->_arrays[i].get_write_pointer()->modify_handle(_current_thread); } } @@ -2017,7 +2017,7 @@ make_array_writers() { GeomVertexData::Arrays::iterator ai; for (ai = _cdata->_arrays.begin(); ai != _cdata->_arrays.end(); ++ai) { PT(GeomVertexArrayData) array_obj = (*ai).get_write_pointer(); - _array_writers.push_back(new GeomVertexArrayDataPipelineWriter(array_obj, _force_to_0, _current_thread)); + _array_writers.push_back(array_obj->modify_handle(_current_thread)); } _object->clear_cache_stage(); @@ -2036,10 +2036,6 @@ void GeomVertexDataPipelineWriter:: delete_array_writers() { nassertv(_got_array_writers); - ArrayWriters::iterator ri; - for (ri = _array_writers.begin(); ri != _array_writers.end(); ++ri) { - delete (*ri); - } _array_writers.clear(); _got_array_writers = false; } diff --git a/panda/src/gobj/geomVertexData.h b/panda/src/gobj/geomVertexData.h index c5006cbcff..5bf0a27bbe 100644 --- a/panda/src/gobj/geomVertexData.h +++ b/panda/src/gobj/geomVertexData.h @@ -409,27 +409,27 @@ public: INLINE const GeomVertexData *get_object() const; INLINE void check_array_readers() const; - INLINE const GeomVertexArrayDataPipelineReader *get_array_reader(int i) const; + INLINE const GeomVertexArrayDataHandle *get_array_reader(int i) const; int get_num_rows() const; bool get_array_info(const InternalName *name, - const GeomVertexArrayDataPipelineReader *&array_reader, + const GeomVertexArrayDataHandle *&array_reader, int &num_values, NumericType &numeric_type, int &start, int &stride) const; INLINE bool has_vertex() const; INLINE bool is_vertex_transformed() const; - bool get_vertex_info(const GeomVertexArrayDataPipelineReader *&array_reader, + bool get_vertex_info(const GeomVertexArrayDataHandle *&array_reader, int &num_values, NumericType &numeric_type, int &start, int &stride) const; INLINE bool has_normal() const; - bool get_normal_info(const GeomVertexArrayDataPipelineReader *&array_reader, + bool get_normal_info(const GeomVertexArrayDataHandle *&array_reader, NumericType &numeric_type, int &start, int &stride) const; INLINE bool has_color() const; - bool get_color_info(const GeomVertexArrayDataPipelineReader *&array_reader, + bool get_color_info(const GeomVertexArrayDataHandle *&array_reader, int &num_values, NumericType &numeric_type, int &start, int &stride) const; @@ -438,7 +438,7 @@ private: void delete_array_readers(); bool _got_array_readers; - typedef pvector ArrayReaders; + typedef pvector ArrayReaders; ArrayReaders _array_readers; public: @@ -473,7 +473,7 @@ public: INLINE GeomVertexData *get_object() const; INLINE void check_array_writers() const; - INLINE GeomVertexArrayDataPipelineWriter *get_array_writer(int i) const; + INLINE GeomVertexArrayDataHandle *get_array_writer(int i) const; PT(GeomVertexArrayData) modify_array(int i); void set_array(int i, const GeomVertexArrayData *array); @@ -488,7 +488,7 @@ private: bool _force_to_0; bool _got_array_writers; - typedef pvector ArrayWriters; + typedef pvector ArrayWriters; ArrayWriters _array_writers; public: diff --git a/panda/src/gobj/geomVertexFormat.cxx b/panda/src/gobj/geomVertexFormat.cxx index 44f2a84d12..fa0e2ef217 100644 --- a/panda/src/gobj/geomVertexFormat.cxx +++ b/panda/src/gobj/geomVertexFormat.cxx @@ -575,9 +575,10 @@ write_with_data(ostream &out, int indent_level, indent(out, indent_level) << data->get_num_rows() << " rows.\n"; for (size_t i = 0; i < _arrays.size(); i++) { - CPTA_uchar array_data = data->get_array(i)->get_data(); + CPT(GeomVertexArrayDataHandle) handle = data->get_array(i)->get_handle(); + const unsigned char *array_data = handle->get_pointer(); indent(out, indent_level) - << "Array " << i << " (" << (void *)array_data.p() << ", " + << "Array " << i << " (" << (void *)array_data << ", " << *_arrays[i] << "):\n"; _arrays[i]->write_with_data(out, indent_level + 2, data->get_array(i)); } diff --git a/panda/src/gobj/geomVertexReader.I b/panda/src/gobj/geomVertexReader.I index 3d5b15b31a..28cb1780a1 100644 --- a/panda/src/gobj/geomVertexReader.I +++ b/panda/src/gobj/geomVertexReader.I @@ -147,7 +147,7 @@ GeomVertexReader(const GeomVertexReader ©) : _current_thread(copy._current_thread), _packer(copy._packer), _stride(copy._stride), - _data(copy._data), + _handle(copy._handle), _pointer_begin(copy._pointer_begin), _pointer_end(copy._pointer_end), _pointer(copy._pointer), @@ -168,7 +168,7 @@ operator = (const GeomVertexReader ©) { _current_thread = copy._current_thread; _packer = copy._packer; _stride = copy._stride; - _data = copy._data; + _handle = copy._handle; _pointer_begin = copy._pointer_begin; _pointer_end = copy._pointer_end; _pointer = copy._pointer; @@ -242,9 +242,7 @@ set_column(int column) { &reader); } if (_array_data != (const GeomVertexArrayData *)NULL) { - GeomVertexArrayDataPipelineReader reader(_array_data, _current_thread); - return set_array_column(reader.get_array_format()->get_column(column), - &reader); + return set_array_column(_array_data->get_array_format()->get_column(column)); } return false; } @@ -291,9 +289,7 @@ set_column(const InternalName *name) { &reader); } if (_array_data != (const GeomVertexArrayData *)NULL) { - GeomVertexArrayDataPipelineReader reader(_array_data, _current_thread); - return set_array_column(reader.get_array_format()->get_column(name), - &reader); + return set_array_column(_array_data->get_array_format()->get_column(name)); } return false; @@ -511,10 +507,9 @@ get_packer() const { // and sets the internal pointer to the indicated row. //////////////////////////////////////////////////////////////////// INLINE void GeomVertexReader:: -set_pointer(int row, const GeomVertexArrayDataPipelineReader *array_reader) { - _data = array_reader->get_data(); - _pointer_begin = _data; - _pointer_end = _pointer_begin + array_reader->get_data_size_bytes(); +set_pointer(int row) { + _pointer_begin = _handle->get_pointer(); + _pointer_end = _pointer_begin + _handle->get_data_size_bytes(); quick_set_pointer(row); } @@ -529,21 +524,16 @@ INLINE void GeomVertexReader:: quick_set_pointer(int row) { nassertv(has_column()); -#if defined(_DEBUG) && !defined(HAVE_THREADS) - // Make sure we still have the same pointer as stored the array. We - // only perform this test in debug mode, because it is expensive, - // and only in single-threaded mode, because in threaded mode - // another thread might have reallocated the other pointer outside - // of our control anyway. - if (_vertex_data != (const GeomVertexData *)NULL) { - const GeomVertexArrayData *array_data = _vertex_data->get_array(_array); - nassertv(_pointer_begin == array_data->get_data()); - } else { - nassertv(_pointer_begin == _array_data->get_data()); - } +#if defined(_DEBUG) + // Make sure we still have the same pointer as stored in the array. + nassertv(_pointer_begin == _handle->get_pointer()); #endif _pointer = _pointer_begin + _packer->_column->get_start() + _stride * row; + +#if defined(_DEBUG) + nassertv(_pointer_begin == _pointer_end || _pointer < _pointer_end); +#endif } //////////////////////////////////////////////////////////////////// @@ -554,14 +544,11 @@ quick_set_pointer(int row) { //////////////////////////////////////////////////////////////////// INLINE const unsigned char *GeomVertexReader:: inc_pointer() { -#ifdef _DEBUG +#if defined(_DEBUG) nassertr(_pointer < _pointer_end, empty_buffer); - if (_vertex_data != (const GeomVertexData *)NULL){ - const GeomVertexArrayData *array_data = _vertex_data->get_array(_array); - nassertr(_pointer >= array_data->get_data().p() && _pointer < array_data->get_data().p() + array_data->get_data_size_bytes(), empty_buffer); - } else { - nassertr(_pointer >= _array_data->get_data().p() && _pointer < _array_data->get_data().p() + _array_data->get_data_size_bytes(), empty_buffer); - } + // Make sure we still have the same pointer as stored in the array. + nassertr(_pointer_begin == _handle->get_pointer(), empty_buffer); + nassertr(_pointer < _pointer_begin + _handle->get_data_size_bytes(), empty_buffer); #endif const unsigned char *orig_pointer = _pointer; diff --git a/panda/src/gobj/geomVertexReader.cxx b/panda/src/gobj/geomVertexReader.cxx index 1d37f9b042..dfb1f1c4b6 100644 --- a/panda/src/gobj/geomVertexReader.cxx +++ b/panda/src/gobj/geomVertexReader.cxx @@ -57,8 +57,7 @@ set_column(int array, const GeomVertexColumn *column) { return set_vertex_column(array, column, &reader); } if (_array_data != (const GeomVertexArrayData *)NULL) { - GeomVertexArrayDataPipelineReader reader(_array_data, _current_thread); - return set_array_column(column, &reader); + return set_array_column(column); } // No data is associated with the Reader. @@ -121,12 +120,11 @@ set_vertex_column(int array, const GeomVertexColumn *column, #endif _array = array; - const GeomVertexArrayDataPipelineReader *array_reader = - data_reader->get_array_reader(_array); - _stride = array_reader->get_array_format()->get_stride(); + _handle = data_reader->get_array_reader(_array); + _stride = _handle->get_array_format()->get_stride(); _packer = column->_packer; - set_pointer(_start_row, array_reader); + set_pointer(_start_row); return true; } @@ -139,18 +137,18 @@ set_vertex_column(int array, const GeomVertexColumn *column, // GeomVertexArrayData. //////////////////////////////////////////////////////////////////// bool GeomVertexReader:: -set_array_column(const GeomVertexColumn *column, - const GeomVertexArrayDataPipelineReader *array_reader) { +set_array_column(const GeomVertexColumn *column) { if (column == (const GeomVertexColumn *)NULL) { return set_column(0, NULL); } nassertr(_array_data != (const GeomVertexArrayData *)NULL, false); - _stride = array_reader->get_array_format()->get_stride(); + _handle = _array_data->get_handle(); + _stride = _handle->get_array_format()->get_stride(); _packer = column->_packer; - set_pointer(_start_row, array_reader); + set_pointer(_start_row); return true; } diff --git a/panda/src/gobj/geomVertexReader.h b/panda/src/gobj/geomVertexReader.h index ee07f0e289..d81d84cc1c 100644 --- a/panda/src/gobj/geomVertexReader.h +++ b/panda/src/gobj/geomVertexReader.h @@ -120,15 +120,13 @@ protected: private: void initialize(); - INLINE void set_pointer(int row, - const GeomVertexArrayDataPipelineReader *array_reader); + INLINE void set_pointer(int row); INLINE void quick_set_pointer(int row); INLINE const unsigned char *inc_pointer(); bool set_vertex_column(int array, const GeomVertexColumn *column, const GeomVertexDataPipelineReader *data_reader); - bool set_array_column(const GeomVertexColumn *column, - const GeomVertexArrayDataPipelineReader *array_reader); + bool set_array_column(const GeomVertexColumn *column); // It is important that we only store *one* of the following two // pointers. If we are storing a GeomVertexData/array index, we @@ -143,7 +141,7 @@ private: GeomVertexColumn::Packer *_packer; int _stride; - CPTA_uchar _data; + CPT(GeomVertexArrayDataHandle) _handle; const unsigned char *_pointer_begin; const unsigned char *_pointer_end; const unsigned char *_pointer; diff --git a/panda/src/gobj/geomVertexWriter.I b/panda/src/gobj/geomVertexWriter.I index 38428cbcef..c4b324e636 100644 --- a/panda/src/gobj/geomVertexWriter.I +++ b/panda/src/gobj/geomVertexWriter.I @@ -145,7 +145,7 @@ GeomVertexWriter(const GeomVertexWriter ©) : _current_thread(copy._current_thread), _packer(copy._packer), _stride(copy._stride), - _data(copy._data), + _handle(copy._handle), _pointer_begin(copy._pointer_begin), _pointer_end(copy._pointer_end), _pointer(copy._pointer), @@ -166,7 +166,7 @@ operator = (const GeomVertexWriter ©) { _current_thread = copy._current_thread; _packer = copy._packer; _stride = copy._stride; - _data = copy._data; + _handle = copy._handle; _pointer_begin = copy._pointer_begin; _pointer_end = copy._pointer_end; _pointer = copy._pointer; @@ -240,9 +240,7 @@ set_column(int column) { &writer); } if (_array_data != (GeomVertexArrayData *)NULL) { - GeomVertexArrayDataPipelineWriter writer(_array_data, true, _current_thread); - return set_array_column(writer.get_array_format()->get_column(column), - &writer); + return set_array_column(_array_data->get_array_format()->get_column(column)); } return false; } @@ -289,9 +287,7 @@ set_column(const InternalName *name) { &writer); } if (_array_data != (GeomVertexArrayData *)NULL) { - GeomVertexArrayDataPipelineWriter writer(_array_data, true, _current_thread); - return set_array_column(writer.get_array_format()->get_column(name), - &writer); + return set_array_column(_array_data->get_array_format()->get_column(name)); } return false; } @@ -814,10 +810,9 @@ get_packer() const { // and sets the internal pointer to the indicated row. //////////////////////////////////////////////////////////////////// INLINE void GeomVertexWriter:: -set_pointer(int row, GeomVertexArrayDataPipelineWriter *array_writer) { - _data = array_writer->modify_data(); - _pointer_begin = _data; - _pointer_end = _pointer_begin + array_writer->get_data_size_bytes(); +set_pointer(int row) { + _pointer_begin = _handle->get_pointer(); + _pointer_end = _pointer_begin + _handle->get_data_size_bytes(); quick_set_pointer(row); } @@ -832,21 +827,16 @@ INLINE void GeomVertexWriter:: quick_set_pointer(int row) { nassertv(has_column()); -#if defined(_DEBUG) && !defined(HAVE_THREADS) - // Make sure we still have the same pointer as stored the array. We - // only perform this test in debug mode, because it is expensive, - // and only in single-threaded mode, because in threaded mode - // another thread might have reallocated the other pointer outside - // of our control anyway. - if (_vertex_data != (const GeomVertexData *)NULL) { - const GeomVertexArrayData *array_data = _vertex_data->get_array(_array); - nassertv(_pointer_begin == array_data->get_data()); - } else { - nassertv(_pointer_begin == _array_data->get_data()); - } +#if defined(_DEBUG) + // Make sure we still have the same pointer as stored in the array. + nassertv(_pointer_begin == _handle->get_pointer()); #endif _pointer = _pointer_begin + _packer->_column->get_start() + _stride * row; + +#if defined(_DEBUG) + nassertv(_pointer_begin == _pointer_end || _pointer <= _pointer_end); +#endif } //////////////////////////////////////////////////////////////////// @@ -857,14 +847,11 @@ quick_set_pointer(int row) { //////////////////////////////////////////////////////////////////// INLINE unsigned char *GeomVertexWriter:: inc_pointer() { -#ifdef _DEBUG +#if defined(_DEBUG) nassertr(_pointer < _pointer_end, empty_buffer); - if (_vertex_data != (GeomVertexData *)NULL){ - const GeomVertexArrayData *array_data = _vertex_data->get_array(_array); - nassertr(_pointer >= array_data->get_data().p() && _pointer < array_data->get_data().p() + array_data->get_data_size_bytes(), empty_buffer); - } else { - nassertr(_pointer >= _array_data->get_data().p() && _pointer < _array_data->get_data().p() + _array_data->get_data_size_bytes(), empty_buffer); - } + // Make sure we still have the same pointer as stored in the array. + nassertr(_pointer_begin == _handle->get_pointer(), empty_buffer); + nassertr(_pointer < _pointer_begin + _handle->get_data_size_bytes(), empty_buffer); #endif unsigned char *orig_pointer = _pointer; @@ -885,16 +872,23 @@ inc_add_pointer() { if (_pointer >= _pointer_end) { // Reset the data pointer. int write_row = get_write_row(); + if (_vertex_data != (GeomVertexData *)NULL) { + // If we have a whole GeomVertexData, we must set the length of + // all its arrays at once. GeomVertexDataPipelineWriter writer(_vertex_data, true, _current_thread); writer.check_array_writers(); writer.set_num_rows(max(write_row + 1, writer.get_num_rows())); - set_pointer(write_row, writer.get_array_writer(_array)); + _handle = writer.get_array_writer(_array); + } else { - GeomVertexArrayDataPipelineWriter writer(_array_data, true, _current_thread); - writer.set_num_rows(max(write_row + 1, writer.get_num_rows())); - set_pointer(write_row, &writer); + // Otherwise, we can get away with modifying only the one array + // we're using. + _handle->set_num_rows(max(write_row + 1, _handle->get_num_rows())); } + + set_pointer(write_row); } return inc_pointer(); } + diff --git a/panda/src/gobj/geomVertexWriter.cxx b/panda/src/gobj/geomVertexWriter.cxx index 2460f71131..32bd91b93e 100644 --- a/panda/src/gobj/geomVertexWriter.cxx +++ b/panda/src/gobj/geomVertexWriter.cxx @@ -62,8 +62,7 @@ set_column(int array, const GeomVertexColumn *column) { return set_vertex_column(array, column, &writer); } if (_array_data != (GeomVertexArrayData *)NULL) { - GeomVertexArrayDataPipelineWriter writer(_array_data, true, _current_thread); - return set_array_column(column, &writer); + return set_array_column(column); } // No data is associated with the Writer. @@ -126,12 +125,11 @@ set_vertex_column(int array, const GeomVertexColumn *column, #endif _array = array; - GeomVertexArrayDataPipelineWriter *array_writer = - data_writer->get_array_writer(_array); - _stride = array_writer->get_array_format()->get_stride(); + _handle = data_writer->get_array_writer(_array); + _stride = _handle->get_array_format()->get_stride(); _packer = column->_packer; - set_pointer(_start_row, array_writer); + set_pointer(_start_row); return true; } @@ -144,18 +142,18 @@ set_vertex_column(int array, const GeomVertexColumn *column, // GeomVertexArrayData. //////////////////////////////////////////////////////////////////// bool GeomVertexWriter:: -set_array_column(const GeomVertexColumn *column, - GeomVertexArrayDataPipelineWriter *array_writer) { +set_array_column(const GeomVertexColumn *column) { if (column == (const GeomVertexColumn *)NULL) { return set_column(0, NULL); } nassertr(_array_data != (GeomVertexArrayData *)NULL, false); - _stride = array_writer->get_array_format()->get_stride(); + _handle = _array_data->modify_handle(); + _stride = _handle->get_array_format()->get_stride(); _packer = column->_packer; - set_pointer(_start_row, array_writer); + set_pointer(_start_row); return true; } diff --git a/panda/src/gobj/geomVertexWriter.h b/panda/src/gobj/geomVertexWriter.h index 5e7c75a70e..c2fa29af1d 100644 --- a/panda/src/gobj/geomVertexWriter.h +++ b/panda/src/gobj/geomVertexWriter.h @@ -157,16 +157,14 @@ private: void initialize(); - INLINE void set_pointer(int row, - GeomVertexArrayDataPipelineWriter *array_writer); + INLINE void set_pointer(int row); INLINE void quick_set_pointer(int row); INLINE unsigned char *inc_pointer(); INLINE unsigned char *inc_add_pointer(); bool set_vertex_column(int array, const GeomVertexColumn *column, GeomVertexDataPipelineWriter *data_writer); - bool set_array_column(const GeomVertexColumn *column, - GeomVertexArrayDataPipelineWriter *array_writer); + bool set_array_column(const GeomVertexColumn *column); // It is important that we only store *one* of the following two // pointers. If we are storing a GeomVertexData/array index, we @@ -181,7 +179,7 @@ private: GeomVertexColumn::Packer *_packer; int _stride; - PTA_uchar _data; + PT(GeomVertexArrayDataHandle) _handle; unsigned char *_pointer_begin; unsigned char *_pointer_end; unsigned char *_pointer; diff --git a/panda/src/gobj/gobj_composite1.cxx b/panda/src/gobj/gobj_composite1.cxx index 80609e645f..97e241f8a8 100644 --- a/panda/src/gobj/gobj_composite1.cxx +++ b/panda/src/gobj/gobj_composite1.cxx @@ -1,25 +1,28 @@ #include "bufferContext.cxx" #include "bufferContextChain.cxx" #include "bufferResidencyTracker.cxx" +#include "config_gobj.cxx" #include "geom.cxx" -#include "geomContext.cxx" -#include "geomEnums.cxx" -#include "geomMunger.cxx" -#include "geomPrimitive.cxx" -#include "geomTriangles.cxx" -#include "geomTristrips.cxx" -#include "geomTrifans.cxx" -#include "geomLines.cxx" -#include "geomLinestrips.cxx" -#include "geomPoints.cxx" -#include "geomVertexArrayData.cxx" -#include "geomVertexArrayFormat.cxx" #include "geomCacheEntry.cxx" #include "geomCacheManager.cxx" +#include "geomContext.cxx" +#include "geomEnums.cxx" +#include "geomLines.cxx" +#include "geomLinestrips.cxx" +#include "geomMunger.cxx" +#include "geomPoints.cxx" +#include "geomPrimitive.cxx" +#include "geomTriangles.cxx" +#include "geomTrifans.cxx" +#include "geomTristrips.cxx" #include "geomVertexAnimationSpec.cxx" -#include "geomVertexData.cxx" +#include "geomVertexArrayData.cxx" +#include "geomVertexArrayFormat.cxx" #include "geomVertexColumn.cxx" +#include "geomVertexData.cxx" #include "geomVertexFormat.cxx" #include "geomVertexReader.cxx" #include "geomVertexRewriter.cxx" #include "geomVertexWriter.cxx" +#include "indexBufferContext.cxx" +#include "internalName.cxx" diff --git a/panda/src/gobj/gobj_composite2.cxx b/panda/src/gobj/gobj_composite2.cxx index c4cf2bf874..98a613a91d 100644 --- a/panda/src/gobj/gobj_composite2.cxx +++ b/panda/src/gobj/gobj_composite2.cxx @@ -1,6 +1,3 @@ -#include "config_gobj.cxx" -#include "indexBufferContext.cxx" -#include "internalName.cxx" #include "lens.cxx" #include "material.cxx" #include "materialPool.cxx" @@ -11,14 +8,15 @@ #include "preparedGraphicsObjects.cxx" #include "queryContext.cxx" #include "savedContext.cxx" +#include "shaderContext.cxx" +#include "shaderExpansion.cxx" +#include "simpleLru.cxx" #include "sliderTable.cxx" #include "texture.cxx" #include "textureContext.cxx" #include "texturePool.cxx" #include "texturePoolFilter.cxx" #include "textureStage.cxx" -#include "shaderExpansion.cxx" -#include "shaderContext.cxx" #include "transformBlend.cxx" #include "transformBlendTable.cxx" #include "transformTable.cxx" diff --git a/panda/src/gobj/simpleLru.I b/panda/src/gobj/simpleLru.I new file mode 100644 index 0000000000..d0199a3a01 --- /dev/null +++ b/panda/src/gobj/simpleLru.I @@ -0,0 +1,203 @@ +// Filename: simpleLru.I +// Created by: drose (11May07) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: SimpleLru::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +SimpleLru:: +SimpleLru(size_t max_size) : LinkedListNode(true) { + _total_size = 0; + _max_size = max_size; +} + +//////////////////////////////////////////////////////////////////// +// Function: SimpleLru::get_total_size +// Access: Published +// Description: Returns the total size of all objects currently +// active on the LRU. +//////////////////////////////////////////////////////////////////// +INLINE size_t SimpleLru:: +get_total_size() const { + return _total_size; +} + +//////////////////////////////////////////////////////////////////// +// Function: SimpleLru::get_max_size +// Access: Published +// Description: Returns the max size of all objects that are allowed +// to be active on the LRU. +//////////////////////////////////////////////////////////////////// +INLINE size_t SimpleLru:: +get_max_size() const { + return _max_size; +} + +//////////////////////////////////////////////////////////////////// +// Function: SimpleLru::set_max_size +// Access: Published +// Description: Changes the max size of all objects that are allowed +// to be active on the LRU. +//////////////////////////////////////////////////////////////////// +INLINE void SimpleLru:: +set_max_size(size_t max_size) { + _max_size = max_size; + consider_evict(); +} + +//////////////////////////////////////////////////////////////////// +// Function: SimpleLru::consider_evict +// Access: Published +// Description: Evicts a sequence of objects if the queue is full. +//////////////////////////////////////////////////////////////////// +INLINE void SimpleLru:: +consider_evict() { + if (_max_size != 0 && _total_size > _max_size) { + do_evict(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: SimpleLruPage::Constructor +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +INLINE SimpleLruPage:: +SimpleLruPage(size_t lru_size) : + _lru(NULL), + _lru_size(lru_size) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: SimpleLruPage::Copy Constructor +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +INLINE SimpleLruPage:: +SimpleLruPage(const SimpleLruPage ©) : + _lru(NULL), + _lru_size(copy._lru_size) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: SimpleLruPage::Copy Assignment Operator +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void SimpleLruPage:: +operator = (const SimpleLruPage ©) { + set_lru_size(copy.get_lru_size()); +} + +//////////////////////////////////////////////////////////////////// +// Function: SimpleLruPage::enqueue_lru +// Access: Published +// Description: Returns the LRU that manages this page, or NULL if it +// is not currently managed by any LRU. +//////////////////////////////////////////////////////////////////// +INLINE SimpleLru *SimpleLruPage:: +get_lru() const { + return _lru; +} + +//////////////////////////////////////////////////////////////////// +// Function: SimpleLruPage::enqueue_lru +// Access: Published +// Description: Adds the page to the tail of the SimpleLru. When it +// reaches the head, it will be the next to be evicted. +//////////////////////////////////////////////////////////////////// +INLINE void SimpleLruPage:: +enqueue_lru(SimpleLru *lru) { + dequeue_lru(); + _lru = lru; + _lru->_total_size += _lru_size; + insert_before(_lru); + + // Let's not automatically evict pages; instead, we'll evict only on + // an explicit epoch test. + // _lru->consider_evict(); +} + +//////////////////////////////////////////////////////////////////// +// Function: SimpleLruPage::dequeue_lru +// Access: Published +// Description: Removes the page from its SimpleLru. +//////////////////////////////////////////////////////////////////// +INLINE void SimpleLruPage:: +dequeue_lru() { + if (_lru != (SimpleLru *)NULL) { + remove_from_list(); + _lru->_total_size -= _lru_size; + _lru = NULL; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: SimpleLruPage::mark_used_lru +// Access: Published +// Description: To be called when the page is used; this will move it +// to the tail of the SimpleLru queue it is already on. +//////////////////////////////////////////////////////////////////// +INLINE void SimpleLruPage:: +mark_used_lru() { + if (_lru != (SimpleLru *)NULL) { + mark_used_lru(_lru); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: SimpleLruPage::mark_used_lru +// Access: Published +// Description: To be called when the page is used; this will move it +// to the tail of the specified SimpleLru queue. +//////////////////////////////////////////////////////////////////// +INLINE void SimpleLruPage:: +mark_used_lru(SimpleLru *lru) { + dequeue_lru(); + enqueue_lru(lru); +} + +//////////////////////////////////////////////////////////////////// +// Function: SimpleLruPage::get_lru_size +// Access: Published +// Description: Returns the size of this page as reported to the LRU, +// presumably in bytes. +//////////////////////////////////////////////////////////////////// +INLINE size_t SimpleLruPage:: +get_lru_size() const { + return _lru_size; +} + +//////////////////////////////////////////////////////////////////// +// Function: SimpleLruPage::set_lru_size +// Access: Published +// Description: Specifies the size of this page, presumably in bytes, +// although any units is possible. +//////////////////////////////////////////////////////////////////// +INLINE void SimpleLruPage:: +set_lru_size(size_t lru_size) { + if (_lru != (SimpleLru *)NULL) { + _lru->_total_size -= _lru_size; + _lru->_total_size += lru_size; + } + _lru_size = lru_size; +} diff --git a/panda/src/gobj/simpleLru.cxx b/panda/src/gobj/simpleLru.cxx new file mode 100644 index 0000000000..3983cca535 --- /dev/null +++ b/panda/src/gobj/simpleLru.cxx @@ -0,0 +1,96 @@ +// Filename: simpleLru.cxx +// Created by: drose (11May07) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "simpleLru.h" + + +//////////////////////////////////////////////////////////////////// +// Function: SimpleLru::Destructor +// Access: Protected, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +SimpleLru:: +~SimpleLru() { +#ifndef NDEBUG + // We're shutting down. Force-remove everything remaining, but + // don't explicitly evict it (that would force vertex buffers to + // write themselves to disk unnecessarily). + while (_next != (LinkedListNode *)NULL) { + ((SimpleLruPage *)_next)->_lru = NULL; + ((SimpleLruPage *)_next)->remove_from_list(); + } +#endif +} + +//////////////////////////////////////////////////////////////////// +// Function: SimpleLru::do_evict +// Access: Private +// Description: Evicts pages until the LRU is within tolerance. +//////////////////////////////////////////////////////////////////// +void SimpleLru:: +do_evict() { + // Store the current end of the list. If pages re-enqueue + // themselves during this traversal, we don't want to visit them + // twice. + SimpleLruPage *end = (SimpleLruPage *)_prev; + + // Now walk through the list. + SimpleLruPage *node = (SimpleLruPage *)_next; + while (_total_size > _max_size) { + SimpleLruPage *next = (SimpleLruPage *)node->_next; + + node->evict_lru(); + if (node == end) { + // If we reach the original tail of the list, stop. + return; + } + node = next; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: SimpleLruPage::Destructor +// Access: Published, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +SimpleLruPage:: +~SimpleLruPage() { + if (_lru != NULL) { + dequeue_lru(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: SimpleLruPage::evict_lru +// Access: Published, Virtual +// Description: Evicts the page from the LRU. Called internally when +// the LRU determines that it is full. May also be +// called externally when necessary to explicitly evict +// the page. +// +// It is legal for this method to either evict the page +// as requested, do nothing (in which case the eviction +// will be requested again at the next epoch), or +// requeue itself on the tail of the queue (in which +// case the eviction will be requested again much +// later). +//////////////////////////////////////////////////////////////////// +void SimpleLruPage:: +evict_lru() { + dequeue_lru(); +} diff --git a/panda/src/gobj/simpleLru.h b/panda/src/gobj/simpleLru.h new file mode 100644 index 0000000000..fcd79e4103 --- /dev/null +++ b/panda/src/gobj/simpleLru.h @@ -0,0 +1,88 @@ +// Filename: simpleLru.h +// Created by: drose (11May07) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef SIMPLELRU_H +#define SIMPLELRU_H + +#include "pandabase.h" +#include "linkedListNode.h" + +class SimpleLruPage; + +//////////////////////////////////////////////////////////////////// +// Class : SimpleLru +// Description : An implementation of a very simple LRU algorithm. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA SimpleLru : public LinkedListNode { +PUBLISHED: + INLINE SimpleLru(size_t max_size); + ~SimpleLru(); + + INLINE size_t get_total_size() const; + INLINE size_t get_max_size() const; + INLINE void set_max_size(size_t max_size); + + INLINE void consider_evict(); + +private: + void do_evict(); + + size_t _total_size; + size_t _max_size; + + friend class SimpleLruPage; +}; + +//////////////////////////////////////////////////////////////////// +// Class : SimpleLruPage +// Description : One atomic piece that may be managed by a SimpleLru +// chain. To use this class, inherit from it and +// override evict_lru(). +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA SimpleLruPage : public LinkedListNode { +PUBLISHED: + INLINE SimpleLruPage(size_t lru_size); + INLINE SimpleLruPage(const SimpleLruPage ©); + INLINE void operator = (const SimpleLruPage ©); + + virtual ~SimpleLruPage(); + + INLINE SimpleLru *get_lru() const; + + INLINE void enqueue_lru(SimpleLru *lru); + INLINE void dequeue_lru(); + + INLINE void mark_used_lru(); + INLINE void mark_used_lru(SimpleLru *lru); + + INLINE size_t get_lru_size() const; + INLINE void set_lru_size(size_t lru_size); + + virtual void evict_lru(); + +private: + SimpleLru *_lru; + + size_t _lru_size; + + friend class SimpleLru; +}; + +#include "simpleLru.I" + +#endif diff --git a/panda/src/gobj/vertexBufferContext.I b/panda/src/gobj/vertexBufferContext.I index 41cac78492..4c5c40028a 100644 --- a/panda/src/gobj/vertexBufferContext.I +++ b/panda/src/gobj/vertexBufferContext.I @@ -47,7 +47,7 @@ get_data() const { // last time mark_loaded() was called. //////////////////////////////////////////////////////////////////// INLINE bool VertexBufferContext:: -changed_size(const GeomVertexArrayDataPipelineReader *reader) const { +changed_size(const GeomVertexArrayDataHandle *reader) const { nassertr(reader->get_object() == _data, false); return get_data_size_bytes() != (size_t)reader->get_data_size_bytes(); } @@ -59,7 +59,7 @@ changed_size(const GeomVertexArrayDataPipelineReader *reader) const { // since the last time mark_loaded() was called. //////////////////////////////////////////////////////////////////// INLINE bool VertexBufferContext:: -changed_usage_hint(const GeomVertexArrayDataPipelineReader *reader) const { +changed_usage_hint(const GeomVertexArrayDataHandle *reader) const { nassertr(reader->get_object() == _data, false); return _usage_hint != reader->get_usage_hint(); } @@ -71,7 +71,7 @@ changed_usage_hint(const GeomVertexArrayDataPipelineReader *reader) const { // last time mark_loaded() was called. //////////////////////////////////////////////////////////////////// INLINE bool VertexBufferContext:: -was_modified(const GeomVertexArrayDataPipelineReader *reader) const { +was_modified(const GeomVertexArrayDataHandle *reader) const { nassertr(reader->get_object() == _data, false); return get_modified() != reader->get_modified(); } @@ -84,7 +84,7 @@ was_modified(const GeomVertexArrayDataPipelineReader *reader) const { // internal flags for changed_size() and modified(). //////////////////////////////////////////////////////////////////// INLINE void VertexBufferContext:: -mark_loaded(const GeomVertexArrayDataPipelineReader *reader) { +mark_loaded(const GeomVertexArrayDataHandle *reader) { nassertv(reader->get_object() == _data); update_data_size_bytes(reader->get_data_size_bytes()); update_modified(reader->get_modified()); diff --git a/panda/src/gobj/vertexBufferContext.h b/panda/src/gobj/vertexBufferContext.h index 28ed15cdd6..6e846e7833 100644 --- a/panda/src/gobj/vertexBufferContext.h +++ b/panda/src/gobj/vertexBufferContext.h @@ -44,12 +44,12 @@ public: PUBLISHED: INLINE GeomVertexArrayData *get_data() const; - INLINE bool changed_size(const GeomVertexArrayDataPipelineReader *reader) const; - INLINE bool changed_usage_hint(const GeomVertexArrayDataPipelineReader *reader) const; - INLINE bool was_modified(const GeomVertexArrayDataPipelineReader *reader) const; + INLINE bool changed_size(const GeomVertexArrayDataHandle *reader) const; + INLINE bool changed_usage_hint(const GeomVertexArrayDataHandle *reader) const; + INLINE bool was_modified(const GeomVertexArrayDataHandle *reader) const; public: - INLINE void mark_loaded(const GeomVertexArrayDataPipelineReader *reader); + INLINE void mark_loaded(const GeomVertexArrayDataHandle *reader); private: // This cannot be a PT(GeomVertexArrayData), because the data and diff --git a/panda/src/pgraph/geomTransformer.cxx b/panda/src/pgraph/geomTransformer.cxx index 2422ca0d83..a66232b014 100644 --- a/panda/src/pgraph/geomTransformer.cxx +++ b/panda/src/pgraph/geomTransformer.cxx @@ -484,15 +484,16 @@ collect_vertex_data(Geom *geom, int collect_bits) { new_data->set_num_rows(new_num_vertices); for (int i = 0; i < vdata->get_num_arrays(); ++i) { - GeomVertexArrayData *new_array = new_data->modify_array(i); - const GeomVertexArrayData *old_array = vdata->get_array(i); + PT(GeomVertexArrayData) new_array = new_data->modify_array(i); + CPT(GeomVertexArrayData) old_array = vdata->get_array(i); int stride = format->get_array(i)->get_stride(); int start_byte = offset * stride; int copy_bytes = old_array->get_data_size_bytes(); nassertr(start_byte + copy_bytes == new_array->get_data_size_bytes(), 0); - memcpy(new_array->modify_data() + start_byte, - old_array->get_data(), copy_bytes); + new_array->modify_handle()->copy_subdata_from + (start_byte, copy_bytes, + old_array->get_handle(), 0, copy_bytes); } // Also, copy the animation data (if any). This means combining diff --git a/panda/src/pgraph/sceneGraphReducer.cxx b/panda/src/pgraph/sceneGraphReducer.cxx index 828c1730a8..f30770c37d 100644 --- a/panda/src/pgraph/sceneGraphReducer.cxx +++ b/panda/src/pgraph/sceneGraphReducer.cxx @@ -67,7 +67,7 @@ flatten(PandaNode *root, int combine_siblings_bits) { // Now visit each of the children in turn. int num_children = cr.get_num_children(); for (int i = 0; i < num_children; i++) { - PandaNode *child_node = cr.get_child(i); + PT(PandaNode) child_node = cr.get_child(i); num_pass_nodes += r_flatten(root, child_node, combine_siblings_bits); } @@ -271,7 +271,7 @@ r_flatten(PandaNode *grandparent_node, PandaNode *parent_node, PandaNode::Children cr = parent_node->get_children(); int num_children = cr.get_num_children(); for (int i = 0; i < num_children; i++) { - PandaNode *child_node = cr.get_child(i); + PT(PandaNode) child_node = cr.get_child(i); num_nodes += r_flatten(parent_node, child_node, combine_siblings_bits); } } diff --git a/panda/src/pstatclient/pStatClient.cxx b/panda/src/pstatclient/pStatClient.cxx index 93b0b0ed96..b671561d88 100644 --- a/panda/src/pstatclient/pStatClient.cxx +++ b/panda/src/pstatclient/pStatClient.cxx @@ -231,7 +231,7 @@ main_tick() { size_t total_usage = 0; int i; - for (int i = 0; i < num_typehandles; ++i) { + for (i = 0; i < num_typehandles; ++i) { TypeHandle type = type_reg->get_typehandle(i); for (int mi = 0; mi < (int)TypeHandle::MC_limit; ++mi) { TypeHandle::MemoryClass mc = (TypeHandle::MemoryClass)mi; @@ -245,7 +245,7 @@ main_tick() { } size_t other_usage = total_usage; - for (int i = 0; i < num_typehandles; ++i) { + for (i = 0; i < num_typehandles; ++i) { TypeHandle type = type_reg->get_typehandle(i); for (int mi = 0; mi < (int)TypeHandle::MC_limit; ++mi) { TypeHandle::MemoryClass mc = (TypeHandle::MemoryClass)mi; diff --git a/panda/src/pstatclient/pStatProperties.cxx b/panda/src/pstatclient/pStatProperties.cxx index 48eb372a86..64042dd3de 100644 --- a/panda/src/pstatclient/pStatProperties.cxx +++ b/panda/src/pstatclient/pStatProperties.cxx @@ -199,6 +199,10 @@ static LevelCollectorProperties level_properties[] = { { 1, "Main memory", { 0.5, 1.0, 0.5 }, "MB", 64, 1048576 }, { 1, "Main memory:C++", { 0.2, 0.2, 1.0 } }, { 1, "Main memory:Interpreter", { 0.8, 0.2, 0.5 } }, + { 1, "Vertex Data", { 1.0, 0.4, 0.0 }, "MB", 64, 1048576 }, + { 1, "Vertex Data:Disk", { 0.6, 0.9, 0.1 } }, + { 1, "Vertex Data:Compressed", { 0.5, 0.1, 0.4 } }, + { 1, "Vertex Data:Resident", { 0.9, 0.1, 0.7 } }, { 1, "TransformStates", { 1.0, 0.5, 0.5 }, "", 5000 }, { 1, "TransformStates:On nodes", { 0.2, 0.8, 1.0 } }, { 1, "TransformStates:Cached", { 1.0, 0.0, 0.2 } }, diff --git a/panda/src/putil/copyOnWritePointer.I b/panda/src/putil/copyOnWritePointer.I index 52ba86b89e..ae7ab4403b 100644 --- a/panda/src/putil/copyOnWritePointer.I +++ b/panda/src/putil/copyOnWritePointer.I @@ -121,7 +121,7 @@ get_write_pointer() { if (_object == (CopyOnWriteObject *)NULL) { return NULL; } - if (_object->get_ref_count() > 1) { + if (_object->get_cache_ref_count() > 1) { PT(CopyOnWriteObject) new_object = _object->make_cow_copy(); cache_unref_delete(_object); _object = new_object;