Skip to content
Commits on Apr 14, 2016
  1. @lgritz

    Fix oslc incorrectly emitting init ops for constructor color(float). (#…

    lgritz committed Apr 14, 2016
    We're talking about a construct like:
        shader foo (color c = color(1), ...)
    It got it right if it was
        color c = color(1,1,1)
    In both cases, it properly reduced the default value to a static constant
    value, but the bug was that it ALSO (unnecessarily) had extra init ops
    for that parameter. That would be eliminated in runtime optimization, the
    shader certainly ran correctly, but it threw off oslinfo, which figures
    that if init ops are present, it can't figure out what the default values
Commits on Apr 8, 2016
  1. @lgritz
Commits on Mar 28, 2016
  1. @lgritz

    Warn for common misstep of forgetting constructor name. (635)

    lgritz committed Mar 28, 2016
        shader test ( output color Cout = 0 )
            vector x = (1, 2, 3);
    See where this goes wrong? This code will make x be (3,3,3).  If you
    don't know why, think about how the comma operator works in C, C++, and
    related languages.
    The user almost certainly meant
        vector x = vector (1, 2, 3);
    With this change, the original (buggy) code will get the following
    warning output:
        test.osl:3: warning: Comma operator is very confusing here. Did you mean to use a constructor: x = vector(...)?
Commits on Mar 11, 2016
  1. @lgritz

    Make an option to have OSL isconnected() return 1 for userdata parame…

    lgritz committed Mar 10, 2016
    This adds a new ShadingSystem attribute, "userdata_isconnected". The
    default of 0 is the old/usual behavior that most applications want.
    However, setting this attribute to 1 will cause the OSL built-in
    function isconnected(paramname) to return 1 not only for connected
    parameters, but also for parameters that may be bound to userdata
    (i.e., those that have lockgeom=0).
    The use case for this involves a renderer implementation that can mix
    C++ and OSL nodes within a shading group. The outputs exported by the
    C++ nodes propagate their values to the downstream node via
    get_userdata(), hijacking the mechanism that is generally used geometric
    primitive variable interpolation. But from the point of view of the
    downstream node, they should semantically appear to be a connection.
Commits on Feb 26, 2016
  1. @lgritz

    New ref images for recent OIIO texture improvement.

    lgritz committed Feb 25, 2016
    Related to OpenImageIO/oiio#1369
    We can remove the old-oiio1.5 images once 1.6 is the minimum standard for OSL.
Commits on Jan 21, 2016
  1. @lgritz

    Testsuite organization overhaul -- no more src or ref in build

    lgritz committed Jan 19, 2016
    The old way was that when CMake runs for the first time (when it builds
    your make or ninja files), it copies everything from testsuite/ into
    build/PLATFORM/testsuite/, and then when you run tests, it uses all the
    info (source data, scripts, and reference output) in the build area.
    That was fine usually, but if you were developing or modifying a test
    itself, it was a big PITA, because changing something in
    testsuite/mytest would not be reflected in the
    build/PLATFORM/testsuite/mytest that had already been copied. It was the
    source of many frustrations and errors. And beware modifying something
    in the build area and then blowing it away, not remembering to copy it
    to the source testsuite/ area.
    This overhaul NO LONGER COPIES source data or reference output en masse
    to build at all. Instead, a combination of selective copies (usually
    just .osl files), links and references to the canonical files are used
    to make the build area only the temporary location of test output
    itself. This sure does make everything easier.
Commits on Jan 11, 2016
  1. @lgritz

    Add DEBUG build and test to the Travis-CI matrix.

    lgritz committed Jan 7, 2016
    And fix any warnings or tests that fail only in debug mode.
    Spruce up the testsuite/ script to make it easier to discern
    what's going wrong just from the console output that Travis prints.
Commits on Jan 9, 2016
  1. @fpsunflower

    Revert addition of search path in testsuite invocation of oslc

    fpsunflower committed Jan 8, 2016
    This doesn't seem to be required afterall
Commits on Jan 8, 2016
  1. @fpsunflower

    Add draw_string utility function to oslutil.h and add a unit test for it

    fpsunflower committed Jan 8, 2016
    Make it possible to include oslutil.h from the testsuite
  2. @fpsunflower
Commits on Jan 6, 2016
  1. @lgritz

    Fix testsuite ref output

    lgritz committed Jan 5, 2016
Commits on Dec 9, 2015
  1. @lgritz

    Fix potential SIGFPE from divide by zero in shaders.

    lgritz committed Dec 7, 2015
    The implementation in LLVM_Util we were relying on for safe div and mod
    turned out to have the property that they generated safe results (e.g.,
    x/0 returns 0, not inf), but still was capable of generating div-by-zero
    exception if the app in which OSL is embedded was trapping SIGFPE.
    Instead, switch to a truly safe implementation that only does the div
    or mod if the denominator is nonzero. Also enhance it by doing a simple
    unchecked div or mod any time the denominator is known to be a nonzero
    constant (no need to have the conditional in that case).
    LLVM_Util add unchecked op_div(), op_mod(), remove safe_div and safe_mod,
    which are now unused and of dubious utility.
Commits on Dec 1, 2015
  1. @lgritz

    Change isconnected() to reveal down-connections

    lgritz committed Nov 30, 2015
    Old: isconnected(param) returns 1 if the param is connected to an upstream
    layer, otherwise 0.
    New: isconnected(param) returns 1 if the param is connected to an upstream
    layer, 2 if connected to a downstream layer, 3 if both, 0 if neither.
Commits on Nov 4, 2015
  1. @lgritz

    Fix broken test from isconstant

    lgritz committed Nov 4, 2015
  2. @lgritz

    isconstant(expr) returns 1 if the expression can be turned into a con…

    lgritz committed Nov 3, 2015
    at runtime (with full knowledge of the shader group's parameters values and
    This is primarily a debugging aid for advanced shader writers to verify
    their assumptions about what expressions can end up being constant-folded
    by the runtime optimizer. Also an aid for me in debugging that the runtime
    optimizer is behaving as I expect.
Commits on Oct 29, 2015
  1. @lgritz

    linearstep & smooth_linearstep: handle degenerate edge0==edge1 case.

    lgritz committed Oct 29, 2015
    Also add a testsuite that exercises these two new functions, including
    the degenerate cases.
Commits on Sep 29, 2015
  1. @lgritz

    Important bug fix for code generation of struct parameters copied whole.

    lgritz committed Sep 29, 2015
    When a shader param that was a struct had its value initialized by copying
    another struct WHOLE, it neglected to set the "method" name for the init
    ops for each field. This made it incorectly chalk up the init ops to the
    struct param itself (which is just a dummy placeholder) instead of the
    fields, and under some circumstances this could simply leave the struct
    fields uninitialized.
    It was fine all along if the struct param's fields were initialized one
    by one -- in that case, the init ops were correctly associated with each
    field individually. It was only the case of initializing by copying
    another whole struct that was problematic.
    The solution is to pass a flag to codegen_assign_struct indicating if we
    are generating that code for a parameter initialization, in which case
    it will do the proper calls to associate the init ops with the right
    variable. This is just like we already did for the field-by-field case
    handled in codegen_struct_initializers.
Commits on Sep 23, 2015
  1. @lgritz

    Change logic of lazy evaluation -- unconnected layers are now lazy.

    lgritz committed Sep 11, 2015
    New logic: the only layers unconditionally run are (1) the LAST layer
    (presumed to be the "root"), (2) any layer that sets a designated
    renderer output, (3) any layer that sets a global, but only if
    lazyglobals is off (it's on by default now). Everything else is run
    "lazily", that is, only if and when its connected outputs are needed
    The old logic additionally considered a layer to be unconditional (i.e.,
    not lazy) if it has NO outgoing connections, on the theory that is must
    be the root, and also lazyglobals was not turned on by default. That
    seemed like a recipe for inefficient shader evaluation, and it doesn't
    look like any renderer needs or wants this.
Commits on Sep 11, 2015
  1. @lgritz
  2. @fpsunflower

    Update tests for keyword argument refactor

    fpsunflower committed Sep 10, 2015
    Due to the previous commit, printing a closure will now display the
    value of all optional keyword arguments. In the case that multiple are
    provided, only the last one is displayed.
Commits on Sep 10, 2015
  1. @lgritz

    Execution order refactor, and per-layer explicit execution order

    lgritz committed Aug 20, 2015
    Let's review what happens when you call
        shadingsys->execute (contextptr, shadergroup, shaderglobals);
    This executes the given shader group on the context, with a specific set
    of shader globals. The group may be composed of many individual layers
    (shader nodes), and execution proceeds from first to last layer,
    executing those that must be run unconditionally and skipping those that
    can be run lazily. Of course, if a layer executes, it may trigger lazy
    execution of other not-yet-run layers. The unconditional layers are the
    layers that set global variables (like Ci or P), the layers whose
    outputs are connected to designated renderer outputs (AOVs and the
    like), and layers that have no connected outputs at all (under the
    theory that this must be the "root" node).
    This all remains the same with this patch, but *additionally* there is
    another option where you can explicitly declare the "entry points" of
    a shader group,
        std::vector<const char *> entrynames;  // fill with layer names
        shadingsys->attribute (shadergroup, "entry_layers",
                               TypeDesc(TypeDesc::STRING, nentries),
    and then execute the group layer by layer:
        shadingsys->execute_init (contextptr, shadergroup, shaderglobals);
        shadingsys->execute_layer (contextptr, shaderglobals, layernumber);
        shadingsys->execute_cleanup (contextptr);
    The execute_init binds and prepares the context, execute_layer will run
    each layer (identified by number, and must correspond to one of the
    declared entry layers of the group). As before, other layers will
    execute lazily when their results are "pulled" by connections. However,
    if you are going to take the approach of manually calling layers, it's
    all up to you -- no layers (whose results aren't pulled downstream) will
    run unconditionally, even if they appear to set global variables or
    appear to be connected to renderer outputs.
    In addition to execute_layer by the layer number, there are also similar
    calls to specificy the layer by name, and by ShaderSymbol* (running
    whichever layer produces the symbol as an output).
    The "all in one shot" approach still works just fine, and is probably
    the usual way of doing things. But for renderer that need even more
    control over which layers are executed and when, this provides an
    alternate calling sequence that gives more flexibility.
    Some things that had to be done along the way:
    * It used to be that the "last" layer was the presumed sole group entry
      point (or "root"), and its code was the one that did certain
      initialization and the calling of the unconditionally-executed layers.
      But now, the app can call any (declared entry) layer, in any order, so
      we can't count on that initialization working. Instead, we now generate
      an additional initialization function, which is called by execute_init.
    * For lazy evaluation, it used to be that the *caller* of an earlier layer
      was responsible for marking it as run (so it wouldn't be run twice).
      But now nodes can get called by the app, so the "this layer ran" flag
      is set by the layer itself rather than the caller.
    * For the reason immediately above, no layer's LLVM IR code is truly
      empty; at the vest least, it marks the "this layer ran" flag. So the
      prior test for "this whole group does nothing" no longer can count on
      simply checking the post-LLVM optimized IR for being empty but for a
      return statement. This forced us to move the 'group does nothing'
      detection entirely out of LLVM generation and into the time of our
      runtime optimization.
    * Groups must track their declared list of possible externally-called
      entry points.
    * Augment testshade to be able to declare and call explicit entry
    * New test: testsuite/layers-entry tests both the default and explicit
      layer execution models, with a test carefully designed to have
      different layer execution orders for the two calling strategies.
Commits on Jul 3, 2015
  1. @UbisoftMotionPictures @lgritz
Commits on Jun 25, 2015
  1. @lgritz

    Better range checking error messages.

    lgritz committed Jun 23, 2015
    Say which variable was being accessed, and print group, layer, shader names.
  2. @lgritz

    Bug fix with unconditional running of earlier layers.

    lgritz committed Jun 24, 2015
    Subtlety: When generating code for the "group entry" (last) layer, which
    is also responsible for executing all earlier layers that are marked as
    needing to run unconditionally (non-lazily), it is important that the
    group entry layer initialize its input parameters BEFORE it runs the
    earlier unconditional layers and copies the upstream outputs to its own
    inputs. Of course. Because, duh, if it first runs the upstream layer and
    copies the upsteam outputs to its own input, THEN zeroes out or
    otherwise initializes its inputs, it will overwrite the value set by the
    earlier layer.
Commits on Jun 22, 2015
  1. @fpsunflower
Commits on Jun 20, 2015
  1. @lgritz
Commits on Jun 19, 2015
  1. @lgritz

    Fix bugs when deserializing shader group strings with unsized arrays.

    lgritz committed Jun 19, 2015
    When an unsized array parameter comes in (like: param int[] 1 2 3 4) we
    don't actually know the parameter type yet, because the shader itself
    hasn't been declared. So, first of all, handle the "int[]" part without
    ending up with an uninitialized length, duh. But then, we can't
    preallocate at that point, because we don't know how many ints there
    will be, so grow the array as we read them, and then reset the type to
    the right length that we actually saw.
Commits on Jun 16, 2015
  1. @lgritz

    OIIO image reader plugin that runs OSL shaders to make the image.

    lgritz committed Jun 12, 2015
    OIIO (and any app that uses it to read images) not only can read many
    image formats, but if it doesn't know a format internally, it will look
    for a plug-in that can read the format. But it's just a black box, it
    doesn't HAVE to actually read an image from disk. It could do something
    So... I wrote an OIIO image reading plugin that executes OSL code to
    procedurally generate image pixels as needed. It can do some fun tricks.
    Generate an image by running a compiled OSL shader:
        shader ramp (
            color topleft     = color(0,0,0),
            color topright    = color(1,0,0),
            color bottomleft  = color(0,1,0),
            color bottomright = color(1,1,1),
            output color result = 0,
            output float alpha = 1
            result = topleft*(1-u)*(1-v) + topright*u*(1-v) +
                     bottomleft*(1-u)*v + bottomright*u*v;
        $ oslc ramp.osl
        $ oiiotool ramp.oso -o ramp.exr
    You can generate directly into an iv window (or any other app that
    uses OIIO to read):
        iv ramp.oso
    A ".oslgroup" file can contain the serialization of an entire shading
        oiiotool network.oslgroup -o complex.exr
    URI notation can be used to set shader parameters:
        oiiotool "fBm.oso?frequency=4&octaves=4&point offset=0,1,0" -o noise.exr
    URI notation also to control the resolution of the "image", or to make
    it look tiled rather than scanline, or even to make it behave like it's
        iv "fBm.oso?octaves=4?RES=512x512&MIP=1&TILE=64x64"
    ".oslbody" signifies a snipped of OSL that will be pasted into
    OSL shader boilerplate, compiled from memory, and JITed on the fly:
        iv "result = noise (u*5, v*5);.oslbody"
    Not just a single expression, you could write a whole program if you
        iv "int octaves=8; float freq=2,amp=0.5; for (int i = 0; i < octaves; ++i, amp /=2, freq*=2)result += amp*(color)snoise(freq*u,freq*v); result += 0.5; .oslbody?RES=512x512"
    Yeah, crazy.
Commits on Jun 11, 2015
  1. @lgritz

    testsuite - improve the way we find OIIO

    lgritz committed Jun 1, 2015
    If OPENIMAGEIOHOME is not found in the environment, assume the binaries
    we need are in the execution search path.
Commits on May 28, 2015
  1. @lgritz
Commits on May 27, 2015
  1. @lgritz

    testshade: allow OSL code snippets in place of shaders.

    lgritz committed May 26, 2015
    Basically, this experimental feature allows you to use testshade in
    such a way that instead of specifying shaders on disk, to be able
    to specify a little bit of OSL code on the command line itself, which
    will be automatically embedded into a shader boilerplate:
        shader <automatically-generated-shadername> (
            float s = u [[ int lockgeom=0 ]],
            float t = v [[ int lockgeom=0 ]],
            output color result = 0,
            output float alpha = 1)
            <the code goes here>
    This is assembled, compiled (in memory!) on the fly, and then treated
    just like any other layer you might have specified to be read from disk.
    Your expression presumably sets 'result', and the point is to save
    result to an image file, with resolution specified on the command
    line. As always, testshade sets u and v to go from 0->1 across the
    resulting image.
    Here's a simple use to make a color gradient across the image:
        testshade -g 512 512 --expr "result = color(u, v, 0);" -o result out.exr
    You can do anything that's valid in OSL, like this texture lookup that
    effectively acts as a filtered rescale of the source image:
        testshade -g 512 512 --expr "result = texture(\"input.exr\", u, v\");" -o result out.exr
    Or this noise pattern, an fBm loop:
        testshade --expr "int octaves = 6; float amp = 0.5, freq=5; for (int i = 0; i < octaves; ++i, freq *= 2, amp *= 0.5) result += amp * ((float)snoise(s*freq,t*freq)); result += 0.5;" -g 640 480 -o result out.exr
Commits on May 26, 2015
  1. @lgritz
  2. @lgritz

    Improve uninitialized value detection mode ("debug_uninit")

    lgritz committed May 26, 2015
    Found a source of "false positives" -- we shouldn't do a check for
    uninitialized values of the arguments to a "useparam" pseudoinstruction,
    since by definition the parameters named may be uninitialized before the
    useparam action itself copies the values from connected layers.
    In the process, beef up the uninitialized value error message to point
    not only to the OSL source file and line, but also to the specific group
    and layer, and (mainly for me in debugging the feature) which
    instruction it is.
Commits on May 7, 2015
  1. @lgritz

    Support defaults for vararry parameters, with relevant tests.

    Daniel Heckenberg committed with lgritz May 5, 2015
    TypeDesc DASSERTS to make sure we aren't misusing the unsized array values.
Commits on Mar 26, 2015
  1. @lgritz

    constant fold for sincos

    lgritz committed Mar 25, 2015
    Also noticed that the vector version of sincos didn't use fast_sincos underneath,
    whereas the float varieties did. Fixed.
Something went wrong with that request. Please try again.