Fix T44404: freestyle crashes blender.
The reported crash case seems to be caused by freeing compiled Python objects in a thread. Now this issue is avoided by allocating a buffer to store a Python script and using BPY_string_exec() to run the script. This makes it unnecessary to repeatedly create and destroy Text data blocks. Many thanks to Campbell Barton for his help on the bug fix.
This commit is contained in:
@@ -927,6 +927,12 @@ void Controller::InsertStyleModule(unsigned index, const char *iFileName)
|
||||
_Canvas->InsertStyleModule(index, sm);
|
||||
}
|
||||
|
||||
void Controller::InsertStyleModule(unsigned index, const char *iName, const char *iBuffer)
|
||||
{
|
||||
StyleModule *sm = new BufferedStyleModule(iBuffer, iName, _inter);
|
||||
_Canvas->InsertStyleModule(index, sm);
|
||||
}
|
||||
|
||||
void Controller::InsertStyleModule(unsigned index, const char *iName, struct Text *iText)
|
||||
{
|
||||
StyleModule *sm = new BlenderStyleModule(iText, iName, _inter);
|
||||
|
||||
@@ -90,6 +90,7 @@ public:
|
||||
Render *RenderStrokes(Render *re, bool render);
|
||||
void SwapStyleModules(unsigned i1, unsigned i2);
|
||||
void InsertStyleModule(unsigned index, const char *iFileName);
|
||||
void InsertStyleModule(unsigned index, const char *iName, const char *iBuffer);
|
||||
void InsertStyleModule(unsigned index, const char *iName, struct Text *iText);
|
||||
void AddStyleModule(const char *iFileName);
|
||||
void RemoveStyleModule(unsigned index);
|
||||
|
||||
@@ -36,6 +36,34 @@ struct Text;
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
class BufferedStyleModule : public StyleModule
|
||||
{
|
||||
public:
|
||||
BufferedStyleModule(const string& buffer, const string& file_name, Interpreter *inter) : StyleModule(file_name, inter)
|
||||
{
|
||||
_buffer = buffer;
|
||||
}
|
||||
|
||||
virtual ~BufferedStyleModule()
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual int interpret()
|
||||
{
|
||||
PythonInterpreter *py_inter = dynamic_cast<PythonInterpreter*>(_inter);
|
||||
BLI_assert(py_inter != 0);
|
||||
return py_inter->interpretString(_buffer, getFileName());
|
||||
}
|
||||
|
||||
private:
|
||||
string _buffer;
|
||||
|
||||
#ifdef WITH_CXX_GUARDEDALLOC
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:BufferedStyleModule")
|
||||
#endif
|
||||
};
|
||||
|
||||
class BlenderStyleModule : public StyleModule
|
||||
{
|
||||
public:
|
||||
@@ -62,7 +90,6 @@ private:
|
||||
#ifdef WITH_CXX_GUARDEDALLOC
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:BlenderStyleModule")
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
} /* namespace Freestyle */
|
||||
|
||||
@@ -211,16 +211,12 @@ static char *escape_quotes(char *name)
|
||||
return s;
|
||||
}
|
||||
|
||||
static Text *create_lineset_handler(Main *bmain, char *layer_name, char *lineset_name)
|
||||
static char * create_lineset_handler(char *layer_name, char *lineset_name)
|
||||
{
|
||||
char *fmt = "__import__('parameter_editor').process('%s', '%s')\n";
|
||||
char *s1 = escape_quotes(layer_name);
|
||||
char *s2 = escape_quotes(lineset_name);
|
||||
Text *text = BKE_text_add(bmain, lineset_name);
|
||||
BKE_text_write(text, "import parameter_editor; parameter_editor.process('");
|
||||
BKE_text_write(text, s1);
|
||||
BKE_text_write(text, "', '");
|
||||
BKE_text_write(text, s2);
|
||||
BKE_text_write(text, "')\n");
|
||||
char *text = BLI_sprintfN(fmt, s1, s2);
|
||||
MEM_freeN(s1);
|
||||
MEM_freeN(s2);
|
||||
return text;
|
||||
@@ -293,7 +289,7 @@ static bool test_edge_type_conditions(struct edge_type_condition *conditions,
|
||||
return true;
|
||||
}
|
||||
|
||||
static void prepare(Main *bmain, Render *re, SceneRenderLayer *srl)
|
||||
static void prepare(Render *re, SceneRenderLayer *srl)
|
||||
{
|
||||
// load mesh
|
||||
re->i.infostr = "Freestyle: Mesh loading";
|
||||
@@ -369,9 +365,10 @@ static void prepare(Main *bmain, Render *re, SceneRenderLayer *srl)
|
||||
cout << " " << layer_count+1 << ": " << lineset->name << " - " <<
|
||||
(lineset->linestyle ? (lineset->linestyle->id.name + 2) : "<NULL>") << endl;
|
||||
}
|
||||
Text *text = create_lineset_handler(bmain, srl->name, lineset->name);
|
||||
controller->InsertStyleModule(layer_count, lineset->name, text);
|
||||
char *buffer = create_lineset_handler(srl->name, lineset->name);
|
||||
controller->InsertStyleModule(layer_count, lineset->name, buffer);
|
||||
controller->toggleLayer(layer_count, true);
|
||||
MEM_freeN(buffer);
|
||||
if (!(lineset->selection & FREESTYLE_SEL_EDGE_TYPES) || !lineset->edge_types) {
|
||||
++use_ridges_and_valleys;
|
||||
++use_suggestive_contours;
|
||||
@@ -584,9 +581,7 @@ void FRS_init_stroke_rendering(Render *re)
|
||||
|
||||
Render *FRS_do_stroke_rendering(Render *re, SceneRenderLayer *srl, int render)
|
||||
{
|
||||
Main *freestyle_bmain = re->freestyle_bmain;
|
||||
Render *freestyle_render = NULL;
|
||||
Text *text, *next_text;
|
||||
|
||||
if (!render)
|
||||
return controller->RenderStrokes(re, false);
|
||||
@@ -607,7 +602,7 @@ Render *FRS_do_stroke_rendering(Render *re, SceneRenderLayer *srl, int render)
|
||||
// - add style modules
|
||||
// - set parameters
|
||||
// - compute view map
|
||||
prepare(freestyle_bmain, re, srl);
|
||||
prepare(re, srl);
|
||||
|
||||
if (re->test_break(re->tbh)) {
|
||||
controller->CloseFile();
|
||||
@@ -635,14 +630,6 @@ Render *FRS_do_stroke_rendering(Render *re, SceneRenderLayer *srl, int render)
|
||||
}
|
||||
}
|
||||
|
||||
// Free temp main (currently only text blocks are stored there)
|
||||
for (text = (Text *)freestyle_bmain->text.first; text; text = next_text) {
|
||||
next_text = (Text *) text->id.next;
|
||||
|
||||
BKE_text_unlink(freestyle_bmain, text);
|
||||
BKE_libblock_free(freestyle_bmain, text);
|
||||
}
|
||||
|
||||
return freestyle_render;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,8 @@ extern "C" {
|
||||
#include "BKE_text.h"
|
||||
|
||||
#include "BPY_extern.h"
|
||||
|
||||
#include "bpy_util.h"
|
||||
}
|
||||
|
||||
namespace Freestyle {
|
||||
@@ -105,6 +107,26 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int interpretString(const string& str, const string& name)
|
||||
{
|
||||
ReportList *reports = CTX_wm_reports(_context);
|
||||
|
||||
BKE_reports_clear(reports);
|
||||
|
||||
if (BPY_string_exec(_context, str.c_str()) != 0) {
|
||||
BPy_errors_to_report(reports);
|
||||
cerr << "\nError executing Python script from PythonInterpreter::interpretString" << endl;
|
||||
cerr << "Name: " << name << endl;
|
||||
cerr << "Errors: " << endl;
|
||||
BKE_reports_print(reports, RPT_ERROR);
|
||||
return 1;
|
||||
}
|
||||
|
||||
BKE_reports_clear(reports);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int interpretText(struct Text *text, const string& name)
|
||||
{
|
||||
ReportList *reports = CTX_wm_reports(_context);
|
||||
|
||||
Reference in New Issue
Block a user