Ejemplo n.º 1
0
void
OSOReaderToMaster::symbol (SymType symtype, TypeSpec typespec, const char *name_)
{
    ustring name(name_);
    Symbol sym (name, typespec, symtype);
    TypeDesc t = typespec.simpletype();
    int nvals = t.aggregate * (t.is_unsized_array() ? 1 : t.numelements());
    if (sym.symtype() == SymTypeParam || sym.symtype() == SymTypeOutputParam) {
        // Skip structs for now, they're just placeholders
        if (typespec.is_structure()) {
        }
        else if (typespec.simpletype().basetype == TypeDesc::FLOAT) {
            sym.dataoffset ((int) m_master->m_fdefaults.size());
            expand (m_master->m_fdefaults, nvals);
        } else if (typespec.simpletype().basetype == TypeDesc::INT) {
            sym.dataoffset ((int) m_master->m_idefaults.size());
            expand (m_master->m_idefaults, nvals);
        } else if (typespec.simpletype().basetype == TypeDesc::STRING) {
            sym.dataoffset ((int) m_master->m_sdefaults.size());
            expand (m_master->m_sdefaults, nvals);
        } else if (typespec.is_closure_based()) {
            // Closures are pointers, so we allocate a string default taking
            // adventage of their default being NULL as well.
            sym.dataoffset ((int) m_master->m_sdefaults.size());
            expand (m_master->m_sdefaults, nvals);
        } else {
            ASSERT (0 && "unexpected type");
        }
    }
    if (sym.symtype() == SymTypeConst) {
        if (typespec.simpletype().basetype == TypeDesc::FLOAT) {
            sym.dataoffset ((int) m_master->m_fconsts.size());
            expand (m_master->m_fconsts, nvals);
        } else if (typespec.simpletype().basetype == TypeDesc::INT) {
            sym.dataoffset ((int) m_master->m_iconsts.size());
            expand (m_master->m_iconsts, nvals);
        } else if (typespec.simpletype().basetype == TypeDesc::STRING) {
            sym.dataoffset ((int) m_master->m_sconsts.size());
            expand (m_master->m_sconsts, nvals);
        } else {
            ASSERT (0 && "unexpected type");
        }
    }
#if 0
    // FIXME -- global_heap_offset is quite broken.  But also not necessary.
    // We made need to fix this later.
    if (sym.symtype() == SymTypeGlobal) {
        sym.dataoffset (m_shadingsys.global_heap_offset (sym.name()));
    }
#endif
    sym.lockgeom (m_shadingsys.lockgeom_default());
    m_master->m_symbols.push_back (sym);
    m_symmap[name] = int(m_master->m_symbols.size()) - 1;
    // Start the index at which we add specified defaults
    m_sym_default_index = 0;
}
Ejemplo n.º 2
0
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->dataoffset (m_instoverrides[i].dataoffset());
                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.º 3
