Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'intern/cycles/render/svm.cpp')
-rw-r--r--intern/cycles/render/svm.cpp1398
1 files changed, 688 insertions, 710 deletions
diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp
index 360b2b461cf..d8e3e24f39e 100644
--- a/intern/cycles/render/svm.cpp
+++ b/intern/cycles/render/svm.cpp
@@ -49,107 +49,106 @@ void SVMShaderManager::device_update_shader(Scene *scene,
Progress *progress,
array<int4> *global_svm_nodes)
{
- if(progress->get_cancel()) {
- return;
- }
- assert(shader->graph);
+ if (progress->get_cancel()) {
+ return;
+ }
+ assert(shader->graph);
- array<int4> svm_nodes;
- svm_nodes.push_back_slow(make_int4(NODE_SHADER_JUMP, 0, 0, 0));
+ array<int4> svm_nodes;
+ svm_nodes.push_back_slow(make_int4(NODE_SHADER_JUMP, 0, 0, 0));
- SVMCompiler::Summary summary;
- SVMCompiler compiler(scene->shader_manager, scene->image_manager, scene->light_manager);
- compiler.background = (shader == scene->default_background);
- compiler.compile(scene, shader, svm_nodes, 0, &summary);
+ SVMCompiler::Summary summary;
+ SVMCompiler compiler(scene->shader_manager, scene->image_manager, scene->light_manager);
+ compiler.background = (shader == scene->default_background);
+ compiler.compile(scene, shader, svm_nodes, 0, &summary);
- VLOG(2) << "Compilation summary:\n"
- << "Shader name: " << shader->name << "\n"
- << summary.full_report();
+ VLOG(2) << "Compilation summary:\n"
+ << "Shader name: " << shader->name << "\n"
+ << summary.full_report();
- nodes_lock_.lock();
- if(shader->use_mis && shader->has_surface_emission) {
- scene->light_manager->need_update = true;
- }
+ nodes_lock_.lock();
+ if (shader->use_mis && shader->has_surface_emission) {
+ scene->light_manager->need_update = true;
+ }
- /* The copy needs to be done inside the lock, if another thread resizes the array
- * while memcpy is running, it'll be copying into possibly invalid/freed ram.
- */
- size_t global_nodes_size = global_svm_nodes->size();
- global_svm_nodes->resize(global_nodes_size + svm_nodes.size());
+ /* The copy needs to be done inside the lock, if another thread resizes the array
+ * while memcpy is running, it'll be copying into possibly invalid/freed ram.
+ */
+ size_t global_nodes_size = global_svm_nodes->size();
+ global_svm_nodes->resize(global_nodes_size + svm_nodes.size());
- /* Offset local SVM nodes to a global address space. */
- int4& jump_node = (*global_svm_nodes)[shader->id];
- jump_node.y = svm_nodes[0].y + global_nodes_size - 1;
- jump_node.z = svm_nodes[0].z + global_nodes_size - 1;
- jump_node.w = svm_nodes[0].w + global_nodes_size - 1;
- /* Copy new nodes to global storage. */
- memcpy(&(*global_svm_nodes)[global_nodes_size],
- &svm_nodes[1],
- sizeof(int4) * (svm_nodes.size() - 1));
- nodes_lock_.unlock();
+ /* Offset local SVM nodes to a global address space. */
+ int4 &jump_node = (*global_svm_nodes)[shader->id];
+ jump_node.y = svm_nodes[0].y + global_nodes_size - 1;
+ jump_node.z = svm_nodes[0].z + global_nodes_size - 1;
+ jump_node.w = svm_nodes[0].w + global_nodes_size - 1;
+ /* Copy new nodes to global storage. */
+ memcpy(&(*global_svm_nodes)[global_nodes_size],
+ &svm_nodes[1],
+ sizeof(int4) * (svm_nodes.size() - 1));
+ nodes_lock_.unlock();
}
-void SVMShaderManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
+void SVMShaderManager::device_update(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress &progress)
{
- if(!need_update)
- return;
+ if (!need_update)
+ return;
- VLOG(1) << "Total " << scene->shaders.size() << " shaders.";
+ VLOG(1) << "Total " << scene->shaders.size() << " shaders.";
- double start_time = time_dt();
+ double start_time = time_dt();
- /* test if we need to update */
- device_free(device, dscene, scene);
+ /* test if we need to update */
+ device_free(device, dscene, scene);
- /* determine which shaders are in use */
- device_update_shaders_used(scene);
+ /* determine which shaders are in use */
+ device_update_shaders_used(scene);
- /* svm_nodes */
- array<int4> svm_nodes;
- size_t i;
+ /* svm_nodes */
+ array<int4> svm_nodes;
+ size_t i;
- for(i = 0; i < scene->shaders.size(); i++) {
- svm_nodes.push_back_slow(make_int4(NODE_SHADER_JUMP, 0, 0, 0));
- }
+ for (i = 0; i < scene->shaders.size(); i++) {
+ svm_nodes.push_back_slow(make_int4(NODE_SHADER_JUMP, 0, 0, 0));
+ }
- TaskPool task_pool;
- foreach(Shader *shader, scene->shaders) {
- task_pool.push(function_bind(&SVMShaderManager::device_update_shader,
- this,
- scene,
- shader,
- &progress,
- &svm_nodes),
- false);
- }
- task_pool.wait_work();
+ TaskPool task_pool;
+ foreach (Shader *shader, scene->shaders) {
+ task_pool.push(
+ function_bind(
+ &SVMShaderManager::device_update_shader, this, scene, shader, &progress, &svm_nodes),
+ false);
+ }
+ task_pool.wait_work();
- if(progress.get_cancel()) {
- return;
- }
+ if (progress.get_cancel()) {
+ return;
+ }
- dscene->svm_nodes.steal_data(svm_nodes);
- dscene->svm_nodes.copy_to_device();
+ dscene->svm_nodes.steal_data(svm_nodes);
+ dscene->svm_nodes.copy_to_device();
- for(i = 0; i < scene->shaders.size(); i++) {
- Shader *shader = scene->shaders[i];
- shader->need_update = false;
- }
+ for (i = 0; i < scene->shaders.size(); i++) {
+ Shader *shader = scene->shaders[i];
+ shader->need_update = false;
+ }
- device_update_common(device, dscene, scene, progress);
+ device_update_common(device, dscene, scene, progress);
- need_update = false;
+ need_update = false;
- VLOG(1) << "Shader manager updated "
- << scene->shaders.size() << " shaders in "
- << time_dt() - start_time << " seconds.";
+ VLOG(1) << "Shader manager updated " << scene->shaders.size() << " shaders in "
+ << time_dt() - start_time << " seconds.";
}
void SVMShaderManager::device_free(Device *device, DeviceScene *dscene, Scene *scene)
{
- device_free_common(device, dscene, scene);
+ device_free_common(device, dscene, scene);
- dscene->svm_nodes.free();
+ dscene->svm_nodes.free();
}
/* Graph Compiler */
@@ -158,772 +157,751 @@ SVMCompiler::SVMCompiler(ShaderManager *shader_manager_,
ImageManager *image_manager_,
LightManager *light_manager_)
{
- shader_manager = shader_manager_;
- image_manager = image_manager_;
- light_manager = light_manager_;
- max_stack_use = 0;
- current_type = SHADER_TYPE_SURFACE;
- current_shader = NULL;
- current_graph = NULL;
- background = false;
- mix_weight_offset = SVM_STACK_INVALID;
- compile_failed = false;
+ shader_manager = shader_manager_;
+ image_manager = image_manager_;
+ light_manager = light_manager_;
+ max_stack_use = 0;
+ current_type = SHADER_TYPE_SURFACE;
+ current_shader = NULL;
+ current_graph = NULL;
+ background = false;
+ mix_weight_offset = SVM_STACK_INVALID;
+ compile_failed = false;
}
int SVMCompiler::stack_size(SocketType::Type type)
{
- int size = 0;
-
- switch(type) {
- case SocketType::FLOAT:
- case SocketType::INT:
- size = 1;
- break;
- case SocketType::COLOR:
- case SocketType::VECTOR:
- case SocketType::NORMAL:
- case SocketType::POINT:
- size = 3;
- break;
- case SocketType::CLOSURE:
- size = 0;
- break;
- default:
- assert(0);
- break;
- }
-
- return size;
+ int size = 0;
+
+ switch (type) {
+ case SocketType::FLOAT:
+ case SocketType::INT:
+ size = 1;
+ break;
+ case SocketType::COLOR:
+ case SocketType::VECTOR:
+ case SocketType::NORMAL:
+ case SocketType::POINT:
+ size = 3;
+ break;
+ case SocketType::CLOSURE:
+ size = 0;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ return size;
}
int SVMCompiler::stack_find_offset(int size)
{
- int offset = -1;
+ int offset = -1;
- /* find free space in stack & mark as used */
- for(int i = 0, num_unused = 0; i < SVM_STACK_SIZE; i++) {
- if(active_stack.users[i]) num_unused = 0;
- else num_unused++;
+ /* find free space in stack & mark as used */
+ for (int i = 0, num_unused = 0; i < SVM_STACK_SIZE; i++) {
+ if (active_stack.users[i])
+ num_unused = 0;
+ else
+ num_unused++;
- if(num_unused == size) {
- offset = i+1 - size;
- max_stack_use = max(i+1, max_stack_use);
+ if (num_unused == size) {
+ offset = i + 1 - size;
+ max_stack_use = max(i + 1, max_stack_use);
- while(i >= offset)
- active_stack.users[i--] = 1;
+ while (i >= offset)
+ active_stack.users[i--] = 1;
- return offset;
- }
- }
+ return offset;
+ }
+ }
- if(!compile_failed) {
- compile_failed = true;
- fprintf(stderr, "Cycles: out of SVM stack space, shader \"%s\" too big.\n", current_shader->name.c_str());
- }
+ if (!compile_failed) {
+ compile_failed = true;
+ fprintf(stderr,
+ "Cycles: out of SVM stack space, shader \"%s\" too big.\n",
+ current_shader->name.c_str());
+ }
- return 0;
+ return 0;
}
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)
{
- int size = stack_size(type);
+ int size = stack_size(type);
- for(int i = 0; i < size; i++)
- active_stack.users[offset + i]--;
+ for (int i = 0; i < size; i++)
+ active_stack.users[offset + i]--;
}
int SVMCompiler::stack_assign(ShaderInput *input)
{
- /* stack offset assign? */
- if(input->stack_offset == SVM_STACK_INVALID) {
- if(input->link) {
- /* linked to output -> use output offset */
- assert(input->link->stack_offset != SVM_STACK_INVALID);
- input->stack_offset = input->link->stack_offset;
- }
- else {
- Node *node = input->parent;
-
- /* not linked to output -> add nodes to load default value */
- input->stack_offset = stack_find_offset(input->type());
-
- if(input->type() == SocketType::FLOAT) {
- add_node(NODE_VALUE_F, __float_as_int(node->get_float(input->socket_type)), input->stack_offset);
- }
- else if(input->type() == SocketType::INT) {
- add_node(NODE_VALUE_F, node->get_int(input->socket_type), input->stack_offset);
- }
- else if(input->type() == SocketType::VECTOR ||
- input->type() == SocketType::NORMAL ||
- input->type() == SocketType::POINT ||
- input->type() == SocketType::COLOR)
- {
-
- add_node(NODE_VALUE_V, input->stack_offset);
- add_node(NODE_VALUE_V, node->get_float3(input->socket_type));
- }
- else /* should not get called for closure */
- assert(0);
- }
- }
-
- return input->stack_offset;
+ /* stack offset assign? */
+ if (input->stack_offset == SVM_STACK_INVALID) {
+ if (input->link) {
+ /* linked to output -> use output offset */
+ assert(input->link->stack_offset != SVM_STACK_INVALID);
+ input->stack_offset = input->link->stack_offset;
+ }
+ else {
+ Node *node = input->parent;
+
+ /* not linked to output -> add nodes to load default value */
+ input->stack_offset = stack_find_offset(input->type());
+
+ if (input->type() == SocketType::FLOAT) {
+ add_node(NODE_VALUE_F,
+ __float_as_int(node->get_float(input->socket_type)),
+ input->stack_offset);
+ }
+ else if (input->type() == SocketType::INT) {
+ add_node(NODE_VALUE_F, node->get_int(input->socket_type), input->stack_offset);
+ }
+ else if (input->type() == SocketType::VECTOR || input->type() == SocketType::NORMAL ||
+ input->type() == SocketType::POINT || input->type() == SocketType::COLOR) {
+
+ add_node(NODE_VALUE_V, input->stack_offset);
+ add_node(NODE_VALUE_V, node->get_float3(input->socket_type));
+ }
+ else /* should not get called for closure */
+ assert(0);
+ }
+ }
+
+ return input->stack_offset;
}
int SVMCompiler::stack_assign(ShaderOutput *output)
{
- /* if no stack offset assigned yet, find one */
- if(output->stack_offset == SVM_STACK_INVALID)
- output->stack_offset = stack_find_offset(output->type());
+ /* if no stack offset assigned yet, find one */
+ if (output->stack_offset == SVM_STACK_INVALID)
+ output->stack_offset = stack_find_offset(output->type());
- return output->stack_offset;
+ return output->stack_offset;
}
int SVMCompiler::stack_assign_if_linked(ShaderInput *input)
{
- if(input->link)
- return stack_assign(input);
+ if (input->link)
+ return stack_assign(input);
- return SVM_STACK_INVALID;
+ return SVM_STACK_INVALID;
}
int SVMCompiler::stack_assign_if_linked(ShaderOutput *output)
{
- if(!output->links.empty())
- return stack_assign(output);
+ if (!output->links.empty())
+ return stack_assign(output);
- return SVM_STACK_INVALID;
+ return SVM_STACK_INVALID;
}
void SVMCompiler::stack_link(ShaderInput *input, ShaderOutput *output)
{
- if(output->stack_offset == SVM_STACK_INVALID) {
- assert(input->link);
- assert(stack_size(output->type()) == stack_size(input->link->type()));
+ if (output->stack_offset == SVM_STACK_INVALID) {
+ assert(input->link);
+ assert(stack_size(output->type()) == stack_size(input->link->type()));
- output->stack_offset = input->link->stack_offset;
+ output->stack_offset = input->link->stack_offset;
- int size = stack_size(output->type());
+ int size = stack_size(output->type());
- for(int i = 0; i < size; i++)
- active_stack.users[output->stack_offset + i]++;
- }
+ for (int i = 0; i < size; i++)
+ active_stack.users[output->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:
- * 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
- * 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
- * with inputs getting stack positions assigned */
+ /* optimization we should add:
+ * 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
+ * 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
+ * with inputs getting stack positions assigned */
- foreach(ShaderInput *input, node->inputs) {
- ShaderOutput *output = input->link;
+ foreach (ShaderInput *input, node->inputs) {
+ ShaderOutput *output = input->link;
- if(output && output->stack_offset != SVM_STACK_INVALID) {
- bool all_done = true;
+ if (output && output->stack_offset != SVM_STACK_INVALID) {
+ bool all_done = true;
- /* optimization we should add: verify if in->parent is actually used */
- foreach(ShaderInput *in, output->links)
- if(in->parent != node && done.find(in->parent) == done.end())
- all_done = false;
+ /* optimization we should add: verify if in->parent is actually used */
+ foreach (ShaderInput *in, output->links)
+ if (in->parent != node && done.find(in->parent) == done.end())
+ all_done = false;
- if(all_done) {
- stack_clear_offset(output->type(), output->stack_offset);
- output->stack_offset = SVM_STACK_INVALID;
+ if (all_done) {
+ stack_clear_offset(output->type(), output->stack_offset);
+ output->stack_offset = SVM_STACK_INVALID;
- foreach(ShaderInput *in, output->links)
- in->stack_offset = SVM_STACK_INVALID;
- }
- }
- }
+ foreach (ShaderInput *in, output->links)
+ in->stack_offset = SVM_STACK_INVALID;
+ }
+ }
+ }
}
void SVMCompiler::stack_clear_temporary(ShaderNode *node)
{
- foreach(ShaderInput *input, node->inputs) {
- if(!input->link && input->stack_offset != SVM_STACK_INVALID) {
- stack_clear_offset(input->type(), input->stack_offset);
- input->stack_offset = SVM_STACK_INVALID;
- }
- }
+ foreach (ShaderInput *input, node->inputs) {
+ if (!input->link && input->stack_offset != SVM_STACK_INVALID) {
+ stack_clear_offset(input->type(), input->stack_offset);
+ input->stack_offset = SVM_STACK_INVALID;
+ }
+ }
}
uint SVMCompiler::encode_uchar4(uint x, uint y, uint z, uint w)
{
- assert(x <= 255);
- assert(y <= 255);
- assert(z <= 255);
- assert(w <= 255);
+ assert(x <= 255);
+ assert(y <= 255);
+ assert(z <= 255);
+ assert(w <= 255);
- return (x) | (y << 8) | (z << 16) | (w << 24);
+ return (x) | (y << 8) | (z << 16) | (w << 24);
}
void SVMCompiler::add_node(int a, int b, int c, int d)
{
- current_svm_nodes.push_back_slow(make_int4(a, b, c, d));
+ current_svm_nodes.push_back_slow(make_int4(a, b, c, d));
}
void SVMCompiler::add_node(ShaderNodeType type, int a, int b, int c)
{
- current_svm_nodes.push_back_slow(make_int4(type, a, b, c));
+ current_svm_nodes.push_back_slow(make_int4(type, a, b, c));
}
-void SVMCompiler::add_node(ShaderNodeType type, const float3& f)
+void SVMCompiler::add_node(ShaderNodeType type, const float3 &f)
{
- current_svm_nodes.push_back_slow(make_int4(type,
- __float_as_int(f.x),
- __float_as_int(f.y),
- __float_as_int(f.z)));
+ current_svm_nodes.push_back_slow(
+ make_int4(type, __float_as_int(f.x), __float_as_int(f.y), __float_as_int(f.z)));
}
-void SVMCompiler::add_node(const float4& f)
+void SVMCompiler::add_node(const float4 &f)
{
- 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)));
+ 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)));
}
uint SVMCompiler::attribute(ustring name)
{
- return shader_manager->get_attribute_id(name);
+ return shader_manager->get_attribute_id(name);
}
uint SVMCompiler::attribute(AttributeStandard std)
{
- return shader_manager->get_attribute_id(std);
+ return shader_manager->get_attribute_id(std);
}
uint SVMCompiler::attribute_standard(ustring name)
{
- AttributeStandard std = Attribute::name_standard(name.c_str());
- return (std)? attribute(std): attribute(name);
+ AttributeStandard std = Attribute::name_standard(name.c_str());
+ return (std) ? attribute(std) : attribute(name);
}
-void SVMCompiler::find_dependencies(ShaderNodeSet& dependencies,
- const ShaderNodeSet& done,
+void SVMCompiler::find_dependencies(ShaderNodeSet &dependencies,
+ const ShaderNodeSet &done,
ShaderInput *input,
ShaderNode *skip_node)
{
- ShaderNode *node = (input->link)? input->link->parent: NULL;
- if(node != NULL &&
- done.find(node) == done.end() &&
- node != skip_node &&
- dependencies.find(node) == dependencies.end())
- {
- foreach(ShaderInput *in, node->inputs) {
- find_dependencies(dependencies, done, in, skip_node);
- }
- dependencies.insert(node);
- }
-}
-
-void SVMCompiler::generate_node(ShaderNode *node, ShaderNodeSet& done)
-{
- node->compile(*this);
- stack_clear_users(node, done);
- stack_clear_temporary(node);
-
- if(current_type == SHADER_TYPE_SURFACE) {
- if(node->has_spatial_varying())
- current_shader->has_surface_spatial_varying = true;
- }
- else if(current_type == SHADER_TYPE_VOLUME) {
- if(node->has_spatial_varying())
- current_shader->has_volume_spatial_varying = true;
- }
-
- if(node->has_object_dependency()) {
- current_shader->has_object_dependency = true;
- }
-
- if(node->has_attribute_dependency()) {
- current_shader->has_attribute_dependency = true;
- }
-
- if(node->has_integrator_dependency()) {
- current_shader->has_integrator_dependency = true;
- }
-}
-
-void SVMCompiler::generate_svm_nodes(const ShaderNodeSet& nodes,
- CompilerState *state)
-{
- ShaderNodeSet& done = state->nodes_done;
- vector<bool>& done_flag = state->nodes_done_flag;
-
- bool nodes_done;
- do {
- nodes_done = true;
-
- foreach(ShaderNode *node, nodes) {
- if(!done_flag[node->id]) {
- bool inputs_done = true;
-
- foreach(ShaderInput *input, node->inputs) {
- if(input->link && !done_flag[input->link->parent->id]) {
- inputs_done = false;
- }
- }
- if(inputs_done) {
- generate_node(node, done);
- done.insert(node);
- done_flag[node->id] = true;
- }
- else {
- nodes_done = false;
- }
- }
- }
- } while(!nodes_done);
-}
-
-void SVMCompiler::generate_closure_node(ShaderNode *node,
- CompilerState *state)
-{
- /* execute dependencies for closure */
- foreach(ShaderInput *in, node->inputs) {
- if(in->link != NULL) {
- ShaderNodeSet dependencies;
- find_dependencies(dependencies, state->nodes_done, in);
- generate_svm_nodes(dependencies, state);
- }
- }
-
- /* closure mix weight */
- const char *weight_name = (current_type == SHADER_TYPE_VOLUME)? "VolumeMixWeight": "SurfaceMixWeight";
- ShaderInput *weight_in = node->input(weight_name);
-
- if(weight_in && (weight_in->link || node->get_float(weight_in->socket_type) != 1.0f))
- mix_weight_offset = stack_assign(weight_in);
- else
- mix_weight_offset = SVM_STACK_INVALID;
-
- /* compile closure itself */
- generate_node(node, state->nodes_done);
-
- mix_weight_offset = SVM_STACK_INVALID;
-
- if(current_type == SHADER_TYPE_SURFACE) {
- if(node->has_surface_emission())
- current_shader->has_surface_emission = true;
- if(node->has_surface_transparent())
- current_shader->has_surface_transparent = true;
- if(node->has_surface_bssrdf()) {
- current_shader->has_surface_bssrdf = true;
- if(node->has_bssrdf_bump())
- current_shader->has_bssrdf_bump = true;
- }
- if(node->has_bump()) {
- current_shader->has_bump = true;
- }
- }
+ ShaderNode *node = (input->link) ? input->link->parent : NULL;
+ if (node != NULL && done.find(node) == done.end() && node != skip_node &&
+ dependencies.find(node) == dependencies.end()) {
+ foreach (ShaderInput *in, node->inputs) {
+ find_dependencies(dependencies, done, in, skip_node);
+ }
+ dependencies.insert(node);
+ }
+}
+
+void SVMCompiler::generate_node(ShaderNode *node, ShaderNodeSet &done)
+{
+ node->compile(*this);
+ stack_clear_users(node, done);
+ stack_clear_temporary(node);
+
+ if (current_type == SHADER_TYPE_SURFACE) {
+ if (node->has_spatial_varying())
+ current_shader->has_surface_spatial_varying = true;
+ }
+ else if (current_type == SHADER_TYPE_VOLUME) {
+ if (node->has_spatial_varying())
+ current_shader->has_volume_spatial_varying = true;
+ }
+
+ if (node->has_object_dependency()) {
+ current_shader->has_object_dependency = true;
+ }
+
+ if (node->has_attribute_dependency()) {
+ current_shader->has_attribute_dependency = true;
+ }
+
+ if (node->has_integrator_dependency()) {
+ current_shader->has_integrator_dependency = true;
+ }
+}
+
+void SVMCompiler::generate_svm_nodes(const ShaderNodeSet &nodes, CompilerState *state)
+{
+ ShaderNodeSet &done = state->nodes_done;
+ vector<bool> &done_flag = state->nodes_done_flag;
+
+ bool nodes_done;
+ do {
+ nodes_done = true;
+
+ foreach (ShaderNode *node, nodes) {
+ if (!done_flag[node->id]) {
+ bool inputs_done = true;
+
+ foreach (ShaderInput *input, node->inputs) {
+ if (input->link && !done_flag[input->link->parent->id]) {
+ inputs_done = false;
+ }
+ }
+ if (inputs_done) {
+ generate_node(node, done);
+ done.insert(node);
+ done_flag[node->id] = true;
+ }
+ else {
+ nodes_done = false;
+ }
+ }
+ }
+ } while (!nodes_done);
+}
+
+void SVMCompiler::generate_closure_node(ShaderNode *node, CompilerState *state)
+{
+ /* execute dependencies for closure */
+ foreach (ShaderInput *in, node->inputs) {
+ if (in->link != NULL) {
+ ShaderNodeSet dependencies;
+ find_dependencies(dependencies, state->nodes_done, in);
+ generate_svm_nodes(dependencies, state);
+ }
+ }
+
+ /* closure mix weight */
+ const char *weight_name = (current_type == SHADER_TYPE_VOLUME) ? "VolumeMixWeight" :
+ "SurfaceMixWeight";
+ ShaderInput *weight_in = node->input(weight_name);
+
+ if (weight_in && (weight_in->link || node->get_float(weight_in->socket_type) != 1.0f))
+ mix_weight_offset = stack_assign(weight_in);
+ else
+ mix_weight_offset = SVM_STACK_INVALID;
+
+ /* compile closure itself */
+ generate_node(node, state->nodes_done);
+
+ mix_weight_offset = SVM_STACK_INVALID;
+
+ if (current_type == SHADER_TYPE_SURFACE) {
+ if (node->has_surface_emission())
+ current_shader->has_surface_emission = true;
+ if (node->has_surface_transparent())
+ current_shader->has_surface_transparent = true;
+ if (node->has_surface_bssrdf()) {
+ current_shader->has_surface_bssrdf = true;
+ if (node->has_bssrdf_bump())
+ current_shader->has_bssrdf_bump = true;
+ }
+ if (node->has_bump()) {
+ current_shader->has_bump = true;
+ }
+ }
}
void SVMCompiler::generated_shared_closure_nodes(ShaderNode *root_node,
ShaderNode *node,
CompilerState *state,
- const ShaderNodeSet& shared)
-{
- if(shared.find(node) != shared.end()) {
- generate_multi_closure(root_node, node, state);
- }
- else {
- foreach(ShaderInput *in, node->inputs) {
- if(in->type() == SocketType::CLOSURE && in->link)
- generated_shared_closure_nodes(root_node,
- in->link->parent,
- state,
- shared);
- }
- }
+ const ShaderNodeSet &shared)
+{
+ if (shared.find(node) != shared.end()) {
+ generate_multi_closure(root_node, node, state);
+ }
+ else {
+ foreach (ShaderInput *in, node->inputs) {
+ if (in->type() == SocketType::CLOSURE && in->link)
+ generated_shared_closure_nodes(root_node, in->link->parent, state, shared);
+ }
+ }
}
void SVMCompiler::generate_multi_closure(ShaderNode *root_node,
ShaderNode *node,
CompilerState *state)
{
- /* only generate once */
- if(state->closure_done.find(node) != state->closure_done.end())
- return;
-
- state->closure_done.insert(node);
-
- if(node->special_type == SHADER_SPECIAL_TYPE_COMBINE_CLOSURE) {
- /* weighting is already taken care of in ShaderGraph::transform_multi_closure */
- ShaderInput *cl1in = node->input("Closure1");
- ShaderInput *cl2in = node->input("Closure2");
- ShaderInput *facin = node->input("Fac");
-
- /* skip empty mix/add closure nodes */
- if(!cl1in->link && !cl2in->link)
- return;
-
- if(facin && facin->link) {
- /* mix closure: generate instructions to compute mix weight */
- ShaderNodeSet dependencies;
- find_dependencies(dependencies, state->nodes_done, facin);
- generate_svm_nodes(dependencies, state);
-
- /* execute shared dependencies. this is needed to allow skipping
- * of zero weight closures and their dependencies later, so we
- * ensure that they only skip dependencies that are unique to them */
- ShaderNodeSet cl1deps, cl2deps, shareddeps;
-
- find_dependencies(cl1deps, state->nodes_done, cl1in);
- find_dependencies(cl2deps, state->nodes_done, cl2in);
-
- ShaderNodeIDComparator node_id_comp;
- set_intersection(cl1deps.begin(), cl1deps.end(),
- cl2deps.begin(), cl2deps.end(),
- std::inserter(shareddeps, shareddeps.begin()),
- node_id_comp);
-
- /* it's possible some nodes are not shared between this mix node
- * inputs, but still needed to be always executed, this mainly
- * happens when a node of current subbranch is used by a parent
- * node or so */
- if(root_node != node) {
- foreach(ShaderInput *in, root_node->inputs) {
- ShaderNodeSet rootdeps;
- find_dependencies(rootdeps, state->nodes_done, in, node);
- set_intersection(rootdeps.begin(), rootdeps.end(),
- cl1deps.begin(), cl1deps.end(),
- std::inserter(shareddeps, shareddeps.begin()),
- node_id_comp);
- set_intersection(rootdeps.begin(), rootdeps.end(),
- cl2deps.begin(), cl2deps.end(),
- std::inserter(shareddeps, shareddeps.begin()),
- node_id_comp);
- }
- }
-
- if(!shareddeps.empty()) {
- if(cl1in->link) {
- generated_shared_closure_nodes(root_node,
- cl1in->link->parent,
- state,
- shareddeps);
- }
- if(cl2in->link) {
- generated_shared_closure_nodes(root_node,
- cl2in->link->parent,
- state,
- shareddeps);
- }
-
- generate_svm_nodes(shareddeps, state);
- }
-
- /* generate instructions for input closure 1 */
- if(cl1in->link) {
- /* Add instruction to skip closure and its dependencies if mix
- * weight is zero.
- */
- 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;
-
- generate_multi_closure(root_node, cl1in->link->parent, state);
-
- /* Fill in jump instruction location to be after closure. */
- current_svm_nodes[node_jump_skip_index].y =
- current_svm_nodes.size() - node_jump_skip_index - 1;
- }
-
- /* generate instructions for input closure 2 */
- if(cl2in->link) {
- /* Add instruction to skip closure and its dependencies if mix
- * weight is zero.
- */
- 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;
-
- generate_multi_closure(root_node, cl2in->link->parent, state);
-
- /* Fill in jump instruction location to be after closure. */
- current_svm_nodes[node_jump_skip_index].y =
- current_svm_nodes.size() - node_jump_skip_index - 1;
- }
-
- /* unassign */
- facin->stack_offset = SVM_STACK_INVALID;
- }
- else {
- /* execute closures and their dependencies, no runtime checks
- * to skip closures here because was already optimized due to
- * fixed weight or add closure that always needs both */
- if(cl1in->link)
- generate_multi_closure(root_node, cl1in->link->parent, state);
- if(cl2in->link)
- generate_multi_closure(root_node, cl2in->link->parent, state);
- }
- }
- else {
- generate_closure_node(node, state);
- }
-
- state->nodes_done.insert(node);
- state->nodes_done_flag[node->id] = true;
+ /* only generate once */
+ if (state->closure_done.find(node) != state->closure_done.end())
+ return;
+
+ state->closure_done.insert(node);
+
+ if (node->special_type == SHADER_SPECIAL_TYPE_COMBINE_CLOSURE) {
+ /* weighting is already taken care of in ShaderGraph::transform_multi_closure */
+ ShaderInput *cl1in = node->input("Closure1");
+ ShaderInput *cl2in = node->input("Closure2");
+ ShaderInput *facin = node->input("Fac");
+
+ /* skip empty mix/add closure nodes */
+ if (!cl1in->link && !cl2in->link)
+ return;
+
+ if (facin && facin->link) {
+ /* mix closure: generate instructions to compute mix weight */
+ ShaderNodeSet dependencies;
+ find_dependencies(dependencies, state->nodes_done, facin);
+ generate_svm_nodes(dependencies, state);
+
+ /* execute shared dependencies. this is needed to allow skipping
+ * of zero weight closures and their dependencies later, so we
+ * ensure that they only skip dependencies that are unique to them */
+ ShaderNodeSet cl1deps, cl2deps, shareddeps;
+
+ find_dependencies(cl1deps, state->nodes_done, cl1in);
+ find_dependencies(cl2deps, state->nodes_done, cl2in);
+
+ ShaderNodeIDComparator node_id_comp;
+ set_intersection(cl1deps.begin(),
+ cl1deps.end(),
+ cl2deps.begin(),
+ cl2deps.end(),
+ std::inserter(shareddeps, shareddeps.begin()),
+ node_id_comp);
+
+ /* it's possible some nodes are not shared between this mix node
+ * inputs, but still needed to be always executed, this mainly
+ * happens when a node of current subbranch is used by a parent
+ * node or so */
+ if (root_node != node) {
+ foreach (ShaderInput *in, root_node->inputs) {
+ ShaderNodeSet rootdeps;
+ find_dependencies(rootdeps, state->nodes_done, in, node);
+ set_intersection(rootdeps.begin(),
+ rootdeps.end(),
+ cl1deps.begin(),
+ cl1deps.end(),
+ std::inserter(shareddeps, shareddeps.begin()),
+ node_id_comp);
+ set_intersection(rootdeps.begin(),
+ rootdeps.end(),
+ cl2deps.begin(),
+ cl2deps.end(),
+ std::inserter(shareddeps, shareddeps.begin()),
+ node_id_comp);
+ }
+ }
+
+ if (!shareddeps.empty()) {
+ if (cl1in->link) {
+ generated_shared_closure_nodes(root_node, cl1in->link->parent, state, shareddeps);
+ }
+ if (cl2in->link) {
+ generated_shared_closure_nodes(root_node, cl2in->link->parent, state, shareddeps);
+ }
+
+ generate_svm_nodes(shareddeps, state);
+ }
+
+ /* generate instructions for input closure 1 */
+ if (cl1in->link) {
+ /* Add instruction to skip closure and its dependencies if mix
+ * weight is zero.
+ */
+ 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;
+
+ generate_multi_closure(root_node, cl1in->link->parent, state);
+
+ /* Fill in jump instruction location to be after closure. */
+ current_svm_nodes[node_jump_skip_index].y = current_svm_nodes.size() -
+ node_jump_skip_index - 1;
+ }
+
+ /* generate instructions for input closure 2 */
+ if (cl2in->link) {
+ /* Add instruction to skip closure and its dependencies if mix
+ * weight is zero.
+ */
+ 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;
+
+ generate_multi_closure(root_node, cl2in->link->parent, state);
+
+ /* Fill in jump instruction location to be after closure. */
+ current_svm_nodes[node_jump_skip_index].y = current_svm_nodes.size() -
+ node_jump_skip_index - 1;
+ }
+
+ /* unassign */
+ facin->stack_offset = SVM_STACK_INVALID;
+ }
+ else {
+ /* execute closures and their dependencies, no runtime checks
+ * to skip closures here because was already optimized due to
+ * fixed weight or add closure that always needs both */
+ if (cl1in->link)
+ generate_multi_closure(root_node, cl1in->link->parent, state);
+ if (cl2in->link)
+ generate_multi_closure(root_node, cl2in->link->parent, state);
+ }
+ }
+ else {
+ generate_closure_node(node, state);
+ }
+
+ state->nodes_done.insert(node);
+ state->nodes_done_flag[node->id] = true;
}
-
void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType type)
{
- /* Converting a shader graph into svm_nodes that can be executed
- * sequentially on the virtual machine is fairly simple. We can keep
- * 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
- * stack and write outputs back to the stack.
- *
- * With the SVM, we always sample only a single closure. We can think
- * of all closures nodes as a binary tree with mix closures as inner
- * nodes and other closures as leafs. The SVM will traverse that tree,
- * each time deciding to go left or right depending on the mix weights,
- * until a closure is found.
- *
- * We only execute nodes that are needed for the mix weights and chosen
- * closure.
- */
-
- current_type = type;
- current_graph = graph;
-
- /* get input in output node */
- ShaderNode *node = graph->output();
- ShaderInput *clin = NULL;
-
- switch(type) {
- case SHADER_TYPE_SURFACE:
- clin = node->input("Surface");
- break;
- case SHADER_TYPE_VOLUME:
- clin = node->input("Volume");
- break;
- case SHADER_TYPE_DISPLACEMENT:
- clin = node->input("Displacement");
- break;
- case SHADER_TYPE_BUMP:
- clin = node->input("Normal");
- break;
- default:
- assert(0);
- break;
- }
-
- /* clear all compiler state */
- memset((void *)&active_stack, 0, sizeof(active_stack));
- current_svm_nodes.clear();
-
- foreach(ShaderNode *node_iter, graph->nodes) {
- foreach(ShaderInput *input, node_iter->inputs)
- input->stack_offset = SVM_STACK_INVALID;
- foreach(ShaderOutput *output, node_iter->outputs)
- output->stack_offset = SVM_STACK_INVALID;
- }
-
- /* for the bump shader we need add a node to store the shader state */
- bool need_bump_state = (type == SHADER_TYPE_BUMP) && (shader->displacement_method == DISPLACE_BOTH);
- int bump_state_offset = SVM_STACK_INVALID;
- if(need_bump_state) {
- bump_state_offset = stack_find_offset(SVM_BUMP_EVAL_STATE_SIZE);
- add_node(NODE_ENTER_BUMP_EVAL, bump_state_offset);
- }
-
- if(shader->used) {
- if(clin->link) {
- bool generate = false;
-
- switch(type) {
- case SHADER_TYPE_SURFACE: /* generate surface shader */
- generate = true;
- shader->has_surface = true;
- break;
- case SHADER_TYPE_VOLUME: /* generate volume shader */
- generate = true;
- shader->has_volume = true;
- break;
- case SHADER_TYPE_DISPLACEMENT: /* generate displacement shader */
- generate = true;
- shader->has_displacement = true;
- break;
- case SHADER_TYPE_BUMP: /* generate bump shader */
- generate = true;
- break;
- default:
- break;
- }
-
- if(generate) {
- CompilerState state(graph);
- generate_multi_closure(clin->link->parent,
- clin->link->parent,
- &state);
- }
- }
-
- /* compile output node */
- node->compile(*this);
- }
-
- /* add node to restore state after bump shader has finished */
- if(need_bump_state) {
- add_node(NODE_LEAVE_BUMP_EVAL, bump_state_offset);
- }
-
- /* if compile failed, generate empty shader */
- if(compile_failed) {
- current_svm_nodes.clear();
- compile_failed = false;
- }
-
- /* for bump shaders we fall thru to the surface shader, but if this is any other kind of shader it ends here */
- if(type != SHADER_TYPE_BUMP) {
- add_node(NODE_END, 0, 0, 0);
- }
-}
-
-void SVMCompiler::compile(Scene *scene,
- Shader *shader,
- array<int4>& svm_nodes,
- int index,
- Summary *summary)
-{
- /* copy graph for shader with bump mapping */
- ShaderNode *output = shader->graph->output();
- int start_num_svm_nodes = svm_nodes.size();
-
- const double time_start = time_dt();
-
- bool has_bump = (shader->displacement_method != DISPLACE_TRUE) &&
- output->input("Surface")->link && output->input("Displacement")->link;
-
- /* finalize */
- {
- scoped_timer timer((summary != NULL)? &summary->time_finalize: NULL);
- shader->graph->finalize(scene,
- has_bump,
- shader->has_integrator_dependency,
- shader->displacement_method == DISPLACE_BOTH);
- }
-
- current_shader = shader;
-
- shader->has_surface = false;
- shader->has_surface_emission = false;
- shader->has_surface_transparent = false;
- shader->has_surface_bssrdf = false;
- shader->has_bump = has_bump;
- shader->has_bssrdf_bump = has_bump;
- shader->has_volume = false;
- shader->has_displacement = false;
- shader->has_surface_spatial_varying = false;
- shader->has_volume_spatial_varying = false;
- shader->has_object_dependency = false;
- shader->has_attribute_dependency = false;
- shader->has_integrator_dependency = false;
-
- /* generate bump shader */
- if(has_bump) {
- scoped_timer timer((summary != NULL)? &summary->time_generate_bump: NULL);
- compile_type(shader, shader->graph, SHADER_TYPE_BUMP);
- svm_nodes[index].y = svm_nodes.size();
- svm_nodes.append(current_svm_nodes);
- }
-
- /* generate surface shader */
- {
- scoped_timer timer((summary != NULL)? &summary->time_generate_surface: NULL);
- compile_type(shader, shader->graph, SHADER_TYPE_SURFACE);
- /* only set jump offset if there's no bump shader, as the bump shader will fall thru to this one if it exists */
- if(!has_bump) {
- svm_nodes[index].y = svm_nodes.size();
- }
- svm_nodes.append(current_svm_nodes);
- }
-
- /* generate volume shader */
- {
- scoped_timer timer((summary != NULL)? &summary->time_generate_volume: NULL);
- compile_type(shader, shader->graph, SHADER_TYPE_VOLUME);
- svm_nodes[index].z = svm_nodes.size();
- svm_nodes.append(current_svm_nodes);
- }
-
- /* generate displacement shader */
- {
- scoped_timer timer((summary != NULL)? &summary->time_generate_displacement: NULL);
- compile_type(shader, shader->graph, SHADER_TYPE_DISPLACEMENT);
- svm_nodes[index].w = svm_nodes.size();
- svm_nodes.append(current_svm_nodes);
- }
-
- /* Fill in summary information. */
- if(summary != NULL) {
- summary->time_total = time_dt() - time_start;
- summary->peak_stack_usage = max_stack_use;
- summary->num_svm_nodes = svm_nodes.size() - start_num_svm_nodes;
- }
+ /* Converting a shader graph into svm_nodes that can be executed
+ * sequentially on the virtual machine is fairly simple. We can keep
+ * 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
+ * stack and write outputs back to the stack.
+ *
+ * With the SVM, we always sample only a single closure. We can think
+ * of all closures nodes as a binary tree with mix closures as inner
+ * nodes and other closures as leafs. The SVM will traverse that tree,
+ * each time deciding to go left or right depending on the mix weights,
+ * until a closure is found.
+ *
+ * We only execute nodes that are needed for the mix weights and chosen
+ * closure.
+ */
+
+ current_type = type;
+ current_graph = graph;
+
+ /* get input in output node */
+ ShaderNode *node = graph->output();
+ ShaderInput *clin = NULL;
+
+ switch (type) {
+ case SHADER_TYPE_SURFACE:
+ clin = node->input("Surface");
+ break;
+ case SHADER_TYPE_VOLUME:
+ clin = node->input("Volume");
+ break;
+ case SHADER_TYPE_DISPLACEMENT:
+ clin = node->input("Displacement");
+ break;
+ case SHADER_TYPE_BUMP:
+ clin = node->input("Normal");
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ /* clear all compiler state */
+ memset((void *)&active_stack, 0, sizeof(active_stack));
+ current_svm_nodes.clear();
+
+ foreach (ShaderNode *node_iter, graph->nodes) {
+ foreach (ShaderInput *input, node_iter->inputs)
+ input->stack_offset = SVM_STACK_INVALID;
+ foreach (ShaderOutput *output, node_iter->outputs)
+ output->stack_offset = SVM_STACK_INVALID;
+ }
+
+ /* for the bump shader we need add a node to store the shader state */
+ bool need_bump_state = (type == SHADER_TYPE_BUMP) &&
+ (shader->displacement_method == DISPLACE_BOTH);
+ int bump_state_offset = SVM_STACK_INVALID;
+ if (need_bump_state) {
+ bump_state_offset = stack_find_offset(SVM_BUMP_EVAL_STATE_SIZE);
+ add_node(NODE_ENTER_BUMP_EVAL, bump_state_offset);
+ }
+
+ if (shader->used) {
+ if (clin->link) {
+ bool generate = false;
+
+ switch (type) {
+ case SHADER_TYPE_SURFACE: /* generate surface shader */
+ generate = true;
+ shader->has_surface = true;
+ break;
+ case SHADER_TYPE_VOLUME: /* generate volume shader */
+ generate = true;
+ shader->has_volume = true;
+ break;
+ case SHADER_TYPE_DISPLACEMENT: /* generate displacement shader */
+ generate = true;
+ shader->has_displacement = true;
+ break;
+ case SHADER_TYPE_BUMP: /* generate bump shader */
+ generate = true;
+ break;
+ default:
+ break;
+ }
+
+ if (generate) {
+ CompilerState state(graph);
+ generate_multi_closure(clin->link->parent, clin->link->parent, &state);
+ }
+ }
+
+ /* compile output node */
+ node->compile(*this);
+ }
+
+ /* add node to restore state after bump shader has finished */
+ if (need_bump_state) {
+ add_node(NODE_LEAVE_BUMP_EVAL, bump_state_offset);
+ }
+
+ /* if compile failed, generate empty shader */
+ if (compile_failed) {
+ current_svm_nodes.clear();
+ compile_failed = false;
+ }
+
+ /* for bump shaders we fall thru to the surface shader, but if this is any other kind of shader it ends here */
+ if (type != SHADER_TYPE_BUMP) {
+ add_node(NODE_END, 0, 0, 0);
+ }
+}
+
+void SVMCompiler::compile(
+ Scene *scene, Shader *shader, array<int4> &svm_nodes, int index, Summary *summary)
+{
+ /* copy graph for shader with bump mapping */
+ ShaderNode *output = shader->graph->output();
+ int start_num_svm_nodes = svm_nodes.size();
+
+ const double time_start = time_dt();
+
+ bool has_bump = (shader->displacement_method != DISPLACE_TRUE) &&
+ output->input("Surface")->link && output->input("Displacement")->link;
+
+ /* finalize */
+ {
+ scoped_timer timer((summary != NULL) ? &summary->time_finalize : NULL);
+ shader->graph->finalize(scene,
+ has_bump,
+ shader->has_integrator_dependency,
+ shader->displacement_method == DISPLACE_BOTH);
+ }
+
+ current_shader = shader;
+
+ shader->has_surface = false;
+ shader->has_surface_emission = false;
+ shader->has_surface_transparent = false;
+ shader->has_surface_bssrdf = false;
+ shader->has_bump = has_bump;
+ shader->has_bssrdf_bump = has_bump;
+ shader->has_volume = false;
+ shader->has_displacement = false;
+ shader->has_surface_spatial_varying = false;
+ shader->has_volume_spatial_varying = false;
+ shader->has_object_dependency = false;
+ shader->has_attribute_dependency = false;
+ shader->has_integrator_dependency = false;
+
+ /* generate bump shader */
+ if (has_bump) {
+ scoped_timer timer((summary != NULL) ? &summary->time_generate_bump : NULL);
+ compile_type(shader, shader->graph, SHADER_TYPE_BUMP);
+ svm_nodes[index].y = svm_nodes.size();
+ svm_nodes.append(current_svm_nodes);
+ }
+
+ /* generate surface shader */
+ {
+ scoped_timer timer((summary != NULL) ? &summary->time_generate_surface : NULL);
+ compile_type(shader, shader->graph, SHADER_TYPE_SURFACE);
+ /* only set jump offset if there's no bump shader, as the bump shader will fall thru to this one if it exists */
+ if (!has_bump) {
+ svm_nodes[index].y = svm_nodes.size();
+ }
+ svm_nodes.append(current_svm_nodes);
+ }
+
+ /* generate volume shader */
+ {
+ scoped_timer timer((summary != NULL) ? &summary->time_generate_volume : NULL);
+ compile_type(shader, shader->graph, SHADER_TYPE_VOLUME);
+ svm_nodes[index].z = svm_nodes.size();
+ svm_nodes.append(current_svm_nodes);
+ }
+
+ /* generate displacement shader */
+ {
+ scoped_timer timer((summary != NULL) ? &summary->time_generate_displacement : NULL);
+ compile_type(shader, shader->graph, SHADER_TYPE_DISPLACEMENT);
+ svm_nodes[index].w = svm_nodes.size();
+ svm_nodes.append(current_svm_nodes);
+ }
+
+ /* Fill in summary information. */
+ if (summary != NULL) {
+ summary->time_total = time_dt() - time_start;
+ summary->peak_stack_usage = max_stack_use;
+ summary->num_svm_nodes = svm_nodes.size() - start_num_svm_nodes;
+ }
}
/* Compiler summary implementation. */
SVMCompiler::Summary::Summary()
- : num_svm_nodes(0),
- peak_stack_usage(0),
- time_finalize(0.0),
- time_generate_surface(0.0),
- time_generate_bump(0.0),
- time_generate_volume(0.0),
- time_generate_displacement(0.0),
- time_total(0.0)
+ : num_svm_nodes(0),
+ peak_stack_usage(0),
+ time_finalize(0.0),
+ time_generate_surface(0.0),
+ time_generate_bump(0.0),
+ time_generate_volume(0.0),
+ time_generate_displacement(0.0),
+ time_total(0.0)
{
}
string SVMCompiler::Summary::full_report() const
{
- string report = "";
- report += string_printf("Number of SVM nodes: %d\n", num_svm_nodes);
- report += string_printf("Peak stack usage: %d\n", peak_stack_usage);
+ string report = "";
+ report += string_printf("Number of SVM nodes: %d\n", num_svm_nodes);
+ report += string_printf("Peak stack usage: %d\n", peak_stack_usage);
- report += string_printf("Time (in seconds):\n");
- report += string_printf("Finalize: %f\n", time_finalize);
- report += string_printf(" Surface: %f\n", time_generate_surface);
- report += string_printf(" Bump: %f\n", time_generate_bump);
- report += string_printf(" Volume: %f\n", time_generate_volume);
- report += string_printf(" Displacement: %f\n", time_generate_displacement);
- report += string_printf("Generate: %f\n", time_generate_surface +
- time_generate_bump +
- time_generate_volume +
- time_generate_displacement);
- report += string_printf("Total: %f\n", time_total);
+ report += string_printf("Time (in seconds):\n");
+ report += string_printf("Finalize: %f\n", time_finalize);
+ report += string_printf(" Surface: %f\n", time_generate_surface);
+ report += string_printf(" Bump: %f\n", time_generate_bump);
+ report += string_printf(" Volume: %f\n", time_generate_volume);
+ report += string_printf(" Displacement: %f\n", time_generate_displacement);
+ report += string_printf("Generate: %f\n",
+ time_generate_surface + time_generate_bump + time_generate_volume +
+ time_generate_displacement);
+ report += string_printf("Total: %f\n", time_total);
- return report;
+ return report;
}
/* Global state of the compiler. */
SVMCompiler::CompilerState::CompilerState(ShaderGraph *graph)
{
- int max_id = 0;
- foreach(ShaderNode *node, graph->nodes) {
- max_id = max(node->id, max_id);
- }
- nodes_done_flag.resize(max_id + 1, false);
+ int max_id = 0;
+ foreach (ShaderNode *node, graph->nodes) {
+ max_id = max(node->id, max_id);
+ }
+ nodes_done_flag.resize(max_id + 1, false);
}
CCL_NAMESPACE_END