void ShaderInstance::copy_code_from_master (ShaderGroup &group) { ASSERT (m_instops.empty() && m_instargs.empty()); // reserve with enough room for a few insertions m_instops.reserve (master()->m_ops.size()+10); m_instargs.reserve (master()->m_args.size()+10); m_instops = master()->m_ops; m_instargs = master()->m_args; // Copy the symbols from the master ASSERT (m_instsymbols.size() == 0 && "should not have copied m_instsymbols yet"); m_instsymbols = m_master->m_symbols; // Copy the instance override data // Also set the renderer_output flags where needed. ASSERT (m_instoverrides.size() == (size_t)std::max(0,lastparam())); ASSERT (m_instsymbols.size() >= (size_t)std::max(0,lastparam())); if (m_instoverrides.size()) { for (size_t i = 0, e = lastparam(); i < e; ++i) { Symbol *si = &m_instsymbols[i]; if (m_instoverrides[i].valuesource() == Symbol::DefaultVal) { // Fix the length of any default-value variable length array // parameters. if (si->typespec().is_unsized_array()) si->arraylen (si->initializers()); } else { if (m_instoverrides[i].arraylen()) si->arraylen (m_instoverrides[i].arraylen()); si->valuesource (m_instoverrides[i].valuesource()); si->connected_down (m_instoverrides[i].connected_down()); si->lockgeom (m_instoverrides[i].lockgeom()); si->data (param_storage(i)); } if (shadingsys().is_renderer_output (layername(), si->name(), &group)) { si->renderer_output (true); renderer_outputs (true); } } } evaluate_writes_globals_and_userdata_params (); off_t symmem = vectorbytes(m_instsymbols) - vectorbytes(m_instoverrides); SymOverrideInfoVec().swap (m_instoverrides); // free it // adjust stats { spin_lock lock (shadingsys().m_stat_mutex); shadingsys().m_stat_mem_inst_syms += symmem; shadingsys().m_stat_mem_inst += symmem; shadingsys().m_stat_memory += symmem; } }
void ShaderInstance::copy_code_from_master () { ASSERT (m_instops.empty() && m_instargs.empty()); // reserve with enough room for a few insertions m_instops.reserve (master()->m_ops.size()+10); m_instargs.reserve (master()->m_args.size()+10); m_instops = master()->m_ops; m_instargs = master()->m_args; // Copy the symbols from the master ASSERT (m_instsymbols.size() == 0 && "should not have copied m_instsymbols yet"); m_instsymbols = m_master->m_symbols; // Copy the instance override data ASSERT (m_instoverrides.size() == (size_t)std::max(0,lastparam())); ASSERT (m_instsymbols.size() >= (size_t)std::max(0,lastparam())); if (m_instoverrides.size()) { for (size_t i = 0, e = lastparam(); i < e; ++i) { if (m_instoverrides[i].valuesource() != Symbol::DefaultVal) { Symbol *si = &m_instsymbols[i]; si->data (param_storage(i)); si->valuesource (m_instoverrides[i].valuesource()); si->connected_down (m_instoverrides[i].connected_down()); si->lockgeom (m_instoverrides[i].lockgeom()); } } } off_t symmem = vectorbytes(m_instsymbols) - vectorbytes(m_instoverrides); SymOverrideInfoVec().swap (m_instoverrides); // free it // adjust stats { spin_lock lock (shadingsys().m_stat_mutex); shadingsys().m_stat_mem_inst_syms += symmem; shadingsys().m_stat_mem_inst += symmem; shadingsys().m_stat_memory += symmem; } }
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; }