Attempt to fix #35041 and #34725: cycles crash with OSL and both a 3D viewport

and preview running at the same time.

It seems there's something in OSL/LLVM that's not thread safe, but I couldn't
figure out what exactly. Now all renders share the same OSL ShadingSystem which
should avoid the problem.
This commit is contained in:
Brecht Van Lommel 2013-04-22 14:27:12 +00:00
parent 919ecbe55d
commit dee74c299f
5 changed files with 106 additions and 51 deletions

@ -469,6 +469,8 @@ enum ShaderDataFlag {
SD_TRANSFORM_APPLIED = 32768 /* vertices have transform applied */ SD_TRANSFORM_APPLIED = 32768 /* vertices have transform applied */
}; };
struct KernelGlobals;
typedef struct ShaderData { typedef struct ShaderData {
/* position */ /* position */
float3 P; float3 P;
@ -536,6 +538,10 @@ typedef struct ShaderData {
/* Closure data, with a single sampled closure for low memory usage */ /* Closure data, with a single sampled closure for low memory usage */
ShaderClosure closure; ShaderClosure closure;
#endif #endif
#ifdef __OSL__
struct KernelGlobals *osl_globals;
#endif
} ShaderData; } ShaderData;
/* Constrant Kernel Data /* Constrant Kernel Data

@ -112,8 +112,8 @@ bool OSLRenderServices::get_matrix(OSL::Matrix44 &result, OSL::TransformationPtr
/* this is only used for shader and object space, we don't really have /* this is only used for shader and object space, we don't really have
* a concept of shader space, so we just use object space for both. */ * a concept of shader space, so we just use object space for both. */
if (xform) { if (xform) {
KernelGlobals *kg = kernel_globals;
const ShaderData *sd = (const ShaderData *)xform; const ShaderData *sd = (const ShaderData *)xform;
KernelGlobals *kg = sd->osl_globals;
int object = sd->object; int object = sd->object;
if (object != ~0) { if (object != ~0) {
@ -142,8 +142,8 @@ bool OSLRenderServices::get_inverse_matrix(OSL::Matrix44 &result, OSL::Transform
/* this is only used for shader and object space, we don't really have /* this is only used for shader and object space, we don't really have
* a concept of shader space, so we just use object space for both. */ * a concept of shader space, so we just use object space for both. */
if (xform) { if (xform) {
KernelGlobals *kg = kernel_globals;
const ShaderData *sd = (const ShaderData *)xform; const ShaderData *sd = (const ShaderData *)xform;
KernelGlobals *kg = sd->osl_globals;
int object = sd->object; int object = sd->object;
if (object != ~0) { if (object != ~0) {
@ -235,7 +235,7 @@ bool OSLRenderServices::get_matrix(OSL::Matrix44 &result, OSL::TransformationPtr
#ifdef __OBJECT_MOTION__ #ifdef __OBJECT_MOTION__
Transform tfm = sd->ob_tfm; Transform tfm = sd->ob_tfm;
#else #else
KernelGlobals *kg = kernel_globals; KernelGlobals *kg = sd->osl_globals;
Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM); Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
#endif #endif
tfm = transform_transpose(tfm); tfm = transform_transpose(tfm);
@ -260,7 +260,7 @@ bool OSLRenderServices::get_inverse_matrix(OSL::Matrix44 &result, OSL::Transform
#ifdef __OBJECT_MOTION__ #ifdef __OBJECT_MOTION__
Transform tfm = sd->ob_itfm; Transform tfm = sd->ob_itfm;
#else #else
KernelGlobals *kg = kernel_globals; KernelGlobals *kg = sd->osl_globals;
Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM); Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
#endif #endif
tfm = transform_transpose(tfm); tfm = transform_transpose(tfm);
@ -662,8 +662,8 @@ bool OSLRenderServices::get_background_attribute(KernelGlobals *kg, ShaderData *
bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustring object_name, bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustring object_name,
TypeDesc type, ustring name, void *val) TypeDesc type, ustring name, void *val)
{ {
KernelGlobals *kg = kernel_globals;
ShaderData *sd = (ShaderData *)renderstate; ShaderData *sd = (ShaderData *)renderstate;
KernelGlobals *kg = sd->osl_globals;
int object, prim, segment; int object, prim, segment;
/* lookup of attribute on another object */ /* lookup of attribute on another object */
@ -861,7 +861,7 @@ bool OSLRenderServices::trace(TraceOpt &options, OSL::ShaderGlobals *sg,
tracedata->init = true; tracedata->init = true;
/* raytrace */ /* raytrace */
return scene_intersect(kernel_globals, &ray, ~0, &tracedata->isect); return scene_intersect(sd->osl_globals, &ray, ~0, &tracedata->isect);
} }
@ -880,8 +880,8 @@ bool OSLRenderServices::getmessage(OSL::ShaderGlobals *sg, ustring source, ustri
return set_attribute_float(f, type, derivatives, val); return set_attribute_float(f, type, derivatives, val);
} }
else { else {
KernelGlobals *kg = kernel_globals;
ShaderData *sd = &tracedata->sd; ShaderData *sd = &tracedata->sd;
KernelGlobals *kg = sd->osl_globals;
if(!tracedata->setup) { if(!tracedata->setup) {
/* lazy shader data setup */ /* lazy shader data setup */

@ -127,6 +127,9 @@ static void shaderdata_to_shaderglobals(KernelGlobals *kg, ShaderData *sd,
/* clear trace data */ /* clear trace data */
tdata->tracedata.init = false; tdata->tracedata.init = false;
/* used by renderservices */
sd->osl_globals = kg;
} }
/* Surface */ /* Surface */

@ -41,46 +41,35 @@ CCL_NAMESPACE_BEGIN
#ifdef WITH_OSL #ifdef WITH_OSL
/* Shared Texture System */ /* Shared Texture and Shading System */
OSL::TextureSystem *OSLShaderManager::ts_shared = NULL; OSL::TextureSystem *OSLShaderManager::ts_shared = NULL;
int OSLShaderManager::ts_shared_users = 0; int OSLShaderManager::ts_shared_users = 0;
thread_mutex OSLShaderManager::ts_shared_mutex; thread_mutex OSLShaderManager::ts_shared_mutex;
OSL::ShadingSystem *OSLShaderManager::ss_shared = NULL;
OSLRenderServices *OSLShaderManager::services_shared = NULL;
int OSLShaderManager::ss_shared_users = 0;
thread_mutex OSLShaderManager::ss_shared_mutex;
thread_mutex OSLShaderManager::ss_mutex;
/* Shader Manager */ /* Shader Manager */
OSLShaderManager::OSLShaderManager() OSLShaderManager::OSLShaderManager()
{ {
services = new OSLRenderServices();
texture_system_init(); texture_system_init();
shading_system_init(); shading_system_init();
} }
OSLShaderManager::~OSLShaderManager() OSLShaderManager::~OSLShaderManager()
{ {
OSL::ShadingSystem::destroy(ss); shading_system_free();
texture_system_free();
/* shared texture system decrease users and destroy if no longer used */
{
thread_scoped_lock lock(ts_shared_mutex);
ts_shared_users--;
if(ts_shared_users == 0) {
OSL::TextureSystem::destroy(ts_shared);
ts_shared = NULL;
}
}
delete services;
} }
void OSLShaderManager::reset(Scene *scene) void OSLShaderManager::reset(Scene *scene)
{ {
OSL::ShadingSystem::destroy(ss); shading_system_free();
delete services;
services = new OSLRenderServices();
shading_system_init(); shading_system_init();
} }
@ -102,6 +91,11 @@ void OSLShaderManager::device_update(Device *device, DeviceScene *dscene, Scene
if(progress.get_cancel()) return; if(progress.get_cancel()) return;
/* we can only compile one shader at the time as the OSL ShadingSytem
* has a single state, but we put the lock here so different renders can
* compile shaders alternating */
thread_scoped_lock lock(ss_mutex);
OSLCompiler compiler((void*)this, (void*)ss, scene->image_manager); OSLCompiler compiler((void*)this, (void*)ss, scene->image_manager);
compiler.background = (shader == scene->shaders[scene->default_background]); compiler.background = (shader == scene->shaders[scene->default_background]);
compiler.compile(og, shader); compiler.compile(og, shader);
@ -167,35 +161,78 @@ void OSLShaderManager::texture_system_init()
ts_shared_users++; ts_shared_users++;
} }
void OSLShaderManager::texture_system_free()
{
/* shared texture system decrease users and destroy if no longer used */
thread_scoped_lock lock(ts_shared_mutex);
ts_shared_users--;
if(ts_shared_users == 0) {
OSL::TextureSystem::destroy(ts_shared);
ts_shared = NULL;
}
ts = NULL;
}
void OSLShaderManager::shading_system_init() void OSLShaderManager::shading_system_init()
{ {
ss = OSL::ShadingSystem::create(services, ts, &errhandler); /* create shading system, shared between different renders to reduce memory usage */
ss->attribute("lockgeom", 1); thread_scoped_lock lock(ss_shared_mutex);
ss->attribute("commonspace", "world");
ss->attribute("optimize", 2);
//ss->attribute("debug", 1);
//ss->attribute("statistics:level", 1);
ss->attribute("searchpath:shader", path_get("shader"));
/* our own ray types */ if(ss_shared_users == 0) {
static const char *raytypes[] = { services_shared = new OSLRenderServices();
"camera", /* PATH_RAY_CAMERA */
"reflection", /* PATH_RAY_REFLECT */
"refraction", /* PATH_RAY_TRANSMIT */
"diffuse", /* PATH_RAY_DIFFUSE */
"glossy", /* PATH_RAY_GLOSSY */
"singular", /* PATH_RAY_SINGULAR */
"transparent", /* PATH_RAY_TRANSPARENT */
"shadow", /* PATH_RAY_SHADOW_OPAQUE */
"shadow", /* PATH_RAY_SHADOW_TRANSPARENT */
};
const int nraytypes = sizeof(raytypes)/sizeof(raytypes[0]); ss_shared = OSL::ShadingSystem::create(services_shared, ts_shared, &errhandler);
ss->attribute("raytypes", TypeDesc(TypeDesc::STRING, nraytypes), raytypes); ss_shared->attribute("lockgeom", 1);
ss_shared->attribute("commonspace", "world");
ss_shared->attribute("optimize", 2);
//ss_shared->attribute("debug", 1);
//ss_shared->attribute("statistics:level", 1);
ss_shared->attribute("searchpath:shader", path_get("shader"));
OSLShader::register_closures((OSLShadingSystem*)ss); /* our own ray types */
static const char *raytypes[] = {
"camera", /* PATH_RAY_CAMERA */
"reflection", /* PATH_RAY_REFLECT */
"refraction", /* PATH_RAY_TRANSMIT */
"diffuse", /* PATH_RAY_DIFFUSE */
"gloss_sharedy", /* PATH_RAY_GLOSSY */
"singular", /* PATH_RAY_SINGULAR */
"transparent", /* PATH_RAY_TRANSPARENT */
"shadow", /* PATH_RAY_SHADOW_OPAQUE */
"shadow", /* PATH_RAY_SHADOW_TRANSPARENT */
};
loaded_shaders.clear(); const int nraytypes = sizeof(raytypes)/sizeof(raytypes[0]);
ss_shared->attribute("raytypes", TypeDesc(TypeDesc::STRING, nraytypes), raytypes);
OSLShader::register_closures((OSLShadingSystem*)ss_shared);
loaded_shaders.clear();
}
ss = ss_shared;
services = services_shared;
ss_shared_users++;
}
void OSLShaderManager::shading_system_free()
{
/* shared shading system decrease users and destroy if no longer used */
thread_scoped_lock lock(ss_shared_mutex);
ss_shared_users--;
if(ss_shared_users == 0) {
OSL::ShadingSystem::destroy(ss_shared);
ss_shared = NULL;
delete services_shared;
services_shared = NULL;
}
ss = NULL;
services = NULL;
} }
bool OSLShaderManager::osl_compile(const string& inputfile, const string& outputfile) bool OSLShaderManager::osl_compile(const string& inputfile, const string& outputfile)

@ -86,7 +86,10 @@ public:
protected: protected:
void texture_system_init(); void texture_system_init();
void texture_system_free();
void shading_system_init(); void shading_system_init();
void shading_system_free();
OSL::ShadingSystem *ss; OSL::ShadingSystem *ss;
OSL::TextureSystem *ts; OSL::TextureSystem *ts;
@ -97,6 +100,12 @@ protected:
static OSL::TextureSystem *ts_shared; static OSL::TextureSystem *ts_shared;
static thread_mutex ts_shared_mutex; static thread_mutex ts_shared_mutex;
static int ts_shared_users; static int ts_shared_users;
static OSL::ShadingSystem *ss_shared;
static OSLRenderServices *services_shared;
static thread_mutex ss_shared_mutex;
static thread_mutex ss_mutex;
static int ss_shared_users;
}; };
#endif #endif