Changeset View
Standalone View
intern/cycles/render/nodes.cpp
| Show All 14 Lines | |||||
| */ | */ | ||||
| #include "image.h" | #include "image.h" | ||||
| #include "integrator.h" | #include "integrator.h" | ||||
| #include "nodes.h" | #include "nodes.h" | ||||
| #include "scene.h" | #include "scene.h" | ||||
| #include "svm.h" | #include "svm.h" | ||||
| #include "svm_color_util.h" | #include "svm_color_util.h" | ||||
| #include "svm_ramp_util.h" | |||||
| #include "svm_math_util.h" | #include "svm_math_util.h" | ||||
| #include "osl.h" | #include "osl.h" | ||||
| #include "constant_fold.h" | #include "constant_fold.h" | ||||
| #include "util_sky_model.h" | #include "util_sky_model.h" | ||||
| #include "util_foreach.h" | #include "util_foreach.h" | ||||
| #include "util_transform.h" | #include "util_transform.h" | ||||
| ▲ Show 20 Lines • Show All 4,816 Lines • ▼ Show 20 Lines | void BumpNode::constant_fold(const ConstantFolder& folder) | ||||
| /* TODO(sergey): Ignore bump with zero strength. */ | /* TODO(sergey): Ignore bump with zero strength. */ | ||||
| } | } | ||||
| /* Curve node */ | /* Curve node */ | ||||
| CurvesNode::CurvesNode(const NodeType *node_type) | CurvesNode::CurvesNode(const NodeType *node_type) | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
sergey: This seems to be almost exact copy of `rgb_ramp_lookup()`. Think it should be possible to… | |||||
Not Done Inline ActionsAs stated at the top, this is an almost exact copy of the similar function for OSL - the reason for it being that the SVM code is way too ugly to be easily understood, and even uses float4 which the nodes definitely don't. The only changes here are the function header, call to ramp.size() and the 'f' suffix to all the floating point constants. Incidentally, speaking of code duplication, that osl function is itself copied verbatim in two osl files, despite osl evidently supporting include. angavrilov: As stated at the top, this is an almost exact copy of the similar function for OSL - the reason… | |||||
Not Done Inline ActionsSince it's essentially the same code, potentially this curves function can be merged with the original OSL version with some #defines and #ifdefs - OSL apparently is supposed to support full C preprocessor. Of course, sharing C++ and OSL code is a bit suspect. angavrilov: Since it's essentially the same code, potentially this curves function can be merged with the… | |||||
Not Done Inline ActionsIt shouldn't be hard to make some changes to SVM code to make rgb_ramp_lookup() re-usable here. Could be an inlined utility function to which we pass pointer to a points array and stride in that array. In fact, you might ignore the fact that rgb_ramp_lookup() operates with float4 and use component after the lookup is done. This is a single-run operation anyway, it's not so much extra evaluation and it works fast enough to be used from kernel even. Or even go a step forward and make svm_node_rgb_curves() usable here, so it saves duplication in constant_fold() as well. I'm all against increasing duplication factor here. sergey: It shouldn't be hard to make some changes to SVM code to make `rgb_ramp_lookup()` re-usable… | |||||
Not Done Inline ActionsThe problem is that SVM uses fetch_node_float, which uses kernel_tex_fetch. We can do something like this to make the SVM function reusable, but it's not pretty: #if !(defined(__KERNEL_CPU__) || defined(__KERNEL_GPU__)) #define KernelGlobals float3 #define fetch_node_float(kg, offset) kg[offset] #endif brecht: The problem is that SVM uses `fetch_node_float`, which uses `kernel_tex_fetch`. We can do… | |||||
Not Done Inline ActionsOr do something like: svm_ramp_util.h:
ccl_device_inline svm_rgb_do_lookup(float4 *values, ...) {
...
// Do all the lookup logic here, using `values[x]` instead of fetch.
..
}
svm_ramp.h:
ccl_device_inline svm_rgb_lookup(KernelGlobals *kg, ...) {
return svm_rgb_do_lookup(&fetch_node_float(kg, 0), ...)
}sergey: Or do something like:
svm_ramp_util.h:
ccl_device_inline svm_rgb_do_lookup(float4 *values… | |||||
Not Done Inline Actionsccl_device_inline svm_rgb_do_lookup(float4 *values, ...) {How would this work given that the array in nodes contains float3? angavrilov: ```
ccl_device_inline svm_rgb_do_lookup(float4 *values, ...) {
```
How would this work given… | |||||
Not Done Inline ActionsYou just replace float4 with float3. I don't have source handy to give exact snippet, just giving idea hoping that one would extend it further. sergey: You just replace `float4` with `float3`. I don't have source handy to give __exact__ snippet… | |||||
Not Done Inline Actions&fetch_node_float(kg, 0) can't work on the GPU when the SVM nodes are stored in a texture. I'd like this code to be deduplicated too, but I'm not sure there's a simple way to do it here. We could change the SVM nodes from texture storage to array storage on all GPUs, so that you can pass an array pointer always. This might have a performance impact on some of the older CUDA GPUs and requires some deeper changes in the device code. It would be interesting to investigate doing constant folding generically, for example compiling and evaluating a single SVM node, or adding some extra abstraction that lets us share code for constant folding, SVM and maybe even OSL. But those are bigger changes which I don't think should block this patch. brecht: `&fetch_node_float(kg, 0)` can't work on the GPU when the SVM nodes are stored in a texture. | |||||
| } | } | ||||
Not Done Inline ActionsThis doesn't follow Cycles code style. sergey: This doesn't follow Cycles code style. | |||||
| void CurvesNode::constant_fold(const ConstantFolder& folder, ShaderInput *value_in) | |||||
| { | |||||
| ShaderInput *fac_in = input("Fac"); | |||||
| /* remove no-op node */ | |||||
| if(!fac_in->link && fac == 0.0f) { | |||||
| folder.bypass(value_in->link); | |||||
| } | |||||
| /* evaluate fully constant node */ | |||||
| else if(folder.all_inputs_constant()) { | |||||
| if (curves.size() == 0) | |||||
| return; | |||||
| float3 pos = (value - make_float3(min_x, min_x, min_x)) / (max_x - min_x); | |||||
| float3 result; | |||||
| result[0] = rgb_ramp_lookup(curves.data(), pos[0], true, true, curves.size()).x; | |||||
| result[1] = rgb_ramp_lookup(curves.data(), pos[1], true, true, curves.size()).y; | |||||
| result[2] = rgb_ramp_lookup(curves.data(), pos[2], true, true, curves.size()).z; | |||||
| folder.make_constant(interp(value, result, fac)); | |||||
| } | |||||
| } | |||||
| void CurvesNode::compile(SVMCompiler& compiler, int type, ShaderInput *value_in, ShaderOutput *value_out) | void CurvesNode::compile(SVMCompiler& compiler, int type, ShaderInput *value_in, ShaderOutput *value_out) | ||||
| { | { | ||||
| if(curves.size() == 0) | if(curves.size() == 0) | ||||
| return; | return; | ||||
| ShaderInput *fac_in = input("Fac"); | ShaderInput *fac_in = input("Fac"); | ||||
| compiler.add_node(type, | compiler.add_node(type, | ||||
| ▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | NODE_DEFINE(RGBCurvesNode) | ||||
| return type; | return type; | ||||
| } | } | ||||
| RGBCurvesNode::RGBCurvesNode() | RGBCurvesNode::RGBCurvesNode() | ||||
| : CurvesNode(node_type) | : CurvesNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| void RGBCurvesNode::constant_fold(const ConstantFolder& folder) | |||||
| { | |||||
| CurvesNode::constant_fold(folder, input("Color")); | |||||
| } | |||||
| void RGBCurvesNode::compile(SVMCompiler& compiler) | void RGBCurvesNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| CurvesNode::compile(compiler, NODE_RGB_CURVES, input("Color"), output("Color")); | CurvesNode::compile(compiler, NODE_RGB_CURVES, input("Color"), output("Color")); | ||||
| } | } | ||||
| void RGBCurvesNode::compile(OSLCompiler& compiler) | void RGBCurvesNode::compile(OSLCompiler& compiler) | ||||
| { | { | ||||
| CurvesNode::compile(compiler, "node_rgb_curves"); | CurvesNode::compile(compiler, "node_rgb_curves"); | ||||
| Show All 17 Lines | NODE_DEFINE(VectorCurvesNode) | ||||
| return type; | return type; | ||||
| } | } | ||||
| VectorCurvesNode::VectorCurvesNode() | VectorCurvesNode::VectorCurvesNode() | ||||
| : CurvesNode(node_type) | : CurvesNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| void VectorCurvesNode::constant_fold(const ConstantFolder& folder) | |||||
| { | |||||
| CurvesNode::constant_fold(folder, input("Vector")); | |||||
| } | |||||
| void VectorCurvesNode::compile(SVMCompiler& compiler) | void VectorCurvesNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| CurvesNode::compile(compiler, NODE_VECTOR_CURVES, input("Vector"), output("Vector")); | CurvesNode::compile(compiler, NODE_VECTOR_CURVES, input("Vector"), output("Vector")); | ||||
| } | } | ||||
| void VectorCurvesNode::compile(OSLCompiler& compiler) | void VectorCurvesNode::compile(OSLCompiler& compiler) | ||||
| { | { | ||||
| CurvesNode::compile(compiler, "node_vector_curves"); | CurvesNode::compile(compiler, "node_vector_curves"); | ||||
| Show All 17 Lines | NODE_DEFINE(RGBRampNode) | ||||
| return type; | return type; | ||||
| } | } | ||||
| RGBRampNode::RGBRampNode() | RGBRampNode::RGBRampNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| void RGBRampNode::constant_fold(const ConstantFolder& folder) | |||||
| { | |||||
| if(ramp.size() == 0 || ramp.size() != ramp_alpha.size()) | |||||
| return; | |||||
| if(folder.all_inputs_constant()) { | |||||
| float f = clamp(fac, 0.0f, 1.0f) * (ramp.size() - 1); | |||||
| /* clamp int as well in case of NaN */ | |||||
| int i = clamp((int)f, 0, ramp.size()-1); | |||||
| float t = f - (float)i; | |||||
| bool use_lerp = interpolate && t > 0.0f; | |||||
| if(folder.output == output("Color")) { | |||||
| float3 color = rgb_ramp_lookup(ramp.data(), fac, use_lerp, false, ramp.size()); | |||||
| folder.make_constant(color); | |||||
| } | |||||
| else if(folder.output == output("Alpha")) { | |||||
| float alpha = float_ramp_lookup(ramp_alpha.data(), fac, use_lerp, false, ramp_alpha.size()); | |||||
| folder.make_constant(alpha); | |||||
| } | |||||
| } | |||||
| } | |||||
| void RGBRampNode::compile(SVMCompiler& compiler) | void RGBRampNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| if(ramp.size() == 0 || ramp.size() != ramp_alpha.size()) | if(ramp.size() == 0 || ramp.size() != ramp_alpha.size()) | ||||
| return; | return; | ||||
| ShaderInput *fac_in = input("Fac"); | ShaderInput *fac_in = input("Fac"); | ||||
| ShaderOutput *color_out = output("Color"); | ShaderOutput *color_out = output("Color"); | ||||
| ShaderOutput *alpha_out = output("Alpha"); | ShaderOutput *alpha_out = output("Alpha"); | ||||
| ▲ Show 20 Lines • Show All 305 Lines • Show Last 20 Lines | |||||
This seems to be almost exact copy of rgb_ramp_lookup(). Think it should be possible to introduce svm_ramp_util.h with implementation of ramp lookup understandable by both kernel and SVM compiler.