Blender V2.61 - r43446

osl.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright 2011, Blender Foundation.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 #include "device.h"
00020 
00021 #include "graph.h"
00022 #include "light.h"
00023 #include "osl.h"
00024 #include "scene.h"
00025 #include "shader.h"
00026 
00027 #ifdef WITH_OSL
00028 
00029 #include "osl_globals.h"
00030 #include "osl_services.h"
00031 #include "osl_shader.h"
00032 
00033 #include "util_foreach.h"
00034 #include "util_path.h"
00035 #include "util_progress.h"
00036 
00037 #endif
00038 
00039 CCL_NAMESPACE_BEGIN
00040 
00041 #ifdef WITH_OSL
00042 
00043 /* Shader Manager */
00044 
00045 OSLShaderManager::OSLShaderManager()
00046 {
00047     services = new OSLRenderServices();
00048 
00049     /* if we let OSL create it, it leaks */
00050     ts = TextureSystem::create(true);
00051     ts->attribute("automip",  1);
00052     ts->attribute("autotile", 64);
00053 
00054     ss = OSL::ShadingSystem::create(services, ts, &errhandler);
00055     ss->attribute("lockgeom", 1);
00056     ss->attribute("commonspace", "world");
00057     ss->attribute("optimize", 2);
00058     //ss->attribute("debug", 1);
00059     //ss->attribute("statistics:level", 1);
00060     ss->attribute("searchpath:shader", path_get("shader").c_str());
00061 
00062     OSLShader::register_closures(ss);
00063 }
00064 
00065 OSLShaderManager::~OSLShaderManager()
00066 {
00067     OSL::ShadingSystem::destroy(ss);
00068     OSL::TextureSystem::destroy(ts);
00069     delete services;
00070 }
00071 
00072 void OSLShaderManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
00073 {
00074     /* test if we need to update */
00075     bool need_update = false;
00076 
00077     foreach(Shader *shader, scene->shaders)
00078         if(shader->need_update)
00079             need_update = true;
00080     
00081     if(!need_update)
00082         return;
00083 
00084     device_free(device, dscene);
00085 
00086     /* create shaders */
00087     OSLGlobals *og = (OSLGlobals*)device->osl_memory();
00088 
00089     foreach(Shader *shader, scene->shaders) {
00090         assert(shader->graph);
00091 
00092         if(progress.get_cancel()) return;
00093 
00094         if(shader->sample_as_light && shader->has_surface_emission)
00095             scene->light_manager->need_update = true;
00096 
00097         OSLCompiler compiler((void*)ss);
00098         compiler.background = (shader == scene->shaders[scene->default_background]);
00099         compiler.compile(og, shader);
00100     }
00101 
00102     /* setup shader engine */
00103     og->ss = ss;
00104     int background_id = scene->shader_manager->get_shader_id(scene->default_background);
00105     og->background_state = og->surface_state[background_id];
00106     og->use = true;
00107 
00108     tls_create(OSLGlobals::ThreadData, og->thread_data);
00109 
00110     foreach(Shader *shader, scene->shaders)
00111         shader->need_update = false;
00112     
00113     /* set texture system */
00114     scene->image_manager->set_osl_texture_system((void*)ts);
00115 
00116     device_update_common(device, dscene, scene, progress);
00117 }
00118 
00119 void OSLShaderManager::device_free(Device *device, DeviceScene *dscene)
00120 {
00121     OSLGlobals *og = (OSLGlobals*)device->osl_memory();
00122 
00123     device_free_common(device, dscene);
00124 
00125     /* clear shader engine */
00126     og->use = false;
00127     og->ss = NULL;
00128 
00129     tls_delete(OSLGlobals::ThreadData, og->thread_data);
00130 
00131     og->surface_state.clear();
00132     og->volume_state.clear();
00133     og->displacement_state.clear();
00134     og->background_state.reset();
00135 }
00136 
00137 /* Graph Compiler */
00138 
00139 OSLCompiler::OSLCompiler(void *shadingsys_)
00140 {
00141     shadingsys = shadingsys_;
00142     current_type = SHADER_TYPE_SURFACE;
00143     current_shader = NULL;
00144     background = false;
00145 }
00146 
00147 string OSLCompiler::id(ShaderNode *node)
00148 {
00149     /* assign layer unique name based on pointer address + bump mode */
00150     stringstream stream;
00151     stream << "node_" << node->name << "_" << node;
00152 
00153     return stream.str();
00154 }
00155 
00156 string OSLCompiler::compatible_name(const char *name)
00157 {
00158     string sname = name;
00159     size_t i;
00160 
00161     while((i = sname.find(" ")) != string::npos)
00162         sname.replace(i, 1, "");
00163     
00164     return sname;
00165 }
00166 
00167 bool OSLCompiler::node_skip_input(ShaderNode *node, ShaderInput *input)
00168 {
00169     /* exception for output node, only one input is actually used
00170        depending on the current shader type */
00171 
00172     if(node->name == ustring("output")) {
00173         if(strcmp(input->name, "Surface") == 0 && current_type != SHADER_TYPE_SURFACE)
00174             return true;
00175         if(strcmp(input->name, "Volume") == 0 && current_type != SHADER_TYPE_VOLUME)
00176             return true;
00177         if(strcmp(input->name, "Displacement") == 0 && current_type != SHADER_TYPE_DISPLACEMENT)
00178             return true;
00179     }
00180     else if(current_type == SHADER_TYPE_DISPLACEMENT && input->link && input->link->parent->name == ustring("bump"))
00181         return true;
00182 
00183     return false;
00184 }
00185 
00186 void OSLCompiler::add(ShaderNode *node, const char *name)
00187 {
00188     OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
00189 
00190     /* pass in fixed parameter values */
00191     foreach(ShaderInput *input, node->inputs) {
00192         if(!input->link) {
00193             /* checks to untangle graphs */
00194             if(node_skip_input(node, input))
00195                 continue;
00196             /* already has default value assigned */
00197             else if(input->default_value != ShaderInput::NONE)
00198                 continue;
00199 
00200             switch(input->type) {
00201                 case SHADER_SOCKET_COLOR:
00202                     parameter_color(input->name, input->value);
00203                     break;
00204                 case SHADER_SOCKET_POINT:
00205                     parameter_point(input->name, input->value);
00206                     break;
00207                 case SHADER_SOCKET_VECTOR:
00208                     parameter_vector(input->name, input->value);
00209                     break;
00210                 case SHADER_SOCKET_NORMAL:
00211                     parameter_normal(input->name, input->value);
00212                     break;
00213                 case SHADER_SOCKET_FLOAT:
00214                     parameter(input->name, input->value.x);
00215                     break;
00216                 case SHADER_SOCKET_CLOSURE:
00217                     break;
00218             }
00219         }
00220     }
00221 
00222     /* create shader of the appropriate type. we pass "surface" to all shaders,
00223      * because "volume" and "displacement" don't work yet in OSL. the shaders
00224      * work fine, but presumably these values would be used for more strict
00225      * checking, so when that is fixed, we should update the code here too. */
00226     if(current_type == SHADER_TYPE_SURFACE)
00227         ss->Shader("surface", name, id(node).c_str());
00228     else if(current_type == SHADER_TYPE_VOLUME)
00229         ss->Shader("surface", name, id(node).c_str());
00230     else if(current_type == SHADER_TYPE_DISPLACEMENT)
00231         ss->Shader("surface", name, id(node).c_str());
00232     else
00233         assert(0);
00234     
00235     /* link inputs to other nodes */
00236     foreach(ShaderInput *input, node->inputs) {
00237         if(input->link) {
00238             if(node_skip_input(node, input))
00239                 continue;
00240 
00241             /* connect shaders */
00242             string id_from = id(input->link->parent);
00243             string id_to = id(node);
00244             string param_from = compatible_name(input->link->name);
00245             string param_to = compatible_name(input->name);
00246 
00247             /* avoid name conflict with same input/output socket name */
00248             if(input->link->parent->input(input->link->name))
00249                 param_from += "_";
00250 
00251             ss->ConnectShaders(id_from.c_str(), param_from.c_str(), id_to.c_str(), param_to.c_str());
00252         }
00253     }
00254 }
00255 
00256 void OSLCompiler::parameter(const char *name, float f)
00257 {
00258     OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
00259     ss->Parameter(name, TypeDesc::TypeFloat, &f);
00260 }
00261 
00262 void OSLCompiler::parameter_color(const char *name, float3 f)
00263 {
00264     OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
00265     ss->Parameter(name, TypeDesc::TypeColor, &f);
00266 }
00267 
00268 void OSLCompiler::parameter_point(const char *name, float3 f)
00269 {
00270     OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
00271     ss->Parameter(name, TypeDesc::TypePoint, &f);
00272 }
00273 
00274 void OSLCompiler::parameter_normal(const char *name, float3 f)
00275 {
00276     OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
00277     ss->Parameter(name, TypeDesc::TypeNormal, &f);
00278 }
00279 
00280 void OSLCompiler::parameter_vector(const char *name, float3 f)
00281 {
00282     OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
00283     ss->Parameter(name, TypeDesc::TypeVector, &f);
00284 }
00285 
00286 void OSLCompiler::parameter(const char *name, int f)
00287 {
00288     OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
00289     ss->Parameter(name, TypeDesc::TypeInt, &f);
00290 }
00291 
00292 void OSLCompiler::parameter(const char *name, const char *s)
00293 {
00294     OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
00295     ss->Parameter(name, TypeDesc::TypeString, &s);
00296 }
00297 
00298 void OSLCompiler::parameter(const char *name, ustring s)
00299 {
00300     OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
00301     const char *str = s.c_str();
00302     ss->Parameter(name, TypeDesc::TypeString, &str);
00303 }
00304 
00305 void OSLCompiler::parameter(const char *name, const Transform& tfm)
00306 {
00307     OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
00308     ss->Parameter(name, TypeDesc::TypeMatrix, (float*)&tfm);
00309 }
00310 
00311 void OSLCompiler::find_dependencies(set<ShaderNode*>& dependencies, ShaderInput *input)
00312 {
00313     ShaderNode *node = (input->link)? input->link->parent: NULL;
00314 
00315     if(node) {
00316         foreach(ShaderInput *in, node->inputs)
00317             if(!node_skip_input(node, in))
00318                 find_dependencies(dependencies, in);
00319 
00320         dependencies.insert(node);
00321     }
00322 }
00323 
00324 void OSLCompiler::generate_nodes(const set<ShaderNode*>& nodes)
00325 {
00326     set<ShaderNode*> done;
00327     bool nodes_done;
00328 
00329     do {
00330         nodes_done = true;
00331 
00332         foreach(ShaderNode *node, nodes) {
00333             if(done.find(node) == done.end()) {
00334                 bool inputs_done = true;
00335 
00336                 foreach(ShaderInput *input, node->inputs)
00337                     if(!node_skip_input(node, input))
00338                         if(input->link && done.find(input->link->parent) == done.end())
00339                             inputs_done = false;
00340 
00341                 if(inputs_done) {
00342                     node->compile(*this);
00343                     done.insert(node);
00344 
00345                     if(node->name == ustring("emission"))
00346                         current_shader->has_surface_emission = true;
00347                     if(node->name == ustring("transparent"))
00348                         current_shader->has_surface_transparent = true;
00349                 }
00350                 else
00351                     nodes_done = false;
00352             }
00353         }
00354     } while(!nodes_done);
00355 }
00356 
00357 void OSLCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType type)
00358 {
00359     OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
00360 
00361     current_type = type;
00362 
00363     ss->ShaderGroupBegin();
00364 
00365     ShaderNode *output = graph->output();
00366     set<ShaderNode*> dependencies;
00367 
00368     if(type == SHADER_TYPE_SURFACE) {
00369         /* generate surface shader */
00370         find_dependencies(dependencies, output->input("Surface"));
00371         generate_nodes(dependencies);
00372         output->compile(*this);
00373     }
00374     else if(type == SHADER_TYPE_VOLUME) {
00375         /* generate volume shader */
00376         find_dependencies(dependencies, output->input("Volume"));
00377         generate_nodes(dependencies);
00378         output->compile(*this);
00379     }
00380     else if(type == SHADER_TYPE_DISPLACEMENT) {
00381         /* generate displacement shader */
00382         find_dependencies(dependencies, output->input("Displacement"));
00383         generate_nodes(dependencies);
00384         output->compile(*this);
00385     }
00386     else
00387         assert(0);
00388 
00389     ss->ShaderGroupEnd();
00390 }
00391 
00392 void OSLCompiler::compile(OSLGlobals *og, Shader *shader)
00393 {
00394     OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
00395     ShaderGraph *graph = shader->graph;
00396     ShaderNode *output = (graph)? graph->output(): NULL;
00397 
00398     /* copy graph for shader with bump mapping */
00399     if(output->input("Surface")->link && output->input("Displacement")->link)
00400         if(!shader->graph_bump)
00401             shader->graph_bump = shader->graph->copy();
00402 
00403     /* finalize */
00404     shader->graph->finalize(false, true);
00405     if(shader->graph_bump)
00406         shader->graph_bump->finalize(true, true);
00407 
00408     current_shader = shader;
00409 
00410     shader->has_surface = false;
00411     shader->has_surface_emission = false;
00412     shader->has_surface_transparent = false;
00413     shader->has_volume = false;
00414     shader->has_displacement = false;
00415 
00416     /* generate surface shader */
00417     if(graph && output->input("Surface")->link) {
00418         compile_type(shader, shader->graph, SHADER_TYPE_SURFACE);
00419         og->surface_state.push_back(ss->state());
00420 
00421         if(shader->graph_bump) {
00422             ss->clear_state();
00423             compile_type(shader, shader->graph_bump, SHADER_TYPE_SURFACE);
00424             og->surface_state.push_back(ss->state());
00425         }
00426         else
00427             og->surface_state.push_back(ss->state());
00428 
00429         ss->clear_state();
00430 
00431         shader->has_surface = true;
00432     }
00433     else {
00434         og->surface_state.push_back(OSL::ShadingAttribStateRef());
00435         og->surface_state.push_back(OSL::ShadingAttribStateRef());
00436     }
00437 
00438     /* generate volume shader */
00439     if(graph && output->input("Volume")->link) {
00440         compile_type(shader, shader->graph, SHADER_TYPE_VOLUME);
00441         shader->has_volume = true;
00442 
00443         og->volume_state.push_back(ss->state());
00444         og->volume_state.push_back(ss->state());
00445         ss->clear_state();
00446     }
00447     else {
00448         og->volume_state.push_back(OSL::ShadingAttribStateRef());
00449         og->volume_state.push_back(OSL::ShadingAttribStateRef());
00450     }
00451 
00452     /* generate displacement shader */
00453     if(graph && output->input("Displacement")->link) {
00454         compile_type(shader, shader->graph, SHADER_TYPE_DISPLACEMENT);
00455         shader->has_displacement = true;
00456 
00457         og->displacement_state.push_back(ss->state());
00458         og->displacement_state.push_back(ss->state());
00459         ss->clear_state();
00460     }
00461     else {
00462         og->displacement_state.push_back(OSL::ShadingAttribStateRef());
00463         og->displacement_state.push_back(OSL::ShadingAttribStateRef());
00464     }
00465 }
00466 
00467 #else
00468 
00469 void OSLCompiler::add(ShaderNode *node, const char *name)
00470 {
00471 }
00472 
00473 void OSLCompiler::parameter(const char *name, float f)
00474 {
00475 }
00476 
00477 void OSLCompiler::parameter_color(const char *name, float3 f)
00478 {
00479 }
00480 
00481 void OSLCompiler::parameter_vector(const char *name, float3 f)
00482 {
00483 }
00484 
00485 void OSLCompiler::parameter(const char *name, int f)
00486 {
00487 }
00488 
00489 void OSLCompiler::parameter(const char *name, const char *s)
00490 {
00491 }
00492 
00493 void OSLCompiler::parameter(const char *name, ustring s)
00494 {
00495 }
00496 
00497 void OSLCompiler::parameter(const char *name, const Transform& tfm)
00498 {
00499 }
00500 
00501 #endif /* WITH_OSL */
00502 
00503 CCL_NAMESPACE_END
00504