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.
This commit is contained in:
bubnikv 2017-03-15 20:45:03 +01:00
parent d18e10c7c9
commit 93cab990c7
4 changed files with 110 additions and 23 deletions

View file

@ -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) {

View file

@ -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<GLVolumeCollection> volumes_per_thread(ctxt.layers.size(), GLVolumeCollection());
std::vector<GLVolumeCollection> volumes_per_thread(ctxt.layers.size());
tbb::parallel_for(
tbb::blocked_range<size_t>(0, ctxt.layers.size(), grain_size),
[&ctxt, &volumes_per_thread](const tbb::blocked_range<size_t>& 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();

View file

@ -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<float> 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<GLTexture> 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

View file

@ -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();