From 93cab990c71cec08f21866a4ad41dfeebc0546f1 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Wed, 15 Mar 2017 20:45:03 +0100 Subject: [PATCH] Fixed some memory allocation issues of the new C++ 3d path preview (reserved memory has to be shrank around the collected data). Initial implementation of the vertex buffer objects for the 3d path preview. --- lib/Slic3r/GUI/3DScene.pm | 48 ++++++++++++++++++++++++++----- xs/src/slic3r/GUI/3DScene.cpp | 19 +++++++++---- xs/src/slic3r/GUI/3DScene.hpp | 53 +++++++++++++++++++++++++++++++---- xs/xsp/GUI_3DScene.xsp | 13 ++++++--- 4 files changed, 110 insertions(+), 23 deletions(-) diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm index b149047c3..f6b66a991 100644 --- a/lib/Slic3r/GUI/3DScene.pm +++ b/lib/Slic3r/GUI/3DScene.pm @@ -1254,20 +1254,54 @@ sub draw_volumes { glPushMatrix(); glTranslatef(@{$volume->origin}); glCullFace(GL_BACK); + if (1) { if ($volume->indexed) { my $quads_cnt = $volume->indexed_quads_to_render_cnt; my $triangles_cnt = $volume->indexed_triangles_to_render_cnt; if ($quads_cnt + $triangles_cnt > 0) { - glInterleavedArrays_c(GL_N3F_V3F, 0, $volume->triangles_to_render_ptr); - glDrawElements_c(GL_QUADS, $quads_cnt, GL_UNSIGNED_INT, $volume->quad_indices_to_render_ptr ) if ($quads_cnt); - glDrawElements_c(GL_TRIANGLES, $triangles_cnt, GL_UNSIGNED_INT, $volume->triangle_indices_to_render_ptr) if ($triangles_cnt); - glInterleavedArrays_c(GL_N3F_V3F, 0, 0); + if ($self->{use_VBOs}) { + my ($name_geometry, $name_triangle_indices, $name_quad_indices) = glGenBuffersARB_p(3); + glBindBufferARB(GL_ARRAY_BUFFER_ARB, $name_geometry); + glBufferDataARB_c(GL_ARRAY_BUFFER_ARB, $volume->geometry_size, $volume->triangles_to_render_ptr, GL_STATIC_DRAW_ARB); + glInterleavedArrays_c(GL_N3F_V3F, 0, 0); + if ($quads_cnt) { + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, $name_quad_indices); + glBufferDataARB_c(GL_ELEMENT_ARRAY_BUFFER_ARB, $volume->indexed_quads_cnt * 4, $volume->quad_indices_ptr, GL_STATIC_DRAW_ARB); + glDrawElements_c(GL_QUADS, $quads_cnt, GL_UNSIGNED_INT, $volume->quad_indices_to_render_offset * 4); + } + if ($triangles_cnt) { + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, $name_triangle_indices); + glBufferDataARB_c(GL_ELEMENT_ARRAY_BUFFER_ARB, $volume->indexed_triangles_cnt * 4, $volume->triangle_indices_ptr, GL_STATIC_DRAW_ARB); + glDrawElements_c(GL_TRIANGLES, $triangles_cnt, GL_UNSIGNED_INT, $volume->triangle_indices_to_render_offset * 4); + } + glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + glDeleteBuffersARB_p(($name_geometry, $name_triangle_indices, $name_quad_indices)); + } else { + glInterleavedArrays_c(GL_N3F_V3F, 0, $volume->triangles_to_render_ptr); + glDrawElements_c(GL_QUADS, $quads_cnt, GL_UNSIGNED_INT, $volume->quad_indices_ptr + $volume->quad_indices_to_render_offset * 4) + if ($quads_cnt); + glDrawElements_c(GL_TRIANGLES, $triangles_cnt, GL_UNSIGNED_INT, $volume->triangle_indices_ptr + $volume->triangle_indices_to_render_offset * 4) + if ($triangles_cnt); + glInterleavedArrays_c(GL_N3F_V3F, 0, 0); + } } } elsif (! $volume->empty) { - glInterleavedArrays_c(GL_N3F_V3F, 0, $volume->triangles_to_render_ptr); - glDrawArrays(GL_TRIANGLES, 0, $volume->triangles_to_render_cnt); - glInterleavedArrays_c(GL_N3F_V3F, 0, 0); + if ($self->{use_VBOs}) { + my ($name_geometry) = glGenBuffersARB_p(1); + glBindBufferARB(GL_ARRAY_BUFFER_ARB, $name_geometry); + glBufferDataARB_c(GL_ARRAY_BUFFER_ARB, $volume->triangles_to_render_cnt * 6 * 4, $volume->triangles_to_render_ptr, GL_STATIC_DRAW_ARB); + glInterleavedArrays_c(GL_N3F_V3F, 0, 0); + glDrawArrays(GL_TRIANGLES, 0, $volume->triangles_to_render_cnt); + glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); + glDeleteBuffersARB_p(($name_geometry)); + } else { + glInterleavedArrays_c(GL_N3F_V3F, 0, $volume->triangles_to_render_ptr); + glDrawArrays(GL_TRIANGLES, 0, $volume->triangles_to_render_cnt); + glInterleavedArrays_c(GL_N3F_V3F, 0, 0); + } } + } glPopMatrix(); if ($shader_active) { diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index e71bd01b8..5196e4740 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -594,7 +594,7 @@ void _3DScene::_load_print_object_toolpaths( //FIXME Improve the heuristics for a grain size. size_t grain_size = std::max(ctxt.layers.size() / 16, size_t(1)); - std::vector volumes_per_thread(ctxt.layers.size(), GLVolumeCollection()); + std::vector volumes_per_thread(ctxt.layers.size()); tbb::parallel_for( tbb::blocked_range(0, ctxt.layers.size(), grain_size), [&ctxt, &volumes_per_thread](const tbb::blocked_range& range) { @@ -636,17 +636,24 @@ void _3DScene::_load_print_object_toolpaths( for (size_t i = 0; i < 3; ++ i) { GLVolume &vol = *volumes[vols[i]]; if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() / 6 > ctxt.alloc_size_max()) { - // Shrink the old vectors to preserve memory. - vol.indexed_vertex_array.shrink_to_fit(); - // Store the vertex arrays and restart their containers. + // Store the vertex arrays and restart their containers, vols[i] = volumes.size(); volumes.emplace_back(new GLVolume(vol.color)); GLVolume &vol_new = *volumes.back(); vol_new.bounding_box = ctxt.bbox; - vol_new.indexed_vertex_array.reserve(ctxt.alloc_size_reserve()); + // Assign the large pre-allocated buffers to the new GLVolume. + vol_new.indexed_vertex_array = std::move(vol.indexed_vertex_array); + // Copy the content back to the old GLVolume. + vol.indexed_vertex_array = vol_new.indexed_vertex_array; + // Clear the buffers, but keep them pre-allocated. + vol_new.indexed_vertex_array.clear(); + // Just make sure that clear did not clear the reserved memory. + vol_new.indexed_vertex_array.reserve(ctx.alloc_size_reserve()); } } } + for (size_t i = 0; i < 3; ++ i) + volumes[vols[i]]->indexed_vertex_array.shrink_to_fit(); while (! volumes.empty() && volumes.back()->empty()) { delete volumes.back(); volumes.pop_back(); @@ -665,7 +672,7 @@ void _3DScene::_load_print_object_toolpaths( volume_ptr += v.volumes.size(); v.volumes.clear(); } - + BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - end"; } diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp index 0049dfe3f..07c8e785b 100644 --- a/xs/src/slic3r/GUI/3DScene.hpp +++ b/xs/src/slic3r/GUI/3DScene.hpp @@ -18,6 +18,32 @@ class ModelObject; class GLIndexedVertexArray { public: GLIndexedVertexArray() {} + GLIndexedVertexArray(const GLIndexedVertexArray &rhs) : + vertices_and_normals_interleaved(rhs.vertices_and_normals_interleaved), + triangle_indices(rhs.triangle_indices), + quad_indices(rhs.quad_indices) + {} + GLIndexedVertexArray(GLIndexedVertexArray &&rhs) : + vertices_and_normals_interleaved(std::move(rhs.vertices_and_normals_interleaved)), + triangle_indices(std::move(rhs.triangle_indices)), + quad_indices(std::move(rhs.quad_indices)) + {} + + GLIndexedVertexArray& operator=(const GLIndexedVertexArray &rhs) + { + this->vertices_and_normals_interleaved = rhs.vertices_and_normals_interleaved; + this->triangle_indices = rhs.triangle_indices; + this->quad_indices = rhs.quad_indices; + return *this; + } + + GLIndexedVertexArray& operator=(GLIndexedVertexArray &&rhs) + { + this->vertices_and_normals_interleaved = std::move(rhs.vertices_and_normals_interleaved); + this->triangle_indices = std::move(rhs.triangle_indices); + this->quad_indices = std::move(rhs.quad_indices); + return *this; + } // Vertices and their normals, interleaved to be used by void glInterleavedArrays(GL_N3F_V3F, 0, x) std::vector vertices_and_normals_interleaved; @@ -52,6 +78,12 @@ public: // Is this object indexed, or is it just a set of triangles? bool indexed() const { return ! this->empty() && (! this->triangle_indices.empty() || ! this->quad_indices.empty()); } + void clear() { + this->vertices_and_normals_interleaved.clear(); + this->triangle_indices.clear(); + this->quad_indices.clear(); + } + // Shrink the internal storage to tighly fit the data stored. void shrink_to_fit() { this->vertices_and_normals_interleaved.shrink_to_fit(); @@ -173,15 +205,20 @@ public: // Non-indexed interleaved vertices & normals, likely forming triangles. void* triangles_to_render_ptr() { return indexed_vertex_array.vertices_and_normals_interleaved.data(); } size_t triangles_to_render_cnt() { return indexed_vertex_array.vertices_and_normals_interleaved.size() / (3 * 2); } - // Indexed triangles & quads. - void* triangle_indices_to_render_ptr() { return indexed_vertex_array.triangle_indices.data() + tverts_range.first; } - void* quad_indices_to_render_ptr() { return indexed_vertex_array.quad_indices.data() + qverts_range.first; } - size_t indexed_triangles_to_render_cnt() { return std::min(indexed_vertex_array.triangle_indices.size(), tverts_range.second - tverts_range.first); } - size_t indexed_quads_to_render_cnt() { return std::min(indexed_vertex_array.quad_indices.size(), qverts_range.second - qverts_range.first); } + // Indexed triangles & quads, complete set for storing into a vertex buffer. + size_t geometry_size() const { return indexed_vertex_array.vertices_and_normals_interleaved.size() * 4; } + void* triangle_indices_ptr() { return indexed_vertex_array.triangle_indices.data(); } + void* quad_indices_ptr() { return indexed_vertex_array.quad_indices.data(); } + size_t indexed_triangles_cnt() { return indexed_vertex_array.triangle_indices.size(); } + size_t indexed_quads_cnt() { return indexed_vertex_array.quad_indices.size(); } + // Indexed triangles & quads, to be painted in an immediate mode. + size_t triangle_indices_to_render_offset() const { return tverts_range.first; } + size_t quad_indices_to_render_offset() const { return qverts_range.first; } + size_t indexed_triangles_to_render_cnt() const { return std::min(indexed_vertex_array.triangle_indices.size(), tverts_range.second - tverts_range.first); } + size_t indexed_quads_to_render_cnt() const { return std::min(indexed_vertex_array.quad_indices.size(), qverts_range.second - qverts_range.first); } void render_VBOs() const; - /************************************************ Layer height texture ****************************************************/ std::shared_ptr layer_height_texture; @@ -228,6 +265,10 @@ public: bool empty() const { return volumes.empty(); } void set_range(double low, double high) { for (GLVolume *vol : this->volumes) vol->set_range(low, high); } void render_VBOs() const { for (GLVolume *vol : this->volumes) vol->render_VBOs(); } + +private: + GLVolumeCollection(const GLVolumeCollection &other); + GLVolumeCollection& operator=(const GLVolumeCollection &); }; class _3DScene diff --git a/xs/xsp/GUI_3DScene.xsp b/xs/xsp/GUI_3DScene.xsp index 48f9a3f96..4532b16ea 100644 --- a/xs/xsp/GUI_3DScene.xsp +++ b/xs/xsp/GUI_3DScene.xsp @@ -40,10 +40,15 @@ void* triangles_to_render_ptr(); size_t triangles_to_render_cnt(); - void* triangle_indices_to_render_ptr(); - void* quad_indices_to_render_ptr(); - size_t indexed_triangles_to_render_cnt(); - size_t indexed_quads_to_render_cnt(); + size_t geometry_size() const; + void* triangle_indices_ptr(); + void* quad_indices_ptr(); + size_t indexed_triangles_cnt(); + size_t indexed_quads_cnt(); + size_t triangle_indices_to_render_offset() const; + size_t quad_indices_to_render_offset() const; + size_t indexed_triangles_to_render_cnt() const; + size_t indexed_quads_to_render_cnt() const; bool has_layer_height_texture(); int layer_height_texture_width();