Fixed a regression issue where excessive memory was allocated

for the GLVolumes before sending to the GPU driver. The following commits
were partially reverted:

4269c8b23c Removed GLVolume non-VBO rendering
d15698e21e GLVolume and GLIndexedVertexArray refactored to send data to gpu at the first render call

Namely, the GLVolume buffers are "shrink to size"'d before sending their
content to the OpenGL driver, and the vertex buffers are populated
as quickly as possible from the GLVolume, so that the same buffer is not
kept twice in RAM on systems, where the RAM is shared with the graphics
card.

Also the memory allocation reporting was improved for the GLVolumes.
This commit is contained in:
bubnikv 2019-08-05 14:30:32 +02:00
parent 28cc595350
commit 731e5abd88
5 changed files with 208 additions and 110 deletions

View file

@ -12,6 +12,7 @@
#include "libslic3r/GCode/Analyzer.hpp"
#include "slic3r/GUI/PresetBundle.hpp"
#include "libslic3r/Format/STL.hpp"
#include "libslic3r/Utils.hpp"
#include <stdio.h>
#include <stdlib.h>
@ -74,15 +75,19 @@ void GLIndexedVertexArray::load_mesh_full_shading(const TriangleMesh &mesh)
}
}
void GLIndexedVertexArray::finalize_geometry() const
void GLIndexedVertexArray::finalize_geometry(bool opengl_initialized)
{
assert(this->vertices_and_normals_interleaved_VBO_id == 0);
assert(this->triangle_indices_VBO_id == 0);
assert(this->quad_indices_VBO_id == 0);
this->shrink_to_fit();
if (! opengl_initialized) {
// Shrink the data vectors to conserve memory in case the data cannot be transfered to the OpenGL driver yet.
this->shrink_to_fit();
return;
}
if (! empty()) {
if (! this->vertices_and_normals_interleaved.empty()) {
glsafe(::glGenBuffers(1, &this->vertices_and_normals_interleaved_VBO_id));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id));
glsafe(::glBufferData(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved.size() * 4, this->vertices_and_normals_interleaved.data(), GL_STATIC_DRAW));
@ -124,13 +129,8 @@ void GLIndexedVertexArray::release_geometry()
void GLIndexedVertexArray::render() const
{
if (this->vertices_and_normals_interleaved_VBO_id == 0)
{
// sends data to gpu, if not done yet
finalize_geometry();
if (this->vertices_and_normals_interleaved_VBO_id == 0)
return;
}
assert(this->vertices_and_normals_interleaved_VBO_id != 0);
assert(this->triangle_indices_VBO_id != 0 || this->quad_indices_VBO_id != 0);
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id));
glsafe(::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), (const void*)(3 * sizeof(float))));
@ -161,13 +161,8 @@ void GLIndexedVertexArray::render(
const std::pair<size_t, size_t>& tverts_range,
const std::pair<size_t, size_t>& qverts_range) const
{
if (this->vertices_and_normals_interleaved_VBO_id == 0)
{
// sends data to gpu, if not done yet
finalize_geometry();
if (this->vertices_and_normals_interleaved_VBO_id == 0)
return;
}
assert(this->vertices_and_normals_interleaved_VBO_id != 0);
assert(this->triangle_indices_VBO_id != 0 || this->quad_indices_VBO_id != 0);
// Render using the Vertex Buffer Objects.
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id));
@ -415,30 +410,32 @@ bool GLVolume::is_sla_support() const { return this->composite_id.volume_id == -
bool GLVolume::is_sla_pad() const { return this->composite_id.volume_id == -int(slaposBasePool); }
std::vector<int> GLVolumeCollection::load_object(
const ModelObject* model_object,
const ModelObject *model_object,
int obj_idx,
const std::vector<int>& instance_idxs,
const std::string& color_by)
const std::vector<int> &instance_idxs,
const std::string &color_by,
bool opengl_initialized)
{
std::vector<int> volumes_idx;
for (int volume_idx = 0; volume_idx < int(model_object->volumes.size()); ++volume_idx)
for (int instance_idx : instance_idxs)
volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx, color_by));
volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx, color_by, opengl_initialized));
return volumes_idx;
}
int GLVolumeCollection::load_object_volume(
const ModelObject* model_object,
int obj_idx,
int volume_idx,
int instance_idx,
const std::string& color_by)
const ModelObject *model_object,
int obj_idx,
int volume_idx,
int instance_idx,
const std::string &color_by,
bool opengl_initialized)
{
const ModelVolume* model_volume = model_object->volumes[volume_idx];
const int extruder_id = model_volume->extruder_id();
const ModelInstance* instance = model_object->instances[instance_idx];
const TriangleMesh& mesh = model_volume->mesh();
float color[4];
const ModelVolume *model_volume = model_object->volumes[volume_idx];
const int extruder_id = model_volume->extruder_id();
const ModelInstance *instance = model_object->instances[instance_idx];
const TriangleMesh &mesh = model_volume->mesh();
float color[4];
memcpy(color, GLVolume::MODEL_COLOR[((color_by == "volume") ? volume_idx : obj_idx) % 4], sizeof(float) * 3);
/* if (model_volume->is_support_blocker()) {
color[0] = 1.0f;
@ -455,6 +452,7 @@ int GLVolumeCollection::load_object_volume(
GLVolume& v = *this->volumes.back();
v.set_color_from_model_volume(model_volume);
v.indexed_vertex_array.load_mesh(mesh);
v.indexed_vertex_array.finalize_geometry(opengl_initialized);
v.composite_id = GLVolume::CompositeID(obj_idx, volume_idx, instance_idx);
if (model_volume->is_model_part())
{
@ -475,13 +473,14 @@ int GLVolumeCollection::load_object_volume(
// This function produces volumes for multiple instances in a single shot,
// as some object specific mesh conversions may be expensive.
void GLVolumeCollection::load_object_auxiliary(
const SLAPrintObject* print_object,
const SLAPrintObject *print_object,
int obj_idx,
// pairs of <instance_idx, print_instance_idx>
const std::vector<std::pair<size_t, size_t>>& instances,
SLAPrintObjectStep milestone,
// Timestamp of the last change of the milestone
size_t timestamp)
size_t timestamp,
bool opengl_initialized)
{
assert(print_object->is_step_done(milestone));
Transform3d mesh_trafo_inv = print_object->trafo().inverse();
@ -495,6 +494,7 @@ void GLVolumeCollection::load_object_auxiliary(
this->volumes.emplace_back(new GLVolume((milestone == slaposBasePool) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR));
GLVolume& v = *this->volumes.back();
v.indexed_vertex_array.load_mesh(mesh);
v.indexed_vertex_array.finalize_geometry(opengl_initialized);
v.composite_id = GLVolume::CompositeID(obj_idx, -int(milestone), (int)instance_idx.first);
v.geometry_id = std::pair<size_t, size_t>(timestamp, model_instance.id().id);
// Create a copy of the convex hull mesh for each instance. Use a move operator on the last instance.
@ -511,7 +511,7 @@ void GLVolumeCollection::load_object_auxiliary(
}
int GLVolumeCollection::load_wipe_tower_preview(
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width)
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width, bool opengl_initialized)
{
if (depth < 0.01f)
return int(this->volumes.size() - 1);
@ -564,6 +564,7 @@ int GLVolumeCollection::load_wipe_tower_preview(
this->volumes.emplace_back(new GLVolume(color));
GLVolume& v = *this->volumes.back();
v.indexed_vertex_array.load_mesh(mesh);
v.indexed_vertex_array.finalize_geometry(opengl_initialized);
v.set_volume_offset(Vec3d(pos_x, pos_y, 0.0));
v.set_volume_rotation(Vec3d(0., 0., (M_PI / 180.) * rotation_angle));
v.composite_id = GLVolume::CompositeID(obj_idx, 0, 0);
@ -823,6 +824,27 @@ std::vector<double> GLVolumeCollection::get_current_print_zs(bool active_only) c
return print_zs;
}
size_t GLVolumeCollection::cpu_memory_used() const
{
size_t memsize = sizeof(*this) + this->volumes.capacity() * sizeof(GLVolume);
for (const GLVolume *volume : this->volumes)
memsize += volume->cpu_memory_used();
return memsize;
}
size_t GLVolumeCollection::gpu_memory_used() const
{
size_t memsize = 0;
for (const GLVolume *volume : this->volumes)
memsize += volume->gpu_memory_used();
return memsize;
}
std::string GLVolumeCollection::log_memory_info() const
{
return " (GLVolumeCollection RAM: " + format_memsize_MB(this->cpu_memory_used()) + " GPU: " + format_memsize_MB(this->gpu_memory_used()) + " Both: " + format_memsize_MB(this->gpu_memory_used()) + ")";
}
// caller is responsible for supplying NO lines with zero length
static void thick_lines_to_indexed_vertex_array(
const Lines &lines,
@ -1598,6 +1620,7 @@ bool GLArrow::on_init()
triangles.emplace_back(7, 13, 6);
m_volume.indexed_vertex_array.load_mesh(TriangleMesh(vertices, triangles));
m_volume.indexed_vertex_array.finalize_geometry(true);
return true;
}
@ -1711,6 +1734,7 @@ bool GLCurvedArrow::on_init()
triangles.emplace_back(vertices_per_level, 2 * vertices_per_level + 1, vertices_per_level + 1);
m_volume.indexed_vertex_array.load_mesh(TriangleMesh(vertices, triangles));
m_volume.indexed_vertex_array.finalize_geometry(true);
return true;
}
@ -1737,6 +1761,7 @@ bool GLBed::on_init_from_file(const std::string& filename)
m_filename = filename;
m_volume.indexed_vertex_array.load_mesh(model.mesh());
m_volume.indexed_vertex_array.finalize_geometry(true);
float color[4] = { 0.235f, 0.235f, 0.235f, 1.0f };
set_color(color, 4);