Cycles OSL minor optimizations: recycle shading context, don't do memory
[blender.git] / intern / cycles / kernel / osl / osl_shader.cpp
index 32712b25e9212806d77808c2a95e85b12452cb8f..f5c04b6755e650a7cbcaf7dbae09f414f2cbf1fa 100644 (file)
@@ -51,8 +51,13 @@ void OSLShader::thread_init(KernelGlobals *kg, KernelGlobals *kernel_globals, OS
        OSLThreadData *tdata = new OSLThreadData();
 
        memset(&tdata->globals, 0, sizeof(OSL::ShaderGlobals));
+       tdata->globals.tracedata = &tdata->tracedata;
+       tdata->globals.flipHandedness = false;
        tdata->thread_info = ss->create_thread_info();
 
+       for(int i = 0; i < SHADER_CONTEXT_NUM; i++)
+               tdata->context[i] = ss->get_context(tdata->thread_info);
+
        kg->osl_ss = (OSLShadingSystem*)ss;
        kg->osl_tdata = tdata;
 }
@@ -65,6 +70,9 @@ void OSLShader::thread_free(KernelGlobals *kg)
        OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
        OSLThreadData *tdata = kg->osl_tdata;
 
+       for(int i = 0; i < SHADER_CONTEXT_NUM; i++)
+               ss->release_context(tdata->context[i]);
+
        ss->destroy_thread_info(tdata->thread_info);
 
        delete tdata;
@@ -77,8 +85,10 @@ void OSLShader::thread_free(KernelGlobals *kg)
 /* Globals */
 
 static void shaderdata_to_shaderglobals(KernelGlobals *kg, ShaderData *sd,
-                                        int path_flag, OSL::ShaderGlobals *globals)
+                                        int path_flag, OSLThreadData *tdata)
 {
+       OSL::ShaderGlobals *globals = &tdata->globals;
+
        /* copy from shader data to shader globals */
        globals->P = TO_VEC3(sd->P);
        globals->dPdx = TO_VEC3(sd->dP.dx);
@@ -100,15 +110,11 @@ static void shaderdata_to_shaderglobals(KernelGlobals *kg, ShaderData *sd,
        globals->time = sd->time;
 
        /* booleans */
-       globals->raytype = path_flag; /* todo: add our own ray types */
+       globals->raytype = path_flag;
        globals->backfacing = (sd->flag & SD_BACKFACING);
 
-       /* don't know yet if we need this */
-       globals->flipHandedness = false;
-       
        /* shader data to be used in services callbacks */
        globals->renderstate = sd; 
-       globals->tracedata = NULL;
 
        /* hacky, we leave it to services to fetch actual object matrix */
        globals->shader2common = sd;
@@ -116,6 +122,9 @@ static void shaderdata_to_shaderglobals(KernelGlobals *kg, ShaderData *sd,
 
        /* must be set to NULL before execute */
        globals->Ci = NULL;
+
+       /* clear trace data */
+       tdata->tracedata.init = false;
 }
 
 /* Surface */
@@ -132,14 +141,10 @@ static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy,
 
                if (prim) {
                        ShaderClosure sc;
-                       sc.prim = prim;
                        sc.weight = weight;
 
                        switch (prim->category()) {
                                case OSL::ClosurePrimitive::BSDF: {
-                                       if (sd->num_closure == MAX_CLOSURE)
-                                               return;
-
                                        CBSDFClosure *bsdf = (CBSDFClosure *)prim;
                                        int scattering = bsdf->scattering();
 
@@ -151,8 +156,13 @@ static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy,
                                        float sample_weight = fabsf(average(weight));
 
                                        sc.sample_weight = sample_weight;
-                                       sc.type = bsdf->shaderclosure_type();
-                                       sc.N = bsdf->sc.N; /* needed for AO */
+
+                                       sc.type = bsdf->sc.type;
+                                       sc.N = bsdf->sc.N;
+                                       sc.T = bsdf->sc.T;
+                                       sc.data0 = bsdf->sc.data0;
+                                       sc.data1 = bsdf->sc.data1;
+                                       sc.prim = bsdf->sc.prim;
 
                                        /* add */
                                        if(sc.sample_weight > 1e-5f && sd->num_closure < MAX_CLOSURE) {
@@ -170,6 +180,7 @@ static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy,
 
                                        sc.sample_weight = sample_weight;
                                        sc.type = CLOSURE_EMISSION_ID;
+                                       sc.prim = NULL;
 
                                        /* flag */
                                        if(sd->num_closure < MAX_CLOSURE) {
@@ -179,14 +190,12 @@ static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy,
                                        break;
                                }
                                case AmbientOcclusion: {
-                                       if (sd->num_closure == MAX_CLOSURE)
-                                               return;
-
                                        /* sample weight */
                                        float sample_weight = fabsf(average(weight));
 
                                        sc.sample_weight = sample_weight;
                                        sc.type = CLOSURE_AMBIENT_OCCLUSION_ID;
+                                       sc.prim = NULL;
 
                                        if(sd->num_closure < MAX_CLOSURE) {
                                                sd->closure[sd->num_closure++] = sc;
@@ -195,11 +204,9 @@ static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy,
                                        break;
                                }
                                case OSL::ClosurePrimitive::Holdout:
-                                       if (sd->num_closure == MAX_CLOSURE)
-                                               return;
-
                                        sc.sample_weight = 0.0f;
                                        sc.type = CLOSURE_HOLDOUT_ID;
+                                       sc.prim = NULL;
 
                                        if(sd->num_closure < MAX_CLOSURE) {
                                                sd->closure[sd->num_closure++] = sc;
@@ -226,26 +233,20 @@ static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy,
        }
 }
 
-void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, float randb, int path_flag)
+void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, float randb, int path_flag, ShaderContext ctx)
 {
-       /* gather pointers */
-       OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
-       OSLThreadData *tdata = kg->osl_tdata;
-       OSL::ShaderGlobals *globals = &tdata->globals;
-       OSL::ShadingContext *ctx = (OSL::ShadingContext *)sd->osl_ctx;
-
        /* setup shader globals from shader data */
-       shaderdata_to_shaderglobals(kg, sd, path_flag, globals);
+       OSLThreadData *tdata = kg->osl_tdata;
+       shaderdata_to_shaderglobals(kg, sd, path_flag, tdata);
 
        /* execute shader for this point */
+       OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
+       OSL::ShaderGlobals *globals = &tdata->globals;
+       OSL::ShadingContext *octx = tdata->context[(int)ctx];
        int shader = sd->shader & SHADER_MASK;
 
        if (kg->osl->surface_state[shader])
-               ss->execute(*ctx, *(kg->osl->surface_state[shader]), *globals);
-
-       /* free trace data */
-       if(globals->tracedata)
-               delete (OSLRenderServices::TraceData*)globals->tracedata;
+               ss->execute(*octx, *(kg->osl->surface_state[shader]), *globals);
 
        /* flatten closure tree */
        sd->num_closure = 0;
@@ -287,24 +288,19 @@ static float3 flatten_background_closure_tree(const OSL::ClosureColor *closure)
        return make_float3(0.0f, 0.0f, 0.0f);
 }
 
-float3 OSLShader::eval_background(KernelGlobals *kg, ShaderData *sd, int path_flag)
+float3 OSLShader::eval_background(KernelGlobals *kg, ShaderData *sd, int path_flag, ShaderContext ctx)
 {
-       /* gather pointers */
-       OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
-       OSLThreadData *tdata = kg->osl_tdata;
-       OSL::ShaderGlobals *globals = &tdata->globals;
-       OSL::ShadingContext *ctx = (OSL::ShadingContext *)sd->osl_ctx;
-
        /* setup shader globals from shader data */
-       shaderdata_to_shaderglobals(kg, sd, path_flag, globals);
+       OSLThreadData *tdata = kg->osl_tdata;
+       shaderdata_to_shaderglobals(kg, sd, path_flag, tdata);
 
        /* execute shader for this point */
-       if (kg->osl->background_state)
-               ss->execute(*ctx, *(kg->osl->background_state), *globals);
+       OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
+       OSL::ShaderGlobals *globals = &tdata->globals;
+       OSL::ShadingContext *octx = tdata->context[(int)ctx];
 
-       /* free trace data */
-       if(globals->tracedata)
-               delete (OSLRenderServices::TraceData*)globals->tracedata;
+       if (kg->osl->background_state)
+               ss->execute(*octx, *(kg->osl->background_state), *globals);
 
        /* return background color immediately */
        if (globals->Ci)
@@ -327,19 +323,16 @@ static void flatten_volume_closure_tree(ShaderData *sd,
 
                if (prim) {
                        ShaderClosure sc;
-                       sc.prim = prim;
                        sc.weight = weight;
 
                        switch (prim->category()) {
                                case OSL::ClosurePrimitive::Volume: {
-                                       if (sd->num_closure == MAX_CLOSURE)
-                                               return;
-
                                        /* sample weight */
                                        float sample_weight = fabsf(average(weight));
 
                                        sc.sample_weight = sample_weight;
                                        sc.type = CLOSURE_VOLUME_ID;
+                                       sc.prim = NULL;
 
                                        /* add */
                                        if(sc.sample_weight > 1e-5f && sd->num_closure < MAX_CLOSURE)
@@ -368,26 +361,20 @@ static void flatten_volume_closure_tree(ShaderData *sd,
        }
 }
 
-void OSLShader::eval_volume(KernelGlobals *kg, ShaderData *sd, float randb, int path_flag)
+void OSLShader::eval_volume(KernelGlobals *kg, ShaderData *sd, float randb, int path_flag, ShaderContext ctx)
 {
-       /* gather pointers */
-       OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
-       OSLThreadData *tdata = kg->osl_tdata;
-       OSL::ShaderGlobals *globals = &tdata->globals;
-       OSL::ShadingContext *ctx = (OSL::ShadingContext *)sd->osl_ctx;
-
        /* setup shader globals from shader data */
-       shaderdata_to_shaderglobals(kg, sd, path_flag, globals);
+       OSLThreadData *tdata = kg->osl_tdata;
+       shaderdata_to_shaderglobals(kg, sd, path_flag, tdata);
 
        /* execute shader */
+       OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
+       OSL::ShaderGlobals *globals = &tdata->globals;
+       OSL::ShadingContext *octx = tdata->context[(int)ctx];
        int shader = sd->shader & SHADER_MASK;
 
        if (kg->osl->volume_state[shader])
-               ss->execute(*ctx, *(kg->osl->volume_state[shader]), *globals);
-
-       /* free trace data */
-       if(globals->tracedata)
-               delete (OSLRenderServices::TraceData*)globals->tracedata;
+               ss->execute(*octx, *(kg->osl->volume_state[shader]), *globals);
 
        if (globals->Ci)
                flatten_volume_closure_tree(sd, globals->Ci);
@@ -395,46 +382,25 @@ void OSLShader::eval_volume(KernelGlobals *kg, ShaderData *sd, float randb, int
 
 /* Displacement */
 
-void OSLShader::eval_displacement(KernelGlobals *kg, ShaderData *sd)
+void OSLShader::eval_displacement(KernelGlobals *kg, ShaderData *sd, ShaderContext ctx)
 {
-       /* gather pointers */
-       OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
-       OSLThreadData *tdata = kg->osl_tdata;
-       OSL::ShaderGlobals *globals = &tdata->globals;
-       OSL::ShadingContext *ctx = (OSL::ShadingContext *)sd->osl_ctx;
-
        /* setup shader globals from shader data */
-       shaderdata_to_shaderglobals(kg, sd, 0, globals);
+       OSLThreadData *tdata = kg->osl_tdata;
+       shaderdata_to_shaderglobals(kg, sd, 0, tdata);
 
        /* execute shader */
+       OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
+       OSL::ShaderGlobals *globals = &tdata->globals;
+       OSL::ShadingContext *octx = tdata->context[(int)ctx];
        int shader = sd->shader & SHADER_MASK;
 
        if (kg->osl->displacement_state[shader])
-               ss->execute(*ctx, *(kg->osl->displacement_state[shader]), *globals);
-
-       /* free trace data */
-       if(globals->tracedata)
-               delete (OSLRenderServices::TraceData*)globals->tracedata;
+               ss->execute(*octx, *(kg->osl->displacement_state[shader]), *globals);
 
        /* get back position */
        sd->P = TO_FLOAT3(globals->P);
 }
 
-void OSLShader::init(KernelGlobals *kg, ShaderData *sd)
-{
-       OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
-       OSLThreadData *tdata = kg->osl_tdata;
-       
-       sd->osl_ctx = ss->get_context(tdata->thread_info);
-}
-
-void OSLShader::release(KernelGlobals *kg, ShaderData *sd)
-{
-       OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
-       
-       ss->release_context((OSL::ShadingContext *)sd->osl_ctx);
-}
-
 /* BSDF Closure */
 
 int OSLShader::bsdf_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3& eval, float3& omega_in, differential3& domega_in, float& pdf)