6b3a996ca12a56254c051e61a1767d0a68ad325e
[blender.git] / intern / cycles / kernel / osl / osl_shader.cpp
1 /*
2  * Copyright 2011-2013 Blender Foundation
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include <OSL/oslexec.h>
18
19 #include "kernel/kernel_compat_cpu.h"
20 #include "kernel/kernel_montecarlo.h"
21 #include "kernel/kernel_types.h"
22 #include "kernel/split/kernel_split_data_types.h"
23 #include "kernel/kernel_globals.h"
24
25 #include "kernel/geom/geom_object.h"
26
27 #include "kernel/osl/osl_closures.h"
28 #include "kernel/osl/osl_globals.h"
29 #include "kernel/osl/osl_services.h"
30 #include "kernel/osl/osl_shader.h"
31
32 #include "util/util_foreach.h"
33
34 #include "render/attribute.h"
35
36
37 CCL_NAMESPACE_BEGIN
38
39 /* Threads */
40
41 void OSLShader::thread_init(KernelGlobals *kg, KernelGlobals *kernel_globals, OSLGlobals *osl_globals)
42 {
43         /* no osl used? */
44         if(!osl_globals->use) {
45                 kg->osl = NULL;
46                 return;
47         }
48
49         /* per thread kernel data init*/
50         kg->osl = osl_globals;
51         kg->osl->services->thread_init(kernel_globals, osl_globals->ts);
52
53         OSL::ShadingSystem *ss = kg->osl->ss;
54         OSLThreadData *tdata = new OSLThreadData();
55
56         memset(&tdata->globals, 0, sizeof(OSL::ShaderGlobals));
57         tdata->globals.tracedata = &tdata->tracedata;
58         tdata->globals.flipHandedness = false;
59         tdata->osl_thread_info = ss->create_thread_info();
60         tdata->context = ss->get_context(tdata->osl_thread_info);
61
62         tdata->oiio_thread_info = osl_globals->ts->get_perthread_info();
63
64         kg->osl_ss = (OSLShadingSystem*)ss;
65         kg->osl_tdata = tdata;
66 }
67
68 void OSLShader::thread_free(KernelGlobals *kg)
69 {
70         if(!kg->osl)
71                 return;
72
73         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
74         OSLThreadData *tdata = kg->osl_tdata;
75         ss->release_context(tdata->context);
76
77         ss->destroy_thread_info(tdata->osl_thread_info);
78
79         delete tdata;
80
81         kg->osl = NULL;
82         kg->osl_ss = NULL;
83         kg->osl_tdata = NULL;
84 }
85
86 /* Globals */
87
88 static void shaderdata_to_shaderglobals(KernelGlobals *kg, ShaderData *sd, PathState *state,
89                                         int path_flag, OSLThreadData *tdata)
90 {
91         OSL::ShaderGlobals *globals = &tdata->globals;
92
93         /* copy from shader data to shader globals */
94         globals->P = TO_VEC3(sd->P);
95         globals->dPdx = TO_VEC3(sd->dP.dx);
96         globals->dPdy = TO_VEC3(sd->dP.dy);
97         globals->I = TO_VEC3(sd->I);
98         globals->dIdx = TO_VEC3(sd->dI.dx);
99         globals->dIdy = TO_VEC3(sd->dI.dy);
100         globals->N = TO_VEC3(sd->N);
101         globals->Ng = TO_VEC3(sd->Ng);
102         globals->u = sd->u;
103         globals->dudx = sd->du.dx;
104         globals->dudy = sd->du.dy;
105         globals->v = sd->v;
106         globals->dvdx = sd->dv.dx;
107         globals->dvdy = sd->dv.dy;
108         globals->dPdu = TO_VEC3(sd->dPdu);
109         globals->dPdv = TO_VEC3(sd->dPdv);
110         globals->surfacearea = (sd->object == OBJECT_NONE) ? 1.0f : object_surface_area(kg, sd->object);
111         globals->time = sd->time;
112
113         /* booleans */
114         globals->raytype = path_flag;
115         globals->backfacing = (sd->flag & SD_BACKFACING);
116
117         /* shader data to be used in services callbacks */
118         globals->renderstate = sd; 
119
120         /* hacky, we leave it to services to fetch actual object matrix */
121         globals->shader2common = sd;
122         globals->object2common = sd;
123
124         /* must be set to NULL before execute */
125         globals->Ci = NULL;
126
127         /* clear trace data */
128         tdata->tracedata.init = false;
129
130         /* used by renderservices */
131         sd->osl_globals = kg;
132         sd->osl_path_state = state;
133 }
134
135 /* Surface */
136
137 static void flatten_surface_closure_tree(ShaderData *sd,
138                                          int path_flag,
139                                          const OSL::ClosureColor *closure,
140                                          float3 weight = make_float3(1.0f, 1.0f, 1.0f))
141 {
142         /* OSL gives us a closure tree, we flatten it into arrays per
143          * closure type, for evaluation, sampling, etc later on. */
144
145         switch(closure->id) {
146                 case OSL::ClosureColor::MUL: {
147                         OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
148                         flatten_surface_closure_tree(sd, path_flag, mul->closure, TO_FLOAT3(mul->weight) * weight);
149                         break;
150                 }
151                 case OSL::ClosureColor::ADD: {
152                         OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
153                         flatten_surface_closure_tree(sd, path_flag, add->closureA, weight);
154                         flatten_surface_closure_tree(sd, path_flag, add->closureB, weight);
155                         break;
156                 }
157                 default: {
158                         OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
159                         CClosurePrimitive *prim = (CClosurePrimitive *)comp->data();
160
161                         if(prim) {
162 #ifdef OSL_SUPPORTS_WEIGHTED_CLOSURE_COMPONENTS
163                                 weight = weight*TO_FLOAT3(comp->w);
164 #endif
165                                 prim->setup(sd, path_flag, weight);
166                         }
167                         break;
168                 }
169         }
170 }
171
172 void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag)
173 {
174         /* setup shader globals from shader data */
175         OSLThreadData *tdata = kg->osl_tdata;
176         shaderdata_to_shaderglobals(kg, sd, state, path_flag, tdata);
177
178         /* execute shader for this point */
179         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
180         OSL::ShaderGlobals *globals = &tdata->globals;
181         OSL::ShadingContext *octx = tdata->context;
182         int shader = sd->shader & SHADER_MASK;
183
184         /* automatic bump shader */
185         if(kg->osl->bump_state[shader]) {
186                 /* save state */
187                 float3 P = sd->P;
188                 float3 dPdx = sd->dP.dx;
189                 float3 dPdy = sd->dP.dy;
190
191                 /* set state as if undisplaced */
192                 if(sd->flag & SD_HAS_DISPLACEMENT) {
193                         float data[9];
194                         bool found = kg->osl->services->get_attribute(sd, true, OSLRenderServices::u_empty, TypeDesc::TypeVector,
195                                                                       OSLRenderServices::u_geom_undisplaced, data);
196                         (void)found;
197                         assert(found);
198
199                         memcpy(&sd->P, data, sizeof(float)*3);
200                         memcpy(&sd->dP.dx, data+3, sizeof(float)*3);
201                         memcpy(&sd->dP.dy, data+6, sizeof(float)*3);
202
203                         object_position_transform(kg, sd, &sd->P);
204                         object_dir_transform(kg, sd, &sd->dP.dx);
205                         object_dir_transform(kg, sd, &sd->dP.dy);
206
207                         globals->P = TO_VEC3(sd->P);
208                         globals->dPdx = TO_VEC3(sd->dP.dx);
209                         globals->dPdy = TO_VEC3(sd->dP.dy);
210                 }
211
212                 /* execute bump shader */
213                 ss->execute(octx, *(kg->osl->bump_state[shader]), *globals);
214
215                 /* reset state */
216                 sd->P = P;
217                 sd->dP.dx = dPdx;
218                 sd->dP.dy = dPdy;
219
220                 globals->P = TO_VEC3(P);
221                 globals->dPdx = TO_VEC3(dPdx);
222                 globals->dPdy = TO_VEC3(dPdy);
223         }
224
225         /* surface shader */
226         if(kg->osl->surface_state[shader]) {
227                 ss->execute(octx, *(kg->osl->surface_state[shader]), *globals);
228         }
229
230         /* flatten closure tree */
231         if(globals->Ci)
232                 flatten_surface_closure_tree(sd, path_flag, globals->Ci);
233 }
234
235 /* Background */
236
237 static void flatten_background_closure_tree(ShaderData *sd,
238                                             const OSL::ClosureColor *closure,
239                                             float3 weight = make_float3(1.0f, 1.0f, 1.0f))
240 {
241         /* OSL gives us a closure tree, if we are shading for background there
242          * is only one supported closure type at the moment, which has no evaluation
243          * functions, so we just sum the weights */
244
245         switch(closure->id) {
246                 case OSL::ClosureColor::MUL: {
247                         OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
248                         flatten_background_closure_tree(sd, mul->closure, weight * TO_FLOAT3(mul->weight));
249                         break;
250                 }
251                 case OSL::ClosureColor::ADD: {
252                         OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
253
254                         flatten_background_closure_tree(sd, add->closureA, weight);
255                         flatten_background_closure_tree(sd, add->closureB, weight);
256                         break;
257                 }
258                 default: {
259                         OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
260                         CClosurePrimitive *prim = (CClosurePrimitive *)comp->data();
261
262                         if(prim) {
263 #ifdef OSL_SUPPORTS_WEIGHTED_CLOSURE_COMPONENTS
264                                 weight = weight*TO_FLOAT3(comp->w);
265 #endif
266                                 prim->setup(sd, 0, weight);
267                         }
268                         break;
269                 }
270         }
271 }
272
273 void OSLShader::eval_background(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag)
274 {
275         /* setup shader globals from shader data */
276         OSLThreadData *tdata = kg->osl_tdata;
277         shaderdata_to_shaderglobals(kg, sd, state, path_flag, tdata);
278
279         /* execute shader for this point */
280         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
281         OSL::ShaderGlobals *globals = &tdata->globals;
282         OSL::ShadingContext *octx = tdata->context;
283
284         if(kg->osl->background_state) {
285                 ss->execute(octx, *(kg->osl->background_state), *globals);
286         }
287
288         /* return background color immediately */
289         if(globals->Ci)
290                 flatten_background_closure_tree(sd, globals->Ci);
291 }
292
293 /* Volume */
294
295 static void flatten_volume_closure_tree(ShaderData *sd,
296                                         const OSL::ClosureColor *closure,
297                                         float3 weight = make_float3(1.0f, 1.0f, 1.0f))
298 {
299         /* OSL gives us a closure tree, we flatten it into arrays per
300          * closure type, for evaluation, sampling, etc later on. */
301
302         switch(closure->id) {
303                 case OSL::ClosureColor::MUL: {
304                         OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
305                         flatten_volume_closure_tree(sd, mul->closure, TO_FLOAT3(mul->weight) * weight);
306                         break;
307                 }
308                 case OSL::ClosureColor::ADD: {
309                         OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
310                         flatten_volume_closure_tree(sd, add->closureA, weight);
311                         flatten_volume_closure_tree(sd, add->closureB, weight);
312                         break;
313                 }
314                 default: {
315                         OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
316                         CClosurePrimitive *prim = (CClosurePrimitive *)comp->data();
317
318                         if(prim) {
319 #ifdef OSL_SUPPORTS_WEIGHTED_CLOSURE_COMPONENTS
320                                 weight = weight*TO_FLOAT3(comp->w);
321 #endif
322                                 prim->setup(sd, 0, weight);
323                         }
324                 }
325         }
326 }
327
328 void OSLShader::eval_volume(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag)
329 {
330         /* setup shader globals from shader data */
331         OSLThreadData *tdata = kg->osl_tdata;
332         shaderdata_to_shaderglobals(kg, sd, state, path_flag, tdata);
333
334         /* execute shader */
335         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
336         OSL::ShaderGlobals *globals = &tdata->globals;
337         OSL::ShadingContext *octx = tdata->context;
338         int shader = sd->shader & SHADER_MASK;
339
340         if(kg->osl->volume_state[shader]) {
341                 ss->execute(octx, *(kg->osl->volume_state[shader]), *globals);
342         }
343         
344         /* flatten closure tree */
345         if(globals->Ci)
346                 flatten_volume_closure_tree(sd, globals->Ci);
347 }
348
349 /* Displacement */
350
351 void OSLShader::eval_displacement(KernelGlobals *kg, ShaderData *sd, PathState *state)
352 {
353         /* setup shader globals from shader data */
354         OSLThreadData *tdata = kg->osl_tdata;
355
356         shaderdata_to_shaderglobals(kg, sd, state, 0, tdata);
357
358         /* execute shader */
359         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
360         OSL::ShaderGlobals *globals = &tdata->globals;
361         OSL::ShadingContext *octx = tdata->context;
362         int shader = sd->shader & SHADER_MASK;
363
364         if(kg->osl->displacement_state[shader]) {
365                 ss->execute(octx, *(kg->osl->displacement_state[shader]), *globals);
366         }
367
368         /* get back position */
369         sd->P = TO_FLOAT3(globals->P);
370 }
371
372 /* Attributes */
373
374 int OSLShader::find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeDescriptor *desc)
375 {
376         /* for OSL, a hash map is used to lookup the attribute by name. */
377         int object = sd->object*ATTR_PRIM_TYPES;
378 #ifdef __HAIR__
379         if(sd->type & PRIMITIVE_ALL_CURVE) object += ATTR_PRIM_CURVE;
380 #endif
381
382         OSLGlobals::AttributeMap &attr_map = kg->osl->attribute_map[object];
383         ustring stdname(std::string("geom:") + std::string(Attribute::standard_name((AttributeStandard)id)));
384         OSLGlobals::AttributeMap::const_iterator it = attr_map.find(stdname);
385
386         if(it != attr_map.end()) {
387                 const OSLGlobals::Attribute &osl_attr = it->second;
388                 *desc = osl_attr.desc;
389
390                 if(sd->prim == PRIM_NONE && (AttributeElement)osl_attr.desc.element != ATTR_ELEMENT_MESH) {
391                         desc->offset = ATTR_STD_NOT_FOUND;
392                         return ATTR_STD_NOT_FOUND;
393                 }
394
395                 /* return result */
396                 if(osl_attr.desc.element == ATTR_ELEMENT_NONE) {
397                         desc->offset = ATTR_STD_NOT_FOUND;
398                 }
399                 return desc->offset;
400         }
401         else {
402                 desc->offset = ATTR_STD_NOT_FOUND;
403                 return (int)ATTR_STD_NOT_FOUND;
404         }
405 }
406
407 CCL_NAMESPACE_END
408