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:
authorBrecht Van Lommel <brechtvanlommel@gmail.com>2016-05-29 16:10:34 +0300
committerBrecht Van Lommel <brechtvanlommel@gmail.com>2016-05-29 21:30:16 +0300
commita70a435f28abc61f1b2d35c0bbc4d034ffaf4324 (patch)
tree1c445e4eb5def6f1231ead221bc607c005331c1a /intern/cycles
parentaf073e149b3c734f70bb13f20a4e18682885342e (diff)
Code refactor: centralize OSL node creation in shader manager.
Diffstat (limited to 'intern/cycles')
-rw-r--r--intern/cycles/app/cycles_xml.cpp81
-rw-r--r--intern/cycles/blender/blender_shader.cpp74
-rw-r--r--intern/cycles/render/nodes.cpp19
-rw-r--r--intern/cycles/render/nodes.h11
-rw-r--r--intern/cycles/render/osl.cpp129
-rw-r--r--intern/cycles/render/osl.h7
6 files changed, 178 insertions, 143 deletions
diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp
index f501a01e14b..60fa2fc11b3 100644
--- a/intern/cycles/app/cycles_xml.cpp
+++ b/intern/cycles/app/cycles_xml.cpp
@@ -31,6 +31,7 @@
#include "mesh.h"
#include "nodes.h"
#include "object.h"
+#include "osl.h"
#include "shader.h"
#include "scene.h"
@@ -250,35 +251,6 @@ static bool xml_read_enum_value(int *value, NodeEnum& enm, pugi::xml_node node,
return false;
}
-static SocketType::Type xml_read_socket_type(pugi::xml_node node, const char *name)
-{
- pugi::xml_attribute attr = node.attribute(name);
-
- if(attr) {
- string value = attr.value();
- if(string_iequals(value, "float"))
- return SocketType::FLOAT;
- else if(string_iequals(value, "int"))
- return SocketType::INT;
- else if(string_iequals(value, "color"))
- return SocketType::COLOR;
- else if(string_iequals(value, "vector"))
- return SocketType::VECTOR;
- else if(string_iequals(value, "point"))
- return SocketType::POINT;
- else if(string_iequals(value, "normal"))
- return SocketType::NORMAL;
- else if(string_iequals(value, "closure color"))
- return SocketType::CLOSURE;
- else if(string_iequals(value, "string"))
- return SocketType::STRING;
- else
- fprintf(stderr, "Unknown shader socket type \"%s\" for attribute \"%s\".\n", value.c_str(), name);
- }
-
- return SocketType::UNDEFINED;
-}
-
/* Camera */
static void xml_read_camera(XMLReadState& state, pugi::xml_node node)
@@ -313,6 +285,7 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml
{
xml_read_node(state, shader, graph_node);
+ ShaderManager *manager = state.scene->shader_manager;
ShaderGraph *graph = new ShaderGraph();
map<string, ShaderNode*> nodemap;
@@ -352,45 +325,27 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml
snode = env;
}
else if(string_iequals(node.name(), "osl_shader")) {
- OSLScriptNode *osl = new OSLScriptNode();
+ if(manager->use_osl()) {
+ std::string filepath;
- /* Source */
- xml_read_string(&osl->filepath, node, "src");
- if(path_is_relative(osl->filepath)) {
- osl->filepath = path_join(state.base, osl->filepath);
- }
+ if(xml_read_string(&filepath, node, "src")) {
+ if(path_is_relative(filepath)) {
+ filepath = path_join(state.base, filepath);
+ }
- /* Generate inputs/outputs from node sockets
- *
- * Note: ShaderInput/ShaderOutput store shallow string copies only!
- * So we register them as ustring to ensure the pointer stays valid. */
- /* read input values */
- for(pugi::xml_node param = node.first_child(); param; param = param.next_sibling()) {
- if(string_iequals(param.name(), "input")) {
- string name;
- if(!xml_read_string(&name, param, "name"))
- continue;
-
- SocketType::Type type = xml_read_socket_type(param, "type");
- if(type == SocketType::UNDEFINED)
- continue;
-
- osl->add_input(ustring(name).c_str(), type);
+ snode = ((OSLShaderManager*)manager)->osl_node(filepath);
+
+ if(!snode) {
+ fprintf(stderr, "Failed to create OSL node from \"%s\".\n", filepath.c_str());
+ }
}
- else if(string_iequals(param.name(), "output")) {
- string name;
- if(!xml_read_string(&name, param, "name"))
- continue;
-
- SocketType::Type type = xml_read_socket_type(param, "type");
- if(type == SocketType::UNDEFINED)
- continue;
-
- osl->add_output(ustring(name).c_str(), type);
+ else {
+ fprintf(stderr, "OSL node missing \"src\" attribute.\n");
}
}
-
- snode = osl;
+ else {
+ fprintf(stderr, "OSL node without using --shadingsys osl.\n");
+ }
}
else if(string_iequals(node.name(), "sky_texture")) {
SkyTextureNode *sky = new SkyTextureNode();
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index 5f16c1b6738..eb96756201a 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -148,29 +148,6 @@ static SocketType::Type convert_socket_type(BL::NodeSocket& b_socket)
}
}
-#ifdef WITH_OSL
-static SocketType::Type convert_osl_socket_type(OSL::OSLQuery& query,
- BL::NodeSocket& b_socket)
-{
- SocketType::Type socket_type = convert_socket_type(b_socket);
- if(socket_type == SocketType::VECTOR) {
- /* TODO(sergey): Do we need compatible_name() here? */
- const OSL::OSLQuery::Parameter *param = query.getparam(b_socket.name());
- assert(param != NULL);
- if(param != NULL) {
- if(param->type.vecsemantics == TypeDesc::POINT) {
- socket_type = SocketType::POINT;
- }
- else if(param->type.vecsemantics == TypeDesc::NORMAL) {
- socket_type = SocketType::NORMAL;
- }
- }
- }
-
- return socket_type;
-}
-#endif /* WITH_OSL */
-
static void set_default_value(ShaderInput *input,
BL::NodeSocket& b_sock,
BL::BlendData& b_data,
@@ -582,62 +559,17 @@ static ShaderNode *add_node(Scene *scene,
if(scene->shader_manager->use_osl()) {
/* create script node */
BL::ShaderNodeScript b_script_node(b_node);
- OSLScriptNode *script_node = new OSLScriptNode();
OSLShaderManager *manager = (OSLShaderManager*)scene->shader_manager;
string bytecode_hash = b_script_node.bytecode_hash();
- /* Gather additional information from the shader, such as
- * input/output type info needed for proper node construction.
- */
- OSL::OSLQuery query;
- string absolute_filepath;
-
if(!bytecode_hash.empty()) {
- query.open_bytecode(b_script_node.bytecode());
+ node = manager->osl_node("", bytecode_hash, b_script_node.bytecode());
}
else {
- absolute_filepath = blender_absolute_path(b_data, b_ntree, b_script_node.filepath());
- OSLShaderManager::osl_query(query, absolute_filepath);
+ string absolute_filepath = blender_absolute_path(b_data, b_ntree, b_script_node.filepath());
+ node = manager->osl_node(absolute_filepath, "");
}
- /* TODO(sergey): Add proper query info error parsing. */
-
- /* Generate inputs/outputs from node sockets
- *
- * Note: the node sockets are generated from OSL parameters,
- * so the names match those of the corresponding parameters exactly.
- *
- * Note 2: ShaderInput/ShaderOutput store shallow string copies only!
- * So we register them as ustring to ensure the pointer stays valid. */
- BL::Node::inputs_iterator b_input;
-
- for(b_script_node.inputs.begin(b_input); b_input != b_script_node.inputs.end(); ++b_input) {
- ShaderInput *input = script_node->add_input(ustring(b_input->name()).c_str(),
- convert_osl_socket_type(query, *b_input));
- set_default_value(input, *b_input, b_data, b_ntree);
- }
-
- BL::Node::outputs_iterator b_output;
-
- for(b_script_node.outputs.begin(b_output); b_output != b_script_node.outputs.end(); ++b_output) {
- script_node->add_output(ustring(b_output->name()).c_str(),
- convert_osl_socket_type(query, *b_output));
- }
-
- /* load bytecode or filepath */
- if(!bytecode_hash.empty()) {
- /* loaded bytecode if not already done */
- if(!manager->shader_test_loaded(bytecode_hash))
- manager->shader_load_bytecode(bytecode_hash, b_script_node.bytecode());
-
- script_node->bytecode_hash = bytecode_hash;
- }
- else {
- /* set filepath */
- script_node->filepath = absolute_filepath;
- }
-
- node = script_node;
}
#else
(void)b_data;
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index ea68a671029..a73204bc190 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -4516,20 +4516,29 @@ void SetNormalNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_set_normal");
}
-/* OSLScriptNode */
+/* OSLNode */
-OSLScriptNode::OSLScriptNode()
-: ShaderNode("osl_script")
+OSLNode::OSLNode()
+: ShaderNode("osl_shader")
{
special_type = SHADER_SPECIAL_TYPE_SCRIPT;
}
-void OSLScriptNode::compile(SVMCompiler& /*compiler*/)
+OSLNode::~OSLNode()
+{
+}
+
+OSLNode* OSLNode::create(size_t)
+{
+ return new OSLNode();
+}
+
+void OSLNode::compile(SVMCompiler&)
{
/* doesn't work for SVM, obviously ... */
}
-void OSLScriptNode::compile(OSLCompiler& compiler)
+void OSLNode::compile(OSLCompiler& compiler)
{
if(!filepath.empty())
compiler.add(this, filepath.c_str(), true);
diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h
index 43dc1dd26fe..9ece9b86eac 100644
--- a/intern/cycles/render/nodes.h
+++ b/intern/cycles/render/nodes.h
@@ -966,17 +966,22 @@ public:
SHADER_NODE_CLASS(SetNormalNode)
};
-class OSLScriptNode : public ShaderNode {
+class OSLNode : public ShaderNode {
public:
- SHADER_NODE_CLASS(OSLScriptNode)
+ static OSLNode *create(size_t num_inputs);
+ ~OSLNode();
+
+ SHADER_NODE_BASE_CLASS(OSLNode)
/* ideally we could beter detect this, but we can't query this now */
bool has_spatial_varying() { return true; }
+ virtual bool equals(const ShaderNode * /*other*/) { return false; }
string filepath;
string bytecode_hash;
- virtual bool equals(const ShaderNode * /*other*/) { return false; }
+private:
+ OSLNode();
};
class NormalMapNode : public ShaderNode {
diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp
index c1112ce44f6..1cfe3fb38e2 100644
--- a/intern/cycles/render/osl.cpp
+++ b/intern/cycles/render/osl.cpp
@@ -394,16 +394,143 @@ const char *OSLShaderManager::shader_load_bytecode(const string& hash, const str
{
ss->LoadMemoryCompiledShader(hash.c_str(), bytecode.c_str());
- /* this is a bit weak, but works */
OSLShaderInfo info;
+
+ if(!info.query.open_bytecode(bytecode)) {
+ fprintf(stderr, "OSL query error: %s\n", info.query.geterror().c_str());
+ }
+
+ /* this is a bit weak, but works */
info.has_surface_emission = (bytecode.find("\"emission\"") != string::npos);
info.has_surface_transparent = (bytecode.find("\"transparent\"") != string::npos);
info.has_surface_bssrdf = (bytecode.find("\"bssrdf\"") != string::npos);
+
loaded_shaders[hash] = info;
return loaded_shaders.find(hash)->first.c_str();
}
+OSLNode *OSLShaderManager::osl_node(const std::string& filepath,
+ const std::string& bytecode_hash,
+ const std::string& bytecode)
+{
+ /* create query */
+ const char *hash;
+
+ if(!filepath.empty()) {
+ hash = shader_load_filepath(filepath);
+ }
+ else {
+ hash = shader_test_loaded(bytecode_hash);
+ if(!hash)
+ hash = shader_load_bytecode(bytecode_hash, bytecode);
+ }
+
+ if(!hash) {
+ return NULL;
+ }
+
+ OSLShaderInfo *info = shader_loaded_info(hash);
+
+ /* count number of inputs */
+ size_t num_inputs = 0;
+
+ for(int i = 0; i < info->query.nparams(); i++) {
+ const OSL::OSLQuery::Parameter *param = info->query.getparam(i);
+
+ /* skip unsupported types */
+ if(param->varlenarray || param->isstruct || param->type.arraylen > 1)
+ continue;
+
+ if(!param->isoutput)
+ num_inputs++;
+ }
+
+ /* create node */
+ OSLNode *node = OSLNode::create(num_inputs);
+
+ /* add new sockets from parameters */
+ set<void*> used_sockets;
+
+ for(int i = 0; i < info->query.nparams(); i++) {
+ const OSL::OSLQuery::Parameter *param = info->query.getparam(i);
+
+ /* skip unsupported types */
+ if(param->varlenarray || param->isstruct || param->type.arraylen > 1)
+ continue;
+
+ SocketType::Type socket_type;
+
+ if(param->isclosure) {
+ socket_type = SocketType::CLOSURE;
+ }
+ else if(param->type.vecsemantics != TypeDesc::NOSEMANTICS) {
+ if(param->type.vecsemantics == TypeDesc::COLOR)
+ socket_type = SocketType::COLOR;
+ else if(param->type.vecsemantics == TypeDesc::POINT)
+ socket_type = SocketType::POINT;
+ else if(param->type.vecsemantics == TypeDesc::VECTOR)
+ socket_type = SocketType::VECTOR;
+ else if(param->type.vecsemantics == TypeDesc::NORMAL)
+ socket_type = SocketType::NORMAL;
+ else
+ continue;
+
+ if(!param->isoutput && param->validdefault) {
+ node->add_input(param->name.c_str(), socket_type, make_float3(param->fdefault[0], param->fdefault[1], param->fdefault[2]));
+ continue;
+ }
+ }
+ else if(param->type.aggregate == TypeDesc::SCALAR) {
+ if(param->type.basetype == TypeDesc::INT) {
+ socket_type = SocketType::INT;
+
+ if(!param->isoutput && param->validdefault) {
+ node->add_input(param->name.c_str(), socket_type, (float)param->idefault[0]);
+ continue;
+ }
+ }
+ else if(param->type.basetype == TypeDesc::FLOAT) {
+ socket_type = SocketType::FLOAT;
+
+ if(!param->isoutput && param->validdefault) {
+ node->add_input(param->name.c_str(), socket_type, param->fdefault[0]);
+ continue;
+ }
+ }
+ else if(param->type.basetype == TypeDesc::STRING) {
+ socket_type = SocketType::STRING;
+
+ if(!param->isoutput && param->validdefault) {
+ node->add_input(param->name.c_str(), socket_type);
+ continue;
+ }
+ }
+ else
+ continue;
+ }
+ else
+ continue;
+
+ if(param->isoutput) {
+ node->add_output(param->name.c_str(), socket_type);
+ }
+ else {
+ node->add_input(param->name.c_str(), socket_type);
+ }
+ }
+
+ /* set bytcode hash or filepath */
+ if(!bytecode_hash.empty()) {
+ node->bytecode_hash = bytecode_hash;
+ }
+ else {
+ node->filepath = filepath;
+ }
+
+ return node;
+}
+
/* Graph Compiler */
OSLCompiler::OSLCompiler(void *manager_, void *shadingsys_, ImageManager *image_manager_)
diff --git a/intern/cycles/render/osl.h b/intern/cycles/render/osl.h
index 110897ff300..13b9d6307f9 100644
--- a/intern/cycles/render/osl.h
+++ b/intern/cycles/render/osl.h
@@ -22,6 +22,7 @@
#include "util_thread.h"
#include "graph.h"
+#include "nodes.h"
#include "shader.h"
#ifdef WITH_OSL
@@ -54,6 +55,7 @@ struct OSLShaderInfo {
has_surface_bssrdf(false)
{}
+ OSL::OSLQuery query;
bool has_surface_emission;
bool has_surface_transparent;
bool has_surface_bssrdf;
@@ -83,6 +85,11 @@ public:
const char *shader_load_filepath(string filepath);
OSLShaderInfo *shader_loaded_info(const string& hash);
+ /* create OSL node using OSLQuery */
+ OSLNode *osl_node(const std::string& filepath,
+ const std::string& bytecode_hash = "",
+ const std::string& bytecode = "");
+
protected:
void texture_system_init();
void texture_system_free();