Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/render/svm.cpp
| Show First 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | |||||
| void SVMShaderManager::device_update_shader(Scene *scene, | void SVMShaderManager::device_update_shader(Scene *scene, | ||||
| Shader *shader, | Shader *shader, | ||||
| Progress *progress, | Progress *progress, | ||||
| array<int4> *svm_nodes) | array<int4> *svm_nodes) | ||||
| { | { | ||||
| if (progress->get_cancel()) { | if (progress->get_cancel()) { | ||||
| return; | return; | ||||
| } | } | ||||
| assert(shader->graph); | assert(shader->get_graph()); | ||||
| svm_nodes->push_back_slow(make_int4(NODE_SHADER_JUMP, 0, 0, 0)); | svm_nodes->push_back_slow(make_int4(NODE_SHADER_JUMP, 0, 0, 0)); | ||||
| SVMCompiler::Summary summary; | SVMCompiler::Summary summary; | ||||
| SVMCompiler compiler(scene); | SVMCompiler compiler(scene); | ||||
| compiler.background = (shader == scene->background->get_shader(scene)); | compiler.background = (shader == scene->get_background()->get_shader(scene)); | ||||
| compiler.compile(shader, *svm_nodes, 0, &summary); | compiler.compile(shader, *svm_nodes, 0, &summary); | ||||
| VLOG(2) << "Compilation summary:\n" | VLOG(2) << "Compilation summary:\n" | ||||
| << "Shader name: " << shader->name << "\n" | << "Shader name: " << shader->get_name() << "\n" | ||||
| << summary.full_report(); | << summary.full_report(); | ||||
| } | } | ||||
| void SVMShaderManager::device_update(Device *device, | void SVMShaderManager::device_update(Device *device, | ||||
| DeviceScene *dscene, | DeviceScene *dscene, | ||||
| Scene *scene, | Scene *scene, | ||||
| Progress &progress) | Progress &progress) | ||||
| { | { | ||||
| if (!need_update) | if (!need_update) | ||||
| return; | return; | ||||
| scoped_callback_timer timer([scene](double time) { | scoped_callback_timer timer([scene](double time) { | ||||
| if (scene->update_stats) { | if (scene->get_update_stats()) { | ||||
| scene->update_stats->svm.times.add_entry({"device_update", time}); | scene->get_update_stats()->svm.times.add_entry({"device_update", time}); | ||||
| } | } | ||||
| }); | }); | ||||
| const int num_shaders = scene->shaders.size(); | const int num_shaders = scene->get_shaders().size(); | ||||
| VLOG(1) << "Total " << num_shaders << " shaders."; | VLOG(1) << "Total " << num_shaders << " shaders."; | ||||
| double start_time = time_dt(); | double start_time = time_dt(); | ||||
| /* test if we need to update */ | /* test if we need to update */ | ||||
| device_free(device, dscene, scene); | device_free(device, dscene, scene); | ||||
| /* Build all shaders. */ | /* Build all shaders. */ | ||||
| TaskPool task_pool; | TaskPool task_pool; | ||||
| vector<array<int4>> shader_svm_nodes(num_shaders); | vector<array<int4>> shader_svm_nodes(num_shaders); | ||||
| for (int i = 0; i < num_shaders; i++) { | for (int i = 0; i < num_shaders; i++) { | ||||
| task_pool.push(function_bind(&SVMShaderManager::device_update_shader, | task_pool.push(function_bind(&SVMShaderManager::device_update_shader, | ||||
| this, | this, | ||||
| scene, | scene, | ||||
| scene->shaders[i], | scene->get_shaders()[i], | ||||
| &progress, | &progress, | ||||
| &shader_svm_nodes[i])); | &shader_svm_nodes[i])); | ||||
| } | } | ||||
| task_pool.wait_work(); | task_pool.wait_work(); | ||||
| if (progress.get_cancel()) { | if (progress.get_cancel()) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* The global node list contains a jump table (one node per shader) | /* The global node list contains a jump table (one node per shader) | ||||
| * followed by the nodes of all shaders. */ | * followed by the nodes of all shaders. */ | ||||
| int svm_nodes_size = num_shaders; | int svm_nodes_size = num_shaders; | ||||
| for (int i = 0; i < num_shaders; i++) { | for (int i = 0; i < num_shaders; i++) { | ||||
| /* Since we're not copying the local jump node, the size ends up being one node lower. */ | /* Since we're not copying the local jump node, the size ends up being one node lower. */ | ||||
| svm_nodes_size += shader_svm_nodes[i].size() - 1; | svm_nodes_size += shader_svm_nodes[i].size() - 1; | ||||
| } | } | ||||
| int4 *svm_nodes = dscene->svm_nodes.alloc(svm_nodes_size); | int4 *svm_nodes = dscene->svm_nodes.alloc(svm_nodes_size); | ||||
| int node_offset = num_shaders; | int node_offset = num_shaders; | ||||
| for (int i = 0; i < num_shaders; i++) { | for (int i = 0; i < num_shaders; i++) { | ||||
| Shader *shader = scene->shaders[i]; | Shader *shader = scene->get_shaders()[i]; | ||||
| shader->clear_modified(); | shader->clear_modified(); | ||||
| if (shader->get_use_mis() && shader->has_surface_emission) { | if (shader->get_use_mis() && shader->get_has_surface_emission()) { | ||||
| scene->light_manager->need_update = true; | scene->get_light_manager()->need_update = true; | ||||
| } | } | ||||
| /* Update the global jump table. | /* Update the global jump table. | ||||
| * Each compiled shader starts with a jump node that has offsets local | * Each compiled shader starts with a jump node that has offsets local | ||||
| * to the shader, so copy those and add the offset into the global node list. */ | * to the shader, so copy those and add the offset into the global node list. */ | ||||
| int4 &global_jump_node = svm_nodes[shader->id]; | int4 &global_jump_node = svm_nodes[shader->get_id()]; | ||||
| int4 &local_jump_node = shader_svm_nodes[i][0]; | int4 &local_jump_node = shader_svm_nodes[i][0]; | ||||
| global_jump_node.x = NODE_SHADER_JUMP; | global_jump_node.x = NODE_SHADER_JUMP; | ||||
| global_jump_node.y = local_jump_node.y - 1 + node_offset; | global_jump_node.y = local_jump_node.y - 1 + node_offset; | ||||
| global_jump_node.z = local_jump_node.z - 1 + node_offset; | global_jump_node.z = local_jump_node.z - 1 + node_offset; | ||||
| global_jump_node.w = local_jump_node.w - 1 + node_offset; | global_jump_node.w = local_jump_node.w - 1 + node_offset; | ||||
| node_offset += shader_svm_nodes[i].size() - 1; | node_offset += shader_svm_nodes[i].size() - 1; | ||||
| ▲ Show 20 Lines • Show All 89 Lines • ▼ Show 20 Lines | if (num_unused == size) { | ||||
| return offset; | return offset; | ||||
| } | } | ||||
| } | } | ||||
| if (!compile_failed) { | if (!compile_failed) { | ||||
| compile_failed = true; | compile_failed = true; | ||||
| fprintf(stderr, | fprintf(stderr, | ||||
| "Cycles: out of SVM stack space, shader \"%s\" too big.\n", | "Cycles: out of SVM stack space, shader \"%s\" too big.\n", | ||||
| current_shader->name.c_str()); | current_shader->get_name().c_str()); | ||||
| } | } | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| int SVMCompiler::stack_find_offset(SocketType::Type type) | int SVMCompiler::stack_find_offset(SocketType::Type type) | ||||
| { | { | ||||
| return stack_find_offset(stack_size(type)); | return stack_find_offset(stack_size(type)); | ||||
| } | } | ||||
| void SVMCompiler::stack_clear_offset(SocketType::Type type, int offset) | void SVMCompiler::stack_clear_offset(SocketType::Type type, int offset) | ||||
| { | { | ||||
| int size = stack_size(type); | int size = stack_size(type); | ||||
| for (int i = 0; i < size; i++) | for (int i = 0; i < size; i++) | ||||
| active_stack.users[offset + i]--; | active_stack.users[offset + i]--; | ||||
| } | } | ||||
| int SVMCompiler::stack_assign(ShaderInput *input) | int SVMCompiler::stack_assign(ShaderInput *input) | ||||
| { | { | ||||
| /* stack offset assign? */ | /* stack offset assign? */ | ||||
| if (input->stack_offset == SVM_STACK_INVALID) { | if (input->get_stack_offset() == SVM_STACK_INVALID) { | ||||
| if (input->link) { | if (input->get_link()) { | ||||
| /* linked to output -> use output offset */ | /* linked to output -> use output offset */ | ||||
| assert(input->link->stack_offset != SVM_STACK_INVALID); | assert(input->get_link()->get_stack_offset() != SVM_STACK_INVALID); | ||||
| input->stack_offset = input->link->stack_offset; | input->get_stack_offset() = input->get_link()->get_stack_offset(); | ||||
| } | } | ||||
| else { | else { | ||||
| Node *node = input->parent; | Node *node = input->get_parent(); | ||||
| /* not linked to output -> add nodes to load default value */ | /* not linked to output -> add nodes to load default value */ | ||||
| input->stack_offset = stack_find_offset(input->type()); | input->get_stack_offset() = stack_find_offset(input->type()); | ||||
| if (input->type() == SocketType::FLOAT) { | if (input->type() == SocketType::FLOAT) { | ||||
| add_node(NODE_VALUE_F, | add_node(NODE_VALUE_F, | ||||
| __float_as_int(node->get_float(input->socket_type)), | __float_as_int(node->get_float(input->get_socket_type())), | ||||
| input->stack_offset); | input->get_stack_offset()); | ||||
| } | } | ||||
| else if (input->type() == SocketType::INT) { | else if (input->type() == SocketType::INT) { | ||||
| add_node(NODE_VALUE_F, node->get_int(input->socket_type), input->stack_offset); | add_node(NODE_VALUE_F, node->get_int(input->get_socket_type()), input->get_stack_offset()); | ||||
| } | } | ||||
| else if (input->type() == SocketType::VECTOR || input->type() == SocketType::NORMAL || | else if (input->type() == SocketType::VECTOR || input->type() == SocketType::NORMAL || | ||||
| input->type() == SocketType::POINT || input->type() == SocketType::COLOR) { | input->type() == SocketType::POINT || input->type() == SocketType::COLOR) { | ||||
| add_node(NODE_VALUE_V, input->stack_offset); | add_node(NODE_VALUE_V, input->get_stack_offset()); | ||||
| add_node(NODE_VALUE_V, node->get_float3(input->socket_type)); | add_node(NODE_VALUE_V, node->get_float3(input->get_socket_type())); | ||||
| } | } | ||||
| else /* should not get called for closure */ | else /* should not get called for closure */ | ||||
| assert(0); | assert(0); | ||||
| } | } | ||||
| } | } | ||||
| return input->stack_offset; | return input->get_stack_offset(); | ||||
| } | } | ||||
| int SVMCompiler::stack_assign(ShaderOutput *output) | int SVMCompiler::stack_assign(ShaderOutput *output) | ||||
| { | { | ||||
| /* if no stack offset assigned yet, find one */ | /* if no stack offset assigned yet, find one */ | ||||
| if (output->stack_offset == SVM_STACK_INVALID) | if (output->get_stack_offset() == SVM_STACK_INVALID) | ||||
| output->stack_offset = stack_find_offset(output->type()); | output->get_stack_offset() = stack_find_offset(output->type()); | ||||
| return output->stack_offset; | return output->get_stack_offset(); | ||||
| } | } | ||||
| int SVMCompiler::stack_assign_if_linked(ShaderInput *input) | int SVMCompiler::stack_assign_if_linked(ShaderInput *input) | ||||
| { | { | ||||
| if (input->link) | if (input->get_link()) | ||||
| return stack_assign(input); | return stack_assign(input); | ||||
| return SVM_STACK_INVALID; | return SVM_STACK_INVALID; | ||||
| } | } | ||||
| int SVMCompiler::stack_assign_if_linked(ShaderOutput *output) | int SVMCompiler::stack_assign_if_linked(ShaderOutput *output) | ||||
| { | { | ||||
| if (!output->links.empty()) | if (output->is_linked()) | ||||
| return stack_assign(output); | return stack_assign(output); | ||||
| return SVM_STACK_INVALID; | return SVM_STACK_INVALID; | ||||
| } | } | ||||
| void SVMCompiler::stack_link(ShaderInput *input, ShaderOutput *output) | void SVMCompiler::stack_link(ShaderInput *input, ShaderOutput *output) | ||||
| { | { | ||||
| if (output->stack_offset == SVM_STACK_INVALID) { | if (output->get_stack_offset() == SVM_STACK_INVALID) { | ||||
| assert(input->link); | assert(input->get_link()); | ||||
| assert(stack_size(output->type()) == stack_size(input->link->type())); | assert(stack_size(output->type()) == stack_size(input->get_link()->type())); | ||||
| output->stack_offset = input->link->stack_offset; | output->get_stack_offset() = input->get_link()->get_stack_offset(); | ||||
| int size = stack_size(output->type()); | int size = stack_size(output->type()); | ||||
| for (int i = 0; i < size; i++) | for (int i = 0; i < size; i++) | ||||
| active_stack.users[output->stack_offset + i]++; | active_stack.users[output->get_stack_offset() + i]++; | ||||
| } | } | ||||
| } | } | ||||
| void SVMCompiler::stack_clear_users(ShaderNode *node, ShaderNodeSet &done) | void SVMCompiler::stack_clear_users(ShaderNode *node, ShaderNodeSet &done) | ||||
| { | { | ||||
| /* optimization we should add: | /* optimization we should add: | ||||
| * find and lower user counts for outputs for which all inputs are done. | * find and lower user counts for outputs for which all inputs are done. | ||||
| * this is done before the node is compiled, under the assumption that the | * this is done before the node is compiled, under the assumption that the | ||||
| * node will first load all inputs from the stack and then writes its | * node will first load all inputs from the stack and then writes its | ||||
| * outputs. this used to work, but was disabled because it gave trouble | * outputs. this used to work, but was disabled because it gave trouble | ||||
| * with inputs getting stack positions assigned */ | * with inputs getting stack positions assigned */ | ||||
| foreach (ShaderInput *input, node->inputs) { | foreach (ShaderInput *input, node->get_inputs()) { | ||||
| ShaderOutput *output = input->link; | ShaderOutput *output = input->get_link(); | ||||
| if (output && output->stack_offset != SVM_STACK_INVALID) { | if (output && output->get_stack_offset() != SVM_STACK_INVALID) { | ||||
| bool all_done = true; | bool all_done = true; | ||||
| /* optimization we should add: verify if in->parent is actually used */ | /* optimization we should add: verify if in->get_parent() is actually used */ | ||||
| foreach (ShaderInput *in, output->links) | foreach (ShaderInput *in, output->get_links()) | ||||
| if (in->parent != node && done.find(in->parent) == done.end()) | if (in->get_parent() != node && done.find(in->get_parent()) == done.end()) | ||||
| all_done = false; | all_done = false; | ||||
| if (all_done) { | if (all_done) { | ||||
| stack_clear_offset(output->type(), output->stack_offset); | stack_clear_offset(output->type(), output->get_stack_offset()); | ||||
| output->stack_offset = SVM_STACK_INVALID; | output->get_stack_offset() = SVM_STACK_INVALID; | ||||
| foreach (ShaderInput *in, output->links) | foreach (ShaderInput *in, output->get_links()) | ||||
| in->stack_offset = SVM_STACK_INVALID; | in->get_stack_offset() = SVM_STACK_INVALID; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void SVMCompiler::stack_clear_temporary(ShaderNode *node) | void SVMCompiler::stack_clear_temporary(ShaderNode *node) | ||||
| { | { | ||||
| foreach (ShaderInput *input, node->inputs) { | foreach (ShaderInput *input, node->get_inputs()) { | ||||
| if (!input->link && input->stack_offset != SVM_STACK_INVALID) { | if (!input->get_link() && input->get_stack_offset() != SVM_STACK_INVALID) { | ||||
| stack_clear_offset(input->type(), input->stack_offset); | stack_clear_offset(input->type(), input->get_stack_offset()); | ||||
| input->stack_offset = SVM_STACK_INVALID; | input->get_stack_offset() = SVM_STACK_INVALID; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| uint SVMCompiler::encode_uchar4(uint x, uint y, uint z, uint w) | uint SVMCompiler::encode_uchar4(uint x, uint y, uint z, uint w) | ||||
| { | { | ||||
| assert(x <= 255); | assert(x <= 255); | ||||
| assert(y <= 255); | assert(y <= 255); | ||||
| Show All 22 Lines | |||||
| void SVMCompiler::add_node(const float4 &f) | void SVMCompiler::add_node(const float4 &f) | ||||
| { | { | ||||
| current_svm_nodes.push_back_slow(make_int4( | current_svm_nodes.push_back_slow(make_int4( | ||||
| __float_as_int(f.x), __float_as_int(f.y), __float_as_int(f.z), __float_as_int(f.w))); | __float_as_int(f.x), __float_as_int(f.y), __float_as_int(f.z), __float_as_int(f.w))); | ||||
| } | } | ||||
| uint SVMCompiler::attribute(ustring name) | uint SVMCompiler::attribute(ustring name) | ||||
| { | { | ||||
| return scene->shader_manager->get_attribute_id(name); | return scene->get_shader_manager()->get_attribute_id(name); | ||||
| } | } | ||||
| uint SVMCompiler::attribute(AttributeStandard std) | uint SVMCompiler::attribute(AttributeStandard std) | ||||
| { | { | ||||
| return scene->shader_manager->get_attribute_id(std); | return scene->get_shader_manager()->get_attribute_id(std); | ||||
| } | } | ||||
| uint SVMCompiler::attribute_standard(ustring name) | uint SVMCompiler::attribute_standard(ustring name) | ||||
| { | { | ||||
| AttributeStandard std = Attribute::name_standard(name.c_str()); | AttributeStandard std = Attribute::name_standard(name.c_str()); | ||||
| return (std) ? attribute(std) : attribute(name); | return (std) ? attribute(std) : attribute(name); | ||||
| } | } | ||||
| void SVMCompiler::find_dependencies(ShaderNodeSet &dependencies, | void SVMCompiler::find_dependencies(ShaderNodeSet &dependencies, | ||||
| const ShaderNodeSet &done, | const ShaderNodeSet &done, | ||||
| ShaderInput *input, | ShaderInput *input, | ||||
| ShaderNode *skip_node) | ShaderNode *skip_node) | ||||
| { | { | ||||
| ShaderNode *node = (input->link) ? input->link->parent : NULL; | ShaderNode *node = (input->get_link()) ? input->get_link()->get_parent() : NULL; | ||||
| if (node != NULL && done.find(node) == done.end() && node != skip_node && | if (node != NULL && done.find(node) == done.end() && node != skip_node && | ||||
| dependencies.find(node) == dependencies.end()) { | dependencies.find(node) == dependencies.end()) { | ||||
| foreach (ShaderInput *in, node->inputs) { | foreach (ShaderInput *in, node->get_inputs()) { | ||||
| find_dependencies(dependencies, done, in, skip_node); | find_dependencies(dependencies, done, in, skip_node); | ||||
| } | } | ||||
| dependencies.insert(node); | dependencies.insert(node); | ||||
| } | } | ||||
| } | } | ||||
| void SVMCompiler::generate_node(ShaderNode *node, ShaderNodeSet &done) | void SVMCompiler::generate_node(ShaderNode *node, ShaderNodeSet &done) | ||||
| { | { | ||||
| node->compile(*this); | node->compile(*this); | ||||
| stack_clear_users(node, done); | stack_clear_users(node, done); | ||||
| stack_clear_temporary(node); | stack_clear_temporary(node); | ||||
| if (current_type == SHADER_TYPE_SURFACE) { | if (current_type == SHADER_TYPE_SURFACE) { | ||||
| if (node->has_spatial_varying()) | if (node->has_spatial_varying()) | ||||
| current_shader->has_surface_spatial_varying = true; | current_shader->set_has_surface_spatial_varying(true); | ||||
| } | } | ||||
| else if (current_type == SHADER_TYPE_VOLUME) { | else if (current_type == SHADER_TYPE_VOLUME) { | ||||
| if (node->has_spatial_varying()) | if (node->has_spatial_varying()) | ||||
| current_shader->has_volume_spatial_varying = true; | current_shader->set_has_volume_spatial_varying(true); | ||||
| if (node->has_attribute_dependency()) | if (node->has_attribute_dependency()) | ||||
| current_shader->has_volume_attribute_dependency = true; | current_shader->set_has_volume_attribute_dependency(true); | ||||
| } | } | ||||
| if (node->has_integrator_dependency()) { | if (node->has_integrator_dependency()) { | ||||
| current_shader->has_integrator_dependency = true; | current_shader->set_has_integrator_dependency(true); | ||||
| } | } | ||||
| } | } | ||||
| void SVMCompiler::generate_svm_nodes(const ShaderNodeSet &nodes, CompilerState *state) | void SVMCompiler::generate_svm_nodes(const ShaderNodeSet &nodes, CompilerState *state) | ||||
| { | { | ||||
| ShaderNodeSet &done = state->nodes_done; | ShaderNodeSet &done = state->nodes_done; | ||||
| vector<bool> &done_flag = state->nodes_done_flag; | vector<bool> &done_flag = state->nodes_done_flag; | ||||
| bool nodes_done; | bool nodes_done; | ||||
| do { | do { | ||||
| nodes_done = true; | nodes_done = true; | ||||
| foreach (ShaderNode *node, nodes) { | foreach (ShaderNode *node, nodes) { | ||||
| if (!done_flag[node->id]) { | if (!done_flag[node->get_id()]) { | ||||
| bool inputs_done = true; | bool inputs_done = true; | ||||
| foreach (ShaderInput *input, node->inputs) { | foreach (ShaderInput *input, node->get_inputs()) { | ||||
| if (input->link && !done_flag[input->link->parent->id]) { | if (input->get_link() && !done_flag[input->get_link()->get_parent()->get_id()]) { | ||||
| inputs_done = false; | inputs_done = false; | ||||
| } | } | ||||
| } | } | ||||
| if (inputs_done) { | if (inputs_done) { | ||||
| generate_node(node, done); | generate_node(node, done); | ||||
| done.insert(node); | done.insert(node); | ||||
| done_flag[node->id] = true; | done_flag[node->get_id()] = true; | ||||
| } | } | ||||
| else { | else { | ||||
| nodes_done = false; | nodes_done = false; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } while (!nodes_done); | } while (!nodes_done); | ||||
| } | } | ||||
| void SVMCompiler::generate_closure_node(ShaderNode *node, CompilerState *state) | void SVMCompiler::generate_closure_node(ShaderNode *node, CompilerState *state) | ||||
| { | { | ||||
| /* execute dependencies for closure */ | /* execute dependencies for closure */ | ||||
| foreach (ShaderInput *in, node->inputs) { | foreach (ShaderInput *in, node->get_inputs()) { | ||||
| if (in->link != NULL) { | if (in->get_link() != NULL) { | ||||
| ShaderNodeSet dependencies; | ShaderNodeSet dependencies; | ||||
| find_dependencies(dependencies, state->nodes_done, in); | find_dependencies(dependencies, state->nodes_done, in); | ||||
| generate_svm_nodes(dependencies, state); | generate_svm_nodes(dependencies, state); | ||||
| } | } | ||||
| } | } | ||||
| /* closure mix weight */ | /* closure mix weight */ | ||||
| const char *weight_name = (current_type == SHADER_TYPE_VOLUME) ? "VolumeMixWeight" : | const char *weight_name = (current_type == SHADER_TYPE_VOLUME) ? "VolumeMixWeight" : | ||||
| "SurfaceMixWeight"; | "SurfaceMixWeight"; | ||||
| ShaderInput *weight_in = node->input(weight_name); | ShaderInput *weight_in = node->input(weight_name); | ||||
| if (weight_in && (weight_in->link || node->get_float(weight_in->socket_type) != 1.0f)) | if (weight_in && | ||||
| (weight_in->get_link() || node->get_float(weight_in->get_socket_type()) != 1.0f)) | |||||
| mix_weight_offset = stack_assign(weight_in); | mix_weight_offset = stack_assign(weight_in); | ||||
| else | else | ||||
| mix_weight_offset = SVM_STACK_INVALID; | mix_weight_offset = SVM_STACK_INVALID; | ||||
| /* compile closure itself */ | /* compile closure itself */ | ||||
| generate_node(node, state->nodes_done); | generate_node(node, state->nodes_done); | ||||
| mix_weight_offset = SVM_STACK_INVALID; | mix_weight_offset = SVM_STACK_INVALID; | ||||
| if (current_type == SHADER_TYPE_SURFACE) { | if (current_type == SHADER_TYPE_SURFACE) { | ||||
| if (node->has_surface_emission()) | if (node->has_surface_emission()) | ||||
| current_shader->has_surface_emission = true; | current_shader->set_has_surface_emission(true); | ||||
| if (node->has_surface_transparent()) | if (node->has_surface_transparent()) | ||||
| current_shader->has_surface_transparent = true; | current_shader->set_has_surface_transparent(true); | ||||
| if (node->has_surface_bssrdf()) { | if (node->has_surface_bssrdf()) { | ||||
| current_shader->has_surface_bssrdf = true; | current_shader->set_has_surface_bssrdf(true); | ||||
| if (node->has_bssrdf_bump()) | if (node->has_bssrdf_bump()) | ||||
| current_shader->has_bssrdf_bump = true; | current_shader->set_has_bssrdf_bump(true); | ||||
| } | } | ||||
| if (node->has_bump()) { | if (node->has_bump()) { | ||||
| current_shader->has_bump = true; | current_shader->set_has_bump(true); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void SVMCompiler::generated_shared_closure_nodes(ShaderNode *root_node, | void SVMCompiler::generated_shared_closure_nodes(ShaderNode *root_node, | ||||
| ShaderNode *node, | ShaderNode *node, | ||||
| CompilerState *state, | CompilerState *state, | ||||
| const ShaderNodeSet &shared) | const ShaderNodeSet &shared) | ||||
| { | { | ||||
| if (shared.find(node) != shared.end()) { | if (shared.find(node) != shared.end()) { | ||||
| generate_multi_closure(root_node, node, state); | generate_multi_closure(root_node, node, state); | ||||
| } | } | ||||
| else { | else { | ||||
| foreach (ShaderInput *in, node->inputs) { | foreach (ShaderInput *in, node->get_inputs()) { | ||||
| if (in->type() == SocketType::CLOSURE && in->link) | if (in->type() == SocketType::CLOSURE && in->get_link()) | ||||
| generated_shared_closure_nodes(root_node, in->link->parent, state, shared); | generated_shared_closure_nodes(root_node, in->get_link()->get_parent(), state, shared); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void SVMCompiler::find_aov_nodes_and_dependencies(ShaderNodeSet &aov_nodes, | void SVMCompiler::find_aov_nodes_and_dependencies(ShaderNodeSet &aov_nodes, | ||||
| ShaderGraph *graph, | ShaderGraph *graph, | ||||
| CompilerState *state) | CompilerState *state) | ||||
| { | { | ||||
| foreach (ShaderNode *node, graph->nodes) { | foreach (ShaderNode *node, graph->get_nodes()) { | ||||
| if (node->special_type == SHADER_SPECIAL_TYPE_OUTPUT_AOV) { | if (node->get_special_type() == SHADER_SPECIAL_TYPE_OUTPUT_AOV) { | ||||
| OutputAOVNode *aov_node = static_cast<OutputAOVNode *>(node); | OutputAOVNode *aov_node = static_cast<OutputAOVNode *>(node); | ||||
| if (aov_node->slot >= 0) { | if (aov_node->slot >= 0) { | ||||
| aov_nodes.insert(aov_node); | aov_nodes.insert(aov_node); | ||||
| foreach (ShaderInput *in, node->inputs) { | foreach (ShaderInput *in, node->get_inputs()) { | ||||
| if (in->link != NULL) { | if (in->get_link() != NULL) { | ||||
| find_dependencies(aov_nodes, state->nodes_done, in); | find_dependencies(aov_nodes, state->nodes_done, in); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void SVMCompiler::generate_multi_closure(ShaderNode *root_node, | void SVMCompiler::generate_multi_closure(ShaderNode *root_node, | ||||
| ShaderNode *node, | ShaderNode *node, | ||||
| CompilerState *state) | CompilerState *state) | ||||
| { | { | ||||
| /* only generate once */ | /* only generate once */ | ||||
| if (state->closure_done.find(node) != state->closure_done.end()) | if (state->closure_done.find(node) != state->closure_done.end()) | ||||
| return; | return; | ||||
| state->closure_done.insert(node); | state->closure_done.insert(node); | ||||
| if (node->special_type == SHADER_SPECIAL_TYPE_COMBINE_CLOSURE) { | if (node->get_special_type() == SHADER_SPECIAL_TYPE_COMBINE_CLOSURE) { | ||||
| /* weighting is already taken care of in ShaderGraph::transform_multi_closure */ | /* weighting is already taken care of in ShaderGraph::transform_multi_closure */ | ||||
| ShaderInput *cl1in = node->input("Closure1"); | ShaderInput *cl1in = node->input("Closure1"); | ||||
| ShaderInput *cl2in = node->input("Closure2"); | ShaderInput *cl2in = node->input("Closure2"); | ||||
| ShaderInput *facin = node->input("Fac"); | ShaderInput *facin = node->input("Fac"); | ||||
| /* skip empty mix/add closure nodes */ | /* skip empty mix/add closure nodes */ | ||||
| if (!cl1in->link && !cl2in->link) | if (!cl1in->get_link() && !cl2in->get_link()) | ||||
| return; | return; | ||||
| if (facin && facin->link) { | if (facin && facin->get_link()) { | ||||
| /* mix closure: generate instructions to compute mix weight */ | /* mix closure: generate instructions to compute mix weight */ | ||||
| ShaderNodeSet dependencies; | ShaderNodeSet dependencies; | ||||
| find_dependencies(dependencies, state->nodes_done, facin); | find_dependencies(dependencies, state->nodes_done, facin); | ||||
| generate_svm_nodes(dependencies, state); | generate_svm_nodes(dependencies, state); | ||||
| /* execute shared dependencies. this is needed to allow skipping | /* execute shared dependencies. this is needed to allow skipping | ||||
| * of zero weight closures and their dependencies later, so we | * of zero weight closures and their dependencies later, so we | ||||
| * ensure that they only skip dependencies that are unique to them */ | * ensure that they only skip dependencies that are unique to them */ | ||||
| Show All 10 Lines | if (facin && facin->get_link()) { | ||||
| std::inserter(shareddeps, shareddeps.begin()), | std::inserter(shareddeps, shareddeps.begin()), | ||||
| node_id_comp); | node_id_comp); | ||||
| /* it's possible some nodes are not shared between this mix node | /* it's possible some nodes are not shared between this mix node | ||||
| * inputs, but still needed to be always executed, this mainly | * inputs, but still needed to be always executed, this mainly | ||||
| * happens when a node of current subbranch is used by a parent | * happens when a node of current subbranch is used by a parent | ||||
| * node or so */ | * node or so */ | ||||
| if (root_node != node) { | if (root_node != node) { | ||||
| foreach (ShaderInput *in, root_node->inputs) { | foreach (ShaderInput *in, root_node->get_inputs()) { | ||||
| ShaderNodeSet rootdeps; | ShaderNodeSet rootdeps; | ||||
| find_dependencies(rootdeps, state->nodes_done, in, node); | find_dependencies(rootdeps, state->nodes_done, in, node); | ||||
| set_intersection(rootdeps.begin(), | set_intersection(rootdeps.begin(), | ||||
| rootdeps.end(), | rootdeps.end(), | ||||
| cl1deps.begin(), | cl1deps.begin(), | ||||
| cl1deps.end(), | cl1deps.end(), | ||||
| std::inserter(shareddeps, shareddeps.begin()), | std::inserter(shareddeps, shareddeps.begin()), | ||||
| node_id_comp); | node_id_comp); | ||||
| Show All 21 Lines | if (facin && facin->get_link()) { | ||||
| state->aov_nodes.end(), | state->aov_nodes.end(), | ||||
| cl2deps.begin(), | cl2deps.begin(), | ||||
| cl2deps.end(), | cl2deps.end(), | ||||
| std::inserter(shareddeps, shareddeps.begin()), | std::inserter(shareddeps, shareddeps.begin()), | ||||
| node_id_comp); | node_id_comp); | ||||
| } | } | ||||
| if (!shareddeps.empty()) { | if (!shareddeps.empty()) { | ||||
| if (cl1in->link) { | if (cl1in->get_link()) { | ||||
| generated_shared_closure_nodes(root_node, cl1in->link->parent, state, shareddeps); | generated_shared_closure_nodes( | ||||
| } | root_node, cl1in->get_link()->get_parent(), state, shareddeps); | ||||
| if (cl2in->link) { | } | ||||
| generated_shared_closure_nodes(root_node, cl2in->link->parent, state, shareddeps); | if (cl2in->get_link()) { | ||||
| generated_shared_closure_nodes( | |||||
| root_node, cl2in->get_link()->get_parent(), state, shareddeps); | |||||
| } | } | ||||
| generate_svm_nodes(shareddeps, state); | generate_svm_nodes(shareddeps, state); | ||||
| } | } | ||||
| /* generate instructions for input closure 1 */ | /* generate instructions for input closure 1 */ | ||||
| if (cl1in->link) { | if (cl1in->get_link()) { | ||||
| /* Add instruction to skip closure and its dependencies if mix | /* Add instruction to skip closure and its dependencies if mix | ||||
| * weight is zero. | * weight is zero. | ||||
| */ | */ | ||||
| current_svm_nodes.push_back_slow(make_int4(NODE_JUMP_IF_ONE, 0, stack_assign(facin), 0)); | current_svm_nodes.push_back_slow(make_int4(NODE_JUMP_IF_ONE, 0, stack_assign(facin), 0)); | ||||
| int node_jump_skip_index = current_svm_nodes.size() - 1; | int node_jump_skip_index = current_svm_nodes.size() - 1; | ||||
| generate_multi_closure(root_node, cl1in->link->parent, state); | generate_multi_closure(root_node, cl1in->get_link()->get_parent(), state); | ||||
| /* Fill in jump instruction location to be after closure. */ | /* Fill in jump instruction location to be after closure. */ | ||||
| current_svm_nodes[node_jump_skip_index].y = current_svm_nodes.size() - | current_svm_nodes[node_jump_skip_index].y = current_svm_nodes.size() - | ||||
| node_jump_skip_index - 1; | node_jump_skip_index - 1; | ||||
| } | } | ||||
| /* generate instructions for input closure 2 */ | /* generate instructions for input closure 2 */ | ||||
| if (cl2in->link) { | if (cl2in->get_link()) { | ||||
| /* Add instruction to skip closure and its dependencies if mix | /* Add instruction to skip closure and its dependencies if mix | ||||
| * weight is zero. | * weight is zero. | ||||
| */ | */ | ||||
| current_svm_nodes.push_back_slow(make_int4(NODE_JUMP_IF_ZERO, 0, stack_assign(facin), 0)); | current_svm_nodes.push_back_slow(make_int4(NODE_JUMP_IF_ZERO, 0, stack_assign(facin), 0)); | ||||
| int node_jump_skip_index = current_svm_nodes.size() - 1; | int node_jump_skip_index = current_svm_nodes.size() - 1; | ||||
| generate_multi_closure(root_node, cl2in->link->parent, state); | generate_multi_closure(root_node, cl2in->get_link()->get_parent(), state); | ||||
| /* Fill in jump instruction location to be after closure. */ | /* Fill in jump instruction location to be after closure. */ | ||||
| current_svm_nodes[node_jump_skip_index].y = current_svm_nodes.size() - | current_svm_nodes[node_jump_skip_index].y = current_svm_nodes.size() - | ||||
| node_jump_skip_index - 1; | node_jump_skip_index - 1; | ||||
| } | } | ||||
| /* unassign */ | /* unassign */ | ||||
| facin->stack_offset = SVM_STACK_INVALID; | facin->get_stack_offset() = SVM_STACK_INVALID; | ||||
| } | } | ||||
| else { | else { | ||||
| /* execute closures and their dependencies, no runtime checks | /* execute closures and their dependencies, no runtime checks | ||||
| * to skip closures here because was already optimized due to | * to skip closures here because was already optimized due to | ||||
| * fixed weight or add closure that always needs both */ | * fixed weight or add closure that always needs both */ | ||||
| if (cl1in->link) | if (cl1in->get_link()) | ||||
| generate_multi_closure(root_node, cl1in->link->parent, state); | generate_multi_closure(root_node, cl1in->get_link()->get_parent(), state); | ||||
| if (cl2in->link) | if (cl2in->get_link()) | ||||
| generate_multi_closure(root_node, cl2in->link->parent, state); | generate_multi_closure(root_node, cl2in->get_link()->get_parent(), state); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| generate_closure_node(node, state); | generate_closure_node(node, state); | ||||
| } | } | ||||
| state->nodes_done.insert(node); | state->nodes_done.insert(node); | ||||
| state->nodes_done_flag[node->id] = true; | state->nodes_done_flag[node->get_id()] = true; | ||||
| } | } | ||||
| void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType type) | void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType type) | ||||
| { | { | ||||
| /* Converting a shader graph into svm_nodes that can be executed | /* Converting a shader graph into svm_nodes that can be executed | ||||
| * sequentially on the virtual machine is fairly simple. We can keep | * sequentially on the virtual machine is fairly simple. We can keep | ||||
| * looping over nodes and each time all the inputs of a node are | * looping over nodes and each time all the inputs of a node are | ||||
| * ready, we add svm_nodes for it that read the inputs from the | * ready, we add svm_nodes for it that read the inputs from the | ||||
| Show All 33 Lines | default: | ||||
| assert(0); | assert(0); | ||||
| break; | break; | ||||
| } | } | ||||
| /* clear all compiler state */ | /* clear all compiler state */ | ||||
| memset((void *)&active_stack, 0, sizeof(active_stack)); | memset((void *)&active_stack, 0, sizeof(active_stack)); | ||||
| current_svm_nodes.clear(); | current_svm_nodes.clear(); | ||||
| foreach (ShaderNode *node, graph->nodes) { | foreach (ShaderNode *node, graph->get_nodes()) { | ||||
| foreach (ShaderInput *input, node->inputs) | foreach (ShaderInput *input, node->get_inputs()) | ||||
| input->stack_offset = SVM_STACK_INVALID; | input->get_stack_offset() = SVM_STACK_INVALID; | ||||
| foreach (ShaderOutput *output, node->outputs) | foreach (ShaderOutput *output, node->get_outputs()) | ||||
| output->stack_offset = SVM_STACK_INVALID; | output->get_stack_offset() = SVM_STACK_INVALID; | ||||
| } | } | ||||
| /* for the bump shader we need add a node to store the shader state */ | /* for the bump shader we need add a node to store the shader state */ | ||||
| bool need_bump_state = (type == SHADER_TYPE_BUMP) && | bool need_bump_state = (type == SHADER_TYPE_BUMP) && | ||||
| (shader->get_displacement_method() == DISPLACE_BOTH); | (shader->get_displacement_method() == DISPLACE_BOTH); | ||||
| int bump_state_offset = SVM_STACK_INVALID; | int bump_state_offset = SVM_STACK_INVALID; | ||||
| if (need_bump_state) { | if (need_bump_state) { | ||||
| bump_state_offset = stack_find_offset(SVM_BUMP_EVAL_STATE_SIZE); | bump_state_offset = stack_find_offset(SVM_BUMP_EVAL_STATE_SIZE); | ||||
| add_node(NODE_ENTER_BUMP_EVAL, bump_state_offset); | add_node(NODE_ENTER_BUMP_EVAL, bump_state_offset); | ||||
| } | } | ||||
| if (shader->used) { | if (shader->get_used()) { | ||||
| CompilerState state(graph); | CompilerState state(graph); | ||||
| if (clin->link) { | if (clin->get_link()) { | ||||
| bool generate = false; | bool generate = false; | ||||
| switch (type) { | switch (type) { | ||||
| case SHADER_TYPE_SURFACE: /* generate surface shader */ | case SHADER_TYPE_SURFACE: /* generate surface shader */ | ||||
| generate = true; | generate = true; | ||||
| shader->has_surface = true; | shader->set_has_surface(true); | ||||
| break; | break; | ||||
| case SHADER_TYPE_VOLUME: /* generate volume shader */ | case SHADER_TYPE_VOLUME: /* generate volume shader */ | ||||
| generate = true; | generate = true; | ||||
| shader->has_volume = true; | shader->set_has_volume(true); | ||||
| break; | break; | ||||
| case SHADER_TYPE_DISPLACEMENT: /* generate displacement shader */ | case SHADER_TYPE_DISPLACEMENT: /* generate displacement shader */ | ||||
| generate = true; | generate = true; | ||||
| shader->has_displacement = true; | shader->set_has_displacement(true); | ||||
| break; | break; | ||||
| case SHADER_TYPE_BUMP: /* generate bump shader */ | case SHADER_TYPE_BUMP: /* generate bump shader */ | ||||
| generate = true; | generate = true; | ||||
| break; | break; | ||||
| default: | default: | ||||
| break; | break; | ||||
| } | } | ||||
| if (generate) { | if (generate) { | ||||
| if (type == SHADER_TYPE_SURFACE) { | if (type == SHADER_TYPE_SURFACE) { | ||||
| find_aov_nodes_and_dependencies(state.aov_nodes, graph, &state); | find_aov_nodes_and_dependencies(state.aov_nodes, graph, &state); | ||||
| } | } | ||||
| generate_multi_closure(clin->link->parent, clin->link->parent, &state); | generate_multi_closure(clin->get_link()->get_parent(), clin->get_link()->get_parent(), &state); | ||||
| } | } | ||||
| } | } | ||||
| /* compile output node */ | /* compile output node */ | ||||
| output->compile(*this); | output->compile(*this); | ||||
| if (!state.aov_nodes.empty()) { | if (!state.aov_nodes.empty()) { | ||||
| /* AOV passes are only written if the object is directly visible, so | /* AOV passes are only written if the object is directly visible, so | ||||
| Show All 23 Lines | void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType type) | ||||
| if (type != SHADER_TYPE_BUMP) { | if (type != SHADER_TYPE_BUMP) { | ||||
| add_node(NODE_END, 0, 0, 0); | add_node(NODE_END, 0, 0, 0); | ||||
| } | } | ||||
| } | } | ||||
| void SVMCompiler::compile(Shader *shader, array<int4> &svm_nodes, int index, Summary *summary) | void SVMCompiler::compile(Shader *shader, array<int4> &svm_nodes, int index, Summary *summary) | ||||
| { | { | ||||
| /* copy graph for shader with bump mapping */ | /* copy graph for shader with bump mapping */ | ||||
| ShaderNode *output = shader->graph->output(); | ShaderNode *output = shader->get_graph()->output(); | ||||
| int start_num_svm_nodes = svm_nodes.size(); | int start_num_svm_nodes = svm_nodes.size(); | ||||
| const double time_start = time_dt(); | const double time_start = time_dt(); | ||||
| bool has_bump = (shader->get_displacement_method() != DISPLACE_TRUE) && | bool has_bump = (shader->get_displacement_method() != DISPLACE_TRUE) && | ||||
| output->input("Surface")->link && output->input("Displacement")->link; | output->input("Surface")->get_link() && | ||||
| output->input("Displacement")->get_link(); | |||||
| /* finalize */ | /* finalize */ | ||||
| { | { | ||||
| scoped_timer timer((summary != NULL) ? &summary->time_finalize : NULL); | scoped_timer timer((summary != NULL) ? &summary->time_finalize : NULL); | ||||
| shader->graph->finalize(scene, | shader->get_graph()->finalize(scene, | ||||
| has_bump, | has_bump, | ||||
| shader->has_integrator_dependency, | shader->get_has_integrator_dependency(), | ||||
| shader->get_displacement_method() == DISPLACE_BOTH); | shader->get_displacement_method() == DISPLACE_BOTH); | ||||
| } | } | ||||
| current_shader = shader; | current_shader = shader; | ||||
| shader->has_surface = false; | shader->set_has_surface(false); | ||||
| shader->has_surface_emission = false; | shader->set_has_surface_emission(false); | ||||
| shader->has_surface_transparent = false; | shader->set_has_surface_transparent(false); | ||||
| shader->has_surface_bssrdf = false; | shader->set_has_surface_bssrdf(false); | ||||
| shader->has_bump = has_bump; | shader->set_has_bump(has_bump); | ||||
| shader->has_bssrdf_bump = has_bump; | shader->set_has_bssrdf_bump(has_bump); | ||||
| shader->has_volume = false; | shader->set_has_volume(false); | ||||
| shader->has_displacement = false; | shader->set_has_displacement(false); | ||||
| shader->has_surface_spatial_varying = false; | shader->set_has_surface_spatial_varying(false); | ||||
| shader->has_volume_spatial_varying = false; | shader->set_has_volume_spatial_varying(false); | ||||
| shader->has_volume_attribute_dependency = false; | shader->set_has_volume_attribute_dependency(false); | ||||
| shader->has_integrator_dependency = false; | shader->set_has_integrator_dependency(false); | ||||
| /* generate bump shader */ | /* generate bump shader */ | ||||
| if (has_bump) { | if (has_bump) { | ||||
| scoped_timer timer((summary != NULL) ? &summary->time_generate_bump : NULL); | scoped_timer timer((summary != NULL) ? &summary->time_generate_bump : NULL); | ||||
| compile_type(shader, shader->graph, SHADER_TYPE_BUMP); | compile_type(shader, shader->get_graph(), SHADER_TYPE_BUMP); | ||||
| svm_nodes[index].y = svm_nodes.size(); | svm_nodes[index].y = svm_nodes.size(); | ||||
| svm_nodes.append(current_svm_nodes); | svm_nodes.append(current_svm_nodes); | ||||
| } | } | ||||
| /* generate surface shader */ | /* generate surface shader */ | ||||
| { | { | ||||
| scoped_timer timer((summary != NULL) ? &summary->time_generate_surface : NULL); | scoped_timer timer((summary != NULL) ? &summary->time_generate_surface : NULL); | ||||
| compile_type(shader, shader->graph, SHADER_TYPE_SURFACE); | compile_type(shader, shader->get_graph(), SHADER_TYPE_SURFACE); | ||||
| /* only set jump offset if there's no bump shader, as the bump shader will fall thru to this | /* only set jump offset if there's no bump shader, as the bump shader will fall thru to this | ||||
| * one if it exists */ | * one if it exists */ | ||||
| if (!has_bump) { | if (!has_bump) { | ||||
| svm_nodes[index].y = svm_nodes.size(); | svm_nodes[index].y = svm_nodes.size(); | ||||
| } | } | ||||
| svm_nodes.append(current_svm_nodes); | svm_nodes.append(current_svm_nodes); | ||||
| } | } | ||||
| /* generate volume shader */ | /* generate volume shader */ | ||||
| { | { | ||||
| scoped_timer timer((summary != NULL) ? &summary->time_generate_volume : NULL); | scoped_timer timer((summary != NULL) ? &summary->time_generate_volume : NULL); | ||||
| compile_type(shader, shader->graph, SHADER_TYPE_VOLUME); | compile_type(shader, shader->get_graph(), SHADER_TYPE_VOLUME); | ||||
| svm_nodes[index].z = svm_nodes.size(); | svm_nodes[index].z = svm_nodes.size(); | ||||
| svm_nodes.append(current_svm_nodes); | svm_nodes.append(current_svm_nodes); | ||||
| } | } | ||||
| /* generate displacement shader */ | /* generate displacement shader */ | ||||
| { | { | ||||
| scoped_timer timer((summary != NULL) ? &summary->time_generate_displacement : NULL); | scoped_timer timer((summary != NULL) ? &summary->time_generate_displacement : NULL); | ||||
| compile_type(shader, shader->graph, SHADER_TYPE_DISPLACEMENT); | compile_type(shader, shader->get_graph(), SHADER_TYPE_DISPLACEMENT); | ||||
| svm_nodes[index].w = svm_nodes.size(); | svm_nodes[index].w = svm_nodes.size(); | ||||
| svm_nodes.append(current_svm_nodes); | svm_nodes.append(current_svm_nodes); | ||||
| } | } | ||||
| /* Fill in summary information. */ | /* Fill in summary information. */ | ||||
| if (summary != NULL) { | if (summary != NULL) { | ||||
| summary->time_total = time_dt() - time_start; | summary->time_total = time_dt() - time_start; | ||||
| summary->peak_stack_usage = max_stack_use; | summary->peak_stack_usage = max_stack_use; | ||||
| Show All 35 Lines | string SVMCompiler::Summary::full_report() const | ||||
| return report; | return report; | ||||
| } | } | ||||
| /* Global state of the compiler. */ | /* Global state of the compiler. */ | ||||
| SVMCompiler::CompilerState::CompilerState(ShaderGraph *graph) | SVMCompiler::CompilerState::CompilerState(ShaderGraph *graph) | ||||
| { | { | ||||
| int max_id = 0; | int max_id = 0; | ||||
| foreach (ShaderNode *node, graph->nodes) { | foreach (ShaderNode *node, graph->get_nodes()) { | ||||
| max_id = max(node->id, max_id); | max_id = max(node->get_id(), max_id); | ||||
| } | } | ||||
| nodes_done_flag.resize(max_id + 1, false); | nodes_done_flag.resize(max_id + 1, false); | ||||
| } | } | ||||
| CCL_NAMESPACE_END | CCL_NAMESPACE_END | ||||