2 * Copyright 2011, Blender Foundation.
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.
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.
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.
19 #include "kernel_compat_cpu.h"
20 #include "kernel_types.h"
21 #include "kernel_globals.h"
22 #include "kernel_object.h"
24 #include "osl_bssrdf.h"
25 #include "osl_closures.h"
26 #include "osl_globals.h"
27 #include "osl_services.h"
28 #include "osl_shader.h"
30 #include "util_foreach.h"
32 #include "attribute.h"
34 #include <OSL/oslexec.h>
40 void OSLShader::thread_init(KernelGlobals *kg, KernelGlobals *kernel_globals, OSLGlobals *osl_globals)
43 if(!osl_globals->use) {
48 /* per thread kernel data init*/
49 kg->osl = osl_globals;
50 kg->osl->services->thread_init(kernel_globals, osl_globals->ts);
52 OSL::ShadingSystem *ss = kg->osl->ss;
53 OSLThreadData *tdata = new OSLThreadData();
55 memset(&tdata->globals, 0, sizeof(OSL::ShaderGlobals));
56 tdata->globals.tracedata = &tdata->tracedata;
57 tdata->globals.flipHandedness = false;
58 tdata->osl_thread_info = ss->create_thread_info();
60 for(int i = 0; i < SHADER_CONTEXT_NUM; i++)
61 tdata->context[i] = ss->get_context(tdata->osl_thread_info);
63 tdata->oiio_thread_info = osl_globals->ts->get_perthread_info();
65 kg->osl_ss = (OSLShadingSystem*)ss;
66 kg->osl_tdata = tdata;
69 void OSLShader::thread_free(KernelGlobals *kg)
74 OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
75 OSLThreadData *tdata = kg->osl_tdata;
77 for(int i = 0; i < SHADER_CONTEXT_NUM; i++)
78 ss->release_context(tdata->context[i]);
80 ss->destroy_thread_info(tdata->osl_thread_info);
91 static void shaderdata_to_shaderglobals(KernelGlobals *kg, ShaderData *sd,
92 int path_flag, OSLThreadData *tdata)
94 OSL::ShaderGlobals *globals = &tdata->globals;
96 /* copy from shader data to shader globals */
97 globals->P = TO_VEC3(sd->P);
98 globals->dPdx = TO_VEC3(sd->dP.dx);
99 globals->dPdy = TO_VEC3(sd->dP.dy);
100 globals->I = TO_VEC3(sd->I);
101 globals->dIdx = TO_VEC3(sd->dI.dx);
102 globals->dIdy = TO_VEC3(sd->dI.dy);
103 globals->N = TO_VEC3(sd->N);
104 globals->Ng = TO_VEC3(sd->Ng);
106 globals->dudx = sd->du.dx;
107 globals->dudy = sd->du.dy;
109 globals->dvdx = sd->dv.dx;
110 globals->dvdy = sd->dv.dy;
111 globals->dPdu = TO_VEC3(sd->dPdu);
112 globals->dPdv = TO_VEC3(sd->dPdv);
113 globals->surfacearea = (sd->object == ~0) ? 1.0f : object_surface_area(kg, sd->object);
114 globals->time = sd->time;
117 globals->raytype = path_flag;
118 globals->backfacing = (sd->flag & SD_BACKFACING);
120 /* shader data to be used in services callbacks */
121 globals->renderstate = sd;
123 /* hacky, we leave it to services to fetch actual object matrix */
124 globals->shader2common = sd;
125 globals->object2common = sd;
127 /* must be set to NULL before execute */
130 /* clear trace data */
131 tdata->tracedata.init = false;
133 /* used by renderservices */
134 sd->osl_globals = kg;
139 static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy,
140 const OSL::ClosureColor *closure, float3 weight = make_float3(1.0f, 1.0f, 1.0f))
142 /* OSL gives us a closure tree, we flatten it into arrays per
143 * closure type, for evaluation, sampling, etc later on. */
145 if (closure->type == OSL::ClosureColor::COMPONENT) {
146 OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
147 OSL::ClosurePrimitive *prim = (OSL::ClosurePrimitive *)comp->data();
153 switch (prim->category()) {
154 case OSL::ClosurePrimitive::BSDF: {
155 CBSDFClosure *bsdf = (CBSDFClosure *)prim;
156 int scattering = bsdf->scattering();
158 /* no caustics option */
159 if (no_glossy && scattering == LABEL_GLOSSY)
163 float sample_weight = fabsf(average(weight));
165 sc.sample_weight = sample_weight;
167 sc.type = bsdf->sc.type;
170 sc.data0 = bsdf->sc.data0;
171 sc.data1 = bsdf->sc.data1;
172 sc.prim = bsdf->sc.prim;
175 if(sc.sample_weight > 1e-5f && sd->num_closure < MAX_CLOSURE) {
176 sd->closure[sd->num_closure++] = sc;
177 sd->flag |= bsdf->shaderdata_flag();
181 case OSL::ClosurePrimitive::Emissive: {
183 float sample_weight = fabsf(average(weight));
185 sc.sample_weight = sample_weight;
186 sc.type = CLOSURE_EMISSION_ID;
190 if(sd->num_closure < MAX_CLOSURE) {
191 sd->closure[sd->num_closure++] = sc;
192 sd->flag |= SD_EMISSION;
196 case AmbientOcclusion: {
198 float sample_weight = fabsf(average(weight));
200 sc.sample_weight = sample_weight;
201 sc.type = CLOSURE_AMBIENT_OCCLUSION_ID;
204 if(sd->num_closure < MAX_CLOSURE) {
205 sd->closure[sd->num_closure++] = sc;
210 case OSL::ClosurePrimitive::Holdout: {
211 sc.sample_weight = 0.0f;
212 sc.type = CLOSURE_HOLDOUT_ID;
215 if(sd->num_closure < MAX_CLOSURE) {
216 sd->closure[sd->num_closure++] = sc;
217 sd->flag |= SD_HOLDOUT;
221 case OSL::ClosurePrimitive::BSSRDF: {
222 CBSSRDFClosure *bssrdf = (CBSSRDFClosure *)prim;
223 float sample_weight = fabsf(average(weight));
225 if(sample_weight > 1e-5f && sd->num_closure+2 < MAX_CLOSURE) {
226 sc.sample_weight = sample_weight;
228 sc.type = bssrdf->sc.type;
230 sc.data1 = bssrdf->sc.data1;
233 /* create one closure for each color channel */
234 if(fabsf(weight.x) > 0.0f) {
235 sc.weight = make_float3(weight.x, 0.0f, 0.0f);
236 sc.data0 = bssrdf->radius.x;
237 sd->closure[sd->num_closure++] = sc;
238 sd->flag |= bssrdf->shaderdata_flag();
241 if(fabsf(weight.y) > 0.0f) {
242 sc.weight = make_float3(0.0f, weight.y, 0.0f);
243 sc.data0 = bssrdf->radius.y;
244 sd->closure[sd->num_closure++] = sc;
245 sd->flag |= bssrdf->shaderdata_flag();
248 if(fabsf(weight.z) > 0.0f) {
249 sc.weight = make_float3(0.0f, 0.0f, weight.z);
250 sc.data0 = bssrdf->radius.z;
251 sd->closure[sd->num_closure++] = sc;
252 sd->flag |= bssrdf->shaderdata_flag();
257 case OSL::ClosurePrimitive::Debug:
258 break; /* not implemented */
259 case OSL::ClosurePrimitive::Background:
260 case OSL::ClosurePrimitive::Volume:
261 break; /* not relevant */
265 else if (closure->type == OSL::ClosureColor::MUL) {
266 OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
267 flatten_surface_closure_tree(sd, no_glossy, mul->closure, TO_FLOAT3(mul->weight) * weight);
269 else if (closure->type == OSL::ClosureColor::ADD) {
270 OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
271 flatten_surface_closure_tree(sd, no_glossy, add->closureA, weight);
272 flatten_surface_closure_tree(sd, no_glossy, add->closureB, weight);
276 void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, float randb, int path_flag, ShaderContext ctx)
278 /* setup shader globals from shader data */
279 OSLThreadData *tdata = kg->osl_tdata;
280 shaderdata_to_shaderglobals(kg, sd, path_flag, tdata);
282 /* execute shader for this point */
283 OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
284 OSL::ShaderGlobals *globals = &tdata->globals;
285 OSL::ShadingContext *octx = tdata->context[(int)ctx];
286 int shader = sd->shader & SHADER_MASK;
288 if (kg->osl->surface_state[shader])
289 ss->execute(*octx, *(kg->osl->surface_state[shader]), *globals);
291 /* flatten closure tree */
293 sd->randb_closure = randb;
296 bool no_glossy = (path_flag & PATH_RAY_DIFFUSE) && kernel_data.integrator.no_caustics;
297 flatten_surface_closure_tree(sd, no_glossy, globals->Ci);
303 static float3 flatten_background_closure_tree(const OSL::ClosureColor *closure)
305 /* OSL gives us a closure tree, if we are shading for background there
306 * is only one supported closure type at the moment, which has no evaluation
307 * functions, so we just sum the weights */
309 if (closure->type == OSL::ClosureColor::COMPONENT) {
310 OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
311 OSL::ClosurePrimitive *prim = (OSL::ClosurePrimitive *)comp->data();
313 if (prim && prim->category() == OSL::ClosurePrimitive::Background)
314 return make_float3(1.0f, 1.0f, 1.0f);
316 else if (closure->type == OSL::ClosureColor::MUL) {
317 OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
319 return TO_FLOAT3(mul->weight) * flatten_background_closure_tree(mul->closure);
321 else if (closure->type == OSL::ClosureColor::ADD) {
322 OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
324 return flatten_background_closure_tree(add->closureA) +
325 flatten_background_closure_tree(add->closureB);
328 return make_float3(0.0f, 0.0f, 0.0f);
331 float3 OSLShader::eval_background(KernelGlobals *kg, ShaderData *sd, int path_flag, ShaderContext ctx)
333 /* setup shader globals from shader data */
334 OSLThreadData *tdata = kg->osl_tdata;
335 shaderdata_to_shaderglobals(kg, sd, path_flag, tdata);
337 /* execute shader for this point */
338 OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
339 OSL::ShaderGlobals *globals = &tdata->globals;
340 OSL::ShadingContext *octx = tdata->context[(int)ctx];
342 if (kg->osl->background_state)
343 ss->execute(*octx, *(kg->osl->background_state), *globals);
345 /* return background color immediately */
347 return flatten_background_closure_tree(globals->Ci);
349 return make_float3(0.0f, 0.0f, 0.0f);
354 static void flatten_volume_closure_tree(ShaderData *sd,
355 const OSL::ClosureColor *closure, float3 weight = make_float3(1.0f, 1.0f, 1.0f))
357 /* OSL gives us a closure tree, we flatten it into arrays per
358 * closure type, for evaluation, sampling, etc later on. */
360 if (closure->type == OSL::ClosureColor::COMPONENT) {
361 OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
362 OSL::ClosurePrimitive *prim = (OSL::ClosurePrimitive *)comp->data();
368 switch (prim->category()) {
369 case OSL::ClosurePrimitive::Volume: {
371 float sample_weight = fabsf(average(weight));
373 sc.sample_weight = sample_weight;
374 sc.type = CLOSURE_VOLUME_ID;
378 if(sc.sample_weight > 1e-5f && sd->num_closure < MAX_CLOSURE)
379 sd->closure[sd->num_closure++] = sc;
382 case OSL::ClosurePrimitive::Holdout:
383 case OSL::ClosurePrimitive::Debug:
384 break; /* not implemented */
385 case OSL::ClosurePrimitive::Background:
386 case OSL::ClosurePrimitive::BSDF:
387 case OSL::ClosurePrimitive::Emissive:
388 case OSL::ClosurePrimitive::BSSRDF:
389 break; /* not relevant */
393 else if (closure->type == OSL::ClosureColor::MUL) {
394 OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
395 flatten_volume_closure_tree(sd, mul->closure, TO_FLOAT3(mul->weight) * weight);
397 else if (closure->type == OSL::ClosureColor::ADD) {
398 OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
399 flatten_volume_closure_tree(sd, add->closureA, weight);
400 flatten_volume_closure_tree(sd, add->closureB, weight);
404 void OSLShader::eval_volume(KernelGlobals *kg, ShaderData *sd, float randb, int path_flag, ShaderContext ctx)
406 /* setup shader globals from shader data */
407 OSLThreadData *tdata = kg->osl_tdata;
408 shaderdata_to_shaderglobals(kg, sd, path_flag, tdata);
411 OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
412 OSL::ShaderGlobals *globals = &tdata->globals;
413 OSL::ShadingContext *octx = tdata->context[(int)ctx];
414 int shader = sd->shader & SHADER_MASK;
416 if (kg->osl->volume_state[shader])
417 ss->execute(*octx, *(kg->osl->volume_state[shader]), *globals);
420 flatten_volume_closure_tree(sd, globals->Ci);
425 void OSLShader::eval_displacement(KernelGlobals *kg, ShaderData *sd, ShaderContext ctx)
427 /* setup shader globals from shader data */
428 OSLThreadData *tdata = kg->osl_tdata;
429 shaderdata_to_shaderglobals(kg, sd, 0, tdata);
432 OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
433 OSL::ShaderGlobals *globals = &tdata->globals;
434 OSL::ShadingContext *octx = tdata->context[(int)ctx];
435 int shader = sd->shader & SHADER_MASK;
437 if (kg->osl->displacement_state[shader])
438 ss->execute(*octx, *(kg->osl->displacement_state[shader]), *globals);
440 /* get back position */
441 sd->P = TO_FLOAT3(globals->P);
446 int OSLShader::bsdf_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3& eval, float3& omega_in, differential3& domega_in, float& pdf)
448 CBSDFClosure *sample_bsdf = (CBSDFClosure *)sc->prim;
452 return sample_bsdf->sample(sd->Ng,
453 sd->I, sd->dI.dx, sd->dI.dy,
455 omega_in, domega_in.dx, domega_in.dy,
459 float3 OSLShader::bsdf_eval(const ShaderData *sd, const ShaderClosure *sc, const float3& omega_in, float& pdf)
461 CBSDFClosure *bsdf = (CBSDFClosure *)sc->prim;
464 if (dot(sd->Ng, omega_in) >= 0.0f)
465 bsdf_eval = bsdf->eval_reflect(sd->I, omega_in, pdf);
467 bsdf_eval = bsdf->eval_transmit(sd->I, omega_in, pdf);
472 void OSLShader::bsdf_blur(ShaderClosure *sc, float roughness)
474 CBSDFClosure *bsdf = (CBSDFClosure *)sc->prim;
475 bsdf->blur(roughness);
478 /* Emissive Closure */
480 float3 OSLShader::emissive_eval(const ShaderData *sd, const ShaderClosure *sc)
482 OSL::EmissiveClosure *emissive = (OSL::EmissiveClosure *)sc->prim;
483 OSL::Color3 emissive_eval = emissive->eval(TO_VEC3(sd->Ng), TO_VEC3(sd->I));
485 return TO_FLOAT3(emissive_eval);
490 float3 OSLShader::volume_eval_phase(const ShaderClosure *sc, const float3 omega_in, const float3 omega_out)
492 OSL::VolumeClosure *volume = (OSL::VolumeClosure *)sc->prim;
493 OSL::Color3 volume_eval = volume->eval_phase(TO_VEC3(omega_in), TO_VEC3(omega_out));
494 return TO_FLOAT3(volume_eval) * sc->weight;
499 int OSLShader::find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeElement *elem)
501 /* for OSL, a hash map is used to lookup the attribute by name. */
502 int object = sd->object*ATTR_PRIM_TYPES;
504 if(sd->segment != ~0) object += ATTR_PRIM_CURVE;
507 OSLGlobals::AttributeMap &attr_map = kg->osl->attribute_map[object];
508 ustring stdname(std::string("geom:") + std::string(Attribute::standard_name((AttributeStandard)id)));
509 OSLGlobals::AttributeMap::const_iterator it = attr_map.find(stdname);
511 if (it != attr_map.end()) {
512 const OSLGlobals::Attribute &osl_attr = it->second;
513 *elem = osl_attr.elem;
515 return (osl_attr.elem == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : osl_attr.offset;
518 return (int)ATTR_STD_NOT_FOUND;