Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/kernel/osl/closures.cpp
| Show All 19 Lines | |||||
| #include "kernel/device/cpu/compat.h" | #include "kernel/device/cpu/compat.h" | ||||
| #include "kernel/device/cpu/globals.h" | #include "kernel/device/cpu/globals.h" | ||||
| #include "kernel/geom/object.h" | #include "kernel/geom/object.h" | ||||
| #include "kernel/util/differential.h" | #include "kernel/util/differential.h" | ||||
| #include "kernel/osl/osl.h" | #include "kernel/osl/osl.h" | ||||
| #include "kernel/osl/closures_setup.h" | |||||
| #define TO_VEC3(v) OSL::Vec3(v.x, v.y, v.z) | #define TO_VEC3(v) OSL::Vec3(v.x, v.y, v.z) | ||||
| #define TO_FLOAT3(v) make_float3(v[0], v[1], v[2]) | #define TO_FLOAT3(v) make_float3(v[0], v[1], v[2]) | ||||
| CCL_NAMESPACE_BEGIN | CCL_NAMESPACE_BEGIN | ||||
| static_assert(sizeof(OSLClosure) == sizeof(OSL::ClosureColor) && | |||||
| sizeof(OSLClosureAdd) == sizeof(OSL::ClosureAdd) && | |||||
| sizeof(OSLClosureMul) == sizeof(OSL::ClosureMul) && | |||||
| sizeof(OSLClosureComponent) == sizeof(OSL::ClosureComponent)); | |||||
| static_assert(sizeof(ShaderGlobals) == sizeof(OSL::ShaderGlobals) && | |||||
| offsetof(ShaderGlobals, Ci) == offsetof(OSL::ShaderGlobals, Ci)); | |||||
| /* Registration */ | /* Registration */ | ||||
| #define OSL_CLOSURE_STRUCT_BEGIN(Upper, lower) \ | #define OSL_CLOSURE_STRUCT_BEGIN(Upper, lower) \ | ||||
| static OSL::ClosureParam *osl_closure_##lower##_params() \ | static OSL::ClosureParam *osl_closure_##lower##_params() \ | ||||
| { \ | { \ | ||||
| static OSL::ClosureParam params[] = { | static OSL::ClosureParam params[] = { | ||||
| #define OSL_CLOSURE_STRUCT_END(Upper, lower) \ | #define OSL_CLOSURE_STRUCT_END(Upper, lower) \ | ||||
| CLOSURE_STRING_KEYPARAM(Upper##Closure, label, "label"), CLOSURE_FINISH_PARAM(Upper##Closure) \ | CLOSURE_STRING_KEYPARAM(Upper##Closure, label, "label"), CLOSURE_FINISH_PARAM(Upper##Closure) \ | ||||
| Show All 12 Lines | |||||
| { | { | ||||
| #define OSL_CLOSURE_STRUCT_BEGIN(Upper, lower) \ | #define OSL_CLOSURE_STRUCT_BEGIN(Upper, lower) \ | ||||
| ss->register_closure( \ | ss->register_closure( \ | ||||
| #lower, OSL_CLOSURE_##Upper##_ID, osl_closure_##lower##_params(), nullptr, nullptr); | #lower, OSL_CLOSURE_##Upper##_ID, osl_closure_##lower##_params(), nullptr, nullptr); | ||||
| #include "closures_template.h" | #include "closures_template.h" | ||||
| } | } | ||||
| /* Globals */ | /* Surface & Background */ | ||||
| static void shaderdata_to_shaderglobals(const KernelGlobalsCPU *kg, | template<> | ||||
| ShaderData *sd, | void osl_eval_nodes<SHADER_TYPE_SURFACE>(const KernelGlobalsCPU *kg, | ||||
| const void *state, | const void *state, | ||||
| uint32_t path_flag, | ShaderData *sd, | ||||
| OSLThreadData *tdata) | uint32_t path_flag) | ||||
| { | { | ||||
| OSL::ShaderGlobals *globals = &tdata->globals; | /* setup shader globals from shader data */ | ||||
| OSLThreadData *tdata = kg->osl_tdata; | |||||
| const differential3 dP = differential_from_compact(sd->Ng, sd->dP); | shaderdata_to_shaderglobals( | ||||
| const differential3 dI = differential_from_compact(sd->I, sd->dI); | kg, sd, path_flag, reinterpret_cast<ShaderGlobals *>(&tdata->globals)); | ||||
| /* copy from shader data to shader globals */ | |||||
| globals->P = TO_VEC3(sd->P); | |||||
| globals->dPdx = TO_VEC3(dP.dx); | |||||
| globals->dPdy = TO_VEC3(dP.dy); | |||||
| globals->I = TO_VEC3(sd->I); | |||||
| globals->dIdx = TO_VEC3(dI.dx); | |||||
| globals->dIdy = TO_VEC3(dI.dy); | |||||
| globals->N = TO_VEC3(sd->N); | |||||
| globals->Ng = TO_VEC3(sd->Ng); | |||||
| globals->u = sd->u; | |||||
| globals->dudx = sd->du.dx; | |||||
| globals->dudy = sd->du.dy; | |||||
| globals->v = sd->v; | |||||
| globals->dvdx = sd->dv.dx; | |||||
| globals->dvdy = sd->dv.dy; | |||||
| globals->dPdu = TO_VEC3(sd->dPdu); | |||||
| globals->dPdv = TO_VEC3(sd->dPdv); | |||||
| globals->surfacearea = 1.0f; | |||||
| globals->time = sd->time; | |||||
| /* booleans */ | |||||
| globals->raytype = path_flag; | |||||
| globals->flipHandedness = 0; | |||||
| globals->backfacing = (sd->flag & SD_BACKFACING); | |||||
| /* shader data to be used in services callbacks */ | |||||
| globals->renderstate = sd; | |||||
| /* hacky, we leave it to services to fetch actual object matrix */ | |||||
| globals->shader2common = sd; | |||||
| globals->object2common = sd; | |||||
| /* must be set to NULL before execute */ | |||||
| globals->Ci = NULL; | |||||
| /* clear trace data */ | /* clear trace data */ | ||||
| tdata->tracedata.init = false; | tdata->tracedata.init = false; | ||||
| /* Used by render-services. */ | /* Used by render-services. */ | ||||
| sd->osl_globals = kg; | sd->osl_globals = kg; | ||||
| if (path_flag & PATH_RAY_SHADOW) { | if (path_flag & PATH_RAY_SHADOW) { | ||||
| sd->osl_path_state = nullptr; | sd->osl_path_state = nullptr; | ||||
| sd->osl_shadow_path_state = (const IntegratorShadowStateCPU *)state; | sd->osl_shadow_path_state = (const IntegratorShadowStateCPU *)state; | ||||
| } | } | ||||
| else { | else { | ||||
| sd->osl_path_state = (const IntegratorStateCPU *)state; | sd->osl_path_state = (const IntegratorStateCPU *)state; | ||||
| sd->osl_shadow_path_state = nullptr; | sd->osl_shadow_path_state = nullptr; | ||||
| } | } | ||||
| } | |||||
| static void flatten_closure_tree(const KernelGlobalsCPU *kg, | |||||
| ShaderData *sd, | |||||
| uint32_t path_flag, | |||||
| const OSL::ClosureColor *closure, | |||||
| float3 weight = make_float3(1.0f, 1.0f, 1.0f)) | |||||
| { | |||||
| /* OSL gives us a closure tree, we flatten it into arrays per | |||||
| * closure type, for evaluation, sampling, etc later on. */ | |||||
| switch (closure->id) { | |||||
| case OSL::ClosureColor::MUL: { | |||||
| OSL::ClosureMul *mul = (OSL::ClosureMul *)closure; | |||||
| flatten_closure_tree(kg, sd, path_flag, mul->closure, TO_FLOAT3(mul->weight) * weight); | |||||
| break; | |||||
| } | |||||
| case OSL::ClosureColor::ADD: { | |||||
| OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure; | |||||
| flatten_closure_tree(kg, sd, path_flag, add->closureA, weight); | |||||
| flatten_closure_tree(kg, sd, path_flag, add->closureB, weight); | |||||
| break; | |||||
| } | |||||
| #define OSL_CLOSURE_STRUCT_BEGIN(Upper, lower) \ | |||||
| case OSL_CLOSURE_##Upper##_ID: { \ | |||||
| const OSL::ClosureComponent *comp = reinterpret_cast<const OSL::ClosureComponent *>(closure); \ | |||||
| weight *= TO_FLOAT3(comp->w); \ | |||||
| osl_closure_##lower##_setup( \ | |||||
| kg, sd, path_flag, weight, reinterpret_cast<const Upper##Closure *>(comp + 1)); \ | |||||
| break; \ | |||||
| } | |||||
| #include "closures_template.h" | |||||
| default: | |||||
| break; | |||||
| } | |||||
| } | |||||
| /* Surface */ | |||||
| void OSLShader::eval_surface(const KernelGlobalsCPU *kg, | |||||
| const void *state, | |||||
| ShaderData *sd, | |||||
| uint32_t path_flag) | |||||
| { | |||||
| /* setup shader globals from shader data */ | |||||
| OSLThreadData *tdata = kg->osl_tdata; | |||||
| shaderdata_to_shaderglobals(kg, sd, state, path_flag, tdata); | |||||
| /* execute shader for this point */ | /* execute shader for this point */ | ||||
| OSL::ShadingSystem *ss = (OSL::ShadingSystem *)kg->osl_ss; | OSL::ShadingSystem *ss = (OSL::ShadingSystem *)kg->osl_ss; | ||||
| OSL::ShaderGlobals *globals = &tdata->globals; | OSL::ShaderGlobals *globals = &tdata->globals; | ||||
| OSL::ShadingContext *octx = tdata->context; | OSL::ShadingContext *octx = tdata->context; | ||||
| int shader = sd->shader & SHADER_MASK; | int shader = sd->shader & SHADER_MASK; | ||||
| if (sd->object == OBJECT_NONE && sd->lamp == LAMP_NONE) { | |||||
| /* background */ | |||||
| if (kg->osl->background_state) { | |||||
| ss->execute(octx, *(kg->osl->background_state), *globals); | |||||
| } | |||||
| } | |||||
| else { | |||||
| /* automatic bump shader */ | /* automatic bump shader */ | ||||
| if (kg->osl->bump_state[shader]) { | if (kg->osl->bump_state[shader]) { | ||||
| /* save state */ | /* save state */ | ||||
| const float3 P = sd->P; | const float3 P = sd->P; | ||||
| const float dP = sd->dP; | const float dP = sd->dP; | ||||
| const OSL::Vec3 dPdx = globals->dPdx; | const OSL::Vec3 dPdx = globals->dPdx; | ||||
| const OSL::Vec3 dPdy = globals->dPdy; | const OSL::Vec3 dPdy = globals->dPdy; | ||||
| /* set state as if undisplaced */ | /* set state as if undisplaced */ | ||||
| if (sd->flag & SD_HAS_DISPLACEMENT) { | if (sd->flag & SD_HAS_DISPLACEMENT) { | ||||
| float data[9]; | float data[9]; | ||||
| bool found = kg->osl->services->get_attribute(sd, | bool found = kg->osl->services->get_attribute(sd, | ||||
| true, | true, | ||||
| OSLRenderServices::u_empty, | OSLRenderServices::u_empty, | ||||
| TypeDesc::TypeVector, | TypeDesc::TypeVector, | ||||
| OSLRenderServices::u_geom_undisplaced, | OSLRenderServices::u_geom_undisplaced, | ||||
| data); | data); | ||||
| (void)found; | (void)found; | ||||
| assert(found); | assert(found); | ||||
| differential3 tmp_dP; | differential3 tmp_dP; | ||||
| memcpy(&sd->P, data, sizeof(float) * 3); | memcpy(&sd->P, data, sizeof(float) * 3); | ||||
| memcpy(&tmp_dP.dx, data + 3, sizeof(float) * 3); | memcpy(&tmp_dP.dx, data + 3, sizeof(float) * 3); | ||||
| memcpy(&tmp_dP.dy, data + 6, sizeof(float) * 3); | memcpy(&tmp_dP.dy, data + 6, sizeof(float) * 3); | ||||
| object_position_transform(kg, sd, &sd->P); | object_position_transform(kg, sd, &sd->P); | ||||
| object_dir_transform(kg, sd, &tmp_dP.dx); | object_dir_transform(kg, sd, &tmp_dP.dx); | ||||
| object_dir_transform(kg, sd, &tmp_dP.dy); | object_dir_transform(kg, sd, &tmp_dP.dy); | ||||
| sd->dP = differential_make_compact(tmp_dP); | sd->dP = differential_make_compact(tmp_dP); | ||||
| globals->P = TO_VEC3(sd->P); | globals->P = TO_VEC3(sd->P); | ||||
| globals->dPdx = TO_VEC3(tmp_dP.dx); | globals->dPdx = TO_VEC3(tmp_dP.dx); | ||||
| globals->dPdy = TO_VEC3(tmp_dP.dy); | globals->dPdy = TO_VEC3(tmp_dP.dy); | ||||
| } | } | ||||
| /* execute bump shader */ | /* execute bump shader */ | ||||
| ss->execute(octx, *(kg->osl->bump_state[shader]), *globals); | ss->execute(octx, *(kg->osl->bump_state[shader]), *globals); | ||||
| /* reset state */ | /* reset state */ | ||||
| sd->P = P; | sd->P = P; | ||||
| sd->dP = dP; | sd->dP = dP; | ||||
| globals->P = TO_VEC3(P); | globals->P = TO_VEC3(P); | ||||
| globals->dPdx = TO_VEC3(dPdx); | globals->dPdx = TO_VEC3(dPdx); | ||||
| globals->dPdy = TO_VEC3(dPdy); | globals->dPdy = TO_VEC3(dPdy); | ||||
| } | } | ||||
| /* surface shader */ | /* surface shader */ | ||||
| if (kg->osl->surface_state[shader]) { | if (kg->osl->surface_state[shader]) { | ||||
| ss->execute(octx, *(kg->osl->surface_state[shader]), *globals); | ss->execute(octx, *(kg->osl->surface_state[shader]), *globals); | ||||
| } | } | ||||
| } | |||||
| /* flatten closure tree */ | /* flatten closure tree */ | ||||
| if (globals->Ci) { | if (globals->Ci) { | ||||
| flatten_closure_tree(kg, sd, path_flag, globals->Ci); | flatten_closure_tree(kg, sd, path_flag, reinterpret_cast<OSLClosure *>(globals->Ci)); | ||||
| } | } | ||||
| } | } | ||||
| /* Background */ | /* Volume */ | ||||
| void OSLShader::eval_background(const KernelGlobalsCPU *kg, | template<> | ||||
| void osl_eval_nodes<SHADER_TYPE_VOLUME>(const KernelGlobalsCPU *kg, | |||||
| const void *state, | const void *state, | ||||
| ShaderData *sd, | ShaderData *sd, | ||||
| uint32_t path_flag) | uint32_t path_flag) | ||||
| { | { | ||||
| /* setup shader globals from shader data */ | /* setup shader globals from shader data */ | ||||
| OSLThreadData *tdata = kg->osl_tdata; | OSLThreadData *tdata = kg->osl_tdata; | ||||
| shaderdata_to_shaderglobals(kg, sd, state, path_flag, tdata); | shaderdata_to_shaderglobals( | ||||
| kg, sd, path_flag, reinterpret_cast<ShaderGlobals *>(&tdata->globals)); | |||||
| /* execute shader for this point */ | /* clear trace data */ | ||||
| OSL::ShadingSystem *ss = (OSL::ShadingSystem *)kg->osl_ss; | tdata->tracedata.init = false; | ||||
| OSL::ShaderGlobals *globals = &tdata->globals; | |||||
| OSL::ShadingContext *octx = tdata->context; | |||||
| if (kg->osl->background_state) { | |||||
| ss->execute(octx, *(kg->osl->background_state), *globals); | |||||
| } | |||||
| /* return background color immediately */ | /* Used by render-services. */ | ||||
| if (globals->Ci) { | sd->osl_globals = kg; | ||||
| flatten_closure_tree(kg, sd, path_flag, globals->Ci); | if (path_flag & PATH_RAY_SHADOW) { | ||||
| sd->osl_path_state = nullptr; | |||||
| sd->osl_shadow_path_state = (const IntegratorShadowStateCPU *)state; | |||||
| } | } | ||||
| else { | |||||
| sd->osl_path_state = (const IntegratorStateCPU *)state; | |||||
| sd->osl_shadow_path_state = nullptr; | |||||
| } | } | ||||
| /* Volume */ | |||||
| void OSLShader::eval_volume(const KernelGlobalsCPU *kg, | |||||
| const void *state, | |||||
| ShaderData *sd, | |||||
| uint32_t path_flag) | |||||
| { | |||||
| /* setup shader globals from shader data */ | |||||
| OSLThreadData *tdata = kg->osl_tdata; | |||||
| shaderdata_to_shaderglobals(kg, sd, state, path_flag, tdata); | |||||
| /* execute shader */ | /* execute shader */ | ||||
| OSL::ShadingSystem *ss = (OSL::ShadingSystem *)kg->osl_ss; | OSL::ShadingSystem *ss = (OSL::ShadingSystem *)kg->osl_ss; | ||||
| OSL::ShaderGlobals *globals = &tdata->globals; | OSL::ShaderGlobals *globals = &tdata->globals; | ||||
| OSL::ShadingContext *octx = tdata->context; | OSL::ShadingContext *octx = tdata->context; | ||||
| int shader = sd->shader & SHADER_MASK; | int shader = sd->shader & SHADER_MASK; | ||||
| if (kg->osl->volume_state[shader]) { | if (kg->osl->volume_state[shader]) { | ||||
| ss->execute(octx, *(kg->osl->volume_state[shader]), *globals); | ss->execute(octx, *(kg->osl->volume_state[shader]), *globals); | ||||
| } | } | ||||
| /* flatten closure tree */ | /* flatten closure tree */ | ||||
| if (globals->Ci) { | if (globals->Ci) { | ||||
| flatten_closure_tree(kg, sd, path_flag, globals->Ci); | flatten_closure_tree(kg, sd, path_flag, reinterpret_cast<OSLClosure *>(globals->Ci)); | ||||
| } | } | ||||
| } | } | ||||
| /* Displacement */ | /* Displacement */ | ||||
| void OSLShader::eval_displacement(const KernelGlobalsCPU *kg, const void *state, ShaderData *sd) | template<> | ||||
| void osl_eval_nodes<SHADER_TYPE_DISPLACEMENT>(const KernelGlobalsCPU *kg, | |||||
| const void *state, | |||||
| ShaderData *sd, | |||||
| uint32_t path_flag) | |||||
| { | { | ||||
| /* setup shader globals from shader data */ | /* setup shader globals from shader data */ | ||||
| OSLThreadData *tdata = kg->osl_tdata; | OSLThreadData *tdata = kg->osl_tdata; | ||||
| shaderdata_to_shaderglobals(kg, sd, state, 0, tdata); | shaderdata_to_shaderglobals( | ||||
| kg, sd, path_flag, reinterpret_cast<ShaderGlobals *>(&tdata->globals)); | |||||
| /* clear trace data */ | |||||
| tdata->tracedata.init = false; | |||||
| /* Used by render-services. */ | |||||
| sd->osl_globals = kg; | |||||
| sd->osl_path_state = (const IntegratorStateCPU *)state; | |||||
| sd->osl_shadow_path_state = nullptr; | |||||
| /* execute shader */ | /* execute shader */ | ||||
| OSL::ShadingSystem *ss = (OSL::ShadingSystem *)kg->osl_ss; | OSL::ShadingSystem *ss = (OSL::ShadingSystem *)kg->osl_ss; | ||||
| OSL::ShaderGlobals *globals = &tdata->globals; | OSL::ShaderGlobals *globals = &tdata->globals; | ||||
| OSL::ShadingContext *octx = tdata->context; | OSL::ShadingContext *octx = tdata->context; | ||||
| int shader = sd->shader & SHADER_MASK; | int shader = sd->shader & SHADER_MASK; | ||||
| if (kg->osl->displacement_state[shader]) { | if (kg->osl->displacement_state[shader]) { | ||||
| ss->execute(octx, *(kg->osl->displacement_state[shader]), *globals); | ss->execute(octx, *(kg->osl->displacement_state[shader]), *globals); | ||||
| } | } | ||||
| /* get back position */ | /* get back position */ | ||||
| sd->P = TO_FLOAT3(globals->P); | sd->P = TO_FLOAT3(globals->P); | ||||
| } | } | ||||
| CCL_NAMESPACE_END | CCL_NAMESPACE_END | ||||