Blender  V3.3
kernel/osl/shader.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright 2011-2022 Blender Foundation */
3 
4 #include <OSL/oslexec.h>
5 
6 // clang-format off
9 
10 #include "kernel/types.h"
11 
12 #include "kernel/geom/object.h"
13 
15 
16 #include "kernel/osl/closures.h"
17 #include "kernel/osl/globals.h"
18 #include "kernel/osl/services.h"
19 #include "kernel/osl/shader.h"
20 
22 // clang-format on
23 
24 #include "scene/attribute.h"
25 
27 
28 /* Threads */
29 
30 void OSLShader::thread_init(KernelGlobalsCPU *kg, OSLGlobals *osl_globals)
31 {
32  /* no osl used? */
33  if (!osl_globals->use) {
34  kg->osl = NULL;
35  return;
36  }
37 
38  /* Per thread kernel data init. */
39  kg->osl = osl_globals;
40 
41  OSL::ShadingSystem *ss = kg->osl->ss;
42  OSLThreadData *tdata = new OSLThreadData();
43 
44  memset((void *)&tdata->globals, 0, sizeof(OSL::ShaderGlobals));
45  tdata->globals.tracedata = &tdata->tracedata;
46  tdata->globals.flipHandedness = false;
47  tdata->osl_thread_info = ss->create_thread_info();
48  tdata->context = ss->get_context(tdata->osl_thread_info);
49 
50  tdata->oiio_thread_info = osl_globals->ts->get_perthread_info();
51 
52  kg->osl_ss = (OSLShadingSystem *)ss;
53  kg->osl_tdata = tdata;
54 }
55 
56 void OSLShader::thread_free(KernelGlobalsCPU *kg)
57 {
58  if (!kg->osl)
59  return;
60 
61  OSL::ShadingSystem *ss = (OSL::ShadingSystem *)kg->osl_ss;
62  OSLThreadData *tdata = kg->osl_tdata;
63  ss->release_context(tdata->context);
64 
65  ss->destroy_thread_info(tdata->osl_thread_info);
66 
67  delete tdata;
68 
69  kg->osl = NULL;
70  kg->osl_ss = NULL;
71  kg->osl_tdata = NULL;
72 }
73 
74 /* Globals */
75 
77  ShaderData *sd,
78  const void *state,
79  uint32_t path_flag,
80  OSLThreadData *tdata)
81 {
82  OSL::ShaderGlobals *globals = &tdata->globals;
83 
84  /* copy from shader data to shader globals */
85  globals->P = TO_VEC3(sd->P);
86  globals->dPdx = TO_VEC3(sd->dP.dx);
87  globals->dPdy = TO_VEC3(sd->dP.dy);
88  globals->I = TO_VEC3(sd->I);
89  globals->dIdx = TO_VEC3(sd->dI.dx);
90  globals->dIdy = TO_VEC3(sd->dI.dy);
91  globals->N = TO_VEC3(sd->N);
92  globals->Ng = TO_VEC3(sd->Ng);
93  globals->u = sd->u;
94  globals->dudx = sd->du.dx;
95  globals->dudy = sd->du.dy;
96  globals->v = sd->v;
97  globals->dvdx = sd->dv.dx;
98  globals->dvdy = sd->dv.dy;
99  globals->dPdu = TO_VEC3(sd->dPdu);
100  globals->dPdv = TO_VEC3(sd->dPdv);
101  globals->surfacearea = 1.0f;
102  globals->time = sd->time;
103 
104  /* booleans */
105  globals->raytype = path_flag;
106  globals->backfacing = (sd->flag & SD_BACKFACING);
107 
108  /* shader data to be used in services callbacks */
109  globals->renderstate = sd;
110 
111  /* hacky, we leave it to services to fetch actual object matrix */
112  globals->shader2common = sd;
113  globals->object2common = sd;
114 
115  /* must be set to NULL before execute */
116  globals->Ci = NULL;
117 
118  /* clear trace data */
119  tdata->tracedata.init = false;
120 
121  /* Used by render-services. */
122  sd->osl_globals = kg;
123  if (path_flag & PATH_RAY_SHADOW) {
124  sd->osl_path_state = nullptr;
125  sd->osl_shadow_path_state = (const IntegratorShadowStateCPU *)state;
126  }
127  else {
128  sd->osl_path_state = (const IntegratorStateCPU *)state;
129  sd->osl_shadow_path_state = nullptr;
130  }
131 }
132 
133 /* Surface */
134 
136  uint32_t path_flag,
137  const OSL::ClosureColor *closure,
138  float3 weight = make_float3(1.0f, 1.0f, 1.0f))
139 {
140  /* OSL gives us a closure tree, we flatten it into arrays per
141  * closure type, for evaluation, sampling, etc later on. */
142 
143  switch (closure->id) {
144  case OSL::ClosureColor::MUL: {
145  OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
146  flatten_surface_closure_tree(sd, path_flag, mul->closure, TO_FLOAT3(mul->weight) * weight);
147  break;
148  }
149  case OSL::ClosureColor::ADD: {
150  OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
151  flatten_surface_closure_tree(sd, path_flag, add->closureA, weight);
152  flatten_surface_closure_tree(sd, path_flag, add->closureB, weight);
153  break;
154  }
155  default: {
156  OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
157  CClosurePrimitive *prim = (CClosurePrimitive *)comp->data();
158 
159  if (prim) {
160 #ifdef OSL_SUPPORTS_WEIGHTED_CLOSURE_COMPONENTS
161  weight = weight * TO_FLOAT3(comp->w);
162 #endif
163  prim->setup(sd, path_flag, weight);
164  }
165  break;
166  }
167  }
168 }
169 
170 void OSLShader::eval_surface(const KernelGlobalsCPU *kg,
171  const void *state,
172  ShaderData *sd,
173  uint32_t path_flag)
174 {
175  /* setup shader globals from shader data */
176  OSLThreadData *tdata = kg->osl_tdata;
177  shaderdata_to_shaderglobals(kg, sd, state, path_flag, tdata);
178 
179  /* execute shader for this point */
180  OSL::ShadingSystem *ss = (OSL::ShadingSystem *)kg->osl_ss;
181  OSL::ShaderGlobals *globals = &tdata->globals;
182  OSL::ShadingContext *octx = tdata->context;
183  int shader = sd->shader & SHADER_MASK;
184 
185  /* automatic bump shader */
186  if (kg->osl->bump_state[shader]) {
187  /* save state */
188  float3 P = sd->P;
189  float3 dPdx = sd->dP.dx;
190  float3 dPdy = sd->dP.dy;
191 
192  /* set state as if undisplaced */
193  if (sd->flag & SD_HAS_DISPLACEMENT) {
194  float data[9];
195  bool found = kg->osl->services->get_attribute(sd,
196  true,
198  TypeDesc::TypeVector,
200  data);
201  (void)found;
202  assert(found);
203 
204  differential3 dP;
205  memcpy(&sd->P, data, sizeof(float) * 3);
206  memcpy(&dP.dx, data + 3, sizeof(float) * 3);
207  memcpy(&dP.dy, data + 6, sizeof(float) * 3);
208 
209  object_position_transform(kg, sd, &sd->P);
210  object_dir_transform(kg, sd, &dP.dx);
211  object_dir_transform(kg, sd, &dP.dy);
212 
213  const float dP_radius = differential_make_compact(dP);
214 
215  make_orthonormals(sd->Ng, &sd->dP.dx, &sd->dP.dy);
216  sd->dP.dx *= dP_radius;
217  sd->dP.dy *= dP_radius;
218 
219  globals->P = TO_VEC3(sd->P);
220  globals->dPdx = TO_VEC3(sd->dP.dx);
221  globals->dPdy = TO_VEC3(sd->dP.dy);
222  }
223 
224  /* execute bump shader */
225  ss->execute(octx, *(kg->osl->bump_state[shader]), *globals);
226 
227  /* reset state */
228  sd->P = P;
229  sd->dP.dx = dPdx;
230  sd->dP.dy = dPdy;
231 
232  globals->P = TO_VEC3(P);
233  globals->dPdx = TO_VEC3(dPdx);
234  globals->dPdy = TO_VEC3(dPdy);
235  }
236 
237  /* surface shader */
238  if (kg->osl->surface_state[shader]) {
239  ss->execute(octx, *(kg->osl->surface_state[shader]), *globals);
240  }
241 
242  /* flatten closure tree */
243  if (globals->Ci)
244  flatten_surface_closure_tree(sd, path_flag, globals->Ci);
245 }
246 
247 /* Background */
248 
250  const OSL::ClosureColor *closure,
251  float3 weight = make_float3(1.0f, 1.0f, 1.0f))
252 {
253  /* OSL gives us a closure tree, if we are shading for background there
254  * is only one supported closure type at the moment, which has no evaluation
255  * functions, so we just sum the weights */
256 
257  switch (closure->id) {
258  case OSL::ClosureColor::MUL: {
259  OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
260  flatten_background_closure_tree(sd, mul->closure, weight * TO_FLOAT3(mul->weight));
261  break;
262  }
263  case OSL::ClosureColor::ADD: {
264  OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
265 
266  flatten_background_closure_tree(sd, add->closureA, weight);
267  flatten_background_closure_tree(sd, add->closureB, weight);
268  break;
269  }
270  default: {
271  OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
272  CClosurePrimitive *prim = (CClosurePrimitive *)comp->data();
273 
274  if (prim) {
275 #ifdef OSL_SUPPORTS_WEIGHTED_CLOSURE_COMPONENTS
276  weight = weight * TO_FLOAT3(comp->w);
277 #endif
278  prim->setup(sd, 0, weight);
279  }
280  break;
281  }
282  }
283 }
284 
285 void OSLShader::eval_background(const KernelGlobalsCPU *kg,
286  const void *state,
287  ShaderData *sd,
288  uint32_t path_flag)
289 {
290  /* setup shader globals from shader data */
291  OSLThreadData *tdata = kg->osl_tdata;
292  shaderdata_to_shaderglobals(kg, sd, state, path_flag, tdata);
293 
294  /* execute shader for this point */
295  OSL::ShadingSystem *ss = (OSL::ShadingSystem *)kg->osl_ss;
296  OSL::ShaderGlobals *globals = &tdata->globals;
297  OSL::ShadingContext *octx = tdata->context;
298 
299  if (kg->osl->background_state) {
300  ss->execute(octx, *(kg->osl->background_state), *globals);
301  }
302 
303  /* return background color immediately */
304  if (globals->Ci)
305  flatten_background_closure_tree(sd, globals->Ci);
306 }
307 
308 /* Volume */
309 
311  const OSL::ClosureColor *closure,
312  float3 weight = make_float3(1.0f, 1.0f, 1.0f))
313 {
314  /* OSL gives us a closure tree, we flatten it into arrays per
315  * closure type, for evaluation, sampling, etc later on. */
316 
317  switch (closure->id) {
318  case OSL::ClosureColor::MUL: {
319  OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
320  flatten_volume_closure_tree(sd, mul->closure, TO_FLOAT3(mul->weight) * weight);
321  break;
322  }
323  case OSL::ClosureColor::ADD: {
324  OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
325  flatten_volume_closure_tree(sd, add->closureA, weight);
326  flatten_volume_closure_tree(sd, add->closureB, weight);
327  break;
328  }
329  default: {
330  OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
331  CClosurePrimitive *prim = (CClosurePrimitive *)comp->data();
332 
333  if (prim) {
334 #ifdef OSL_SUPPORTS_WEIGHTED_CLOSURE_COMPONENTS
335  weight = weight * TO_FLOAT3(comp->w);
336 #endif
337  prim->setup(sd, 0, weight);
338  }
339  }
340  }
341 }
342 
343 void OSLShader::eval_volume(const KernelGlobalsCPU *kg,
344  const void *state,
345  ShaderData *sd,
346  uint32_t path_flag)
347 {
348  /* setup shader globals from shader data */
349  OSLThreadData *tdata = kg->osl_tdata;
350  shaderdata_to_shaderglobals(kg, sd, state, path_flag, tdata);
351 
352  /* execute shader */
353  OSL::ShadingSystem *ss = (OSL::ShadingSystem *)kg->osl_ss;
354  OSL::ShaderGlobals *globals = &tdata->globals;
355  OSL::ShadingContext *octx = tdata->context;
356  int shader = sd->shader & SHADER_MASK;
357 
358  if (kg->osl->volume_state[shader]) {
359  ss->execute(octx, *(kg->osl->volume_state[shader]), *globals);
360  }
361 
362  /* flatten closure tree */
363  if (globals->Ci)
364  flatten_volume_closure_tree(sd, globals->Ci);
365 }
366 
367 /* Displacement */
368 
369 void OSLShader::eval_displacement(const KernelGlobalsCPU *kg, const void *state, ShaderData *sd)
370 {
371  /* setup shader globals from shader data */
372  OSLThreadData *tdata = kg->osl_tdata;
373 
374  shaderdata_to_shaderglobals(kg, sd, state, 0, tdata);
375 
376  /* execute shader */
377  OSL::ShadingSystem *ss = (OSL::ShadingSystem *)kg->osl_ss;
378  OSL::ShaderGlobals *globals = &tdata->globals;
379  OSL::ShadingContext *octx = tdata->context;
380  int shader = sd->shader & SHADER_MASK;
381 
382  if (kg->osl->displacement_state[shader]) {
383  ss->execute(octx, *(kg->osl->displacement_state[shader]), *globals);
384  }
385 
386  /* get back position */
387  sd->P = TO_FLOAT3(globals->P);
388 }
389 
390 /* Attributes */
391 
393  const ShaderData *sd,
394  uint id,
395  AttributeDescriptor *desc)
396 {
397  /* for OSL, a hash map is used to lookup the attribute by name. */
398  int object = sd->object * ATTR_PRIM_TYPES;
399 
400  OSLGlobals::AttributeMap &attr_map = kg->osl->attribute_map[object];
401  ustring stdname(std::string("geom:") +
402  std::string(Attribute::standard_name((AttributeStandard)id)));
403  OSLGlobals::AttributeMap::const_iterator it = attr_map.find(stdname);
404 
405  if (it != attr_map.end()) {
406  const OSLGlobals::Attribute &osl_attr = it->second;
407  *desc = osl_attr.desc;
408 
409  if (sd->prim == PRIM_NONE && (AttributeElement)osl_attr.desc.element != ATTR_ELEMENT_MESH) {
410  desc->offset = ATTR_STD_NOT_FOUND;
411  return ATTR_STD_NOT_FOUND;
412  }
413 
414  /* return result */
415  if (osl_attr.desc.element == ATTR_ELEMENT_NONE) {
416  desc->offset = ATTR_STD_NOT_FOUND;
417  }
418  return desc->offset;
419  }
420  else {
421  desc->offset = ATTR_STD_NOT_FOUND;
422  return (int)ATTR_STD_NOT_FOUND;
423  }
424 }
425 
unsigned int uint
Definition: BLI_sys_types.h:67
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its and value channels Color Attribute
#define MUL(x, y, z)
Definition: RandGen.cpp:33
static void mul(btAlignedObjectArray< T > &items, const Q &value)
static const char * standard_name(AttributeStandard std)
virtual void setup(ShaderData *sd, uint32_t path_flag, float3 weight)=0
static ustring u_empty
Definition: services.h:316
static ustring u_geom_undisplaced
Definition: services.h:289
#define TO_FLOAT3(v)
Definition: closures.h:89
#define TO_VEC3(v)
Definition: closures.h:87
#define CCL_NAMESPACE_END
Definition: cuda/compat.h:9
ccl_device_forceinline float differential_make_compact(const differential3 D)
Definition: differential.h:117
SyclQueue void void size_t num_bytes void
const int state
ccl_device_inline AttributeDescriptor find_attribute(KernelGlobals kg, ccl_private const ShaderData *sd, uint id)
ccl_device_inline void object_position_transform(KernelGlobals kg, ccl_private const ShaderData *sd, ccl_private float3 *P)
ccl_device_inline void object_dir_transform(KernelGlobals kg, ccl_private const ShaderData *sd, ccl_private float3 *D)
static void shaderdata_to_shaderglobals(const KernelGlobalsCPU *kg, ShaderData *sd, const void *state, uint32_t path_flag, OSLThreadData *tdata)
static void flatten_background_closure_tree(ShaderData *sd, const OSL::ClosureColor *closure, float3 weight=make_float3(1.0f, 1.0f, 1.0f))
static void flatten_surface_closure_tree(ShaderData *sd, uint32_t path_flag, const OSL::ClosureColor *closure, float3 weight=make_float3(1.0f, 1.0f, 1.0f))
static void flatten_volume_closure_tree(ShaderData *sd, const OSL::ClosureColor *closure, float3 weight=make_float3(1.0f, 1.0f, 1.0f))
@ SD_HAS_DISPLACEMENT
Definition: kernel/types.h:784
@ SD_BACKFACING
Definition: kernel/types.h:738
AttributeStandard
Definition: kernel/types.h:612
@ ATTR_STD_NOT_FOUND
Definition: kernel/types.h:647
#define PRIM_NONE
Definition: kernel/types.h:41
@ PATH_RAY_SHADOW
Definition: kernel/types.h:206
struct AttributeMap AttributeMap
ShaderData
Definition: kernel/types.h:925
@ SHADER_MASK
Definition: kernel/types.h:449
AttributeElement
Definition: kernel/types.h:597
@ ATTR_ELEMENT_NONE
Definition: kernel/types.h:598
@ ATTR_ELEMENT_MESH
Definition: kernel/types.h:600
@ ATTR_PRIM_TYPES
Definition: kernel/types.h:594
static float P(float k)
Definition: math_interp.c:25
#define make_float3(x, y, z)
Definition: metal/compat.h:204
bool add(void *owner, const AttributeIDRef &attribute_id, eAttrDomain domain, eCustomDataType data_type, const AttributeInit &initializer)
ShadingSystem
Definition: scene/shader.h:34
unsigned int uint32_t
Definition: stdint.h:80
static void eval_displacement(SubdivDisplacement *displacement, const int ptex_face_index, const float u, const float v, const float dPdu[3], const float dPdv[3], float r_D[3])
ccl_device_inline void make_orthonormals(const float3 N, ccl_private float3 *a, ccl_private float3 *b)
Definition: util/math.h:566