void VarianceShadowRenderer::render(void *ptr) { child->render(ptr); getFrameBuffer().bind(); ShaderInstance *sh = getVSMShader(); sh->setValue(SVTexture0, child->getShadowMap()); sh->bind(); GLContext::getContext()->getScreen().draw(MaterialRenderData()); FrameBuffer *temp = GLContext::getContext()->getFrameBufferPool().get(getSize(), false, ImageFormat::RG32F); blurs[1]->setValue(SVTexture0, temp->getAttachment(0)); blurs[0]->setValue(SVTexture0, getFrameBuffer().getAttachment(0)); temp->bind(); blurs[0]->bind(); GLContext::getContext()->getScreen().draw(MaterialRenderData()); getFrameBuffer().bind(); blurs[1]->bind(); GLContext::getContext()->getScreen().draw(MaterialRenderData()); blurs[1]->unbind(); GLContext::getContext()->getFrameBufferPool().add(temp); child->discardBuffer(); }
//------------------------------------------------------------------------- // @brief //------------------------------------------------------------------------- const ShaderInstance ForceField::deserialise( const tinyxml2::XMLElement* element) { ShaderInstance shaderInstance; const tinyxml2::XMLAttribute* attribute = element->FindAttribute("name"); if (attribute != nullptr) { m_name = attribute->Value(); } for (element = element->FirstChildElement(); element != 0; element = element->NextSiblingElement()) { unsigned int typeHash = hashString(element->Value()); if (Material::m_hash == typeHash) { shaderInstance.getMaterial().deserialise(m_resource, getGameResource().getDeviceManager(), getGameResource().getTextureManager(), getGameResource().getLightManager(), element); shaderInstance.getMaterial().setBlendState(true); } else if (Vector3::m_hash == typeHash) { m_position.deserialise(element); translate(m_world, m_position.x(), m_position.y(), m_position.z()); } } return shaderInstance; }
//------------------------------------------------------------------------- // @brief //------------------------------------------------------------------------- const ShaderInstance Core::deserialise( const tinyxml2::XMLElement* element) { ShaderInstance shaderInstance; const tinyxml2::XMLAttribute* attribute = element->FindAttribute("name"); if (attribute != nullptr) { m_name = attribute->Value(); } for (const tinyxml2::XMLElement* childElement = element->FirstChildElement(); childElement; childElement = childElement->NextSiblingElement()) { unsigned int childElementHash = hashString(childElement->Value()); if (childElementHash == Material::m_hash) { const tinyxml2::XMLAttribute* nameAttribute = childElement->FindAttribute("name"); //This material needs a name to distinguish between normal and glowing versions of the material if (nameAttribute) { if (strICmp(nameAttribute->Value(), "CoreMaterialNormal")) { m_forcefieldmatnormal.deserialise(m_resource, getGameResource().getDeviceManager(), getGameResource().getTextureManager(), getGameResource().getLightManager(), childElement); shaderInstance.getMaterial().deserialise(m_resource, getGameResource().getDeviceManager(), getGameResource().getTextureManager(), getGameResource().getLightManager(), childElement); shaderInstance.getMaterial().addTextureReference(Material::TextureSlotMapping(hashString("cube_player_forcefield"), Material::TextureSlotMapping::Diffuse0)); } else if( strICmp(nameAttribute->Value(), "CoreMaterialNormalGlow") ) { m_forcefieldmatglowing.deserialise(m_resource, getGameResource().getDeviceManager(), getGameResource().getTextureManager(), getGameResource().getLightManager(), childElement); } } } else if (childElementHash == hashString("Model")) { attribute = childElement->FindAttribute("file_name"); if (attribute != nullptr) { //Heavily relies on the shader instance existing before we load the model, might be better to put the model construction in initialise instead m_drawableObject = getWriteableGameResource().getModelManager().LoadModel(m_resource, shaderInstance, attribute->Value()); m_drawableObject->setDirty(); } } } //Get texture strings and load textures const SettingsManager& sm = getGameResource().getSettingsManager(); TextureManager& tm = getWriteableGameResource().getTextureManager(); const ISetting<std::string>* textureString = sm.getSetting<std::string>("Core"); if (textureString) { tm.addLoad(getGameResource().getDeviceManager(), textureString->getData()); shaderInstance.getMaterial().addTextureReference(Material::TextureSlotMapping(hashString(getTextureNameFromFileName(textureString->getData())), Material::TextureSlotMapping::Diffuse0)); } textureString = sm.getSetting<std::string>("ForceFieldCore"); if (textureString) { tm.addLoad(getGameResource().getDeviceManager(), textureString->getData()); shaderInstance.getMaterial().addTextureReference(Material::TextureSlotMapping(hashString(getTextureNameFromFileName(textureString->getData())), Material::TextureSlotMapping::Diffuse0)); } return shaderInstance; }
void GunTurret::fireLaser() { ShaderInstance shaderInstance; shaderInstance.setMaterial(Material(0.0f, Color::black(), Color::black(), Color::red(), Color::red())); shaderInstance.getMaterial().setBlendState(true); shaderInstance.getMaterial().setEffect(getGameResource().getEffectCache().getEffect("laser_effect.xml")); getWriteableGameResource().getLaserManager().addInstance(m_position + Vector3(0.0f, 3.0f, 0.0f), m_direction, shaderInstance); }
//------------------------------------------------------------------------- // @brief //------------------------------------------------------------------------- const ShaderInstance GunTurret::deserialise( const tinyxml2::XMLElement* element) { ShaderInstance shaderInstance; const tinyxml2::XMLAttribute* attribute = element->FindAttribute("name"); if (attribute != nullptr) { m_name = attribute->Value(); } Matrix44 scaleTransform, translation, rotation; for (const tinyxml2::XMLElement* childElement = element->FirstChildElement(); childElement; childElement = childElement->NextSiblingElement()) { unsigned int childElementHash = hashString(childElement->Value()); if (childElementHash == Vector3::m_hash) { const tinyxml2::XMLAttribute* nameAttribute = childElement->FindAttribute("name"); //This material needs a name to distinguish between normal and glowing versions of the material if (nameAttribute) { if (strICmp(nameAttribute->Value(), "position")) { m_position.deserialise(childElement); scale(scaleTransform, 5.0f, 5.0f, 5.0f); translate(translation, m_position); } else if( strICmp(nameAttribute->Value(), "direction") ) { m_direction.deserialise(childElement); m_direction.normalize(); rotation = rotationFromDirection(m_direction); } } } if (childElementHash == hashString("Model")) { attribute = childElement->FindAttribute("file"); if (attribute != nullptr) { //Heavily relies on the shader instance existing before we load the model, might be better to put the model construction in initialise instead m_drawableObject = getWriteableGameResource().getModelManager().LoadModel(m_resource, shaderInstance, attribute->Value()); m_drawableObject->setDirty(); } } if (childElementHash == Material::m_hash) { shaderInstance.getMaterial().deserialise(m_resource, getGameResource().getDeviceManager(), getGameResource().getTextureManager(), getGameResource().getLightManager(), childElement ); } } m_world = rotation * scaleTransform * translation; return shaderInstance; }
llvm::Type * BackendLLVM::llvm_type_groupdata () { // If already computed, return it if (m_llvm_type_groupdata) return m_llvm_type_groupdata; std::vector<llvm::Type*> fields; // First, add the array that tells if each layer has run. But only make // slots for the layers that may be called/used. int sz = (m_num_used_layers + 3) & (~3); // Round up to 32 bit boundary fields.push_back (ll.type_array (ll.type_bool(), sz)); size_t offset = sz * sizeof(bool); // For each layer in the group, add entries for all params that are // connected or interpolated, and output params. Also mark those // symbols with their offset within the group struct. if (llvm_debug() >= 2) std::cout << "Group param struct:\n"; m_param_order_map.clear (); int order = 1; for (int layer = 0; layer < group().nlayers(); ++layer) { ShaderInstance *inst = group()[layer]; if (inst->unused()) continue; FOREACH_PARAM (Symbol &sym, inst) { TypeSpec ts = sym.typespec(); if (ts.is_structure()) // skip the struct symbol itself continue; int arraylen = std::max (1, sym.typespec().arraylength()); int deriv_mult = sym.has_derivs() ? 3 : 1; int n = arraylen * deriv_mult; ts.make_array (n); fields.push_back (llvm_type (ts)); // Alignment size_t align = sym.typespec().is_closure_based() ? sizeof(void*) : sym.typespec().simpletype().basesize(); if (offset & (align-1)) offset += align - (offset & (align-1)); if (llvm_debug() >= 2) std::cout << " " << inst->layername() << " (" << inst->id() << ") " << sym.mangled() << " " << ts.c_str() << ", field " << order << ", offset " << offset << std::endl; sym.dataoffset ((int)offset); offset += int(sym.size()) * deriv_mult; m_param_order_map[&sym] = order; ++order; } }
bool ShaderInstance::mergeable (const ShaderInstance &b, const ShaderGroup &g) const { // Must both be instances of the same master -- very fast early-out // for most potential pair comparisons. if (master() != b.master()) return false; // If the shaders haven't been optimized yet, they don't yet have // their own symbol tables and instructions (they just refer to // their unoptimized master), but they may have an "instance // override" vector that describes which parameters have // instance-specific values or connections. bool optimized = (m_instsymbols.size() != 0 || m_instops.size() != 0); // Same instance overrides if (m_instoverrides.size() || b.m_instoverrides.size()) { ASSERT (! optimized); // should not be post-opt ASSERT (m_instoverrides.size() == b.m_instoverrides.size()); for (size_t i = 0, e = m_instoverrides.size(); i < e; ++i) { if ((m_instoverrides[i].valuesource() == Symbol::DefaultVal || m_instoverrides[i].valuesource() == Symbol::InstanceVal) && (b.m_instoverrides[i].valuesource() == Symbol::DefaultVal || b.m_instoverrides[i].valuesource() == Symbol::InstanceVal)) { // If both params are defaults or instances, let the // instance parameter value checking below handle // things. No need to reject default-vs-instance // mismatches if the actual values turn out to be the // same later. continue; } if (! (equivalent(m_instoverrides[i], b.m_instoverrides[i]))) { const Symbol *sym = mastersymbol(i); // remember, it's pre-opt if (! sym->everused()) continue; return false; } } } // Make sure that the two nodes have the same parameter values. If // the group has already been optimized, it's got an // instance-specific symbol table to check; but if it hasn't been // optimized, we check the symbol table int he master. for (int i = firstparam(); i < lastparam(); ++i) { const Symbol *sym = optimized ? symbol(i) : mastersymbol(i); if (! sym->everused()) continue; if (sym->typespec().is_closure()) continue; // Closures can't have instance override values if ((sym->valuesource() == Symbol::InstanceVal || sym->valuesource() == Symbol::DefaultVal) && memcmp (param_storage(i), b.param_storage(i), sym->typespec().simpletype().size())) { return false; } } if (m_run_lazily != b.m_run_lazily) { return false; } // The connection list need to be the same for the two shaders. if (m_connections.size() != b.m_connections.size()) { return false; } if (m_connections != b.m_connections) { return false; } // If there are no "local" ops or symbols, this instance hasn't been // optimized yet. In that case, we've already done enough checking, // since the masters being the same and having the same instance // params and connections is all it takes. The rest (below) only // comes into play after instances are more fully elaborated from // their masters in order to be optimized. if (!optimized) { return true; } // Same symbol table if (! equivalent (m_instsymbols, b.m_instsymbols)) { return false; } // Same opcodes to run if (! equivalent (m_instops, b.m_instops)) { return false; } // Same arguments to the ops if (m_instargs != b.m_instargs) { return false; } // Parameter and code ranges if (m_firstparam != b.m_firstparam || m_lastparam != b.m_lastparam || m_maincodebegin != b.m_maincodebegin || m_maincodeend != b.m_maincodeend || m_Psym != b.m_Psym || m_Nsym != b.m_Nsym) { return false; } // Nothing left to check, they must be identical! return true; }
llvm::Function* BackendLLVM::build_llvm_instance (bool groupentry) { // Make a layer function: void layer_func(ShaderGlobals*, GroupData*) // Note that the GroupData* is passed as a void*. std::string unique_layer_name = Strutil::format ("%s_%d", inst()->layername(), inst()->id()); ll.current_function ( ll.make_function (unique_layer_name, !groupentry, // fastcall for non-entry layer functions ll.type_void(), // return type llvm_type_sg_ptr(), llvm_type_groupdata_ptr())); // Get shader globals and groupdata pointers m_llvm_shaderglobals_ptr = ll.current_function_arg(0); //arg_it++; m_llvm_groupdata_ptr = ll.current_function_arg(1); //arg_it++; llvm::BasicBlock *entry_bb = ll.new_basic_block (unique_layer_name); m_exit_instance_block = NULL; // Set up a new IR builder ll.new_builder (entry_bb); #if 0 /* helpful for debuggin */ if (llvm_debug() && groupentry) llvm_gen_debug_printf (Strutil::format("\n\n\n\nGROUP! %s",group().name())); if (llvm_debug()) llvm_gen_debug_printf (Strutil::format("enter layer %s %s", inst()->layername(), inst()->shadername())); #endif if (shadingsys().countlayerexecs()) ll.call_function ("osl_incr_layers_executed", sg_void_ptr()); if (groupentry) { if (m_num_used_layers > 1) { // If this is the group entry point, clear all the "layer // executed" bits. If it's not the group entry (but rather is // an upstream node), then set its bit! int sz = (m_num_used_layers + 3) & (~3); // round up to 32 bits ll.op_memset (ll.void_ptr(layer_run_ptr(0)), 0, sz, 4 /*align*/); } // Group entries also need to allot space for ALL layers' params // that are closures (to avoid weird order of layer eval problems). for (int i = 0; i < group().nlayers(); ++i) { ShaderInstance *gi = group()[i]; if (gi->unused()) continue; FOREACH_PARAM (Symbol &sym, gi) { if (sym.typespec().is_closure_based()) { int arraylen = std::max (1, sym.typespec().arraylength()); llvm::Value *val = ll.constant_ptr(NULL, ll.type_void_ptr()); for (int a = 0; a < arraylen; ++a) { llvm::Value *arrind = sym.typespec().is_array() ? ll.constant(a) : NULL; llvm_store_value (val, sym, 0, arrind, 0); } } } // Unconditionally execute earlier layers that are not lazy if (! gi->run_lazily() && i < group().nlayers()-1) llvm_call_layer (i, true /* unconditionally run */); } } // Setup the symbols m_named_values.clear (); BOOST_FOREACH (Symbol &s, inst()->symbols()) { // Skip constants -- we always inline scalar constants, and for // array constants we will just use the pointers to the copy of // the constant that belongs to the instance. if (s.symtype() == SymTypeConst) continue; // Skip structure placeholders if (s.typespec().is_structure()) continue; // Allocate space for locals, temps, aggregate constants if (s.symtype() == SymTypeLocal || s.symtype() == SymTypeTemp || s.symtype() == SymTypeConst) getOrAllocateLLVMSymbol (s); // Set initial value for constants, closures, and strings that are // not parameters. if (s.symtype() != SymTypeParam && s.symtype() != SymTypeOutputParam && s.symtype() != SymTypeGlobal && (s.is_constant() || s.typespec().is_closure_based() || s.typespec().is_string_based() || ((s.symtype() == SymTypeLocal || s.symtype() == SymTypeTemp) && shadingsys().debug_uninit()))) llvm_assign_initial_value (s); // If debugnan is turned on, globals check that their values are ok if (s.symtype() == SymTypeGlobal && shadingsys().debug_nan()) { TypeDesc t = s.typespec().simpletype(); if (t.basetype == TypeDesc::FLOAT) { // just check float-based types int ncomps = t.numelements() * t.aggregate; llvm::Value *args[] = { ll.constant(ncomps), llvm_void_ptr(s), ll.constant((int)s.has_derivs()), sg_void_ptr(), ll.constant(ustring(inst()->shadername())), ll.constant(0), ll.constant(s.name()), ll.constant(0), ll.constant(ncomps), ll.constant("<none>") }; ll.call_function ("osl_naninf_check", args, 10); } } } // make a second pass for the parameters (which may make use of // locals and constants from the first pass) FOREACH_PARAM (Symbol &s, inst()) { // Skip structure placeholders if (s.typespec().is_structure()) continue; // Skip if it's never read and isn't connected if (! s.everread() && ! s.connected_down() && ! s.connected() && ! shadingsys().is_renderer_output(s.name())) continue; // Set initial value for params (may contain init ops) llvm_assign_initial_value (s); } // All the symbols are stack allocated now. // Mark all the basic blocks, including allocating llvm::BasicBlock // records for each. find_basic_blocks (); find_conditionals (); m_layers_already_run.clear (); build_llvm_code (inst()->maincodebegin(), inst()->maincodeend()); if (llvm_has_exit_instance_block()) ll.op_branch (m_exit_instance_block); // also sets insert point // Transfer all of this layer's outputs into the downstream shader's // inputs. for (int layer = this->layer()+1; layer < group().nlayers(); ++layer) { ShaderInstance *child = group()[layer]; for (int c = 0; c < child->nconnections(); ++c) { const Connection &con (child->connection (c)); if (con.srclayer == this->layer()) { ASSERT (con.src.arrayindex == -1 && con.src.channel == -1 && con.dst.arrayindex == -1 && con.dst.channel == -1 && "no support for individual element/channel connection"); Symbol *srcsym (inst()->symbol (con.src.param)); Symbol *dstsym (child->symbol (con.dst.param)); llvm_run_connected_layers (*srcsym, con.src.param); // FIXME -- I'm not sure I understand this. Isn't this // unnecessary if we wrote to the parameter ourself? llvm_assign_impl (*dstsym, *srcsym); } } } // llvm_gen_debug_printf ("done copying connections"); // All done #if 0 /* helpful for debugging */ if (llvm_debug()) llvm_gen_debug_printf (Strutil::format("exit layer %s %s", inst()->layername(), inst()->shadername())); #endif ll.op_return(); if (llvm_debug()) std::cout << "layer_func (" << unique_layer_name << ") "<< this->layer() << "/" << group().nlayers() << " after llvm = " << ll.bitcode_string(ll.current_function()) << "\n"; ll.end_builder(); // clear the builder return ll.current_function(); }
llvm::Type * BackendLLVM::llvm_type_groupdata () { // If already computed, return it if (m_llvm_type_groupdata) return m_llvm_type_groupdata; std::vector<llvm::Type*> fields; int offset = 0; int order = 0; if (llvm_debug() >= 2) std::cout << "Group param struct:\n"; // First, add the array that tells if each layer has run. But only make // slots for the layers that may be called/used. if (llvm_debug() >= 2) std::cout << " layers run flags: " << m_num_used_layers << " at offset " << offset << "\n"; int sz = (m_num_used_layers + 3) & (~3); // Round up to 32 bit boundary fields.push_back (ll.type_array (ll.type_bool(), sz)); offset += sz * sizeof(bool); ++order; // Now add the array that tells which userdata have been initialized, // and the space for the userdata values. int nuserdata = (int) group().m_userdata_names.size(); if (nuserdata) { if (llvm_debug() >= 2) std::cout << " userdata initialized flags: " << nuserdata << " at offset " << offset << ", field " << order << "\n"; ustring *names = & group().m_userdata_names[0]; TypeDesc *types = & group().m_userdata_types[0]; int *offsets = & group().m_userdata_offsets[0]; int sz = (nuserdata + 3) & (~3); fields.push_back (ll.type_array (ll.type_bool(), sz)); offset += nuserdata * sizeof(bool); ++order; for (int i = 0; i < nuserdata; ++i) { TypeDesc type = types[i]; int n = type.numelements() * 3; // always make deriv room type.arraylen = n; fields.push_back (llvm_type (type)); // Alignment int align = type.basesize(); offset = OIIO::round_to_multiple_of_pow2 (offset, align); if (llvm_debug() >= 2) std::cout << " userdata " << names[i] << ' ' << type << ", field " << order << ", offset " << offset << "\n"; offsets[i] = offset; offset += int(type.size()); ++order; } } // For each layer in the group, add entries for all params that are // connected or interpolated, and output params. Also mark those // symbols with their offset within the group struct. m_param_order_map.clear (); for (int layer = 0; layer < group().nlayers(); ++layer) { ShaderInstance *inst = group()[layer]; if (inst->unused()) continue; FOREACH_PARAM (Symbol &sym, inst) { TypeSpec ts = sym.typespec(); if (ts.is_structure()) // skip the struct symbol itself continue; const int arraylen = std::max (1, sym.typespec().arraylength()); const int derivSize = (sym.has_derivs() ? 3 : 1); ts.make_array (arraylen * derivSize); fields.push_back (llvm_type (ts)); // Alignment size_t align = sym.typespec().is_closure_based() ? sizeof(void*) : sym.typespec().simpletype().basesize(); if (offset & (align-1)) offset += align - (offset & (align-1)); if (llvm_debug() >= 2) std::cout << " " << inst->layername() << " (" << inst->id() << ") " << sym.mangled() << " " << ts.c_str() << ", field " << order << ", size " << derivSize * int(sym.size()) << ", offset " << offset << std::endl; sym.dataoffset ((int)offset); offset += derivSize* int(sym.size()); m_param_order_map[&sym] = order; ++order; } }
llvm::Function* RuntimeOptimizer::build_llvm_instance (bool groupentry) { // Make a layer function: void layer_func(ShaderGlobals*, GroupData*) // Note that the GroupData* is passed as a void*. std::string unique_layer_name = Strutil::format ("%s_%d", inst()->layername().c_str(), inst()->id()); m_layer_func = llvm::cast<llvm::Function>(m_llvm_module->getOrInsertFunction(unique_layer_name, llvm_type_void(), llvm_type_sg_ptr(), llvm_type_groupdata_ptr(), NULL)); // Use fastcall for non-entry layer functions to encourage register calling if (!groupentry) m_layer_func->setCallingConv(llvm::CallingConv::Fast); llvm::Function::arg_iterator arg_it = m_layer_func->arg_begin(); // Get shader globals pointer m_llvm_shaderglobals_ptr = arg_it++; m_llvm_groupdata_ptr = arg_it++; llvm::BasicBlock *entry_bb = llvm_new_basic_block (unique_layer_name); // Set up a new IR builder delete m_builder; m_builder = new llvm::IRBuilder<> (entry_bb); // llvm_gen_debug_printf (std::string("enter layer ")+inst()->shadername()); if (groupentry) { if (m_num_used_layers > 1) { // If this is the group entry point, clear all the "layer // executed" bits. If it's not the group entry (but rather is // an upstream node), then set its bit! int sz = (m_num_used_layers + 3) & (~3); // round up to 32 bits llvm_memset (llvm_void_ptr(layer_run_ptr(0)), 0, sz, 4 /*align*/); } // Group entries also need to allot space for ALL layers' params // that are closures (to avoid weird order of layer eval problems). for (int i = 0; i < group().nlayers(); ++i) { ShaderInstance *gi = group()[i]; if (gi->unused()) continue; FOREACH_PARAM (Symbol &sym, gi) { if (sym.typespec().is_closure_based()) { int arraylen = std::max (1, sym.typespec().arraylength()); llvm::Value *val = llvm_constant_ptr(NULL, llvm_type_void_ptr()); for (int a = 0; a < arraylen; ++a) { llvm::Value *arrind = sym.typespec().is_array() ? llvm_constant(a) : NULL; llvm_store_value (val, sym, 0, arrind, 0); } } } // Unconditionally execute earlier layers that are not lazy if (! gi->run_lazily() && i < group().nlayers()-1) llvm_call_layer (i, true /* unconditionally run */); } } // Setup the symbols m_named_values.clear (); BOOST_FOREACH (Symbol &s, inst()->symbols()) { // Skip non-array constants -- we always inline them if (s.symtype() == SymTypeConst && !s.typespec().is_array()) continue; // Skip structure placeholders if (s.typespec().is_structure()) continue; // Allocate space for locals, temps, aggregate constants if (s.symtype() == SymTypeLocal || s.symtype() == SymTypeTemp || s.symtype() == SymTypeConst) getOrAllocateLLVMSymbol (s); // Set initial value for constants, closures, and strings that are // not parameters. if (s.symtype() != SymTypeParam && s.symtype() != SymTypeOutputParam && (s.is_constant() || s.typespec().is_closure_based() || s.typespec().is_string_based())) llvm_assign_initial_value (s); // If debugnan is turned on, globals check that their values are ok if (s.symtype() == SymTypeGlobal && m_shadingsys.debug_nan()) { TypeDesc t = s.typespec().simpletype(); if (t.basetype == TypeDesc::FLOAT) { // just check float-based types int ncomps = t.numelements() * t.aggregate; llvm::Value *args[] = { llvm_constant(ncomps), llvm_void_ptr(s), llvm_constant((int)s.has_derivs()), sg_void_ptr(), llvm_constant(ustring(inst()->shadername())), llvm_constant(0), llvm_constant(s.name()) }; llvm_call_function ("osl_naninf_check", args, 7); } } } // make a second pass for the parameters (which may make use of // locals and constants from the first pass) FOREACH_PARAM (Symbol &s, inst()) { // Skip structure placeholders if (s.typespec().is_structure()) continue; // Skip if it's never read and isn't connected if (! s.everread() && ! s.connected_down() && ! s.connected()) continue; // Set initial value for params (may contain init ops) llvm_assign_initial_value (s); } // All the symbols are stack allocated now. // Mark all the basic blocks, including allocating llvm::BasicBlock // records for each. find_basic_blocks (true); find_conditionals (); m_layers_already_run.clear (); build_llvm_code (inst()->maincodebegin(), inst()->maincodeend()); // Transfer all of this layer's outputs into the downstream shader's // inputs. for (int layer = m_layer+1; layer < group().nlayers(); ++layer) { ShaderInstance *child = m_group[layer]; for (int c = 0; c < child->nconnections(); ++c) { const Connection &con (child->connection (c)); if (con.srclayer == m_layer) { ASSERT (con.src.arrayindex == -1 && con.src.channel == -1 && con.dst.arrayindex == -1 && con.dst.channel == -1 && "no support for individual element/channel connection"); Symbol *srcsym (inst()->symbol (con.src.param)); Symbol *dstsym (child->symbol (con.dst.param)); llvm_run_connected_layers (*srcsym, con.src.param); // FIXME -- I'm not sure I understand this. Isn't this // unnecessary if we wrote to the parameter ourself? llvm_assign_impl (*dstsym, *srcsym); } } } // llvm_gen_debug_printf ("done copying connections"); // All done // llvm_gen_debug_printf (std::string("exit layer ")+inst()->shadername()); builder().CreateRetVoid(); if (shadingsys().llvm_debug()) llvm::outs() << "layer_func (" << unique_layer_name << ") after llvm = " << *m_layer_func << "\n"; delete m_builder; m_builder = NULL; return m_layer_func; }
void MaterialInstance::createForConfiguration (const std::string& configuration) { bool res = mMaterial->createConfiguration(configuration); if (!res) return; // listener was false positive if (mListener) mListener->requestedConfiguration (this, configuration); mFactory->setActiveConfiguration (configuration); bool allowFixedFunction = true; if (!mShadersEnabled && hasProperty("allow_fixed_function")) { allowFixedFunction = retrieveValue<BooleanValue>(getProperty("allow_fixed_function"), NULL).get(); } // get passes of the top-most parent PassVector passes = getPasses(); for (PassVector::iterator it = passes.begin(); it != passes.end(); ++it) { boost::shared_ptr<Pass> pass = mMaterial->createPass (configuration); it->copyAll (pass.get(), this); // texture samplers used in the shaders std::vector<std::string> usedTextureSamplersVertex; std::vector<std::string> usedTextureSamplersFragment; PropertySetGet* context = this; // create or retrieve shaders if (mShadersEnabled || !allowFixedFunction) { it->setContext(context); it->mShaderProperties.setContext(context); if (it->hasProperty("vertex_program")) { ShaderSet* vertex = mFactory->getShaderSet(retrieveValue<StringValue>(it->getProperty("vertex_program"), context).get()); ShaderInstance* v = vertex->getInstance(&it->mShaderProperties); if (v) { pass->assignProgram (GPT_Vertex, v->getName()); v->setUniformParameters (pass, &it->mShaderProperties); std::vector<std::string> sharedParams = v->getSharedParameters (); for (std::vector<std::string>::iterator it = sharedParams.begin(); it != sharedParams.end(); ++it) { pass->addSharedParameter (GPT_Vertex, *it); } std::vector<std::string> vector = v->getUsedSamplers (); usedTextureSamplersVertex.insert(usedTextureSamplersVertex.end(), vector.begin(), vector.end()); } } if (it->hasProperty("fragment_program")) { ShaderSet* fragment = mFactory->getShaderSet(retrieveValue<StringValue>(it->getProperty("fragment_program"), context).get()); ShaderInstance* f = fragment->getInstance(&it->mShaderProperties); if (f) { pass->assignProgram (GPT_Fragment, f->getName()); f->setUniformParameters (pass, &it->mShaderProperties); std::vector<std::string> sharedParams = f->getSharedParameters (); for (std::vector<std::string>::iterator it = sharedParams.begin(); it != sharedParams.end(); ++it) { pass->addSharedParameter (GPT_Fragment, *it); } std::vector<std::string> vector = f->getUsedSamplers (); usedTextureSamplersFragment.insert(usedTextureSamplersFragment.end(), vector.begin(), vector.end()); } } } // create texture units std::vector<MaterialInstanceTextureUnit> texUnits = it->getTexUnits(); int i=0; for (std::vector<MaterialInstanceTextureUnit>::iterator texIt = texUnits.begin(); texIt != texUnits.end(); ++texIt ) { // only create those that are needed by the shader, OR those marked to be created in fixed function pipeline if shaders are disabled bool foundVertex = std::find(usedTextureSamplersVertex.begin(), usedTextureSamplersVertex.end(), texIt->getName()) != usedTextureSamplersVertex.end(); bool foundFragment = std::find(usedTextureSamplersFragment.begin(), usedTextureSamplersFragment.end(), texIt->getName()) != usedTextureSamplersFragment.end(); if ( (foundVertex || foundFragment) || ((!mShadersEnabled && allowFixedFunction) && texIt->hasProperty("create_in_ffp") && retrieveValue<BooleanValue>(texIt->getProperty("create_in_ffp"), this).get())) { boost::shared_ptr<TextureUnitState> texUnit = pass->createTextureUnitState (); texIt->copyAll (texUnit.get(), context); mTexUnits.push_back(texUnit); // set texture unit indices (required by GLSL) if (mShadersEnabled && mFactory->getCurrentLanguage () == Language_GLSL) { pass->setTextureUnitIndex (foundVertex ? GPT_Vertex : GPT_Fragment, texIt->getName(), i); ++i; } } } } }
bool MaterialInstance::createForConfiguration (const std::string& configuration, unsigned short lodIndex) { if (mFailedToCreate) return false; try{ mMaterial->ensureLoaded(); bool res = mMaterial->createConfiguration(configuration, lodIndex); if (!res) return false; // listener was false positive if (mListener) mListener->requestedConfiguration (this, configuration); mFactory->setActiveConfiguration (configuration); mFactory->setActiveLodLevel (lodIndex); bool allowFixedFunction = true; if (!mShadersEnabled && hasProperty("allow_fixed_function")) { allowFixedFunction = retrieveValue<BooleanValue>(getProperty("allow_fixed_function"), NULL).get(); } bool useShaders = mShadersEnabled || !allowFixedFunction; // get passes of the top-most parent PassVector* passes = getParentPasses(); if (passes->empty()) throw std::runtime_error ("material \"" + mName + "\" does not have any passes"); for (PassVector::iterator it = passes->begin(); it != passes->end(); ++it) { boost::shared_ptr<Pass> pass = mMaterial->createPass (configuration, lodIndex); it->copyAll (pass.get(), this); // texture samplers used in the shaders std::vector<std::string> usedTextureSamplersVertex; std::vector<std::string> usedTextureSamplersFragment; PropertySetGet* context = this; // create or retrieve shaders bool hasVertex = it->hasProperty("vertex_program") && !retrieveValue<StringValue>(it->getProperty("vertex_program"), context).get().empty(); bool hasFragment = it->hasProperty("fragment_program") && !retrieveValue<StringValue>(it->getProperty("fragment_program"), context).get().empty(); if (useShaders) { it->setContext(context); it->mShaderProperties.setContext(context); if (hasVertex) { ShaderSet* vertex = mFactory->getShaderSet(retrieveValue<StringValue>(it->getProperty("vertex_program"), context).get()); ShaderInstance* v = vertex->getInstance(&it->mShaderProperties); if (v) { pass->assignProgram (GPT_Vertex, v->getName()); v->setUniformParameters (pass, &it->mShaderProperties); std::vector<std::string> sharedParams = v->getSharedParameters (); for (std::vector<std::string>::iterator it2 = sharedParams.begin(); it2 != sharedParams.end(); ++it2) { pass->addSharedParameter (GPT_Vertex, *it2); } std::vector<std::string> vector = v->getUsedSamplers (); usedTextureSamplersVertex.insert(usedTextureSamplersVertex.end(), vector.begin(), vector.end()); } } if (hasFragment) { ShaderSet* fragment = mFactory->getShaderSet(retrieveValue<StringValue>(it->getProperty("fragment_program"), context).get()); ShaderInstance* f = fragment->getInstance(&it->mShaderProperties); if (f) { pass->assignProgram (GPT_Fragment, f->getName()); f->setUniformParameters (pass, &it->mShaderProperties); std::vector<std::string> sharedParams = f->getSharedParameters (); for (std::vector<std::string>::iterator it2 = sharedParams.begin(); it2 != sharedParams.end(); ++it2) { pass->addSharedParameter (GPT_Fragment, *it2); } std::vector<std::string> vector = f->getUsedSamplers (); usedTextureSamplersFragment.insert(usedTextureSamplersFragment.end(), vector.begin(), vector.end()); } } } // create texture units std::vector<MaterialInstanceTextureUnit>* texUnits = &it->mTexUnits; int i=0; for (std::vector<MaterialInstanceTextureUnit>::iterator texIt = texUnits->begin(); texIt != texUnits->end(); ++texIt ) { // only create those that are needed by the shader, OR those marked to be created in fixed function pipeline if shaders are disabled bool foundVertex = std::find(usedTextureSamplersVertex.begin(), usedTextureSamplersVertex.end(), texIt->getName()) != usedTextureSamplersVertex.end(); bool foundFragment = std::find(usedTextureSamplersFragment.begin(), usedTextureSamplersFragment.end(), texIt->getName()) != usedTextureSamplersFragment.end(); if ( (foundVertex || foundFragment) || (((!useShaders || (!hasVertex || !hasFragment)) && allowFixedFunction) && texIt->hasProperty("create_in_ffp") && retrieveValue<BooleanValue>(texIt->getProperty("create_in_ffp"), this).get())) { boost::shared_ptr<TextureUnitState> texUnit = pass->createTextureUnitState (texIt->getName()); texIt->copyAll (texUnit.get(), context); mTexUnits.push_back(texUnit); // set texture unit indices (required by GLSL) if (useShaders && ((hasVertex && foundVertex) || (hasFragment && foundFragment)) && mFactory->getCurrentLanguage () == Language_GLSL) { pass->setTextureUnitIndex (foundVertex ? GPT_Vertex : GPT_Fragment, texIt->getName(), i); ++i; } } } } if (mListener) mListener->createdConfiguration (this, configuration); return true; } catch (std::runtime_error& e) { destroyAll(); mFailedToCreate = true; std::stringstream msg; msg << "Error while creating material " << mName << ": " << e.what(); std::cerr << msg.str() << std::endl; mFactory->logError(msg.str()); return false; } }