Delayed loading of the opengl texture for the G-code preview legend,

as the opengl context may not be ready on some platforms (Linux)
at the time the window gets its focus for the first time.

Changed the G-code preview invalidation to trigger when the print
gets invalidated. At that time the 3D path preview switches to the old
preview, if there is anything valid left.
This commit is contained in:
bubnikv 2018-02-15 14:37:53 +01:00
parent b5bdb46268
commit f9cdda7bfd
6 changed files with 68 additions and 79 deletions

View File

@ -1602,7 +1602,8 @@ sub draw_legend {
if ($self->_legend_enabled) if ($self->_legend_enabled)
{ {
my $tex_id = Slic3r::GUI::_3DScene::get_legend_texture_id; # If the legend texture has not been loaded into the GPU, do it now.
my $tex_id = Slic3r::GUI::_3DScene::finalize_legend_texture;
if ($tex_id > 0) if ($tex_id > 0)
{ {
my $tex_w = Slic3r::GUI::_3DScene::get_legend_texture_width; my $tex_w = Slic3r::GUI::_3DScene::get_legend_texture_width;

View File

@ -786,7 +786,6 @@ sub remove {
splice @{$self->{objects}}, $obj_idx, 1; splice @{$self->{objects}}, $obj_idx, 1;
$self->{model}->delete_object($obj_idx); $self->{model}->delete_object($obj_idx);
$self->{print}->delete_object($obj_idx); $self->{print}->delete_object($obj_idx);
$self->{gcode_preview_data}->reset;
$self->{list}->DeleteItem($obj_idx); $self->{list}->DeleteItem($obj_idx);
$self->object_list_changed; $self->object_list_changed;
@ -807,7 +806,6 @@ sub reset {
@{$self->{objects}} = (); @{$self->{objects}} = ();
$self->{model}->clear_objects; $self->{model}->clear_objects;
$self->{print}->clear_objects; $self->{print}->clear_objects;
$self->{gcode_preview_data}->reset;
$self->{list}->DeleteAllItems; $self->{list}->DeleteAllItems;
$self->object_list_changed; $self->object_list_changed;
@ -1161,6 +1159,7 @@ sub async_apply_config {
# Reset preview canvases. If the print has been invalidated, the preview canvases will be cleared. # Reset preview canvases. If the print has been invalidated, the preview canvases will be cleared.
# Otherwise they will be just refreshed. # Otherwise they will be just refreshed.
if ($invalidated) { if ($invalidated) {
$self->{gcode_preview_data}->reset;
$self->{toolpaths2D}->reload_print if $self->{toolpaths2D}; $self->{toolpaths2D}->reload_print if $self->{toolpaths2D};
$self->{preview3D}->reload_print if $self->{preview3D}; $self->{preview3D}->reload_print if $self->{preview3D};
} }
@ -1267,8 +1266,6 @@ sub reslice {
$self->stop_background_process; $self->stop_background_process;
# Rather perform one additional unnecessary update of the print object instead of skipping a pending async update. # Rather perform one additional unnecessary update of the print object instead of skipping a pending async update.
$self->async_apply_config; $self->async_apply_config;
# Reset gcode data
$self->{gcode_preview_data}->reset;
$self->statusbar->SetCancelCallback(sub { $self->statusbar->SetCancelCallback(sub {
$self->stop_background_process; $self->stop_background_process;
$self->statusbar->SetStatusText("Slicing cancelled"); $self->statusbar->SetStatusText("Slicing cancelled");

View File

@ -776,7 +776,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
_writeln(file, this->placeholder_parser_process("end_filament_gcode", print.config.end_filament_gcode.get_at(m_writer.extruder()->id()), m_writer.extruder()->id())); _writeln(file, this->placeholder_parser_process("end_filament_gcode", print.config.end_filament_gcode.get_at(m_writer.extruder()->id()), m_writer.extruder()->id()));
} else { } else {
for (const std::string &end_gcode : print.config.end_filament_gcode.values) for (const std::string &end_gcode : print.config.end_filament_gcode.values)
_writeln(file, this->placeholder_parser_process("end_gcode", end_gcode, (unsigned int)(&end_gcode - &print.config.end_filament_gcode.values.front()))); _writeln(file, this->placeholder_parser_process("end_filament_gcode", end_gcode, (unsigned int)(&end_gcode - &print.config.end_filament_gcode.values.front())));
} }
_writeln(file, this->placeholder_parser_process("end_gcode", print.config.end_gcode, m_writer.extruder()->id())); _writeln(file, this->placeholder_parser_process("end_gcode", print.config.end_gcode, m_writer.extruder()->id()));
_write(file, m_writer.update_progress(m_layer_count, m_layer_count, true)); // 100% _write(file, m_writer.update_progress(m_layer_count, m_layer_count, true)); // 100%

View File

@ -1117,21 +1117,12 @@ const unsigned char _3DScene::LegendTexture::Squares_Border_Color[3] = { 64, 64,
const unsigned char _3DScene::LegendTexture::Background_Color[3] = { 9, 91, 134 }; const unsigned char _3DScene::LegendTexture::Background_Color[3] = { 9, 91, 134 };
const unsigned char _3DScene::LegendTexture::Opacity = 255; const unsigned char _3DScene::LegendTexture::Opacity = 255;
_3DScene::LegendTexture::LegendTexture() // Generate a texture data, but don't load it into the GPU yet, as the GPU context may not yet be valid.
: m_tex_id(0) bool _3DScene::LegendTexture::generate(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors)
, m_tex_width(0)
, m_tex_height(0)
{ {
} // Mark the texture as released, but don't release the texture from the GPU yet.
m_tex_width = m_tex_height = 0;
_3DScene::LegendTexture::~LegendTexture() m_data.clear();
{
_destroy_texture();
}
bool _3DScene::LegendTexture::generate_texture(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors)
{
_destroy_texture();
// collects items to render // collects items to render
const std::string& title = preview_data.get_legend_title(); const std::string& title = preview_data.get_legend_title();
@ -1241,64 +1232,45 @@ bool _3DScene::LegendTexture::generate_texture(const GCodePreviewData& preview_d
memDC.SelectObject(wxNullBitmap); memDC.SelectObject(wxNullBitmap);
return _create_texture(preview_data, bitmap); // Convert the bitmap into a linear data ready to be loaded into the GPU.
}
unsigned int _3DScene::LegendTexture::get_texture_id() const
{
return m_tex_id;
}
unsigned int _3DScene::LegendTexture::get_texture_width() const
{
return m_tex_width;
}
unsigned int _3DScene::LegendTexture::get_texture_height() const
{
return m_tex_height;
}
void _3DScene::LegendTexture::reset_texture()
{
_destroy_texture();
}
bool _3DScene::LegendTexture::_create_texture(const GCodePreviewData& preview_data, const wxBitmap& bitmap)
{
if ((m_tex_width == 0) || (m_tex_height == 0))
return false;
wxImage image = bitmap.ConvertToImage();
image.SetMaskColour(Background_Color[0], Background_Color[1], Background_Color[2]);
// prepare buffer
std::vector<unsigned char> buffer(4 * m_tex_width * m_tex_height, 0);
for (unsigned int h = 0; h < m_tex_height; ++h)
{ {
unsigned int hh = h * m_tex_width; wxImage image = bitmap.ConvertToImage();
for (unsigned int w = 0; w < m_tex_width; ++w) image.SetMaskColour(Background_Color[0], Background_Color[1], Background_Color[2]);
// prepare buffer
m_data.assign(4 * m_tex_width * m_tex_height, 0);
for (unsigned int h = 0; h < m_tex_height; ++h)
{ {
unsigned char* px_ptr = buffer.data() + 4 * (hh + w); unsigned int hh = h * m_tex_width;
*px_ptr++ = image.GetRed(w, h); unsigned char* px_ptr = m_data.data() + 4 * hh;
*px_ptr++ = image.GetGreen(w, h); for (unsigned int w = 0; w < m_tex_width; ++w)
*px_ptr++ = image.GetBlue(w, h); {
*px_ptr++ = image.IsTransparent(w, h) ? 0 : Opacity; *px_ptr++ = image.GetRed(w, h);
*px_ptr++ = image.GetGreen(w, h);
*px_ptr++ = image.GetBlue(w, h);
*px_ptr++ = image.IsTransparent(w, h) ? 0 : Opacity;
}
} }
} }
// sends buffer to gpu
::glGenTextures(1, &m_tex_id);
::glBindTexture(GL_TEXTURE_2D, m_tex_id);
::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)m_tex_width, (GLsizei)m_tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid*)buffer.data());
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
::glBindTexture(GL_TEXTURE_2D, 0);
return true; return true;
} }
unsigned int _3DScene::LegendTexture::finalize()
{
if (! m_data.empty()) {
// sends buffer to gpu
::glGenTextures(1, &m_tex_id);
::glBindTexture(GL_TEXTURE_2D, m_tex_id);
::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)m_tex_width, (GLsizei)m_tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid*)m_data.data());
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
::glBindTexture(GL_TEXTURE_2D, 0);
m_data.clear();
}
return (m_tex_width > 0 && m_tex_height > 0) ? m_tex_id : 0;
}
void _3DScene::LegendTexture::_destroy_texture() void _3DScene::LegendTexture::_destroy_texture()
{ {
if (m_tex_id > 0) if (m_tex_id > 0)
@ -1308,6 +1280,7 @@ void _3DScene::LegendTexture::_destroy_texture()
m_tex_height = 0; m_tex_height = 0;
m_tex_width = 0; m_tex_width = 0;
} }
m_data.clear();
} }
void _3DScene::_glew_init() void _3DScene::_glew_init()
@ -2267,7 +2240,12 @@ void _3DScene::_update_gcode_volumes_visibility(const GCodePreviewData& preview_
void _3DScene::_generate_legend_texture(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors) void _3DScene::_generate_legend_texture(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors)
{ {
s_legend_texture.generate_texture(preview_data, tool_colors); s_legend_texture.generate(preview_data, tool_colors);
}
unsigned int _3DScene::finalize_legend_texture()
{
return s_legend_texture.finalize();
} }
void _3DScene::_load_shells(const Print& print, GLVolumeCollection& volumes, bool use_VBOs) void _3DScene::_load_shells(const Print& print, GLVolumeCollection& volumes, bool use_VBOs)

View File

@ -421,20 +421,25 @@ class _3DScene
unsigned int m_tex_height; unsigned int m_tex_height;
public: public:
LegendTexture(); LegendTexture() : m_tex_id(0), m_tex_width(0), m_tex_height(0) {}
~LegendTexture(); ~LegendTexture() { _destroy_texture(); }
bool generate_texture(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors); // Generate a texture data, but don't load it into the GPU yet, as the glcontext may not be valid yet.
bool generate(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors);
// If not loaded, load the texture data into the GPU. Return a texture ID or 0 if the texture has zero size.
unsigned int finalize();
unsigned int get_texture_id() const; unsigned int get_texture_id() const { return m_tex_id; }
unsigned int get_texture_width() const; unsigned int get_texture_width() const { return m_tex_width; }
unsigned int get_texture_height() const; unsigned int get_texture_height() const { return m_tex_height; }
void reset_texture(); void reset_texture() { _destroy_texture(); }
private: private:
bool _create_texture(const GCodePreviewData& preview_data, const wxBitmap& bitmap); bool _create_texture(const GCodePreviewData& preview_data, const wxBitmap& bitmap);
void _destroy_texture(); void _destroy_texture();
// generate() fills in m_data with the pixels, while finalize() moves the data to the GPU before rendering.
std::vector<unsigned char> m_data;
}; };
static LegendTexture s_legend_texture; static LegendTexture s_legend_texture;
@ -449,6 +454,7 @@ public:
static unsigned int get_legend_texture_height(); static unsigned int get_legend_texture_height();
static void reset_legend_texture(); static void reset_legend_texture();
static unsigned int finalize_legend_texture();
static void _load_print_toolpaths( static void _load_print_toolpaths(
const Print *print, const Print *print,

View File

@ -141,6 +141,13 @@ _glew_init()
CODE: CODE:
_3DScene::_glew_init(); _3DScene::_glew_init();
unsigned int
finalize_legend_texture()
CODE:
RETVAL = _3DScene::finalize_legend_texture();
OUTPUT:
RETVAL
unsigned int unsigned int
get_legend_texture_id() get_legend_texture_id()
CODE: CODE: