Cycles OSL minor optimizations: recycle shading context, don't do memory
[blender.git] / intern / cycles / kernel / osl / osl_shader.cpp
1 /*
2  * Copyright 2011, Blender Foundation.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18
19 #include "kernel_compat_cpu.h"
20 #include "kernel_types.h"
21 #include "kernel_globals.h"
22 #include "kernel_object.h"
23
24 #include "osl_closures.h"
25 #include "osl_globals.h"
26 #include "osl_services.h"
27 #include "osl_shader.h"
28
29 #include "util_attribute.h"
30 #include "util_foreach.h"
31
32 #include <OSL/oslexec.h>
33
34 CCL_NAMESPACE_BEGIN
35
36 /* Threads */
37
38 void OSLShader::thread_init(KernelGlobals *kg, KernelGlobals *kernel_globals, OSLGlobals *osl_globals)
39 {
40         /* no osl used? */
41         if(!osl_globals->use) {
42                 kg->osl = NULL;
43                 return;
44         }
45
46         /* per thread kernel data init*/
47         kg->osl = osl_globals;
48         kg->osl->services->thread_init(kernel_globals);
49
50         OSL::ShadingSystem *ss = kg->osl->ss;
51         OSLThreadData *tdata = new OSLThreadData();
52
53         memset(&tdata->globals, 0, sizeof(OSL::ShaderGlobals));
54         tdata->globals.tracedata = &tdata->tracedata;
55         tdata->globals.flipHandedness = false;
56         tdata->thread_info = ss->create_thread_info();
57
58         for(int i = 0; i < SHADER_CONTEXT_NUM; i++)
59                 tdata->context[i] = ss->get_context(tdata->thread_info);
60
61         kg->osl_ss = (OSLShadingSystem*)ss;
62         kg->osl_tdata = tdata;
63 }
64
65 void OSLShader::thread_free(KernelGlobals *kg)
66 {
67         if(!kg->osl)
68                 return;
69
70         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
71         OSLThreadData *tdata = kg->osl_tdata;
72
73         for(int i = 0; i < SHADER_CONTEXT_NUM; i++)
74                 ss->release_context(tdata->context[i]);
75
76         ss->destroy_thread_info(tdata->thread_info);
77
78         delete tdata;
79
80         kg->osl = NULL;
81         kg->osl_ss = NULL;
82         kg->osl_tdata = NULL;
83 }
84
85 /* Globals */
86
87 static void shaderdata_to_shaderglobals(KernelGlobals *kg, ShaderData *sd,
88                                         int path_flag, OSLThreadData *tdata)
89 {
90         OSL::ShaderGlobals *globals = &tdata->globals;
91
92         /* copy from shader data to shader globals */
93         globals->P = TO_VEC3(sd->P);
94         globals->dPdx = TO_VEC3(sd->dP.dx);
95         globals->dPdy = TO_VEC3(sd->dP.dy);
96         globals->I = TO_VEC3(sd->I);
97         globals->dIdx = TO_VEC3(sd->dI.dx);
98         globals->dIdy = TO_VEC3(sd->dI.dy);
99         globals->N = TO_VEC3(sd->N);
100         globals->Ng = TO_VEC3(sd->Ng);
101         globals->u = sd->u;
102         globals->dudx = sd->du.dx;
103         globals->dudy = sd->du.dy;
104         globals->v = sd->v;
105         globals->dvdx = sd->dv.dx;
106         globals->dvdy = sd->dv.dy;
107         globals->dPdu = TO_VEC3(sd->dPdu);
108         globals->dPdv = TO_VEC3(sd->dPdv);
109         globals->surfacearea = (sd->object == ~0) ? 1.0f : object_surface_area(kg, sd->object);
110         globals->time = sd->time;
111
112         /* booleans */
113         globals->raytype = path_flag;
114         globals->backfacing = (sd->flag & SD_BACKFACING);
115
116         /* shader data to be used in services callbacks */
117         globals->renderstate = sd; 
118
119         /* hacky, we leave it to services to fetch actual object matrix */
120         globals->shader2common = sd;
121         globals->object2common = sd;
122
123         /* must be set to NULL before execute */
124         globals->Ci = NULL;
125
126         /* clear trace data */
127         tdata->tracedata.init = false;
128 }
129
130 /* Surface */
131
132 static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy,
133                                          const OSL::ClosureColor *closure, float3 weight = make_float3(1.0f, 1.0f, 1.0f))
134 {
135         /* OSL gives us a closure tree, we flatten it into arrays per
136          * closure type, for evaluation, sampling, etc later on. */
137
138         if (closure->type == OSL::ClosureColor::COMPONENT) {
139                 OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
140                 OSL::ClosurePrimitive *prim = (OSL::ClosurePrimitive *)comp->data();
141
142                 if (prim) {
143                         ShaderClosure sc;
144                         sc.weight = weight;
145
146                         switch (prim->category()) {
147                                 case OSL::ClosurePrimitive::BSDF: {
148                                         CBSDFClosure *bsdf = (CBSDFClosure *)prim;
149                                         int scattering = bsdf->scattering();
150
151                                         /* no caustics option */
152                                         if (no_glossy && scattering == LABEL_GLOSSY)
153                                                 return;
154
155                                         /* sample weight */
156                                         float sample_weight = fabsf(average(weight));
157
158                                         sc.sample_weight = sample_weight;
159
160                                         sc.type = bsdf->sc.type;
161                                         sc.N = bsdf->sc.N;
162                                         sc.T = bsdf->sc.T;
163                                         sc.data0 = bsdf->sc.data0;
164                                         sc.data1 = bsdf->sc.data1;
165                                         sc.prim = bsdf->sc.prim;
166
167                                         /* add */
168                                         if(sc.sample_weight > 1e-5f && sd->num_closure < MAX_CLOSURE) {
169                                                 sd->closure[sd->num_closure++] = sc;
170                                                 sd->flag |= bsdf->shaderdata_flag();
171                                         }
172                                         break;
173                                 }
174                                 case OSL::ClosurePrimitive::Emissive: {
175                                         if (sd->num_closure == MAX_CLOSURE)
176                                                 return;
177
178                                         /* sample weight */
179                                         float sample_weight = fabsf(average(weight));
180
181                                         sc.sample_weight = sample_weight;
182                                         sc.type = CLOSURE_EMISSION_ID;
183                                         sc.prim = NULL;
184
185                                         /* flag */
186                                         if(sd->num_closure < MAX_CLOSURE) {
187                                                 sd->closure[sd->num_closure++] = sc;
188                                                 sd->flag |= SD_EMISSION;
189                                         }
190                                         break;
191                                 }
192                                 case AmbientOcclusion: {
193                                         /* sample weight */
194                                         float sample_weight = fabsf(average(weight));
195
196                                         sc.sample_weight = sample_weight;
197                                         sc.type = CLOSURE_AMBIENT_OCCLUSION_ID;
198                                         sc.prim = NULL;
199
200                                         if(sd->num_closure < MAX_CLOSURE) {
201                                                 sd->closure[sd->num_closure++] = sc;
202                                                 sd->flag |= SD_AO;
203                                         }
204                                         break;
205                                 }
206                                 case OSL::ClosurePrimitive::Holdout:
207                                         sc.sample_weight = 0.0f;
208                                         sc.type = CLOSURE_HOLDOUT_ID;
209                                         sc.prim = NULL;
210
211                                         if(sd->num_closure < MAX_CLOSURE) {
212                                                 sd->closure[sd->num_closure++] = sc;
213                                                 sd->flag |= SD_HOLDOUT;
214                                         }
215                                         break;
216                                 case OSL::ClosurePrimitive::BSSRDF:
217                                 case OSL::ClosurePrimitive::Debug:
218                                         break; /* not implemented */
219                                 case OSL::ClosurePrimitive::Background:
220                                 case OSL::ClosurePrimitive::Volume:
221                                         break; /* not relevant */
222                         }
223                 }
224         }
225         else if (closure->type == OSL::ClosureColor::MUL) {
226                 OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
227                 flatten_surface_closure_tree(sd, no_glossy, mul->closure, TO_FLOAT3(mul->weight) * weight);
228         }
229         else if (closure->type == OSL::ClosureColor::ADD) {
230                 OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
231                 flatten_surface_closure_tree(sd, no_glossy, add->closureA, weight);
232                 flatten_surface_closure_tree(sd, no_glossy, add->closureB, weight);
233         }
234 }
235
236 void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, float randb, int path_flag, ShaderContext ctx)
237 {
238         /* setup shader globals from shader data */
239         OSLThreadData *tdata = kg->osl_tdata;
240         shaderdata_to_shaderglobals(kg, sd, path_flag, tdata);
241
242         /* execute shader for this point */
243         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
244         OSL::ShaderGlobals *globals = &tdata->globals;
245         OSL::ShadingContext *octx = tdata->context[(int)ctx];
246         int shader = sd->shader & SHADER_MASK;
247
248         if (kg->osl->surface_state[shader])
249                 ss->execute(*octx, *(kg->osl->surface_state[shader]), *globals);
250
251         /* flatten closure tree */
252         sd->num_closure = 0;
253         sd->randb_closure = randb;
254
255         if (globals->Ci) {
256                 bool no_glossy = (path_flag & PATH_RAY_DIFFUSE) && kernel_data.integrator.no_caustics;
257                 flatten_surface_closure_tree(sd, no_glossy, globals->Ci);
258         }
259 }
260
261 /* Background */
262
263 static float3 flatten_background_closure_tree(const OSL::ClosureColor *closure)
264 {
265         /* OSL gives us a closure tree, if we are shading for background there
266          * is only one supported closure type at the moment, which has no evaluation
267          * functions, so we just sum the weights */
268
269         if (closure->type == OSL::ClosureColor::COMPONENT) {
270                 OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
271                 OSL::ClosurePrimitive *prim = (OSL::ClosurePrimitive *)comp->data();
272
273                 if (prim && prim->category() == OSL::ClosurePrimitive::Background)
274                         return make_float3(1.0f, 1.0f, 1.0f);
275         }
276         else if (closure->type == OSL::ClosureColor::MUL) {
277                 OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
278
279                 return TO_FLOAT3(mul->weight) * flatten_background_closure_tree(mul->closure);
280         }
281         else if (closure->type == OSL::ClosureColor::ADD) {
282                 OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
283
284                 return flatten_background_closure_tree(add->closureA) +
285                        flatten_background_closure_tree(add->closureB);
286         }
287
288         return make_float3(0.0f, 0.0f, 0.0f);
289 }
290
291 float3 OSLShader::eval_background(KernelGlobals *kg, ShaderData *sd, int path_flag, ShaderContext ctx)
292 {
293         /* setup shader globals from shader data */
294         OSLThreadData *tdata = kg->osl_tdata;
295         shaderdata_to_shaderglobals(kg, sd, path_flag, tdata);
296
297         /* execute shader for this point */
298         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
299         OSL::ShaderGlobals *globals = &tdata->globals;
300         OSL::ShadingContext *octx = tdata->context[(int)ctx];
301
302         if (kg->osl->background_state)
303                 ss->execute(*octx, *(kg->osl->background_state), *globals);
304
305         /* return background color immediately */
306         if (globals->Ci)
307                 return flatten_background_closure_tree(globals->Ci);
308
309         return make_float3(0.0f, 0.0f, 0.0f);
310 }
311
312 /* Volume */
313
314 static void flatten_volume_closure_tree(ShaderData *sd,
315                                         const OSL::ClosureColor *closure, float3 weight = make_float3(1.0f, 1.0f, 1.0f))
316 {
317         /* OSL gives us a closure tree, we flatten it into arrays per
318          * closure type, for evaluation, sampling, etc later on. */
319
320         if (closure->type == OSL::ClosureColor::COMPONENT) {
321                 OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
322                 OSL::ClosurePrimitive *prim = (OSL::ClosurePrimitive *)comp->data();
323
324                 if (prim) {
325                         ShaderClosure sc;
326                         sc.weight = weight;
327
328                         switch (prim->category()) {
329                                 case OSL::ClosurePrimitive::Volume: {
330                                         /* sample weight */
331                                         float sample_weight = fabsf(average(weight));
332
333                                         sc.sample_weight = sample_weight;
334                                         sc.type = CLOSURE_VOLUME_ID;
335                                         sc.prim = NULL;
336
337                                         /* add */
338                                         if(sc.sample_weight > 1e-5f && sd->num_closure < MAX_CLOSURE)
339                                                 sd->closure[sd->num_closure++] = sc;
340                                         break;
341                                 }
342                                 case OSL::ClosurePrimitive::Holdout:
343                                 case OSL::ClosurePrimitive::Debug:
344                                         break; /* not implemented */
345                                 case OSL::ClosurePrimitive::Background:
346                                 case OSL::ClosurePrimitive::BSDF:
347                                 case OSL::ClosurePrimitive::Emissive:
348                                 case OSL::ClosurePrimitive::BSSRDF:
349                                         break; /* not relevant */
350                         }
351                 }
352         }
353         else if (closure->type == OSL::ClosureColor::MUL) {
354                 OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
355                 flatten_volume_closure_tree(sd, mul->closure, TO_FLOAT3(mul->weight) * weight);
356         }
357         else if (closure->type == OSL::ClosureColor::ADD) {
358                 OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
359                 flatten_volume_closure_tree(sd, add->closureA, weight);
360                 flatten_volume_closure_tree(sd, add->closureB, weight);
361         }
362 }
363
364 void OSLShader::eval_volume(KernelGlobals *kg, ShaderData *sd, float randb, int path_flag, ShaderContext ctx)
365 {
366         /* setup shader globals from shader data */
367         OSLThreadData *tdata = kg->osl_tdata;
368         shaderdata_to_shaderglobals(kg, sd, path_flag, tdata);
369
370         /* execute shader */
371         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
372         OSL::ShaderGlobals *globals = &tdata->globals;
373         OSL::ShadingContext *octx = tdata->context[(int)ctx];
374         int shader = sd->shader & SHADER_MASK;
375
376         if (kg->osl->volume_state[shader])
377                 ss->execute(*octx, *(kg->osl->volume_state[shader]), *globals);
378
379         if (globals->Ci)
380                 flatten_volume_closure_tree(sd, globals->Ci);
381 }
382
383 /* Displacement */
384
385 void OSLShader::eval_displacement(KernelGlobals *kg, ShaderData *sd, ShaderContext ctx)
386 {
387         /* setup shader globals from shader data */
388         OSLThreadData *tdata = kg->osl_tdata;
389         shaderdata_to_shaderglobals(kg, sd, 0, tdata);
390
391         /* execute shader */
392         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
393         OSL::ShaderGlobals *globals = &tdata->globals;
394         OSL::ShadingContext *octx = tdata->context[(int)ctx];
395         int shader = sd->shader & SHADER_MASK;
396
397         if (kg->osl->displacement_state[shader])
398                 ss->execute(*octx, *(kg->osl->displacement_state[shader]), *globals);
399
400         /* get back position */
401         sd->P = TO_FLOAT3(globals->P);
402 }
403
404 /* BSDF Closure */
405
406 int OSLShader::bsdf_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3& eval, float3& omega_in, differential3& domega_in, float& pdf)
407 {
408         CBSDFClosure *sample_bsdf = (CBSDFClosure *)sc->prim;
409
410         pdf = 0.0f;
411
412         return sample_bsdf->sample(sd->Ng,
413                                    sd->I, sd->dI.dx, sd->dI.dy,
414                                    randu, randv,
415                                    omega_in, domega_in.dx, domega_in.dy,
416                                    pdf, eval);
417 }
418
419 float3 OSLShader::bsdf_eval(const ShaderData *sd, const ShaderClosure *sc, const float3& omega_in, float& pdf)
420 {
421         CBSDFClosure *bsdf = (CBSDFClosure *)sc->prim;
422         float3 bsdf_eval;
423
424         if (dot(sd->Ng, omega_in) >= 0.0f)
425                 bsdf_eval = bsdf->eval_reflect(sd->I, omega_in, pdf);
426         else
427                 bsdf_eval = bsdf->eval_transmit(sd->I, omega_in, pdf);
428         
429         return bsdf_eval;
430 }
431
432 void OSLShader::bsdf_blur(ShaderClosure *sc, float roughness)
433 {
434         CBSDFClosure *bsdf = (CBSDFClosure *)sc->prim;
435         bsdf->blur(roughness);
436 }
437
438 /* Emissive Closure */
439
440 float3 OSLShader::emissive_eval(const ShaderData *sd, const ShaderClosure *sc)
441 {
442         OSL::EmissiveClosure *emissive = (OSL::EmissiveClosure *)sc->prim;
443         OSL::Color3 emissive_eval = emissive->eval(TO_VEC3(sd->Ng), TO_VEC3(sd->I));
444
445         return TO_FLOAT3(emissive_eval);
446 }
447
448 /* Volume Closure */
449
450 float3 OSLShader::volume_eval_phase(const ShaderClosure *sc, const float3 omega_in, const float3 omega_out)
451 {
452         OSL::VolumeClosure *volume = (OSL::VolumeClosure *)sc->prim;
453         OSL::Color3 volume_eval = volume->eval_phase(TO_VEC3(omega_in), TO_VEC3(omega_out));
454         return TO_FLOAT3(volume_eval) * sc->weight;
455 }
456
457 /* Attributes */
458
459 int OSLShader::find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id)
460 {
461         /* for OSL, a hash map is used to lookup the attribute by name. */
462         OSLGlobals::AttributeMap &attr_map = kg->osl->attribute_map[sd->object];
463         ustring stdname(std::string("std::") + std::string(attribute_standard_name((AttributeStandard)id)));
464         OSLGlobals::AttributeMap::const_iterator it = attr_map.find(stdname);
465
466         if (it != attr_map.end()) {
467                 const OSLGlobals::Attribute &osl_attr = it->second;
468                 /* return result */
469                 return (osl_attr.elem == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : osl_attr.offset;
470         }
471         else
472                 return (int)ATTR_STD_NOT_FOUND;
473 }
474
475 CCL_NAMESPACE_END
476