Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/render/constant_fold.cpp
| Show All 26 Lines | ConstantFolder::ConstantFolder(ShaderGraph *graph, | ||||
| ShaderOutput *output, | ShaderOutput *output, | ||||
| Scene *scene) | Scene *scene) | ||||
| : graph(graph), node(node), output(output), scene(scene) | : graph(graph), node(node), output(output), scene(scene) | ||||
| { | { | ||||
| } | } | ||||
| bool ConstantFolder::all_inputs_constant() const | bool ConstantFolder::all_inputs_constant() const | ||||
| { | { | ||||
| foreach (ShaderInput *input, node->inputs) { | foreach (ShaderInput *input, node->get_inputs()) { | ||||
| if (input->link) { | if (input->get_link()) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| void ConstantFolder::make_constant(float value) const | void ConstantFolder::make_constant(float value) const | ||||
| { | { | ||||
| VLOG(1) << "Folding " << node->name << "::" << output->name() << " to constant (" << value | VLOG(1) << "Folding " << node->get_name() << "::" << output->name() << " to constant (" << value | ||||
| << ")."; | << ")."; | ||||
| foreach (ShaderInput *sock, output->links) { | foreach (ShaderInput *sock, output->get_links()) { | ||||
| sock->set(value); | sock->set(value); | ||||
| } | } | ||||
| graph->disconnect(output); | graph->disconnect(output); | ||||
| } | } | ||||
| void ConstantFolder::make_constant(float3 value) const | void ConstantFolder::make_constant(float3 value) const | ||||
| { | { | ||||
| VLOG(1) << "Folding " << node->name << "::" << output->name() << " to constant " << value << "."; | VLOG(1) << "Folding " << node->get_name() << "::" << output->name() << " to constant " << value | ||||
| << "."; | |||||
| foreach (ShaderInput *sock, output->links) { | foreach (ShaderInput *sock, output->get_links()) { | ||||
| sock->set(value); | sock->set(value); | ||||
| } | } | ||||
| graph->disconnect(output); | graph->disconnect(output); | ||||
| } | } | ||||
| void ConstantFolder::make_constant_clamp(float value, bool clamp) const | void ConstantFolder::make_constant_clamp(float value, bool clamp) const | ||||
| { | { | ||||
| Show All 36 Lines | else { | ||||
| assert(0); | assert(0); | ||||
| } | } | ||||
| } | } | ||||
| void ConstantFolder::bypass(ShaderOutput *new_output) const | void ConstantFolder::bypass(ShaderOutput *new_output) const | ||||
| { | { | ||||
| assert(new_output); | assert(new_output); | ||||
| VLOG(1) << "Folding " << node->name << "::" << output->name() << " to socket " | VLOG(1) << "Folding " << node->get_name() << "::" << output->name() << " to socket " | ||||
| << new_output->parent->name << "::" << new_output->name() << "."; | << new_output->get_parent()->get_name() << "::" << new_output->name() << "."; | ||||
| /* Remove all outgoing links from socket and connect them to new_output instead. | /* Remove all outgoing links from socket and connect them to new_output instead. | ||||
| * The graph->relink method affects node inputs, so it's not safe to use in constant | * The graph->relink method affects node inputs, so it's not safe to use in constant | ||||
| * folding if the node has multiple outputs and will thus be folded multiple times. */ | * folding if the node has multiple outputs and will thus be folded multiple times. */ | ||||
| vector<ShaderInput *> outputs = output->links; | vector<ShaderInput *> outputs = output->get_links(); | ||||
| graph->disconnect(output); | graph->disconnect(output); | ||||
| foreach (ShaderInput *sock, outputs) { | foreach (ShaderInput *sock, outputs) { | ||||
| graph->connect(new_output, sock); | graph->connect(new_output, sock); | ||||
| } | } | ||||
| } | } | ||||
| void ConstantFolder::discard() const | void ConstantFolder::discard() const | ||||
| { | { | ||||
| assert(output->type() == SocketType::CLOSURE); | assert(output->type() == SocketType::CLOSURE); | ||||
| VLOG(1) << "Discarding closure " << node->name << "."; | VLOG(1) << "Discarding closure " << node->get_name() << "."; | ||||
| graph->disconnect(output); | graph->disconnect(output); | ||||
| } | } | ||||
| void ConstantFolder::bypass_or_discard(ShaderInput *input) const | void ConstantFolder::bypass_or_discard(ShaderInput *input) const | ||||
| { | { | ||||
| assert(input->type() == SocketType::CLOSURE); | assert(input->type() == SocketType::CLOSURE); | ||||
| if (input->link) { | if (input->get_link()) { | ||||
| bypass(input->link); | bypass(input->get_link()); | ||||
| } | } | ||||
| else { | else { | ||||
| discard(); | discard(); | ||||
| } | } | ||||
| } | } | ||||
| bool ConstantFolder::try_bypass_or_make_constant(ShaderInput *input, bool clamp) const | bool ConstantFolder::try_bypass_or_make_constant(ShaderInput *input, bool clamp) const | ||||
| { | { | ||||
| if (input->type() != output->type()) { | if (input->type() != output->type()) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| else if (!input->link) { | else if (!input->get_link()) { | ||||
| if (input->type() == SocketType::FLOAT) { | if (input->type() == SocketType::FLOAT) { | ||||
| make_constant_clamp(node->get_float(input->socket_type), clamp); | make_constant_clamp(node->get_float(input->get_socket_type()), clamp); | ||||
| return true; | return true; | ||||
| } | } | ||||
| else if (SocketType::is_float3(input->type())) { | else if (SocketType::is_float3(input->type())) { | ||||
| make_constant_clamp(node->get_float3(input->socket_type), clamp); | make_constant_clamp(node->get_float3(input->get_socket_type()), clamp); | ||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| else if (!clamp) { | else if (!clamp) { | ||||
| bypass(input->link); | bypass(input->get_link()); | ||||
| return true; | return true; | ||||
| } | } | ||||
| else { | else { | ||||
| /* disconnect other inputs if we can't fully bypass due to clamp */ | /* disconnect other inputs if we can't fully bypass due to clamp */ | ||||
| foreach (ShaderInput *other, node->inputs) { | foreach (ShaderInput *other, node->get_inputs()) { | ||||
| if (other != input && other->link) { | if (other != input && other->get_link()) { | ||||
| graph->disconnect(other); | graph->disconnect(other); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| bool ConstantFolder::is_zero(ShaderInput *input) const | bool ConstantFolder::is_zero(ShaderInput *input) const | ||||
| { | { | ||||
| if (!input->link) { | if (!input->get_link()) { | ||||
| if (input->type() == SocketType::FLOAT) { | if (input->type() == SocketType::FLOAT) { | ||||
| return node->get_float(input->socket_type) == 0.0f; | return node->get_float(input->get_socket_type()) == 0.0f; | ||||
| } | } | ||||
| else if (SocketType::is_float3(input->type())) { | else if (SocketType::is_float3(input->type())) { | ||||
| return node->get_float3(input->socket_type) == make_float3(0.0f, 0.0f, 0.0f); | return node->get_float3(input->get_socket_type()) == make_float3(0.0f, 0.0f, 0.0f); | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| bool ConstantFolder::is_one(ShaderInput *input) const | bool ConstantFolder::is_one(ShaderInput *input) const | ||||
| { | { | ||||
| if (!input->link) { | if (!input->get_link()) { | ||||
| if (input->type() == SocketType::FLOAT) { | if (input->type() == SocketType::FLOAT) { | ||||
| return node->get_float(input->socket_type) == 1.0f; | return node->get_float(input->get_socket_type()) == 1.0f; | ||||
| } | } | ||||
| else if (SocketType::is_float3(input->type())) { | else if (SocketType::is_float3(input->type())) { | ||||
| return node->get_float3(input->socket_type) == make_float3(1.0f, 1.0f, 1.0f); | return node->get_float3(input->get_socket_type()) == make_float3(1.0f, 1.0f, 1.0f); | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* Specific nodes */ | /* Specific nodes */ | ||||
| void ConstantFolder::fold_mix(NodeMix type, bool clamp) const | void ConstantFolder::fold_mix(NodeMix type, bool clamp) const | ||||
| { | { | ||||
| ShaderInput *fac_in = node->input("Fac"); | ShaderInput *fac_in = node->input("Fac"); | ||||
| ShaderInput *color1_in = node->input("Color1"); | ShaderInput *color1_in = node->input("Color1"); | ||||
| ShaderInput *color2_in = node->input("Color2"); | ShaderInput *color2_in = node->input("Color2"); | ||||
| float fac = saturate(node->get_float(fac_in->socket_type)); | float fac = saturate(node->get_float(fac_in->get_socket_type())); | ||||
| bool fac_is_zero = !fac_in->link && fac == 0.0f; | bool fac_is_zero = !fac_in->get_link() && fac == 0.0f; | ||||
| bool fac_is_one = !fac_in->link && fac == 1.0f; | bool fac_is_one = !fac_in->get_link() && fac == 1.0f; | ||||
| /* remove no-op node when factor is 0.0 */ | /* remove no-op node when factor is 0.0 */ | ||||
| if (fac_is_zero) { | if (fac_is_zero) { | ||||
| /* note that some of the modes will clamp out of bounds values even without use_clamp */ | /* note that some of the modes will clamp out of bounds values even without use_clamp */ | ||||
| if (!(type == NODE_MIX_LIGHT || type == NODE_MIX_DODGE || type == NODE_MIX_BURN)) { | if (!(type == NODE_MIX_LIGHT || type == NODE_MIX_DODGE || type == NODE_MIX_BURN)) { | ||||
| if (try_bypass_or_make_constant(color1_in, clamp)) { | if (try_bypass_or_make_constant(color1_in, clamp)) { | ||||
| return; | return; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| switch (type) { | switch (type) { | ||||
| case NODE_MIX_BLEND: | case NODE_MIX_BLEND: | ||||
| /* remove useless mix colors nodes */ | /* remove useless mix colors nodes */ | ||||
| if (color1_in->link && color2_in->link) { | if (color1_in->get_link() && color2_in->get_link()) { | ||||
| if (color1_in->link == color2_in->link) { | if (color1_in->get_link() == color2_in->get_link()) { | ||||
| try_bypass_or_make_constant(color1_in, clamp); | try_bypass_or_make_constant(color1_in, clamp); | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| else if (!color1_in->link && !color2_in->link) { | else if (!color1_in->get_link() && !color2_in->get_link()) { | ||||
| float3 color1 = node->get_float3(color1_in->socket_type); | float3 color1 = node->get_float3(color1_in->get_socket_type()); | ||||
| float3 color2 = node->get_float3(color2_in->socket_type); | float3 color2 = node->get_float3(color2_in->get_socket_type()); | ||||
| if (color1 == color2) { | if (color1 == color2) { | ||||
| try_bypass_or_make_constant(color1_in, clamp); | try_bypass_or_make_constant(color1_in, clamp); | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| /* remove no-op mix color node when factor is 1.0 */ | /* remove no-op mix color node when factor is 1.0 */ | ||||
| if (fac_is_one) { | if (fac_is_one) { | ||||
| try_bypass_or_make_constant(color2_in, clamp); | try_bypass_or_make_constant(color2_in, clamp); | ||||
| Show All 11 Lines | case NODE_MIX_ADD: | ||||
| } | } | ||||
| break; | break; | ||||
| case NODE_MIX_SUB: | case NODE_MIX_SUB: | ||||
| /* X - 0 (fac ?) == X */ | /* X - 0 (fac ?) == X */ | ||||
| if (is_zero(color2_in)) { | if (is_zero(color2_in)) { | ||||
| try_bypass_or_make_constant(color1_in, clamp); | try_bypass_or_make_constant(color1_in, clamp); | ||||
| } | } | ||||
| /* X - X (fac 1) == 0 */ | /* X - X (fac 1) == 0 */ | ||||
| else if (color1_in->link && color1_in->link == color2_in->link && fac_is_one) { | else if (color1_in->get_link() && color1_in->get_link() == color2_in->get_link() && | ||||
| fac_is_one) { | |||||
| make_zero(); | make_zero(); | ||||
| } | } | ||||
| break; | break; | ||||
| case NODE_MIX_MUL: | case NODE_MIX_MUL: | ||||
| /* X * 1 (fac ?) == X, 1 * X (fac 1) == X */ | /* X * 1 (fac ?) == X, 1 * X (fac 1) == X */ | ||||
| if (is_one(color1_in) && fac_is_one) { | if (is_one(color1_in) && fac_is_one) { | ||||
| try_bypass_or_make_constant(color2_in, clamp); | try_bypass_or_make_constant(color2_in, clamp); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 172 Lines • Show Last 20 Lines | |||||