0
void
ShaderInstance::parameters (const ParamValueList &params)
{
    // Seed the params with the master's defaults
    m_iparams = m_master->m_idefaults;
    m_fparams = m_master->m_fdefaults;
    m_sparams = m_master->m_sdefaults;

    m_instoverrides.resize (std::max (0, lastparam()));

    // Set the initial lockgeom and dataoffset on the instoverrides, based
    // on the master.
    for (int i = 0, e = (int)m_instoverrides.size(); i < e; ++i) {
        Symbol *sym = master()->symbol(i);
        m_instoverrides[i].lockgeom (sym->lockgeom());
        m_instoverrides[i].dataoffset (sym->dataoffset());
    }

    for (auto&& p : params) {
        if (p.name().size() == 0)
            continue;   // skip empty names
        int i = findparam (p.name());
        if (i >= 0) {
            // if (shadingsys().debug())
            //     shadingsys().info (" PARAMETER %s %s", p.name(), p.type());
            const Symbol *sm = master()->symbol(i);    // This sym in the master
            SymOverrideInfo *so = &m_instoverrides[i]; // Slot for sym's override info
            TypeSpec sm_typespec = sm->typespec(); // Type of the master's param
            if (sm_typespec.is_closure_based()) {
                // Can't assign a closure instance value.
                shadingsys().warning ("skipping assignment of closure: %s", sm->name());
                continue;
            }
            if (sm_typespec.is_structure())
                continue;    // structs are just placeholders; skip

            const void *data = p.data();
            float tmpdata[3]; // used for inline conversions to float/float[3]

            // Check type of parameter and matching symbol. Note that the
            // compatible accounts for indefinite-length arrays.
            TypeDesc paramtype = sm_typespec.simpletype();  // what the shader writer wants
            TypeDesc valuetype = p.type();                  // what the data provided actually is

            if (master()->shadingsys().relaxed_param_typecheck()) {
                // first handle cases where we actually need to modify the data (like setting a float parameter with an int)
                 if ((paramtype == TypeDesc::FLOAT || paramtype.is_vec3()) && valuetype.basetype == TypeDesc::INT && valuetype.basevalues() == 1) {
                    int val = *static_cast<const int*>(p.data());
                    float conv = float(val);
                    if (val != int(conv))
                        shadingsys().error ("attempting to set parameter from wrong type would change the value: %s (set %.9g from %d)",
                            sm->name(), conv, val);
                    tmpdata[0] = conv;
                    data = tmpdata;
                    valuetype = TypeDesc::FLOAT;
                }

                // Relaxed rules just look to see that the types are isomorphic to each other (ie: same number of base values)
                // Note that:
                //   * basetypes must match exactly (int vs float vs string)
                //   * valuetype cannot be unsized (we must know the concrete number of values)
                //   * if paramtype is sized (or not an array) just check for the total number of entries
                //   * if paramtype is unsized (shader writer is flexible about how many values come in) -- make sure we are a multiple of the target type
                //   * allow a single float setting a vec3 (or equivalent)
                if (!( valuetype.basetype == paramtype.basetype &&
                      !valuetype.is_unsized_array() &&
                      ((!paramtype.is_unsized_array() && valuetype.basevalues() == paramtype.basevalues()) ||
                       ( paramtype.is_unsized_array() && valuetype.basevalues() % paramtype.aggregate == 0) ||
                       ( paramtype.is_vec3()          && valuetype == TypeDesc::FLOAT) ) )) {
                    // We are being very relaxed in this mode, so if the user _still_ got it wrong
                    // something more serious is at play and we should treat it as an error.
                    shadingsys().error ("attempting to set parameter from incompatible type: %s (expected '%s', received '%s')",
                                          sm->name(), paramtype, valuetype);
                    continue;
                }
            } else if (!compatible_param(paramtype, valuetype)) {
                shadingsys().warning ("attempting to set parameter with wrong type: %s (expected '%s', received '%s')",
                                      sm->name(), paramtype, valuetype);
                continue;
            }

            // Mark that the override as an instance value
            so->valuesource (Symbol::InstanceVal);

            // Lock the param against geometric primitive overrides if the
            // master thinks it was so locked, AND the Parameter() call
            // didn't specify lockgeom=false (which would be indicated by
            // the parameter's interpolation being non-CONSTANT).
            bool lockgeom = (sm->lockgeom() &&
                             p.interp() == ParamValue::INTERP_CONSTANT);
            so->lockgeom (lockgeom);

            DASSERT (so->dataoffset() == sm->dataoffset());
            so->dataoffset (sm->dataoffset());

            if (paramtype.is_vec3() && valuetype == TypeDesc::FLOAT) {
                // Handle the special case of assigning a float for a triple
                // by replicating it into local memory.
                tmpdata[0] = *(const float *)data;
                tmpdata[1] = *(const float *)data;
                tmpdata[2] = *(const float *)data;
                data = &tmpdata;
                valuetype = paramtype;
            }

            if (paramtype.arraylen < 0) {
                // An array of definite size was supplied to a parameter
                // that was an array of indefinite size. Magic! The trick
                // here is that we need to allocate paramter space at the
                // END of the ordinary param storage, since when we assigned
                // data offsets to each parameter, we didn't know the length
                // needed to allocate this param in its proper spot.
                int nelements = valuetype.basevalues();
                // Store the actual length in the shader instance parameter
                // override info. Compute the length this way to account for relaxed
                // parameter checking (for example passing an array of floats to an array of colors)
                so->arraylen (nelements / paramtype.aggregate);
                // Allocate space for the new param size at the end of its
                // usual parameter area, and set the new dataoffset to that
                // position.
                if (paramtype.basetype == TypeDesc::FLOAT) {
                    so->dataoffset((int) m_fparams.size());
                    expand (m_fparams, nelements);
                } else if (paramtype.basetype == TypeDesc::INT) {
                    so->dataoffset((int) m_iparams.size());
                    expand (m_iparams, nelements);
                } else if (paramtype.basetype == TypeDesc::STRING) {
                    so->dataoffset((int) m_sparams.size());
                    expand (m_sparams, nelements);
                } else {
                    ASSERT (0 && "unexpected type");
                }
                // FIXME: There's a tricky case that we overlook here, where
                // an indefinite-length-array parameter is given DIFFERENT
                // definite length in subsequent rerenders. Don't do that.
            }
            else {
                // If the instance value is the same as the master's default,
                // just skip the parameter, let it "keep" the default.
                // Note that this can't/shouldn't happen for the indefinite-
                // sized array case, which is why we have it in the 'else'
                // clause of that test.
                void *defaultdata = m_master->param_default_storage(i);
                if (lockgeom &&
                      memcmp (defaultdata, data, valuetype.size()) == 0) {
                    // Must reset valuesource to default, in case the parameter
                    // was set already, and now is being changed back to default.
                    so->valuesource (Symbol::DefaultVal);
                }
            }

            // Copy the supplied data into place.
            memcpy (param_storage(i), data, valuetype.size());
        }
        else {
            shadingsys().warning ("attempting to set nonexistent parameter: %s", p.name());
        }
    }

    {
        // Adjust the stats
        ShadingSystemImpl &ss (shadingsys());
        size_t symmem = vectorbytes(m_instoverrides);
        size_t parammem = (vectorbytes(m_iparams) + vectorbytes(m_fparams) +
                           vectorbytes(m_sparams));
        spin_lock lock (ss.m_stat_mutex);
        ss.m_stat_mem_inst_syms += symmem;
        ss.m_stat_mem_inst_paramvals += parammem;
        ss.m_stat_mem_inst += (symmem+parammem);
        ss.m_stat_memory += (symmem+parammem);
    }
}