From 301957c59188ae6d83276e4796a1f421f95b9daa Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 4 Dec 2018 12:36:03 +0100 Subject: [PATCH] gobj: improve performance of GeomPrimitive::make_nonindexed() It now no longer has to create two GeomVertexArrayDataHandle objects for every vertex it visits. --- panda/src/gobj/geomPrimitive.cxx | 27 ++++++++---- panda/src/gobj/geomVertexData.cxx | 68 ++++++++++++++++++++----------- panda/src/gobj/geomVertexData.h | 3 ++ 3 files changed, 66 insertions(+), 32 deletions(-) diff --git a/panda/src/gobj/geomPrimitive.cxx b/panda/src/gobj/geomPrimitive.cxx index 011d66b132..2cd5e2739a 100644 --- a/panda/src/gobj/geomPrimitive.cxx +++ b/panda/src/gobj/geomPrimitive.cxx @@ -538,15 +538,26 @@ offset_vertices(int offset, int begin_row, int end_row) { void GeomPrimitive:: make_nonindexed(GeomVertexData *dest, const GeomVertexData *source) { Thread *current_thread = Thread::get_current_thread(); - int num_vertices = get_num_vertices(); - int dest_start = dest->get_num_rows(); - int strip_cut_index = get_strip_cut_index(); - dest->set_num_rows(dest_start + num_vertices); - for (int i = 0; i < num_vertices; ++i) { - int v = get_vertex(i); - nassertd(v != strip_cut_index) continue; - dest->copy_row_from(dest_start + i, source, v, current_thread); + int num_vertices, dest_start; + { + GeomPrimitivePipelineReader reader(this, current_thread); + num_vertices = reader.get_num_vertices(); + int strip_cut_index = reader.get_strip_cut_index(); + + GeomVertexDataPipelineWriter data_writer(dest, false, current_thread); + data_writer.check_array_writers(); + dest_start = data_writer.get_num_rows(); + data_writer.set_num_rows(dest_start + num_vertices); + + GeomVertexDataPipelineReader data_reader(source, current_thread); + data_reader.check_array_readers(); + + for (int i = 0; i < num_vertices; ++i) { + int v = reader.get_vertex(i); + nassertd(v != strip_cut_index) continue; + data_writer.copy_row_from(dest_start + i, data_reader, v); + } } set_nonindexed_vertices(dest_start, num_vertices); diff --git a/panda/src/gobj/geomVertexData.cxx b/panda/src/gobj/geomVertexData.cxx index 45522427c2..d7bf35ba9d 100644 --- a/panda/src/gobj/geomVertexData.cxx +++ b/panda/src/gobj/geomVertexData.cxx @@ -686,32 +686,13 @@ copy_from(const GeomVertexData *source, bool keep_data_objects, void GeomVertexData:: copy_row_from(int dest_row, const GeomVertexData *source, int source_row, Thread *current_thread) { - const GeomVertexFormat *source_format = source->get_format(); - const GeomVertexFormat *dest_format = get_format(); - nassertv(source_format == dest_format); - nassertv(source_row >= 0 && source_row < source->get_num_rows()); - if (dest_row >= get_num_rows()) { - // Implicitly add enough rows to get to the indicated row. - set_num_rows(dest_row + 1); - } + GeomVertexDataPipelineReader reader(source, current_thread); + reader.check_array_readers(); - int num_arrays = source_format->get_num_arrays(); - - for (int i = 0; i < num_arrays; ++i) { - PT(GeomVertexArrayDataHandle) dest_handle = modify_array_handle(i); - unsigned char *dest_array_data = dest_handle->get_write_pointer(); - - CPT(GeomVertexArrayDataHandle) source_array_handle = source->get_array_handle(i); - const unsigned char *source_array_data = source_array_handle->get_read_pointer(true); - - const GeomVertexArrayFormat *array_format = source_format->get_array(i); - int stride = array_format->get_stride(); - - memcpy(dest_array_data + stride * dest_row, - source_array_data + stride * source_row, - stride); - } + GeomVertexDataPipelineWriter writer(this, true, current_thread); + writer.check_array_writers(); + writer.copy_row_from(dest_row, reader, source_row); } /** @@ -2601,6 +2582,45 @@ set_array(size_t i, const GeomVertexArrayData *array) { } } +/** + * Copies a single row of the data from the other array into the indicated row + * of this array. In this case, the source format must exactly match the + * destination format. + * + * 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. + */ +void GeomVertexDataPipelineWriter:: +copy_row_from(int dest_row, const GeomVertexDataPipelineReader &source, + int source_row) { + const GeomVertexFormat *source_format = source.get_format(); + const GeomVertexFormat *dest_format = get_format(); + nassertv(source_format == dest_format); + nassertv(source_row >= 0 && source_row < source.get_num_rows()); + nassertv(_got_array_writers); + + if (dest_row >= get_num_rows()) { + // Implicitly add enough rows to get to the indicated row. + set_num_rows(dest_row + 1); + } + + size_t num_arrays = source_format->get_num_arrays(); + for (size_t i = 0; i < num_arrays; ++i) { + GeomVertexArrayDataHandle *dest_handle = get_array_writer(i); + unsigned char *dest_array_data = dest_handle->get_write_pointer(); + + const GeomVertexArrayDataHandle *source_array_handle = source.get_array_reader(i); + const unsigned char *source_array_data = source_array_handle->get_read_pointer(true); + + const GeomVertexArrayFormat *array_format = source_format->get_array(i); + int stride = array_format->get_stride(); + + memcpy(dest_array_data + stride * dest_row, + source_array_data + stride * source_row, + stride); + } +} + /** * */ diff --git a/panda/src/gobj/geomVertexData.h b/panda/src/gobj/geomVertexData.h index 9b861c1cbc..2b267045c5 100644 --- a/panda/src/gobj/geomVertexData.h +++ b/panda/src/gobj/geomVertexData.h @@ -526,6 +526,9 @@ public: bool unclean_set_num_rows(int n); bool reserve_num_rows(int n); + void copy_row_from(int dest_row, const GeomVertexDataPipelineReader &source, + int source_row); + private: void make_array_writers(); void delete_array_writers();