2 * Copyright 2011-2013 Blender Foundation
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
17 #include "kernel_compat_cpu.h"
18 #include "kernel_montecarlo.h"
19 #include "kernel_types.h"
20 #include "kernel_globals.h"
21 #include "kernel_object.h"
23 #include "closure/bsdf_diffuse.h"
24 #include "closure/bssrdf.h"
26 #include "osl_bssrdf.h"
27 #include "osl_closures.h"
28 #include "osl_globals.h"
29 #include "osl_services.h"
30 #include "osl_shader.h"
32 #include "util_foreach.h"
34 #include "attribute.h"
36 #include <OSL/oslexec.h>
42 void OSLShader::thread_init(KernelGlobals *kg, KernelGlobals *kernel_globals, OSLGlobals *osl_globals)
45 if(!osl_globals->use) {
50 /* per thread kernel data init*/
51 kg->osl = osl_globals;
52 kg->osl->services->thread_init(kernel_globals, osl_globals->ts);
54 OSL::ShadingSystem *ss = kg->osl->ss;
55 OSLThreadData *tdata = new OSLThreadData();
57 memset(&tdata->globals, 0, sizeof(OSL::ShaderGlobals));
58 tdata->globals.tracedata = &tdata->tracedata;
59 tdata->globals.flipHandedness = false;
60 tdata->osl_thread_info = ss->create_thread_info();
62 for(int i = 0; i < SHADER_CONTEXT_NUM; i++)
63 tdata->context[i] = ss->get_context(tdata->osl_thread_info);
65 tdata->oiio_thread_info = osl_globals->ts->get_perthread_info();
67 kg->osl_ss = (OSLShadingSystem*)ss;
68 kg->osl_tdata = tdata;
71 void OSLShader::thread_free(KernelGlobals *kg)
76 OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
77 OSLThreadData *tdata = kg->osl_tdata;
79 for(int i = 0; i < SHADER_CONTEXT_NUM; i++)
80 ss->release_context(tdata->context[i]);
82 ss->destroy_thread_info(tdata->osl_thread_info);
93 static void shaderdata_to_shaderglobals(KernelGlobals *kg, ShaderData *sd,
94 int path_flag, OSLThreadData *tdata)
96 OSL::ShaderGlobals *globals = &tdata->globals;
98 /* copy from shader data to shader globals */
99 globals->P = TO_VEC3(sd->P);
100 globals->dPdx = TO_VEC3(sd->dP.dx);
101 globals->dPdy = TO_VEC3(sd->dP.dy);
102 globals->I = TO_VEC3(sd->I);
103 globals->dIdx = TO_VEC3(sd->dI.dx);
104 globals->dIdy = TO_VEC3(sd->dI.dy);
105 globals->N = TO_VEC3(sd->N);
106 globals->Ng = TO_VEC3(sd->Ng);
108 globals->dudx = sd->du.dx;
109 globals->dudy = sd->du.dy;
111 globals->dvdx = sd->dv.dx;
112 globals->dvdy = sd->dv.dy;
113 globals->dPdu = TO_VEC3(sd->dPdu);
114 globals->dPdv = TO_VEC3(sd->dPdv);
115 globals->surfacearea = (sd->object == ~0) ? 1.0f : object_surface_area(kg, sd->object);
116 globals->time = sd->time;
119 globals->raytype = path_flag;
120 globals->backfacing = (sd->flag & SD_BACKFACING);
122 /* shader data to be used in services callbacks */
123 globals->renderstate = sd;
125 /* hacky, we leave it to services to fetch actual object matrix */
126 globals->shader2common = sd;
127 globals->object2common = sd;
129 /* must be set to NULL before execute */
132 /* clear trace data */
133 tdata->tracedata.init = false;
135 /* used by renderservices */
136 sd->osl_globals = kg;
141 static void flatten_surface_closure_tree(ShaderData *sd, int path_flag,
142 const OSL::ClosureColor *closure, float3 weight = make_float3(1.0f, 1.0f, 1.0f))
144 /* OSL gives us a closure tree, we flatten it into arrays per
145 * closure type, for evaluation, sampling, etc later on. */
147 if (closure->type == OSL::ClosureColor::COMPONENT) {
148 OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
149 CClosurePrimitive *prim = (CClosurePrimitive *)comp->data();
154 #ifdef OSL_SUPPORTS_WEIGHTED_CLOSURE_COMPONENTS
155 weight = weight*TO_FLOAT3(comp->w);
161 switch (prim->category) {
162 case CClosurePrimitive::BSDF: {
163 CBSDFClosure *bsdf = (CBSDFClosure *)prim;
164 int scattering = bsdf->scattering();
166 /* no caustics option */
167 if(scattering == LABEL_GLOSSY && (path_flag & PATH_RAY_DIFFUSE)) {
168 KernelGlobals *kg = sd->osl_globals;
169 if(kernel_data.integrator.no_caustics)
174 float sample_weight = fabsf(average(weight));
176 sc.sample_weight = sample_weight;
178 sc.type = bsdf->sc.type;
181 sc.data0 = bsdf->sc.data0;
182 sc.data1 = bsdf->sc.data1;
183 sc.prim = bsdf->sc.prim;
186 sc.offset = bsdf->sc.offset;
190 if(sc.sample_weight > 1e-5f && sd->num_closure < MAX_CLOSURE) {
191 sd->closure[sd->num_closure++] = sc;
192 sd->flag |= bsdf->shaderdata_flag();
196 case CClosurePrimitive::Emissive: {
198 float sample_weight = fabsf(average(weight));
200 sc.sample_weight = sample_weight;
201 sc.type = CLOSURE_EMISSION_ID;
207 if(sd->num_closure < MAX_CLOSURE) {
208 sd->closure[sd->num_closure++] = sc;
209 sd->flag |= SD_EMISSION;
213 case CClosurePrimitive::AmbientOcclusion: {
215 float sample_weight = fabsf(average(weight));
217 sc.sample_weight = sample_weight;
218 sc.type = CLOSURE_AMBIENT_OCCLUSION_ID;
223 if(sd->num_closure < MAX_CLOSURE) {
224 sd->closure[sd->num_closure++] = sc;
229 case CClosurePrimitive::Holdout: {
230 sc.sample_weight = 0.0f;
231 sc.type = CLOSURE_HOLDOUT_ID;
236 if(sd->num_closure < MAX_CLOSURE) {
237 sd->closure[sd->num_closure++] = sc;
238 sd->flag |= SD_HOLDOUT;
242 case CClosurePrimitive::BSSRDF: {
243 CBSSRDFClosure *bssrdf = (CBSSRDFClosure *)prim;
244 float sample_weight = fabsf(average(weight));
246 if(sample_weight > 1e-5f && sd->num_closure+2 < MAX_CLOSURE) {
247 sc.sample_weight = sample_weight;
249 sc.type = bssrdf->sc.type;
251 sc.data1 = bssrdf->sc.data1;
252 sc.T.x = bssrdf->sc.T.x;
255 /* disable in case of diffuse ancestor, can't see it well then and
256 * adds considerably noise due to probabilities of continuing path
257 * getting lower and lower */
258 if(path_flag & PATH_RAY_DIFFUSE_ANCESTOR)
259 bssrdf->radius = make_float3(0.0f, 0.0f, 0.0f);
261 /* create one closure for each color channel */
262 if(fabsf(weight.x) > 0.0f) {
263 sc.weight = make_float3(weight.x, 0.0f, 0.0f);
264 sc.data0 = bssrdf->radius.x;
265 sd->flag |= bssrdf_setup(&sc, sc.type);
266 sd->closure[sd->num_closure++] = sc;
269 if(fabsf(weight.y) > 0.0f) {
270 sc.weight = make_float3(0.0f, weight.y, 0.0f);
271 sc.data0 = bssrdf->radius.y;
272 sd->flag |= bssrdf_setup(&sc, sc.type);
273 sd->closure[sd->num_closure++] = sc;
276 if(fabsf(weight.z) > 0.0f) {
277 sc.weight = make_float3(0.0f, 0.0f, weight.z);
278 sc.data0 = bssrdf->radius.z;
279 sd->flag |= bssrdf_setup(&sc, sc.type);
280 sd->closure[sd->num_closure++] = sc;
285 case CClosurePrimitive::Background:
286 case CClosurePrimitive::Volume:
287 break; /* not relevant */
291 else if (closure->type == OSL::ClosureColor::MUL) {
292 OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
293 flatten_surface_closure_tree(sd, path_flag, mul->closure, TO_FLOAT3(mul->weight) * weight);
295 else if (closure->type == OSL::ClosureColor::ADD) {
296 OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
297 flatten_surface_closure_tree(sd, path_flag, add->closureA, weight);
298 flatten_surface_closure_tree(sd, path_flag, add->closureB, weight);
302 void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, float randb, int path_flag, ShaderContext ctx)
304 /* setup shader globals from shader data */
305 OSLThreadData *tdata = kg->osl_tdata;
306 shaderdata_to_shaderglobals(kg, sd, path_flag, tdata);
308 /* execute shader for this point */
309 OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
310 OSL::ShaderGlobals *globals = &tdata->globals;
311 OSL::ShadingContext *octx = tdata->context[(int)ctx];
312 int shader = sd->shader & SHADER_MASK;
314 if (kg->osl->surface_state[shader])
315 ss->execute(*octx, *(kg->osl->surface_state[shader]), *globals);
317 /* flatten closure tree */
319 sd->randb_closure = randb;
322 flatten_surface_closure_tree(sd, path_flag, globals->Ci);
327 static float3 flatten_background_closure_tree(const OSL::ClosureColor *closure)
329 /* OSL gives us a closure tree, if we are shading for background there
330 * is only one supported closure type at the moment, which has no evaluation
331 * functions, so we just sum the weights */
333 if (closure->type == OSL::ClosureColor::COMPONENT) {
334 OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
335 CClosurePrimitive *prim = (CClosurePrimitive *)comp->data();
337 if (prim && prim->category == CClosurePrimitive::Background)
338 #ifdef OSL_SUPPORTS_WEIGHTED_CLOSURE_COMPONENTS
339 return TO_FLOAT3(comp->w);
341 return make_float3(1.0f, 1.0f, 1.0f);
344 else if (closure->type == OSL::ClosureColor::MUL) {
345 OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
347 return TO_FLOAT3(mul->weight) * flatten_background_closure_tree(mul->closure);
349 else if (closure->type == OSL::ClosureColor::ADD) {
350 OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
352 return flatten_background_closure_tree(add->closureA) +
353 flatten_background_closure_tree(add->closureB);
356 return make_float3(0.0f, 0.0f, 0.0f);
359 float3 OSLShader::eval_background(KernelGlobals *kg, ShaderData *sd, int path_flag, ShaderContext ctx)
361 /* setup shader globals from shader data */
362 OSLThreadData *tdata = kg->osl_tdata;
363 shaderdata_to_shaderglobals(kg, sd, path_flag, tdata);
365 /* execute shader for this point */
366 OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
367 OSL::ShaderGlobals *globals = &tdata->globals;
368 OSL::ShadingContext *octx = tdata->context[(int)ctx];
370 if (kg->osl->background_state)
371 ss->execute(*octx, *(kg->osl->background_state), *globals);
373 /* return background color immediately */
375 return flatten_background_closure_tree(globals->Ci);
377 return make_float3(0.0f, 0.0f, 0.0f);
382 static void flatten_volume_closure_tree(ShaderData *sd,
383 const OSL::ClosureColor *closure, float3 weight = make_float3(1.0f, 1.0f, 1.0f))
385 /* OSL gives us a closure tree, we flatten it into arrays per
386 * closure type, for evaluation, sampling, etc later on. */
388 if (closure->type == OSL::ClosureColor::COMPONENT) {
389 OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
390 CClosurePrimitive *prim = (CClosurePrimitive *)comp->data();
395 #ifdef OSL_SUPPORTS_WEIGHTED_CLOSURE_COMPONENTS
396 weight = weight*TO_FLOAT3(comp->w);
402 switch (prim->category) {
403 case CClosurePrimitive::Volume: {
405 float sample_weight = fabsf(average(weight));
407 sc.sample_weight = sample_weight;
408 sc.type = CLOSURE_VOLUME_ID;
414 if(sc.sample_weight > 1e-5f && sd->num_closure < MAX_CLOSURE)
415 sd->closure[sd->num_closure++] = sc;
418 case CClosurePrimitive::Holdout:
419 break; /* not implemented */
420 case CClosurePrimitive::Background:
421 case CClosurePrimitive::BSDF:
422 case CClosurePrimitive::Emissive:
423 case CClosurePrimitive::BSSRDF:
424 case CClosurePrimitive::AmbientOcclusion:
425 break; /* not relevant */
429 else if (closure->type == OSL::ClosureColor::MUL) {
430 OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
431 flatten_volume_closure_tree(sd, mul->closure, TO_FLOAT3(mul->weight) * weight);
433 else if (closure->type == OSL::ClosureColor::ADD) {
434 OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
435 flatten_volume_closure_tree(sd, add->closureA, weight);
436 flatten_volume_closure_tree(sd, add->closureB, weight);
440 void OSLShader::eval_volume(KernelGlobals *kg, ShaderData *sd, float randb, int path_flag, ShaderContext ctx)
442 /* setup shader globals from shader data */
443 OSLThreadData *tdata = kg->osl_tdata;
444 shaderdata_to_shaderglobals(kg, sd, path_flag, tdata);
447 OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
448 OSL::ShaderGlobals *globals = &tdata->globals;
449 OSL::ShadingContext *octx = tdata->context[(int)ctx];
450 int shader = sd->shader & SHADER_MASK;
452 if (kg->osl->volume_state[shader])
453 ss->execute(*octx, *(kg->osl->volume_state[shader]), *globals);
456 flatten_volume_closure_tree(sd, globals->Ci);
461 void OSLShader::eval_displacement(KernelGlobals *kg, ShaderData *sd, ShaderContext ctx)
463 /* setup shader globals from shader data */
464 OSLThreadData *tdata = kg->osl_tdata;
465 shaderdata_to_shaderglobals(kg, sd, 0, tdata);
468 OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
469 OSL::ShaderGlobals *globals = &tdata->globals;
470 OSL::ShadingContext *octx = tdata->context[(int)ctx];
471 int shader = sd->shader & SHADER_MASK;
473 if (kg->osl->displacement_state[shader])
474 ss->execute(*octx, *(kg->osl->displacement_state[shader]), *globals);
476 /* get back position */
477 sd->P = TO_FLOAT3(globals->P);
482 int OSLShader::bsdf_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3& eval, float3& omega_in, differential3& domega_in, float& pdf)
484 CBSDFClosure *sample_bsdf = (CBSDFClosure *)sc->prim;
488 return sample_bsdf->sample(sd->Ng,
489 sd->I, sd->dI.dx, sd->dI.dy,
491 omega_in, domega_in.dx, domega_in.dy,
495 float3 OSLShader::bsdf_eval(const ShaderData *sd, const ShaderClosure *sc, const float3& omega_in, float& pdf)
497 CBSDFClosure *bsdf = (CBSDFClosure *)sc->prim;
500 if (dot(sd->Ng, omega_in) >= 0.0f)
501 bsdf_eval = bsdf->eval_reflect(sd->I, omega_in, pdf);
503 bsdf_eval = bsdf->eval_transmit(sd->I, omega_in, pdf);
508 void OSLShader::bsdf_blur(ShaderClosure *sc, float roughness)
510 CBSDFClosure *bsdf = (CBSDFClosure *)sc->prim;
511 bsdf->blur(roughness);
516 int OSLShader::find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeElement *elem)
518 /* for OSL, a hash map is used to lookup the attribute by name. */
519 int object = sd->object*ATTR_PRIM_TYPES;
521 if(sd->segment != ~0) object += ATTR_PRIM_CURVE;
524 OSLGlobals::AttributeMap &attr_map = kg->osl->attribute_map[object];
525 ustring stdname(std::string("geom:") + std::string(Attribute::standard_name((AttributeStandard)id)));
526 OSLGlobals::AttributeMap::const_iterator it = attr_map.find(stdname);
528 if (it != attr_map.end()) {
529 const OSLGlobals::Attribute &osl_attr = it->second;
530 *elem = osl_attr.elem;
532 return (osl_attr.elem == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : osl_attr.offset;
535 return (int)ATTR_STD_NOT_FOUND;