Ejemplo n.º 1
0
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;
    // We already have the symbols on [0,lastparam).  Now copy the rest.
    off_t symmem = vectorbytes(m_instsymbols);
    ASSERT (m_master->m_lastparam < 0 ||
            m_instsymbols.size() == (size_t)m_master->m_lastparam);
    ASSERT (m_instsymbols.size() <= m_master->m_symbols.size());
    m_instsymbols.reserve (m_master->m_symbols.size());
    for (size_t i = m_instsymbols.size(), e = m_master->m_symbols.size();
         i < e;  ++i)
        m_instsymbols.push_back (m_master->m_symbols[i]);
    ASSERT (m_instsymbols.size() == m_master->m_symbols.size());

    // adjust stats
    symmem = vectorbytes(m_instsymbols) - symmem;  // just the new mem
    {
        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;
    }
}
Ejemplo n.º 2
0
void
ShadingContext::process_errors () const
{
    size_t nerrors = m_buffered_errors.size();
    if (! nerrors)
        return;

    // Use a mutex to make sure output from different threads stays
    // together, at least for one shader invocation, rather than being
    // interleaved with other threads.
    lock_guard lock (buffered_errors_mutex);

    for (size_t i = 0;  i < nerrors;  ++i) {
        switch (m_buffered_errors[i].first) {
        case ErrorHandler::EH_MESSAGE :
        case ErrorHandler::EH_DEBUG :
           shadingsys().message (m_buffered_errors[i].second);
            break;
        case ErrorHandler::EH_INFO :
            shadingsys().info (m_buffered_errors[i].second);
            break;
        case ErrorHandler::EH_WARNING :
            shadingsys().warning (m_buffered_errors[i].second);
            break;
        case ErrorHandler::EH_ERROR :
        case ErrorHandler::EH_SEVERE :
            shadingsys().error (m_buffered_errors[i].second);
            break;
        default:
            break;
        }
    }
    m_buffered_errors.clear();
}
void
ShaderInstance::compute_run_lazily (const ShaderGroup &group)
{
    if (shadingsys().m_lazylayers) {
        // lazylayers option turned on: unconditionally run shaders with no
        // outgoing connections ("root" nodes, including the last in the
        // group) or shaders that alter global variables (unless
        // 'lazyglobals' is turned on).
        if (shadingsys().m_lazyglobals) {
            if (group[group.nlayers()-1] == this)
                run_lazily (false);  // force run of last group
            else
                run_lazily ((outgoing_connections() && ! renderer_outputs())
                            || empty_instance() || merged_unused());
        }
        else
            run_lazily (outgoing_connections() && ! writes_globals()
                        && ! renderer_outputs());
#if 0
        // Suggested warning below... but are there use cases where people
        // want these to run (because they will extract the results they
        // want from output params)?
        if (! outgoing_connections() && ! empty_instance() &&
                ! writes_globals() && ! renderer_outputs())
            shadingsys().warning ("Layer \"%s\" (shader %s) will run even though it appears to have no used results",
                                  layername(), shadername());
#endif
    } else {
        // lazylayers option turned off: never run lazily
        run_lazily (false);
    }
}
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;
    }
}
Ejemplo n.º 5
0
void
ShaderInstance::add_connection (int srclayer, const ConnectedParam &srccon,
                                const ConnectedParam &dstcon)
{
    off_t oldmem = vectorbytes(m_connections);
    m_connections.push_back (Connection (srclayer, srccon, dstcon));

    // adjust stats
    off_t mem = vectorbytes(m_connections) - oldmem;
    {
        spin_lock lock (shadingsys().m_stat_mutex);
        shadingsys().m_stat_mem_inst_connections += mem;
        shadingsys().m_stat_mem_inst += mem;
        shadingsys().m_stat_memory += mem;
    }
}
Ejemplo n.º 6
0
int
ShadingContext::dict_find (int nodeID, ustring query)
{
    if (! m_dictionary) {
        m_dictionary = new Dictionary (shadingsys());
    }
    return m_dictionary->dict_find (nodeID, query);
}
Ejemplo n.º 7
0
int
ShadingContext::dict_find (ustring dictionaryname, ustring query)
{
    if (! m_dictionary) {
        m_dictionary = new Dictionary (shadingsys());
    }
    return m_dictionary->dict_find (dictionaryname, query);
}
Ejemplo n.º 8
0
void
ShadingContext::record_error (ErrorHandler::ErrCode code,
                              const std::string &text) const
{
    m_buffered_errors.push_back (ErrorItem(code,text));
    // If we aren't buffering, just process immediately
    if (! shadingsys().m_buffer_printf)
        process_errors ();
}
void
ShaderInstance::add_connection (int srclayer, const ConnectedParam &srccon,
                                const ConnectedParam &dstcon)
{
    // specialize symbol in case of dstcon is an unsized array
    if (dstcon.type.is_unsized_array()) {
        SymOverrideInfo *so = &m_instoverrides[dstcon.param];
        so->arraylen(srccon.type.arraylength());

        const TypeDesc& type = srccon.type.simpletype();
        // Skip structs for now, they're just placeholders
        /*if      (t.is_structure()) {
        }
        else*/ if (type.basetype == TypeDesc::FLOAT) {
            so->dataoffset((int) m_fparams.size());
            expand (m_fparams,type.size());
        } else if (type.basetype == TypeDesc::INT) {
            so->dataoffset((int) m_iparams.size());
            expand (m_iparams, type.size());
        } else if (type.basetype == TypeDesc::STRING) {
            so->dataoffset((int) m_sparams.size());
            expand (m_sparams, type.size());
        }/* else if (t.is_closure()) {
            // Closures are pointers, so we allocate a string default taking
            // adventage of their default being NULL as well.
            so->dataoffset((int) m_sparams.size());
            expand (m_sparams, type.size());
        }*/ else {
            ASSERT (0 && "unexpected type");
        }
    }

    off_t oldmem = vectorbytes(m_connections);
    m_connections.push_back (Connection (srclayer, srccon, dstcon));

    // adjust stats
    off_t mem = vectorbytes(m_connections) - oldmem;
    {
        spin_lock lock (shadingsys().m_stat_mutex);
        shadingsys().m_stat_mem_inst_connections += mem;
        shadingsys().m_stat_mem_inst += mem;
        shadingsys().m_stat_memory += mem;
    }
}
Ejemplo n.º 10
0
void
ShaderInstance::make_symbol_room (size_t moresyms)
{
    size_t oldsize = m_instsymbols.capacity();
    if (oldsize < m_instsymbols.size()+moresyms) {
        // Allocate a bit more than we need, so that most times we don't
        // need to reallocate.  But don't be wasteful by doubling or
        // anything like that, since we only expect a few to be added.
        const size_t extra_room = 10;
        size_t newsize = m_instsymbols.size() + moresyms + extra_room;
        m_instsymbols.reserve (newsize);

        // adjust stats
        spin_lock lock (shadingsys().m_stat_mutex);
        size_t mem = (newsize-oldsize) * sizeof(Symbol);
        shadingsys().m_stat_mem_inst_syms += mem;
        shadingsys().m_stat_mem_inst += mem;
        shadingsys().m_stat_memory += mem;
    }
}
Ejemplo n.º 11
0
bool
ShadingContext::execute (ShaderUse use, ShaderGroup &sgroup,
                         ShaderGlobals &ssg, bool run)
{
    DASSERT (use == ShadUseSurface);  // FIXME
    m_curuse = use;
    m_attribs = &sgroup;

    // Optimize if we haven't already
    if (sgroup.nlayers()) {
        sgroup.start_running ();
        if (! sgroup.optimized()) {
            shadingsys().optimize_group (sgroup);
            if (shadingsys().m_greedyjit && shadingsys().m_groups_to_compile_count) {
                // If we are greedily JITing, optimize/JIT everything now
                shadingsys().optimize_all_groups ();
            }
        }
        if (sgroup.does_nothing())
            return false;
    } else {
       // empty shader - nothing to do!
       return false;
    }

    // Allocate enough space on the heap
    size_t heap_size_needed = sgroup.llvm_groupdata_size();
    if (heap_size_needed > m_heap.size()) {
        if (shadingsys().debug())
            shadingsys().info ("  ShadingContext %p growing heap to %llu",
                               this, (unsigned long long) heap_size_needed);
        m_heap.resize (heap_size_needed);
    }
    // Zero out the heap memory we will be using
    if (shadingsys().m_clearmemory)
        memset (&m_heap[0], 0, heap_size_needed);

    // Set up closure storage
    m_closure_pool.clear();

    // Clear the message blackboard
    m_messages.clear ();

    // Clear miscellaneous scratch space
    m_scratch_pool.clear ();

    if (run) {
        ssg.context = this;
        ssg.Ci = NULL;
        RunLLVMGroupFunc run_func = sgroup.llvm_compiled_version();
        DASSERT (run_func);
        DASSERT (sgroup.llvm_groupdata_size() <= m_heap.size());
        run_func (&ssg, &m_heap[0]);
    }
    return true;
}
Ejemplo n.º 12
0
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;
    }
}
Ejemplo n.º 13
0
bool
ShadingContext::osl_get_attribute (ShaderGlobals *sg, void *objdata,
                                   int dest_derivs,
                                   ustring obj_name, ustring attr_name,
                                   int array_lookup, int index,
                                   TypeDesc attr_type, void *attr_dest)
{
#if 0
    // Change the #if's below if you want to
    OIIO::Timer timer;
#endif
    bool ok;

    for (int i = 0;  i < FAILED_ATTRIBS;  ++i) {
        if ((obj_name || m_failed_attribs[i].objdata == objdata) &&
            m_failed_attribs[i].attr_name == attr_name &&
            m_failed_attribs[i].obj_name == obj_name &&
            m_failed_attribs[i].attr_type == attr_type &&
            m_failed_attribs[i].array_lookup == array_lookup &&
            m_failed_attribs[i].index == index &&
            m_failed_attribs[i].objdata) {
#if 0
            double time = timer();
            shadingsys().m_stat_getattribute_time += time;
            shadingsys().m_stat_getattribute_fail_time += time;
            shadingsys().m_stat_getattribute_calls += 1;
#endif
            return false;
        }
    }

    if (array_lookup)
        ok = renderer()->get_array_attribute (sg, dest_derivs,
                                              obj_name, attr_type,
                                              attr_name, index, attr_dest);
    else
        ok = renderer()->get_attribute (sg, dest_derivs,
                                        obj_name, attr_type,
                                        attr_name, attr_dest);
    if (!ok) {
        int i = m_next_failed_attrib;
        m_failed_attribs[i].objdata = objdata;
        m_failed_attribs[i].obj_name = obj_name;
        m_failed_attribs[i].attr_name = attr_name;
        m_failed_attribs[i].attr_type = attr_type;
        m_failed_attribs[i].array_lookup = array_lookup;
        m_failed_attribs[i].index = index;
        m_next_failed_attrib = (i == FAILED_ATTRIBS-1) ? 0 : (i+1);
    }

#if 0
    double time = timer();
    shadingsys().m_stat_getattribute_time += time;
    if (!ok)
        shadingsys().m_stat_getattribute_fail_time += time;
    shadingsys().m_stat_getattribute_calls += 1;
#endif
//    std::cout << "getattribute! '" << obj_name << "' " << attr_name << ' ' << attr_type.c_str() << " ok=" << ok << ", objdata was " << objdata << "\n";
    return ok;
}
Ejemplo n.º 14
0
ShaderMaster::~ShaderMaster ()
{
    // Adjust statistics
    size_t opmem = vectorbytes (m_ops);
    size_t argmem = vectorbytes (m_args);
    size_t symmem = vectorbytes (m_symbols);
    size_t defaultmem = vectorbytes (m_idefaults) 
        + vectorbytes (m_fdefaults) + vectorbytes (m_sdefaults);
    size_t constmem = vectorbytes (m_iconsts)
        + vectorbytes (m_fconsts) + vectorbytes (m_sconsts);
    size_t totalmem = (opmem + argmem + symmem + defaultmem +
                       constmem + sizeof(ShaderMaster));
    {
        ShadingSystemImpl &ss (shadingsys());
        OIIO::spin_lock lock (ss.m_stat_mutex);
        ss.m_stat_mem_master_ops -= opmem;
        ss.m_stat_mem_master_args -= argmem;
        ss.m_stat_mem_master_syms -= symmem;
        ss.m_stat_mem_master_defaults -= defaultmem;
        ss.m_stat_mem_master_consts -= constmem;
        ss.m_stat_mem_master -= totalmem;
        ss.m_stat_memory -= totalmem;
    }
}
Ejemplo n.º 15
0
bool
ShadingContext::execute (ShaderGroup &sgroup, ShaderGlobals &ssg, bool run)
{
    m_attribs = &sgroup;

    // Optimize if we haven't already
    if (sgroup.nlayers()) {
        sgroup.start_running ();
        if (! sgroup.optimized()) {
            shadingsys().optimize_group (sgroup);
            if (shadingsys().m_greedyjit && shadingsys().m_groups_to_compile_count) {
                // If we are greedily JITing, optimize/JIT everything now
                shadingsys().optimize_all_groups ();
            }
        }
        if (sgroup.does_nothing())
            return false;
    } else {
       // empty shader - nothing to do!
       return false;
    }

    int profile = shadingsys().m_profile;
    OIIO::Timer timer (profile);

    // Allocate enough space on the heap
    size_t heap_size_needed = sgroup.llvm_groupdata_size();
    if (heap_size_needed > m_heap.size()) {
        if (shadingsys().debug())
            info ("  ShadingContext %p growing heap to %llu",
                  this, (unsigned long long) heap_size_needed);
        m_heap.resize (heap_size_needed);
    }
    // Zero out the heap memory we will be using
    if (shadingsys().m_clearmemory)
        memset (&m_heap[0], 0, heap_size_needed);

    // Set up closure storage
    m_closure_pool.clear();

    // Clear the message blackboard
    m_messages.clear ();

    // Clear miscellaneous scratch space
    m_scratch_pool.clear ();

    if (run) {
        ssg.context = this;
        ssg.renderer = renderer();
        ssg.Ci = NULL;
        RunLLVMGroupFunc run_func = sgroup.llvm_compiled_version();
        DASSERT (run_func);
        DASSERT (sgroup.llvm_groupdata_size() <= m_heap.size());
        run_func (&ssg, &m_heap[0]);
    }

    // Process any queued up error messages, warnings, printfs from shaders
    process_errors ();

    if (profile) {
        long long ticks = timer.ticks();
        shadingsys().m_stat_total_shading_time_ticks += ticks;
        sgroup.m_stat_total_shading_time_ticks += ticks;
    }

    return true;
}
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
                const Symbol *bsym = b.mastersymbol(i);
                if (! sym->everused_in_group() && ! bsym->everused_in_group())
                    continue;
                return false;
            }
            // But still, if they differ in their lockgeom'edness, we can't
            // merge the instances.
            if (m_instoverrides[i].lockgeom() != b.m_instoverrides[i].lockgeom()) {
                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 in the master.
    for (int i = firstparam();  i < lastparam();  ++i) {
        const Symbol *sym = optimized ? symbol(i) : mastersymbol(i);
        if (! sym->everused_in_group())
            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;
    }

    // Make sure system didn't ask for instances that query userdata to be
    // immune from instance merging.
    if (! shadingsys().m_opt_merge_instances_with_userdata
            && (userdata_params() || b.userdata_params())) {
        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;
}